Commit 38f6c83e authored by unknown's avatar unknown

merge


sql/mysql_priv.h:
  Auto merged
sql/sql_select.cc:
  Auto merged
parents 52a62ce0 e51447b1
......@@ -417,6 +417,7 @@ typedef struct st_mi_sort_param
#define MI_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */
#define MI_MIN_ROWS_TO_USE_BULK_INSERT 100
#define MI_MIN_ROWS_TO_DISABLE_INDEXES 100
#define MI_MIN_ROWS_TO_USE_WRITE_CACHE 10
/* The UNIQUE check is done with a hashed long key */
......
......@@ -670,7 +670,7 @@ report_stats () {
$ECHO "The log files in $MY_LOG_DIR may give you some hint"
$ECHO "of what when wrong."
$ECHO "If you want to report this error, please read first the documentation at"
$ECHO "http://www.mysql.com/doc/M/y/MySQL_test_suite.html"
$ECHO "http://www.mysql.com/doc/en/MySQL_test_suite.html"
fi
if test -z "$USE_RUNNING_SERVER"
......
......@@ -750,3 +750,10 @@ analyze table t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
drop table t1;
CREATE TABLE t1 (
fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
g GEOMETRY NOT NULL,
SPATIAL KEY(g)
) ENGINE=MyISAM;
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
drop table t1;
......@@ -76,6 +76,8 @@ delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
show grants for mysqltest_1@localhost;
ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host 'localhost'
create table t1 (a int);
GRANT select,update,insert on t1 to mysqltest_1@localhost;
GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost;
......
......@@ -103,3 +103,16 @@ check table t1;
analyze table t1;
drop table t1;
#
# The following crashed gis
#
CREATE TABLE t1 (
fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
g GEOMETRY NOT NULL,
SPATIAL KEY(g)
) ENGINE=MyISAM;
INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
#select * from t1 where g<GeomFromText('LineString(1 2, 2 3)');
drop table t1;
......@@ -53,6 +53,8 @@ delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
--error 1141
show grants for mysqltest_1@localhost;
#
# Test what happens when you have same table and colum level grants
......
......@@ -4359,7 +4359,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
error= 1;
}
memcpy(ptr+2,from,length);
memcpy(ptr+HA_KEY_BLOB_LENGTH,from,length);
int2store(ptr, length);
return error;
}
......@@ -4388,18 +4388,18 @@ int Field_varstring::store(longlong nr)
double Field_varstring::val_real(void)
{
int not_used;
uint length=uint2korr(ptr)+2;
uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
CHARSET_INFO *cs=charset();
return my_strntod(cs,ptr+2,length,(char**)0, &not_used);
return my_strntod(cs, ptr+HA_KEY_BLOB_LENGTH, length, (char**)0, &not_used);
}
longlong Field_varstring::val_int(void)
{
int not_used;
uint length=uint2korr(ptr)+2;
uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
CHARSET_INFO *cs=charset();
return my_strntoll(cs,ptr+2,length,10,NULL, &not_used);
return my_strntoll(cs,ptr+HA_KEY_BLOB_LENGTH,length,10,NULL, &not_used);
}
......@@ -4407,7 +4407,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
uint length=uint2korr(ptr);
val_ptr->set((const char*) ptr+2,length,field_charset);
val_ptr->set((const char*) ptr+HA_KEY_BLOB_LENGTH,length,field_charset);
return val_ptr;
}
......@@ -4417,18 +4417,21 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
uint a_length=uint2korr(a_ptr);
uint b_length=uint2korr(b_ptr);
int diff;
diff=my_strnncoll(field_charset,
(const uchar*)a_ptr+2,min(a_length,b_length),
(const uchar*)b_ptr+2,min(a_length,b_length));
diff= my_strnncoll(field_charset,
(const uchar*) a_ptr+HA_KEY_BLOB_LENGTH,
min(a_length,b_length),
(const uchar*) b_ptr+HA_KEY_BLOB_LENGTH,
min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
void Field_varstring::sort_string(char *to,uint length)
{
uint tot_length=uint2korr(ptr);
tot_length=my_strnxfrm(field_charset,
(unsigned char *) to, length,
(unsigned char *)ptr+2, tot_length);
tot_length= my_strnxfrm(field_charset,
(uchar*) to, length,
(uchar*) ptr+HA_KEY_BLOB_LENGTH,
tot_length);
if (tot_length < length)
field_charset->cset->fill(field_charset, to+tot_length,length-tot_length,
binary() ? (char) 0 : ' ');
......@@ -4453,7 +4456,7 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
if (max_length > 255)
*to++= (char) (length >> 8);
if (length)
memcpy(to, from+2, length);
memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
return to+length;
}
......@@ -4473,7 +4476,7 @@ const char *Field_varstring::unpack(char *to, const char *from)
to[1] = *from++;
}
if (length)
memcpy(to+2, from, length);
memcpy(to+HA_KEY_BLOB_LENGTH, from, length);
return from+length;
}
......@@ -4484,8 +4487,8 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
uint b_length;
if (key_length > 255)
{
a_length=uint2korr(a); a+=2;
b_length=uint2korr(b); b+=2;
a_length=uint2korr(a); a+= 2;
b_length=uint2korr(b); b+= 2;
}
else
{
......@@ -4493,32 +4496,32 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
b_length= (uint) (uchar) *b++;
}
return my_strnncoll(field_charset,
(const uchar *)a,a_length,
(const uchar *)b,b_length);
(const uchar*) a, a_length,
(const uchar*) b, b_length);
}
int Field_varstring::pack_cmp(const char *b, uint key_length)
{
char *a=ptr+2;
uint a_length=uint2korr(ptr);
char *a= ptr+HA_KEY_BLOB_LENGTH;
uint a_length= uint2korr(ptr);
uint b_length;
if (key_length > 255)
{
b_length=uint2korr(b); b+=2;
b_length=uint2korr(b); b+= 2;
}
else
{
b_length= (uint) (uchar) *b++;
}
return my_strnncoll(field_charset,
(const uchar *)a,a_length,
(const uchar *)b,b_length);
(const uchar*) a, a_length,
(const uchar*) b, b_length);
}
uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
return uint2korr(data_ptr)+HA_KEY_BLOB_LENGTH;
else
return (uint) ((uchar) *data_ptr)+1;
}
......@@ -4531,22 +4534,21 @@ uint Field_varstring::max_packed_col_length(uint max_length)
void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
imagetype type)
{
length-= HA_KEY_BLOB_LENGTH;
uint f_length=uint2korr(ptr);
if (f_length > length)
f_length= length;
int2store(buff,length);
memcpy(buff+2,ptr+2,length);
memcpy(buff+HA_KEY_BLOB_LENGTH, ptr+HA_KEY_BLOB_LENGTH, length);
#ifdef HAVE_purify
if (f_length < length)
bzero(buff+2+f_length, (length-f_length));
bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length));
#endif
}
void Field_varstring::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
{
length=uint2korr(buff); // Real length is here
(void) Field_varstring::store(buff+2, length, cs);
(void) Field_varstring::store(buff+HA_KEY_BLOB_LENGTH, length, cs);
}
......@@ -4799,7 +4801,6 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
void Field_blob::get_key_image(char *buff,uint length,
CHARSET_INFO *cs, imagetype type)
{
length-= HA_KEY_BLOB_LENGTH;
uint32 blob_length= get_length(ptr);
char *blob;
......@@ -4838,18 +4839,18 @@ void Field_blob::get_key_image(char *buff,uint length,
Must clear this as we do a memcmp in opt_range.cc to detect
identical keys
*/
bzero(buff+2+blob_length, (length-blob_length));
bzero(buff+HA_KEY_BLOB_LENGTH+blob_length, (length-blob_length));
length=(uint) blob_length;
}
int2store(buff,length);
get_ptr(&blob);
memcpy(buff+2,blob,length);
memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
}
void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
{
length=uint2korr(buff);
(void) Field_blob::store(buff+2,length,cs);
length= uint2korr(buff);
(void) Field_blob::store(buff+HA_KEY_BLOB_LENGTH, length, cs);
}
......@@ -4857,16 +4858,16 @@ int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
char *blob1;
uint blob_length=get_length(ptr);
max_key_length-=2;
memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
return Field_blob::cmp(blob1,min(blob_length, max_key_length),
(char*) key_ptr+2,uint2korr(key_ptr));
(char*) key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
}
int Field_blob::key_cmp(const byte *a,const byte *b)
{
return Field_blob::cmp((char*) a+2,uint2korr(a),
(char*) b+2,uint2korr(b));
return Field_blob::cmp((char*) a+HA_KEY_BLOB_LENGTH, uint2korr(a),
(char*) b+HA_KEY_BLOB_LENGTH, uint2korr(b));
}
......@@ -4882,8 +4883,8 @@ void Field_blob::sort_string(char *to,uint length)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
blob_length=my_strnxfrm(field_charset,
(unsigned char *)to, length,
(unsigned char *)blob, blob_length);
(uchar*) to, length,
(uchar*) blob, blob_length);
if (blob_length < length)
field_charset->cset->fill(field_charset, to+blob_length,
length-blob_length,
......@@ -4965,8 +4966,8 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
b_length= (uint) (uchar) *b++;
}
return my_strnncoll(field_charset,
(const uchar *)a,a_length,
(const uchar *)b,b_length);
(const uchar*) a, a_length,
(const uchar*) b, b_length);
}
......@@ -4988,8 +4989,8 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
b_length= (uint) (uchar) *b++;
}
return my_strnncoll(field_charset,
(const uchar *)a,a_length,
(const uchar *)b,b_length);
(const uchar*) a, a_length,
(const uchar*) b, b_length);
}
/* Create a packed key that will be used for storage from a MySQL row */
......@@ -5025,7 +5026,7 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
if (max_length > 255)
*to++= (char) (length >> 8);
if (length)
memcpy(to, from+2, length);
memcpy(to, from+HA_KEY_BLOB_LENGTH, length);
return to+length;
}
......@@ -5048,11 +5049,12 @@ uint Field_blob::max_packed_col_length(uint max_length)
void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
imagetype type)
{
length-= HA_KEY_BLOB_LENGTH;
ulong blob_length= get_length(ptr);
char *blob;
const char *dummy;
MBR mbr;
ulong blob_length= get_length(ptr);
Geometry_buffer buffer;
Geometry *gobj;
if (blob_length < SRID_SIZE)
{
......@@ -5060,8 +5062,6 @@ void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
return;
}
get_ptr(&blob);
Geometry_buffer buffer;
Geometry *gobj;
gobj= Geometry::create_from_wkb(&buffer,
blob + SRID_SIZE, blob_length - SRID_SIZE);
if (gobj->get_mbr(&mbr, &dummy))
......@@ -5554,7 +5554,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
switch (type) {
case FIELD_TYPE_STRING:
case FIELD_TYPE_DECIMAL: return (length);
case FIELD_TYPE_VAR_STRING: return (length+2);
case FIELD_TYPE_VAR_STRING: return (length+HA_KEY_BLOB_LENGTH);
case FIELD_TYPE_YEAR:
case FIELD_TYPE_TINY : return 1;
case FIELD_TYPE_SHORT : return 2;
......
......@@ -212,7 +212,8 @@ class Field
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length, CHARSET_INFO *cs)
{ memcpy(ptr,buff,length); }
virtual void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type)
virtual void get_key_image(char *buff,uint length, CHARSET_INFO *cs,
imagetype type)
{ get_image(buff,length,cs); }
virtual void set_key_image(char *buff,uint length, CHARSET_INFO *cs)
{ set_image(buff,length,cs); }
......
......@@ -867,7 +867,9 @@ void ha_myisam::start_bulk_insert(ha_rows rows)
THD *thd=current_thd;
ulong size= min(thd->variables.read_buff_size, table->avg_row_length*rows);
mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*)&size);
/* don't enable row cache if too few rows */
if (!rows && rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE)
mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
can_enable_indexes= (file->s->state.key_map ==
set_bits(ulonglong, file->s->base.keys));
......
......@@ -1287,3 +1287,141 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
mi_change_key_cache(old_key_cache, new_key_cache);
return 0;
}
/*
Read first row between two ranges.
Store ranges for future calls to read_range_next
SYNOPSIS
read_range_first()
start_key Start key. Is 0 if no min range
end_key End key. Is 0 if no max range
sorted Set to 1 if result should be sorted per key
NOTES
Record is read into table->record[0]
RETURN
0 Found row
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
int handler::read_range_first(const key_range *start_key,
const key_range *end_key,
bool sorted)
{
int result;
DBUG_ENTER("handler::read_range_first");
end_range= 0;
if (end_key)
{
end_range= &save_end_range;
save_end_range= *end_key;
key_compare_result_on_equal= ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 :
(end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0);
}
range_key_part= table->key_info[active_index].key_part;
if (!start_key) // Read first record
result= index_first(table->record[0]);
else
result= index_read(table->record[0],
start_key->key,
start_key->length,
start_key->flag);
if (result)
DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND ||
result == HA_ERR_END_OF_FILE) ? HA_ERR_END_OF_FILE :
result);
DBUG_RETURN (compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE);
}
/*
Read next row between two ranges.
SYNOPSIS
read_range_next()
eq_range Set to 1 if start_key == end_key
NOTES
Record is read into table->record[0]
RETURN
0 Found row
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
int handler::read_range_next(bool eq_range)
{
int result;
DBUG_ENTER("handler::read_range_next");
if (eq_range)
result= index_next_same(table->record[0],
end_range->key,
end_range->length);
else
result= index_next(table->record[0]);
if (result)
DBUG_RETURN(result);
DBUG_RETURN(compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE);
}
/*
Compare if found key is over max-value
SYNOPSIS
compare_key
range key to compare to row
NOTES
For this to work, the row must be stored in table->record[0]
RETURN
0 Key is equal to range or 'range' == 0 (no range)
-1 Key is less than range
1 Key is larger than range
*/
int handler::compare_key(key_range *range)
{
KEY_PART_INFO *key_part= range_key_part;
uint store_length;
if (!range)
return 0; // No max range
for (const char *key=range->key, *end=key+range->length;
key < end;
key+= store_length, key_part++)
{
int cmp;
store_length= key_part->store_length;
if (key_part->null_bit)
{
if (*key)
{
if (!key_part->field->is_null())
return 1;
continue;
}
else if (key_part->field->is_null())
return 0;
key++; // Skip null byte
store_length--;
}
if ((cmp=key_part->field->key_cmp((byte*) key, key_part->length)) < 0)
return -1;
if (cmp > 0)
return 1;
}
return key_compare_result_on_equal;
}
......@@ -218,6 +218,14 @@ typedef struct st_ha_check_opt
} HA_CHECK_OPT;
typedef struct st_key_range
{
const byte *key;
uint length;
enum ha_rkey_function flag;
} key_range;
class handler :public Sql_alloc
{
protected:
......@@ -239,6 +247,12 @@ class handler :public Sql_alloc
time_t create_time; /* When table was created */
time_t check_time;
time_t update_time;
/* The following are for read_range() */
key_range save_end_range, *end_range;
KEY_PART_INFO *range_key_part;
int key_compare_result_on_equal;
uint errkey; /* Last dup key */
uint sortkey, key_used_on_scan;
uint active_index;
......@@ -250,6 +264,7 @@ class handler :public Sql_alloc
bool auto_increment_column_changed;
bool implicit_emptied; /* Can be !=0 only if HEAP */
handler(TABLE *table_arg) :table(table_arg),
ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0),
delete_length(0), auto_increment_value(0),
......@@ -298,6 +313,11 @@ class handler :public Sql_alloc
{
return (my_errno=HA_ERR_WRONG_COMMAND);
}
virtual int handler::read_range_first(const key_range *start_key,
const key_range *end_key,
bool sorted);
virtual int handler::read_range_next(bool eq_range);
int handler::compare_key(key_range *range);
virtual int ft_init()
{ return -1; }
virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key, uint keylen)
......
......@@ -516,19 +516,7 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
uint order_num, ORDER *order, int alter_flags,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP,
bool simple_alter=0);
int real_alter_table(THD *thd, char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
TABLE *table,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
uint order_num, ORDER *order, int alter_flags,
uint order_num, ORDER *order, uint alter_flags,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP,
......@@ -544,10 +532,6 @@ bool mysql_rename_table(enum db_type base,
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_add_column(THD *thd, TABLE_LIST *table_list,
List<create_field> &fields);
int mysql_drop_column(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds,
uint order_num, ORDER *order, ha_rows limit,
......@@ -951,7 +935,8 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list,
void unireg_init(ulong options);
void unireg_end(void);
int mysql_create_frm(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
bool mysql_create_frm(THD *thd, my_string file_name,
HA_CREATE_INFO *create_info,
List<create_field> &create_field,
uint key_count,KEY *key_info,handler *db_type);
int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
......
......@@ -177,11 +177,11 @@ class SEL_ARG :public Sql_alloc
if (maybe_null && *min_value)
{
**min_key=1;
bzero(*min_key+1,length);
bzero(*min_key+1,length-1);
}
else
memcpy(*min_key,min_value,length+(int) maybe_null);
(*min_key)+= length+(int) maybe_null;
memcpy(*min_key,min_value,length);
(*min_key)+= length;
}
if (!(max_flag & NO_MAX_RANGE) &&
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
......@@ -189,18 +189,18 @@ class SEL_ARG :public Sql_alloc
if (maybe_null && *max_value)
{
**max_key=1;
bzero(*max_key+1,length);
bzero(*max_key+1,length-1);
}
else
memcpy(*max_key,max_value,length+(int) maybe_null);
(*max_key)+= length+(int) maybe_null;
memcpy(*max_key,max_value,length);
(*max_key)+= length;
}
}
void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
{
SEL_ARG *key_tree= first();
key_tree->store(key[key_tree->part].part_length,
key_tree->store(key[key_tree->part].store_length,
range_key,*range_key_flag,range_key,NO_MAX_RANGE);
*range_key_flag|= key_tree->min_flag;
if (key_tree->next_key_part &&
......@@ -213,7 +213,7 @@ class SEL_ARG :public Sql_alloc
void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
{
SEL_ARG *key_tree= last();
key_tree->store(key[key_tree->part].part_length,
key_tree->store(key[key_tree->part].store_length,
range_key, NO_MIN_RANGE, range_key,*range_key_flag);
(*range_key_flag)|= key_tree->max_flag;
if (key_tree->next_key_part &&
......@@ -646,6 +646,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
MEM_ROOT *old_root,alloc;
SEL_TREE *tree;
KEY_PART *key_parts;
KEY *key_info;
PARAM param;
/* set up parameter that is passed to all functions */
......@@ -671,24 +672,26 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
my_pthread_setspecific_ptr(THR_MALLOC,&alloc);
for (idx=0 ; idx < head->keys ; idx++)
key_info= head->key_info;
for (idx=0 ; idx < head->keys ; idx++, key_info++)
{
KEY_PART_INFO *key_part_info;
if (!keys_to_use.is_set(idx))
continue;
KEY *key_info= &head->key_info[idx];
if (key_info->flags & HA_FULLTEXT)
continue; // ToDo: ft-keys in non-ft ranges, if possible SerG
param.key[param.keys]=key_parts;
for (uint part=0 ; part < key_info->key_parts ; part++,key_parts++)
{
key_parts->key=param.keys;
key_parts->part=part;
key_parts->part_length= key_info->key_part[part].length;
key_parts->field= key_info->key_part[part].field;
key_parts->null_bit= key_info->key_part[part].null_bit;
if (key_parts->field->type() == FIELD_TYPE_BLOB)
key_parts->part_length+=HA_KEY_BLOB_LENGTH;
key_part_info= key_info->key_part;
for (uint part=0 ; part < key_info->key_parts ;
part++, key_parts++, key_part_info++)
{
key_parts->key= param.keys;
key_parts->part= part;
key_parts->length= key_part_info->length;
key_parts->store_length= key_part_info->store_length;
key_parts->field= key_part_info->field;
key_parts->null_bit= key_part_info->null_bit;
key_parts->image_type =
(key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
}
......@@ -1043,18 +1046,26 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
DBUG_RETURN(0); // Can only optimize strings
offset=maybe_null;
length=key_part->part_length;
if (field->type() == FIELD_TYPE_BLOB)
length=key_part->store_length;
if (length != key_part->length + maybe_null)
{
offset+=HA_KEY_BLOB_LENGTH;
field_length=key_part->part_length-HA_KEY_BLOB_LENGTH;
/* key packed with length prefix */
offset+= HA_KEY_BLOB_LENGTH;
field_length= length - HA_KEY_BLOB_LENGTH;
}
else
{
if (length < field_length)
length=field_length; // Only if overlapping key
if (unlikely(length < field_length))
{
/*
This can only happen in a table created with UNIREG where one key
overlaps many fields
*/
length= field_length;
}
else
field_length=length;
field_length= length;
}
length+=offset;
if (!(min_str= (char*) alloc_root(param->mem_root, length*2)))
......@@ -1067,7 +1078,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
res->ptr(), res->length(),
((Item_func_like*)(param->cond))->escape,
wild_one, wild_many,
field_length,
field_length-maybe_null,
min_str+offset, max_str+offset,
&min_length, &max_length);
if (like_error) // Can't optimize with LIKE
......@@ -1105,13 +1116,13 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
if (field->key_type() == HA_KEYTYPE_VARTEXT)
copies= 2;
str= str2= (char*) alloc_root(param->mem_root,
(key_part->part_length+maybe_null)*copies+1);
(key_part->store_length)*copies+1);
if (!str)
DBUG_RETURN(0);
if (maybe_null)
*str= (char) field->is_real_null(); // Set to 1 if null
field->get_key_image(str+maybe_null,key_part->part_length,
field->charset(),key_part->image_type);
field->get_key_image(str+maybe_null, key_part->length,
field->charset(), key_part->image_type);
if (copies == 2)
{
/*
......@@ -1120,16 +1131,17 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
all rows between 'X' and 'X ...'
*/
uint length= uint2korr(str+maybe_null);
str2= str+ key_part->part_length + maybe_null;
str2= str+ key_part->store_length;
/* remove end space */
while (length > 0 && str[length+HA_KEY_BLOB_LENGTH+maybe_null-1] == ' ')
length--;
int2store(str+maybe_null, length);
/* Create key that is space filled */
memcpy(str2, str, length + HA_KEY_BLOB_LENGTH + maybe_null);
bfill(str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null,
key_part->part_length-length - HA_KEY_BLOB_LENGTH, ' ');
int2store(str2+maybe_null, key_part->part_length - HA_KEY_BLOB_LENGTH);
my_fill_8bit(field->charset(),
str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null,
key_part->length-length, ' ');
int2store(str2+maybe_null, key_part->length);
}
if (!(tree=new SEL_ARG(field,str,str2)))
DBUG_RETURN(0); // out of memory
......@@ -2236,7 +2248,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
uint tmp_min_flag,tmp_max_flag,keynr;
char *tmp_min_key=min_key,*tmp_max_key=max_key;
key_tree->store(param->key[idx][key_tree->part].part_length,
key_tree->store(param->key[idx][key_tree->part].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
uint min_key_length= (uint) (tmp_min_key- param->min_key);
uint max_key_length= (uint) (tmp_max_key- param->max_key);
......@@ -2332,8 +2344,14 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree)
{
QUICK_SELECT *quick;
DBUG_ENTER("get_quick_select");
if ((quick=new QUICK_SELECT(param->thd, param->table,
param->real_keynr[idx])))
if (param->table->key_info[param->real_keynr[idx]].flags & HA_SPATIAL)
quick=new QUICK_SELECT_GEOM(param->thd, param->table, param->real_keynr[idx],
0);
else
quick=new QUICK_SELECT(param->thd, param->table, param->real_keynr[idx]);
if (quick)
{
if (quick->error ||
get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0,
......@@ -2373,7 +2391,7 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
return 1;
}
char *tmp_min_key=min_key,*tmp_max_key=max_key;
key_tree->store(key[key_tree->part].part_length,
key_tree->store(key[key_tree->part].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
if (key_tree->next_key_part &&
......@@ -2491,19 +2509,17 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
{
for (const char *end=key+length ;
key < end;
key+= key_part++->part_length)
key+= key_part++->store_length)
{
if (key_part->null_bit)
{
if (*key++)
if (key_part->null_bit && *key)
return 1;
}
}
return 0;
}
/****************************************************************************
** Create a QUICK RANGE based on a key
Create a QUICK RANGE based on a key
****************************************************************************/
QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
......@@ -2541,9 +2557,8 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
{
key_part->part=part;
key_part->field= key_info->key_part[part].field;
key_part->part_length= key_info->key_part[part].length;
if (key_part->field->type() == FIELD_TYPE_BLOB)
key_part->part_length+=HA_KEY_BLOB_LENGTH;
key_part->length= key_info->key_part[part].length;
key_part->store_length= key_info->key_part[part].store_length;
key_part->null_bit= key_info->key_part[part].null_bit;
}
if (quick->ranges.push_back(range))
......@@ -2585,111 +2600,74 @@ int QUICK_SELECT::get_next()
for (;;)
{
int result;
key_range start_key, end_key;
if (range)
{ // Already read through key
result=((range->flag & (EQ_RANGE | GEOM_FLAG)) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
if (!result)
{
if ((range->flag & GEOM_FLAG) || !cmp_next(*it.ref()))
DBUG_RETURN(0);
}
else if (result != HA_ERR_END_OF_FILE)
// Already read through key
result= file->read_range_next(test(range->flag & EQ_RANGE));
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
}
if (!(range=it++))
if (!(range= it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
if (range->flag & GEOM_FLAG)
{
if ((result = file->index_read(record,
(byte*) (range->min_key),
range->min_length,
(ha_rkey_function)(range->flag ^
GEOM_FLAG))))
{
if (result != HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(result);
range=0; // Not found, to next range
continue;
}
DBUG_RETURN(0);
}
if (range->flag & NO_MIN_RANGE) // Read first record
{
int local_error;
if ((local_error=file->index_first(record)))
DBUG_RETURN(local_error); // Empty table
if (cmp_next(range) == 0)
DBUG_RETURN(0);
range=0; // No matching records; go to next range
continue;
}
if ((result = file->index_read(record,
(byte*) (range->min_key +
test(range->flag & GEOM_FLAG)),
range->min_length,
(range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY:
start_key.key= range->min_key;
start_key.length= range->min_length;
start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
(range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT :
HA_READ_KEY_OR_NEXT)))
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
end_key.key= range->max_key;
end_key.length= range->max_length;
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
*/
end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
{
if (result != HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(result);
range=0; // Not found, to next range
continue;
}
if (cmp_next(range) == 0)
{
result= file->read_range_first(range->min_length ? &start_key : 0,
range->max_length ? &end_key : 0,
sorted);
if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
range=0; // Stop searching
DBUG_RETURN(0); // Found key is in range
}
range=0; // To next range
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
range=0; // No matching rows; go to next range
}
}
/*
Compare if found key is over max-value
Returns 0 if key <= range->max_key
*/
/* Get next for geometrical indexes */
int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg)
int QUICK_SELECT_GEOM::get_next()
{
if (range_arg->flag & NO_MAX_RANGE)
return 0; /* key can't be to large */
DBUG_ENTER(" QUICK_SELECT_GEOM::get_next");
KEY_PART *key_part=key_parts;
for (char *key=range_arg->max_key, *end=key+range_arg->max_length;
key < end;
key+= key_part++->part_length)
{
int cmp;
if (key_part->null_bit)
for (;;)
{
if (*key++)
int result;
if (range)
{
if (!key_part->field->is_null())
return 1;
continue;
}
else if (key_part->field->is_null())
return 0;
// Already read through key
result= file->index_next_same(record, (byte*) range->min_key,
range->min_length);
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
}
if ((cmp=key_part->field->key_cmp((byte*) key, key_part->part_length)) < 0)
return 0;
if (cmp > 0)
return 1;
if (!(range= it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
result= file->index_read(record,
(byte*) range->min_key,
range->min_length,
(ha_rkey_function)(range->flag ^ GEOM_FLAG));
if (result != HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(result);
range=0; // Not found, to next range
}
return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match
}
......@@ -2841,15 +2819,18 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
return 0; /* key can't be to small */
KEY_PART *key_part = key_parts;
uint store_length;
for (char *key = range_arg->min_key, *end = key + range_arg->min_length;
key < end;
key += key_part++->part_length)
key += store_length, key_part++)
{
int cmp;
store_length= key_part->store_length;
if (key_part->null_bit)
{
// this key part allows null values; NULL is lower than everything else
if (*key++)
if (*key)
{
// the range is expecting a null value
if (!key_part->field->is_null())
......@@ -2858,9 +2839,11 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
}
else if (key_part->field->is_null())
return 1; // null -- outside the range
key++;
store_length--;
}
if ((cmp = key_part->field->key_cmp((byte*) key,
key_part->part_length)) > 0)
key_part->length)) > 0)
return 0;
if (cmp < 0)
return 1;
......@@ -2888,23 +2871,20 @@ bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg)
bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
uint used_key_parts)
{
uint offset,end;
uint offset, end;
KEY_PART *key_part = key_parts,
*key_part_end= key_part+used_key_parts;
for (offset= 0, end = min(range_arg->min_length, range_arg->max_length) ;
offset < end && key_part != key_part_end ;
offset += key_part++->part_length)
offset+= key_part++->store_length)
{
uint null_length=test(key_part->null_bit);
if (!memcmp((char*) range_arg->min_key+offset,
(char*) range_arg->max_key+offset,
key_part->part_length + null_length))
{
offset+=null_length;
key_part->store_length))
continue;
}
if (null_length && range_arg->min_key[offset])
if (key_part->null_bit && range_arg->min_key[offset])
return 1; // min_key is null and max_key isn't
// Range doesn't cover NULL. This is ok if there is no more null parts
break;
......@@ -2946,33 +2926,34 @@ static void
print_key(KEY_PART *key_part,const char *key,uint used_length)
{
char buff[1024];
const char *key_end= key+used_length;
String tmp(buff,sizeof(buff),&my_charset_bin);
uint store_length;
for (uint length=0;
length < used_length ;
length+=key_part->part_length, key+=key_part->part_length, key_part++)
for (; key < key_end; key+=store_length, key_part++)
{
Field *field=key_part->field;
if (length != 0)
fputc('/',DBUG_FILE);
Field *field= key_part->field;
store_length= key_part->store_length;
if (field->real_maybe_null())
{
length++; // null byte is not in part_length
if (*key++)
if (*key)
{
fwrite("NULL",sizeof(char),4,DBUG_FILE);
continue;
}
key++; // Skip null byte
store_length--;
}
field->set_key_image((char*) key,key_part->part_length -
((field->type() == FIELD_TYPE_BLOB) ?
HA_KEY_BLOB_LENGTH : 0),
field->charset());
field->set_key_image((char*) key, key_part->length, field->charset());
field->val_str(&tmp);
fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE);
if (key+store_length < key_end)
fputc('/',DBUG_FILE);
}
}
static void print_quick(QUICK_SELECT *quick,const key_map* needed_reg)
{
QUICK_RANGE *range;
......
......@@ -35,7 +35,7 @@
typedef struct st_key_part {
uint16 key,part,part_length;
uint16 key,part, store_length, length;
uint8 null_bit;
Field *field;
Field::imagetype image_type;
......@@ -68,7 +68,7 @@ class QUICK_RANGE :public Sql_alloc {
class QUICK_SELECT {
public:
bool next,dont_free;
bool next,dont_free,sorted;
int error;
uint index, max_used_key_length, used_key_parts;
TABLE *head;
......@@ -89,11 +89,20 @@ class QUICK_SELECT {
int init() { return error=file->index_init(index); }
virtual int get_next();
virtual bool reverse_sorted() { return 0; }
int cmp_next(QUICK_RANGE *range);
bool unique_key_range();
};
class QUICK_SELECT_GEOM: public QUICK_SELECT
{
public:
QUICK_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg, bool no_alloc)
:QUICK_SELECT(thd, table, index_arg, no_alloc)
{};
virtual int get_next();
};
class QUICK_SELECT_DESC: public QUICK_SELECT
{
public:
......
......@@ -260,6 +260,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->proc_info="update";
if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
/*
let's *try* to start bulk inserts. It won't necessary
start them as values_list.elements should be greater than
some - handler dependent - threshold.
So we call start_bulk_insert to perform nesessary checks on
values_list.elements, and - if nothing else - to initialize
the code to make the call of end_bulk_insert() below safe.
*/
if (lock_type != TL_WRITE_DELAYED)
table->file->start_bulk_insert(values_list.elements);
......
......@@ -4907,6 +4907,52 @@ Item * all_any_subquery_creator(Item *left_expr,
}
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
the proper arguments. This isn't very fast but it should work for most
cases.
In the future ALTER TABLE will notice that only added indexes
and create these one by one for the existing table without having to do
a full rebuild.
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
{
List<create_field> fields;
List<Alter_drop> drop;
List<Alter_column> alter;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_ADD_INDEX, DUP_ERROR));
}
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
{
List<create_field> fields;
List<Key> keys;
List<Alter_column> alter;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_drop_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_DROP_INDEX, DUP_ERROR));
}
/*
Multi update query pre-check
......
......@@ -3746,7 +3746,8 @@ make_join_readinfo(JOIN *join, uint options)
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
else if (!table->used_keys.is_clear_all() && ! (tab->select && tab->select->quick))
else if (!table->used_keys.is_clear_all() &&
!(tab->select && tab->select->quick))
{ // Only read index tree
tab->index=find_shortest_key(table, & table->used_keys);
tab->table->file->index_init(tab->index);
......@@ -6907,6 +6908,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
key_part_end=key_part+table->key_info[idx].key_parts;
key_part_map const_key_parts=table->const_key_parts[idx];
int reverse=0;
DBUG_ENTER("test_if_order_by_key");
for (; order ; order=order->next, const_key_parts>>=1)
{
......@@ -6917,25 +6919,24 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
Skip key parts that are constants in the WHERE clause.
These are already skipped in the ORDER BY by const_expression_in_where()
*/
while (const_key_parts & 1)
{
key_part++; const_key_parts>>=1;
}
for (; const_key_parts & 1 ; const_key_parts>>= 1)
key_part++;
if (key_part == key_part_end || key_part->field != field)
return 0;
DBUG_RETURN(0);
/* set flag to 1 if we can use read-next on key, else to -1 */
flag=(order->asc == !(key_part->key_part_flag & HA_REVERSE_SORT))
? 1 : -1;
flag= ((order->asc == !(key_part->key_part_flag & HA_REVERSE_SORT)) ? 1 : -1);
if (reverse && flag != reverse)
return 0;
DBUG_RETURN(0);
reverse=flag; // Remember if reverse
key_part++;
}
*used_key_parts= (uint) (key_part - table->key_info[idx].key_part);
return reverse;
DBUG_RETURN(reverse);
}
static uint find_shortest_key(TABLE *table, const key_map *usable_keys)
{
uint min_length= (uint) ~0;
......@@ -6958,18 +6959,20 @@ static uint find_shortest_key(TABLE *table, const key_map *usable_keys)
}
/*
Test if a second key is the subkey of the first one.
SYNOPSIS
is_subkey()
key_part - first key parts
ref_key_part - second key parts
ref_key_part_end - last+1 part of the second key
DESCRIPTION
Test if a second key is the subkey of the first one.
key_part First key parts
ref_key_part Second key parts
ref_key_part_end Last+1 part of the second key
NOTE
Second key MUST be shorter than the first one.
RETURN
1 - is the subkey
0 - otherwise
1 is a subkey
0 no sub key
*/
inline bool
......@@ -6983,20 +6986,21 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
}
/*
Test if we can use one of the 'usable_keys' instead of 'ref' key for sorting
SYNOPSIS
test_if_subkey()
ref - number of key, used for WHERE clause
usable_keys - keys for testing
DESCRIPTION
Test if we can use one of the 'usable_keys' instead of 'ref' key.
ref Number of key, used for WHERE clause
usable_keys Keys for testing
RETURN
MAX_KEY - if we can't use other key
the number of found key - otherwise
MAX_KEY If we can't use other key
the number of found key Otherwise
*/
static uint
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
const key_map& usable_keys)
const key_map *usable_keys)
{
uint nr;
uint min_length= (uint) ~0;
......@@ -7007,7 +7011,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
for (nr= 0 ; nr < table->keys ; nr++)
{
if (usable_keys.is_set(nr) &&
if (usable_keys->is_set(nr) &&
table->key_info[nr].key_length < min_length &&
table->key_info[nr].key_parts >= ref_key_parts &&
is_subkey(table->key_info[nr].key_part, ref_key_part,
......@@ -7051,12 +7055,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
{
usable_keys.clear_all();
break;
DBUG_RETURN(0);
}
usable_keys.intersect(
((Item_field*) (*tmp_order->item))->field->part_of_sortkey);
usable_keys.intersect(((Item_field*) (*tmp_order->item))->
field->part_of_sortkey);
if (usable_keys.is_clear_all())
break; // No usable keys
DBUG_RETURN(0); // No usable keys
}
ref_key= -1;
......@@ -7092,9 +7096,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
keys
*/
if (table->used_keys.is_set(ref_key))
usable_keys.merge(table->used_keys);
usable_keys.intersect(table->used_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
usable_keys)) < MAX_KEY)
&usable_keys)) < MAX_KEY)
{
/* Found key that can be used to retrieve data in sorted order */
if (tab->ref.key >= 0)
......@@ -7154,6 +7158,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/* fall through */
}
}
else if (select && select->quick)
select->quick->sorted= 1;
DBUG_RETURN(1); /* No need to sort */
}
}
......@@ -7292,9 +7298,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
For impossible ranges (like when doing a lookup on NULL on a NOT NULL
field, quick will contain an empty record set.
*/
if (!(select->quick= tab->type == JT_FT ?
if (!(select->quick= (tab->type == JT_FT ?
new FT_SELECT(thd, table, tab->ref.key) :
get_quick_select_for_ref(thd, table, &tab->ref)))
get_quick_select_for_ref(thd, table, &tab->ref))))
goto err;
}
}
......
......@@ -289,15 +289,12 @@ int quick_rm_table(enum db_type base,const char *db,
{
char path[FN_REFLEN];
int error=0;
if (snprintf(path, sizeof(path), "%s/%s/%s%s",
mysql_data_home, db, table_name, reg_ext)>= (int)sizeof(path))
return 1;
my_snprintf(path, sizeof(path), "%s/%s/%s%s",
mysql_data_home, db, table_name, reg_ext);
unpack_filename(path,path);
if (my_delete(path,MYF(0)))
error=1; /* purecov: inspected */
if (snprintf(path, sizeof(path), "%s/%s/%s",
mysql_data_home, db, table_name)>= (int)sizeof(path))
return 1;
my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home, db, table_name);
unpack_filename(path,path);
return ha_delete_table(base,path) || error;
}
......@@ -410,7 +407,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> &fields,
List<Key> &keys, bool tmp_table, uint &db_options,
handler *file, KEY *&key_info_buffer,
uint &key_count, int select_field_count)
uint *key_count, int select_field_count)
{
const char *key_name;
create_field *sql_field,*dup_field;
......@@ -650,7 +647,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
uint tmp, key_number;
/* Calculate number of key segements */
key_count=0;
*key_count= 0;
while ((key=key_iterator++))
{
......@@ -668,7 +665,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
continue;
}
key_count++;
(*key_count)++;
tmp=max(file->max_key_parts(),MAX_REF_PARTS);
if (key->columns.elements > tmp)
{
......@@ -689,13 +686,13 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
tmp=min(file->max_keys(), MAX_KEY);
if (key_count > tmp)
if (*key_count > tmp)
{
my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
DBUG_RETURN(-1);
}
key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count);
key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)* *key_count);
key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
if (!key_info_buffer || ! key_part_info)
DBUG_RETURN(-1); // Out of memory
......@@ -907,9 +904,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
/* not a critical problem */
char warn_buff[MYSQL_ERRMSG_SIZE];
if (snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
length)>= (int)sizeof(warn_buff))
DBUG_RETURN(-1);
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
length);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_LONG_KEY, warn_buff);
}
......@@ -946,9 +942,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
/* not a critical problem */
char warn_buff[MYSQL_ERRMSG_SIZE];
if (snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
length)>= (int)sizeof(warn_buff))
DBUG_RETURN(-1);
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
length);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_LONG_KEY, warn_buff);
}
......@@ -1026,11 +1021,13 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
/* Sort keys in optimized order */
qsort((gptr) key_info_buffer, key_count, sizeof(KEY), (qsort_cmp) sort_keys);
qsort((gptr) key_info_buffer, *key_count, sizeof(KEY),
(qsort_cmp) sort_keys);
DBUG_RETURN(0);
}
/*
Create a table
......@@ -1105,23 +1102,21 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (mysql_prepare_table(thd, create_info, fields,
keys, tmp_table, db_options, file,
key_info_buffer, key_count,
key_info_buffer, &key_count,
select_field_count))
DBUG_RETURN(-1);
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
if (snprintf(path, sizeof(path), "%s%s%lx_%lx_%x%s",
my_snprintf(path, sizeof(path), "%s%s%lx_%lx_%x%s",
mysql_tmpdir, tmp_file_prefix, current_pid, thd->thread_id,
thd->tmp_table++, reg_ext)>= (int)sizeof(path))
DBUG_RETURN(-1);
thd->tmp_table++, reg_ext);
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
}
else
if (snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home, db,
alias, reg_ext)>= (int)sizeof(path))
DBUG_RETURN(-1);
my_snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home, db,
alias, reg_ext);
unpack_filename(path,path);
/* Check if table already exists */
if ((create_info->options & HA_LEX_CREATE_TMP_TABLE)
......@@ -1215,25 +1210,27 @@ static char *
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
{
char buff[MAX_FIELD_NAME],*buff_end;
int remain;
if (!check_if_keyname_exists(field_name,start,end) &&
my_strcasecmp(system_charset_info,field_name,primary_key_name))
return (char*) field_name; // Use fieldname
buff_end=strmake(buff,field_name,MAX_FIELD_NAME-4);
/*ingo 2004-04-07 only 3 chars + '\0' left, so need to limit to 2 digit*/
buff_end=strmake(buff,field_name, sizeof(buff)-4);
/*
Only 3 chars + '\0' left, so need to limit to 2 digit
This is ok as we can't have more than 100 keys anyway
*/
for (uint i=2 ; i< 100; i++)
{
remain= (int)sizeof(buff)- (buff_end- buff);
if (snprintf(buff_end, remain, "_%d", i)>= remain)
return NULL;
*buff_end= '_';
int10_to_str(i, buff_end+1, 10);
if (!check_if_keyname_exists(buff,start,end))
return sql_strdup(buff);
}
/*ingo 2004-04-07 dedicated return is inevitable*/
return NULL;
return (char*) "not_specified"; // Should never happen
}
/****************************************************************************
** Create table from a list of fields and items
****************************************************************************/
......@@ -1329,12 +1326,10 @@ mysql_rename_table(enum db_type base,
my_casedn_str(system_charset_info, tmp_to);
new_name= tmp_to;
}
if (snprintf(from, sizeof(from), "%s/%s/%s",
mysql_data_home, old_db, old_name)>= (int)sizeof(from))
DBUG_RETURN(1);
if (snprintf(to, sizeof(to), "%s/%s/%s",
mysql_data_home, new_db, new_name)>= (int)sizeof(to))
DBUG_RETURN(1);
my_snprintf(from, sizeof(from), "%s/%s/%s",
mysql_data_home, old_db, old_name);
my_snprintf(to, sizeof(to), "%s/%s/%s",
mysql_data_home, new_db, new_name);
fn_format(from,from,"","",4);
fn_format(to,to, "","",4);
......@@ -1469,9 +1464,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
reg_ext))
DBUG_RETURN(-1); // protect buffer overflow
if (snprintf(dst_path, sizeof(dst_path), "%s/%s/%s",
mysql_real_data_home, db, table_name)>= (int)sizeof(dst_path))
DBUG_RETURN(-1);
my_snprintf(dst_path, sizeof(dst_path), "%s/%s/%s",
mysql_real_data_home, db, table_name);
if (lock_and_wait_for_table_name(thd,table))
DBUG_RETURN(-1);
......@@ -1555,12 +1549,8 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
if (!my_stat(from, &stat_info, MYF(0)))
goto end; // Can't use USE_FRM flag
if (snprintf(tmp, sizeof(tmp), "%s-%lx_%lx",
from, current_pid, thd->thread_id)>= (int)sizeof(tmp))
{
error= -1;
goto end;
}
my_snprintf(tmp, sizeof(tmp), "%s-%lx_%lx",
from, current_pid, thd->thread_id);
/* If we could open the table, close it */
if (table_list->table)
......@@ -1695,9 +1685,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
protocol->store(table_name, system_charset_info);
protocol->store(operator_name, system_charset_info);
protocol->store("error", 5, system_charset_info);
if (snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
table_name)>= (int)sizeof(buff))
goto err;
my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY), table_name);
protocol->store(buff, system_charset_info);
close_thread_tables(thd);
table->table=0; // For query cache
......@@ -2019,11 +2007,9 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table,
{
if (find_temporary_table(thd, db, table_name))
goto table_exists;
if (snprintf(dst_path, sizeof(dst_path), "%s%s%lx_%lx_%x%s",
my_snprintf(dst_path, sizeof(dst_path), "%s%s%lx_%lx_%x%s",
mysql_tmpdir, tmp_file_prefix, current_pid,
thd->thread_id, thd->tmp_table++, reg_ext)>=
(int)sizeof(dst_path))
DBUG_RETURN(-1);
thd->thread_id, thd->tmp_table++, reg_ext);
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
}
else
......@@ -2081,9 +2067,8 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table,
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
if (snprintf(warn_buff, sizeof(warn_buff),
ER(ER_TABLE_EXISTS_ERROR), table_name)>= (int)sizeof(warn_buff))
DBUG_RETURN(-1);
my_snprintf(warn_buff, sizeof(warn_buff),
ER(ER_TABLE_EXISTS_ERROR), table_name);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TABLE_EXISTS_ERROR,warn_buff);
res= 0;
......@@ -2194,6 +2179,8 @@ int mysql_discard_or_import_tablespace(THD *thd,
DBUG_RETURN(error);
}
#ifdef NOT_USED
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
the proper arguments. This isn't very fast but it should work for most
......@@ -2201,7 +2188,7 @@ int mysql_discard_or_import_tablespace(THD *thd,
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
{
List<create_field> fields;
List<Alter_drop> drop;
......@@ -2214,7 +2201,7 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
TABLE *table;
Field **f_ptr;
KEY *key_info_buffer;
char path[FN_REFLEN];
char path[FN_REFLEN+1];
DBUG_ENTER("mysql_create_index");
/*
......@@ -2272,29 +2259,29 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
&create_info, table_list, table,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_ADD_INDEX, DUP_ERROR))
/*don't need to free((gptr) key_info_buffer);*/
/* Don't need to free((gptr) key_info_buffer);*/
DBUG_RETURN(-1);
}
else
{
if (table->file->add_index(table, key_info_buffer, key_count)||
(snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
table_list->db, (lower_case_table_names == 2)?
table_list->alias: table_list->real_name, reg_ext)>=
(int)sizeof(path))||
! unpack_filename(path, path)||
(my_snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
table_list->db, (lower_case_table_names == 2) ?
table_list->alias: table_list->real_name, reg_ext) >=
(int) sizeof(path)) ||
! unpack_filename(path, path) ||
mysql_create_frm(thd, path, &create_info,
fields, key_count, key_info_buffer, table->file))
/*don't need to free((gptr) key_info_buffer);*/
/* don't need to free((gptr) key_info_buffer);*/
DBUG_RETURN(-1);
}
/*don't need to free((gptr) key_info_buffer);*/
/* don't need to free((gptr) key_info_buffer);*/
DBUG_RETURN(0);
}
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop)
{
List<create_field> fields;
List<Key> keys;
......@@ -2394,47 +2381,12 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
/*don't need to free((gptr) key_numbers);*/
DBUG_RETURN(0);
}
#endif /* NOT_USED */
int mysql_add_column(THD *thd, TABLE_LIST *table_list,
List<create_field> &fields)
{
List<Alter_drop> drop;
List<Key> keys;
List<Alter_column> alter;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_add_column");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
TABLE *table;
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(-1);
DBUG_RETURN(real_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list, table,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_ADD_COLUMN, DUP_ERROR));
}
int mysql_drop_column(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
{
List<create_field> fields;
List<Key> keys;
List<Alter_column> alter;
HA_CREATE_INFO create_info;
DBUG_ENTER("mysql_drop_column");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.default_table_charset= thd->variables.collation_database;
TABLE *table;
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(-1);
DBUG_RETURN(real_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list, table,
fields, keys, drop, alter, 0, (ORDER*)0,
ALTER_DROP_COLUMN, DUP_ERROR));
}
/*
Alter table
*/
int mysql_alter_table(THD *thd,char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
......@@ -2442,69 +2394,22 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
uint order_num, ORDER *order, int alter_flags,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff,
enum tablespace_op_type tablespace_op,
bool simple_alter)
{
DBUG_ENTER("mysql_alter_table");
mysql_ha_closeall(thd, table_list);
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
if (tablespace_op != NO_TABLESPACE_OP)
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
tablespace_op));
if (alter_flags == ALTER_ADD_INDEX)
DBUG_RETURN(mysql_create_index(thd, table_list, keys));
if (alter_flags == ALTER_DROP_INDEX)
DBUG_RETURN(mysql_drop_index(thd, table_list, drop_list));
if (alter_flags == ALTER_ADD_COLUMN)
DBUG_RETURN(mysql_add_column(thd, table_list, fields));
if (alter_flags == ALTER_DROP_COLUMN)
DBUG_RETURN(mysql_drop_column(thd, table_list, drop_list));
TABLE *table;
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(-1);
DBUG_RETURN(real_alter_table(thd, new_db, new_name,
create_info, table_list, table, fields,
keys, drop_list, alter_list,
order_num, order, alter_flags,
handle_duplicates, keys_onoff,
tablespace_op, simple_alter));
}
int real_alter_table(THD *thd,char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
TABLE *table,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
uint order_num, ORDER *order, int alter_flags,
uint order_num, ORDER *order, uint alter_flags,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff,
enum tablespace_op_type tablespace_op,
bool simple_alter)
{
TABLE *new_table;
TABLE *table,*new_table;
int error;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
char index_file[FN_REFLEN], data_file[FN_REFLEN];
bool use_timestamp=0;
ha_rows copied,deleted;
ulonglong next_insert_id;
uint db_create_options, used_fields;
enum db_type old_db_type,new_db_type;
DBUG_ENTER("real_alter_table");
DBUG_ENTER("mysql_alter_table");
thd->proc_info="init";
table_name=table_list->real_name;
......@@ -2512,11 +2417,18 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
db=table_list->db;
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
{
new_db= db;
}
used_fields=create_info->used_fields;
mysql_ha_closeall(thd, table_list);
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
if (tablespace_op != NO_TABLESPACE_OP)
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
tablespace_op));
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(-1);
/* Check that we are not trying to rename to an existing table */
if (new_name)
{
......@@ -2627,7 +2539,7 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
break;
}
}
if (error==HA_ERR_WRONG_COMMAND)
if (error == HA_ERR_WRONG_COMMAND)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
......@@ -2648,7 +2560,7 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
else
{
table->file->print_error(error, MYF(0));
error=-1;
error= -1;
}
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
......@@ -2716,8 +2628,6 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
if (def)
{ // Field is changed
def->field=field;
if (def->sql_type == FIELD_TYPE_TIMESTAMP)
use_timestamp=1;
if (!def->after)
{
create_list.push_back(def);
......@@ -2727,8 +2637,6 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
else
{ // Use old field value
create_list.push_back(def=new create_field(field,field));
if (def->sql_type == FIELD_TYPE_TIMESTAMP)
use_timestamp=1;
alter_it.rewind(); // Change default if ALTER
Alter_column *alter;
while ((alter=alter_it++))
......@@ -2891,9 +2799,8 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
}
db_create_options=table->db_create_options & ~(HA_OPTION_PACK_RECORD);
if (snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
current_pid, thd->thread_id)>= (int)sizeof(tmp_name))
goto err;
my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
current_pid, thd->thread_id);
create_info->db_type=new_db_type;
if (!create_info->comment)
create_info->comment=table->comment;
......@@ -2972,9 +2879,8 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
else
{
char path[FN_REFLEN];
if (snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
new_db, tmp_name)>= (int)sizeof(path))
goto err;
my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
new_db, tmp_name);
fn_format(path,path,"","",4);
new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
}
......@@ -3057,9 +2963,8 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
*/
thd->proc_info="rename result table";
if (snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix,
current_pid, thd->thread_id)>= (int)sizeof(old_name))
goto err;
my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix,
current_pid, thd->thread_id);
if (new_name != table_name || new_db != db)
{
if (!access(new_name_buff,F_OK))
......@@ -3182,9 +3087,8 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
shutdown.
*/
char path[FN_REFLEN];
if (snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
new_db, table_name)>= (int)sizeof(path))
goto err;
my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
new_db, table_name);
fn_format(path,path,"","",4);
table=open_temporary_table(thd, path, new_db, tmp_name,0);
if (table)
......@@ -3202,10 +3106,9 @@ int real_alter_table(THD *thd,char *new_db, char *new_name,
query_cache_invalidate3(thd, table_list, 0);
end_temporary:
if (snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
(ulong) thd->cuted_fields)>= (int)sizeof(tmp_name))
goto err;
(ulong) thd->cuted_fields);
send_ok(thd,copied+deleted,0L,tmp_name);
thd->some_tables_deleted=0;
DBUG_RETURN(0);
......
......@@ -553,7 +553,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
if (field->type() == FIELD_TYPE_BLOB ||
field->type() == FIELD_TYPE_GEOMETRY ||
field->real_type() == FIELD_TYPE_VAR_STRING)
{
if (field->type() == FIELD_TYPE_BLOB)
......
......@@ -46,8 +46,25 @@ static bool make_empty_rec(int file, enum db_type table_type,
List<create_field> &create_fields,
uint reclength,uint null_fields);
/*
Create a frm (table definition) file
SYNOPSIS
mysql_create_frm()
thd Thread handler
file_name Name of file (including database and .frm)
create_info create info parameters
create_fields Fields to create
keys number of keys to create
key_info Keys to create
db_file Handler to use. May be zero, in which case we use
create_info->db_type
RETURN
0 ok
1 error
*/
int mysql_create_frm(THD *thd, my_string file_name,
bool mysql_create_frm(THD *thd, my_string file_name,
HA_CREATE_INFO *create_info,
List<create_field> &create_fields,
uint keys, KEY *key_info,
......@@ -166,9 +183,29 @@ int mysql_create_frm(THD *thd, my_string file_name,
err2:
VOID(my_close(file,MYF(MY_WME)));
err3:
my_delete(file_name,MYF(0));
DBUG_RETURN(1);
} /* mysql_create_frm */
/*
Create a frm (table definition) file and the tables
SYNOPSIS
mysql_create_frm()
thd Thread handler
file_name Name of file (including database and .frm)
create_info create info parameters
create_fields Fields to create
keys number of keys to create
key_info Keys to create
db_file Handler to use. May be zero, in which case we use
create_info->db_type
RETURN
0 ok
1 error
*/
int rea_create_table(THD *thd, my_string file_name,
HA_CREATE_INFO *create_info,
List<create_field> &create_fields,
......@@ -179,12 +216,8 @@ int rea_create_table(THD *thd, my_string file_name,
if (mysql_create_frm(thd, file_name, create_info,
create_fields, keys, key_info, NULL) ||
ha_create_table(file_name,create_info,0))
goto err;
DBUG_RETURN(0);
err:
my_delete(file_name,MYF(0));
DBUG_RETURN(1);
DBUG_RETURN(0);
} /* rea_create_table */
......
......@@ -25,8 +25,9 @@
IMPLEMENTION:
Supports following formats:
%#d
%#u
%#[l]d
%#[l]u
%#[l]x
%#.#s Note #.# is skiped
RETURN
......@@ -47,7 +48,7 @@ int my_snprintf(char* to, size_t n, const char* fmt, ...)
int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
{
char *start=to, *end=to+n-1;
uint length, num_state, pre_zero;
uint length, num_state, pre_zero, have_long;
for (; *fmt ; fmt++)
{
......@@ -62,7 +63,7 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
/* Read max fill size (only used with %d and %u) */
if (*fmt == '-')
fmt++;
length= num_state= pre_zero= 0;
length= num_state= pre_zero= have_long= 0;
for (;; fmt++)
{
if (my_isdigit(&my_charset_latin1,*fmt))
......@@ -80,7 +81,10 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
num_state= 1;
}
if (*fmt == 'l')
{
fmt++;
have_long= 1;
}
if (*fmt == 's') /* String parameter */
{
reg2 char *par = va_arg(ap, char *);
......@@ -92,20 +96,29 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
to=strnmov(to,par,plen);
continue;
}
else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
else if (*fmt == 'd' || *fmt == 'u'|| *fmt== 'x') /* Integer parameter */
{
register int iarg;
register long larg;
uint res_length, to_length;
char *store_start= to, *store_end;
char buff[16];
char buff[32];
if ((to_length= (uint) (end-to)) < 16 || length)
store_start= buff;
iarg = va_arg(ap, int);
if (have_long)
larg = va_arg(ap, long);
else
if (*fmt == 'd')
store_end= int10_to_str((long) iarg, store_start, -10);
larg = va_arg(ap, int);
else
larg= (long) (uint) va_arg(ap, int);
if (*fmt == 'd')
store_end= int10_to_str(larg, store_start, -10);
else
if (*fmt== 'u')
store_end= int10_to_str(larg, store_start, 10);
else
store_end= int10_to_str((long) (uint) iarg, store_start, 10);
store_end= int2str(larg, store_start, 16);
if ((res_length= (uint) (store_end - store_start)) > to_length)
break; /* num doesn't fit in output */
/* If %#d syntax was used, we have to pre-zero/pre-space the string */
......@@ -146,7 +159,7 @@ static void my_printf(const char * fmt, ...)
n = my_vsnprintf(buf, sizeof(buf)-1,fmt, ar);
printf(buf);
printf("n=%d, strlen=%d\n", n, strlen(buf));
if (buf[sizeof(buf)-1] != OVERRUN_SENTRY)
if ((uchar) buf[sizeof(buf)-1] != OVERRUN_SENTRY)
{
fprintf(stderr, "Buffer overrun\n");
abort();
......@@ -167,6 +180,7 @@ int main()
my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack");
my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1);
my_printf("Hello %u\n", 1);
my_printf("Hex: %lx '%6lx'\n", 32, 65);
my_printf("conn %ld to: '%-.64s' user: '%-.32s' host:\
`%-.64s' (%-.64s)", 1, 0,0,0,0);
return 0;
......
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