diff options
author | Mattias Jonsson <mattias.jonsson@sun.com> | 2008-10-10 12:01:01 +0200 |
---|---|---|
committer | Mattias Jonsson <mattias.jonsson@sun.com> | 2008-10-10 12:01:01 +0200 |
commit | d3ea7430152fad48cabd9efb8c80d177405dd090 (patch) | |
tree | 26c18991c89e887e3a6c706f648f8e6be6a7803f /sql/key.cc | |
parent | 9846ab0a70241945f59e1f474137546dcbd66ed8 (diff) | |
download | mariadb-git-d3ea7430152fad48cabd9efb8c80d177405dd090.tar.gz |
Bug#37721: ORDER BY when WHERE contains non-partitioned
index column
There was actually two problems
1) when clustered pk, order by non pk index should also
compare with pk as last resort to differ keys from each
other
2) bug in the index search handling in ha_partition (was
found when extending the test case
Solution to 1 was to include the pk in key compare if
clustered pk and search on other index.
Solution for 2 was to remove the optimization from
ordered scan to unordered scan if clustered pk.
mysql-test/r/partition_innodb.result:
Bug#37721: ORDER BY when WHERE contains non-partitioned
index column
updated test result.
mysql-test/t/partition_innodb.test:
Bug#37721: ORDER BY when WHERE contains non-partitioned
index column
Added test case for bug verification.
sql/ha_partition.cc:
Bug#37721: ORDER BY when WHERE contains non-partitioned
index column
using m_curr_key_info with both given index and PK
if clustered PK.
Also including PK in read_set.
Added debug prints for easier verification.
sql/ha_partition.h:
Bug#37721: ORDER BY when WHERE contains non-partitioned
index column
Changed m_curr_key_info to a null terminated array
with max 2 keys and a terminating null.
For use with key_rec_cmp with both given index and PK.
sql/key.cc:
Bug#37721: ORDER BY when WHERE contains non-partitioned
index column
added handling of a null terminated array of keys for
use in compare.
Diffstat (limited to 'sql/key.cc')
-rw-r--r-- | sql/key.cc | 144 |
1 files changed, 82 insertions, 62 deletions
diff --git a/sql/key.cc b/sql/key.cc index 47e5c5ebdd7..5b2ae8029dd 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -448,84 +448,104 @@ int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length) } -/* - Compare two records in index order - SYNOPSIS - key_rec_cmp() - key Index information - rec0 Pointer to table->record[0] - first_rec Pointer to record compare with - second_rec Pointer to record compare against first_rec - - DESCRIPTION - This method is set-up such that it can be called directly from the - priority queue and it is attempted to be optimised as much as possible - since this will be called O(N * log N) times while performing a merge - sort in various places in the code. - - We retrieve the pointer to table->record[0] using the fact that key_parts - have an offset making it possible to calculate the start of the record. - We need to get the diff to the compared record since none of the records - being compared are stored in table->record[0]. - - We first check for NULL values, if there are no NULL values we use - a compare method that gets two field pointers and a max length - and return the result of the comparison. +/** + Compare two records in index order. + + This method is set-up such that it can be called directly from the + priority queue and it is attempted to be optimised as much as possible + since this will be called O(N * log N) times while performing a merge + sort in various places in the code. + + We retrieve the pointer to table->record[0] using the fact that key_parts + have an offset making it possible to calculate the start of the record. + We need to get the diff to the compared record since none of the records + being compared are stored in table->record[0]. + + We first check for NULL values, if there are no NULL values we use + a compare method that gets two field pointers and a max length + and return the result of the comparison. + + key is a null terminated array, since in some cases (clustered + primary key) it must compare more than one index. + + @param key Null terminated array of index information + @param first_rec Pointer to record compare with + @param second_rec Pointer to record compare against first_rec + + @return Return value is SIGN(first_rec - second_rec) + @retval 0 Keys are equal + @retval -1 second_rec is greater than first_rec + @retval +1 first_rec is greater than second_rec */ -int key_rec_cmp(void *key, uchar *first_rec, uchar *second_rec) +int key_rec_cmp(void *key_p, uchar *first_rec, uchar *second_rec) { - KEY *key_info= (KEY*)key; - uint key_parts= key_info->key_parts, i= 0; + KEY **key= (KEY**) key_p; + KEY *key_info= *(key++); // Start with first key + uint key_parts, key_part_num; KEY_PART_INFO *key_part= key_info->key_part; uchar *rec0= key_part->field->ptr - key_part->offset; my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0; int result= 0; + Field *field; DBUG_ENTER("key_rec_cmp"); + /* loop over all given keys */ do { - Field *field= key_part->field; + key_parts= key_info->key_parts; + key_part= key_info->key_part; + key_part_num= 0; - if (key_part->null_bit) + /* loop over every key part */ + do { - /* The key_part can contain NULL values */ - bool first_is_null= field->is_null_in_record_with_offset(first_diff); - bool sec_is_null= field->is_null_in_record_with_offset(sec_diff); - /* - NULL is smaller then everything so if first is NULL and the other - not then we know that we should return -1 and for the opposite - we should return +1. If both are NULL then we call it equality - although it is a strange form of equality, we have equally little - information of the real value. - */ - if (!first_is_null) + field= key_part->field; + + if (key_part->null_bit) { - if (!sec_is_null) - ; /* Fall through, no NULL fields */ - else + /* The key_part can contain NULL values */ + bool first_is_null= field->is_null_in_record_with_offset(first_diff); + bool sec_is_null= field->is_null_in_record_with_offset(sec_diff); + /* + NULL is smaller then everything so if first is NULL and the other + not then we know that we should return -1 and for the opposite + we should return +1. If both are NULL then we call it equality + although it is a strange form of equality, we have equally little + information of the real value. + */ + if (!first_is_null) { - DBUG_RETURN(+1); + if (!sec_is_null) + ; /* Fall through, no NULL fields */ + else + { + DBUG_RETURN(+1); + } } + else if (!sec_is_null) + { + DBUG_RETURN(-1); + } + else + goto next_loop; /* Both were NULL */ } - else if (!sec_is_null) - { - DBUG_RETURN(-1); - } - else - goto next_loop; /* Both were NULL */ - } - /* - No null values in the fields - We use the virtual method cmp_max with a max length parameter. - For most field types this translates into a cmp without - max length. The exceptions are the BLOB and VARCHAR field types - that take the max length into account. - */ - result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff, - key_part->length); + /* + No null values in the fields + We use the virtual method cmp_max with a max length parameter. + For most field types this translates into a cmp without + max length. The exceptions are the BLOB and VARCHAR field types + that take the max length into account. + */ + if ((result= field->cmp_max(field->ptr+first_diff, field->ptr+sec_diff, + key_part->length))) + DBUG_RETURN(result); next_loop: - key_part++; - } while (!result && ++i < key_parts); - DBUG_RETURN(result); + key_part++; + key_part_num++; + } while (key_part_num < key_parts); /* this key is done */ + + key_info= *(key++); + } while (key_info); /* no more keys to test */ + DBUG_RETURN(0); } |