summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <pem@mysql.comhem.se>2004-05-14 16:00:57 +0200
committerunknown <pem@mysql.comhem.se>2004-05-14 16:00:57 +0200
commit3a272c1fa91121d3792a558840d2b764d758f4e9 (patch)
treed27d078b95ca20c323af435a836f475562c863d0 /sql
parente9c1e75b48e5d2c0047a3e88b35667a33d6395e4 (diff)
downloadmariadb-git-3a272c1fa91121d3792a558840d2b764d758f4e9.tar.gz
Post-merge fixes.
Note: One sp.test still fails (prime), and rpl_server_id2.test fails (will be fixed by guilhem ASAP). mysql-test/r/index_merge.result: Fixed syntax error (no ',' after last index in create table any more). mysql-test/r/index_merge_bdb.result: Fixed syntax error (no ',' after last index in create table any more). mysql-test/r/index_merge_innodb.result: Fixed syntax error (no ',' after last index in create table any more). mysql-test/r/index_merge_innodb2.result: Fixed syntax error (no ',' after last index in create table any more). mysql-test/r/rpl_server_id1.result: Update result after merge. mysql-test/r/sp-error.result: Update result after merge. mysql-test/r/variables.result: Update result after merge. mysql-test/t/index_merge.test: Fixed syntax error (no ',' after last index in create table any more). mysql-test/t/index_merge_bdb.test: Fixed syntax error (no ',' after last index in create table any more). mysql-test/t/index_merge_innodb.test: Fixed syntax error (no ',' after last index in create table any more). mysql-test/t/index_merge_innodb2.test: Fixed syntax error (no ',' after last index in create table any more). mysql-test/t/sp-error.test: Post-merge fix of error codes. sql/opt_range.cc: Manually merged by Monty. sql/opt_range.h: Manually merged by Monty. sql/slave.cc: Post-merge fixes with some help from Guilhem. sql/slave.h: Post-merge fixes with some help from Guilhem. sql/sp_head.cc: Got rid of warning (reordering initialization). sql/sql_parse.cc: Post-merge fix: Need to set/reset select_limit at SP CALL time as well. tests/client_test.c: Post-merge fix: key_len length in explain has changed.
Diffstat (limited to 'sql')
-rw-r--r--sql/opt_range.cc408
-rw-r--r--sql/opt_range.h14
-rw-r--r--sql/slave.cc39
-rw-r--r--sql/slave.h8
-rw-r--r--sql/sp_head.cc4
-rw-r--r--sql/sql_parse.cc4
6 files changed, 276 insertions, 201 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3907ba866fe..28b9cd79fdd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -177,11 +177,11 @@ public:
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 @@ public:
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 @@ public:
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 &&
@@ -959,6 +959,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 */
@@ -985,24 +986,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_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->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_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;
}
@@ -1348,7 +1351,7 @@ static int get_index_merge_params(PARAM *param, key_map& needed_reg,
else
{
double n_blocks=
- ceil((double)(longlong)param->table->file->data_file_length / IO_SIZE);
+ ceil((double) ((longlong)param->table->file->data_file_length / IO_SIZE));
double busy_blocks=
n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, (double) records_for_unique));
@@ -1776,18 +1779,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)))
@@ -1800,7 +1811,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
@@ -1838,13 +1849,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)
{
/*
@@ -1853,16 +1864,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
@@ -1889,39 +1901,39 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
tree->max_flag=NO_MAX_RANGE;
break;
case Item_func::SP_EQUALS_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_DISJOINT_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_INTERSECTS_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_TOUCHES_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_CROSSES_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_WITHIN_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_CONTAINS_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
case Item_func::SP_OVERLAPS_FUNC:
- tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
- tree->max_flag=NO_MAX_RANGE;
- break;
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
default:
break;
@@ -3055,7 +3067,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);
@@ -3152,9 +3164,20 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree,
{
QUICK_RANGE_SELECT *quick;
DBUG_ENTER("get_quick_select");
- if ((quick=new QUICK_RANGE_SELECT(param->thd, param->table,
- param->real_keynr[idx],test(parent_alloc),
- parent_alloc)))
+
+
+
+ if (param->table->key_info[param->real_keynr[idx]].flags & HA_SPATIAL)
+ quick=new QUICK_RANGE_SELECT_GEOM(param->thd, param->table,
+ param->real_keynr[idx],
+ test(parent_alloc),
+ parent_alloc);
+ else
+ quick=new QUICK_RANGE_SELECT(param->thd, param->table,
+ param->real_keynr[idx],
+ test(parent_alloc), parent_alloc);
+
+ if (quick)
{
if (quick->error ||
get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0,
@@ -3194,7 +3217,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_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 &&
@@ -3314,19 +3337,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++)
- return 1;
- }
+ 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_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
@@ -3370,9 +3391,8 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
{
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 (insert_dynamic(&quick->ranges,(gptr)&range))
@@ -3539,117 +3559,88 @@ int QUICK_RANGE_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(*cur_range))
- 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 (!cur_range)
- range= *(cur_range= (QUICK_RANGE**)ranges.buffer);
+ range= *(cur_range= (QUICK_RANGE**) ranges.buffer);
else
range=
- (cur_range == ((QUICK_RANGE**)ranges.buffer + ranges.elements - 1))?
- NULL: *(++cur_range);
+ (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
+ (QUICK_RANGE*) 0 : *(++cur_range);
if (!range)
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:
- (range->flag & EQ_RANGE) ?
- HA_READ_KEY_EXACT :
- HA_READ_KEY_OR_NEXT)))
+ start_key.key= (const byte*) 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);
+ end_key.key= (const byte*) 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)
- {
- if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
- range=0; // Stop searching
- DBUG_RETURN(0); // Found key is in range
- }
- range=0; // To next range
+ 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
+
+ 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_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
+int QUICK_RANGE_SELECT_GEOM::get_next()
{
- if (range_arg->flag & NO_MAX_RANGE)
- return 0; /* key can't be to large */
+ DBUG_ENTER("QUICK_RANGE_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)
+ for (;;)
{
- int cmp;
- if (key_part->null_bit)
+ int result;
+ if (range)
{
- if (*key++)
- {
- 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 (!cur_range)
+ range= *(cur_range= (QUICK_RANGE**) ranges.buffer);
+ else
+ range=
+ (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
+ (QUICK_RANGE*) 0 : *(++cur_range);
+
+ if (!range)
+ 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
}
@@ -3834,6 +3825,47 @@ int QUICK_SELECT_DESC::get_next()
/*
+ Compare if found key is over max-value
+ Returns 0 if key <= range->max_key
+*/
+
+int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
+{
+ if (range_arg->flag & NO_MAX_RANGE)
+ return 0; /* key can't be to large */
+
+ KEY_PART *key_part=key_parts;
+ uint store_length;
+
+ for (char *key=range_arg->max_key, *end=key+range_arg->max_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 0;
+ if (cmp > 0)
+ return 1;
+ }
+ return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match
+}
+
+
+/*
Returns 0 if found key is inside range (found key >= range->min_key).
*/
@@ -3843,15 +3875,18 @@ int QUICK_RANGE_SELECT::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())
@@ -3860,9 +3895,11 @@ int QUICK_RANGE_SELECT::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;
@@ -3890,23 +3927,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;
@@ -3948,33 +3982,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->val_str(&tmp,&tmp);
+ 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_sel_imerge(QUICK_INDEX_MERGE_SELECT *quick,
const key_map *needed_reg)
{
@@ -3994,6 +4029,7 @@ static void print_quick_sel_imerge(QUICK_INDEX_MERGE_SELECT *quick,
DBUG_VOID_RETURN;
}
+
void print_quick_sel_range(QUICK_RANGE_SELECT *quick,
const key_map *needed_reg)
{
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 3c528719b29..30e0fcd7be5 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -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;
@@ -74,6 +74,7 @@ class QUICK_RANGE :public Sql_alloc {
class QUICK_SELECT_I
{
public:
+ bool sorted;
ha_rows records; /* estimate of # of records to be retrieved */
double read_time; /* time to perform this retrieval */
TABLE *head;
@@ -170,6 +171,17 @@ public:
};
+class QUICK_RANGE_SELECT_GEOM: public QUICK_RANGE_SELECT
+{
+public:
+ QUICK_RANGE_SELECT_GEOM(THD *thd, TABLE *table, uint index_arg,
+ bool no_alloc, MEM_ROOT *parent_alloc)
+ :QUICK_RANGE_SELECT(thd, table, index_arg, no_alloc, parent_alloc)
+ {};
+ virtual int get_next();
+};
+
+
/*
QUICK_INDEX_MERGE_SELECT - index_merge access method quick select.
diff --git a/sql/slave.cc b/sql/slave.cc
index 3fddc4dc783..1fe4aa40f8e 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -464,16 +464,15 @@ void init_slave_skip_errors(const char* arg)
}
-void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
- ulonglong log_pos,
- bool skip_lock)
+void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
+ bool skip_lock=0)
{
if (!skip_lock)
pthread_mutex_lock(&data_lock);
- inc_event_relay_log_pos(val);
+ inc_event_relay_log_pos();
group_relay_log_pos= event_relay_log_pos;
strmake(group_relay_log_name,event_relay_log_name,
- sizeof(group_relay_log_name)-1);
+ sizeof(group_relay_log_name)-1);
notify_group_relay_log_name_update();
@@ -487,6 +486,28 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
not advance as it should on the non-transactional slave (it advances by
big leaps, whereas it should advance by small leaps).
*/
+ /*
+ In 4.x we used the event's len to compute the positions here. This is
+ wrong if the event was 3.23/4.0 and has been converted to 5.0, because
+ then the event's len is not what is was in the master's binlog, so this
+ will make a wrong group_master_log_pos (yes it's a bug in 3.23->4.0
+ replication: Exec_master_log_pos is wrong). Only way to solve this is to
+ have the original offset of the end of the event the relay log. This is
+ what we do in 5.0: log_pos has become "end_log_pos" (because the real use
+ of log_pos in 4.0 was to compute the end_log_pos; so better to store
+ end_log_pos instead of begin_log_pos.
+ If we had not done this fix here, the problem would also have appeared
+ when the slave and master are 5.0 but with different event length (for
+ example the slave is more recent than the master and features the event
+ UID). It would give false MASTER_POS_WAIT, false Exec_master_log_pos in
+ SHOW SLAVE STATUS, and so the user would do some CHANGE MASTER using this
+ value which would lead to badly broken replication.
+ Even the relay_log_pos will be corrupted in this case, because the len is
+ the relay log is not "val".
+ With the end_log_pos solution, we avoid computations involving lengthes.
+ */
+ DBUG_PRINT("info", ("log_pos=%lld group_master_log_pos=%lld",
+ log_pos,group_master_log_pos));
if (log_pos) // 3.23 binlogs don't have log_posx
{
#if MYSQL_VERSION_ID < 50000
@@ -500,10 +521,10 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong val,
Yes this is a hack but it's just to make 3.23->4.x replication work;
3.23->5.0 replication is working much better.
*/
- group_master_log_pos= log_pos + val -
+ group_master_log_pos= log_pos -
(mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
#else
- group_master_log_pos= log_pos+ val;
+ group_master_log_pos= log_pos;
#endif /* MYSQL_VERSION_ID < 5000 */
}
pthread_cond_broadcast(&data_cond);
@@ -2540,13 +2561,13 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
goto err;
}
- int cmp_result;
-
/* The "compare and wait" main loop */
while (!thd->killed &&
init_abort_pos_wait == abort_pos_wait &&
slave_running)
{
+ bool pos_reached;
+ int cmp_result= 0;
/*
group_master_log_name can be "", if we are just after a fresh
diff --git a/sql/slave.h b/sql/slave.h
index 157111e54f0..46fe58e1976 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -283,12 +283,14 @@ typedef struct st_relay_log_info
until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
}
- inline void inc_event_relay_log_pos(ulonglong val)
+ inline void inc_event_relay_log_pos()
{
- event_relay_log_pos+= val;
+ event_relay_log_pos= future_event_relay_log_pos;
}
- void inc_group_relay_log_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0);
+ void inc_group_relay_log_pos(ulonglong log_pos,
+ bool skip_lock=0);
+
int wait_for_pos(THD* thd, String* log_name, longlong log_pos,
longlong timeout);
void close_temporary_tables();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 063474fc960..96e340fa745 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -206,8 +206,8 @@ sp_head::operator delete(void *ptr, size_t size)
}
sp_head::sp_head()
- : Sql_alloc(), m_has_return(FALSE), m_simple_case(FALSE),
- m_multi_results(FALSE), m_free_list(NULL), m_returns_cs(NULL)
+ : Sql_alloc(), m_returns_cs(NULL), m_has_return(FALSE), m_simple_case(FALSE),
+ m_multi_results(FALSE), m_free_list(NULL)
{
DBUG_ENTER("sp_head::sp_head");
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 057ea6e8bd5..598f131985c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3434,6 +3434,7 @@ unsent_create_error:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
st_sp_security_context save_ctx;
#endif
+ ha_rows select_limit;
uint smrx;
LINT_INIT(smrx);
@@ -3468,9 +3469,12 @@ unsent_create_error:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
sp_change_security_context(thd, sp, &save_ctx);
#endif
+ select_limit= thd->variables.select_limit;
+ thd->variables.select_limit= HA_POS_ERROR;
res= sp->execute_procedure(thd, &lex->value_list);
+ thd->variables.select_limit= select_limit;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
sp_restore_security_context(thd, sp, &save_ctx);
#endif