summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorserg@serg.mylan <>2003-10-21 11:58:43 +0200
committerserg@serg.mylan <>2003-10-21 11:58:43 +0200
commitf944fd4a65014651e130bc208563f00d668a1928 (patch)
tree8d1d6d06c790efe700899d57a87e63e8d91764f4 /sql
parent282b402813d104f7363542a2e5bb36fa5380ed38 (diff)
parent58e9369511972c7de916382d807a2632aa3c2f69 (diff)
downloadmariadb-git-f944fd4a65014651e130bc208563f00d668a1928.tar.gz
merged
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc3
-rw-r--r--sql/field.h4
-rw-r--r--sql/ha_berkeley.cc48
-rw-r--r--sql/ha_berkeley.h2
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/ha_isam.cc2
-rw-r--r--sql/ha_myisam.cc25
-rw-r--r--sql/ha_myisammrg.cc2
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc20
-rw-r--r--sql/item_cmpfunc.h1
-rw-r--r--sql/item_func.cc77
-rw-r--r--sql/item_func.h30
-rw-r--r--sql/mysql_priv.h117
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/opt_range.cc32
-rw-r--r--sql/opt_range.h2
-rw-r--r--sql/opt_sum.cc6
-rw-r--r--sql/share/english/errmsg.txt3
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_acl.cc8
-rw-r--r--sql/sql_base.cc42
-rw-r--r--sql/sql_delete.cc7
-rw-r--r--sql/sql_select.cc208
-rw-r--r--sql/sql_select.h6
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_table.cc137
-rw-r--r--sql/sql_test.cc5
-rw-r--r--sql/sql_update.cc13
-rw-r--r--sql/sql_yacc.yy18
-rw-r--r--sql/table.cc41
-rw-r--r--sql/unireg.cc27
32 files changed, 543 insertions, 353 deletions
diff --git a/sql/field.cc b/sql/field.cc
index b025f65a798..98eb0e01f56 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -181,8 +181,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
:ptr(ptr_arg),null_ptr(null_ptr_arg),
table(table_arg),table_name(table_arg ? table_arg->table_name : 0),
field_name(field_name_arg),
- query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
- unireg_check(unireg_check_arg),
+ query_id(0),unireg_check(unireg_check_arg),
field_length(length_arg),null_bit(null_bit_arg),abs_offset(0)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
diff --git a/sql/field.h b/sql/field.h
index fe5141e9d80..eb0af881121 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -151,7 +151,9 @@ public:
if (tmp->table->maybe_null)
tmp->flags&= ~NOT_NULL_FLAG;
tmp->table= new_table;
- tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0;
+ tmp->key_start.init().clear_all();
+ tmp->part_of_key.init().clear_all();
+ tmp->part_of_sortkey.init().clear_all();
tmp->unireg_check=Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 5b0fc95442c..3e5dc38e864 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -844,7 +844,7 @@ int ha_berkeley::write_row(byte * record)
ulong thd_options = table->in_use ? table->in_use->options : 0;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
- key_map changed_keys = 0;
+ key_map changed_keys;
if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
{
if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
@@ -855,7 +855,7 @@ int ha_berkeley::write_row(byte * record)
key_buff, record),
&row, key_type[primary_key])))
{
- changed_keys |= (key_map) 1 << primary_key;
+ changed_keys.set_bit(primary_key);
for (uint keynr=0 ; keynr < table->keys ; keynr++)
{
if (keynr == primary_key)
@@ -868,7 +868,7 @@ int ha_berkeley::write_row(byte * record)
last_dup_key=keynr;
break;
}
- changed_keys |= (key_map) 1 << keynr;
+ changed_keys.set_bit(keynr);
}
}
else
@@ -885,12 +885,12 @@ int ha_berkeley::write_row(byte * record)
DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
new_error=txn_abort(sub_trans); /* purecov: deadcode */
}
- else if (changed_keys)
+ else if (!changed_keys.is_clear_all())
{
new_error = 0;
- for (uint keynr=0; changed_keys; keynr++, changed_keys >>= 1)
+ for (uint keynr=0; keynr < changed_keys.length(); keynr++)
{
- if (changed_keys & 1)
+ if (changed_keys.is_set(keynr))
{
if ((new_error = remove_key(sub_trans, keynr, record,
&prim_key)))
@@ -1034,18 +1034,22 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map changed_keys,
rolled back. The last key set in changed_keys is the one that
triggered the duplicate key error (it wasn't inserted), so for
that one just put back the old value. */
- for (keynr=0; changed_keys; keynr++, changed_keys >>= 1)
+ if (!changed_keys.is_clear_all())
{
- if (changed_keys & 1)
+ key_map map1(1);
+ for (keynr=0; keynr < changed_keys.length(); keynr++)
{
- if (changed_keys != 1 &&
- (error = remove_key(trans, keynr, new_row, new_key)))
- break; /* purecov: inspected */
- if ((error = key_file[keynr]->put(key_file[keynr], trans,
- create_key(&tmp_key, keynr, key_buff2,
- old_row),
- old_key, key_type[keynr])))
- break; /* purecov: inspected */
+ if (changed_keys.is_set(keynr))
+ {
+ if (changed_keys.is_subset(map1) &&
+ (error = remove_key(trans, keynr, new_row, new_key)))
+ break; /* purecov: inspected */
+ if ((error = key_file[keynr]->put(key_file[keynr], trans,
+ create_key(&tmp_key, keynr, key_buff2,
+ old_row),
+ old_key, key_type[keynr])))
+ break; /* purecov: inspected */
+ }
}
}
@@ -1090,7 +1094,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
sub_trans = transaction;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
- key_map changed_keys = 0;
+ key_map changed_keys;
if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
{
if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
@@ -1123,7 +1127,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
}
DBUG_RETURN(error); // Fatal error /* purecov: inspected */
}
- changed_keys |= (key_map)1 << keynr;
+ changed_keys.set_bit(keynr);
if ((error=key_file[keynr]->put(key_file[keynr], sub_trans,
create_key(&key, keynr, key_buff2,
new_row),
@@ -1147,7 +1151,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
new_error=txn_abort(sub_trans); /* purecov: deadcode */
}
- else if (changed_keys)
+ else if (!changed_keys.is_clear_all())
new_error=restore_keys(transaction, changed_keys, primary_key,
old_row, &old_prim_key, new_row, &prim_key,
thd_options);
@@ -1232,9 +1236,9 @@ int ha_berkeley::remove_keys(DB_TXN *trans, const byte *record,
DBT *new_record, DBT *prim_key, key_map keys)
{
int result = 0;
- for (uint keynr=0; keys; keynr++, keys>>=1)
+ for (uint keynr=0; keynr < keys.length(); keynr++)
{
- if (keys & 1)
+ if (keys.is_set(keynr))
{
int new_error=remove_key(trans, keynr, record, prim_key);
if (new_error)
@@ -1261,7 +1265,7 @@ int ha_berkeley::delete_row(const byte * record)
DBUG_RETURN((error)); /* purecov: inspected */
create_key(&prim_key, primary_key, key_buff, record);
if (hidden_primary_key)
- keys|= (key_map) 1 << primary_key;
+ keys.set_bit(primary_key);
/* Subtransactions may be used in order to retry the delete in
case we get a DB_LOCK_DEADLOCK error. */
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index f1669e9b6c7..850be48258a 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -107,7 +107,7 @@ class ha_berkeley: public handler
uint extra_rec_buf_length() { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
ha_rows estimate_number_of_rows();
bool fast_key_read() { return 1;}
- key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
+ const key_map& keys_to_use_for_scanning() { return key_map_full; }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 0c89a9d29ce..9ef47a105d6 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -125,7 +125,7 @@ class ha_innobase: public handler
uint max_key_length() const { return((MAX_KEY_LENGTH <= 3500) ?
MAX_KEY_LENGTH : 3500);}
bool fast_key_read() { return 1;}
- key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
+ const key_map& keys_to_use_for_scanning() { return key_map_full; }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index 3acc385d251..8025e5169c8 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -202,7 +202,7 @@ void ha_isam::info(uint flag)
sortkey = info.sortkey;
block_size=nisam_block_size;
table->keys = min(table->keys,info.keys);
- table->keys_in_use= set_bits(key_map,table->keys);
+ table->keys_in_use.set_prefix(table->keys);
table->db_options_in_use= info.options;
table->db_record_offset=
(table->db_options_in_use &
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 864ee55a85f..ea356a4f17c 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -705,20 +705,21 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
DBUG_ENTER("ha_myisam::preload_keys");
- /* Check validity of the index references */
+ /* Check validity of the index references */
if (table_list->use_index)
{
- key_map kmap= get_key_map_from_key_list(table, table_list->use_index);
- if (kmap == ~(key_map) 0)
+ key_map kmap;
+ get_key_map_from_key_list(&kmap, table, table_list->use_index);
+ if (kmap.is_set_all())
{
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
- if (kmap)
- map= kmap;
+ if (!kmap.is_clear_all())
+ map= kmap.to_ulonglong();
}
-
+
mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
(void *) &thd->variables.preload_buff_size);
@@ -731,16 +732,16 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
case HA_ERR_OUT_OF_MEM:
errmsg= "Failed to allocate buffer";
break;
- default:
+ default:
char buf[ERRMSGSIZE+20];
- my_snprintf(buf, ERRMSGSIZE,
+ my_snprintf(buf, ERRMSGSIZE,
"Failed to read from index file (errno: %d)", my_errno);
errmsg= buf;
}
error= HA_ADMIN_FAILED;
goto err;
}
-
+
DBUG_RETURN(HA_ADMIN_OK);
err:
@@ -1022,9 +1023,9 @@ void ha_myisam::info(uint flag)
ref_length=info.reflength;
table->db_options_in_use = info.options;
block_size=myisam_block_size;
- table->keys_in_use= (set_bits(key_map, table->keys) &
- (key_map) info.key_map);
- table->keys_for_keyread= table->keys_in_use & ~table->read_only_keys;
+ table->keys_in_use.set_prefix(table->keys).intersect(info.key_map);
+ table->keys_for_keyread= table->keys_in_use;
+ table->keys_for_keyread.subtract(table->read_only_keys);
table->db_record_offset=info.record_offset;
if (table->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index a0449e83222..42c2ba10808 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -228,7 +228,7 @@ void ha_myisammrg::info(uint flag)
#endif
data_file_length=info.data_file_length;
errkey = info.errkey;
- table->keys_in_use= set_bits(key_map, table->keys);
+ table->keys_in_use.set_prefix(table->keys);
table->db_options_in_use = info.options;
table->is_view=1;
mean_rec_length=info.reclength;
diff --git a/sql/handler.h b/sql/handler.h
index ad209e5cec9..638125e23d0 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -241,7 +241,7 @@ public:
virtual double read_time(uint index, uint ranges, ha_rows rows)
{ return rows2double(ranges+rows); }
virtual bool fast_key_read() { return 0;}
- virtual key_map keys_to_use_for_scanning() { return 0; }
+ virtual const key_map& keys_to_use_for_scanning() { return key_map_empty; }
virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual ha_rows estimate_number_of_rows() { return records+EXTRA_RECORDS; }
diff --git a/sql/item.cc b/sql/item.cc
index ea1eaf29373..e610453e981 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -801,11 +801,11 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
not_found_field)
{
/*
- We can't find table field in table list of current select,
+ We can't find table field in table list of current select,
consequently we have to find it in outer subselect(s).
- We can't join lists of outer & current select, because of scope
- of view rules. For example if both tables (outer & current) have
- field 'field' it is not mistake to refer to this field without
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
mention of table name, but if we join tables in one list it will
cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
*/
@@ -834,8 +834,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
0)) != not_found_field)
break;
if (sl->resolve_mode == SELECT_LEX::SELECT_MODE &&
- (refer= find_item_in_list(this, sl->item_list, &counter,
- REPORT_EXCEPT_NOT_FOUND)) !=
+ (refer= find_item_in_list(this, sl->item_list, &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
(Item **) not_found_item)
break;
if (sl->master_unit()->first_select()->linkage ==
@@ -899,7 +899,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
TABLE *table=field->table;
field->query_id=thd->query_id;
table->used_fields++;
- table->used_keys&=field->part_of_key;
+ table->used_keys.intersect(field->part_of_key);
}
fixed= 1;
return 0;
@@ -908,14 +908,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type)
-{
+{
char *empty_name= (char*) "";
- tmp_field->db_name= empty_name;
+ tmp_field->db_name= empty_name;
tmp_field->org_table_name= empty_name;
tmp_field->org_col_name= empty_name;
tmp_field->table_name= empty_name;
tmp_field->col_name= name;
- tmp_field->charsetnr= collation.collation->number;
+ tmp_field->charsetnr= collation.collation->number;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
tmp_field->type=field_type;
tmp_field->length=max_length;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 42b73c48606..41e7060335c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -647,7 +647,6 @@ class Item_func_in :public Item_int_func
~Item_func_in() { delete array; delete in_item; }
optimize_type select_optimize() const
{ return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
- Item *key_item() const { return args[0]; }
void print(String *str);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 929f85a112d..5a7aada8c1d 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -81,12 +81,12 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count)
}
-bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
+bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
Item **av, uint count)
{
if (agg_arg_collations(c, av, count))
return TRUE;
-
+
if (c.derivation == DERIVATION_NONE)
{
my_coll_agg_error(av, count, func_name());
@@ -211,7 +211,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
item= *arg;
if (item->maybe_null)
maybe_null=1;
-
+
with_sum_func= with_sum_func || item->with_sum_func;
used_tables_cache|= item->used_tables();
not_null_tables_cache|= item->not_null_tables();
@@ -2554,9 +2554,13 @@ void Item_func_match::init_search(bool no_order)
DBUG_VOID_RETURN;
if (key == NO_SUCH_KEY)
+ {
+ List<Item> fields;
+ for (uint i=1; i < arg_count; i++)
+ fields.push_back(args[i]);
concat=new Item_func_concat_ws(new Item_string(" ",1,
- default_charset_info),
- fields);
+ cmp_collation.collation), fields);
+ }
if (master)
{
@@ -2568,14 +2572,19 @@ void Item_func_match::init_search(bool no_order)
}
String *ft_tmp= 0;
- char tmp1[FT_QUERY_MAXLEN];
- String tmp2(tmp1,sizeof(tmp1),default_charset_info);
// MATCH ... AGAINST (NULL) is meaningless, but possible
- if (!(ft_tmp=key_item()->val_str(&tmp2)))
+ if (!(ft_tmp=key_item()->val_str(&value)))
{
- ft_tmp= &tmp2;
- tmp2.set("",0,default_charset_info);
+ ft_tmp= &value;
+ value.set("",0,cmp_collation.collation);
+ }
+
+ if (ft_tmp->charset() != cmp_collation.collation)
+ {
+ search_value.copy(ft_tmp->ptr(), ft_tmp->length(), ft_tmp->charset(),
+ cmp_collation.collation);
+ ft_tmp= &search_value;
}
ft_handler=table->file->ft_init_ext(mode, key,
@@ -2592,7 +2601,6 @@ void Item_func_match::init_search(bool no_order)
bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- List_iterator<Item> li(fields);
Item *item;
maybe_null=1;
@@ -2604,51 +2612,37 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
modifications to find_best and auto_close as complement to auto_init code
above.
*/
- if (Item_func::fix_fields(thd, tlist, ref) || !const_item())
+ if (Item_func::fix_fields(thd, tlist, ref) || !args[0]->const_item())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST");
return 1;
}
- while ((item=li++))
+ const_item_cache=0;
+ for (uint i=1 ; i < arg_count ; i++)
{
- if (item->fix_fields(thd, tlist, li.ref()) || item->check_cols(1))
- return 1;
+ item=args[i];
if (item->type() == Item::REF_ITEM)
- li.replace(item= *((Item_ref *)item)->ref);
- if (item->type() != Item::FIELD_ITEM || !item->used_tables())
+ args[i]= item= *((Item_ref *)item)->ref;
+ if (item->type() != Item::FIELD_ITEM)
key=NO_SUCH_KEY;
used_tables_cache|=item->used_tables();
}
/* check that all columns come from the same table */
if (my_count_bits(used_tables_cache) != 1)
key=NO_SUCH_KEY;
- const_item_cache=0;
- table=((Item_field *)fields.head())->field->table;
- table->fulltext_searched=1;
- record=table->record[0];
if (key == NO_SUCH_KEY && mode != FT_BOOL)
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
return 1;
}
-
- return 0;
-}
-
-bool Item_func_match::walk(Item_processor processor, byte *arg)
-{
- List_iterator_fast<Item> li(fields);
- Item *item;
- while ((item= li++))
- if (item->walk(processor, arg))
- return 1;
- return Item_func::walk(processor, arg);
+ table=((Item_field *)item)->field->table;
+ table->fulltext_searched=1;
+ return agg_arg_collations_for_comparison(cmp_collation, args+1, arg_count-1);
}
bool Item_func_match::fix_index()
{
- List_iterator_fast<Item> li(fields);
Item_field *item;
uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, keynr;
uint max_cnt=0, mkeys=0;
@@ -2659,7 +2653,7 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr < table->keys ; keynr++)
{
if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
- (table->keys_in_use_for_query & (((key_map)1) << keynr)))
+ (table->keys_in_use_for_query.is_set(keynr)))
{
ft_to_key[fts]=keynr;
ft_cnt[fts]=0;
@@ -2670,8 +2664,9 @@ bool Item_func_match::fix_index()
if (!fts)
goto err;
- while ((item=(Item_field*)(li++)))
+ for (uint i=1; i < arg_count; i++)
{
+ item=(Item_field*)args[i];
for (keynr=0 ; keynr < fts ; keynr++)
{
KEY *ft_key=&table->key_info[ft_to_key[keynr]];
@@ -2705,8 +2700,8 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr <= mkeys ; keynr++)
{
- // for now, partial keys won't work. SerG
- if (max_cnt < fields.elements ||
+ // partial keys doesn't work
+ if (max_cnt < arg_count-1 ||
max_cnt < table->key_info[ft_to_key[keynr]].key_parts)
continue;
@@ -2721,8 +2716,7 @@ err:
key=NO_SUCH_KEY;
return 0;
}
- my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
- ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0));
+ my_error(ER_FT_MATCHING_KEY_NOT_FOUND,MYF(0));
return 1;
}
@@ -2768,7 +2762,8 @@ double Item_func_match::val()
(byte *)a->ptr(), a->length()));
}
else
- DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, record, 0));
+ DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
+ table->record[0], 0));
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 8086e65786d..33609694fe9 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -962,20 +962,18 @@ public:
class Item_func_match :public Item_real_func
{
public:
- List<Item> fields;
- String value;
- TABLE *table;
- Item_func_match *master;
- FT_INFO * ft_handler;
- Item *concat;
- byte *record;
uint key, mode;
bool join_key;
+ DTCollation cmp_collation;
+ FT_INFO *ft_handler;
+ TABLE *table;
+ Item_func_match *master; // for master-slave optimization
+ Item *concat; // Item_func_concat_ws
+ String value; // value of concat
+ String search_value; // key_item()'s value converted to cmp_collation
- Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
- fields(a), table(0), master(0), ft_handler(0),
- concat(0), key(0), join_key(0)
- {}
+ Item_func_match(List<Item> &a): Item_real_func(a),
+ table(0), master(0), ft_handler(0), concat(0), key(0), join_key(0) { }
~Item_func_match()
{
if (!master && ft_handler)
@@ -999,17 +997,13 @@ public:
bool fix_index();
void init_search(bool no_order);
-
- bool walk(Item_processor processor, byte *arg);
};
class Item_func_match_nl :public Item_func_match
{
public:
- Item_func_match_nl(List<Item> &a, Item *b)
- :Item_func_match(a,b)
- { mode=FT_NL; }
+ Item_func_match_nl(List<Item> &a) :Item_func_match(a) { mode=FT_NL; }
const char *func_name() const { return "match_nl"; }
};
@@ -1017,9 +1011,7 @@ public:
class Item_func_match_bool :public Item_func_match
{
public:
- Item_func_match_bool(List<Item> &a, Item *b)
- :Item_func_match(a,b)
- { mode=FT_BOOL; }
+ Item_func_match_bool(List<Item> &a) :Item_func_match(a) { mode=FT_BOOL; }
const char *func_name() const { return "match_bool"; }
};
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index c8d793ede29..dd5c4837663 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -30,9 +30,114 @@
#undef write /* remove pthread.h macro definition for EMX */
#endif
-typedef ulonglong table_map; /* Used for table bits in join */
-typedef ulong key_map; /* Used for finding keys */
-typedef ulong key_part_map; /* Used for finding key parts */
+template <uint default_width> class Bitmap
+{
+ MY_BITMAP map;
+ uchar buffer[(default_width+7)/8];
+public:
+ Bitmap(uint prefix_to_set=0) { init(); set_prefix(prefix_to_set); }
+ Bitmap& init()
+ {
+ bitmap_init(&map, buffer, default_width, 0);
+ return *this;
+ }
+ uint length() const { return default_width; }
+ Bitmap& operator=(const Bitmap& map2)
+ {
+ init();
+ memcpy(buffer, map2.buffer, sizeof(buffer));
+ return *this;
+ }
+ Bitmap& set_bit(uint n) { bitmap_set_bit(&map, n); return *this; }
+ Bitmap& clear_bit(uint n) { bitmap_clear_bit(&map, n); return *this; }
+ Bitmap& set_prefix(uint n) { bitmap_set_prefix(&map, n); return *this; }
+ Bitmap& set_all() { bitmap_set_all(&map); return *this;}
+ Bitmap& clear_all() { bitmap_clear_all(&map); return *this; }
+ Bitmap& intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); return *this; }
+ Bitmap& intersect(ulonglong map2buff)
+ {
+ MY_BITMAP map2;
+ bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0);
+ bitmap_intersect(&map, &map2);
+ return *this;
+ }
+ Bitmap& subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); return *this; }
+ Bitmap& merge(Bitmap& map2) { bitmap_union(&map, &map2.map); return *this; }
+ my_bool is_set(uint n) const { return bitmap_is_set((MY_BITMAP*)&map, n); }
+ my_bool is_prefix(uint n) const { return bitmap_is_prefix((MY_BITMAP*)&map, n); }
+ my_bool is_clear_all() const { return bitmap_is_clear_all((MY_BITMAP*)&map); }
+ my_bool is_set_all() const { return bitmap_is_set_all((MY_BITMAP*)&map); }
+ my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset((MY_BITMAP*)&map, (MY_BITMAP*)&map2.map); }
+ my_bool operator==(const Bitmap& map2) const { return bitmap_cmp((MY_BITMAP*)&map, (MY_BITMAP*)&map2.map); }
+ char *print(char *buf) const
+ {
+ char *s=buf; int i;
+ for (i=sizeof(buffer)-1; i>=0 ; i--)
+ {
+ if ((*s=_dig_vec[buffer[i] >> 4]) != '0')
+ break;
+ if ((*s=_dig_vec[buffer[i] & 15]) != '0')
+ break;
+ }
+ for (s++, i-- ; i>=0 ; i--)
+ {
+ *s++=_dig_vec[buffer[i] >> 4];
+ *s++=_dig_vec[buffer[i] & 15];
+ }
+ *s=0;
+ return buf;
+ }
+ ulonglong to_ulonglong() const
+ {
+ if (sizeof(buffer) >= sizeof(ulonglong))
+ return *(ulonglong*)buffer;
+ ulonglong x=0;
+ memcpy(&x, buffer, sizeof(buffer));
+ return x;
+ }
+};
+
+template <> class Bitmap<64>
+{
+ ulonglong map;
+public:
+ Bitmap(uint prefix_to_set=0) { set_prefix(prefix_to_set); }
+ Bitmap<64>& init() { return *this; }
+ uint length() const { return 64; }
+ Bitmap<64>& set_bit(uint n) { map|= ((ulonglong)1) << n; return *this; }
+ Bitmap<64>& clear_bit(uint n) { map&= ~(((ulonglong)1) << n); return *this; }
+ Bitmap<64>& set_prefix(uint n)
+ {
+ if (n >= length())
+ set_all();
+ else
+ map= (((ulonglong)1) << n)-1;
+ return *this;
+ }
+ Bitmap<64>& set_all() { map=~(ulonglong)0; return *this;}
+ Bitmap<64>& clear_all() { map=(ulonglong)0; return *this; }
+ Bitmap<64>& intersect(Bitmap<64>& map2) { map&= map2.map; return *this; }
+ Bitmap<64>& intersect(ulonglong map2) { map&= map2; return *this; }
+ Bitmap<64>& subtract(Bitmap<64>& map2) { map&= ~map2.map; return *this; }
+ Bitmap<64>& merge(Bitmap<64>& map2) { map|= map2.map; return *this; }
+ my_bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); }
+ my_bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; }
+ my_bool is_clear_all() const { return map == (ulonglong)0; }
+ my_bool is_set_all() const { return map == ~(ulonglong)0; }
+ my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
+ my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
+ char *print(char *buf) const { longlong2str(map,buf,16); return buf; }
+ ulonglong to_ulonglong() const { return map; }
+};
+
+/* TODO convert all these three maps to Bitmap classes */
+typedef ulonglong table_map; /* Used for table bits in join */
+typedef Bitmap<64> key_map; /* Used for finding keys */
+typedef ulong key_part_map; /* Used for finding key parts */
+
+/* useful constants */
+extern const key_map key_map_empty;
+extern const key_map key_map_full;
#include "mysql_com.h"
#include <violite.h>
@@ -647,8 +752,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
extern const Item **not_found_item;
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error);
-key_map get_key_map_from_key_list(TABLE *table,
- List<String> *index_list);
+void get_key_map_from_key_list(key_map *map, TABLE *table,
+ List<String> *index_list);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
List_iterator<Item> *it);
@@ -656,7 +761,7 @@ bool setup_tables(TABLE_LIST *tables);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
- List<Item> &item, bool set_query_id,
+ List<Item> &item, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func);
void unfix_item_list(List<Item> item_list);
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 8a8c3a6c32d..6cd61536944 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2159,7 +2159,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
init_global_datetime_format(DATETIME_FORMAT_TYPE, 1))
return 1;
- if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
+ if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
return 0;
}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index b356bda6112..cf1838489d0 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -305,7 +305,7 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
static QUICK_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree);
#ifndef DBUG_OFF
-static void print_quick(QUICK_SELECT *quick,key_map needed_reg);
+static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg);
#endif
static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
@@ -364,7 +364,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
{
- quick_keys=0; needed_reg=0;
my_b_clear(&file);
}
@@ -589,18 +588,18 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
uint idx;
double scan_time;
DBUG_ENTER("test_quick_select");
- DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
+/* DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
(ulong) keys_to_use, (ulong) prev_tables,
- (ulong) const_tables));
+ (ulong) const_tables));*/
delete quick;
quick=0;
- needed_reg=0; quick_keys=0;
+ needed_reg.clear_all(); quick_keys.clear_all();
if (!cond || (specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
!limit)
DBUG_RETURN(0); /* purecov: inspected */
if (!((basflag= head->file->table_flags()) & HA_KEYPOS_TO_RNDPOS) &&
- keys_to_use == (uint) ~0 || !keys_to_use)
+ keys_to_use.is_set_all() || keys_to_use.is_clear_all())
DBUG_RETURN(0); /* Not smart database */
records=head->file->records;
if (!records)
@@ -616,8 +615,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
DBUG_PRINT("info",("Time to scan table: %g", read_time));
- keys_to_use&=head->keys_in_use_for_query;
- if (keys_to_use)
+ keys_to_use.intersect(head->keys_in_use_for_query);
+ if (!keys_to_use.is_clear_all())
{
MEM_ROOT *old_root,alloc;
SEL_TREE *tree;
@@ -650,7 +649,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
for (idx=0 ; idx < head->keys ; idx++)
{
- if (!(keys_to_use & ((key_map) 1L << idx)))
+ if (!keys_to_use.is_set(idx))
continue;
KEY *key_info= &head->key_info[idx];
if (key_info->flags & HA_FULLTEXT)
@@ -666,7 +665,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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_parts->image_type =
+ key_parts->image_type =
(key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
}
param.real_keynr[param.keys++]=idx;
@@ -697,11 +696,11 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
uint keynr= param.real_keynr[idx];
if ((*key)->type == SEL_ARG::MAYBE_KEY ||
(*key)->maybe_flag)
- needed_reg|= (key_map) 1 << keynr;
+ needed_reg.set_bit(keynr);
found_records=check_quick_select(&param, idx, *key);
if (found_records != HA_POS_ERROR && found_records > 2 &&
- head->used_keys & ((table_map) 1 << keynr) &&
+ head->used_keys.is_set(keynr) &&
(head->file->index_flags(keynr) & HA_KEY_READ_ONLY))
{
/*
@@ -2128,7 +2127,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
if (records != HA_POS_ERROR)
{
uint key=param->real_keynr[idx];
- param->table->quick_keys|= (key_map) 1 << key;
+ param->table->quick_keys.set_bit(key);
param->table->quick_rows[key]=records;
param->table->quick_key_parts[key]=param->max_key_part+1;
}
@@ -2870,17 +2869,18 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
}
}
-static void print_quick(QUICK_SELECT *quick,key_map needed_reg)
+static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg)
{
QUICK_RANGE *range;
+ char buf[MAX_KEY/8+1];
DBUG_ENTER("print_param");
if (! _db_on_ || !quick)
DBUG_VOID_RETURN;
List_iterator<QUICK_RANGE> li(quick->ranges);
DBUG_LOCK_FILE;
- fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %lu):\n",
- quick->index, (ulong) needed_reg);
+ fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %s):\n",
+ quick->index, needed_reg.print(buf));
while ((range=li++))
{
if (!(range->flag & NO_MIN_RANGE))
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 128f6259055..b4d855c0faa 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -128,7 +128,7 @@ class SQL_SELECT :public Sql_alloc {
SQL_SELECT();
~SQL_SELECT();
bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
- { return test_quick_select(thd, ~0L,0,limit, force_quick_range) < 0; }
+ { return test_quick_select(thd, key_map(~0L),0,limit, force_quick_range) < 0; }
inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; }
int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
ha_rows limit, bool force_quick_range=0);
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 34cce98d087..932aceebdbb 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -683,7 +683,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
The following test is false when the key in the key tree is
converted (for example to upper case)
*/
- if (field->part_of_key & ((key_map) 1 << idx))
+ if (field->part_of_key.is_set(idx))
{
table->key_read= 1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -696,7 +696,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
return 0;
}
-
+
/*
Check whether found key is in range specified by conditions
@@ -707,7 +707,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
field in: Field used the MIN/MAX expression
cond in: WHERE condition
range_fl in: Says whether there is a condition to to be checked
- prefix_len in: Length of the constant part of the key
+ prefix_len in: Length of the constant part of the key
RETURN
0 ok
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 9a266c41669..5ccfb39478a 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -277,9 +277,10 @@ character-set=latin1
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
-"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format",
+"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
"Incorrect index name '%-.100s'",
+"Column '%-.64s' cannot be part of FULLTEXT index"
diff --git a/sql/slave.cc b/sql/slave.cc
index bb190762855..415969a2955 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -330,7 +330,7 @@ err:
void init_slave_skip_errors(const char* arg)
{
const char *p;
- if (bitmap_init(&slave_error_mask,MAX_SLAVE_ERROR,0))
+ if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0))
{
fprintf(stderr, "Badly out of memory, please check your system status\n");
exit(1);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index a27dd3999fe..7b79d1aa1b5 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3545,8 +3545,16 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
+
+ /* XXX this should not be necessary. The error message is already printed
+ by replace_xxx_table. my_error() should be use above instead of
+ sql_print_error(), and print ER_NONEXISTING_GRANT - as other grant
+ commands do */
+ /* when this code is deleted, the error slot (error 1268) can be reused,
+ as this error code was not present in any MySQL release */
if (result)
my_error(ER_REVOKE_GRANTS, MYF(0));
+
DBUG_RETURN(result);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a926c6e66fe..b151400db68 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1675,7 +1675,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
goto found;
}
}
- if (allow_rowid &&
+ if (allow_rowid &&
!my_strcasecmp(system_charset_info, name, "_rowid") &&
(field=table->rowid_field))
goto found;
@@ -1688,7 +1688,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
{
field->query_id=thd->query_id;
table->used_fields++;
- table->used_keys&= field->part_of_key;
+ table->used_keys.intersect(field->part_of_key);
}
else
thd->dupp_field=field;
@@ -1717,7 +1717,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
RETURN VALUES
0 Field is not found or field is not unique- error
message is reported
- not_found_field Function was called with report_error == FALSE and
+ not_found_field Function was called with report_error == FALSE and
field was not found. no error message reported.
found field
*/
@@ -2041,21 +2041,21 @@ bool setup_tables(TABLE_LIST *tables)
table->used_keys= table->keys_for_keyread;
if (table_list->use_index)
{
- key_map map= get_key_map_from_key_list(table,
- table_list->use_index);
- if (map == ~(key_map) 0)
+ key_map map;
+ get_key_map_from_key_list(&map, table, table_list->use_index);
+ if (map.is_set_all())
DBUG_RETURN(1);
table->keys_in_use_for_query=map;
}
if (table_list->ignore_index)
{
- key_map map= get_key_map_from_key_list(table,
- table_list->ignore_index);
- if (map == ~(key_map) 0)
+ key_map map;
+ get_key_map_from_key_list(&map, table, table_list->ignore_index);
+ if (map.is_set_all())
DBUG_RETURN(1);
- table->keys_in_use_for_query &= ~map;
+ table->keys_in_use_for_query.subtract(map);
}
- table->used_keys &= table->keys_in_use_for_query;
+ table->used_keys.intersect(table->keys_in_use_for_query);
if (table_list->shared || table->clear_query_id)
{
table->clear_query_id= 0;
@@ -2073,24 +2073,26 @@ bool setup_tables(TABLE_LIST *tables)
}
-key_map get_key_map_from_key_list(TABLE *table,
- List<String> *index_list)
+void get_key_map_from_key_list(key_map *map, TABLE *table,
+ List<String> *index_list)
{
- key_map map=0;
List_iterator_fast<String> it(*index_list);
String *name;
uint pos;
+
+ map->clear_all();
while ((name=it++))
{
if ((pos=find_type(name->c_ptr(), &table->keynames, 1+2)) <= 0)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
table->real_name);
- return (~ (key_map) 0);
+ map->set_all();
+ return;
}
- map|= ((key_map) 1) << (pos-1);
+ map->set_bit(pos-1);
}
- return map;
+ return;
}
/****************************************************************************
@@ -2135,7 +2137,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
if (field->query_id == thd->query_id)
thd->dupp_field=field;
field->query_id=thd->query_id;
- table->used_keys&= field->part_of_key;
+ table->used_keys.intersect(field->part_of_key);
}
/* All fields are used */
table->used_fields=table->fields;
@@ -2226,8 +2228,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
/* Mark field used for table cache */
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
cond_and->list.push_back(tmp);
- t1->used_keys&= t1->field[i]->part_of_key;
- t2->used_keys&= t2->field[j]->part_of_key;
+ t1->used_keys.intersect(t1->field[i]->part_of_key);
+ t2->used_keys.intersect(t2->field[j]->part_of_key);
break;
}
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 070d4cbbce9..2985f7e04a0 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -85,7 +85,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
/* Handler didn't support fast delete; Delete rows one by one */
}
- table->used_keys=table->quick_keys=0; // Can't use 'only index'
+ table->used_keys.clear_all();
+ table->quick_keys.clear_all(); // Can't use 'only index'
select=make_select(table,0,0,conds,&error);
if (error)
DBUG_RETURN(-1);
@@ -98,7 +99,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
}
/* If running in safe sql mode, don't allow updates without keys */
- if (!table->quick_keys)
+ if (table->quick_keys.is_clear_all())
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
@@ -292,7 +293,7 @@ multi_delete::initialize_tables(JOIN *join)
walk=walk->next;
/* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1;
- tbl->used_keys= 0;
+ tbl->used_keys.clear_all();
if (tbl->file->has_transactions())
log_delayed= transactional_tables= 1;
else if (tbl->tmp_table != NO_TMP_TABLE)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 9bdb989b6a1..f25b012a0fa 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -35,6 +35,9 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"ref_or_null","unique_subquery","index_subquery"
};
+const key_map key_map_empty(0);
+const key_map key_map_full(~0);
+
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse);
@@ -114,7 +117,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
-static uint find_shortest_key(TABLE *table, key_map usable_keys);
+static uint find_shortest_key(TABLE *table, const key_map& usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
@@ -831,7 +834,7 @@ JOIN::optimize()
conds,
1)));
}
-
+
}
/*
Need to tell Innobase that to play it safe, it should fetch all
@@ -1558,7 +1561,7 @@ err:
JOIN *curr_join= (join->need_tmp&&join->tmp_join?
(join->tmp_join->error=join->error,join->tmp_join):
join);
-
+
thd->proc_info="end";
err= join->cleanup();
if (thd->net.report_error)
@@ -1576,7 +1579,7 @@ err:
static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
TABLE *table,
- key_map keys,ha_rows limit)
+ const key_map& keys,ha_rows limit)
{
int error;
DBUG_ENTER("get_quick_record_count");
@@ -1638,9 +1641,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
TABLE *table;
stat_vector[i]=s;
+ s->keys.init();
+ s->const_keys.init();
+ s->checked_keys.init();
+ s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
- table->quick_keys=0;
+ table->quick_keys.clear_all();
table->reginfo.join_tab=s;
table->reginfo.not_exists_optimize=0;
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
@@ -1786,24 +1793,25 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
start_keyuse=keyuse;
key=keyuse->key;
- s->keys|= (key_map) 1 << key; // QQ: remove this ?
+ s->keys.set_bit(key); // QQ: remove this ?
- refs=const_ref=0;
- eq_part=0;
+ refs=0;
+ const_ref.clear_all();
+ eq_part.clear_all();
do
{
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
{
if (!((~found_const_table_map) & keyuse->used_tables))
- const_ref|= (key_map) 1 << keyuse->keypart;
+ const_ref.set_bit(keyuse->keypart);
else
refs|=keyuse->used_tables;
- eq_part|= (key_map) 1 << keyuse->keypart;
+ eq_part.set_bit(keyuse->keypart);
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
- if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
+ if (eq_part.is_prefix(table->key_info[key].key_parts) &&
(table->key_info[key].flags & HA_NOSAME) &&
!table->fulltext_searched)
{
@@ -1859,7 +1867,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
- if (s->const_keys)
+ if (! s->const_keys.is_clear_all())
{
ha_rows records;
SQL_SELECT *select;
@@ -2096,9 +2104,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
else
{
JOIN_TAB *stat=field->table->reginfo.join_tab;
- key_map possible_keys= (field->key_start &
- field->table->keys_in_use_for_query);
- stat[0].keys|= possible_keys; // Add possible keys
+ key_map possible_keys;
+ possible_keys=field->key_start;
+ possible_keys.intersect(field->table->keys_in_use_for_query);
+ stat[0].keys.merge(possible_keys); // Add possible keys
/*
Save the following cases:
@@ -2117,7 +2126,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
for (uint i=0; i<num_values; i++)
is_const&= (*value)->const_item();
if (is_const)
- stat[0].const_keys |= possible_keys;
+ stat[0].const_keys.merge(possible_keys);
/*
We can't always use indexes when comparing a string index to a
number. cmp_type() is checked to allow compare of dates to numbers.
@@ -2248,14 +2257,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
*/
static uint
-max_part_bit(key_map bits)
+max_part_bit(key_part_map bits)
{
uint found;
for (found=0; bits & 1 ; found++,bits>>=1) ;
return found;
}
-
static void
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
@@ -2267,7 +2275,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
for (uint key=0 ; key < form->keys ; key++)
{
- if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
+ if (!(form->keys_in_use_for_query.is_set(key)))
continue;
if (form->key_info[key].flags & HA_FULLTEXT)
continue; // ToDo: ft-keys in non-ft queries. SerG
@@ -2458,7 +2466,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* Save ptr to first use */
if (!use->table->reginfo.join_tab->keyuse)
use->table->reginfo.join_tab->keyuse=save_pos;
- use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
+ use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
@@ -2599,7 +2607,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
for (keyuse=s->keyuse ; keyuse->table == table ;)
{
- key_map found_part=0;
+ key_part_map found_part=0;
table_map found_ref=0;
uint key=keyuse->key;
KEY *keyinfo=table->key_info+key;
@@ -2668,7 +2676,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
if (!found_ref)
{ // We found a const key
- if (table->quick_keys & ((key_map) 1 << key))
+ if (table->quick_keys.is_set(key))
records= (double) table->quick_rows[key];
else
{
@@ -2692,7 +2700,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- if (table->used_keys & ((key_map) 1 << key))
+ if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@@ -2719,7 +2727,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
Check if quick_range could determinate how many rows we
will match
*/
- if (table->quick_keys & ((key_map) 1 << key) &&
+ if (table->quick_keys.is_set(key) &&
table->quick_key_parts[key] <= max_key_part)
tmp=records= (double) table->quick_rows[key];
else
@@ -2771,7 +2779,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- if (table->used_keys & ((key_map) 1 << key))
+ if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@@ -2810,7 +2818,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
!(s->quick && best_key && s->quick->index == best_key->key &&
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
- s->table->used_keys && best_key) &&
+ ! s->table->used_keys.is_clear_all() && best_key) &&
!(s->table->force_index && best_key))
{ // Check full join
ha_rows rnd_records= s->found_records;
@@ -3024,7 +3032,7 @@ get_best_combination(JOIN *join)
if (j->type == JT_SYSTEM)
continue;
- if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
+ if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
if (tablenr != join->const_tables)
@@ -3255,7 +3263,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->select_cond=0;
join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
- join_tab->keys= (uint) ~0; /* test everything in quick */
+ join_tab->keys.init().set_all(); /* test everything in quick */
join_tab->info=0;
join_tab->on_expr=0;
join_tab->ref.key = -1;
@@ -3337,13 +3345,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Use quick key read if it's a constant and it's not used
with key reading */
- if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
+ if (tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF
&& tab->type != JT_FT && (tab->type != JT_REF ||
(uint) tab->ref.key == tab->quick->index))
{
sel->quick=tab->quick; // Use value from get_quick_...
- sel->quick_keys=0;
- sel->needed_reg=0;
+ sel->quick_keys.clear_all();
+ sel->needed_reg.clear_all();
}
else
{
@@ -3354,12 +3362,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
if (i == join->const_tables && ref_key)
{
- if (tab->const_keys && tab->table->reginfo.impossible_range)
+ if (!tab->const_keys.is_clear_all() &&
+ tab->table->reginfo.impossible_range)
DBUG_RETURN(1);
}
else if (tab->type == JT_ALL && ! use_quick_range)
{
- if (tab->const_keys &&
+ if (!tab->const_keys.is_clear_all() &&
tab->table->reginfo.impossible_range)
DBUG_RETURN(1); // Impossible range
/*
@@ -3369,9 +3378,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table
*/
- if ((tab->keys & ~ tab->const_keys && i > 0) ||
- (tab->const_keys && i == join->const_tables &&
- join->unit->select_limit_cnt <
+ if ((!tab->keys.is_subset(tab->const_keys) && i > 0) ||
+ (!tab->const_keys.is_clear_all() && i == join->const_tables &&
+ join->unit->select_limit_cnt <
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
@@ -3409,13 +3418,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
else
{
sel->needed_reg=tab->needed_reg;
- sel->quick_keys=0;
+ sel->quick_keys.clear_all();
}
- if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
+ if (!sel->quick_keys.is_subset(tab->checked_keys) ||
+ !sel->needed_reg.is_subset(tab->checked_keys))
{
- tab->keys=sel->quick_keys | sel->needed_reg;
- tab->use_quick= (sel->needed_reg &&
- (!select->quick_keys ||
+ tab->keys=sel->quick_keys;
+ tab->keys.merge(sel->needed_reg);
+ tab->use_quick= (!sel->needed_reg.is_clear_all() &&
+ (select->quick_keys.is_clear_all() ||
(select->quick &&
(select->quick->records >= 100L)))) ?
2 : 1;
@@ -3480,7 +3491,7 @@ make_join_readinfo(JOIN *join, uint options)
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
- if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
+ if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -3498,7 +3509,7 @@ make_join_readinfo(JOIN *join, uint options)
delete tab->quick;
tab->quick=0;
table->file->index_init(tab->ref.key);
- if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
+ if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -3573,12 +3584,12 @@ make_join_readinfo(JOIN *join, uint options)
if (!table->no_keyread)
{
if (tab->select && tab->select->quick &&
- table->used_keys & ((key_map) 1 << tab->select->quick->index))
+ table->used_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
- else if (table->used_keys && ! (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);
@@ -3924,7 +3935,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
DBUG_ENTER("return_zero_rows");
if (select_options & SELECT_DESCRIBE)
- {
+ {
select_describe(join, false, false, false, info);
DBUG_RETURN(0);
}
@@ -4654,6 +4665,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->db_low_byte_first=1; // True for HEAP and MyISAM
table->temp_pool_slot = temp_pool_slot;
table->copy_blobs= 1;
+ table->keys_for_keyread.init();
+ table->keys_in_use.init();
+ table->read_only_keys.init();
+ table->quick_keys.init();
+ table->used_keys.init();
+ table->keys_in_use_for_query.init();
/* Calculate which type of fields we will store in the temporary table */
@@ -5853,7 +5870,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
- if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
+ if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@@ -5890,7 +5907,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
- if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
+ if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@@ -6588,18 +6605,21 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return reverse;
}
-static uint find_shortest_key(TABLE *table, key_map usable_keys)
+static uint find_shortest_key(TABLE *table, const key_map& usable_keys)
{
uint min_length= (uint) ~0;
uint best= MAX_KEY;
- for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
+ if (!usable_keys.is_clear_all())
{
- if (usable_keys & 1)
+ for (uint nr=0; nr < usable_keys.length() ; nr++)
{
- if (table->key_info[nr].key_length < min_length)
+ if (usable_keys.is_set(nr))
{
- min_length=table->key_info[nr].key_length;
- best=nr;
+ if (table->key_info[nr].key_length < min_length)
+ {
+ min_length=table->key_info[nr].key_length;
+ best=nr;
+ }
}
}
}
@@ -6645,7 +6665,7 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
static uint
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
- key_map usable_keys)
+ const key_map& usable_keys)
{
uint nr;
uint min_length= (uint) ~0;
@@ -6653,10 +6673,10 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
uint not_used;
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
-
- for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
+
+ for (nr= 0; nr < usable_keys.length(); nr++)
{
- if ((usable_keys & 1) &&
+ 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,
@@ -6694,16 +6714,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY */
- usable_keys= ~(key_map) 0;
+ usable_keys.set_all();
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
{
- usable_keys=0;
+ usable_keys.clear_all();
break;
}
- if (!(usable_keys&= (((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
}
@@ -6729,7 +6750,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
int order_direction;
uint used_key_parts;
- if (!(usable_keys & ((key_map) 1 << ref_key)))
+ if (!usable_keys.is_set(ref_key))
{
/*
We come here when ref_key is not among usable_keys
@@ -6739,8 +6760,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
- if (table->used_keys & (((key_map) 1 << ref_key)))
- usable_keys|= table->used_keys;
+ if (table->used_keys.is_set(ref_key))
+ usable_keys.merge(table->used_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
usable_keys)) < MAX_KEY)
{
@@ -6756,10 +6777,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select->quick->init();
}
ref_key= new_ref_key;
- }
+ }
}
/* Check if we get the rows in requested sorted order by using the key */
- if ((usable_keys & ((key_map) 1 << ref_key)) &&
+ if (usable_keys.is_set(ref_key) &&
(order_direction = test_if_order_by_key(order,table,ref_key,
&used_key_parts)))
{
@@ -6810,7 +6831,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/* check if we can use a key to resolve the group */
/* Tables using JT_NEXT are handled here */
uint nr;
- key_map keys=usable_keys;
+ key_map keys;
/*
If not used with LIMIT, only use keys if the whole query can be
@@ -6818,12 +6839,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
retrieving all rows through an index.
*/
if (select_limit >= table->file->records)
- keys&= (table->used_keys | table->file->keys_to_use_for_scanning());
+ {
+ keys=table->file->keys_to_use_for_scanning();
+ keys.merge(table->used_keys);
+ }
+ else
+ keys.set_all();
+
+ keys.intersect(usable_keys);
- for (nr=0; keys ; keys>>=1, nr++)
+ for (nr=0; nr < keys.length() ; nr++)
{
uint not_used;
- if (keys & 1)
+ if (keys.is_set(nr))
{
int flag;
if ((flag=test_if_order_by_key(order, table, nr, &not_used)))
@@ -6835,7 +6863,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
join_read_last);
table->file->index_init(nr);
tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->used_keys & ((key_map) 1 << nr))
+ if (table->used_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -6860,7 +6888,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
order How table should be sorted
filesort_limit Max number of rows that needs to be sorted
select_limit Max number of rows in final output
- Used to decide if we should use index or not
+ Used to decide if we should use index or not
IMPLEMENTATION
@@ -8690,7 +8718,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
Item *item_null= new Item_null();
CHARSET_INFO *cs= &my_charset_latin1;
DBUG_ENTER("select_describe");
- DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
+ DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
(ulong)join->select_lex, join->select_lex->type,
message));
/* Don't log this into the slow query log */
@@ -8724,7 +8752,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
tmp2.length(0);
item_list.empty();
- item_list.push_back(new Item_int((int32)
+ item_list.push_back(new Item_int((int32)
join->select_lex->select_number));
item_list.push_back(new Item_string(join->select_lex->type,
strlen(join->select_lex->type),
@@ -8746,21 +8774,23 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
cs));
- key_map bits;
uint j;
- for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
+ if (!tab->keys.is_clear_all())
{
- if (bits & 1)
- {
- if (tmp1.length())
- tmp1.append(',');
- tmp1.append(table->key_info[j].name);
- }
+ for (j=0 ; j < tab->keys.length() ; j++)
+ {
+ if (tab->keys.is_set(j))
+ {
+ if (tmp1.length())
+ tmp1.append(',');
+ tmp1.append(table->key_info[j].name);
+ }
+ }
}
if (tmp1.length())
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
else
- item_list.push_back(item_null);
+ item_list.push_back(item_null);
if (tab->ref.key_parts)
{
KEY *key_info=table->key_info+ tab->ref.key;
@@ -8803,10 +8833,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
join->best_positions[i]. records_read,
21));
my_bool key_read=table->key_read;
- if (tab->type == JT_NEXT &&
- ((table->used_keys & ((key_map) 1 << tab->index))))
+ if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
key_read=1;
-
+
if (tab->info)
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
else
@@ -8815,8 +8844,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
if (tab->use_quick == 2)
{
- sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
- tab->keys);
+ char buf[MAX_KEY/8+1];
+ sprintf(buff_ptr,"; Range checked for each record (index map: %s)",
+ tab->keys.print(buf));
buff_ptr=strend(buff_ptr);
}
else
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 6c17a646ee6..aa77722546d 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -29,8 +29,8 @@ typedef struct keyuse_t {
Item *val; /* or value if no field */
table_map used_tables;
uint key, keypart, optimize;
- key_map keypart_map;
- ha_rows ref_table_rows;
+ key_part_map keypart_map;
+ ha_rows ref_table_rows;
} KEYUSE;
class store_key;
@@ -96,9 +96,9 @@ typedef struct st_join_table {
key_map const_keys; /* Keys with constant part */
key_map checked_keys; /* Keys checked in find_best */
key_map needed_reg;
+ key_map keys; /* all keys with can be used */
ha_rows records,found_records,read_time;
table_map dependent,key_dependent;
- uint keys; /* all keys with can be used */
uint use_quick,index;
uint status; // Save status for cache
uint used_fields,used_fieldlength,used_blobs;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index fce25da2cd0..3be829acbda 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -939,7 +939,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
protocol->store((const char*) pos, system_charset_info);
protocol->store(table->file->index_type(i), system_charset_info);
/* Comment */
- if (!(table->keys_in_use & ((key_map) 1 << i)))
+ if (!table->keys_in_use.is_set(i))
protocol->store("disabled",8, system_charset_info);
else
protocol->store("", 0, system_charset_info);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 3d07c7e04de..7559f2a86e2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -424,7 +424,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!sql_field->charset)
sql_field->charset= create_info->table_charset;
sql_field->create_length_to_internal_length();
-
+
/* Don't pack keys in old tables if the user has requested this */
if ((sql_field->flags & BLOB_FLAG) ||
sql_field->sql_type == FIELD_TYPE_VAR_STRING &&
@@ -663,12 +663,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_info->usable_key_parts= key_number;
key_info->algorithm=key->algorithm;
- /* TODO: Add proper checks if handler supports key_type and algorithm */
if (key->type == Key::FULLTEXT)
{
if (!(file->table_flags() & HA_CAN_FULLTEXT))
{
- my_error(ER_TABLE_CANT_HANDLE_FULLTEXT, MYF(0));
+ my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
DBUG_RETURN(-1);
}
}
@@ -680,6 +679,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
checking for proper key parts number:
*/
+ /* TODO: Add proper checks if handler supports key_type and algorithm */
if (key_info->flags == HA_SPATIAL)
{
if (key_info->key_parts != 1)
@@ -704,6 +704,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
List_iterator<key_part_spec> cols(key->columns);
+ CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
it.rewind();
@@ -727,64 +728,88 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
from a data prefix, ignoring column->length).
*/
if (key->type == Key::FULLTEXT)
+ {
+ if ((sql_field->sql_type != FIELD_TYPE_STRING &&
+ sql_field->sql_type != FIELD_TYPE_VAR_STRING &&
+ !f_is_blob(sql_field->pack_flag)) ||
+ sql_field->charset == &my_charset_bin ||
+ sql_field->charset->state & MY_CS_NONTEXT || // ucs2 doesn't work yet
+ (ft_key_charset && sql_field->charset != ft_key_charset))
+ {
+ my_printf_error(ER_BAD_FT_COLUMN,ER(ER_BAD_FT_COLUMN),MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ ft_key_charset=sql_field->charset;
+ /*
+ for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
+ code anyway, and 0 (set to column width later) for char's. it has
+ to be correct col width for char's, as char data are not prefixed
+ with length (unlike blobs, where ft code takes data length from a
+ data prefix, ignoring column->length).
+ */
column->length=test(f_is_blob(sql_field->pack_flag));
+ }
else
+ {
column->length*= sql_field->charset->mbmaxlen;
- if (f_is_blob(sql_field->pack_flag))
- {
- if (!(file->table_flags() & HA_BLOB_KEY))
- {
- my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0),
- column->field_name);
- DBUG_RETURN(-1);
- }
- if (!column->length)
- {
- my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
- ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0),
- column->field_name);
- DBUG_RETURN(-1);
- }
- }
- if (key->type == Key::SPATIAL)
- {
- if (!column->length )
- {
- /*
- BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
- Lately we'll extend this code to support more dimensions
- */
- column->length=4*sizeof(double);
- }
- }
- if (!(sql_field->flags & NOT_NULL_FLAG))
- {
- if (key->type == Key::PRIMARY)
- {
- /* Implicitly set primary key fields to NOT NULL for ISO conf. */
- sql_field->flags|= NOT_NULL_FLAG;
- sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
- }
- else
- key_info->flags|= HA_NULL_PART_KEY;
- if (!(file->table_flags() & HA_NULL_KEY))
- {
- my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
- MYF(0),column->field_name);
- DBUG_RETURN(-1);
- }
- if (key->type == Key::SPATIAL)
- {
- my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
- DBUG_RETURN(-1);
- }
- }
- if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
- {
- if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY))
- auto_increment--; // Field is used
+ if (f_is_blob(sql_field->pack_flag))
+ {
+ if (!(file->table_flags() & HA_BLOB_KEY))
+ {
+ my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ if (!column->length)
+ {
+ my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
+ ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0),
+ column->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ if (key->type == Key::SPATIAL)
+ {
+ if (!column->length )
+ {
+ /*
+ BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
+ */
+ column->length=4*sizeof(double);
+ }
+ }
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ {
+ if (key->type == Key::PRIMARY)
+ {
+ /* Implicitly set primary key fields to NOT NULL for ISO conf. */
+ sql_field->flags|= NOT_NULL_FLAG;
+ sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
+ }
+ else
+ key_info->flags|= HA_NULL_PART_KEY;
+ if (!(file->table_flags() & HA_NULL_KEY))
+ {
+ my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
+ MYF(0),column->field_name);
+ DBUG_RETURN(-1);
+ }
+ if (key->type == Key::SPATIAL)
+ {
+ my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
+ {
+ if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY))
+ auto_increment--; // Field is used
+ }
}
+
key_part_info->fieldnr= field;
key_part_info->offset= (uint16) sql_field->offset;
key_part_info->key_type=sql_field->pack_flag;
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 112d42e4643..d8d6d716abe 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -173,10 +173,11 @@ TEST_join(JOIN *join)
tab->ref.key_length);
if (tab->select)
{
+ char buf[MAX_KEY/8+1];
if (tab->use_quick == 2)
fprintf(DBUG_FILE,
- " quick select checked for each record (keys: %d)\n",
- (int) tab->select->quick_keys);
+ " quick select checked for each record (keys: %s)\n",
+ tab->select->quick_keys.print(buf));
else if (tab->select->quick)
fprintf(DBUG_FILE," quick select used on key %s, length: %d\n",
form->key_info[tab->select->quick->index].name,
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e14e20b62d6..9214894e214 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -85,7 +85,7 @@ int mysql_update(THD *thd,
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys=table->keys_in_use;
- table->quick_keys=0;
+ table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
want_privilege=table->grant.want_privilege;
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
@@ -149,7 +149,7 @@ int mysql_update(THD *thd,
}
// Don't count on usage of 'only index' when calculating which key to use
- table->used_keys=0;
+ table->used_keys.clear_all();
select=make_select(table,0,0,conds,&error);
if (error ||
(select && select->check_quick(thd, safe_update, limit)) || !limit)
@@ -164,7 +164,7 @@ int mysql_update(THD *thd,
DBUG_RETURN(0);
}
/* If running in safe sql mode, don't allow updates without keys */
- if (!table->quick_keys)
+ if (table->quick_keys.is_clear_all())
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
@@ -192,7 +192,7 @@ int mysql_update(THD *thd,
matching rows before updating the table!
*/
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (old_used_keys & ((key_map) 1 << used_index))
+ if (old_used_keys.is_set(used_index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -501,8 +501,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
if (!tables_to_update)
{
- my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "You didn't specify any tables to UPDATE");
+ my_error(ER_NO_TABLES_USED, MYF(0));
DBUG_RETURN(1);
}
@@ -533,7 +532,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
update.link_in_list((byte*) tl, (byte**) &tl->next);
tl->shared= table_count++;
table->no_keyread=1;
- table->used_keys=0;
+ table->used_keys.clear_all();
table->pos_in_table_list= tl;
}
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 8491ba7675d..04f5043839f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2449,11 +2449,13 @@ simple_expr:
| singlerow_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')'
- { Select->add_ftfunc_to_list((Item_func_match *)
- ($$=new Item_func_match_nl(*$2,$5))); }
+ { $2->push_front($5);
+ Select->add_ftfunc_to_list((Item_func_match *)
+ ($$=new Item_func_match_nl(*$2))); }
| MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
- { Select->add_ftfunc_to_list((Item_func_match *)
- ($$=new Item_func_match_bool(*$2,$5))); }
+ { $2->push_front($5);
+ Select->add_ftfunc_to_list((Item_func_match *)
+ ($$=new Item_func_match_bool(*$2))); }
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
| BINARY expr %prec NEG
{
@@ -2461,10 +2463,10 @@ simple_expr:
6, &my_charset_latin1));
}
| CAST_SYM '(' expr AS cast_type ')'
- {
- $$= create_func_cast($3, $5,
+ {
+ $$= create_func_cast($3, $5,
Lex->length ? atoi(Lex->length) : -1,
- Lex->charset);
+ Lex->charset);
}
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
@@ -2967,7 +2969,7 @@ ident_list2:
opt_expr:
/* empty */ { $$= NULL; }
- | expr { $$= $1; };
+ | expr { $$= $1; };
opt_else:
/* empty */ { $$= NULL; }
diff --git a/sql/table.cc b/sql/table.cc
index be5b7edfd93..24c5b941c0b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -137,10 +137,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->raid_type= head[41];
outparam->raid_chunks= head[42];
outparam->raid_chunksize= uint4korr(head+43);
- if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0))))
- outparam->table_charset=default_charset_info; // QQ display error message?
+ outparam->table_charset=get_charset((uint) head[38],MYF(0));
null_field_first=1;
}
+ if (!outparam->table_charset) /* unknown charset in head[38] or pre-3.23 frm */
+ outparam->table_charset=default_charset_info;
outparam->db_record_offset=1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
outparam->blob_ptr_size=portable_sizeof_char_ptr;
@@ -155,10 +156,23 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
if (read_string(file,(gptr*) &disk_buff,key_info_length))
goto err_not_open; /* purecov: inspected */
- outparam->keys=keys= disk_buff[0];
- outparam->keys_for_keyread= outparam->keys_in_use= set_bits(key_map, keys);
+ if (disk_buff[1] & 0x80)
+ {
+ outparam->keys= keys= uint2korr(disk_buff) & 0x7fff;
+ outparam->key_parts= key_parts= uint2korr(disk_buff+2);
+ }
+ else
+ {
+ outparam->keys= keys= disk_buff[0];
+ outparam->key_parts= key_parts= disk_buff[1];
+ }
+ outparam->keys_for_keyread.init().set_prefix(keys);
+ outparam->keys_in_use.init().set_prefix(keys);
+ outparam->read_only_keys.init().clear_all();
+ outparam->quick_keys.init();
+ outparam->used_keys.init();
+ outparam->keys_in_use_for_query.init();
- outparam->key_parts=key_parts=disk_buff[1];
n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
n_length+uint2korr(disk_buff+4))))
@@ -263,7 +277,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
record[outparam->reclength]=0; // For purify and ->c_ptr()
outparam->rec_buff_length=rec_buff_length;
if (my_pread(file,(byte*) record,(uint) outparam->reclength,
- (ulong) (uint2korr(head+6)+uint2korr(head+14)),
+ (ulong) (uint2korr(head+6)+
+ ((uint2korr(head+14) == 0xffff ?
+ uint4korr(head+10) : uint2korr(head+14)))),
MYF(MY_NABP)))
goto err_not_open; /* purecov: inspected */
/* HACK: table->record[2] is used instead of table->default_values here */
@@ -484,8 +500,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
index_flags=outparam->file->index_flags(key);
if (!(index_flags & HA_KEY_READ_ONLY))
{
- outparam->read_only_keys|= ((key_map) 1 << key);
- outparam->keys_for_keyread&= ~((key_map) 1 << key);
+ outparam->read_only_keys.set_bit(key);
+ outparam->keys_for_keyread.clear_bit(key);
}
if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
@@ -545,7 +561,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
field->key_length() ==
keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
if (i == 0)
- field->key_start|= ((key_map) 1 << key);
+ field->key_start.set_bit(key);
if (field->key_length() == key_part->length &&
!(field->flags & BLOB_FLAG))
{
@@ -553,11 +569,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(field->key_type() != HA_KEYTYPE_TEXT ||
(!(ha_option & HA_KEY_READ_WRONG_STR) &&
!(keyinfo->flags & HA_FULLTEXT))))
- field->part_of_key|= ((key_map) 1 << key);
+ field->part_of_key.set_bit(key);
if ((field->key_type() != HA_KEYTYPE_TEXT ||
!(keyinfo->flags & HA_FULLTEXT)) &&
!(index_flags & HA_WRONG_ASCII_ORDER))
- field->part_of_sortkey|= ((key_map) 1 << key);
+ field->part_of_sortkey.set_bit(key);
}
if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
usable_parts == i)
@@ -600,7 +616,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->usable_key_parts=usable_parts; // Filesort
}
if (primary_key < MAX_KEY &&
- (outparam->keys_in_use & ((key_map) 1 << primary_key)))
+ (outparam->keys_in_use.is_set(primary_key)))
{
outparam->primary_key=primary_key;
/*
@@ -1108,6 +1124,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
int4store(fileinfo+10,length);
+ if (key_length > 0xffff) key_length=0xffff;
int2store(fileinfo+14,key_length);
int2store(fileinfo+16,reclength);
int4store(fileinfo+18,create_info->max_rows);
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 3e634f54b4f..d95aba97424 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -33,7 +33,7 @@
static uchar * pack_screens(List<create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info);
-static bool pack_header(uchar *forminfo, enum db_type table_type,
+static bool pack_header(uchar *forminfo,enum db_type table_type,
List<create_field> &create_fields,
uint info_length, uint screens, uint table_options,
handler *file);
@@ -92,15 +92,15 @@ int rea_create_table(THD *thd, my_string file_name,
DBUG_RETURN(1);
}
- uint key_buff_length=uint2korr(fileinfo+14);
- keybuff=(uchar*) my_alloca(key_buff_length);
+ uint key_buff_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
+ keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
key_info_length=pack_keys(keybuff,keys,key_info);
VOID(get_form_pos(file,fileinfo,&formnames));
if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
goto err;
maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
int2store(forminfo+2,maxlength);
- int4store(fileinfo+10,(ulong) (filepos+maxlength));
+ int4store(fileinfo+10,key_buff_length);
fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
(create_info->min_rows == 1) && (keys == 0));
int2store(fileinfo+28,key_info_length);
@@ -148,7 +148,7 @@ int rea_create_table(THD *thd, my_string file_name,
#endif
my_free((gptr) screen_buff,MYF(0));
- my_afree((gptr) keybuff);
+ my_free((gptr) keybuff, MYF(0));
VOID(my_close(file,MYF(MY_WME)));
if (ha_create_table(file_name,create_info,0))
goto err2;
@@ -156,7 +156,7 @@ int rea_create_table(THD *thd, my_string file_name,
err:
my_free((gptr) screen_buff,MYF(0));
- my_afree((gptr) keybuff);
+ my_free((gptr) keybuff, MYF(0));
VOID(my_close(file,MYF(MY_WME)));
err2:
my_delete(file_name,MYF(0));
@@ -291,10 +291,17 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
}
*(pos++)=0;
- keybuff[0]=(uchar) key_count;
- keybuff[1]=(uchar) key_parts;
- length=(uint) (keyname_pos-keybuff);
- int2store(keybuff+2,length);
+ if (key_count > 127 || key_parts > 127)
+ {
+ key_count|=0x8000;
+ int2store(keybuff,key_count);
+ int2store(keybuff+2,key_parts);
+ }
+ else
+ {
+ keybuff[0]=(uchar) key_count;
+ keybuff[1]=(uchar) key_parts;
+ }
length=(uint) (pos-keyname_pos);
int2store(keybuff+4,length);
DBUG_RETURN((uint) (pos-keybuff));