From b9008b0e1b0c9b58db2f37f037d2f8d5f7d22084 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Sun, 28 Jan 2007 21:09:54 +0100 Subject: [PATCH 01/34] BUILD scripts: s/(dist)?clean/maintainer-clean/ --- BUILD/FINISH.sh | 2 +- BUILD/compile-alpha-ccc | 4 +++- BUILD/compile-alpha-cxx | 4 +++- BUILD/compile-alpha-debug | 4 +++- BUILD/compile-dist | 2 +- BUILD/compile-hpux11-parisc2-aCC | 2 +- BUILD/compile-ia64-debug-max | 2 +- BUILD/compile-irix-mips64-mipspro | 2 +- BUILD/compile-pentium-pgcc | 4 +++- BUILD/compile-solaris-sparc-forte | 2 +- BUILD/compile-solaris-sparc-purify | 2 +- 11 files changed, 19 insertions(+), 11 deletions(-) diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh index 6f0600c9de3..142ff7eb08e 100644 --- a/BUILD/FINISH.sh +++ b/BUILD/FINISH.sh @@ -4,7 +4,7 @@ extra_configs="$extra_configs $local_infile_configs" configure="./configure $base_configs $extra_configs" commands="\ -$make -k distclean || true +$make -k maintainer-clean || true /bin/rm -rf */.deps/*.P configure config.cache storage/*/configure storage/*/config.cache autom4te.cache storage/*/autom4te.cache; path=`dirname $0` diff --git a/BUILD/compile-alpha-ccc b/BUILD/compile-alpha-ccc index 889592295b5..59ed241d51c 100755 --- a/BUILD/compile-alpha-ccc +++ b/BUILD/compile-alpha-ccc @@ -1,5 +1,7 @@ +#! /bin/sh + /bin/rm -f */.deps/*.P */*.o -make -k clean +make -k maintainer-clean /bin/rm -f */.deps/*.P */*.o /bin/rm -f config.cache mysql-*.tar.gz diff --git a/BUILD/compile-alpha-cxx b/BUILD/compile-alpha-cxx index 1624f4ed622..a1b5605ac5e 100755 --- a/BUILD/compile-alpha-cxx +++ b/BUILD/compile-alpha-cxx @@ -1,5 +1,7 @@ +#! /bin/sh + /bin/rm -f */.deps/*.P */*.o -make -k clean +make -k maintainer-clean /bin/rm -f */.deps/*.P */*.o /bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz diff --git a/BUILD/compile-alpha-debug b/BUILD/compile-alpha-debug index b565a18272f..94fe8a2b414 100755 --- a/BUILD/compile-alpha-debug +++ b/BUILD/compile-alpha-debug @@ -1,5 +1,7 @@ +#! /bin/sh + /bin/rm -f */.deps/*.P */*.o -make -k clean +make -k maintainer-clean /bin/rm -f */.deps/*.P */*.o /bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz diff --git a/BUILD/compile-dist b/BUILD/compile-dist index 0504b308ceb..0ecb386bf71 100755 --- a/BUILD/compile-dist +++ b/BUILD/compile-dist @@ -6,7 +6,7 @@ # tree can then be picked up by "make dist" to create the "pristine source # package" that is used as the basis for all other binary builds. # -test -f Makefile && make distclean +test -f Makefile && make maintainer-clean (cd storage/innobase && aclocal && autoheader && \ libtoolize --automake --force --copy && \ automake --force --add-missing --copy && autoconf) diff --git a/BUILD/compile-hpux11-parisc2-aCC b/BUILD/compile-hpux11-parisc2-aCC index c286488bb26..0e825715663 100755 --- a/BUILD/compile-hpux11-parisc2-aCC +++ b/BUILD/compile-hpux11-parisc2-aCC @@ -61,7 +61,7 @@ done set -x -make distclean +make maintainer-clean path=`dirname $0` . "$path/autorun.sh" diff --git a/BUILD/compile-ia64-debug-max b/BUILD/compile-ia64-debug-max index d1017ad506b..123bfb06300 100755 --- a/BUILD/compile-ia64-debug-max +++ b/BUILD/compile-ia64-debug-max @@ -1,4 +1,4 @@ -gmake -k clean || true +gmake -k maintainer-clean || true /bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache path=`dirname $0` diff --git a/BUILD/compile-irix-mips64-mipspro b/BUILD/compile-irix-mips64-mipspro index 0cebb4b9f5b..5e34df20c28 100755 --- a/BUILD/compile-irix-mips64-mipspro +++ b/BUILD/compile-irix-mips64-mipspro @@ -33,7 +33,7 @@ else fi set -x -make distclean +make maintainer-clean path=`dirname $0` . "$path/autorun.sh" diff --git a/BUILD/compile-pentium-pgcc b/BUILD/compile-pentium-pgcc index 411241451cf..c13a6ff14f7 100755 --- a/BUILD/compile-pentium-pgcc +++ b/BUILD/compile-pentium-pgcc @@ -1,5 +1,7 @@ +#! /bin/sh + AM_MAKEFLAGS="-j 2" -gmake -k clean || true +gmake -k maintainer-clean || true /bin/rm -f */.deps/*.P config.cache path=`dirname $0` diff --git a/BUILD/compile-solaris-sparc-forte b/BUILD/compile-solaris-sparc-forte index 7cdbff6ae4a..43f68acbbcc 100755 --- a/BUILD/compile-solaris-sparc-forte +++ b/BUILD/compile-solaris-sparc-forte @@ -1,6 +1,6 @@ #! /bin/sh -gmake -k clean || true +gmake -k maintainer-clean || true /bin/rm -f */.deps/*.P config.cache path=`dirname $0` diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify index 8c24b0db98c..547d1b69d68 100755 --- a/BUILD/compile-solaris-sparc-purify +++ b/BUILD/compile-solaris-sparc-purify @@ -31,7 +31,7 @@ do shift done -gmake -k clean || true +gmake -k maintainer-clean || true /bin/rm -f */.deps/*.P config.cache path=`dirname $0` From 24186aa176dd6e91b5f425de2eabab06b743e07c Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Sun, 28 Jan 2007 21:11:42 +0100 Subject: [PATCH 02/34] dbug: don't consider double colom (::) a separator - it can be part of a function name (Item::reset) --- dbug/dbug.c | 6 ++++-- dbug/user.r | 11 +++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/dbug/dbug.c b/dbug/dbug.c index ef63f660543..c212e9117a1 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -1995,12 +1995,14 @@ static char *DbugMalloc(size_t size) /* - * strtok lookalike - splits on ':', magically handles :\ and :/ + * strtok lookalike - splits on ':', magically handles ::, :\ and :/ */ static const char *DbugStrTok(const char *s) { - while (s[0] && (s[0] != ':' || (s[1] == '\\' || s[1] == '/'))) + const char *start=s; + while (s[0] && (s[0] != ':' || + (s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++)))) s++; return s; } diff --git a/dbug/user.r b/dbug/user.r index 3bcc0c91d1d..e41367de321 100644 --- a/dbug/user.r +++ b/dbug/user.r @@ -908,9 +908,10 @@ via the .B DBUG_PUSH or .B DBUG_SET -macros. Control string consists of colon separate flags. A flag -may take an argument or a list of arguments. If a control string -starts from a '+' sign it works +macros. Control string consists of colon separate flags. Colons +that are part of ':\\', ':/', or '::' are not considered flag +separators. A flag may take an argument or a list of arguments. +If a control string starts from a '+' sign it works .I incrementally, that is, it can modify existing state without overriding it. In such a string every flag may be preceded by a '+' or '-' to enable or disable @@ -923,9 +924,7 @@ optional. .LI a[,file] Redirect the debugger output stream and append it to the specified file. The default output stream is stderr. A null argument list -causes output to be redirected to stdout. A colon that is followed by -the '\\' or '/' is cosidered a part of the path and not a flag -separator. +causes output to be redirected to stdout. .SP 1 EX: \fCa,C:\\tmp\\log\fR .LI A[,file] From 045d7047095be717c94fd823252d513dad8c4478 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Sun, 28 Jan 2007 21:12:58 +0100 Subject: [PATCH 03/34] move intptr from my_atomic.h to my_global.h --- include/my_atomic.h | 8 -------- include/my_global.h | 10 +++++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/my_atomic.h b/include/my_atomic.h index 7b066e9b529..a1347d26401 100644 --- a/include/my_atomic.h +++ b/include/my_atomic.h @@ -134,14 +134,6 @@ make_atomic_swap(ptr) #undef _atomic_h_cleanup_ #endif -#if SIZEOF_CHARP == SIZEOF_INT -typedef int intptr; -#elif SIZEOF_CHARP == SIZEOF_LONG -typedef long intptr; -#else -#error -#endif - #define MY_ATOMIC_OK 0 #define MY_ATOMIC_NOT_1CPU 1 extern int my_atomic_initialize(); diff --git a/include/my_global.h b/include/my_global.h index f758352b46c..fe60b1b8989 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -987,7 +987,7 @@ typedef long int32; typedef unsigned long uint32; #endif #else -#error "Neither int or long is of 4 bytes width" +#error Neither int or long is of 4 bytes width #endif #if !defined(HAVE_ULONG) && !defined(__USE_MISC) @@ -1017,6 +1017,14 @@ typedef unsigned __int64 my_ulonglong; typedef unsigned long long my_ulonglong; #endif +#if SIZEOF_CHARP == SIZEOF_INT +typedef int intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG +typedef long intptr; +#else +#error sizeof(void *) is neither sizeof(int) nor sizeof(long) +#endif + #ifdef USE_RAID /* The following is done with a if to not get problems with pre-processors From a07fd5fa8ff4b5b98fbe79b8e7301d5effaf9c2f Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Mon, 29 Jan 2007 10:40:26 +0100 Subject: [PATCH 04/34] WL#3700: Handler API change: all index search methods - that is, index_read(), index_read_idx(), index_read_last(), and records_in_range() - instead of 'uint keylen' argument take 'ulonglong keypart_map', a bitmap showing which keyparts are present in the key value. Fallback method is provided for handlers that are lagging behind. --- include/heap.h | 2 +- include/my_base.h | 8 +- include/myisam.h | 7 +- include/myisammrg.h | 6 +- sql/event_db_repository.cc | 6 +- sql/ha_ndbcluster.cc | 20 +-- sql/ha_ndbcluster.h | 2 - sql/ha_partition.cc | 55 ++---- sql/ha_partition.h | 10 +- sql/handler.cc | 36 ++-- sql/handler.h | 38 +++- sql/item_subselect.cc | 6 +- sql/key.cc | 14 +- sql/log.cc | 2 +- sql/log_event.cc | 8 +- sql/mysql_priv.h | 2 +- sql/opt_range.cc | 243 ++++++++++++++++---------- sql/opt_range.h | 23 ++- sql/opt_sum.cc | 18 +- sql/slave.cc | 2 + sql/slave.h | 2 - sql/sp.cc | 7 +- sql/sql_acl.cc | 31 ++-- sql/sql_handler.cc | 6 +- sql/sql_help.cc | 5 +- sql/sql_insert.cc | 4 +- sql/sql_plugin.cc | 3 +- sql/sql_select.cc | 16 +- sql/sql_select.h | 5 + sql/sql_servers.cc | 13 +- sql/sql_servers.h | 1 - sql/sql_udf.cc | 3 +- sql/table.cc | 34 +++- sql/table.h | 1 + sql/tztime.cc | 12 +- storage/blackhole/ha_blackhole.cc | 9 +- storage/blackhole/ha_blackhole.h | 7 +- storage/example/ha_example.cc | 5 +- storage/example/ha_example.h | 2 +- storage/federated/ha_federated.cc | 5 +- storage/heap/ha_heap.cc | 13 +- storage/heap/ha_heap.h | 10 +- storage/heap/heapdef.h | 2 +- storage/heap/hp_hash.c | 12 +- storage/heap/hp_rkey.c | 4 +- storage/innobase/handler/ha_innodb.cc | 16 +- storage/myisam/ha_myisam.cc | 26 +-- storage/myisam/ha_myisam.h | 10 +- storage/myisam/mi_check.c | 2 +- storage/myisam/mi_key.c | 51 ++---- storage/myisam/mi_range.c | 42 ++--- storage/myisam/mi_rkey.c | 17 +- storage/myisam/myisamdef.h | 5 +- storage/myisam/rt_test.c | 2 +- storage/myisam/sp_test.c | 2 +- storage/myisammrg/ha_myisammrg.cc | 15 +- storage/myisammrg/ha_myisammrg.h | 10 +- storage/myisammrg/myrg_rkey.c | 6 +- 58 files changed, 483 insertions(+), 441 deletions(-) diff --git a/include/heap.h b/include/heap.h index af053341203..33bbd2f0b3f 100644 --- a/include/heap.h +++ b/include/heap.h @@ -226,7 +226,7 @@ ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key, key_range *max_key); int hp_panic(enum ha_panic_function flag); int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, - uint key_len, enum ha_rkey_function find_flag); + ulonglong keypart_map, enum ha_rkey_function find_flag); extern gptr heap_find(HP_INFO *info,int inx,const byte *key); extern int heap_check_heap(HP_INFO *info, my_bool print_status); extern byte *heap_position(HP_INFO *info); diff --git a/include/my_base.h b/include/my_base.h index 14e4e3afb44..d7cb68efd1f 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -384,9 +384,10 @@ enum ha_base_keytype { #define HA_ERR_TABLE_NEEDS_UPGRADE 164 /* The table changed in storage engine */ #define HA_ERR_TABLE_READONLY 165 /* The table is not writable */ -#define HA_ERR_AUTOINC_READ_FAILED 166/* Failed to get the next autoinc value */ -#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set the row autoinc value */ -#define HA_ERR_LAST 167 /*Copy last error nr.*/ +#define HA_ERR_AUTOINC_READ_FAILED 166 /* Failed to get next autoinc value */ +#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set row autoinc value */ +#define HA_ERR_GENERIC 168 /* Generic error */ +#define HA_ERR_LAST 168 /*Copy last error nr.*/ /* Add error numbers before HA_ERR_LAST and change it accordingly. */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) @@ -467,6 +468,7 @@ typedef struct st_key_range { const byte *key; uint length; + ulonglong keypart_map; enum ha_rkey_function flag; } key_range; diff --git a/include/myisam.h b/include/myisam.h index f763bf07719..1dd8f6f7ec4 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -274,9 +274,8 @@ extern struct st_myisam_info *mi_open(const char *name,int mode, uint wait_if_locked); extern int mi_panic(enum ha_panic_function function); extern int mi_rfirst(struct st_myisam_info *file,byte *buf,int inx); -extern int mi_rkey(struct st_myisam_info *file,byte *buf,int inx, - const byte *key, - uint key_len, enum ha_rkey_function search_flag); +extern int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, + ulonglong keypart_map, enum ha_rkey_function search_flag); extern int mi_rlast(struct st_myisam_info *file,byte *buf,int inx); extern int mi_rnext(struct st_myisam_info *file,byte *buf,int inx); extern int mi_rnext_same(struct st_myisam_info *info, byte *buf); @@ -303,7 +302,7 @@ extern int mi_extra(struct st_myisam_info *file, enum ha_extra_function function, void *extra_arg); extern int mi_reset(struct st_myisam_info *file); -extern ha_rows mi_records_in_range(struct st_myisam_info *info,int inx, +extern ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key, key_range *max_key); extern int mi_log(int activate_log); extern int mi_is_changed(struct st_myisam_info *info); diff --git a/include/myisammrg.h b/include/myisammrg.h index 6587613697a..149b72dc7e1 100644 --- a/include/myisammrg.h +++ b/include/myisammrg.h @@ -86,8 +86,8 @@ extern int myrg_rlast(MYRG_INFO *file,byte *buf,int inx); extern int myrg_rnext(MYRG_INFO *file,byte *buf,int inx); extern int myrg_rprev(MYRG_INFO *file,byte *buf,int inx); extern int myrg_rnext_same(MYRG_INFO *file,byte *buf); -extern int myrg_rkey(MYRG_INFO *file,byte *buf,int inx,const byte *key, - uint key_len, enum ha_rkey_function search_flag); +extern int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, + ulonglong keypart_map, enum ha_rkey_function search_flag); extern int myrg_rrnd(MYRG_INFO *file,byte *buf,ulonglong pos); extern int myrg_rsame(MYRG_INFO *file,byte *record,int inx); extern int myrg_update(MYRG_INFO *file,const byte *old,byte *new_rec); @@ -100,7 +100,7 @@ extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function, void *extra_arg); extern int myrg_reset(MYRG_INFO *info); extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv); -extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx, +extern ha_rows myrg_records_in_range(MYRG_INFO *info, int inx, key_range *min_key, key_range *max_key); extern ulonglong myrg_position(MYRG_INFO *info); diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index bcc7d476fff..860cb54e27f 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -288,7 +288,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, { key_copy(key_buf, event_table->record[0], key_info, key_len); if (!(ret= event_table->file->index_read(event_table->record[0], key_buf, - key_len, HA_READ_PREFIX))) + (ulonglong)1, HA_READ_PREFIX))) { DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret)); do @@ -518,7 +518,6 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not) { int ret= 0; - CHARSET_INFO *scs= system_charset_info; TABLE *table= NULL; char old_db_buf[NAME_LEN+1]; LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; @@ -844,8 +843,7 @@ Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name, key_copy(key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, key, - table->key_info->key_length, + if (table->file->index_read_idx(table->record[0], 0, key, ~ULL(0), HA_READ_KEY_EXACT)) { DBUG_PRINT("info", ("Row not found")); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 21697be83aa..cacc2a91c24 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -956,7 +956,6 @@ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) bool ha_ndbcluster::uses_blob_value() { - uint blob_fields; MY_BITMAP *bitmap; uint *blob_index, *blob_index_end; if (table_share->blob_fields == 0) @@ -1108,7 +1107,7 @@ int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab) const char **key_name= tab->s->keynames.type_names; NDBDICT *dict= ndb->getDictionary(); DBUG_ENTER("ha_ndbcluster::create_indexes"); - + for (i= 0; i < tab->s->keys; i++, key_info++, key_name++) { index_name= *key_name; @@ -3375,19 +3374,6 @@ int ha_ndbcluster::index_read(byte *buf, } -int ha_ndbcluster::index_read_idx(byte *buf, uint index_no, - const byte *key, uint key_len, - enum ha_rkey_function find_flag) -{ - statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status); - DBUG_ENTER("ha_ndbcluster::index_read_idx"); - DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len)); - close_scan(); - index_init(index_no, 0); - DBUG_RETURN(index_read(buf, key, key_len, find_flag)); -} - - int ha_ndbcluster::index_next(byte *buf) { DBUG_ENTER("ha_ndbcluster::index_next"); @@ -3554,10 +3540,10 @@ int ha_ndbcluster::close_scan() m_multi_cursor= 0; if (!m_active_cursor && !m_multi_cursor) - DBUG_RETURN(1); + DBUG_RETURN(0); NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor; - + if (m_lock_tuple) { /* diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 5b6900766b6..db94bcd24ff 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -641,8 +641,6 @@ class ha_ndbcluster: public handler int index_end(); int index_read(byte *buf, const byte *key, uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte *buf, uint index, const byte *key, uint key_len, - enum ha_rkey_function find_flag); int index_next(byte *buf); int index_prev(byte *buf); int index_first(byte *buf); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 9d4cd69be12..8b20317d1e7 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -584,7 +584,6 @@ int ha_partition::drop_partitions(const char *path) List_iterator part_it(m_part_info->partitions); char part_name_buff[FN_REFLEN]; uint no_parts= m_part_info->partitions.elements; - uint part_count= 0; uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; @@ -1075,7 +1074,6 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint no_parts= m_part_info->no_parts; uint no_subparts= m_part_info->no_subparts; uint i= 0; - LEX *lex= thd->lex; int error; DBUG_ENTER("ha_partition::handle_opt_partitions"); DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag)); @@ -1136,7 +1134,6 @@ int ha_partition::prepare_new_partition(TABLE *table, { int error; bool create_flag= FALSE; - bool open_flag= FALSE; DBUG_ENTER("prepare_new_partition"); if ((error= set_up_table_before_create(table, part_name, create_info, @@ -1245,7 +1242,6 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, handler **new_file_array; int error= 1; bool first; - bool copy_parts= FALSE; uint temp_partitions= m_part_info->temp_partitions.elements; THD *thd= current_thd; DBUG_ENTER("ha_partition::change_partitions"); @@ -2061,7 +2057,6 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) partition_element *part_elem; uint alloc_len= (m_tot_parts + 1) * sizeof(handler*); List_iterator_fast part_it(m_part_info->partitions); - THD *thd= current_thd; DBUG_ENTER("ha_partition::new_handlers_from_part_info"); if (!(m_file= (handler **) alloc_root(mem_root, alloc_len))) @@ -3327,13 +3322,14 @@ int ha_partition::index_end() */ int ha_partition::index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, + enum ha_rkey_function find_flag) { DBUG_ENTER("ha_partition::index_read"); end_range= 0; m_index_scan_type= partition_index_read; - DBUG_RETURN(common_index_read(buf, key, key_len, find_flag)); + DBUG_RETURN(common_index_read(buf, key, keypart_map, find_flag)); } @@ -3346,14 +3342,17 @@ int ha_partition::index_read(byte * buf, const byte * key, see index_read for rest */ -int ha_partition::common_index_read(byte *buf, const byte *key, uint key_len, +int ha_partition::common_index_read(byte *buf, const byte *key, + ulonglong keypart_map, enum ha_rkey_function find_flag) { int error; bool reverse_order= FALSE; + uint key_len= calculate_key_len(table, active_index, key, keypart_map); DBUG_ENTER("ha_partition::common_index_read"); memcpy((void*)m_start_key.key, key, key_len); + m_start_key.keypart_map= keypart_map; m_start_key.length= key_len; m_start_key.flag= find_flag; @@ -3481,33 +3480,6 @@ int ha_partition::common_first_last(byte *buf) } -/* - Perform index read using index where always only one row is returned - - SYNOPSIS - index_read_idx() - see index_read for rest of parameters and return values - - DESCRIPTION - Positions an index cursor to the index specified in key. Fetches the - row if any. This is only used to read whole keys. - TODO: Optimise this code to avoid index_init and index_end -*/ - -int ha_partition::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len, - enum ha_rkey_function find_flag) -{ - int res; - DBUG_ENTER("ha_partition::index_read_idx"); - - index_init(index, 0); - res= index_read(buf, key, key_len, find_flag); - index_end(); - DBUG_RETURN(res); -} - - /* Read last using key @@ -3526,14 +3498,15 @@ int ha_partition::index_read_idx(byte * buf, uint index, const byte * key, Can only be used on indexes supporting HA_READ_ORDER */ -int ha_partition::index_read_last(byte *buf, const byte *key, uint keylen) +int ha_partition::index_read_last(byte *buf, const byte *key, + ulonglong keypart_map) { DBUG_ENTER("ha_partition::index_read_last"); m_ordered= TRUE; // Safety measure end_range= 0; m_index_scan_type= partition_index_read_last; - DBUG_RETURN(common_index_read(buf, key, keylen, HA_READ_PREFIX_LAST)); + DBUG_RETURN(common_index_read(buf, key, keypart_map, HA_READ_PREFIX_LAST)); } @@ -3679,7 +3652,7 @@ int ha_partition::read_range_first(const key_range *start_key, m_index_scan_type= partition_index_read; error= common_index_read(m_rec0, start_key->key, - start_key->length, start_key->flag); + start_key->keypart_map, start_key->flag); } DBUG_RETURN(error); } @@ -3878,7 +3851,7 @@ int ha_partition::handle_unordered_scan_next_partition(byte * buf) case partition_index_read: DBUG_PRINT("info", ("index_read on partition %d", i)); error= file->index_read(buf, m_start_key.key, - m_start_key.length, + m_start_key.keypart_map, m_start_key.flag); break; case partition_index_first: @@ -3970,7 +3943,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order) case partition_index_read: error= file->index_read(rec_buf_ptr, m_start_key.key, - m_start_key.length, + m_start_key.keypart_map, m_start_key.flag); break; case partition_index_first: @@ -3984,7 +3957,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order) case partition_index_read_last: error= file->index_read_last(rec_buf_ptr, m_start_key.key, - m_start_key.length); + m_start_key.keypart_map); reverse_order= TRUE; break; default: diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 4fdf325fa06..ad5d412a6d2 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -378,9 +378,8 @@ public: any end processing needed. */ virtual int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - virtual int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); + ulonglong keypart_map, + enum ha_rkey_function find_flag); virtual int index_init(uint idx, bool sorted); virtual int index_end(); @@ -393,7 +392,8 @@ public: virtual int index_first(byte * buf); virtual int index_last(byte * buf); virtual int index_next_same(byte * buf, const byte * key, uint keylen); - virtual int index_read_last(byte * buf, const byte * key, uint keylen); + virtual int index_read_last(byte * buf, const byte * key, + ulonglong keypart_map); /* read_first_row is virtual method but is only implemented by @@ -419,7 +419,7 @@ public: private: int common_index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); + ulonglong keypart_map, enum ha_rkey_function find_flag); int common_first_last(byte * buf); int partition_scan_set_up(byte * buf, bool idx_read_flag); int handle_unordered_next(byte * buf, bool next_same); diff --git a/sql/handler.cc b/sql/handler.cc index c596556fc98..1d38411330a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -48,8 +48,6 @@ KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} }; static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root); -static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; - /* number of entries in handlertons[] */ ulong total_ha= 0; /* number of storage engines (from handlertons[]) that support 2pc */ @@ -1854,7 +1852,7 @@ int handler::update_auto_increment() nr= compute_next_insert_id(nr-1, variables); } - if (table->s->next_number_key_offset == 0) + if (table->s->next_number_keypart == 0) { /* We must defer the appending until "nr" has been possibly truncated */ append= TRUE; @@ -1976,7 +1974,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment, table->read_set); column_bitmaps_signal(); index_init(table->s->next_number_index, 1); - if (!table->s->next_number_key_offset) + if (table->s->next_number_keypart == 0) { // Autoincrement at key-start error=index_last(table->record[1]); /* @@ -1992,7 +1990,8 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment, key_copy(key, table->record[0], table->key_info + table->s->next_number_index, table->s->next_number_key_offset); - error= index_read(table->record[1], key, table->s->next_number_key_offset, + error= index_read(table->record[1], key, + make_prev_keypart_map(table->s->next_number_keypart), HA_READ_PREFIX_LAST); /* MySQL needs to call us for next row: assume we are inserting ("a",null) @@ -3103,9 +3102,9 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, multi_range_curr < multi_range_end; multi_range_curr++) { - result= read_range_first(multi_range_curr->start_key.length ? + result= read_range_first(multi_range_curr->start_key.keypart_map ? &multi_range_curr->start_key : 0, - multi_range_curr->end_key.length ? + multi_range_curr->end_key.keypart_map ? &multi_range_curr->end_key : 0, test(multi_range_curr->range_flag & EQ_RANGE), multi_range_sorted); @@ -3171,9 +3170,9 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) multi_range_curr < multi_range_end; multi_range_curr++) { - result= read_range_first(multi_range_curr->start_key.length ? + result= read_range_first(multi_range_curr->start_key.keypart_map ? &multi_range_curr->start_key : 0, - multi_range_curr->end_key.length ? + multi_range_curr->end_key.keypart_map ? &multi_range_curr->end_key : 0, test(multi_range_curr->range_flag & EQ_RANGE), multi_range_sorted); @@ -3233,7 +3232,7 @@ int handler::read_range_first(const key_range *start_key, else result= index_read(table->record[0], start_key->key, - start_key->length, + start_key->keypart_map, start_key->flag); if (result) DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND) @@ -3307,15 +3306,19 @@ int handler::compare_key(key_range *range) return cmp; } + int handler::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, + enum ha_rkey_function find_flag) { - int error= ha_index_init(index, 0); + int error, error1; + error= index_init(index, 0); if (!error) - error= index_read(buf, key, key_len, find_flag); - if (!error) - error= ha_index_end(); - return error; + { + error= index_read(buf, key, keypart_map, find_flag); + error1= index_end(); + } + return error ? error : error1; } @@ -3365,7 +3368,6 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin, TYPELIB *ha_known_exts(void) { - MEM_ROOT *mem_root= current_thd->mem_root; if (!known_extensions.type_names || mysys_usage_id != known_extensions_id) { List found_exts; diff --git a/sql/handler.h b/sql/handler.h index 82970cc1ac6..1d02d6a7ee3 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -867,6 +867,18 @@ public: {} }; +uint calculate_key_len(TABLE *, uint, const byte *, ulonglong); +/* + bitmap with first N+1 bits set + (keypart_map for a key prefix of [0..N] keyparts) +*/ +#define make_keypart_map(N) (((ulonglong)2 << (N)) - 1) +/* + bitmap with first N bits set + (keypart_map for a key prefix of [0..N-1] keyparts) +*/ +#define make_prev_keypart_map(N) (((ulonglong)1 << (N)) - 1) + /* The handler class is the interface for dynamically loadable storage engines. Do not add ifdefs and take care when adding or @@ -1202,11 +1214,20 @@ public: DBUG_ASSERT(FALSE); return HA_ERR_WRONG_COMMAND; } - virtual int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + private: + virtual int index_read(byte * buf, const byte * key, uint key_len, + enum ha_rkey_function find_flag) { return HA_ERR_WRONG_COMMAND; } + public: + virtual int index_read(byte * buf, const byte * key, ulonglong keypart_map, + enum ha_rkey_function find_flag) + { + uint key_len= calculate_key_len(table, active_index, key, keypart_map); + return index_read(buf, key, key_len, find_flag); + } virtual int index_read_idx(byte * buf, uint index, const byte * key, - uint key_len, enum ha_rkey_function find_flag); + ulonglong keypart_map, + enum ha_rkey_function find_flag); virtual int index_next(byte * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_prev(byte * buf) @@ -1216,8 +1237,16 @@ public: virtual int index_last(byte * buf) { return HA_ERR_WRONG_COMMAND; } virtual int index_next_same(byte *buf, const byte *key, uint keylen); + private: virtual int index_read_last(byte * buf, const byte * key, uint key_len) { return (my_errno=HA_ERR_WRONG_COMMAND); } + public: + virtual int index_read_last(byte * buf, const byte * key, + ulonglong keypart_map) + { + uint key_len= calculate_key_len(table, active_index, key, keypart_map); + return index_read_last(buf, key, key_len); + } virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer); @@ -1243,8 +1272,7 @@ public: { return HA_ERR_WRONG_COMMAND; } virtual int rnd_same(byte *buf, uint inx) { return HA_ERR_WRONG_COMMAND; } - virtual ha_rows records_in_range(uint inx, key_range *min_key, - key_range *max_key) + virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) { return (ha_rows) 10; } virtual void position(const byte *record)=0; virtual int info(uint)=0; // see my_base.h for full description diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e131072d9bf..9867464e88e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2013,7 +2013,8 @@ int subselect_uniquesubquery_engine::exec() table->file->ha_index_init(tab->ref.key, 0); error= table->file->index_read(table->record[0], tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT); + tab_to_keypart_map(tab), + HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) error= report_error(table, error); @@ -2122,7 +2123,8 @@ int subselect_indexsubquery_engine::exec() table->file->ha_index_init(tab->ref.key, 1); error= table->file->index_read(table->record[0], tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT); + tab_to_keypart_map(tab), + HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) error= report_error(table, error); diff --git a/sql/key.cc b/sql/key.cc index bd614b10a70..faa7bf1f04b 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -29,6 +29,7 @@ field Field to search after key_length On partial match, contains length of fields before field + keypart key part # of a field NOTES Used when calculating key for NEXT_NUMBER @@ -45,7 +46,7 @@ */ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field, - uint *key_length) + uint *key_length, uint *keypart) { reg2 int i; reg3 KEY *key_info; @@ -60,8 +61,8 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field, { if (key_info->key_part[0].offset == fieldpos) { /* Found key. Calc keylength */ - *key_length=0; - return(i); /* Use this key */ + *key_length= *keypart= 0; + return i; /* Use this key */ } } @@ -78,8 +79,11 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field, j++, key_part++) { if (key_part->offset == fieldpos) - return(i); /* Use this key */ - *key_length+=key_part->store_length; + { + *keypart= j; + return i; /* Use this key */ + } + *key_length+= key_part->store_length; } } return(-1); /* No key is ok */ diff --git a/sql/log.cc b/sql/log.cc index 1b432ca15c0..5dc15ecc445 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3787,7 +3787,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) nb_elements())); /* If the auto_increment was second in a table's index (possible with - MyISAM or BDB) (table->next_number_key_offset != 0), such event is + MyISAM or BDB) (table->next_number_keypart != 0), such event is in fact not necessary. We could avoid logging it. */ Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT, diff --git a/sql/log_event.cc b/sql/log_event.cc index 82fb64bfe15..673b23d933f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6720,9 +6720,8 @@ replace_record(THD *thd, TABLE *table, } key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0); - error= table->file->index_read_idx(table->record[1], keynum, - (const byte*)key.get(), - table->key_info[keynum].key_length, + error= table->file->index_read_idx(table->record[1], keynum, + (const byte*)key.get(), ~ULL(0), HA_READ_KEY_EXACT); if (error) DBUG_RETURN(error); @@ -6907,8 +6906,7 @@ static int find_and_fetch_row(TABLE *table, byte *key) table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0; table->record[1][pos]= 0xFF; if ((error= table->file->index_read(table->record[1], key, - table->key_info->key_length, - HA_READ_KEY_EXACT))) + ~(ulonglong)0, HA_READ_KEY_EXACT))) { table->file->print_error(error, MYF(0)); table->file->ha_index_end(); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 742efc71e63..faac6f4a7ca 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1445,7 +1445,7 @@ void print_plan(JOIN* join,uint idx, double record_count, double read_time, void mysql_print_status(); /* key.cc */ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field, - uint *key_length); + uint *key_length, uint *keypart); void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length); void key_restore(byte *to_record, byte *from_key, KEY *key_info, uint key_length); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 628b07631c1..3c729688e8d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -310,7 +310,7 @@ public: min_value=arg->max_value; min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN; } - void store_min(uint length,char **min_key,uint min_key_flag) + int store_min(uint length,char **min_key,uint min_key_flag) { if ((min_flag & GEOM_FLAG) || (!(min_flag & NO_MIN_RANGE) && @@ -324,12 +324,12 @@ public: else memcpy(*min_key,min_value,length); (*min_key)+= length; + return 1; } + return 0; } - void store(uint length,char **min_key,uint min_key_flag, - char **max_key, uint max_key_flag) + int store_max(uint length,char **max_key, uint max_key_flag) { - store_min(length, min_key, min_key_flag); if (!(max_flag & NO_MAX_RANGE) && !(max_key_flag & (NO_MAX_RANGE | NEAR_MAX))) { @@ -341,33 +341,45 @@ public: else memcpy(*max_key,max_value,length); (*max_key)+= length; + return 1; } + return 0; } + /*void store(uint length,char **min_key,uint min_key_flag, + char **max_key, uint max_key_flag) + { + store_min(length, min_key, min_key_flag); + store_max(length, max_key, max_key_flag); + }*/ - void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag) + int 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].store_length, - range_key,*range_key_flag,range_key,NO_MAX_RANGE); + uint res= key_tree->store_min(key[key_tree->part].store_length, + range_key, *range_key_flag); *range_key_flag|= key_tree->min_flag; if (key_tree->next_key_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) - key_tree->next_key_part->store_min_key(key,range_key, range_key_flag); + res+= key_tree->next_key_part->store_min_key(key, range_key, + range_key_flag); + return res; } - void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag) + int 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].store_length, - range_key, NO_MIN_RANGE, range_key,*range_key_flag); + uint res=key_tree->store_max(key[key_tree->part].store_length, + range_key, *range_key_flag); (*range_key_flag)|= key_tree->max_flag; if (key_tree->next_key_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) - key_tree->next_key_part->store_max_key(key,range_key, range_key_flag); + res+= key_tree->next_key_part->store_max_key(key, range_key, + range_key_flag); + return res; } SEL_ARG *insert(SEL_ARG *key); @@ -583,8 +595,8 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts); static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree, bool update_tbl_stats); static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree, - char *min_key,uint min_key_flag, - char *max_key, uint max_key_flag); + char *min_key, uint min_key_flag, int, + char *max_key, uint max_key_flag, int); QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index, SEL_ARG *key_tree, @@ -606,9 +618,6 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, double read_time); static TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree); -static int get_index_merge_params(PARAM *param, key_map& needed_reg, - SEL_IMERGE *imerge, double *read_time, - ha_rows* imerge_rows); static double get_index_only_read_time(const PARAM* param, ha_rows records, int keynr); @@ -1455,6 +1464,7 @@ QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT() QUICK_RANGE::QUICK_RANGE() :min_key(0),max_key(0),min_length(0),max_length(0), + min_keypart_map(0), max_keypart_map(0), flag(NO_MIN_RANGE | NO_MAX_RANGE) {} @@ -2425,8 +2435,6 @@ static int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar, List &merges); static void mark_all_partitions_as_used(partition_info *part_info); -static uint32 part_num_to_part_id_range(PART_PRUNE_PARAM* prune_par, - uint32 num); #ifndef DBUG_OFF static void print_partitioning_index(KEY_PART *parts, KEY_PART *parts_end); @@ -4035,9 +4043,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src) The calculation is conducted as follows: Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate - n_{k1} n_{k_2} + n_{k1} n_{k2} --------- * --------- * .... (3) - n_{k1-1} n_{k2_1} + n_{k1-1} n_{k2-1} where k1,k2,... are key parts which fields were not yet marked as fixed ( this is result of application of option b) of the recursion step for @@ -4045,9 +4053,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src) Since it is reasonable to expect that most of the fields are not marked as fixed, we calculate (3) as - n_{i1} n_{i_2} + n_{i1} n_{i2} (3) = n_{max_key_part} / ( --------- * --------- * .... ) - n_{i1-1} n_{i2_1} + n_{i1-1} n_{i2-1} where i1,i2, .. are key parts that were already marked as fixed. @@ -4056,7 +4064,6 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src) RETURN Selectivity of given ROR scan. - */ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, @@ -4067,6 +4074,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, byte key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */ char *key_ptr= (char*) key_val; SEL_ARG *sel_arg, *tuple_arg= NULL; + ulonglong keypart_map= 0; bool cur_covered; bool prev_covered= test(bitmap_is_set(&info->covered_fields, key_part->fieldnr-1)); @@ -4077,7 +4085,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, max_range.key= (byte*) key_val; max_range.flag= HA_READ_AFTER_KEY; ha_rows prev_records= info->param->table->file->stats.records; - DBUG_ENTER("ror_intersect_selectivity"); + DBUG_ENTER("ror_scan_selectivity"); for (sel_arg= scan->sel_arg; sel_arg; sel_arg= sel_arg->next_key_part) @@ -4094,13 +4102,17 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, tuple_arg= scan->sel_arg; /* Here we use the length of the first key part */ tuple_arg->store_min(key_part->store_length, &key_ptr, 0); + keypart_map= 1; } while (tuple_arg->next_key_part != sel_arg) { tuple_arg= tuple_arg->next_key_part; - tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0); + tuple_arg->store_min(key_part[tuple_arg->part].store_length, + &key_ptr, 0); + keypart_map= (keypart_map << 1) | 1; } min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val); + min_range.keypart_map= max_range.keypart_map= keypart_map; records= (info->param->table->file-> records_in_range(scan->keynr, &min_range, &max_range)); if (cur_covered) @@ -5310,12 +5322,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) */ for (uint i= 1 ; i < cond_func->arg_count ; i++) { - if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM) { field_item= (Item_field*) (cond_func->arguments()[i]->real_item()); SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, - field_item, (Item*) i, inv); + field_item, (Item*)(intptr)i, inv); if (inv) tree= !tree ? tmp : tree_or(param, tree, tmp); else @@ -7046,7 +7057,9 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats) } param->n_ranges= 0; - records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0); + records= check_quick_keys(param, idx, tree, + param->min_key, 0, -1, + param->max_key, 0, -1); if (records != HA_POS_ERROR) { if (update_tbl_stats) @@ -7109,12 +7122,13 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats) */ static ha_rows -check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, - char *min_key,uint min_key_flag, char *max_key, - uint max_key_flag) +check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree, + char *min_key, uint min_key_flag, int min_keypart, + char *max_key, uint max_key_flag, int max_keypart) { ha_rows records=0, tmp; uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length; + uint tmp_min_keypart= min_keypart, tmp_max_keypart= max_keypart; char *tmp_min_key, *tmp_max_key; param->max_key_part=max(param->max_key_part,key_tree->part); @@ -7127,18 +7141,21 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, This is not a ROR scan if the key is not Clustered Primary Key. */ param->is_ror_scan= FALSE; - records=check_quick_keys(param,idx,key_tree->left,min_key,min_key_flag, - max_key,max_key_flag); + records=check_quick_keys(param, idx, key_tree->left, + min_key, min_key_flag, min_keypart, + max_key, max_key_flag, max_keypart); if (records == HA_POS_ERROR) // Impossible return records; } tmp_min_key= min_key; tmp_max_key= max_key; - key_tree->store(param->key[idx][key_tree->part].store_length, - &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag); - min_key_length= (uint) (tmp_min_key- param->min_key); - max_key_length= (uint) (tmp_max_key- param->max_key); + tmp_min_keypart+= key_tree->store_min(param->key[idx][key_tree->part].store_length, + &tmp_min_key, min_key_flag); + tmp_max_keypart+= key_tree->store_max(param->key[idx][key_tree->part].store_length, + &tmp_max_key, max_key_flag); + min_key_length= (uint) (tmp_min_key - param->min_key); + max_key_length= (uint) (tmp_max_key - param->max_key); if (param->is_ror_scan) { @@ -7158,12 +7175,13 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) { // const key as prefix if (min_key_length == max_key_length && - !memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) && + !memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) && !key_tree->min_flag && !key_tree->max_flag) { - tmp=check_quick_keys(param,idx,key_tree->next_key_part, - tmp_min_key, min_key_flag | key_tree->min_flag, - tmp_max_key, max_key_flag | key_tree->max_flag); + tmp=check_quick_keys(param,idx,key_tree->next_key_part, tmp_min_key, + min_key_flag | key_tree->min_flag, tmp_min_keypart, + tmp_max_key, max_key_flag | key_tree->max_flag, + tmp_max_keypart); goto end; // Ugly, but efficient } else @@ -7175,18 +7193,20 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, tmp_min_flag=key_tree->min_flag; tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) + tmp_min_keypart+= key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key, &tmp_min_flag); if (!tmp_max_flag) + tmp_max_keypart+= key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key, &tmp_max_flag); - min_key_length= (uint) (tmp_min_key- param->min_key); - max_key_length= (uint) (tmp_max_key- param->max_key); + min_key_length= (uint) (tmp_min_key - param->min_key); + max_key_length= (uint) (tmp_max_key - param->max_key); } else { - tmp_min_flag=min_key_flag | key_tree->min_flag; - tmp_max_flag=max_key_flag | key_tree->max_flag; + tmp_min_flag= min_key_flag | key_tree->min_flag; + tmp_max_flag= max_key_flag | key_tree->max_flag; } keynr=param->real_keynr[idx]; @@ -7194,9 +7214,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, if (!tmp_min_flag && ! tmp_max_flag && (uint) key_tree->part+1 == param->table->key_info[keynr].key_parts && (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) == - HA_NOSAME && - min_key_length == max_key_length && - !memcmp(param->min_key,param->max_key,min_key_length)) + HA_NOSAME && min_key_length == max_key_length && + !memcmp(param->min_key, param->max_key, min_key_length)) { tmp=1; // Max one record param->n_ranges++; @@ -7215,7 +7234,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, first members of clustered primary key. */ if (!(min_key_length == max_key_length && - !memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) && + !memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) && !key_tree->min_flag && !key_tree->max_flag && is_key_scan_ror(param, keynr, key_tree->part + 1))) param->is_ror_scan= FALSE; @@ -7227,11 +7246,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, key_range min_range; min_range.key= (byte*) param->min_key; min_range.length= min_key_length; + min_range.keypart_map= make_keypart_map(tmp_min_keypart); /* In this case tmp_min_flag contains the handler-read-function */ min_range.flag= (ha_rkey_function) (tmp_min_flag ^ GEOM_FLAG); - tmp= param->table->file->records_in_range(keynr, &min_range, - (key_range*) 0); + tmp= param->table->file->records_in_range(keynr, + &min_range, (key_range*) 0); } else { @@ -7241,10 +7261,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, min_range.length= min_key_length; min_range.flag= (tmp_min_flag & NEAR_MIN ? HA_READ_AFTER_KEY : HA_READ_KEY_EXACT); + min_range.keypart_map= make_keypart_map(tmp_min_keypart); max_range.key= (byte*) param->max_key; max_range.length= max_key_length; max_range.flag= (tmp_max_flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); + max_range.keypart_map= make_keypart_map(tmp_max_keypart); tmp=param->table->file->records_in_range(keynr, (min_key_length ? &min_range : (key_range*) 0), @@ -7265,8 +7287,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, This is not a ROR scan if the key is not Clustered Primary Key. */ param->is_ror_scan= FALSE; - tmp=check_quick_keys(param,idx,key_tree->right,min_key,min_key_flag, - max_key,max_key_flag); + tmp=check_quick_keys(param, idx, key_tree->right, + min_key, min_key_flag, min_keypart, + max_key, max_key_flag, max_keypart); if (tmp == HA_POS_ERROR) return tmp; records+=tmp; @@ -7412,6 +7435,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { QUICK_RANGE *range; uint flag; + int min_part= key_tree->part-1, max_part=key_tree->part-1; if (key_tree->left != &null_element) { @@ -7420,16 +7444,18 @@ 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].store_length, - &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag); + min_part+= key_tree->store_min(key[key_tree->part].store_length, + &tmp_min_key,min_key_flag); + max_part+= key_tree->store_max(key[key_tree->part].store_length, + &tmp_max_key,max_key_flag); if (key_tree->next_key_part && key_tree->next_key_part->part == key_tree->part+1 && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) { // const key as prefix - if (!((tmp_min_key - min_key) != (tmp_max_key - max_key) || - memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) || - key_tree->min_flag || key_tree->max_flag)) + if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && + memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 && + key_tree->min_flag==0 && key_tree->max_flag==0) { if (get_quick_keys(param,quick,key,key_tree->next_key_part, tmp_min_key, min_key_flag | key_tree->min_flag, @@ -7440,11 +7466,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) - key_tree->next_key_part->store_min_key(key, &tmp_min_key, + { + min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, &tmp_min_flag); + } if (!tmp_max_flag) - key_tree->next_key_part->store_max_key(key, &tmp_max_key, + { + max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, &tmp_max_flag); + } flag=tmp_min_flag | tmp_max_flag; } } @@ -7494,13 +7524,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, /* Get range for retrieving rows in QUICK_SELECT::get_next */ if (!(range= new QUICK_RANGE((const char *) param->min_key, (uint) (tmp_min_key - param->min_key), + min_part >=0 ? make_keypart_map(min_part) : 0, (const char *) param->max_key, (uint) (tmp_max_key - param->max_key), + max_part >=0 ? make_keypart_map(max_part) : 0, flag))) return 1; // out of memory - set_if_bigger(quick->max_used_key_length,range->min_length); - set_if_bigger(quick->max_used_key_length,range->max_length); + set_if_bigger(quick->max_used_key_length, range->min_length); + set_if_bigger(quick->max_used_key_length, range->max_length); set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1); if (insert_dynamic(&quick->ranges, (gptr)&range)) return 1; @@ -7642,6 +7674,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, range->min_key=range->max_key=(char*) ref->key_buff; range->min_length=range->max_length=ref->key_length; + range->min_keypart_map= range->max_keypart_map= (1 << ref->key_parts) - 1; range->flag= ((ref->key_length == key_info->key_length && (key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME) ? EQ_RANGE : 0); @@ -7675,8 +7708,10 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, *ref->null_ref_key= 1; // Set null byte then create a range if (!(null_range= new (alloc) QUICK_RANGE((char*)ref->key_buff, ref->key_length, + (1 << ref->key_parts) - 1, (char*)ref->key_buff, ref->key_length, + (1 << ref->key_parts) - 1, EQ_RANGE))) goto err; *ref->null_ref_key= 0; // Clear null byte @@ -8129,6 +8164,7 @@ int QUICK_RANGE_SELECT::get_next() start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : (range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); + start_key->keypart_map= range->min_keypart_map; end_key->key= (const byte*) range->max_key; end_key->length= range->max_length; /* @@ -8137,6 +8173,7 @@ int QUICK_RANGE_SELECT::get_next() */ end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); + end_key->keypart_map= range->max_keypart_map; mrange_slot->range_flag= range->flag; } @@ -8186,7 +8223,9 @@ end: other if some error occurred */ -int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) +int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, + ulonglong keypart_map, + byte *cur_prefix) { DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix"); @@ -8198,8 +8237,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) { /* Read the next record in the same range with prefix after cur_prefix. */ DBUG_ASSERT(cur_prefix != 0); - result= file->index_read(record, cur_prefix, prefix_length, - HA_READ_AFTER_KEY); + result= file->index_read(record, cur_prefix, keypart_map, HA_READ_AFTER_KEY); if (result || (file->compare_key(file->end_range) <= 0)) DBUG_RETURN(result); } @@ -8215,11 +8253,13 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) start_key.key= (const byte*) range->min_key; start_key.length= min(range->min_length, prefix_length); + start_key.keypart_map= range->min_keypart_map & keypart_map; 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= min(range->max_length, prefix_length); + end_key.keypart_map= range->max_keypart_map & keypart_map; /* We use READ_AFTER_KEY here because if we are reading on a key prefix we want to find all keys with this prefix @@ -8227,8 +8267,8 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); - result= file->read_range_first(range->min_length ? &start_key : 0, - range->max_length ? &end_key : 0, + result= file->read_range_first(range->min_keypart_map ? &start_key : 0, + range->max_keypart_map ? &end_key : 0, test(range->flag & EQ_RANGE), sorted); if (range->flag == (UNIQUE_RANGE | EQ_RANGE)) @@ -8268,9 +8308,8 @@ int QUICK_RANGE_SELECT_GEOM::get_next() } range= *(cur_range++); - result= file->index_read(record, - (byte*) range->min_key, - range->min_length, + result= file->index_read(record, (byte*) range->min_key, + range->min_keypart_map, (ha_rkey_function)(range->flag ^ GEOM_FLAG)); if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE) DBUG_RETURN(result); @@ -8403,13 +8442,13 @@ int QUICK_SELECT_DESC::get_next() if (range->flag & EQ_RANGE) { result = file->index_read(record, (byte*) range->max_key, - range->max_length, HA_READ_KEY_EXACT); + range->max_keypart_map, HA_READ_KEY_EXACT); } else { DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); result=file->index_read(record, (byte*) range->max_key, - range->max_length, + range->max_keypart_map, ((range->flag & NEAR_MAX) ? HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV)); } @@ -8728,8 +8767,7 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names, static inline uint get_field_keypart(KEY *index, Field *field); static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, PARAM *param, uint *param_idx); -static bool -get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, +static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, KEY_PART_INFO *first_non_group_part, KEY_PART_INFO *min_max_arg_part, KEY_PART_INFO *last_part, THD *thd, @@ -9127,7 +9165,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) NULL; first_non_infix_part= min_max_arg_part ? (min_max_arg_part < last_part) ? - min_max_arg_part + 1 : + min_max_arg_part : NULL : NULL; if (first_non_group_part && @@ -9184,7 +9222,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (first_non_infix_part) { - for (cur_part= first_non_infix_part; cur_part != last_part; cur_part++) + cur_part= first_non_infix_part + + (min_max_arg_part && (min_max_arg_part < last_part)); + for (; cur_part != last_part; cur_part++) { if (bitmap_is_set(table->read_set, cur_part->field->field_index)) goto next_index; @@ -9730,7 +9770,7 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, RETURN New QUICK_GROUP_MIN_MAX_SELECT object if successfully created, - NULL o/w. + NULL otherwise. */ QUICK_SELECT_I * @@ -9743,10 +9783,10 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows, quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table, param->thd->lex->current_select->join, have_min, have_max, min_max_arg_part, - group_prefix_len, used_key_parts, - index_info, index, read_cost, records, - key_infix_len, key_infix, - parent_alloc); + group_prefix_len, group_key_parts, + used_key_parts, index_info, index, + read_cost, records, key_infix_len, + key_infix, parent_alloc); if (!quick) DBUG_RETURN(NULL); @@ -9835,7 +9875,7 @@ QUICK_GROUP_MIN_MAX_SELECT:: QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, bool have_max_arg, KEY_PART_INFO *min_max_arg_part_arg, - uint group_prefix_len_arg, + uint group_prefix_len_arg, uint group_key_parts_arg, uint used_key_parts_arg, KEY *index_info_arg, uint use_index, double read_cost_arg, ha_rows records_arg, uint key_infix_len_arg, @@ -9845,7 +9885,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, have_max(have_max_arg), seen_first_key(FALSE), min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg), key_infix_len(key_infix_len_arg), min_functions_it(NULL), - max_functions_it(NULL) + max_functions_it(NULL), group_key_parts(group_key_parts_arg) { head= table; file= head->file; @@ -9855,6 +9895,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg, read_time= read_cost_arg; records= records_arg; used_key_parts= used_key_parts_arg; + real_key_parts= used_key_parts_arg; real_prefix_len= group_prefix_len + key_infix_len; group_prefix= NULL; min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0; @@ -10021,7 +10062,9 @@ bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range) range_flag|= EQ_RANGE; /* equality condition */ } range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len, + make_keypart_map(sel_range->part), sel_range->max_value, min_max_arg_len, + make_keypart_map(sel_range->part), range_flag); if (!range) return TRUE; @@ -10256,7 +10299,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() first sub-group with the extended prefix. */ if (!have_min && !have_max && key_infix_len > 0) - result= file->index_read(record, group_prefix, real_prefix_len, + result= file->index_read(record, group_prefix, + make_prev_keypart_map(real_key_parts), HA_READ_KEY_EXACT); result= have_min ? min_res : have_max ? max_res : result; @@ -10319,7 +10363,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min() /* Apply the constant equality conditions to the non-group select fields */ if (key_infix_len > 0) { - if ((result= file->index_read(record, group_prefix, real_prefix_len, + if ((result= file->index_read(record, group_prefix, + make_prev_keypart_map(real_key_parts), HA_READ_KEY_EXACT))) DBUG_RETURN(result); } @@ -10336,7 +10381,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min() /* Find the first subsequent record without NULL in the MIN/MAX field. */ key_copy(tmp_record, record, index_info, 0); result= file->index_read(record, tmp_record, - real_prefix_len + min_max_arg_len, + make_keypart_map(real_key_parts), HA_READ_AFTER_KEY); /* Check if the new record belongs to the current group by comparing its @@ -10392,7 +10437,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max() if (min_max_ranges.elements > 0) result= next_max_in_range(); else - result= file->index_read(record, group_prefix, real_prefix_len, + result= file->index_read(record, group_prefix, + make_prev_keypart_map(real_key_parts), HA_READ_PREFIX_LAST); DBUG_RETURN(result); } @@ -10428,7 +10474,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() { byte *cur_prefix= seen_first_key ? group_prefix : NULL; if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, - cur_prefix))) + (ULL(1) << group_key_parts) - 1, cur_prefix))) DBUG_RETURN(result); seen_first_key= TRUE; } @@ -10444,7 +10490,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() else { /* Load the first key in this group into record. */ - result= file->index_read(record, group_prefix, group_prefix_len, + result= file->index_read(record, group_prefix, + make_prev_keypart_map(group_key_parts), HA_READ_AFTER_KEY); if (result) DBUG_RETURN(result); @@ -10487,6 +10534,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() { ha_rkey_function find_flag; uint search_prefix_len; + ulonglong keypart_map; QUICK_RANGE *cur_range; bool found_null= FALSE; int result= HA_ERR_KEY_NOT_FOUND; @@ -10508,8 +10556,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() if (cur_range->flag & NO_MIN_RANGE) { - find_flag= HA_READ_KEY_EXACT; search_prefix_len= real_prefix_len; + keypart_map= (ULL(1) << real_key_parts) - 1; + find_flag= HA_READ_KEY_EXACT; } else { @@ -10517,13 +10566,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() memcpy(group_prefix + real_prefix_len, cur_range->min_key, cur_range->min_length); search_prefix_len= real_prefix_len + min_max_arg_len; + keypart_map= (ULL(2) << real_key_parts) - 1; find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; } - result= file->index_read(record, group_prefix, search_prefix_len, - find_flag); + result= file->index_read(record, group_prefix, keypart_map, find_flag); if (result) { if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) && @@ -10621,6 +10670,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() { ha_rkey_function find_flag; uint search_prefix_len; + ulonglong keypart_map; QUICK_RANGE *cur_range; int result; @@ -10642,8 +10692,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() if (cur_range->flag & NO_MAX_RANGE) { - find_flag= HA_READ_PREFIX_LAST; search_prefix_len= real_prefix_len; + keypart_map= (ULL(1) << real_key_parts) - 1; + find_flag= HA_READ_PREFIX_LAST; } else { @@ -10651,13 +10702,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() memcpy(group_prefix + real_prefix_len, cur_range->max_key, cur_range->max_length); search_prefix_len= real_prefix_len + min_max_arg_len; + keypart_map= (ULL(2) << real_key_parts) - 1; find_flag= (cur_range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; } - result= file->index_read(record, group_prefix, search_prefix_len, - find_flag); + result= file->index_read(record, group_prefix, keypart_map, find_flag); if (result) { diff --git a/sql/opt_range.h b/sql/opt_range.h index 525a0adcff7..40c0f0c6388 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -37,17 +37,22 @@ class QUICK_RANGE :public Sql_alloc { public: char *min_key,*max_key; uint16 min_length,max_length,flag; + ulonglong min_keypart_map, max_keypart_map; #ifdef HAVE_purify uint16 dummy; /* Avoid warnings on 'flag' */ #endif QUICK_RANGE(); /* Full range */ - QUICK_RANGE(const char *min_key_arg,uint min_length_arg, - const char *max_key_arg,uint max_length_arg, + QUICK_RANGE(const char *min_key_arg, uint min_length_arg, + ulonglong min_keypart_map_arg, + const char *max_key_arg, uint max_length_arg, + ulonglong max_keypart_map_arg, uint flag_arg) : min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)), max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)), min_length((uint16) min_length_arg), max_length((uint16) max_length_arg), + min_keypart_map(min_keypart_map_arg), + max_keypart_map(max_keypart_map_arg), flag((uint16) flag_arg) { #ifdef HAVE_purify @@ -318,7 +323,8 @@ public: int reset(void); int get_next(); void range_end(); - int get_next_prefix(uint prefix_length, byte *cur_prefix); + int get_next_prefix(uint prefix_length, ulonglong keypart_map, + byte *cur_prefix); bool reverse_sorted() { return 0; } bool unique_key_range(); int init_ror_merged_scan(bool reuse_handler); @@ -605,6 +611,7 @@ private: byte *tmp_record; /* Temporary storage for next_min(), next_max(). */ byte *group_prefix; /* Key prefix consisting of the GROUP fields. */ uint group_prefix_len; /* Length of the group prefix. */ + uint group_key_parts; byte *last_prefix; /* Prefix of the last group for detecting EOF. */ bool have_min; /* Specify whether we are computing */ bool have_max; /* a MIN, a MAX, or both. */ @@ -616,6 +623,7 @@ private: uint key_infix_len; DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */ uint real_prefix_len; /* Length of key prefix extended with key_infix. */ + uint real_key_parts; List *min_functions; List *max_functions; List_iterator *min_functions_it; @@ -638,10 +646,11 @@ private: public: QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min, bool have_max, KEY_PART_INFO *min_max_arg_part, - uint group_prefix_len, uint used_key_parts, - KEY *index_info, uint use_index, double read_cost, - ha_rows records, uint key_infix_len, - byte *key_infix, MEM_ROOT *parent_alloc); + uint group_prefix_len, uint group_key_parts, + uint used_key_parts, KEY *index_info, uint + use_index, double read_cost, ha_rows records, uint + key_infix_len, byte *key_infix, MEM_ROOT + *parent_alloc); ~QUICK_GROUP_MIN_MAX_SELECT(); bool add_range(SEL_ARG *sel_range); void update_key_stat(); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 90a3ff66a22..9b3197d0589 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -251,7 +251,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) error= table->file->index_first(table->record[0]); else error= table->file->index_read(table->record[0],key_buff, - ref.key_length, + make_prev_keypart_map(ref.key_parts), range_fl & NEAR_MIN ? HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT); @@ -338,11 +338,11 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) error= table->file->index_last(table->record[0]); else error= table->file->index_read(table->record[0], key_buff, - ref.key_length, + make_prev_keypart_map(ref.key_parts), range_fl & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV); - if (!error && reckey_in_range(1, &ref, item_field->field, + if (!error && reckey_in_range(1, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; if (table->key_read) @@ -605,15 +605,13 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, /* Check if field is part of the tested partial key */ byte *key_ptr= ref->key_buff; KEY_PART_INFO *part; - for (part= keyinfo->key_part; - ; - key_ptr+= part++->store_length) + for (part= keyinfo->key_part; ; key_ptr+= part++->store_length) { if (part > field_part) return 0; // Field is beyond the tested parts if (part->field->eq(((Item_field*) args[0])->field)) - break; // Found a part od the key for the field + break; // Found a part of the key for the field } bool is_field_part= part == field_part; @@ -625,8 +623,11 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, { uint length= (key_ptr-ref->key_buff)+part->store_length; if (ref->key_length < length) + { /* Ultimately ref->key_length will contain the length of the search key */ ref->key_length= length; + ref->key_parts= (part - keyinfo->key_part) + 1; + } if (!*prefix_len && part+1 == field_part) *prefix_len= length; if (is_field_part && eq_type) @@ -773,6 +774,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, { ref->key= idx; ref->key_length= 0; + ref->key_parts= 0; key_part_map key_part_used= 0; *range_fl= NO_MIN_RANGE | NO_MAX_RANGE; if (matching_cond(max_fl, ref, keyinfo, part, cond, @@ -788,6 +790,8 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, */ ref->key_buff[ref->key_length]= 1; ref->key_length+= part->store_length; + ref->key_parts++; + DBUG_ASSERT(ref->key_parts == jdx+1); *range_fl&= ~NO_MIN_RANGE; *range_fl|= NEAR_MIN; // > NULL } diff --git a/sql/slave.cc b/sql/slave.cc index c21aec49e88..a0916adb8eb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -31,6 +31,8 @@ #include "rpl_tblmap.h" int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len); +static Log_event* next_event(RELAY_LOG_INFO* rli); + #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") diff --git a/sql/slave.h b/sql/slave.h index 43eb71be601..bc039f6eb75 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -111,8 +111,6 @@ extern ulonglong relay_log_space_limit; #define MYSQL_SLAVE_RUN_NOT_CONNECT 1 #define MYSQL_SLAVE_RUN_CONNECT 2 -static Log_event* next_event(RELAY_LOG_INFO* rli); - #define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\ "FIRST") #define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\ diff --git a/sql/sp.cc b/sql/sp.cc index 14703e3aa42..19195a4f043 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -218,8 +218,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) key_copy(key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, - key, table->key_info->key_length, + if (table->file->index_read_idx(table->record[0], 0, key, ~ULL(0), HA_READ_KEY_EXACT)) DBUG_RETURN(SP_KEY_NOT_FOUND); @@ -494,8 +493,6 @@ db_create_routine(THD *thd, int type, sp_head *sp) int ret; TABLE *table; char definer[USER_HOST_BUFF_SIZE]; - char old_db_buf[NAME_LEN+1]; - LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; DBUG_ENTER("db_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length, sp->m_name.str)); @@ -906,7 +903,7 @@ sp_drop_db_routines(THD *thd, char *db) table->file->ha_index_init(0, 1); if (! table->file->index_read(table->record[0], (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr, - key_len, HA_READ_KEY_EXACT)) + (ulonglong)1, HA_READ_KEY_EXACT)) { int nxtres; bool deleted= FALSE; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0d9653172e0..f72cf94c0ac 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1813,8 +1813,7 @@ static bool update_user_table(THD *thd, TABLE *table, table->key_info->key_length); if (table->file->index_read_idx(table->record[0], 0, - (byte *) user_key, - table->key_info->key_length, + (byte *) user_key, ~ULL(0), HA_READ_KEY_EXACT)) { my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), @@ -1905,8 +1904,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, - user_key, table->key_info->key_length, + if (table->file->index_read_idx(table->record[0], 0, user_key, ~ULL(0), HA_READ_KEY_EXACT)) { /* what == 'N' means revoke */ @@ -2123,8 +2121,7 @@ static int replace_db_table(TABLE *table, const char *db, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0],0, - user_key, table->key_info->key_length, + if (table->file->index_read_idx(table->record[0],0, user_key, ~ULL(0), HA_READ_KEY_EXACT)) { if (what == 'N') @@ -2341,9 +2338,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) col_privs->field[4]->store("",0, &my_charset_latin1); col_privs->file->ha_index_init(0, 1); - if (col_privs->file->index_read(col_privs->record[0], - (byte*) key, - key_prefix_len, HA_READ_KEY_EXACT)) + if (col_privs->file->index_read(col_privs->record[0], (byte*) key, + (ulonglong)15, HA_READ_KEY_EXACT)) { cols = 0; /* purecov: deadcode */ col_privs->file->ha_index_end(); @@ -2479,7 +2475,7 @@ static int replace_column_table(GRANT_TABLE *g_t, table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info); - /* Get length of 3 first key parts */ + /* Get length of 4 first key parts */ key_prefix_length= (key_part[0].store_length + key_part[1].store_length + key_part[2].store_length + key_part[3].store_length); key_copy(key, table->record[0], table->key_info, key_prefix_length); @@ -2505,8 +2501,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read(table->record[0], user_key, - table->key_info->key_length, + if (table->file->index_read(table->record[0], user_key, ~(ulonglong)0, HA_READ_KEY_EXACT)) { if (revoke_grant) @@ -2582,8 +2577,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, key_prefix_length); - if (table->file->index_read(table->record[0], user_key, - key_prefix_length, + if (table->file->index_read(table->record[0], user_key, (ulonglong)15, HA_READ_KEY_EXACT)) goto end; @@ -2684,8 +2678,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, - user_key, table->key_info->key_length, + if (table->file->index_read_idx(table->record[0], 0, user_key, ~ULL(0), HA_READ_KEY_EXACT)) { /* @@ -2808,8 +2801,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, TRUE); store_record(table,record[1]); // store at pos 1 - if (table->file->index_read_idx(table->record[0],0, - (byte*) table->field[0]->ptr,0, + if (table->file->index_read_idx(table->record[0], 0, + (byte*) table->field[0]->ptr, ~ULL(0), HA_READ_KEY_EXACT)) { /* @@ -4987,7 +4980,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop, key_copy(user_key, table->record[0], table->key_info, key_prefix_length); if ((error= table->file->index_read_idx(table->record[0], 0, - user_key, key_prefix_length, + user_key, ULL(3), HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 91e61be0478..9c6c98cb151 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -515,7 +515,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } List_iterator it_ke(*key_expr); Item *item; - for (key_len=0 ; (item=it_ke++) ; key_part++) + ulonglong keypart_map; + for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++) { my_bitmap_map *old_map; // 'item' can be changed by fix_fields() call @@ -532,6 +533,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, (void) item->save_in_field(key_part->field, 1); dbug_tmp_restore_column_map(table->write_set, old_map); key_len+=key_part->store_length; + keypart_map= (keypart_map << 1) | 1; } if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len)))) @@ -540,7 +542,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, table->file->ha_index_init(keyno, 1); key_copy(key, table->record[0], table->key_info + keyno, key_len); error= table->file->index_read(table->record[0], - key,key_len,ha_rkey_mode); + key, keypart_map, ha_rkey_mode); mode=rkey_to_rnext[(int)ha_rkey_mode]; break; } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 7b7f7602163..6656543e13d 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -295,8 +295,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, rkey_id->store((longlong) key_id, TRUE); rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW); int key_res= relations->file->index_read(relations->record[0], - (byte *) buff, - rkey_id->pack_length(), + (byte *) buff, (ulonglong)1, HA_READ_KEY_EXACT); for ( ; @@ -310,7 +309,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW); if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff, - field->pack_length(), HA_READ_KEY_EXACT)) + (ulonglong)1, HA_READ_KEY_EXACT)) { memorize_variant_topic(thd,topics,count,find_fields, names,name,description,example); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4ad8e5ee128..08af2960631 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1165,9 +1165,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } key_copy((byte*) key,table->record[0],table->key_info+key_nr,0); if ((error=(table->file->index_read_idx(table->record[1],key_nr, - (byte*) key, - table->key_info[key_nr]. - key_length, + (byte*) key, ~ULL(0), HA_READ_KEY_EXACT)))) goto err; } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 1d711b7835c..defbc344327 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -921,8 +921,7 @@ my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) table->use_all_columns(); table->field[0]->store(name->str, name->length, system_charset_info); if (! table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, - table->key_info[0].key_length, + (byte *)table->field[0]->ptr, ~ULL(0), HA_READ_KEY_EXACT)) { int error; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c11553e9eed..0805b0fd861 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10854,7 +10854,8 @@ int safe_index_read(JOIN_TAB *tab) TABLE *table= tab->table; if ((error=table->file->index_read(table->record[0], tab->ref.key_buff, - tab->ref.key_length, HA_READ_KEY_EXACT))) + tab_to_keypart_map(tab), + HA_READ_KEY_EXACT))) return report_error(table, error); return 0; } @@ -10992,7 +10993,8 @@ join_read_const(JOIN_TAB *tab) { error=table->file->index_read_idx(table->record[0],tab->ref.key, (byte*) tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT); + tab_to_keypart_map(tab), + HA_READ_KEY_EXACT); } if (error) { @@ -11035,7 +11037,8 @@ join_read_key(JOIN_TAB *tab) } error=table->file->index_read(table->record[0], tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT); + tab_to_keypart_map(tab), + HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); } @@ -11063,7 +11066,8 @@ join_read_always_key(JOIN_TAB *tab) return -1; if ((error=table->file->index_read(table->record[0], tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT))) + tab_to_keypart_map(tab), + HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); @@ -11090,7 +11094,7 @@ join_read_last_key(JOIN_TAB *tab) return -1; if ((error=table->file->index_read_last(table->record[0], tab->ref.key_buff, - tab->ref.key_length))) + tab_to_keypart_map(tab)))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); @@ -11631,7 +11635,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), group->buff[-1]= (char) group->field->is_null(); } if (!table->file->index_read(table->record[1], - join->tmp_table_param.group_buff,0, + join->tmp_table_param.group_buff, ~(ulonglong)0, HA_READ_KEY_EXACT)) { /* Update old record */ restore_record(table,record[1]); diff --git a/sql/sql_select.h b/sql/sql_select.h index 1d1fa666c60..4e47f5a8134 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -202,6 +202,11 @@ typedef struct st_join_table { } } JOIN_TAB; +static inline ulonglong tab_to_keypart_map(JOIN_TAB *tab) +{ + return (ULL(1) << tab->ref.key_parts) - 1; +} + enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 0ec7c54487a..d89462e8522 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -25,6 +25,7 @@ #include "sp_head.h" #include "sp.h" +static my_bool servers_load(THD *thd, TABLE_LIST *tables); HASH servers_cache; pthread_mutex_t servers_cache_mutex; // To init the hash uint servers_cache_initialised=FALSE; @@ -356,8 +357,7 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options) system_charset_info); if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, - table->key_info[0].key_length, + (byte *)table->field[0]->ptr, ~(ulonglong)0, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) @@ -556,8 +556,7 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) /* read index until record is that specified in server_name */ if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, - table->key_info[0].key_length, + (byte *)table->field[0]->ptr, ~(longlong)0, HA_READ_KEY_EXACT))) { /* if not found, err */ @@ -876,8 +875,7 @@ int update_server_record(TABLE *table, FOREIGN_SERVER *server) system_charset_info); if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, - table->key_info[0].key_length, + (byte *)table->field[0]->ptr, ~(longlong)0, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) @@ -931,8 +929,7 @@ int delete_server_record(TABLE *table, table->field[0]->store(server_name, server_name_length, system_charset_info); if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, - table->key_info[0].key_length, + (byte *)table->field[0]->ptr, ~(ulonglong)0, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) diff --git a/sql/sql_servers.h b/sql/sql_servers.h index 36fb4d07d1b..23b8cefd5bb 100644 --- a/sql/sql_servers.h +++ b/sql/sql_servers.h @@ -26,7 +26,6 @@ typedef struct st_federated_server /* cache handlers */ my_bool servers_init(bool dont_read_server_table); -static my_bool servers_load(THD *thd, TABLE_LIST *tables); my_bool servers_reload(THD *thd); my_bool get_server_from_table_to_cache(TABLE *table); void servers_free(bool end=0); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 7dec58d9b6e..b0e7831465a 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -514,8 +514,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) table->use_all_columns(); table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); if (!table->file->index_read_idx(table->record[0], 0, - (byte*) table->field[0]->ptr, - table->key_info[0].key_length, + (byte*) table->field[0]->ptr, ~ULL(0), HA_READ_KEY_EXACT)) { int error; diff --git a/sql/table.cc b/sql/table.cc index cf2eb1705a5..894e8b82266 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1223,12 +1223,12 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, if ((int) (share->next_number_index= (uint) find_ref_key(share->key_info, share->keys, share->default_values, reg_field, - &share->next_number_key_offset)) < 0) + &share->next_number_key_offset, + &share->next_number_keypart)) < 0) { /* Wrong field definition */ - DBUG_ASSERT(0); - reg_field->unireg_check= Field::NONE; /* purecov: inspected */ - share->found_next_number_field= 0; + error= 4; + goto err; } else reg_field->flags |= AUTO_INCREMENT_FLAG; @@ -2245,6 +2245,30 @@ char *get_field(MEM_ROOT *mem, Field *field) return to; } +/* + DESCRIPTION + given a buffer with a key value, and a map of keyparts + that are present in this value, returns the length of the value +*/ +uint calculate_key_len(TABLE *table, uint key, const byte *buf, + ulonglong keypart_map) +{ + /* works only with key prefixes */ + DBUG_ASSERT(((keypart_map + 1) & keypart_map) == 0); + + KEY *key_info= table->s->key_info+key; + KEY_PART_INFO *key_part= key_info->key_part; + KEY_PART_INFO *end_key_part= key_part + key_info->key_parts; + uint length= 0; + + while (key_part < end_key_part && keypart_map) + { + length+= key_part->store_length; + keypart_map >>= 1; + key_part++; + } + return length; +} /* Check if database name is valid @@ -3936,7 +3960,7 @@ void st_table::mark_auto_increment_column() */ bitmap_set_bit(read_set, found_next_number_field->field_index); bitmap_set_bit(write_set, found_next_number_field->field_index); - if (s->next_number_key_offset) + if (s->next_number_keypart) mark_columns_used_by_index_no_reset(s->next_number_index, read_set); file->column_bitmaps_signal(); } diff --git a/sql/table.h b/sql/table.h index 82083d79570..841a1f7d038 100644 --- a/sql/table.h +++ b/sql/table.h @@ -194,6 +194,7 @@ typedef struct st_table_share uint primary_key; uint next_number_index; uint next_number_key_offset; + uint next_number_keypart; uint error, open_errno, errarg; /* error from open_table_def() */ uint column_bitmap_size; uchar frm_version; diff --git a/sql/tztime.cc b/sql/tztime.cc index fe91aa71272..6704a7874a4 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1900,9 +1900,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) (void)table->file->ha_index_init(0, 1); if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - 0, HA_READ_KEY_EXACT)) + ~(ulonglong)0, HA_READ_KEY_EXACT)) { -#ifdef EXTRA_DEBUG +#ifdef EXTRA_DEBUG /* Most probably user has mistyped time zone name, so no need to bark here unless we need it for debugging. @@ -1928,7 +1928,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) (void)table->file->ha_index_init(0, 1); if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - 0, HA_READ_KEY_EXACT)) + ~(ulonglong)0, HA_READ_KEY_EXACT)) { sql_print_error("Can't find description of time zone '%u'", tzid); goto end; @@ -1955,9 +1955,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) table->field[0]->store((longlong) tzid, TRUE); (void)table->file->ha_index_init(0, 1); - // FIXME Is there any better approach than explicitly specifying 4 ??? res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - 4, HA_READ_KEY_EXACT); + (ulonglong)1, HA_READ_KEY_EXACT); while (!res) { ttid= (uint)table->field[1]->val_int(); @@ -2028,9 +2027,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) table->field[0]->store((longlong) tzid, TRUE); (void)table->file->ha_index_init(0, 1); - // FIXME Is there any better approach than explicitly specifying 4 ??? res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - 4, HA_READ_KEY_EXACT); + (ulonglong)1, HA_READ_KEY_EXACT); while (!res) { ttime= (my_time_t)table->field[1]->val_int(); diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index 7bdb4e40b3d..b128ab16cc7 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -152,7 +152,8 @@ THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd, int ha_blackhole::index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, uint key_len, + enum ha_rkey_function find_flag) { DBUG_ENTER("ha_blackhole::index_read"); DBUG_RETURN(0); @@ -160,14 +161,16 @@ int ha_blackhole::index_read(byte * buf, const byte * key, int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, uint key_len, + enum ha_rkey_function find_flag) { DBUG_ENTER("ha_blackhole::index_read_idx"); DBUG_RETURN(HA_ERR_END_OF_FILE); } -int ha_blackhole::index_read_last(byte * buf, const byte * key, uint key_len) +int ha_blackhole::index_read_last(byte * buf, const byte * key, + ulonglong keypart_map) { DBUG_ENTER("ha_blackhole::index_read_last"); DBUG_RETURN(HA_ERR_END_OF_FILE); diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h index 5388dcfc187..cd8b6491dba 100644 --- a/storage/blackhole/ha_blackhole.h +++ b/storage/blackhole/ha_blackhole.h @@ -64,11 +64,12 @@ public: int rnd_init(bool scan); int rnd_next(byte *buf); int rnd_pos(byte * buf, byte *pos); - int index_read(byte * buf, const byte * key, + int index_read(byte * buf, const byte * key, ulonglong keypart_map, uint key_len, enum ha_rkey_function find_flag); int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_last(byte * buf, const byte * key, uint key_len); + ulonglong keypart_map, uint key_len, + enum ha_rkey_function find_flag); + int index_read_last(byte * buf, const byte * key, ulonglong keypart_map); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 12ca91f0a6f..65554eb1252 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -90,14 +90,13 @@ static handler *example_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); -static int example_init_func(); +static int example_init_func(void *); handlerton *example_hton; /* Variables for example share methods */ static HASH example_open_tables; ///< Hash used to track the number of open tables; variable for example share methods pthread_mutex_t example_mutex; ///< This is the mutex used to init the hash; variable for example share methods -static int example_init= 0; ///< This variable is used to check the init state of hash; variable for example share methods /** @brief Function we use in the creation of our hash to get key. @@ -372,7 +371,7 @@ int ha_example::delete_row(const byte * buf) index. */ int ha_example::index_read(byte * buf, const byte * key, - uint key_len __attribute__((unused)), + ulonglong keypart_map __attribute__((unused)), enum ha_rkey_function find_flag __attribute__((unused))) { diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h index 9b912514887..ee60b412974 100644 --- a/storage/example/ha_example.h +++ b/storage/example/ha_example.h @@ -191,7 +191,7 @@ public: skip it and and MySQL will treat it as not implemented. */ int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); + ulonglong keypart_map, enum ha_rkey_function find_flag); /** @brief We implement this in ha_example.cc. It's not an obligatory method; diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 9290418c7aa..cb599715b9d 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -362,7 +362,7 @@ static handler *federated_create_handler(handlerton *hton, MEM_ROOT *mem_root); static int federated_commit(handlerton *hton, THD *thd, bool all); static int federated_rollback(handlerton *hton, THD *thd, bool all); -static int federated_db_init(void); +static int federated_db_init(void *); /* Federated storage engine handlerton */ @@ -573,9 +573,6 @@ int get_connection(FEDERATED_SHARE *share) int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; FOREIGN_SERVER *server; - MYSQL *mysql_conn= 0; - MYSQL_RES *result= 0; - MYSQL_ROW row= 0; DBUG_ENTER("ha_federated::get_connection"); if (!(server= diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 7a2f8e20c56..c0ca0af3923 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -238,34 +238,35 @@ int ha_heap::delete_row(const byte * buf) return res; } -int ha_heap::index_read(byte * buf, const byte * key, uint key_len, +int ha_heap::index_read(byte * buf, const byte * key, ulonglong keypart_map, enum ha_rkey_function find_flag) { DBUG_ASSERT(inited==INDEX); statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error = heap_rkey(file,buf,active_index, key, key_len, find_flag); + int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag); table->status = error ? STATUS_NOT_FOUND : 0; return error; } -int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len) +int ha_heap::index_read_last(byte *buf, const byte *key, ulonglong keypart_map) { DBUG_ASSERT(inited==INDEX); statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error= heap_rkey(file, buf, active_index, key, key_len, + int error= heap_rkey(file, buf, active_index, key, keypart_map, HA_READ_PREFIX_LAST); table->status= error ? STATUS_NOT_FOUND : 0; return error; } int ha_heap::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, + enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error = heap_rkey(file, buf, index, key, key_len, find_flag); + int error = heap_rkey(file, buf, index, key, keypart_map, find_flag); table->status = error ? STATUS_NOT_FOUND : 0; return error; } diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h index 2de80c76999..b49ded6e33d 100644 --- a/storage/heap/ha_heap.h +++ b/storage/heap/ha_heap.h @@ -75,11 +75,11 @@ public: ulonglong nb_desired_values, ulonglong *first_value, ulonglong *nb_reserved_values); - int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_last(byte * buf, const byte * key, uint key_len); + int index_read(byte * buf, const byte * key, ulonglong keypart_map, + enum ha_rkey_function find_flag); + int index_read_last(byte *buf, const byte *key, ulonglong keypart_map); + int index_read_idx(byte * buf, uint index, const byte * key, + ulonglong keypart_map, enum ha_rkey_function find_flag); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/heap/heapdef.h b/storage/heap/heapdef.h index 016c83db8e0..d9c3ff147b4 100644 --- a/storage/heap/heapdef.h +++ b/storage/heap/heapdef.h @@ -100,7 +100,7 @@ extern int hp_close(register HP_INFO *info); extern void hp_clear(HP_SHARE *info); extern void hp_clear_keys(HP_SHARE *info); extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, - uint k_len); + ulonglong keypart_map); #ifdef THREAD extern pthread_mutex_t THR_LOCK_heap; #else diff --git a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c index c5a30a3ef65..326f6adea45 100644 --- a/storage/heap/hp_hash.c +++ b/storage/heap/hp_hash.c @@ -784,30 +784,26 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key, uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, - uint k_len) + ulonglong keypart_map) { HA_KEYSEG *seg, *endseg; uchar *start_key= key; for (seg= keydef->seg, endseg= seg + keydef->keysegs; - seg < endseg && (int) k_len > 0; old+= seg->length, seg++) + seg < endseg && keypart_map; old+= seg->length, seg++) { uint char_length; + keypart_map>>= 1; if (seg->null_bit) { - k_len--; if (!(*key++= (char) 1 - *old++)) - { - k_len-= seg->length; continue; } - } if (seg->flag & HA_SWAP_KEY) { uint length= seg->length; byte *pos= (byte*) old + length; - k_len-= length; while (length--) { *key++= *--pos; @@ -822,7 +818,6 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, CHARSET_INFO *cs= seg->charset; char_length= length/cs->mbmaxlen; - k_len-= 2+length; old+= 2; set_if_smaller(length,tmp_length); /* Safety */ FIX_LENGTH(cs, old, length, char_length); @@ -843,7 +838,6 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, } memcpy(key, old, (size_t) char_length); key+= seg->length; - k_len-= seg->length; } return (uint) (key - start_key); } diff --git a/storage/heap/hp_rkey.c b/storage/heap/hp_rkey.c index a095336d295..98714bf875f 100644 --- a/storage/heap/hp_rkey.c +++ b/storage/heap/hp_rkey.c @@ -16,7 +16,7 @@ #include "heapdef.h" int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, enum ha_rkey_function find_flag) { byte *pos; HP_SHARE *share= info->s; @@ -38,7 +38,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, custom_arg.keyseg= info->s->keydef[inx].seg; custom_arg.key_length= info->lastkey_len= hp_rb_pack_key(keyinfo, (uchar*) info->lastkey, - (uchar*) key, key_len); + (uchar*) key, keypart_map); custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME; /* for next rkey() after deletion */ if (find_flag == HA_READ_AFTER_KEY) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b5b354d4b39..bebd0422a24 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3920,14 +3920,14 @@ statement issued by the user. We also increment trx->n_mysql_tables_in_use. 2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search instructions to prebuilt->template of the table handle instance in -::index_read. The template is used to save CPU time in large joins. +::index_read_old. The template is used to save CPU time in large joins. 3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we allocate a new consistent read view for the trx if it does not yet have one, or in the case of a locking read, set an InnoDB 'intention' table level lock on the table. - 4) We do the SELECT. MySQL may repeatedly call ::index_read for the + 4) We do the SELECT. MySQL may repeatedly call ::index_read_old for the same table handle instance, if it is a join. 5) When the SELECT ends, MySQL removes its intention table level locks @@ -3941,7 +3941,7 @@ table handler in that case has to execute the COMMIT in ::external_lock. B) If the user has explicitly set MySQL table level locks, then MySQL does NOT call ::external_lock at the start of the statement. To determine when we are at the start of a new SQL statement we at the start of -::index_read also compare the query id to the latest query id where the +::index_read_old also compare the query id to the latest query id where the table handle instance was used. If it has changed, we know we are at the start of a new SQL statement. Since the query id can theoretically overwrap, we use this test only as a secondary way of determining the @@ -3978,7 +3978,7 @@ ha_innobase::index_read( int error; ulint ret; - DBUG_ENTER("index_read"); + DBUG_ENTER("index_read_old"); ut_a(prebuilt->trx == (trx_t*) current_thd->ha_data[ht->slot]); @@ -4060,7 +4060,7 @@ ha_innobase::index_read( } /*********************************************************************** -The following functions works like index_read, but it find the last +The following functions works like index_read_old, but it find the last row with the current key value or prefix. */ int @@ -4166,7 +4166,7 @@ ha_innobase::index_read_idx( /*************************************************************************** Reads the next or previous row from a cursor, which must have previously been -positioned using index_read. */ +positioned using index_read_old. */ int ha_innobase::general_fetch( @@ -4215,7 +4215,7 @@ ha_innobase::general_fetch( /*************************************************************************** Reads the next row from a cursor, which must have previously been -positioned using index_read. */ +positioned using index_read_old. */ int ha_innobase::index_next( @@ -4251,7 +4251,7 @@ ha_innobase::index_next_same( /*************************************************************************** Reads the previous row from a cursor, which must have previously been -positioned using index_read. */ +positioned using index_read_old. */ int ha_innobase::index_prev( diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 397856a4a4e..83180872f5f 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1203,34 +1203,37 @@ int ha_myisam::delete_row(const byte * buf) return mi_delete(file,buf); } -int ha_myisam::index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag) +int ha_myisam::index_read(byte *buf, const byte *key, ulonglong keypart_map, + enum ha_rkey_function find_flag) { DBUG_ASSERT(inited==INDEX); statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error=mi_rkey(file,buf,active_index, key, key_len, find_flag); + int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; return error; } -int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len, enum ha_rkey_function find_flag) +int ha_myisam::index_read_idx(byte *buf, uint index, const byte *key, + ulonglong keypart_map, + enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error=mi_rkey(file,buf,index, key, key_len, find_flag); + int error=mi_rkey(file, buf, index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; return error; } -int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len) +int ha_myisam::index_read_last(byte *buf, const byte *key, + ulonglong keypart_map) { DBUG_ENTER("ha_myisam::index_read_last"); DBUG_ASSERT(inited==INDEX); statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error=mi_rkey(file,buf,active_index, key, key_len, HA_READ_PREFIX_LAST); + int error=mi_rkey(file, buf, active_index, key, keypart_map, + HA_READ_PREFIX_LAST); table->status=error ? STATUS_NOT_FOUND: 0; DBUG_RETURN(error); } @@ -1338,7 +1341,7 @@ int ha_myisam::info(uint flag) stats.index_file_length=info.index_file_length; stats.delete_length = info.delete_length; stats.check_time = info.check_time; - stats. mean_rec_length=info.mean_reclength; + stats.mean_rec_length=info.mean_reclength; } if (flag & HA_STATUS_CONST) { @@ -1698,8 +1701,9 @@ void ha_myisam::get_auto_increment(ulonglong offset, ulonglong increment, key_copy(key, table->record[0], table->key_info + table->s->next_number_index, table->s->next_number_key_offset); - error= mi_rkey(file,table->record[1],(int) table->s->next_number_index, - key,table->s->next_number_key_offset,HA_READ_PREFIX_LAST); + error= mi_rkey(file, table->record[1], (int) table->s->next_number_index, + key, make_prev_keypart_map(table->s->next_number_keypart), + HA_READ_PREFIX_LAST); if (error) nr= 1; else diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 882900bd35f..b66a9e5cca4 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -69,11 +69,11 @@ class ha_myisam: public handler int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); int delete_row(const byte * buf); - int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_last(byte * buf, const byte * key, uint key_len); + int index_read(byte *buf, const byte *key, ulonglong keypart_map, + enum ha_rkey_function find_flag); + int index_read_idx(byte *buf, uint index, const byte *key, + ulonglong keypart_map, enum ha_rkey_function find_flag); + int index_read_last(byte *buf, const byte *key, ulonglong keypart_map); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 7bcb8041fe0..5c67404559e 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -532,7 +532,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) mi_extra(info,HA_EXTRA_KEYREAD,0); bzero(info->lastkey,keyinfo->seg->length); if (!mi_rkey(info, info->rec_buff, key, (const byte*) info->lastkey, - keyinfo->seg->length, HA_READ_KEY_EXACT)) + ULL(1), HA_READ_KEY_EXACT)) { /* Don't count this as a real warning, as myisamchk can't correct it */ uint save=param->warning_printed; diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c index b203286d544..1b7ba676139 100644 --- a/storage/myisam/mi_key.c +++ b/storage/myisam/mi_key.c @@ -206,7 +206,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, uint keynr key number key Store packed key here old Not packed key - k_length Length of 'old' to use + keypart_map bitmap of used keyparts last_used_keyseg out parameter. May be NULL RETURN @@ -216,34 +216,36 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, */ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, - uint k_length, HA_KEYSEG **last_used_keyseg) + ulonglong keypart_map, HA_KEYSEG **last_used_keyseg) { uchar *start_key=key; HA_KEYSEG *keyseg; my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT; DBUG_ENTER("_mi_pack_key"); - for (keyseg=info->s->keyinfo[keynr].seg ; - keyseg->type && (int) k_length > 0; - old+=keyseg->length, keyseg++) + /* "one part" rtree key is 2*SPDIMS part key in MyISAM */ + if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE) + keypart_map= (ULL(1) << (2*SPDIMS)) - 1; + + /* only key prefixes are supported */ + DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0); + + for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map; + old+= keyseg->length, keyseg++) { - enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type; - uint length=min((uint) keyseg->length,(uint) k_length); + enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type; + uint length= keyseg->length; uint char_length; uchar *pos; CHARSET_INFO *cs=keyseg->charset; + keypart_map>>= 1; if (keyseg->null_bit) { - k_length--; if (!(*key++= (char) 1-*old++)) /* Copy null marker */ { - k_length-=length; if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) - { - k_length-=2; /* Skip length */ old+= 2; - } continue; /* Found NULL */ } } @@ -262,7 +264,6 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, while (pos < end && pos[0] == ' ') pos++; } - k_length-=length; length=(uint) (end-pos); FIX_LENGTH(cs, pos, length, char_length); store_key_length_inc(key,char_length); @@ -274,7 +275,6 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, { /* Length of key-part used with mi_rkey() always 2 */ uint tmp_length=uint2korr(pos); - k_length-= 2+length; pos+=2; set_if_smaller(length,tmp_length); /* Safety */ FIX_LENGTH(cs, pos, length, char_length); @@ -287,11 +287,8 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, else if (keyseg->flag & HA_SWAP_KEY) { /* Numerical column */ pos+=length; - k_length-=length; while (length--) - { *key++ = *--pos; - } continue; } FIX_LENGTH(cs, pos, length, char_length); @@ -299,30 +296,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, if (length > char_length) cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' '); key+= length; - k_length-=length; } if (last_used_keyseg) *last_used_keyseg= keyseg; -#ifdef NOT_USED - if (keyseg->type) - { - /* Part-key ; fill with ASCII 0 for easier searching */ - length= (uint) -k_length; /* unused part of last key */ - do - { - if (keyseg->flag & HA_NULL_PART) - length++; - if (keyseg->flag & HA_SPACE_PACK) - length+=2; - else - length+= keyseg->length; - keyseg++; - } while (keyseg->type); - bzero((byte*) key,length); - key+=length; - } -#endif DBUG_RETURN((uint) (key-start_key)); } /* _mi_pack_key */ diff --git a/storage/myisam/mi_range.c b/storage/myisam/mi_range.c index 6655f5a7de6..5e5fe3c6b22 100644 --- a/storage/myisam/mi_range.c +++ b/storage/myisam/mi_range.c @@ -21,13 +21,10 @@ #include "myisamdef.h" #include "rt_index.h" -static ha_rows _mi_record_pos(MI_INFO *info,const byte *key,uint key_len, - enum ha_rkey_function search_flag); -static double _mi_search_pos(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, - uint key_len,uint nextflag,my_off_t pos); -static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, - uchar *keypos,uint *ret_max_key); - +static ha_rows _mi_record_pos(MI_INFO *, const byte *, ulonglong, + enum ha_rkey_function); +static double _mi_search_pos(MI_INFO *,MI_KEYDEF *,uchar *, uint,uint,my_off_t); +static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *,uchar *, uchar *,uint *); /* Estimate how many records there is in a given range @@ -47,9 +44,8 @@ static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, number Estimated number of rows */ - -ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key, - key_range *max_key) +ha_rows mi_records_in_range(MI_INFO *info, int inx, + key_range *min_key, key_range *max_key) { ha_rows start_pos,end_pos,res; DBUG_ENTER("mi_records_in_range"); @@ -87,7 +83,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key, } key_buff= info->lastkey+info->s->base.max_key_length; start_key_len= _mi_pack_key(info,inx, key_buff, - (uchar*) min_key->key, min_key->length, + (uchar*) min_key->key, min_key->keypart_map, (HA_KEYSEG**) 0); res= rtree_estimate(info, inx, key_buff, start_key_len, myisam_read_vec[min_key->flag]); @@ -97,14 +93,12 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key, #endif case HA_KEY_ALG_BTREE: default: - start_pos= (min_key ? - _mi_record_pos(info, min_key->key, min_key->length, - min_key->flag) : - (ha_rows) 0); - end_pos= (max_key ? - _mi_record_pos(info, max_key->key, max_key->length, - max_key->flag) : - info->state->records+ (ha_rows) 1); + start_pos= (min_key ? _mi_record_pos(info, min_key->key, + min_key->keypart_map, min_key->flag) + : (ha_rows) 0); + end_pos= (max_key ? _mi_record_pos(info, max_key->key, + max_key->keypart_map, max_key->flag) + : info->state->records + (ha_rows) 1); res= (end_pos < start_pos ? (ha_rows) 0 : (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos)); if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) @@ -122,21 +116,21 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key, /* Find relative position (in records) for key in index-tree */ -static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, uint key_len, +static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, + ulonglong keypart_map, enum ha_rkey_function search_flag) { - uint inx=(uint) info->lastinx, nextflag; + uint inx=(uint) info->lastinx, nextflag, key_len; MI_KEYDEF *keyinfo=info->s->keyinfo+inx; uchar *key_buff; double pos; DBUG_ENTER("_mi_record_pos"); DBUG_PRINT("enter",("search_flag: %d",search_flag)); + DBUG_ASSERT(keypart_map); - if (key_len == 0) - key_len=USE_WHOLE_KEY; key_buff=info->lastkey+info->s->base.max_key_length; - key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key,key_len, + key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key, keypart_map, (HA_KEYSEG**) 0); DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg, (uchar*) key_buff,key_len);); diff --git a/storage/myisam/mi_rkey.c b/storage/myisam/mi_rkey.c index 6323c95ffd7..027d3d8dea0 100644 --- a/storage/myisam/mi_rkey.c +++ b/storage/myisam/mi_rkey.c @@ -21,8 +21,8 @@ /* Read a record using key */ /* Ordinary search_flag is 0 ; Give error if no record with key */ -int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, - enum ha_rkey_function search_flag) +int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, + ulonglong keypart_map, enum ha_rkey_function search_flag) { uchar *key_buff; MYISAM_SHARE *share=info->s; @@ -30,8 +30,8 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, HA_KEYSEG *last_used_keyseg; uint pack_key_length, use_key_length, nextflag; DBUG_ENTER("mi_rkey"); - DBUG_PRINT("enter", ("base: %lx buf: %lx inx: %d search_flag: %d", - (long) info, (long) buf, inx, search_flag)); + DBUG_PRINT("enter", ("base: %lx buf: %lx inx: %d keyparts %lx search_flag: %d", + (long) info, (long) buf, inx, keypart_map, search_flag)); if ((inx = _mi_check_index(info,inx)) < 0) DBUG_RETURN(my_errno); @@ -47,18 +47,17 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, key is already packed!; This happens when we are using a MERGE TABLE */ key_buff=info->lastkey+info->s->base.max_key_length; - pack_key_length= key_len; - bmove(key_buff,key,key_len); + pack_key_length= keypart_map; + bmove(key_buff, key, pack_key_length); last_used_keyseg= 0; } else { - if (key_len == 0) - key_len=USE_WHOLE_KEY; + DBUG_ASSERT(keypart_map); /* Save the packed key for later use in the second buffer of lastkey. */ key_buff=info->lastkey+info->s->base.max_key_length; pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key, - key_len, &last_used_keyseg); + keypart_map, &last_used_keyseg); /* Save packed_key_length for use by the MERGE engine. */ info->pack_key_length= pack_key_length; DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE, keyinfo->seg, diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h index dceccd10ae2..f1ca1754696 100644 --- a/storage/myisam/myisamdef.h +++ b/storage/myisam/myisamdef.h @@ -604,8 +604,9 @@ extern int _mi_dispose(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos, extern my_off_t _mi_new(MI_INFO *info,MI_KEYDEF *keyinfo,int level); extern uint _mi_make_key(MI_INFO *info,uint keynr,uchar *key, const byte *record,my_off_t filepos); -extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old, - uint key_length, HA_KEYSEG **last_used_keyseg); +extern uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, + uchar *old, ulonglong keypart_map, + HA_KEYSEG **last_used_keyseg); extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf); extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos, uint length,int re_read_if_possibly); diff --git a/storage/myisam/rt_test.c b/storage/myisam/rt_test.c index 1126266d2f9..55b52c0c3bf 100644 --- a/storage/myisam/rt_test.c +++ b/storage/myisam/rt_test.c @@ -323,7 +323,7 @@ static int run_test(const char *filename) range.key= record+1; range.length= 1000; /* Big enough */ range.flag= HA_READ_MBR_INTERSECT; - hrows= mi_records_in_range(file,0, &range, (key_range*) 0); + hrows= mi_records_in_range(file, 0, &range, (key_range*) 0); printf(" %ld rows\n", (long) hrows); if (mi_close(file)) goto err; diff --git a/storage/myisam/sp_test.c b/storage/myisam/sp_test.c index c7226589811..96ba05e8a74 100644 --- a/storage/myisam/sp_test.c +++ b/storage/myisam/sp_test.c @@ -255,7 +255,7 @@ int run_test(const char *filename) max_range.key= record+1; max_range.length= 1000; /* Big enough */ max_range.flag= HA_READ_KEY_EXACT; - hrows= mi_records_in_range(file,0, &min_range, &max_range); + hrows= mi_records_in_range(file, 0, &min_range, &max_range); printf(" %ld rows\n", (long) hrows); if (mi_close(file)) goto err; diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 7df81a4802f..9ed24f35aba 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -145,30 +145,33 @@ int ha_myisammrg::delete_row(const byte * buf) } int ha_myisammrg::index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, + enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error=myrg_rkey(file,buf,active_index, key, key_len, find_flag); + int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; return error; } int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len, enum ha_rkey_function find_flag) + ulonglong keypart_map, + enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error=myrg_rkey(file,buf,index, key, key_len, find_flag); + int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; return error; } -int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len) +int ha_myisammrg::index_read_last(byte * buf, const byte * key, + ulonglong keypart_map) { statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); - int error=myrg_rkey(file,buf,active_index, key, key_len, + int error=myrg_rkey(file,buf,active_index, key, keypart_map, HA_READ_PREFIX_LAST); table->status=error ? STATUS_NOT_FOUND: 0; return error; diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index ffa55673ad1..ee2a46e3d00 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -56,11 +56,11 @@ class ha_myisammrg: public handler int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); int delete_row(const byte * buf); - int index_read(byte * buf, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_idx(byte * buf, uint idx, const byte * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_last(byte * buf, const byte * key, uint key_len); + int index_read(byte * buf, const byte * key, ulonglong keypart_map, + enum ha_rkey_function find_flag); + int index_read_idx(byte * buf, uint index, const byte * key, + ulonglong keypart_map, enum ha_rkey_function find_flag); + int index_read_last(byte * buf, const byte * key, ulonglong keypart_map); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/myisammrg/myrg_rkey.c b/storage/myisammrg/myrg_rkey.c index f7b7f082019..2273f7d62b8 100644 --- a/storage/myisammrg/myrg_rkey.c +++ b/storage/myisammrg/myrg_rkey.c @@ -36,7 +36,7 @@ */ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, - uint key_len, enum ha_rkey_function search_flag) + ulonglong keypart_map, enum ha_rkey_function search_flag) { byte *key_buff; uint pack_key_length; @@ -56,7 +56,7 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, if (table == info->open_tables) { - err=mi_rkey(mi,0,inx,key,key_len,search_flag); + err=mi_rkey(mi, 0, inx, key, keypart_map, search_flag); /* Get the saved packed key and packed key length. */ key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length; pack_key_length=mi->pack_key_length; @@ -64,7 +64,7 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, else { mi->once_flags|= USE_PACKED_KEYS; - err=mi_rkey(mi,0,inx,key_buff,pack_key_length,search_flag); + err=mi_rkey(mi, 0, inx, key_buff, pack_key_length, search_flag); } info->last_used_table=table+1; From 2141f9f0ee1df4d476feaed1c2b233d54e2ef5e8 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Mon, 29 Jan 2007 18:07:02 +0100 Subject: [PATCH 05/34] making diff-p-helper obsolete --- BitKeeper/triggers/post-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index 86f3db012ee..b4dcb311dde 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -72,7 +72,7 @@ X-CSetKey: <$CSETKEY> $BH EOF bk changes -v -r+ - bk cset -r+ -d + bk rset -r+ -ah | bk gnupatch -h -dup -T ) > $BKROOT/BitKeeper/tmp/dev_public.txt $SENDMAIL -t < $BKROOT/BitKeeper/tmp/dev_public.txt From 3dafdf7de257f6a24c489eff9dd7416ad54c7d26 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Wed, 14 Feb 2007 12:42:11 +0100 Subject: [PATCH 06/34] /usr/share/aclocal/mysql.m4 --- server-tools/CMakeLists.txt | 0 support-files/Makefile.am | 3 + support-files/mysql.m4 | 108 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) mode change 100755 => 100644 server-tools/CMakeLists.txt create mode 100644 support-files/mysql.m4 diff --git a/server-tools/CMakeLists.txt b/server-tools/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/support-files/Makefile.am b/support-files/Makefile.am index da8c25ccb1e..ce39b67ef5d 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -43,6 +43,9 @@ pkgdata_DATA = my-small.cnf \ pkgdata_SCRIPTS = mysql.server +aclocaldir = $(datadir)/aclocal +aclocal_DATA = mysql.m4 + noinst_DATA = mysql-@VERSION@.spec \ MySQL-shared-compat.spec diff --git a/support-files/mysql.m4 b/support-files/mysql.m4 new file mode 100644 index 00000000000..a440353c196 --- /dev/null +++ b/support-files/mysql.m4 @@ -0,0 +1,108 @@ +# Copyright (C) 2007 MySQL AB +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA + +AC_DEFUN([_MYSQL_CONFIG],[ + AC_ARG_WITH([mysql-config], + AS_HELP_STRING([--with-mysql-config=PATH], [A path to mysql_config script]), + [mysql_config="$withval"], [mysql_config=mysql_config]) +]) + +dnl +dnl Usage: +dnl +dnl MYSQL_CLIENT([version], [client|thread-safe|embedded]) +dnl +dnl Two optional arguments: +dnl first: The minimal version of the MySQL to use +dnl if not specified, any version will be accepted. +dnl The version should be specified as three numbers, +dnl without suffixes. E.g. 4.10.15 or 5.0.3 +dnl second: force the specified library flavor to be selected, +dnl if not specified, a user will be able to choose +dnl between client (non-thread-safe) and embedded +dnl +dnl On successful execution sets MYSQL_CLIENT_CFLAGS and +dnl MYSQL_CLIENT_LIBS shell variables and makes substitutions +dnl out of them (calls AC_SUBST) +dnl + +AC_DEFUN([MYSQL_CLIENT],[ + AC_REQUIRE([_MYSQL_CONFIG]) + AC_MSG_CHECKING([for MySQL]) + ifelse([$2], [client], + [mysql_libs=--libs mysql_cflags=--cflags], + [$2], [thread-safe], + [mysql_libs=--libs_r mysql_cflags=--cflags], + [$2], [embedded], + [mysql_libs=--libmysqld-libs mysql_cflags=--cflags], + [$2], [], [ + AC_ARG_WITH([mysql-library], + AS_HELP_STRING([--with-mysql-library], ['client' or 'embedded']), + [mysql_lib="$withval"], [mysql_lib=client]) +[ + case "$mysql_lib" in + client) mysql_libs=--libs mysql_cflags=--cflags ;; + embedded) mysql_libs=--libmysqld-libs mysql_cflags=--cflags ;; + *) ]AC_MSG_ERROR([Bad value for --with-mysql-library])[ + esac +] + ], + [AC_FATAL([Bad second (library flavor) argument to MYSQL_CLIENT])]) +[ + mysql_version=`$mysql_config --version` + if test -z "$mysql_version" ; then + ]AC_MSG_ERROR([Cannot execute $mysql_config])[ + fi +] + ifelse([$1], [], [], [ + ifelse(regexp([$1], [^[0-9][0-9]?\.[0-9][0-9]?\.[0-9][0-9]?$]), -1, + [AC_FATAL([Bad first (version) argument to MYSQL_CLIENT])], [ +dnl +dnl Transformation below works as follows: +dnl assume, we have a number 1.2.3-beta +dnl *a* line removes the suffix and adds first and last dot to the version: +dnl .1.2.3. +dnl *b* line adds a 0 to a "single digit surrounded by dots" +dnl .01.2.03. +dnl note that the pattern that matched .1. has eaten the dot for .2. +dnl and 2 still has no 0 +dnl *c* we repeat the same replacement as in *b*, matching .2. this time +dnl .01.02.03. +dnl the last replacement removes all dots +dnl 010203 +dnl giving us a number we can compare with +dnl + mysql_ver=`echo ${mysql_version}|dnl + sed 's/[[-a-z]].*//; s/.*/.&./;dnl *a* + s/\.\([[0-9]]\)\./.0\1./g;dnl *b* + s/\.\([[0-9]]\)\./.0\1./g;dnl *c* + s/\.//g'` + if test "$mysql_ver" -lt]dnl +dnl the same as sed transformation above, without suffix-stripping, in m4 + patsubst(patsubst(patsubst(.[$1]., [\.\([0-9]\)\.], [.0\1.]), [\.\([0-9]\)\.], [.0\1.]), [\.], [])[ ; then + AC_MSG_ERROR([MySQL version $mysql_version is too low, minimum of $1 is required]) + fi + ])]) + + MYSQL_CLIENT_CFLAGS=`$mysql_config $mysql_cflags` + MYSQL_CLIENT_LIBS=`$mysql_config $mysql_libs` + AC_SUBST(MYSQL_CLIENT_CFLAGS) + AC_SUBST(MYSQL_CLIENT_LIBS) + + # should we try to build a test program ? + + AC_MSG_RESULT([$mysql_version]) +]) + From ecc2dde594a251229fbfea568f76590b7fe10529 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Wed, 21 Feb 2007 19:18:09 +0100 Subject: [PATCH 07/34] after merge --- sql/opt_range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6eb7d927ed6..f87439dd3eb 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8195,7 +8195,7 @@ int QUICK_RANGE_SELECT::get_next() */ end_key->flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); - end_key->keypart_map= range->max_keypart_map; + end_key->keypart_map= last_range->max_keypart_map; mrange_slot->range_flag= last_range->flag; } From 151aa17bfe533c05e16d89f2e5202130bcd12720 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Mon, 5 Mar 2007 02:09:24 +0400 Subject: [PATCH 08/34] bug #26538 (flush2.test fails in embedded run) in the embedded result we don't have 'log_slave_updates OFF' line as replication is disabled in the embedded server. As we don't need to check for log_slave_updates variable in this test, we can not to SHOW it at all --- mysql-test/r/flush2.result | 18 ++---------------- mysql-test/t/flush2.test | 4 ++-- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/flush2.result b/mysql-test/r/flush2.result index 8257fa05b41..13bcc371ef6 100644 --- a/mysql-test/r/flush2.result +++ b/mysql-test/r/flush2.result @@ -1,26 +1,12 @@ flush logs; set global expire_logs_days = 3; -show variables like 'log%'; +show variables like 'log_bin%'; Variable_name Value -log ON log_bin OFF log_bin_trust_function_creators ON -log_error -log_output TABLE -log_queries_not_using_indexes OFF -log_slave_updates OFF -log_slow_queries OFF -log_warnings 1 flush logs; -show variables like 'log%'; +show variables like 'log_bin%'; Variable_name Value -log ON log_bin OFF log_bin_trust_function_creators ON -log_error -log_output TABLE -log_queries_not_using_indexes OFF -log_slave_updates OFF -log_slow_queries OFF -log_warnings 1 set global expire_logs_days = 0; diff --git a/mysql-test/t/flush2.test b/mysql-test/t/flush2.test index fc9e88e3141..7582ab8426b 100644 --- a/mysql-test/t/flush2.test +++ b/mysql-test/t/flush2.test @@ -3,7 +3,7 @@ # flush logs; set global expire_logs_days = 3; -show variables like 'log%'; +show variables like 'log_bin%'; flush logs; -show variables like 'log%'; +show variables like 'log_bin%'; set global expire_logs_days = 0; From b9c82eaa89f79ce7f2898a3fdd1823102c44a09a Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Mon, 5 Mar 2007 19:08:41 +0200 Subject: [PATCH 09/34] WL#3527: Extend IGNORE INDEX so places where index is ignored can be specified Currently MySQL allows one to specify what indexes to ignore during join optimization. The scope of the current USE/FORCE/IGNORE INDEX statement is only the FROM clause, while all other clauses are not affected. However, in certain cases, the optimizer may incorrectly choose an index for sorting and/or grouping, and produce an inefficient query plan. This task provides the means to specify what indexes are ignored/used for what operation in a more fine-grained manner, thus making it possible to manually force a better plan. We do this by extending the current IGNORE/USE/FORCE INDEX syntax to: IGNORE/USE/FORCE INDEX [FOR {JOIN | ORDER | GROUP BY}] so that: - if no FOR is specified, the index hint will apply everywhere. - if MySQL is started with the compatibility option --old_mode then an index hint without a FOR clause works as in 5.0 (i.e, the index will only be ignored for JOINs, but can still be used to compute ORDER BY). See the WL#3527 for further details. --- mysql-test/r/endspace.result | 15 +-- mysql-test/r/group_by.result | 112 +++++++++++++++++++++-- mysql-test/t/endspace.test | 9 +- mysql-test/t/group_by.test | 66 +++++++++++++- sql/item.cc | 2 +- sql/mysql_priv.h | 3 +- sql/mysqld.cc | 7 +- sql/mysqld.cc.rej | 17 ---- sql/opt_range.cc | 8 +- sql/sql_base.cc | 37 ++------ sql/sql_class.h | 6 ++ sql/sql_delete.cc | 4 +- sql/sql_help.cc | 2 +- sql/sql_lex.cc | 91 +++++++++++++++---- sql/sql_lex.h | 81 +++++++++++++++-- sql/sql_parse.cc | 13 +-- sql/sql_parse.cc.rej | 166 ---------------------------------- sql/sql_select.cc | 96 ++++++++++++-------- sql/sql_show.cc | 6 +- sql/sql_update.cc | 16 ++-- sql/sql_yacc.yy | 162 +++++++++++++++++---------------- sql/table.cc | 171 ++++++++++++++++++++++++++++++++++- sql/table.cc.rej | 17 ---- sql/table.h | 29 +++++- storage/myisam/ha_myisam.cc | 49 +++++----- 25 files changed, 727 insertions(+), 458 deletions(-) delete mode 100644 sql/mysqld.cc.rej delete mode 100644 sql/sql_parse.cc.rej delete mode 100644 sql/table.cc.rej diff --git a/mysql-test/r/endspace.result b/mysql-test/r/endspace.result index 0e68418a80f..d7135fe3e2c 100644 --- a/mysql-test/r/endspace.result +++ b/mysql-test/r/endspace.result @@ -25,10 +25,11 @@ insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); check table t1; Table Op Msg_type Msg_text test.t1 check status OK -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or +text1 like 'teststring_%' ORDER BY text1; text1 -teststring teststring +teststring select * from t1 where text1='teststring' or text1 like 'teststring_%'; text1 teststring @@ -48,10 +49,11 @@ alter table t1 modify text1 char(32) binary not null; check table t1; Table Op Msg_type Msg_text test.t1 check status OK -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or +text1 like 'teststring_%' ORDER BY text1; text1 -teststring teststring +teststring select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; concat('|', text1, '|') |teststring | @@ -132,10 +134,11 @@ concat('|', text1, '|') drop table t1; create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap; insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or +text1 like 'teststring_%' ORDER BY text1; text1 -teststring teststring +teststring select * from t1 where text1='teststring' or text1 like 'teststring_%'; text1 teststring diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 663ef6cced4..14f517a9520 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -933,12 +933,110 @@ b sum(1) 18 6 19 6 DROP TABLE t1; -CREATE TABLE t1 (a INT, b INT, KEY(a)); -INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); -EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; +CREATE TABLE t1 (a INT, b INT, +PRIMARY KEY (a), +KEY i2(a,b)); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8); +INSERT INTO t1 SELECT a + 8,b FROM t1; +INSERT INTO t1 SELECT a + 16,b FROM t1; +INSERT INTO t1 SELECT a + 32,b FROM t1; +INSERT INTO t1 SELECT a + 64,b FROM t1; +INSERT INTO t1 SELECT a + 128,b FROM t1; +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +EXPLAIN SELECT a FROM t1 WHERE a < 2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 5 NULL 4 -EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; +1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index +EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort -DROP TABLE t1; +1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index +EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY,i2 PRIMARY 4 NULL 2 Using where; Using index +EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 256 +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 256 +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY) +IGNORE INDEX FOR GROUP BY (i2) GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index +EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY) IGNORE INDEX FOR ORDER BY (i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i2 9 NULL 256 Using index +EXPLAIN SELECT a FROM t1 FORCE INDEX (i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i2 9 NULL 256 Using index +EXPLAIN SELECT a FROM t1 USE INDEX (); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 256 +EXPLAIN SELECT a FROM t1 USE INDEX () USE INDEX (i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 256 +EXPLAIN SELECT a FROM t1 +FORCE INDEX (PRIMARY) +IGNORE INDEX FOR GROUP BY (i2) +IGNORE INDEX FOR ORDER BY (i2) +USE INDEX (i2); +ERROR HY000: Incorrect usage of USE INDEX and FORCE INDEX +EXPLAIN SELECT a FROM t1 USE INDEX (i2) USE INDEX (); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i2 9 NULL 256 Using index +EXPLAIN SELECT a FROM t1 FORCE INDEX (); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 +EXPLAIN SELECT a FROM t1 IGNORE INDEX (); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 +EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2) +USE INDEX FOR GROUP BY (i2) GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i2 9 NULL 256 Using index +EXPLAIN SELECT a FROM t1 FORCE INDEX FOR JOIN (i2) +FORCE INDEX FOR GROUP BY (i2) GROUP BY a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL i2 4 NULL 257 Using index for group-by +EXPLAIN SELECT a FROM t1 USE INDEX () IGNORE INDEX (i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 256 +EXPLAIN SELECT a FROM t1 IGNORE INDEX (i2) USE INDEX (); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 256 +EXPLAIN SELECT a FROM t1 +USE INDEX FOR GROUP BY (i2) +USE INDEX FOR ORDER BY (i2) +USE INDEX FOR JOIN (i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i2 9 NULL 256 Using index +EXPLAIN SELECT a FROM t1 +USE INDEX FOR JOIN (i2) +USE INDEX FOR JOIN (i2) +USE INDEX FOR JOIN (i2,i2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL i2 9 NULL 256 Using index +EXPLAIN SELECT 1 FROM t1 WHERE a IN +(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL PRIMARY 4 NULL 256 Using where; Using index +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where +CREATE TABLE t2 (a INT, b INT, KEY(a)); +INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); +EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index NULL a 5 NULL 4 +EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +EXPLAIN SELECT 1 FROM t2 WHERE a IN +(SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where +DROP TABLE t1, t2; diff --git a/mysql-test/t/endspace.test b/mysql-test/t/endspace.test index c4d53450910..b223c683cde 100644 --- a/mysql-test/t/endspace.test +++ b/mysql-test/t/endspace.test @@ -16,7 +16,8 @@ drop table if exists t1; create table t1 (text1 varchar(32) not NULL, KEY key1 (text1)); insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); check table t1; -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or + text1 like 'teststring_%' ORDER BY text1; select * from t1 where text1='teststring' or text1 like 'teststring_%'; select * from t1 where text1='teststring' or text1 > 'teststring\t'; select * from t1 order by text1; @@ -24,7 +25,8 @@ explain select * from t1 order by text1; alter table t1 modify text1 char(32) binary not null; check table t1; -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or + text1 like 'teststring_%' ORDER BY text1; select concat('|', text1, '|') from t1 where text1='teststring' or text1 like 'teststring_%'; select concat('|', text1, '|') from t1 where text1='teststring' or text1 > 'teststring\t'; select text1, length(text1) from t1 order by text1; @@ -57,7 +59,8 @@ drop table t1; create table t1 (text1 varchar(32) not NULL, KEY key1 using BTREE (text1)) engine=heap; insert into t1 values ('teststring'), ('nothing'), ('teststring\t'); -select * from t1 ignore key (key1) where text1='teststring' or text1 like 'teststring_%'; +select * from t1 ignore key (key1) where text1='teststring' or + text1 like 'teststring_%' ORDER BY text1; select * from t1 where text1='teststring' or text1 like 'teststring_%'; select * from t1 where text1='teststring' or text1 >= 'teststring\t'; select * from t1 order by text1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 7f887335753..96ca79e15b5 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -706,10 +706,66 @@ DROP TABLE t1; # Bug #21174: Index degrades sort performance and # optimizer does not honor IGNORE INDEX # -CREATE TABLE t1 (a INT, b INT, KEY(a)); -INSERT INTO t1 VALUES (1, 1), (2, 2), (3,3), (4,4); +CREATE TABLE t1 (a INT, b INT, + PRIMARY KEY (a), + KEY i2(a,b)); +INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8); +INSERT INTO t1 SELECT a + 8,b FROM t1; +INSERT INTO t1 SELECT a + 16,b FROM t1; +INSERT INTO t1 SELECT a + 32,b FROM t1; +INSERT INTO t1 SELECT a + 64,b FROM t1; +INSERT INTO t1 SELECT a + 128,b FROM t1; +ANALYZE TABLE t1; +EXPLAIN SELECT a FROM t1 WHERE a < 2; +EXPLAIN SELECT a FROM t1 WHERE a < 2 ORDER BY a; +EXPLAIN SELECT a FROM t1 WHERE a < 2 GROUP BY a; +EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY,i2); +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR JOIN (PRIMARY,i2); +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR GROUP BY (PRIMARY,i2) GROUP BY a; +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a; +EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY) + IGNORE INDEX FOR GROUP BY (i2) GROUP BY a; +EXPLAIN SELECT a FROM t1 IGNORE INDEX (PRIMARY) IGNORE INDEX FOR ORDER BY (i2); +EXPLAIN SELECT a FROM t1 FORCE INDEX (i2); +EXPLAIN SELECT a FROM t1 USE INDEX (); +EXPLAIN SELECT a FROM t1 USE INDEX () USE INDEX (i2); +--error ER_WRONG_USAGE +EXPLAIN SELECT a FROM t1 + FORCE INDEX (PRIMARY) + IGNORE INDEX FOR GROUP BY (i2) + IGNORE INDEX FOR ORDER BY (i2) + USE INDEX (i2); +EXPLAIN SELECT a FROM t1 USE INDEX (i2) USE INDEX (); +--error ER_PARSE_ERROR +EXPLAIN SELECT a FROM t1 FORCE INDEX (); +--error ER_PARSE_ERROR +EXPLAIN SELECT a FROM t1 IGNORE INDEX (); +EXPLAIN SELECT a FROM t1 USE INDEX FOR JOIN (i2) + USE INDEX FOR GROUP BY (i2) GROUP BY a; +EXPLAIN SELECT a FROM t1 FORCE INDEX FOR JOIN (i2) + FORCE INDEX FOR GROUP BY (i2) GROUP BY a; +EXPLAIN SELECT a FROM t1 USE INDEX () IGNORE INDEX (i2); +EXPLAIN SELECT a FROM t1 IGNORE INDEX (i2) USE INDEX (); -EXPLAIN SELECT a, SUM(b) FROM t1 GROUP BY a LIMIT 2; -EXPLAIN SELECT a, SUM(b) FROM t1 IGNORE INDEX (a) GROUP BY a LIMIT 2; +EXPLAIN SELECT a FROM t1 + USE INDEX FOR GROUP BY (i2) + USE INDEX FOR ORDER BY (i2) + USE INDEX FOR JOIN (i2); -DROP TABLE t1; +EXPLAIN SELECT a FROM t1 + USE INDEX FOR JOIN (i2) + USE INDEX FOR JOIN (i2) + USE INDEX FOR JOIN (i2,i2); + +EXPLAIN SELECT 1 FROM t1 WHERE a IN + (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); + +CREATE TABLE t2 (a INT, b INT, KEY(a)); +INSERT INTO t2 VALUES (1, 1), (2, 2), (3,3), (4,4); +EXPLAIN SELECT a, SUM(b) FROM t2 GROUP BY a LIMIT 2; +EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2; + +EXPLAIN SELECT 1 FROM t2 WHERE a IN + (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); + +DROP TABLE t1, t2; diff --git a/sql/item.cc b/sql/item.cc index e2ab28dd452..0bd5e70773a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3828,7 +3828,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference) { /* First usage of column */ table->used_fields++; // Used to optimize loops - table->used_keys.intersect(field->part_of_key); + table->covering_keys.intersect(field->part_of_key); } } } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 812268fc92c..410dbd71304 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1957,7 +1957,6 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->const_table= 0; table->null_row= 0; table->status= STATUS_NO_RECORD; - table->keys_in_use_for_query= table->s->keys_in_use; table->maybe_null= table_list->outer_join; TABLE_LIST *embedding= table_list->embedding; while (!table->maybe_null && embedding) @@ -1968,6 +1967,8 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; + table->covering_keys= table->s->keys_for_keyread; + table->merge_keys.clear_all(); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 96dfb3d01ec..a8406451b75 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4869,7 +4869,8 @@ enum options_mysqld OPT_PORT_OPEN_TIMEOUT, OPT_GENERAL_LOG, OPT_SLOW_LOG, - OPT_MERGE + OPT_MERGE, + OPT_OLD_MODE }; @@ -6080,6 +6081,10 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.net_write_timeout, (gptr*) &max_system_variables.net_write_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, + { "old_mode", OPT_OLD_MODE, "Use compatible behaviour.", + (gptr*) &global_system_variables.old_mode, + (gptr*) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"open_files_limit", OPT_OPEN_FILES_LIMIT, "If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.", (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej deleted file mode 100644 index 62f0357622d..00000000000 --- a/sql/mysqld.cc.rej +++ /dev/null @@ -1,17 +0,0 @@ -*************** -*** 5316,5322 **** - (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ - --skip-merge.", -! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0}, - {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, ---- 5336,5342 ---- - (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \ - --skip-merge.", -! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"myisam-recover", OPT_MYISAM_RECOVER, - "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.", - (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fa575e73c39..e8c37856151 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2109,9 +2109,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.key_parts_end=key_parts; /* Calculate cost of full index read for the shortest covering index */ - if (!head->used_keys.is_clear_all()) + if (!head->covering_keys.is_clear_all()) { - int key_for_use= find_shortest_key(head, &head->used_keys); + int key_for_use= find_shortest_key(head, &head->covering_keys); double key_read_time= (get_index_only_read_time(¶m, records, key_for_use) + (double) records / TIME_FOR_COMPARE); @@ -4646,7 +4646,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, param->needed_reg->set_bit(keynr); bool read_index_only= index_read_must_be_used ? TRUE : - (bool) param->table->used_keys.is_set(keynr); + (bool) param->table->covering_keys.is_set(keynr); found_records= check_quick_select(param, idx, *key, update_tbl_stats); if (param->is_ror_scan) @@ -8988,7 +8988,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) cur_index_info++, cur_index++) { /* Check (B1) - if current index is covering. */ - if (!table->used_keys.is_set(cur_index)) + if (!table->covering_keys.is_set(cur_index)) goto next_index; /* diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3fd09d909a4..e7a0a9ed89e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1792,8 +1792,6 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) table->const_table=0; table->null_row= table->maybe_null= table->force_index= 0; table->status=STATUS_NO_RECORD; - table->keys_in_use_for_query= share->keys_in_use; - table->used_keys= share->keys_for_keyread; DBUG_RETURN(FALSE); } @@ -2115,9 +2113,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->const_table=0; table->null_row= table->maybe_null= table->force_index= 0; table->status=STATUS_NO_RECORD; - table->keys_in_use_for_query= table->s->keys_in_use; table->insert_values= 0; - table->used_keys= table->s->keys_for_keyread; table->fulltext_searched= 0; table->file->ft_handler= 0; if (table->timestamp_field) @@ -2202,8 +2198,6 @@ static bool reopen_table(TABLE *table) tmp.null_row= table->null_row; tmp.maybe_null= table->maybe_null; tmp.status= table->status; - tmp.keys_in_use_for_query= tmp.s->keys_in_use; - tmp.used_keys= tmp.s->keys_for_keyread; tmp.s->table_map_id= table->s->table_map_id; @@ -3621,7 +3615,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) been set for all fields (for example for view). */ - table->used_keys.intersect(field->part_of_key); + table->covering_keys.intersect(field->part_of_key); table->merge_keys.merge(field->part_of_key); if (thd->mark_used_columns == MARK_COLUMNS_READ) @@ -4798,7 +4792,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, TABLE *table_1= nj_col_1->table_ref->table; /* Mark field_1 used for table cache. */ bitmap_set_bit(table_1->read_set, field_1->field_index); - table_1->used_keys.intersect(field_1->part_of_key); + table_1->covering_keys.intersect(field_1->part_of_key); table_1->merge_keys.merge(field_1->part_of_key); } if (field_2) @@ -4806,7 +4800,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, TABLE *table_2= nj_col_2->table_ref->table; /* Mark field_2 used for table cache. */ bitmap_set_bit(table_2->read_set, field_2->field_index); - table_2->used_keys.intersect(field_2->part_of_key); + table_2->covering_keys.intersect(field_2->part_of_key); table_2->merge_keys.merge(field_2->part_of_key); } @@ -5446,25 +5440,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context, tablenr= 0; } setup_table_map(table, table_list, tablenr); - table->used_keys= table->s->keys_for_keyread; - table->merge_keys.clear_all(); - if (table_list->use_index) - { - 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(&map, table, table_list->ignore_index); - if (map.is_set_all()) - DBUG_RETURN(1); - table->keys_in_use_for_query.subtract(map); - } - table->used_keys.intersect(table->keys_in_use_for_query); + if (table_list->process_index_hints(table)) + DBUG_RETURN(1); } if (tablenr > MAX_TABLES) { @@ -5746,7 +5723,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, bitmap_set_bit(field->table->read_set, field->field_index); if (table) { - table->used_keys.intersect(field->part_of_key); + table->covering_keys.intersect(field->part_of_key); table->merge_keys.merge(field->part_of_key); } if (tables->is_natural_join) @@ -5764,7 +5741,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (field_table) { thd->used_tables|= field_table->map; - field_table->used_keys.intersect(field->part_of_key); + field_table->covering_keys.intersect(field->part_of_key); field_table->merge_keys.merge(field->part_of_key); field_table->used_fields++; } diff --git a/sql/sql_class.h b/sql/sql_class.h index de4a394d53c..7c61bdbb14e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -240,6 +240,11 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; + /* + compatibility option: + - index usage hints (USE INDEX without a FOR clause) behave as in 5.0 + */ + my_bool old_mode; my_bool query_cache_wlock_invalidate; my_bool engine_condition_pushdown; my_bool innodb_table_locks; @@ -277,6 +282,7 @@ struct system_variables DATE_TIME_FORMAT *datetime_format; DATE_TIME_FORMAT *time_format; my_bool sysdate_is_now; + }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index df24dad2d4c..085b8348da2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -117,7 +117,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - table->used_keys.clear_all(); + table->covering_keys.clear_all(); table->quick_keys.clear_all(); // Can't use 'only index' select=make_select(table, 0, 0, conds, 0, &error); if (error) @@ -548,7 +548,7 @@ multi_delete::initialize_tables(JOIN *join) tbl->no_keyread=1; /* Don't use record cache */ tbl->no_cache= 1; - tbl->used_keys.clear_all(); + tbl->covering_keys.clear_all(); if (tbl->file->has_transactions()) transactional_tables= 1; else diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 69d21f8b7bb..adca77d86c4 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -568,7 +568,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, cond->fix_fields(thd, &cond); // can never fail /* Assume that no indexes cover all required fields */ - table->used_keys.clear_all(); + table->covering_keys.clear_all(); SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error); if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) || diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d156973a790..d4906122f76 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -70,6 +70,17 @@ static uchar to_upper_lex[]= 208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255 }; +/* + Names of the index hints (for error messages). Keep in sync with + index_hint_type +*/ + +const char * index_hint_type_name[] = +{ + "IGNORE INDEX", + "USE INDEX", + "FORCE INDEX" +}; inline int lex_casecmp(const char *s, const char *t, uint len) { @@ -1173,7 +1184,6 @@ void st_select_lex::init_select() group_list.empty(); type= db= 0; having= 0; - use_index_ptr= ignore_index_ptr= 0; table_join_options= 0; in_sum_expr= with_wild= 0; options= 0; @@ -1182,7 +1192,6 @@ void st_select_lex::init_select() when_list.empty(); expr_list.empty(); interval_list.empty(); - use_index.empty(); ftfunc_list_alloc.empty(); inner_sum_func_list= 0; ftfunc_list= &ftfunc_list_alloc; @@ -1397,14 +1406,11 @@ bool st_select_lex_node::inc_in_sum_expr() { return 1; } uint st_select_lex_node::get_in_sum_expr() { return 0; } TABLE_LIST* st_select_lex_node::get_table_list() { return 0; } List* st_select_lex_node::get_item_list() { return 0; } -List* st_select_lex_node::get_use_index() { return 0; } -List* st_select_lex_node::get_ignore_index() { return 0; } -TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table, +TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_join_options, thr_lock_type flags, - List *use_index, - List *ignore_index, + List *hints, LEX_STRING *option) { return 0; @@ -1511,19 +1517,6 @@ List* st_select_lex::get_item_list() return &item_list; } - -List* st_select_lex::get_use_index() -{ - return use_index_ptr; -} - - -List* st_select_lex::get_ignore_index() -{ - return ignore_index_ptr; -} - - ulong st_select_lex::get_table_join_options() { return table_join_options; @@ -2260,3 +2253,61 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, are in sql_union.cc */ +/* + Sets the kind of hints to be added by the calls to add_index_hint(). + + SYNOPSIS + set_index_hint_type() + type the kind of hints to be added from now on. + clause the clause to use for hints to be added from now on. + + DESCRIPTION + Used in filling up the tagged hints list. + This list is filled by first setting the kind of the hint as a + context variable and then adding hints of the current kind. + Then the context variable index_hint_type can be reset to the + next hint type. +*/ +void st_select_lex::set_index_hint_type(enum index_hint_type type, + index_clause_map clause) +{ + current_index_hint_type= type; + current_index_hint_clause= clause; +} + + +/* + Makes an array to store index usage hints (ADD/FORCE/IGNORE INDEX). + + SYNOPSIS + alloc_index_hints() + thd current thread. +*/ + +void st_select_lex::alloc_index_hints (THD *thd) +{ + index_hints= new (thd->mem_root) List(); +} + + + +/* + adds an element to the array storing index usage hints + (ADD/FORCE/IGNORE INDEX). + + SYNOPSIS + add_index_hint() + thd current thread. + str name of the index. + length number of characters in str. + + RETURN VALUE + 0 on success, non-zero otherwise +*/ +bool st_select_lex::add_index_hint (THD *thd, char *str, uint length) +{ + return index_hints->push_front (new (thd->mem_root) + index_hint(current_index_hint_type, + current_index_hint_clause, + str, length)); +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7fd60cbfa58..0e91b2a786b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -208,6 +208,47 @@ enum tablespace_op_type NO_TABLESPACE_OP, DISCARD_TABLESPACE, IMPORT_TABLESPACE }; +/* + String names used to print a statement with index hints. + Keep in sync with index_hint_type. +*/ +extern const char * index_hint_type_name[]; +typedef byte index_clause_map; + +/* + Bits in index_clause_map : one for each possible FOR clause in + USE/FORCE/IGNORE INDEX index hint specification +*/ +#define INDEX_HINT_MASK_JOIN (1) +#define INDEX_HINT_MASK_GROUP (1 << 1) +#define INDEX_HINT_MASK_ORDER (1 << 2) + +#define INDEX_HINT_MASK_ALL (INDEX_HINT_MASK_JOIN | INDEX_HINT_MASK_GROUP | \ + INDEX_HINT_MASK_ORDER) + +/* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */ +class index_hint : public Sql_alloc +{ +public: + /* The type of the hint : USE/FORCE/IGNORE */ + enum index_hint_type type; + /* Where the hit applies to. A bitmask of INDEX_HINT_MASK_ values */ + index_clause_map clause; + /* + The index name. Empty (str=NULL) name represents an empty list + USE INDEX () clause + */ + LEX_STRING key_name; + + index_hint (enum index_hint_type type_arg, index_clause_map clause_arg, + char *str, uint length) : + type(type_arg), clause(clause_arg) + { + key_name.str= str; + key_name.length= length; + } +}; + /* The state of the lex parsing for selects @@ -386,15 +427,12 @@ public: virtual uint get_in_sum_expr(); virtual TABLE_LIST* get_table_list(); virtual List* get_item_list(); - virtual List* get_use_index(); - virtual List* get_ignore_index(); virtual ulong get_table_join_options(); virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_options, thr_lock_type flags= TL_UNLOCK, - List *use_index= 0, - List *ignore_index= 0, + List *hints= 0, LEX_STRING *option= 0); virtual void set_lock_for_tables(thr_lock_type lock_type) {} @@ -521,8 +559,7 @@ public: SQL_LIST table_list; SQL_LIST group_list; /* GROUP BY clause. */ List item_list; /* list of fields & expressions */ - List interval_list, use_index, *use_index_ptr, - ignore_index, *ignore_index_ptr; + List interval_list; bool is_item_list_lookup; /* Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake @@ -645,8 +682,7 @@ public: LEX_STRING *alias, ulong table_options, thr_lock_type flags= TL_UNLOCK, - List *use_index= 0, - List *ignore_index= 0, + List *hints= 0, LEX_STRING *option= 0); TABLE_LIST* get_table_list(); bool init_nested_join(THD *thd); @@ -655,8 +691,6 @@ public: void add_joined_table(TABLE_LIST *table); TABLE_LIST *convert_right_join(); List* get_item_list(); - List* get_use_index(); - List* get_ignore_index(); ulong get_table_join_options(); void set_lock_for_tables(thr_lock_type lock_type); inline void init_order() @@ -696,6 +730,33 @@ public: select lexes. */ void cleanup_all_joins(bool full); + + void set_index_hint_type(enum index_hint_type type, index_clause_map clause); + + /* + Add a index hint to the tagged list of hints. The type and clause of the + hint will be the current ones (set by set_index_hint()) + */ + bool add_index_hint (THD *thd, char *str, uint length); + + /* make a list to hold index hints */ + void alloc_index_hints (THD *thd); + /* read and clear the index hints */ + List* pop_index_hints(void) + { + List *hints= index_hints; + index_hints= NULL; + return hints; + } + + void clear_index_hints(void) { index_hints= NULL; } + +private: + /* current index hint kind. used in filling up index_hints */ + enum index_hint_type current_index_hint_type; + index_clause_map current_index_hint_clause; + /* a list of USE/FORCE/IGNORE INDEX */ + List *index_hints; }; typedef class st_select_lex SELECT_LEX; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1c46c3189d9..5fa3c22408f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2382,8 +2382,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, /* 'parent_lex' is used in init_query() so it must be before it. */ sel->parent_lex= lex; sel->init_query(); - if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, - (List *) 0, (List *) 0)) + if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ)) DBUG_RETURN(1); lex->query_tables_last= query_tables_last; TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first; @@ -6336,8 +6335,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, LEX_STRING *alias, ulong table_options, thr_lock_type lock_type, - List *use_index_arg, - List *ignore_index_arg, + List *index_hints_arg, LEX_STRING *option) { register TABLE_LIST *ptr; @@ -6412,12 +6410,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } ptr->select_lex= lex->current_select; ptr->cacheable_table= 1; - if (use_index_arg) - ptr->use_index=(List *) thd->memdup((gptr) use_index_arg, - sizeof(*use_index_arg)); - if (ignore_index_arg) - ptr->ignore_index=(List *) thd->memdup((gptr) ignore_index_arg, - sizeof(*ignore_index_arg)); + ptr->index_hints= index_hints_arg; ptr->option= option ? option->str : 0; /* check that used name is unique */ if (lock_type != TL_IGNORE) diff --git a/sql/sql_parse.cc.rej b/sql/sql_parse.cc.rej deleted file mode 100644 index 6e2bd03867d..00000000000 --- a/sql/sql_parse.cc.rej +++ /dev/null @@ -1,166 +0,0 @@ -*************** -*** 67,109 **** - static void decrease_user_connections(USER_CONN *uc); - #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - static bool check_multi_update_lock(THD *thd); -- static void remove_escape(char *name); - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); - - const char *any_db="*any*"; // Special symbol for check_access - -! LEX_STRING command_name[]={ -! (char *)STRING_WITH_LEN("Sleep"), -! (char *)STRING_WITH_LEN("Quit"), -! (char *)STRING_WITH_LEN("Init DB"), -! (char *)STRING_WITH_LEN("Query"), -! (char *)STRING_WITH_LEN("Field List"), -! (char *)STRING_WITH_LEN("Create DB"), -! (char *)STRING_WITH_LEN("Drop DB"), -! (char *)STRING_WITH_LEN("Refresh"), -! (char *)STRING_WITH_LEN("Shutdown"), -! (char *)STRING_WITH_LEN("Statistics"), -! (char *)STRING_WITH_LEN("Processlist"), -! (char *)STRING_WITH_LEN("Connect"), -! (char *)STRING_WITH_LEN("Kill"), -! (char *)STRING_WITH_LEN("Debug"), -! (char *)STRING_WITH_LEN("Ping"), -! (char *)STRING_WITH_LEN("Time"), -! (char *)STRING_WITH_LEN("Delayed insert"), -! (char *)STRING_WITH_LEN("Change user"), -! (char *)STRING_WITH_LEN("Binlog Dump"), -! (char *)STRING_WITH_LEN("Table Dump"), -! (char *)STRING_WITH_LEN("Connect Out"), -! (char *)STRING_WITH_LEN("Register Slave"), -! (char *)STRING_WITH_LEN("Prepare"), -! (char *)STRING_WITH_LEN("Execute"), -! (char *)STRING_WITH_LEN("Long Data"), -! (char *)STRING_WITH_LEN("Close stmt"), -! (char *)STRING_WITH_LEN("Reset stmt"), -! (char *)STRING_WITH_LEN("Set option"), -! (char *)STRING_WITH_LEN("Fetch"), -! (char *)STRING_WITH_LEN("Daemon"), -! (char *)STRING_WITH_LEN("Error") // Last command number - }; - - const char *xa_state_names[]={ ---- 67,108 ---- - static void decrease_user_connections(USER_CONN *uc); - #endif /* NO_EMBEDDED_ACCESS_CHECKS */ - static bool check_multi_update_lock(THD *thd); - static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); - - const char *any_db="*any*"; // Special symbol for check_access - -! const LEX_STRING command_name[]={ -! C_STRING_WITH_LEN("Sleep"), -! C_STRING_WITH_LEN("Quit"), -! C_STRING_WITH_LEN("Init DB"), -! C_STRING_WITH_LEN("Query"), -! C_STRING_WITH_LEN("Field List"), -! C_STRING_WITH_LEN("Create DB"), -! C_STRING_WITH_LEN("Drop DB"), -! C_STRING_WITH_LEN("Refresh"), -! C_STRING_WITH_LEN("Shutdown"), -! C_STRING_WITH_LEN("Statistics"), -! C_STRING_WITH_LEN("Processlist"), -! C_STRING_WITH_LEN("Connect"), -! C_STRING_WITH_LEN("Kill"), -! C_STRING_WITH_LEN("Debug"), -! C_STRING_WITH_LEN("Ping"), -! C_STRING_WITH_LEN("Time"), -! C_STRING_WITH_LEN("Delayed insert"), -! C_STRING_WITH_LEN("Change user"), -! C_STRING_WITH_LEN("Binlog Dump"), -! C_STRING_WITH_LEN("Table Dump"), -! C_STRING_WITH_LEN("Connect Out"), -! C_STRING_WITH_LEN("Register Slave"), -! C_STRING_WITH_LEN("Prepare"), -! C_STRING_WITH_LEN("Execute"), -! C_STRING_WITH_LEN("Long Data"), -! C_STRING_WITH_LEN("Close stmt"), -! C_STRING_WITH_LEN("Reset stmt"), -! C_STRING_WITH_LEN("Set option"), -! C_STRING_WITH_LEN("Fetch"), -! C_STRING_WITH_LEN("Daemon"), -! C_STRING_WITH_LEN("Error") // Last command number - }; - - const char *xa_state_names[]={ -*************** -*** 1738,1744 **** - password. New clients send the size (1 byte) + string (not null - terminated, so also '\0' for empty string). - */ -! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 - char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); ---- 1736,1742 ---- - password. New clients send the size (1 byte) + string (not null - terminated, so also '\0' for empty string). - */ -! char db_buff[NAME_LEN+1]; // buffer to store db in utf8 - char *db= passwd; - uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? - *passwd++ : strlen(passwd); -*************** -*** 2315,2321 **** - DBUG_RETURN(1); - } - db= lex->select_lex.db; -- remove_escape(db); // Fix escaped '_' - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); ---- 2312,2317 ---- - DBUG_RETURN(1); - } - db= lex->select_lex.db; - if (check_db_name(db)) - { - my_error(ER_WRONG_DB_NAME, MYF(0), db); -*************** -*** 6310,6345 **** - } - - -- /* Fix escaping of _, % and \ in database and table names (for ODBC) */ -- -- static void remove_escape(char *name) -- { -- if (!*name) // For empty DB names -- return; -- char *to; -- #ifdef USE_MB -- char *strend=name+(uint) strlen(name); -- #endif -- for (to=name; *name ; name++) -- { -- #ifdef USE_MB -- int l; -- if (use_mb(system_charset_info) && -- (l = my_ismbchar(system_charset_info, name, strend))) -- { -- while (l--) -- *to++ = *name++; -- name--; -- continue; -- } -- #endif -- if (*name == '\\' && name[1]) -- name++; // Skip '\\' -- *to++= *name; -- } -- *to=0; -- } -- - /**************************************************************************** - ** save order by and tables in own lists - ****************************************************************************/ ---- 6296,6301 ---- - } - - - /**************************************************************************** - ** save order by and tables in own lists - ****************************************************************************/ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9a64055f2e3..f05bf555816 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -165,13 +165,15 @@ static COND *make_cond_for_table(COND *cond,table_map table, static Item* part_of_refkey(TABLE *form,Field *field); 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); + ha_rows select_limit, bool no_changes, + key_map *map); static bool list_contains_unique_index(TABLE *table, bool (*find_func) (Field *, void *), void *data); static bool find_field_in_item_list (Field *field, void *data); static bool find_field_in_order_list (Field *field, void *data); static int create_sort_index(THD *thd, JOIN *join, ORDER *order, - ha_rows filesort_limit, ha_rows select_limit); + ha_rows filesort_limit, ha_rows select_limit, + bool is_order_by); static int remove_duplicates(JOIN *join,TABLE *entry,List &fields, Item *having); static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field, @@ -916,14 +918,15 @@ JOIN::optimize() JOIN_TAB *tab= &join_tab[const_tables]; bool all_order_fields_used; if (order) - skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); + skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1, + &tab->table->keys_in_use_for_order_by); if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, order, fields_list, &all_order_fields_used))) { bool skip_group= (skip_sort_order && - test_if_skip_sort_order(tab, group_list, select_limit, - 1) != 0); + test_if_skip_sort_order(tab, group_list, select_limit, 1, + &tab->table->keys_in_use_for_group_by) != 0); if ((skip_group && all_order_fields_used) || select_limit == HA_POS_ERROR || (order && !skip_sort_order)) @@ -1113,7 +1116,9 @@ JOIN::optimize() ((group_list && (!simple_group || !test_if_skip_sort_order(&join_tab[const_tables], group_list, - unit->select_limit_cnt, 0))) || + unit->select_limit_cnt, 0, + &join_tab[const_tables].table-> + keys_in_use_for_group_by))) || select_distinct) && tmp_table_param.quick_group && !procedure) { @@ -1215,7 +1220,7 @@ JOIN::optimize() DBUG_PRINT("info",("Sorting for group")); thd->proc_info="Sorting for group"; if (create_sort_index(thd, this, group_list, - HA_POS_ERROR, HA_POS_ERROR) || + HA_POS_ERROR, HA_POS_ERROR, FALSE) || alloc_group_fields(this, group_list) || make_sum_func_list(all_fields, fields_list, 1) || setup_sum_funcs(thd, sum_funcs)) @@ -1232,7 +1237,7 @@ JOIN::optimize() DBUG_PRINT("info",("Sorting for order")); thd->proc_info="Sorting for order"; if (create_sort_index(thd, this, order, - HA_POS_ERROR, HA_POS_ERROR)) + HA_POS_ERROR, HA_POS_ERROR, TRUE)) DBUG_RETURN(1); order=0; } @@ -1259,7 +1264,9 @@ JOIN::optimize() { /* Should always succeed */ if (test_if_skip_sort_order(&join_tab[const_tables], - order, unit->select_limit_cnt, 0)) + order, unit->select_limit_cnt, 0, + &join_tab[const_tables].table-> + keys_in_use_for_order_by)) order=0; } } @@ -1452,7 +1459,9 @@ JOIN::exec() (const_tables == tables || ((simple_order || skip_sort_order) && test_if_skip_sort_order(&join_tab[const_tables], order, - select_limit, 0)))) + select_limit, 0, + &join_tab[const_tables].table-> + keys_in_use_for_order_by)))) order=0; having= tmp_having; select_describe(this, need_tmp, @@ -1628,7 +1637,7 @@ JOIN::exec() DBUG_VOID_RETURN; } if (create_sort_index(thd, curr_join, curr_join->group_list, - HA_POS_ERROR, HA_POS_ERROR) || + HA_POS_ERROR, HA_POS_ERROR, FALSE) || make_group_fields(this, curr_join)) { DBUG_VOID_RETURN; @@ -1844,7 +1853,8 @@ JOIN::exec() curr_join->group_list : curr_join->order, curr_join->select_limit, (select_options & OPTION_FOUND_ROWS ? - HA_POS_ERROR : unit->select_limit_cnt))) + HA_POS_ERROR : unit->select_limit_cnt), + curr_join->group_list ? TRUE : FALSE)) DBUG_VOID_RETURN; sortorder= curr_join->sortorder; if (curr_join->const_tables != curr_join->tables && @@ -3842,7 +3852,7 @@ best_access_path(JOIN *join, /* Limit the number of matched rows */ tmp= records; set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); - if (table->used_keys.is_set(key)) + if (table->covering_keys.is_set(key)) { /* we can use only index tree */ uint keys_per_block= table->file->stats.block_size/2/ @@ -4009,7 +4019,7 @@ best_access_path(JOIN *join, /* Limit the number of matched rows */ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); - if (table->used_keys.is_set(key)) + if (table->covering_keys.is_set(key)) { /* we can use only index tree */ uint keys_per_block= table->file->stats.block_size/2/ @@ -4068,7 +4078,7 @@ best_access_path(JOIN *join, !(s->quick && best_key && s->quick->index == best_key->key && // (2) best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2) !((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3) - ! s->table->used_keys.is_clear_all() && best_key) && // (3) + ! s->table->covering_keys.is_clear_all() && best_key) && // (3) !(s->table->force_index && best_key && !s->quick)) // (4) { // Check full join ha_rows rnd_records= s->found_records; @@ -5965,7 +5975,7 @@ make_join_readinfo(JOIN *join, ulonglong options) (table == join->sort_by_table && (!join->order || join->skip_sort_order || test_if_skip_sort_order(tab, join->order, join->select_limit, - 1)) + 1, &table->keys_in_use_for_order_by)) ) || (join->sort_by_table == (TABLE *) 1 && i != join->const_tables)) ordered_set= 1; @@ -5982,7 +5992,7 @@ make_join_readinfo(JOIN *join, ulonglong options) table->status=STATUS_NO_RECORD; tab->read_first_record= join_read_const; tab->read_record.read_record= join_no_more_records; - if (table->used_keys.is_set(tab->ref.key) && + if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) { table->key_read=1; @@ -6000,7 +6010,7 @@ make_join_readinfo(JOIN *join, ulonglong options) tab->quick=0; tab->read_first_record= join_read_key; tab->read_record.read_record= join_no_more_records; - if (table->used_keys.is_set(tab->ref.key) && + if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) { table->key_read=1; @@ -6017,7 +6027,7 @@ make_join_readinfo(JOIN *join, ulonglong options) } delete tab->quick; tab->quick=0; - if (table->used_keys.is_set(tab->ref.key) && + if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) { table->key_read=1; @@ -6103,15 +6113,15 @@ make_join_readinfo(JOIN *join, ulonglong options) { if (tab->select && tab->select->quick && tab->select->quick->index != MAX_KEY && //not index_merge - table->used_keys.is_set(tab->select->quick->index)) + table->covering_keys.is_set(tab->select->quick->index)) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } - else if (!table->used_keys.is_clear_all() && + else if (!table->covering_keys.is_clear_all() && !(tab->select && tab->select->quick)) { // Only read index tree - tab->index=find_shortest_key(table, & table->used_keys); + tab->index=find_shortest_key(table, & table->covering_keys); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next } @@ -9179,7 +9189,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, table->copy_blobs= 1; table->in_use= thd; table->quick_keys.init(); - table->used_keys.init(); + table->covering_keys.init(); table->keys_in_use_for_query.init(); table->s= share; @@ -10804,7 +10814,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) } else { - if (!table->key_read && table->used_keys.is_set(tab->ref.key) && + if (!table->key_read && table->covering_keys.is_set(tab->ref.key) && !table->no_keyread && (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY) { @@ -11109,7 +11119,7 @@ join_read_first(JOIN_TAB *tab) { int error; TABLE *table=tab->table; - if (!table->key_read && table->used_keys.is_set(tab->index) && + if (!table->key_read && table->covering_keys.is_set(tab->index) && !table->no_keyread) { table->key_read=1; @@ -11148,7 +11158,7 @@ join_read_last(JOIN_TAB *tab) { TABLE *table=tab->table; int error; - if (!table->key_read && table->used_keys.is_set(tab->index) && + if (!table->key_read && table->covering_keys.is_set(tab->index) && !table->no_keyread) { table->key_read=1; @@ -12170,7 +12180,7 @@ find_field_in_item_list (Field *field, void *data) static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, - bool no_changes) + bool no_changes, key_map *map) { int ref_key; uint ref_key_parts; @@ -12184,9 +12194,16 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, Check which keys can be used to resolve ORDER BY. We must not try to use disabled keys. */ - usable_keys= table->s->keys_in_use; - /* we must not consider keys that are disabled by IGNORE INDEX */ - usable_keys.intersect(table->keys_in_use_for_query); + usable_keys= *map; + + /* + If there is a covering index, and we have IGNORE INDEX FOR GROUP/ORDER + and this index is used for the JOIN part, then we have to ignore the + IGNORE INDEX FOR GROUP/ORDER + */ + if (table->key_read || + (table->covering_keys.is_set(tab->index) && !table->no_keyread)) + usable_keys.set_bit (tab->index); for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { @@ -12244,8 +12261,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.is_set(ref_key)) - usable_keys.intersect(table->used_keys); + if (table->covering_keys.is_set(ref_key)) + usable_keys.intersect(table->covering_keys); if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts, &usable_keys)) < MAX_KEY) { @@ -12360,7 +12377,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (select_limit >= table->file->stats.records) { keys= *table->file->keys_to_use_for_scanning(); - keys.merge(table->used_keys); + keys.merge(table->covering_keys); /* We are adding here also the index specified in FORCE INDEX clause, @@ -12388,7 +12405,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->read_first_record= (flag > 0 ? join_read_first: join_read_last); tab->type=JT_NEXT; // Read with index_first(), index_next() - if (table->used_keys.is_set(nr)) + if (table->covering_keys.is_set(nr)) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); @@ -12414,6 +12431,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, 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 + is_order_by true if we are sorting on ORDER BY, false if GROUP BY + Used to decide if we should use index or not IMPLEMENTATION @@ -12432,7 +12451,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, static int create_sort_index(THD *thd, JOIN *join, ORDER *order, - ha_rows filesort_limit, ha_rows select_limit) + ha_rows filesort_limit, ha_rows select_limit, + bool is_order_by) { uint length; ha_rows examined_rows; @@ -12453,7 +12473,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, */ if ((order != join->group_list || !(join->select_options & SELECT_BIG_RESULT)) && - test_if_skip_sort_order(tab,order,select_limit,0)) + test_if_skip_sort_order(tab,order,select_limit,0, + is_order_by ? &table->keys_in_use_for_order_by : + &table->keys_in_use_for_group_by)) DBUG_RETURN(0); if (!(join->sortorder= make_unireg_sortorder(order,&length,join->sortorder))) @@ -15047,7 +15069,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, /* Build "Extra" field and add it to item_list. */ my_bool key_read=table->key_read; if ((tab->type == JT_NEXT || tab->type == JT_CONST) && - table->used_keys.is_set(tab->index)) + table->covering_keys.is_set(tab->index)) key_read=1; if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT && !((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0ebccba43ca..622a415a743 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2269,8 +2269,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel, ident_table.length= strlen(table); table_ident= new Table_ident(thd, ident_db, ident_table, 1); sel->init_query(); - if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, - (List *) 0, (List *) 0)) + if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ)) return 1; return 0; } @@ -4934,8 +4933,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, strlen(schema_table->table_name), 0); if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), - 0, 0, TL_READ, (List *) 0, - (List *) 0)) + 0, 0, TL_READ)) { DBUG_RETURN(1); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a379ea66db6..41ddd89f759 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -130,7 +130,7 @@ int mysql_update(THD *thd, #endif uint table_count= 0; ha_rows updated, found; - key_map old_used_keys; + key_map old_covering_keys; TABLE *table; SQL_SELECT *select; READ_RECORD info; @@ -168,8 +168,8 @@ int mysql_update(THD *thd, thd->proc_info="init"; table= table_list->table; - /* Calculate "table->used_keys" based on the WHERE */ - table->used_keys= table->s->keys_in_use; + /* Calculate "table->covering_keys" based on the WHERE */ + table->covering_keys= table->s->keys_in_use; table->quick_keys.clear_all(); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -179,7 +179,7 @@ int mysql_update(THD *thd, if (mysql_prepare_update(thd, table_list, &conds, order_num, order)) DBUG_RETURN(1); - old_used_keys= table->used_keys; // Keys used in WHERE + old_covering_keys= table->covering_keys; // Keys used in WHERE /* Check the fields we are going to modify */ #ifndef NO_EMBEDDED_ACCESS_CHECKS table_list->grant.want_privilege= table->grant.want_privilege= want_privilege; @@ -228,7 +228,7 @@ int mysql_update(THD *thd, limit= 0; // Impossible WHERE } // Don't count on usage of 'only index' when calculating which key to use - table->used_keys.clear_all(); + table->covering_keys.clear_all(); #ifdef WITH_PARTITION_STORAGE_ENGINE if (prune_partitions(thd, table, conds)) @@ -303,7 +303,7 @@ int mysql_update(THD *thd, We can't update table directly; We must first search after all matching rows before updating the table! */ - if (used_index < MAX_KEY && old_used_keys.is_set(used_index)) + if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) { table->key_read=1; table->mark_columns_used_by_index(used_index); @@ -1091,7 +1091,7 @@ int multi_update::prepare(List ¬_used_values, } /* - We have to check values after setup_tables to get used_keys right in + We have to check values after setup_tables to get covering_keys right in reference tables */ @@ -1118,7 +1118,7 @@ int multi_update::prepare(List ¬_used_values, update.link_in_list((byte*) tl, (byte**) &tl->next_local); tl->shared= table_count++; table->no_keyread=1; - table->used_keys.clear_all(); + table->covering_keys.clear_all(); table->pos_in_table_list= tl; } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 704c505ded9..b067443ba8c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -150,6 +150,7 @@ static bool is_native_function(THD *thd, const LEX_STRING *name) struct st_lex *lex; sp_head *sphead; struct p_elem_val *p_elem_value; + enum index_hint_type index_hint; } %{ @@ -820,7 +821,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); btree_or_rtree %type - key_usage_list using_list + using_list %type key_part @@ -890,7 +891,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list clear_privileges flush_options flush_option - equal optional_braces opt_key_definition key_usage_list2 + equal optional_braces opt_mi_check_type opt_to mi_check_types normal_join db_to_db table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan @@ -924,6 +925,8 @@ END_OF_INPUT %type sp_decls sp_decl %type sp_cursor_stmt %type sp_name +%type index_hint_type +%type index_hint_clause %type '-' '+' '*' '/' '%' '(' ')' @@ -5523,12 +5526,8 @@ keycache_list: assign_to_keycache: table_ident cache_keys_spec { - LEX *lex=Lex; - SELECT_LEX *sel= &lex->select_lex; - if (!sel->add_table_to_list(lex->thd, $1, NULL, 0, - TL_READ, - sel->get_use_index(), - (List *)0)) + if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ, + Select->pop_index_hints())) YYABORT; } ; @@ -5555,33 +5554,26 @@ preload_list: preload_keys: table_ident cache_keys_spec opt_ignore_leaves { - LEX *lex=Lex; - SELECT_LEX *sel= &lex->select_lex; - if (!sel->add_table_to_list(lex->thd, $1, NULL, $3, - TL_READ, - sel->get_use_index(), - (List *)0)) + if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ, + Select->pop_index_hints())) YYABORT; } ; cache_keys_spec: - { Select->interval_list.empty(); } - cache_key_list_or_empty - { - LEX *lex=Lex; - SELECT_LEX *sel= &lex->select_lex; - sel->use_index= sel->interval_list; + { + Lex->select_lex.alloc_index_hints(YYTHD); + Select->set_index_hint_type(INDEX_HINT_USE, + global_system_variables.old_mode ? + INDEX_HINT_MASK_JOIN : + INDEX_HINT_MASK_ALL); } + cache_key_list_or_empty ; cache_key_list_or_empty: - /* empty */ { Lex->select_lex.use_index_ptr= 0; } - | opt_key_or_index '(' key_usage_list2 ')' - { - SELECT_LEX *sel= &Lex->select_lex; - sel->use_index_ptr= &sel->use_index; - } + /* empty */ { } + | key_or_index '(' opt_key_usage_list ')' ; opt_ignore_leaves: @@ -6949,20 +6941,16 @@ normal_join: table_factor: { SELECT_LEX *sel= Select; - sel->use_index_ptr=sel->ignore_index_ptr=0; sel->table_join_options= 0; } table_ident opt_table_alias opt_key_definition { - LEX *lex= Lex; - SELECT_LEX *sel= lex->current_select; - if (!($$= sel->add_table_to_list(lex->thd, $2, $3, - sel->get_table_join_options(), - lex->lock_option, - sel->get_use_index(), - sel->get_ignore_index()))) + if (!($$= Select->add_table_to_list(YYTHD, $2, $3, + Select->get_table_join_options(), + Lex->lock_option, + Select->pop_index_hints()))) YYABORT; - sel->add_joined_table($$); + Select->add_joined_table($$); } | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON @@ -7031,8 +7019,7 @@ table_factor: lex->current_select= sel= unit->outer_select(); if (!($$= sel-> add_table_to_list(lex->thd, new Table_ident(unit), $6, 0, - TL_READ,(List *)0, - (List *)0))) + TL_READ))) YYABORT; sel->add_joined_table($$); @@ -7131,52 +7118,67 @@ opt_outer: /* empty */ {} | OUTER {}; +index_hint_clause: + /* empty */ + { + $$= global_system_variables.old_mode ? + INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL; + } + | FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; } + | FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; } + | FOR_SYM GROUP BY { $$= INDEX_HINT_MASK_GROUP; } + ; + +index_hint_type: + FORCE_SYM { $$= INDEX_HINT_FORCE; } + | IGNORE_SYM { $$= INDEX_HINT_IGNORE; } + ; + +index_hint_definition: + index_hint_type key_or_index index_hint_clause + { + Select->set_index_hint_type($1, $3); + } + '(' key_usage_list ')'; + | USE_SYM key_or_index index_hint_clause + { + Select->set_index_hint_type(INDEX_HINT_USE, $3); + } + '(' opt_key_usage_list ')'; + + +index_hints_list: + index_hint_definition + | index_hints_list index_hint_definition + ; + +opt_index_hints_list: + /* empty */ + | { Select->alloc_index_hints(YYTHD); } index_hints_list + ; + opt_key_definition: - /* empty */ {} - | USE_SYM key_usage_list - { - SELECT_LEX *sel= Select; - sel->use_index= *$2; - sel->use_index_ptr= &sel->use_index; - } - | FORCE_SYM key_usage_list - { - SELECT_LEX *sel= Select; - sel->use_index= *$2; - sel->use_index_ptr= &sel->use_index; - sel->table_join_options|= TL_OPTION_FORCE_INDEX; - } - | IGNORE_SYM key_usage_list - { - SELECT_LEX *sel= Select; - sel->ignore_index= *$2; - sel->ignore_index_ptr= &sel->ignore_index; - }; + { Select->clear_index_hints(); } + opt_index_hints_list + ; + +opt_key_usage_list: + /* empty */ { Select->add_index_hint(YYTHD, NULL, 0); } + | key_usage_list {} + ; + +key_usage_element: + ident { Select->add_index_hint(YYTHD, $1.str, $1.length); } + | PRIMARY_SYM + { + Select->add_index_hint(YYTHD, (char *)"PRIMARY", 7); + } + ; key_usage_list: - key_or_index { Select->interval_list.empty(); } - '(' key_list_or_empty ')' - { $$= &Select->interval_list; } - ; - -key_list_or_empty: - /* empty */ {} - | key_usage_list2 {} - ; - -key_usage_list2: - key_usage_list2 ',' ident - { Select-> - interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length, - system_charset_info)); } - | ident - { Select-> - interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length, - system_charset_info)); } - | PRIMARY_SYM - { Select-> - interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7, - system_charset_info)); }; + key_usage_element + | key_usage_list ',' key_usage_element + ; using_list: ident diff --git a/sql/table.cc b/sql/table.cc index 52074ee1e7c..9d74affb788 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1354,7 +1354,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, if (!(outparam->alias= my_strdup(alias, MYF(MY_WME)))) goto err; outparam->quick_keys.init(); - outparam->used_keys.init(); + outparam->covering_keys.init(); outparam->keys_in_use_for_query.init(); /* Allocate handler */ @@ -4133,6 +4133,175 @@ Item_subselect *st_table_list::containing_subselect() return (select_lex ? select_lex->master_unit()->item : 0); } +/* + Compiles the tagged hints list and fills up the bitmasks. + + SYNOPSIS + process_index_hints() + table the TABLE to operate on. + + DESCRIPTION + The parser collects the index hints for each table in a "tagged list" + (st_table_list::index_hints). Using the information in this tagged list + this function sets the members st_table::keys_in_use_for_query, + st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by, + st_table::force_index and st_table::covering_keys. + + Current implementation of the runtime does not allow mixing FORCE INDEX + and USE INDEX, so this is checked here. Then the FORCE INDEX list + (if non-empty) is appended to the USE INDEX list and a flag is set. + + Multiple hints of the same kind are processed so that each clause + is applied to what is computed in the previous clause. + For example: + USE INDEX (i1) USE INDEX (i2) + is equivalent to + USE INDEX (i1,i2) + and means "consider only i1 and i2". + + Similarly + USE INDEX () USE INDEX (i1) + is equivalent to + USE INDEX (i1) + and means "consider only the index i1" + + It is OK to have the same index several times, e.g. "USE INDEX (i1,i1)" is + not an error. + + Different kind of hints (USE/FORCE/IGNORE) are processed in the following + order: + 1. All indexes in USE (or FORCE) INDEX are added to the mask. + 2. All IGNORE INDEX + + e.g. "USE INDEX i1, IGNORE INDEX i1, USE INDEX i1" will not use i1 at all + as if we had "USE INDEX i1, USE INDEX i1, IGNORE INDEX i1". + + As an optimization if there is a covering index, and we have + IGNORE INDEX FOR GROUP/ORDER, and this index is used for the JOIN part, + then we have to ignore the IGNORE INDEX FROM GROUP/ORDER. + + RETURN VALUE + FALSE no errors found + TRUE found and reported an error. +*/ +bool st_table_list::process_index_hints(TABLE *table) +{ + /* initialize the result variables */ + table->keys_in_use_for_query= table->keys_in_use_for_group_by= + table->keys_in_use_for_order_by= table->s->keys_in_use; + + /* index hint list processing */ + if (index_hints) + { + key_map index_join[INDEX_HINT_FORCE + 1]; + key_map index_order[INDEX_HINT_FORCE + 1]; + key_map index_group[INDEX_HINT_FORCE + 1]; + index_hint *hint; + int type; + bool have_empty_use_join= FALSE, have_empty_use_order= FALSE, + have_empty_use_group= FALSE; + List_iterator iter(*index_hints); + + /* initialize temporary variables used to collect hints of each kind */ + for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++) + { + index_join[type].clear_all(); + index_order[type].clear_all(); + index_group[type].clear_all(); + } + + /* iterate over the hints list */ + while ((hint= iter++)) + { + uint pos; + + /* process empty USE INDEX () */ + if (hint->type == INDEX_HINT_USE && !hint->key_name.str) + { + if (hint->clause & INDEX_HINT_MASK_JOIN) + { + index_join[hint->type].clear_all(); + have_empty_use_join= TRUE; + } + if (hint->clause & INDEX_HINT_MASK_ORDER) + { + index_order[hint->type].clear_all(); + have_empty_use_order= TRUE; + } + if (hint->clause & INDEX_HINT_MASK_GROUP) + { + index_group[hint->type].clear_all(); + have_empty_use_group= TRUE; + } + continue; + } + + /* + Check if an index with the given name exists and get his offset in + the keys bitmask for the table + */ + if (table->s->keynames.type_names == 0 || + (pos= find_type(&table->s->keynames, hint->key_name.str, + hint->key_name.length, 1)) <= 0) + { + my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias); + return 1; + } + + pos--; + + /* add to the appropriate clause mask */ + if (hint->clause & INDEX_HINT_MASK_JOIN) + index_join[hint->type].set_bit (pos); + if (hint->clause & INDEX_HINT_MASK_ORDER) + index_order[hint->type].set_bit (pos); + if (hint->clause & INDEX_HINT_MASK_GROUP) + index_group[hint->type].set_bit (pos); + } + + /* cannot mix USE INDEX and FORCE INDEX */ + if ((!index_join[INDEX_HINT_FORCE].is_clear_all() || + !index_order[INDEX_HINT_FORCE].is_clear_all() || + !index_group[INDEX_HINT_FORCE].is_clear_all()) && + (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join || + !index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order || + !index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group)) + { + my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE], + index_hint_type_name[INDEX_HINT_FORCE]); + return 1; + } + + /* process FORCE INDEX as USE INDEX with a flag */ + if (!index_join[INDEX_HINT_FORCE].is_clear_all() || + !index_order[INDEX_HINT_FORCE].is_clear_all() || + !index_group[INDEX_HINT_FORCE].is_clear_all()) + { + table->force_index= TRUE; + index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]); + index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); + index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); + } + + /* apply USE INDEX */ + if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join) + table->keys_in_use_for_query= index_join[INDEX_HINT_USE]; + if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order) + table->keys_in_use_for_order_by= index_order[INDEX_HINT_USE]; + if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group) + table->keys_in_use_for_group_by= index_group[INDEX_HINT_USE]; + + /* apply IGNORE INDEX */ + table->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]); + table->keys_in_use_for_order_by.subtract (index_order[INDEX_HINT_IGNORE]); + table->keys_in_use_for_group_by.subtract (index_group[INDEX_HINT_IGNORE]); + } + + /* make sure covering_keys don't include indexes disabled with a hint */ + table->covering_keys.intersect(table->keys_in_use_for_query); + return 0; +} + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/table.cc.rej b/sql/table.cc.rej deleted file mode 100644 index fd728ba9965..00000000000 --- a/sql/table.cc.rej +++ /dev/null @@ -1,17 +0,0 @@ -*************** -*** 2246,2252 **** - - bool check_db_name(char *name) - { -! char *start=name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; - ---- 2257,2263 ---- - - bool check_db_name(char *name) - { -! char *start= name; - /* Used to catch empty names and names with end space */ - bool last_char_is_space= TRUE; - diff --git a/sql/table.h b/sql/table.h index 13666c82f4b..0dfca83d454 100644 --- a/sql/table.h +++ b/sql/table.h @@ -295,6 +295,12 @@ typedef struct st_table_share /* Information for one open table */ +enum index_hint_type +{ + INDEX_HINT_IGNORE, + INDEX_HINT_USE, + INDEX_HINT_FORCE +}; struct st_table { st_table() {} /* Remove gcc warning */ @@ -314,7 +320,18 @@ struct st_table { byte *write_row_record; /* Used as optimisation in THD::write_row */ byte *insert_values; /* used by INSERT ... UPDATE */ - key_map quick_keys, used_keys, keys_in_use_for_query, merge_keys; + /* + Map of keys that can be used to retrieve all data from this table + needed by the query without reading the row. + */ + key_map covering_keys; + key_map quick_keys, merge_keys; + /* Map of keys that can be used to access the table */ + key_map keys_in_use_for_query; + /* Map of keys that can be used to calculate GROUP BY without sorting */ + key_map keys_in_use_for_group_by; + /* Map of keys that can be used to calculate ORDER BY without sorting */ + key_map keys_in_use_for_order_by; KEY *key_info; /* data of keys in database */ Field *next_number_field; /* Set if next_number is activated */ @@ -636,6 +653,7 @@ public: (TABLE_LIST::join_using_fields != NULL) */ +class index_hint; typedef struct st_table_list { st_table_list() {} /* Remove gcc warning */ @@ -692,7 +710,7 @@ typedef struct st_table_list */ struct st_table_list *next_name_resolution_table; /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ - List *use_index, *ignore_index; + List *index_hints; TABLE *table; /* opened table */ uint table_id; /* table id (from binlog) for opened table */ /* @@ -866,6 +884,13 @@ typedef struct st_table_list void reinit_before_use(THD *thd); Item_subselect *containing_subselect(); + /* + Compiles the tagged hints list and fills up st_table::keys_in_use_for_query, + st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by, + st_table::force_index and st_table::covering_keys. + */ + bool process_index_hints(TABLE *table); + private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index f407f62fa0c..906d4e8a1a5 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -804,23 +804,22 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt) KEY_CACHE *new_key_cache= check_opt->key_cache; const char *errmsg= 0; int error= HA_ADMIN_OK; - ulonglong map= ~(ulonglong) 0; + ulonglong map; TABLE_LIST *table_list= table->pos_in_table_list; DBUG_ENTER("ha_myisam::assign_to_keycache"); - /* Check validity of the index references */ - if (table_list->use_index) + table->keys_in_use_for_query.clear_all(); + + if (table_list->process_index_hints(table)) { - /* We only come here when the user did specify an index map */ - key_map kmap; - if (get_key_map_from_key_list(&kmap, table, table_list->use_index)) - { - errmsg= thd->net.last_error; - error= HA_ADMIN_FAILED; - goto err; - } - map= kmap.to_ulonglong(); + errmsg= thd->net.last_error; + error= HA_ADMIN_FAILED; + goto err; } + map= ~(ulonglong) 0; + if (!table->keys_in_use_for_query.is_clear_all()) + /* use all keys if there's no list specified by the user through hints */ + map= table->keys_in_use_for_query.to_ulonglong(); if ((error= mi_assign_to_key_cache(file, map, new_key_cache))) { @@ -856,27 +855,27 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt) { int error; const char *errmsg; - ulonglong map= ~(ulonglong) 0; + ulonglong map; TABLE_LIST *table_list= table->pos_in_table_list; my_bool ignore_leaves= table_list->ignore_leaves; DBUG_ENTER("ha_myisam::preload_keys"); - /* Check validity of the index references */ - if (table_list->use_index) + table->keys_in_use_for_query.clear_all(); + + if (table_list->process_index_hints(table)) { - 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.is_clear_all()) - map= kmap.to_ulonglong(); + errmsg= thd->net.last_error; + error= HA_ADMIN_FAILED; + goto err; } + map= ~(ulonglong) 0; + /* Check validity of the index references */ + if (!table->keys_in_use_for_query.is_clear_all()) + /* use all keys if there's no list specified by the user through hints */ + map= table->keys_in_use_for_query.to_ulonglong(); + mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE, (void *) &thd->variables.preload_buff_size); From d2c977a9355f69311d0007f5e1b2eac958e5084d Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Wed, 7 Mar 2007 14:51:45 +0200 Subject: [PATCH 10/34] Bug #26672: DATE/DATETIME values are out of the currently supported 4 basic value types (INT,STRING,REAL and DECIMAL). So expressions (not fields) of compile type DATE/DATETIME are generally considered as STRING values. This is not so when they are compared : then they are compared as INTEGER values. But the rule for comparison as INTEGERS must be checked explicitly each time when a comparison is to be performed. filesort is one such place. However there the check was not done and hence the expressions (not fields) of type DATE/DATETIME were sorted by their string representation. Fixed to compare them as INTEGER values for filesort. --- mysql-test/r/order_by.result | 22 ++++++++++++++++++++++ mysql-test/t/order_by.test | 15 +++++++++++++++ sql/filesort.cc | 5 ++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 0b1edfd3e8f..2093b5cd465 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -934,3 +934,25 @@ a ratio 19 1.3333 9 2.6667 drop table t1; +CREATE TABLE t1 (a INT UNSIGNED NOT NULL, b TIME); +INSERT INTO t1 (a) VALUES (100000), (0), (100), (1000000),(10000), (1000), (10); +UPDATE t1 SET b = SEC_TO_TIME(a); +SELECT a, b FROM t1 ORDER BY b DESC; +a b +1000000 277:46:40 +100000 27:46:40 +10000 02:46:40 +1000 00:16:40 +100 00:01:40 +10 00:00:10 +0 00:00:00 +SELECT a, b FROM t1 ORDER BY SEC_TO_TIME(a) DESC; +a b +1000000 277:46:40 +100000 27:46:40 +10000 02:46:40 +1000 00:16:40 +100 00:01:40 +10 00:00:10 +0 00:00:00 +DROP TABLE t1; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index a3aa2c0081d..2de6f791cfa 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -648,3 +648,18 @@ create table t1 (a int, b int, c int); insert into t1 values (1,2,3), (9,8,3), (19,4,3), (1,4,9); select a,(sum(b)/sum(c)) as ratio from t1 group by a order by sum(b)/sum(c) asc; drop table t1; + +# +# Bug#26672: Incorrect SEC_TO_TIME() casting in ORDER BY +# +CREATE TABLE t1 (a INT UNSIGNED NOT NULL, b TIME); +INSERT INTO t1 (a) VALUES (100000), (0), (100), (1000000),(10000), (1000), (10); +UPDATE t1 SET b = SEC_TO_TIME(a); + +-- Correct ORDER +SELECT a, b FROM t1 ORDER BY b DESC; + +-- must be ordered as the above +SELECT a, b FROM t1 ORDER BY SEC_TO_TIME(a) DESC; + +DROP TABLE t1; diff --git a/sql/filesort.cc b/sql/filesort.cc index e40c492fe8e..23d652cb8cc 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1298,7 +1298,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length, } else { - switch ((sortorder->result_type=sortorder->item->result_type())) { + sortorder->result_type= sortorder->item->result_type(); + if (sortorder->item->result_as_longlong()) + sortorder->result_type= INT_RESULT; + switch (sortorder->result_type) { case STRING_RESULT: sortorder->length=sortorder->item->max_length; set_if_smaller(sortorder->length, thd->variables.max_sort_length); From 6bea442d269478810611c1ea9f56b2a76b5ecb07 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Fri, 9 Mar 2007 15:20:06 +0200 Subject: [PATCH 11/34] WL#3527: Extend IGNORE INDEX so places where index is ignored can be specified 5.0 part of the fix. Implements IGNORE INDEX FOR JOIN as a synonym of IGNORE INDEX for backward compatibility with the 5.1 fix. --- mysql-test/r/select.result | 9 +++++++++ mysql-test/t/select.test | 10 ++++++++++ sql/sql_yacc.yy | 17 +++++++++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 44063c1e890..6fbe0a3b9df 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3611,3 +3611,12 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range si,ai si 5 NULL 2 Using where 1 SIMPLE t3 eq_ref PRIMARY,ci PRIMARY 4 test.t2.a 1 Using where DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a INT, b INT, KEY (a)); +INSERT INTO t1 VALUES (1,1),(2,2); +EXPLAIN SELECT 1 FROM t1 WHERE a = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref a a 5 const 1 Using where; Using index +EXPLAIN SELECT 1 FROM t1 IGNORE INDEX FOR JOIN (a) WHERE a = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +DROP TABLE t1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 0c82cef867f..033573304c7 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3092,3 +3092,13 @@ SELECT t3.a FROM t1,t2,t3 t3.c IN ('bb','ee'); DROP TABLE t1,t2,t3; + +# +# WL3527: Extend IGNORE INDEX so places where index is ignored can +# be specified +# +CREATE TABLE t1 (a INT, b INT, KEY (a)); INSERT INTO t1 VALUES (1,1),(2,2); +EXPLAIN SELECT 1 FROM t1 WHERE a = 1; +EXPLAIN SELECT 1 FROM t1 IGNORE INDEX FOR JOIN (a) WHERE a = 1; +DROP TABLE t1; + diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 90dc6d54fe1..69052e5e0d6 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -772,7 +772,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); key_alg opt_btree_or_rtree %type - key_usage_list using_list + key_usage_list key_usage_list_inner using_list %type key_part @@ -5553,6 +5553,10 @@ opt_outer: /* empty */ {} | OUTER {}; +opt_for_join: + /* empty */ + | FOR_SYM JOIN_SYM; + opt_key_definition: /* empty */ {} | USE_SYM key_usage_list @@ -5568,15 +5572,20 @@ opt_key_definition: sel->use_index_ptr= &sel->use_index; sel->table_join_options|= TL_OPTION_FORCE_INDEX; } - | IGNORE_SYM key_usage_list + | IGNORE_SYM key_or_index opt_for_join key_usage_list_inner { SELECT_LEX *sel= Select; - sel->ignore_index= *$2; + sel->ignore_index= *$4; sel->ignore_index_ptr= &sel->ignore_index; }; key_usage_list: - key_or_index { Select->interval_list.empty(); } + key_or_index key_usage_list_inner + { $$= $2; } + ; + +key_usage_list_inner: + { Select->interval_list.empty(); } '(' key_list_or_empty ')' { $$= &Select->interval_list; } ; From 6088b025d732f012a2909f768693af066f1002b0 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Sat, 10 Mar 2007 17:44:25 +0400 Subject: [PATCH 12/34] bug #26833 (Compile error with embedded lib) org_tables declaration was mistakenly #ifdef-ed with the EMBEDDED_LIBRARY instead of ACCESS_CHECKS --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b503e147624..d22b511c630 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5402,7 +5402,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, { uint found=0; ulong found_access=0; -#ifndef EMBEDDED_LIBRARY +#ifndef NO_EMBEDDED_ACCESS_CHECKS TABLE_LIST *org_tables= tables; #endif TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); From a474f334948345127abbbdde7264436a998c8b75 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Sun, 11 Mar 2007 14:31:43 +0200 Subject: [PATCH 13/34] WL3527: post-merge updates sql_yacc.yy: WL3527: updated the diff to use correct parser words table.cc: WL3527: exteneded the fix for bug #20604 to fit the new variables sql_select.cc: WL3527: renamed used_keys to covering_keys --- sql/sql_select.cc | 2 +- sql/sql_yacc.yy | 2 +- sql/table.cc | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d78b722632d..3a6cb754cbe 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -654,7 +654,7 @@ void JOIN::remove_subq_pushed_predicates(Item **where) static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where) { join_tab->packed_info= TAB_INFO_HAVE_VALUE; - if (join_tab->table->used_keys.is_set(join_tab->ref.key)) + if (join_tab->table->covering_keys.is_set(join_tab->ref.key)) join_tab->packed_info |= TAB_INFO_USING_INDEX; if (where) join_tab->packed_info |= TAB_INFO_USING_WHERE; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 01a813b4357..7da1ddc7cad 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7548,7 +7548,7 @@ index_hint_clause: } | FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; } | FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; } - | FOR_SYM GROUP BY { $$= INDEX_HINT_MASK_GROUP; } + | FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; } ; index_hint_type: diff --git a/sql/table.cc b/sql/table.cc index daec7492500..fd810ae7478 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4272,11 +4272,11 @@ bool st_table_list::process_index_hints(TABLE *table) /* apply USE INDEX */ if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join) - table->keys_in_use_for_query= index_join[INDEX_HINT_USE]; + table->keys_in_use_for_query.intersect(index_join[INDEX_HINT_USE]); if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order) - table->keys_in_use_for_order_by= index_order[INDEX_HINT_USE]; + table->keys_in_use_for_order_by.intersect (index_order[INDEX_HINT_USE]); if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group) - table->keys_in_use_for_group_by= index_group[INDEX_HINT_USE]; + table->keys_in_use_for_group_by.intersect (index_group[INDEX_HINT_USE]); /* apply IGNORE INDEX */ table->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]); From e7284ace4f0f25fef34a72c16e34c30e11fdf6b4 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Sun, 11 Mar 2007 23:34:40 -0700 Subject: [PATCH 14/34] Fixed bug #26963: invalid optimization of the pushdown conditions after single-row table substitution could lead to a wrong result set. The bug happened because the function Item_field::replace_equal_field erroniously assumed that any field included in a multiple equality with a constant has been already substituted for this constant. This not true for fields becoming constant after row substitutions for constant tables. --- mysql-test/r/select.result | 38 ++++++++++++++++++++++++++++++ mysql-test/t/select.test | 47 ++++++++++++++++++++++++++++++++++++++ sql/item.cc | 15 ++++++++++-- 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index c3132a1b5f6..ae32607973a 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3933,4 +3933,42 @@ cc cc 7 aa aa 2 aa aa 2 DROP TABLE t1,t2; +CREATE TABLE t1 ( +access_id int NOT NULL default '0', +name varchar(20) default NULL, +rank int NOT NULL default '0', +KEY idx (access_id) +); +CREATE TABLE t2 ( +faq_group_id int NOT NULL default '0', +faq_id int NOT NULL default '0', +access_id int default NULL, +UNIQUE KEY idx1 (faq_id), +KEY idx2 (faq_group_id,faq_id) +); +INSERT INTO t1 VALUES +(1,'Everyone',2),(2,'Help',3),(3,'Technical Support',1),(4,'Chat User',4); +INSERT INTO t2 VALUES +(261,265,1),(490,494,1); +SELECT t2.faq_id +FROM t1 INNER JOIN t2 IGNORE INDEX (idx1) +ON (t1.access_id = t2.access_id) +LEFT JOIN t2 t +ON (t.faq_group_id = t2.faq_group_id AND +find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4')) +WHERE +t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265); +faq_id +265 +SELECT t2.faq_id +FROM t1 INNER JOIN t2 +ON (t1.access_id = t2.access_id) +LEFT JOIN t2 t +ON (t.faq_group_id = t2.faq_group_id AND +find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4')) +WHERE +t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265); +faq_id +265 +DROP TABLE t1,t2; End of 5.0 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index ea5fadb2e1b..8442a073620 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3299,4 +3299,51 @@ SELECT * FROM t1 LEFT JOIN t2 ON t1.name=t2.name; DROP TABLE t1,t2; + +# +# Bug #26963: join with predicates that contain fields from equalities evaluated +# to constants after constant table substitution +# + +CREATE TABLE t1 ( + access_id int NOT NULL default '0', + name varchar(20) default NULL, + rank int NOT NULL default '0', + KEY idx (access_id) +); + +CREATE TABLE t2 ( + faq_group_id int NOT NULL default '0', + faq_id int NOT NULL default '0', + access_id int default NULL, + UNIQUE KEY idx1 (faq_id), + KEY idx2 (faq_group_id,faq_id) +); + +INSERT INTO t1 VALUES + (1,'Everyone',2),(2,'Help',3),(3,'Technical Support',1),(4,'Chat User',4); +INSERT INTO t2 VALUES + (261,265,1),(490,494,1); + + +SELECT t2.faq_id + FROM t1 INNER JOIN t2 IGNORE INDEX (idx1) + ON (t1.access_id = t2.access_id) + LEFT JOIN t2 t + ON (t.faq_group_id = t2.faq_group_id AND + find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4')) + WHERE + t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265); + +SELECT t2.faq_id + FROM t1 INNER JOIN t2 + ON (t1.access_id = t2.access_id) + LEFT JOIN t2 t + ON (t.faq_group_id = t2.faq_group_id AND + find_in_set(t.access_id, '1,4') < find_in_set(t2.access_id, '1,4')) + WHERE + t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265); + +DROP TABLE t1,t2; + --echo End of 5.0 tests diff --git a/sql/item.cc b/sql/item.cc index ec33bf1ddc7..11a5039ca19 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4075,7 +4075,9 @@ bool Item_field::set_no_const_sub(byte *arg) DESCRIPTION The function returns a pointer to an item that is taken from the very beginning of the item_equal list which the Item_field - object refers to (belongs to). + object refers to (belongs to) unless item_equal contains a constant + item. In this case the function returns this constant item, + (if the substitution does not require conversion). If the Item_field object does not refer any Item_equal object 'this' is returned @@ -4084,7 +4086,8 @@ bool Item_field::set_no_const_sub(byte *arg) of the thransformer method. RETURN VALUES - pointer to a replacement Item_field if there is a better equal item; + pointer to a replacement Item_field if there is a better equal item or + a pointer to a constant equal item; this - otherwise. */ @@ -4092,6 +4095,14 @@ Item *Item_field::replace_equal_field(byte *arg) { if (item_equal) { + Item *const_item= item_equal->get_const(); + if (const_item) + { + if (cmp_context != (Item_result)-1 && + const_item->cmp_context != cmp_context) + return this; + return const_item; + } Item_field *subst= item_equal->get_first(); if (subst && !field->eq(subst->field)) return subst; From 06a315ded67a5751b46dd6295780e85e3e68de28 Mon Sep 17 00:00:00 2001 From: "igor@olga.mysql.com" <> Date: Mon, 12 Mar 2007 01:39:57 -0700 Subject: [PATCH 15/34] Fixed bug #26738: incomplete string values in a result set column when the column is to be read from a derived table column which was specified as a concatenation of string literals. The bug happened because the Item_string::append did not adjust the value of Item_string::max_length. As a result of it the temporary table column defined to store the concatenation of literals was not wide enough to hold the whole value. --- mysql-test/r/subselect.result | 13 +++++++++++++ mysql-test/t/subselect.test | 13 +++++++++++++ sql/item.h | 6 +++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 71dbff65e7d..f2d41bd44ae 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3867,3 +3867,16 @@ id_1 DROP TABLE t1; DROP TABLE t2; DROP TABLE t1xt2; +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (1), (2); +SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1; +col1 col2 +this is a test. 3 +this is a test. 1 +this is a test. 2 +SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t; +col1 t2 +this is a test. 3 +this is a test. 1 +this is a test. 2 +DROP table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1deda2a4382..1655422c51e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2729,3 +2729,16 @@ DROP TABLE t1; DROP TABLE t2; DROP TABLE t1xt2; +# +# Bug #26728: derived table with concatanation of literals in select list +# + +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (3), (1), (2); + +SELECT 'this is ' 'a test.' AS col1, a AS col2 FROM t1; +SELECT * FROM (SELECT 'this is ' 'a test.' AS col1, a AS t2 FROM t1) t; + +DROP table t1; + + diff --git a/sql/item.h b/sql/item.h index fb1a87d54fa..c2084fb727c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1713,7 +1713,11 @@ public: str_value.length(), collation.collation); } Item *safe_charset_converter(CHARSET_INFO *tocs); - inline void append(char *str, uint length) { str_value.append(str, length); } + inline void append(char *str, uint length) + { + str_value.append(str, length); + max_length= str_value.numchars() * collation.collation->mbmaxlen; + } void print(String *str); // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} From f2ce1445e13f82a9f005c980146a29f99e5a92ff Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Mon, 12 Mar 2007 13:20:46 +0200 Subject: [PATCH 16/34] group_by.result: WL3527: disable wrong optimization. sql_select.cc: WL#3527: disable wrong optimization. --- mysql-test/r/group_by.result | 2 +- sql/sql_select.cc | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index ae61dfb252d..5cff5fec7ed 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1067,7 +1067,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY,i2) ORDER BY a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL 256 Using index; Using filesort EXPLAIN SELECT a FROM t1 IGNORE INDEX FOR ORDER BY (PRIMARY) IGNORE INDEX FOR GROUP BY (i2) GROUP BY a; id select_type table type possible_keys key key_len ref rows Extra diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3a6cb754cbe..5029ae2cf22 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12393,24 +12393,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, DBUG_ENTER("test_if_skip_sort_order"); LINT_INIT(ref_key_parts); - /* Check which keys can be used to resolve ORDER BY. */ - usable_keys= table->keys_in_use_for_query; - /* Keys disabled by ALTER TABLE ... DISABLE KEYS should have already been taken into account. */ usable_keys= *map; - /* - If there is a covering index, and we have IGNORE INDEX FOR GROUP/ORDER - and this index is used for the JOIN part, then we have to ignore the - IGNORE INDEX FOR GROUP/ORDER - */ - if (table->key_read || - (table->covering_keys.is_set(tab->index) && !table->no_keyread)) - usable_keys.set_bit (tab->index); - for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { Item *item= (*tmp_order->item)->real_item(); From 36d2a231e31dcdf1dc0194a3c98e9160cb7a5ba3 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Mon, 12 Mar 2007 16:57:00 +0200 Subject: [PATCH 17/34] Bug #26794: Different set of conditions is used to verify the validity of index definitions over a GEOMETRY column in ALTER TABLE and CREATE TABLE. The difference was on how sub-keys notion validity is checked. Fixed by extending the CREATE TABLE condition to support the cases allowed in ALTER TABLE. Made the SHOW CREATE TABLE not to display spatial indexes using the sub-key notion. --- mysql-test/r/alter_table.result | 34 +++++++++++++++++++++++++++++++++ mysql-test/r/gis-rtree.result | 4 ++-- mysql-test/t/alter_table.test | 23 ++++++++++++++++++++++ sql/field.cc | 1 + sql/sql_show.cc | 2 +- sql/sql_table.cc | 4 +++- 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index d8de2655c6c..82c35ff963a 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -826,3 +826,37 @@ create table t1 (t varchar(255) default null, key t (t(80))) engine=myisam default charset=latin1; alter table t1 change t t text; drop table t1; +CREATE TABLE t1 (a varchar(500)); +ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) default NULL, + `b` geometry NOT NULL, + SPATIAL KEY `b` (`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD KEY(b(50)); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) default NULL, + `b` geometry NOT NULL, + SPATIAL KEY `b` (`b`), + KEY `b_2` (`b`(50)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD c POINT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) default NULL, + `b` geometry NOT NULL, + `c` point default NULL, + SPATIAL KEY `b` (`b`), + KEY `b_2` (`b`(50)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CREATE TABLE t2 (a INT, KEY (a(20))); +ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys +ALTER TABLE t1 ADD d INT; +ALTER TABLE t1 ADD KEY (d(20)); +ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys +DROP TABLE t1; diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 05d0d5634e6..4ca2bc98d82 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -10,7 +10,7 @@ t1 CREATE TABLE `t1` ( `fid` int(11) NOT NULL auto_increment, `g` geometry NOT NULL, PRIMARY KEY (`fid`), - SPATIAL KEY `g` (`g`(32)) + SPATIAL KEY `g` (`g`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)')); INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)')); @@ -293,7 +293,7 @@ t2 CREATE TABLE `t2` ( `fid` int(11) NOT NULL auto_increment, `g` geometry NOT NULL, PRIMARY KEY (`fid`), - SPATIAL KEY `g` (`g`(32)) + SPATIAL KEY `g` (`g`) ) ENGINE=MyISAM AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 SELECT count(*) FROM t2; count(*) diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 01f55931ca4..307138added 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -613,3 +613,26 @@ create table t1 (t varchar(255) default null, key t (t(80))) engine=myisam default charset=latin1; alter table t1 change t t text; drop table t1; + +# +# Bug #26794: Adding an index with a prefix on a SPATIAL type breaks ALTER +# TABLE +# +CREATE TABLE t1 (a varchar(500)); + +ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD KEY(b(50)); +SHOW CREATE TABLE t1; + +ALTER TABLE t1 ADD c POINT; +SHOW CREATE TABLE t1; + +--error ER_WRONG_SUB_KEY +CREATE TABLE t2 (a INT, KEY (a(20))); + +ALTER TABLE t1 ADD d INT; +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD KEY (d(20)); + +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 981a877783f..0f8103b4046 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1011,6 +1011,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type) case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_GEOMETRY: return TRUE; default: return FALSE; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c4b06934fc3..24aef80626f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -992,7 +992,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (key_part->field && (key_part->length != table->field[key_part->fieldnr-1]->key_length() && - !(key_info->flags & HA_FULLTEXT))) + !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL)))) { buff[0] = '('; char* end=int10_to_str((long) key_part->length / diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 512d990347f..38a22c47f12 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1344,6 +1344,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } else if (!f_is_geom(sql_field->pack_flag) && (column->length > length || + !Field::type_can_have_key_part (sql_field->sql_type) || ((f_is_packed(sql_field->pack_flag) || ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && (key_info->flags & HA_NOSAME))) && @@ -3470,7 +3471,8 @@ view_err: checking whether cfield->length < key_part_length (in chars). */ if (!Field::type_can_have_key_part(cfield->field->type()) || - !Field::type_can_have_key_part(cfield->sql_type) || + (!Field::type_can_have_key_part(cfield->sql_type) && + !f_is_geom (cfield->pack_flag)) || (cfield->field->field_length == key_part_length && !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / From 8c1f70aef6ed0abc70da2892d6c2b53f04d63265 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 14 Mar 2007 11:54:20 +0200 Subject: [PATCH 18/34] Bug #26794: Different set of conditions is used to verify the validity of index definitions over a GEOMETRY column in ALTER TABLE and CREATE TABLE. The difference was on how sub-keys notion validity is checked. Fixed by extending the CREATE TABLE condition to support the cases allowed in ALTER TABLE. Made the SHOW CREATE TABLE not to display spatial indexes using the sub-key notion. --- mysql-test/r/alter_table.result | 34 +++++++++++++++++++++++++++++++++ mysql-test/r/gis-rtree.result | 4 ++-- mysql-test/t/alter_table.test | 23 ++++++++++++++++++++++ sql/field.cc | 1 + sql/sql_show.cc | 2 +- sql/sql_table.cc | 4 +++- 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index d8de2655c6c..82c35ff963a 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -826,3 +826,37 @@ create table t1 (t varchar(255) default null, key t (t(80))) engine=myisam default charset=latin1; alter table t1 change t t text; drop table t1; +CREATE TABLE t1 (a varchar(500)); +ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) default NULL, + `b` geometry NOT NULL, + SPATIAL KEY `b` (`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD KEY(b(50)); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) default NULL, + `b` geometry NOT NULL, + SPATIAL KEY `b` (`b`), + KEY `b_2` (`b`(50)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD c POINT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) default NULL, + `b` geometry NOT NULL, + `c` point default NULL, + SPATIAL KEY `b` (`b`), + KEY `b_2` (`b`(50)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CREATE TABLE t2 (a INT, KEY (a(20))); +ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys +ALTER TABLE t1 ADD d INT; +ALTER TABLE t1 ADD KEY (d(20)); +ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys +DROP TABLE t1; diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 05d0d5634e6..4ca2bc98d82 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -10,7 +10,7 @@ t1 CREATE TABLE `t1` ( `fid` int(11) NOT NULL auto_increment, `g` geometry NOT NULL, PRIMARY KEY (`fid`), - SPATIAL KEY `g` (`g`(32)) + SPATIAL KEY `g` (`g`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)')); INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)')); @@ -293,7 +293,7 @@ t2 CREATE TABLE `t2` ( `fid` int(11) NOT NULL auto_increment, `g` geometry NOT NULL, PRIMARY KEY (`fid`), - SPATIAL KEY `g` (`g`(32)) + SPATIAL KEY `g` (`g`) ) ENGINE=MyISAM AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 SELECT count(*) FROM t2; count(*) diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 01f55931ca4..307138added 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -613,3 +613,26 @@ create table t1 (t varchar(255) default null, key t (t(80))) engine=myisam default charset=latin1; alter table t1 change t t text; drop table t1; + +# +# Bug #26794: Adding an index with a prefix on a SPATIAL type breaks ALTER +# TABLE +# +CREATE TABLE t1 (a varchar(500)); + +ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD KEY(b(50)); +SHOW CREATE TABLE t1; + +ALTER TABLE t1 ADD c POINT; +SHOW CREATE TABLE t1; + +--error ER_WRONG_SUB_KEY +CREATE TABLE t2 (a INT, KEY (a(20))); + +ALTER TABLE t1 ADD d INT; +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD KEY (d(20)); + +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 981a877783f..0f8103b4046 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1011,6 +1011,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type) case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_GEOMETRY: return TRUE; default: return FALSE; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c4b06934fc3..24aef80626f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -992,7 +992,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet) if (key_part->field && (key_part->length != table->field[key_part->fieldnr-1]->key_length() && - !(key_info->flags & HA_FULLTEXT))) + !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL)))) { buff[0] = '('; char* end=int10_to_str((long) key_part->length / diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 512d990347f..38a22c47f12 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1344,6 +1344,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } else if (!f_is_geom(sql_field->pack_flag) && (column->length > length || + !Field::type_can_have_key_part (sql_field->sql_type) || ((f_is_packed(sql_field->pack_flag) || ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && (key_info->flags & HA_NOSAME))) && @@ -3470,7 +3471,8 @@ view_err: checking whether cfield->length < key_part_length (in chars). */ if (!Field::type_can_have_key_part(cfield->field->type()) || - !Field::type_can_have_key_part(cfield->sql_type) || + (!Field::type_can_have_key_part(cfield->sql_type) && + !f_is_geom (cfield->pack_flag)) || (cfield->field->field_length == key_part_length && !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / From 03df3bf6db97be4578b1d2ccdce9317fae61c2b0 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 14 Mar 2007 12:20:34 +0200 Subject: [PATCH 19/34] Bug #26794: 5.1 part It was syntactically correct to define spatial keys over parts of columns (e.g. ALTER TABLE t1 ADD x GEOMETRY NOT NULL, ADD SPATIAL KEY (x(32))). This may lead to undefined results and/or interpretation. Fixed by not allowing partial column specification in a SPATIAL index definition. --- mysql-test/r/alter_table.result | 10 ++++++---- mysql-test/r/gis-rtree.result | 6 +++--- mysql-test/t/alter_table.test | 4 ++++ mysql-test/t/gis-rtree.test | 6 +++--- sql/sql_table.cc | 8 ++++++++ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index f90827929e5..fa18b58a927 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -886,7 +886,7 @@ ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(500) default NULL, + `a` varchar(500) DEFAULT NULL, `b` geometry NOT NULL, SPATIAL KEY `b` (`b`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -894,7 +894,7 @@ ALTER TABLE t1 ADD KEY(b(50)); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(500) default NULL, + `a` varchar(500) DEFAULT NULL, `b` geometry NOT NULL, SPATIAL KEY `b` (`b`), KEY `b_2` (`b`(50)) @@ -903,9 +903,9 @@ ALTER TABLE t1 ADD c POINT; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(500) default NULL, + `a` varchar(500) DEFAULT NULL, `b` geometry NOT NULL, - `c` point default NULL, + `c` point DEFAULT NULL, SPATIAL KEY `b` (`b`), KEY `b_2` (`b`(50)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -914,6 +914,8 @@ ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used ALTER TABLE t1 ADD d INT; ALTER TABLE t1 ADD KEY (d(20)); ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys +ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30)); +ERROR HY000: Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys DROP TABLE t1; CREATE TABLE t1 (s CHAR(8) BINARY); INSERT INTO t1 VALUES ('test'); diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 4a0f5d9b2eb..a1fd657b361 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -803,7 +803,7 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); INSERT INTO t2 SELECT GeomFromText(st) FROM t1; ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field drop table t1, t2; -CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`(32))) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; Warnings: Warning 1101 BLOB/TEXT column 'geometry' can't have a default value INSERT INTO t1 (geometry) VALUES @@ -820,7 +820,7 @@ test.t1 check status OK drop table t1; CREATE TABLE t1 ( c1 geometry NOT NULL default '', -SPATIAL KEY i1 (c1(32)) +SPATIAL KEY i1 (c1) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Warnings: Warning 1101 BLOB/TEXT column 'c1' can't have a default value @@ -836,7 +836,7 @@ test.t1 check status OK DROP TABLE t1; CREATE TABLE t1 ( c1 geometry NOT NULL default '', -SPATIAL KEY i1 (c1(32)) +SPATIAL KEY i1 (c1) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Warnings: Warning 1101 BLOB/TEXT column 'c1' can't have a default value diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 5844119ac92..b8ba35b78ca 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -662,6 +662,10 @@ ALTER TABLE t1 ADD d INT; --error ER_WRONG_SUB_KEY ALTER TABLE t1 ADD KEY (d(20)); +# the 5.1 part of the test +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30)); + DROP TABLE t1; # diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index 1704fe7dc80..90af71929ca 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -172,7 +172,7 @@ CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); INSERT INTO t2 SELECT GeomFromText(st) FROM t1; drop table t1, t2; -CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`(32))) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; INSERT INTO t1 (geometry) VALUES (PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000 @@ -192,7 +192,7 @@ drop table t1; # CREATE TABLE t1 ( c1 geometry NOT NULL default '', - SPATIAL KEY i1 (c1(32)) + SPATIAL KEY i1 (c1) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; INSERT INTO t1 (c1) VALUES ( PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, @@ -206,7 +206,7 @@ DROP TABLE t1; # CREATE TABLE t1 ( c1 geometry NOT NULL default '', - SPATIAL KEY i1 (c1(32)) + SPATIAL KEY i1 (c1) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; INSERT INTO t1 (c1) VALUES ( PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 177b568746a..328830f5db2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2791,6 +2791,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, { column->length*= sql_field->charset->mbmaxlen; + if (key->type == Key::SPATIAL && column->length) + { + my_error(ER_WRONG_SUB_KEY, MYF(0)); + DBUG_RETURN(-1); + } + if (f_is_blob(sql_field->pack_flag) || (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL)) { @@ -5861,6 +5867,8 @@ view_err: if (!Field::type_can_have_key_part(cfield->field->type()) || (!Field::type_can_have_key_part(cfield->sql_type) && !f_is_geom (cfield->pack_flag)) || + /* spatial keys can't have sub-key length */ + (key_info->flags & HA_SPATIAL) || (cfield->field->field_length == key_part_length && !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / From e61cce4d6b47e27407e3631c4aba81701d1ef41a Mon Sep 17 00:00:00 2001 From: "mhansson/martin@linux-st28.site" <> Date: Wed, 14 Mar 2007 12:15:14 +0100 Subject: [PATCH 20/34] Bug #24778: Innodb: No result when using ORDER BY This bug was intruduced by the fix for bug#17212 (in 4.1). It is not ok to call test_if_skip_sort_order since this function will alter the execution plan. By contract it is not ok to call test_if_skip_sort_order in this context. This bug appears only in the case when the optimizer has chosen an index for accessing a particular table but finds a covering index that enables it to skip ORDER BY. This happens in test_if_skip_sort_order. --- mysql-test/r/key.result | 41 +++++++++++++++++++++++++++++++++++ mysql-test/t/key.test | 48 +++++++++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 5 +---- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 853b837c46e..e348a387252 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -489,3 +489,44 @@ EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 drop table t1; +CREATE TABLE t1 ( +a INTEGER auto_increment PRIMARY KEY, +b INTEGER NOT NULL, +c INTEGER NOT NULL, +d CHAR(64) +); +CREATE TABLE t2 ( +a INTEGER auto_increment PRIMARY KEY, +b INTEGER NOT NULL, +c SMALLINT NOT NULL, +d DATETIME NOT NULL, +e SMALLINT NOT NULL, +f INTEGER NOT NULL, +g INTEGER NOT NULL, +h SMALLINT NOT NULL, +i INTEGER NOT NULL, +j INTEGER NOT NULL, +UNIQUE INDEX (b), +INDEX (b, d, e, f, g, h, i, j, c), +INDEX (c) +); +INSERT INTO t2 VALUES +(NULL, 1, 254, '1000-01-01 00:00:00', 257, 0, 0, 0, 0, 0), +(NULL, 2, 1, '2004-11-30 12:00:00', 1, 0, 0, 0, 0, 0), +(NULL, 3, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -21600, 0), +(NULL, 4, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -10800, 0), +(NULL, 5, 1, '2004-11-30 12:00:00', 1, 0, 0, 5, -10800, 0), +(NULL, 6, 1, '2004-11-30 12:00:00', 102, 0, 0, 0, 0, 0), +(NULL, 7, 1, '2004-11-30 12:00:00', 105, 2, 0, 0, 0, 0), +(NULL, 8, 1, '2004-11-30 12:00:00', 105, 10, 0, 0, 0, 0); +INSERT INTO t1 (b, c, d) VALUES +(3388000, -553000, NULL), +(3388000, -553000, NULL); +SELECT * +FROM t2 c JOIN t1 pa ON c.b = pa.a +WHERE c.c = 1 +ORDER BY c.b, c.d +; +a b c d e f g h i j a b c d +2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL +DROP TABLE t1, t2; diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 1a53344c8ef..99736e0f11f 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -453,3 +453,51 @@ ALTER TABLE t1 DISABLE KEYS; EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a); drop table t1; + +# +# Bug #24778: Innodb: No result when using ORDER BY +# +CREATE TABLE t1 ( + a INTEGER auto_increment PRIMARY KEY, + b INTEGER NOT NULL, + c INTEGER NOT NULL, + d CHAR(64) +); + +CREATE TABLE t2 ( + a INTEGER auto_increment PRIMARY KEY, + b INTEGER NOT NULL, + c SMALLINT NOT NULL, + d DATETIME NOT NULL, + e SMALLINT NOT NULL, + f INTEGER NOT NULL, + g INTEGER NOT NULL, + h SMALLINT NOT NULL, + i INTEGER NOT NULL, + j INTEGER NOT NULL, + UNIQUE INDEX (b), + INDEX (b, d, e, f, g, h, i, j, c), + INDEX (c) +); + +INSERT INTO t2 VALUES + (NULL, 1, 254, '1000-01-01 00:00:00', 257, 0, 0, 0, 0, 0), + (NULL, 2, 1, '2004-11-30 12:00:00', 1, 0, 0, 0, 0, 0), + (NULL, 3, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -21600, 0), + (NULL, 4, 1, '2004-11-30 12:00:00', 1, 0, 0, 2, -10800, 0), + (NULL, 5, 1, '2004-11-30 12:00:00', 1, 0, 0, 5, -10800, 0), + (NULL, 6, 1, '2004-11-30 12:00:00', 102, 0, 0, 0, 0, 0), + (NULL, 7, 1, '2004-11-30 12:00:00', 105, 2, 0, 0, 0, 0), + (NULL, 8, 1, '2004-11-30 12:00:00', 105, 10, 0, 0, 0, 0); + +INSERT INTO t1 (b, c, d) VALUES + (3388000, -553000, NULL), + (3388000, -553000, NULL); + +SELECT * +FROM t2 c JOIN t1 pa ON c.b = pa.a +WHERE c.c = 1 +ORDER BY c.b, c.d +; + +DROP TABLE t1, t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5029ae2cf22..efdedcc5e84 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6106,10 +6106,7 @@ make_join_readinfo(JOIN *join, ulonglong options) */ if (!ordered_set && (table == join->sort_by_table && - (!join->order || join->skip_sort_order || - test_if_skip_sort_order(tab, join->order, join->select_limit, - 1, &table->keys_in_use_for_order_by)) - ) || + (!join->order || join->skip_sort_order)) || (join->sort_by_table == (TABLE *) 1 && i != join->const_tables)) ordered_set= 1; From 31b636c0419987933bab5d26ca132816ac28d8e4 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 14 Mar 2007 13:32:12 +0200 Subject: [PATCH 21/34] WL#3527 : inspected a 5.1 covarage report --- sql/item.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/item.cc b/sql/item.cc index dcedfcb6d84..5c032e3356f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3907,7 +3907,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) { /* First usage of column */ table->used_fields++; // Used to optimize loops + /* purecov: begin inspected */ table->covering_keys.intersect(field->part_of_key); + /* purecov: end */ } } } From 2525db66fa72538135a0da3225d71f7b854b6d89 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 14 Mar 2007 15:58:14 +0200 Subject: [PATCH 22/34] Bug #26794: fixed valgrind warning --- sql/sql_table.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 38a22c47f12..14b9e0aa25d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3471,8 +3471,7 @@ view_err: checking whether cfield->length < key_part_length (in chars). */ if (!Field::type_can_have_key_part(cfield->field->type()) || - (!Field::type_can_have_key_part(cfield->sql_type) && - !f_is_geom (cfield->pack_flag)) || + !Field::type_can_have_key_part(cfield->sql_type) || (cfield->field->field_length == key_part_length && !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / From 5e2e4161d9b01664e524700ba7a84cc6c308c94d Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 14 Mar 2007 17:07:48 +0200 Subject: [PATCH 23/34] Bug #26794: fixed valgrind warning --- sql/sql_table.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 328830f5db2..1af76ad1086 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5865,8 +5865,7 @@ view_err: checking whether cfield->length < key_part_length (in chars). */ if (!Field::type_can_have_key_part(cfield->field->type()) || - (!Field::type_can_have_key_part(cfield->sql_type) && - !f_is_geom (cfield->pack_flag)) || + !Field::type_can_have_key_part(cfield->sql_type) || /* spatial keys can't have sub-key length */ (key_info->flags & HA_SPATIAL) || (cfield->field->field_length == key_part_length && From fe06c72d3f4b66548b9bd58959fb53e912b56420 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Wed, 14 Mar 2007 18:18:30 +0200 Subject: [PATCH 24/34] merge 5.0->5.1 --- mysql-test/r/alter_table.result | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index f2317961e99..fa18b58a927 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -886,7 +886,7 @@ ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(500) default NULL, + `a` varchar(500) DEFAULT NULL, `b` geometry NOT NULL, SPATIAL KEY `b` (`b`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -894,7 +894,7 @@ ALTER TABLE t1 ADD KEY(b(50)); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(500) default NULL, + `a` varchar(500) DEFAULT NULL, `b` geometry NOT NULL, SPATIAL KEY `b` (`b`), KEY `b_2` (`b`(50)) @@ -903,9 +903,9 @@ ALTER TABLE t1 ADD c POINT; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` varchar(500) default NULL, + `a` varchar(500) DEFAULT NULL, `b` geometry NOT NULL, - `c` point default NULL, + `c` point DEFAULT NULL, SPATIAL KEY `b` (`b`), KEY `b_2` (`b`(50)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 From 6640efd5f34650576f1fe1575e41fb2079c4fd17 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Thu, 15 Mar 2007 17:35:31 +0400 Subject: [PATCH 25/34] merging --- mysql-test/r/gis-rtree.result | 2 +- mysql-test/t/gis-rtree.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index b92601e7b5c..a3955e8c008 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -879,7 +879,7 @@ c1 varchar(15) collate utf8_bin default NULL, c3 varchar(10) collate utf8_bin default NULL, spatial_point point NOT NULL, PRIMARY KEY(id), -SPATIAL KEY (spatial_point(32)) +SPATIAL KEY (spatial_point) )ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES ('y', 's', 'j', GeomFromText('POINT(167 74)')), diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index 348b79be6c2..579ec65f149 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -251,7 +251,7 @@ CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment, c3 varchar(10) collate utf8_bin default NULL, spatial_point point NOT NULL, PRIMARY KEY(id), - SPATIAL KEY (spatial_point(32)) + SPATIAL KEY (spatial_point) )ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; # INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES From 92c8558224f09a91c38197ff2158e011d014be7d Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Thu, 15 Mar 2007 23:21:29 +0300 Subject: [PATCH 26/34] Bug#27033: 0 as LAST_INSERT_ID() after INSERT .. ON DUPLICATE if rows were touched but not actually changed. The LAST_INSERT_ID() is reset to 0 if no rows were inserted or changed. This is the case when an INSERT ... ON DUPLICATE KEY UPDATE updates a row with the same values as the row contains. Now the LAST_INSERT_ID() values is reset to 0 only if there were no rows successfully inserted or touched. The new 'touched' field is added to the COPY_INFO structure. It holds the number of rows that were touched no matter whether they were actually changed or not. --- mysql-test/r/insert_update.result | 11 +++++++++++ mysql-test/t/insert_update.test | 12 ++++++++++++ sql/sql_class.h | 22 +++++++++++++++++----- sql/sql_insert.cc | 16 +++++++++------- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index f658ff06624..b1dee844515 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -236,3 +236,14 @@ INSERT INTO t2 VALUES (1), (3); INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a; ERROR 42S22: Unknown column 'a' in 'field list' DROP TABLE t1,t2; +CREATE TABLE t1 (f1 INT AUTO_INCREMENT PRIMARY KEY, +f2 VARCHAR(5) NOT NULL UNIQUE); +INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1); +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +1 +DROP TABLE t1; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 4581cc7a875..2ef378aa478 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -162,3 +162,15 @@ INSERT INTO t2 VALUES (1), (3); --error ER_BAD_FIELD_ERROR INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a; DROP TABLE t1,t2; + +# +# Bug#27033: 0 as LAST_INSERT_ID() after INSERT .. ON DUPLICATE if rows were +# touched but not actually changed. +# +CREATE TABLE t1 (f1 INT AUTO_INCREMENT PRIMARY KEY, + f2 VARCHAR(5) NOT NULL UNIQUE); +INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1); +SELECT LAST_INSERT_ID(); +INSERT t1 (f2) VALUES ('test') ON DUPLICATE KEY UPDATE f1 = LAST_INSERT_ID(f1); +SELECT LAST_INSERT_ID(); +DROP TABLE t1; diff --git a/sql/sql_class.h b/sql/sql_class.h index 995b5ac0bde..99803802001 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -356,13 +356,25 @@ public: inline uint32 get_open_count() { return open_count; } }; - +/* + The COPY_INFO structure is used by INSERT/REPLACE code. + The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY + UPDATE code: + If a row is inserted then the copied variable is incremented. + If a row is updated by the INSERT ... ON DUPLICATE KEY UPDATE and the + new data differs from the old one then the copied and the updated + variables are incremented. + The touched variable is incremented if a row was touched by the update part + of the INSERT ... ON DUPLICATE KEY UPDATE no matter whether the row + was actually changed or not. +*/ typedef struct st_copy_info { - ha_rows records; - ha_rows deleted; - ha_rows updated; - ha_rows copied; + ha_rows records; /* Number of processed records */ + ha_rows deleted; /* Number of deleted records */ + ha_rows updated; /* Number of updated records */ + ha_rows copied; /* Number of copied records */ ha_rows error_count; + ha_rows touched; /* Number of touched records */ enum enum_duplicates handle_duplicates; int escape_char, last_errno; bool ignore; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a5f6f08973d..629d1e68d4e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -522,7 +522,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* Fill in the given fields and dump it to the table file */ - info.records= info.deleted= info.copied= info.updated= 0; + info.records= info.deleted= info.copied= info.updated= info.touched= 0; info.ignore= ignore; info.handle_duplicates=duplic; info.update_fields= &update_fields; @@ -767,8 +767,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, (!table->triggers || !table->triggers->has_delete_triggers())) table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); - /* Reset value of LAST_INSERT_ID if no rows where inserted */ - if (!info.copied && thd->insert_id_used) + /* Reset value of LAST_INSERT_ID if no rows were inserted or touched */ + if (!info.copied && !info.touched && thd->insert_id_used) { thd->insert_id(0); id=0; @@ -1221,15 +1221,17 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } goto err; } + + if (table->next_number_field) + table->file->adjust_next_insert_id_after_explicit_value( + table->next_number_field->val_int()); + info->touched++; + if ((table->file->table_flags() & HA_PARTIAL_COLUMN_READ) || compare_record(table, thd->query_id)) { info->updated++; - if (table->next_number_field) - table->file->adjust_next_insert_id_after_explicit_value( - table->next_number_field->val_int()); - trg_error= (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, From ec4f730ba77b8459d7af12e52b007f8d7b23af40 Mon Sep 17 00:00:00 2001 From: "gluh@mysql.com/eagle.(none)" <> Date: Fri, 16 Mar 2007 12:15:51 +0400 Subject: [PATCH 27/34] Bug#26285 selecting information_schema crahes server The crash happens when 'skip-grant-tables' is enabled. We skip the filling of I_S privilege tables if acl_cache is not initialized. --- mysql-test/r/skip_grants.result | 12 ++++++++++++ mysql-test/t/skip_grants.test | 8 ++++++++ sql/sql_acl.cc | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/mysql-test/r/skip_grants.result b/mysql-test/r/skip_grants.result index 58ced16acac..3052bae8e97 100644 --- a/mysql-test/r/skip_grants.result +++ b/mysql-test/r/skip_grants.result @@ -58,3 +58,15 @@ DROP PROCEDURE p3; DROP FUNCTION f1; DROP FUNCTION f2; DROP FUNCTION f3; +select count(*) from information_schema.COLUMN_PRIVILEGES; +count(*) +0 +select count(*) from information_schema.SCHEMA_PRIVILEGES; +count(*) +0 +select count(*) from information_schema.TABLE_PRIVILEGES; +count(*) +0 +select count(*) from information_schema.USER_PRIVILEGES; +count(*) +0 diff --git a/mysql-test/t/skip_grants.test b/mysql-test/t/skip_grants.test index 6dda97fcf8a..75694672a17 100644 --- a/mysql-test/t/skip_grants.test +++ b/mysql-test/t/skip_grants.test @@ -108,3 +108,11 @@ DROP PROCEDURE p3; DROP FUNCTION f1; DROP FUNCTION f2; DROP FUNCTION f3; + +# +# Bug#26285 Selecting information_schema crahes server +# +select count(*) from information_schema.COLUMN_PRIVILEGES; +select count(*) from information_schema.SCHEMA_PRIVILEGES; +select count(*) from information_schema.TABLE_PRIVILEGES; +select count(*) from information_schema.USER_PRIVILEGES; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 298fb61d5f0..ee15f95f305 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5882,6 +5882,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_user_privileges"); + if (!initialized) + DBUG_RETURN(0); pthread_mutex_lock(&acl_cache->lock); for (counter=0 ; counter < acl_users.elements ; counter++) @@ -5941,6 +5943,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_schema_privileges"); + if (!initialized) + DBUG_RETURN(0); pthread_mutex_lock(&acl_cache->lock); for (counter=0 ; counter < acl_dbs.elements ; counter++) From 61d93679c3f30cfbd5dbd1c6a32cffc34cd6824a Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@macbook.gmz" <> Date: Fri, 16 Mar 2007 10:35:39 +0200 Subject: [PATCH 28/34] Bug #26261: INSERT uses query_id to verify what fields are mentioned in the fields list of the INSERT command. However the check for that is made after the ON DUPLICATE KEY is processed. This causes all the fields mentioned in ON DUPLICATE KEY to be considered as mentioned in the fields list of INSERT. Moved the check up, right after processing the fields list. --- mysql-test/r/insert_update.result | 11 +++++ mysql-test/t/insert_update.test | 21 ++++++++++ sql/mysql_priv.h | 3 +- sql/sql_insert.cc | 68 ++++++++++++++++++++----------- sql/sql_prepare.cc | 2 +- 5 files changed, 80 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index f658ff06624..2403de5f7a9 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -236,3 +236,14 @@ INSERT INTO t2 VALUES (1), (3); INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a; ERROR 42S22: Unknown column 'a' in 'field list' DROP TABLE t1,t2; +SET SQL_MODE = 'TRADITIONAL'; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL); +INSERT INTO t1 (a) VALUES (1); +ERROR HY000: Field 'b' doesn't have a default value +INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b; +ERROR HY000: Field 'b' doesn't have a default value +INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b; +ERROR HY000: Field 'b' doesn't have a default value +SELECT * FROM t1; +a b +DROP TABLE t1; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 4581cc7a875..3ebcf7d8ff3 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -162,3 +162,24 @@ INSERT INTO t2 VALUES (1), (3); --error ER_BAD_FIELD_ERROR INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a; DROP TABLE t1,t2; + +# +# Bug #26261: Missing default value isn't noticed in +# insert ... on duplicate key update +# +SET SQL_MODE = 'TRADITIONAL'; + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL); + +--error 1364 +INSERT INTO t1 (a) VALUES (1); + +--error 1364 +INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE a = b; + +--error 1364 +INSERT INTO t1 (a) VALUES (1) ON DUPLICATE KEY UPDATE b = b; + +SELECT * FROM t1; + +DROP TABLE t1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f90ea5587fa..e5877e8ed1f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -823,7 +823,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, List &update_values, enum_duplicates duplic, - COND **where, bool select_insert); + COND **where, bool select_insert, + bool check_fields, bool abort_on_warning); bool mysql_insert(THD *thd,TABLE_LIST *table,List &fields, List &values, List &update_fields, List &update_values, enum_duplicates flag, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 332c4c82ba1..dfff70e858e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -451,10 +451,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->proc_info="init"; thd->used_tables=0; values= its++; + value_count= values->elements; if (mysql_prepare_insert(thd, table_list, table, fields, values, update_fields, update_values, duplic, &unused_conds, - FALSE)) + FALSE, + (fields.elements || !value_count), + !ignore && (thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES)))) goto abort; /* mysql_prepare_insert set table_list->table if it was not set */ @@ -480,7 +485,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - value_count= values->elements; while ((values= its++)) { counter++; @@ -551,17 +555,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, table->file->start_bulk_insert(values_list.elements); thd->no_trans_update= 0; - thd->abort_on_warning= (!ignore && - (thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | - MODE_STRICT_ALL_TABLES))); - - if ((fields.elements || !value_count) && - check_that_all_fields_are_given_values(thd, table, table_list)) - { - /* thd->net.report_error is now set, which will abort the next loop */ - error= 1; - } + thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES))); mark_fields_used_by_triggers_for_insert_stmt(thd, table, duplic); @@ -934,6 +930,10 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement + check_fields TRUE if need to check that all INSERT fields are + given values. + abort_on_warning whether to report if some INSERT field is not + assigned as an error (TRUE) or as a warning (FALSE). TODO (in far future) In cases of: @@ -954,7 +954,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, List &fields, List_item *values, List &update_fields, List &update_values, enum_duplicates duplic, - COND **where, bool select_insert) + COND **where, bool select_insert, + bool check_fields, bool abort_on_warning) { SELECT_LEX *select_lex= &thd->lex->select_lex; Name_resolution_context *context= &select_lex->context; @@ -1017,10 +1018,22 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - if (!(res= check_insert_fields(thd, context->table_list, fields, *values, - !insert_into_view, &map) || - setup_fields(thd, 0, *values, 0, 0, 0)) - && duplic == DUP_UPDATE) + res= check_insert_fields(thd, context->table_list, fields, *values, + !insert_into_view, &map) || + setup_fields(thd, 0, *values, 0, 0, 0); + + if (!res && check_fields) + { + bool saved_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= abort_on_warning; + res= check_that_all_fields_are_given_values(thd, + table ? table : + context->table_list->table, + context->table_list); + thd->abort_on_warning= saved_abort_on_warning; + } + + if (!res && duplic == DUP_UPDATE) { select_lex->no_wrap_view_item= TRUE; res= check_update_fields(thd, context->table_list, update_fields, &map); @@ -2295,7 +2308,7 @@ bool mysql_insert_select_prepare(THD *thd) lex->query_tables->table, lex->field_list, 0, lex->update_list, lex->value_list, lex->duplicates, - &select_lex->where, TRUE)) + &select_lex->where, TRUE, FALSE, FALSE)) DBUG_RETURN(TRUE); /* @@ -2357,7 +2370,18 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) !insert_into_view, &map) || setup_fields(thd, 0, values, 0, 0, 0); - if (info.handle_duplicates == DUP_UPDATE) + if (!res && fields->elements) + { + bool saved_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= !info.ignore && (thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES)); + res= check_that_all_fields_are_given_values(thd, table_list->table, + table_list); + thd->abort_on_warning= saved_abort_on_warning; + } + + if (info.handle_duplicates == DUP_UPDATE && !res) { Name_resolution_context *context= &lex->select_lex.context; Name_resolution_context_state ctx_state; @@ -2459,9 +2483,7 @@ select_insert::prepare(List &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - res= ((fields->elements && - check_that_all_fields_are_given_values(thd, table, table_list)) || - table_list->prepare_where(thd, 0, TRUE) || + res= (table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)); if (!res) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ad2b0be4eb8..8e807ca0ada 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1058,7 +1058,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, if (mysql_prepare_insert(thd, table_list, table_list->table, fields, values, update_fields, update_values, - duplic, &unused_conds, FALSE)) + duplic, &unused_conds, FALSE, FALSE, FALSE)) goto error; value_count= values->elements; From e84584e2e34c9c32b132f785909c576cb233f9c3 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Fri, 16 Mar 2007 17:23:26 +0300 Subject: [PATCH 29/34] Bug#27006: AFTER UPDATE triggers not fired with INSERT ... ON DUPLICATE KEY UPDATE if the row wasn't actually changed. This bug was caused by fix for bug#19978. It causes AFTER UPDATE triggers not firing if a row wasn't actually changed by the update part of the INSERT .. ON DUPLICATE KEY UPDATE. Now triggers are always fired if a row is touched by the INSERT ... ON DUPLICATE KEY UPDATE. --- mysql-test/r/trigger.result | 41 +++++++++++++++++++++++++++++++++++++ mysql-test/t/trigger.test | 38 ++++++++++++++++++++++++++++++++++ sql/sql_insert.cc | 12 +++++------ 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index aa511ca27a7..da72973dc52 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1372,4 +1372,45 @@ INSERT INTO bug22580_t1 VALUES (1,1); DROP TABLE bug22580_t1; DROP PROCEDURE bug22580_proc_1; DROP PROCEDURE bug22580_proc_2; +DROP TRIGGER IF EXISTS trg27006_a_update; +DROP TRIGGER IF EXISTS trg27006_a_insert; +CREATE TABLE t1 ( +`id` int(10) unsigned NOT NULL auto_increment, +`val` varchar(10) NOT NULL, +PRIMARY KEY (`id`) +); +CREATE TABLE t2 like t1; +CREATE TRIGGER trg27006_a_insert AFTER INSERT ON t1 FOR EACH ROW +BEGIN +insert into t2 values (NULL,new.val); +END | +CREATE TRIGGER trg27006_a_update AFTER UPDATE ON t1 FOR EACH ROW +BEGIN +insert into t2 values (NULL,new.val); +END | +INSERT INTO t1(val) VALUES ('test1'),('test2'); +SELECT * FROM t1; +id val +1 test1 +2 test2 +SELECT * FROM t2; +id val +1 test1 +2 test2 +INSERT INTO t1 VALUES (2,'test2') ON DUPLICATE KEY UPDATE val=VALUES(val); +INSERT INTO t1 VALUES (3,'test3') ON DUPLICATE KEY UPDATE val=VALUES(val); +SELECT * FROM t1; +id val +1 test1 +2 test2 +3 test3 +SELECT * FROM t2; +id val +1 test1 +2 test2 +3 test2 +4 test3 +DROP TRIGGER trg27006_a_insert; +DROP TRIGGER trg27006_a_update; +drop table t1,t2; End of 5.0 tests diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 5c95004c901..49b7b527bd9 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1699,4 +1699,42 @@ DROP TABLE bug22580_t1; DROP PROCEDURE bug22580_proc_1; DROP PROCEDURE bug22580_proc_2; +# +# Bug#27006: AFTER UPDATE triggers not fired with INSERT ... ON DUPLICATE KEY +# UPDATE if the row wasn't actually changed. +# +--disable_warnings +DROP TRIGGER IF EXISTS trg27006_a_update; +DROP TRIGGER IF EXISTS trg27006_a_insert; +--enable_warnings + +CREATE TABLE t1 ( + `id` int(10) unsigned NOT NULL auto_increment, + `val` varchar(10) NOT NULL, + PRIMARY KEY (`id`) +); +CREATE TABLE t2 like t1; +DELIMITER |; + +CREATE TRIGGER trg27006_a_insert AFTER INSERT ON t1 FOR EACH ROW +BEGIN + insert into t2 values (NULL,new.val); +END | +CREATE TRIGGER trg27006_a_update AFTER UPDATE ON t1 FOR EACH ROW +BEGIN + insert into t2 values (NULL,new.val); +END | +DELIMITER ;| + +INSERT INTO t1(val) VALUES ('test1'),('test2'); +SELECT * FROM t1; +SELECT * FROM t2; +INSERT INTO t1 VALUES (2,'test2') ON DUPLICATE KEY UPDATE val=VALUES(val); +INSERT INTO t1 VALUES (3,'test3') ON DUPLICATE KEY UPDATE val=VALUES(val); +SELECT * FROM t1; +SELECT * FROM t2; +DROP TRIGGER trg27006_a_insert; +DROP TRIGGER trg27006_a_update; +drop table t1,t2; + --echo End of 5.0 tests diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 35e724beec8..dd08ccef462 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1238,19 +1238,19 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (table->next_number_field) table->file->adjust_next_insert_id_after_explicit_value( table->next_number_field->val_int()); - info->touched++; + info->touched++; if ((table->file->table_flags() & HA_PARTIAL_COLUMN_READ) || compare_record(table, thd->query_id)) { info->updated++; - - trg_error= (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, - TRUE)); info->copied++; } + + trg_error= (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, + TRG_ACTION_AFTER, + TRUE)); goto ok_or_after_trg_err; } else /* DUP_REPLACE */ From 5233a2a52a50a9e153a6f4174b5a5526b18f78e7 Mon Sep 17 00:00:00 2001 From: "holyfoot/hf@mysql.com/hfmain.(none)" <> Date: Fri, 16 Mar 2007 22:23:37 +0400 Subject: [PATCH 30/34] merging --- sql/sql_insert.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a9652fe9717..06a1ebdc89b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1039,7 +1039,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, res= check_insert_fields(thd, context->table_list, fields, *values, !insert_into_view, &map) || - setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) + setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0); if (!res && check_fields) { From 11fbf30e7545adb8434ba2fa5322a33597f5617c Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Fri, 16 Mar 2007 19:44:00 +0100 Subject: [PATCH 31/34] remove unnecessary line --- unittest/mysys/my_atomic-t.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c index c4ba7850ae1..8280aff5422 100644 --- a/unittest/mysys/my_atomic-t.c +++ b/unittest/mysys/my_atomic-t.c @@ -182,9 +182,6 @@ int main() test_atomic("my_atomic_add32", test_atomic_add_handler, THREADS, CYCLES); test_atomic("my_atomic_swap32", test_atomic_swap_handler, THREADS, CYCLES); test_atomic("my_atomic_cas32", test_atomic_cas_handler, THREADS, CYCLES); - - /* workaround until we know why this includes dbug but not safemalloc */ - if(err) { my_thread_global_init(); my_free(my_malloc(0, MYF(0)), MYF(0)); } /* workaround until we know why it crashes randomly on some machine (BUG#22320). From cb89159eb13c9565b588b51c81d5e72d2208bc87 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Fri, 16 Mar 2007 23:10:12 +0300 Subject: [PATCH 32/34] sql_insert.cc: Post-merge fix. --- sql/sql_insert.cc | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 06a1ebdc89b..52f3fd507e4 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1262,21 +1262,22 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) compare_record(table)) { info->updated++; - /* - If ON DUP KEY UPDATE updates a row instead of inserting one, it's - like a regular UPDATE statement: it should not affect the value of a - next SELECT LAST_INSERT_ID() or mysql_insert_id(). - Except if LAST_INSERT_ID(#) was in the INSERT query, which is - handled separately by THD::arg_of_last_insert_id_function. - */ - insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; - if (table->next_number_field) - table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int()); - trg_error= (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, TRUE)); info->copied++; } + /* + If ON DUP KEY UPDATE updates a row instead of inserting one, it's + like a regular UPDATE statement: it should not affect the value of a + next SELECT LAST_INSERT_ID() or mysql_insert_id(). + Except if LAST_INSERT_ID(#) was in the INSERT query, which is + handled separately by THD::arg_of_last_insert_id_function. + */ + insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0; + if (table->next_number_field) + table->file->adjust_next_insert_id_after_explicit_value( + table->next_number_field->val_int()); + trg_error= (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, + TRG_ACTION_AFTER, TRUE)); goto ok_or_after_trg_err; } else /* DUP_REPLACE */ From 68fd66e853cd94fcb76aba6b95a592bb39e2b8f7 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Sat, 17 Mar 2007 00:13:25 +0100 Subject: [PATCH 33/34] wl#3700 - post-review fixes: s/ulonglong/key_part_map/, comments --- include/heap.h | 4 +- include/my_base.h | 7 ++- include/myisam.h | 2 +- include/myisammrg.h | 2 +- sql/event_db_repository.cc | 4 +- sql/ha_partition.cc | 6 +-- sql/ha_partition.h | 9 ++-- sql/handler.cc | 4 +- sql/handler.h | 29 ++++++++--- sql/item_subselect.cc | 4 +- sql/log_event.cc | 6 +-- sql/mysql_priv.h | 1 - sql/opt_range.cc | 70 +++++++++++---------------- sql/opt_range.h | 29 ++++++----- sql/sp.cc | 4 +- sql/sql_acl.cc | 20 ++++---- sql/sql_handler.cc | 2 +- sql/sql_help.cc | 4 +- sql/sql_insert.cc | 2 +- sql/sql_plugin.cc | 2 +- sql/sql_select.cc | 13 +++-- sql/sql_select.h | 7 +-- sql/sql_servers.cc | 6 +-- sql/sql_udf.cc | 4 +- sql/table.cc | 2 +- sql/table.h | 6 +-- sql/tztime.cc | 8 +-- storage/blackhole/ha_blackhole.cc | 6 +-- storage/blackhole/ha_blackhole.h | 9 ++-- storage/example/ha_example.cc | 2 +- storage/example/ha_example.h | 2 +- storage/heap/ha_heap.cc | 6 +-- storage/heap/ha_heap.h | 6 +-- storage/heap/heapdef.h | 6 +-- storage/heap/hp_hash.c | 14 +++--- storage/heap/hp_rkey.c | 2 +- storage/innobase/handler/ha_innodb.cc | 16 +++--- storage/myisam/ha_myisam.cc | 6 +-- storage/myisam/ha_myisam.h | 6 +-- storage/myisam/mi_check.c | 2 +- storage/myisam/mi_key.c | 4 +- storage/myisam/mi_range.c | 8 +-- storage/myisam/mi_rkey.c | 2 +- storage/myisam/myisamdef.h | 2 +- storage/myisammrg/ha_myisammrg.cc | 6 +-- storage/myisammrg/ha_myisammrg.h | 6 +-- storage/myisammrg/myrg_rkey.c | 2 +- 47 files changed, 187 insertions(+), 183 deletions(-) diff --git a/include/heap.h b/include/heap.h index 33bbd2f0b3f..6cacb7fc529 100644 --- a/include/heap.h +++ b/include/heap.h @@ -225,8 +225,8 @@ extern void heap_update_auto_increment(HP_INFO *info, const byte *record); ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key, key_range *max_key); int hp_panic(enum ha_panic_function flag); -int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, - ulonglong keypart_map, enum ha_rkey_function find_flag); +int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, + key_part_map keypart_map, enum ha_rkey_function find_flag); extern gptr heap_find(HP_INFO *info,int inx,const byte *key); extern int heap_check_heap(HP_INFO *info, my_bool print_status); extern byte *heap_position(HP_INFO *info); diff --git a/include/my_base.h b/include/my_base.h index 3aa280d825a..dd21362e8f7 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -395,7 +395,10 @@ enum ha_base_keytype { /* Other constants */ #define HA_NAMELEN 64 /* Max length of saved filename */ -#define NO_SUCH_KEY ((uint)~0) /* used as a key no. */ +#define NO_SUCH_KEY (~(uint)0) /* used as a key no. */ + +typedef ulong key_part_map; +#define HA_WHOLE_KEY (~(key_part_map)0) /* Intern constants in databases */ @@ -469,7 +472,7 @@ typedef struct st_key_range { const byte *key; uint length; - ulonglong keypart_map; + key_part_map keypart_map; enum ha_rkey_function flag; } key_range; diff --git a/include/myisam.h b/include/myisam.h index 1dd8f6f7ec4..b05440e5ae4 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -275,7 +275,7 @@ extern struct st_myisam_info *mi_open(const char *name,int mode, extern int mi_panic(enum ha_panic_function function); extern int mi_rfirst(struct st_myisam_info *file,byte *buf,int inx); extern int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, - ulonglong keypart_map, enum ha_rkey_function search_flag); + key_part_map keypart_map, enum ha_rkey_function search_flag); extern int mi_rlast(struct st_myisam_info *file,byte *buf,int inx); extern int mi_rnext(struct st_myisam_info *file,byte *buf,int inx); extern int mi_rnext_same(struct st_myisam_info *info, byte *buf); diff --git a/include/myisammrg.h b/include/myisammrg.h index 149b72dc7e1..02e81cf806d 100644 --- a/include/myisammrg.h +++ b/include/myisammrg.h @@ -87,7 +87,7 @@ extern int myrg_rnext(MYRG_INFO *file,byte *buf,int inx); extern int myrg_rprev(MYRG_INFO *file,byte *buf,int inx); extern int myrg_rnext_same(MYRG_INFO *file,byte *buf); extern int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, - ulonglong keypart_map, enum ha_rkey_function search_flag); + key_part_map keypart_map, enum ha_rkey_function search_flag); extern int myrg_rrnd(MYRG_INFO *file,byte *buf,ulonglong pos); extern int myrg_rsame(MYRG_INFO *file,byte *record,int inx); extern int myrg_update(MYRG_INFO *file,const byte *old,byte *new_rec); diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 860cb54e27f..c5d015cdea7 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -288,7 +288,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, { key_copy(key_buf, event_table->record[0], key_info, key_len); if (!(ret= event_table->file->index_read(event_table->record[0], key_buf, - (ulonglong)1, HA_READ_PREFIX))) + (key_part_map)1, HA_READ_PREFIX))) { DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret)); do @@ -843,7 +843,7 @@ Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name, key_copy(key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, key, ~ULL(0), + if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { DBUG_PRINT("info", ("Row not found")); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 4ed602be54d..d3979fa0718 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3336,7 +3336,7 @@ int ha_partition::index_end() */ int ha_partition::index_read(byte * buf, const byte * key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag) { DBUG_ENTER("ha_partition::index_read"); @@ -3357,7 +3357,7 @@ int ha_partition::index_read(byte * buf, const byte * key, */ int ha_partition::common_index_read(byte *buf, const byte *key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag) { int error; @@ -3513,7 +3513,7 @@ int ha_partition::common_first_last(byte *buf) */ int ha_partition::index_read_last(byte *buf, const byte *key, - ulonglong keypart_map) + key_part_map keypart_map) { DBUG_ENTER("ha_partition::index_read_last"); diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 2d43e2b0df2..a081e4bb472 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -384,8 +384,8 @@ public: any end processing needed. */ virtual int index_read(byte * buf, const byte * key, - ulonglong keypart_map, - enum ha_rkey_function find_flag); + key_part_map keypart_map, + enum ha_rkey_function find_flag); virtual int index_init(uint idx, bool sorted); virtual int index_end(); @@ -399,7 +399,7 @@ public: virtual int index_last(byte * buf); virtual int index_next_same(byte * buf, const byte * key, uint keylen); virtual int index_read_last(byte * buf, const byte * key, - ulonglong keypart_map); + key_part_map keypart_map); /* read_first_row is virtual method but is only implemented by @@ -425,7 +425,8 @@ public: private: int common_index_read(byte * buf, const byte * key, - ulonglong keypart_map, enum ha_rkey_function find_flag); + key_part_map keypart_map, + enum ha_rkey_function find_flag); int common_first_last(byte * buf); int partition_scan_set_up(byte * buf, bool idx_read_flag); int handle_unordered_next(byte * buf, bool next_same); diff --git a/sql/handler.cc b/sql/handler.cc index 7d3edf36162..6df8a4a5021 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3282,8 +3282,8 @@ int handler::compare_key(key_range *range) int handler::index_read_idx(byte * buf, uint index, const byte * key, - ulonglong keypart_map, - enum ha_rkey_function find_flag) + key_part_map keypart_map, + enum ha_rkey_function find_flag) { int error, error1; error= index_init(index, 0); diff --git a/sql/handler.h b/sql/handler.h index 1d02d6a7ee3..0158cbad515 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -867,17 +867,17 @@ public: {} }; -uint calculate_key_len(TABLE *, uint, const byte *, ulonglong); +uint calculate_key_len(TABLE *, uint, const byte *, key_part_map); /* bitmap with first N+1 bits set (keypart_map for a key prefix of [0..N] keyparts) */ -#define make_keypart_map(N) (((ulonglong)2 << (N)) - 1) +#define make_keypart_map(N) (((key_part_map)2 << (N)) - 1) /* bitmap with first N bits set (keypart_map for a key prefix of [0..N-1] keyparts) */ -#define make_prev_keypart_map(N) (((ulonglong)1 << (N)) - 1) +#define make_prev_keypart_map(N) (((key_part_map)1 << (N)) - 1) /* The handler class is the interface for dynamically loadable @@ -1219,14 +1219,26 @@ public: enum ha_rkey_function find_flag) { return HA_ERR_WRONG_COMMAND; } public: - virtual int index_read(byte * buf, const byte * key, ulonglong keypart_map, +/** + @brief + Positions an index cursor to the index specified in the handle. Fetches the + row if available. If the key value is null, begin at the first key of the + index. +*/ + virtual int index_read(byte * buf, const byte * key, key_part_map keypart_map, enum ha_rkey_function find_flag) { uint key_len= calculate_key_len(table, active_index, key, keypart_map); return index_read(buf, key, key_len, find_flag); } +/** + @brief + Positions an index cursor to the index specified in the handle. Fetches the + row if available. If the key value is null, begin at the first key of the + index. +*/ virtual int index_read_idx(byte * buf, uint index, const byte * key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag); virtual int index_next(byte * buf) { return HA_ERR_WRONG_COMMAND; } @@ -1241,8 +1253,13 @@ public: virtual int index_read_last(byte * buf, const byte * key, uint key_len) { return (my_errno=HA_ERR_WRONG_COMMAND); } public: +/** + @brief + The following functions works like index_read, but it find the last + row with the current key value or prefix. +*/ virtual int index_read_last(byte * buf, const byte * key, - ulonglong keypart_map) + key_part_map keypart_map) { uint key_len= calculate_key_len(table, active_index, key, keypart_map); return index_read_last(buf, key, key_len); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d9141cc0740..e1abda2f612 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2045,7 +2045,7 @@ int subselect_uniquesubquery_engine::exec() table->file->ha_index_init(tab->ref.key, 0); error= table->file->index_read(table->record[0], tab->ref.key_buff, - tab_to_keypart_map(tab), + make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) @@ -2155,7 +2155,7 @@ int subselect_indexsubquery_engine::exec() table->file->ha_index_init(tab->ref.key, 1); error= table->file->index_read(table->record[0], tab->ref.key_buff, - tab_to_keypart_map(tab), + make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5ff23a49252..0448aacd4f3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6855,7 +6855,7 @@ replace_record(THD *thd, TABLE *table, key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0); error= table->file->index_read_idx(table->record[1], keynum, - (const byte*)key.get(), ~ULL(0), + (const byte*)key.get(), HA_WHOLE_KEY, HA_READ_KEY_EXACT); if (error) DBUG_RETURN(error); @@ -7039,8 +7039,8 @@ static int find_and_fetch_row(TABLE *table, byte *key) my_ptrdiff_t const pos= table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0; table->record[1][pos]= 0xFF; - if ((error= table->file->index_read(table->record[1], key, - ~(ulonglong)0, HA_READ_KEY_EXACT))) + if ((error= table->file->index_read(table->record[1], key, HA_WHOLE_KEY, + HA_READ_KEY_EXACT))) { table->file->print_error(error, MYF(0)); table->file->ha_index_end(); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1852e74a333..099c9b98c1f 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -47,7 +47,6 @@ typedef Bitmap<64> key_map; /* Used for finding keys */ #else typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */ #endif -typedef ulong key_part_map; /* Used for finding key parts */ typedef ulong nesting_map; /* Used for flags of nesting constructs */ /* Used to identify NESTED_JOIN structures within a join (applicable only to diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d95eb1c3553..52faaf25b42 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -312,6 +312,7 @@ public: min_value=arg->max_value; min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN; } + /* returns a number of keypart values (0 or 1) appended to the key buffer */ int store_min(uint length,char **min_key,uint min_key_flag) { if ((min_flag & GEOM_FLAG) || @@ -330,6 +331,7 @@ public: } return 0; } + /* returns a number of keypart values (0 or 1) appended to the key buffer */ int store_max(uint length,char **max_key, uint max_key_flag) { if (!(max_flag & NO_MAX_RANGE) && @@ -347,13 +349,8 @@ public: } return 0; } - /*void store(uint length,char **min_key,uint min_key_flag, - char **max_key, uint max_key_flag) - { - store_min(length, min_key, min_key_flag); - store_max(length, max_key, max_key_flag); - }*/ + /* returns a number of keypart values appended to the key buffer */ int store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag) { SEL_ARG *key_tree= first(); @@ -369,6 +366,7 @@ public: return res; } + /* returns a number of keypart values appended to the key buffer */ int store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag) { SEL_ARG *key_tree= last(); @@ -595,7 +593,7 @@ static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field, static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond); static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts); -static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree, +static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree, bool update_tbl_stats); static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree, char *min_key, uint min_key_flag, int, @@ -4075,7 +4073,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, byte key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */ char *key_ptr= (char*) key_val; SEL_ARG *sel_arg, *tuple_arg= NULL; - ulonglong keypart_map= 0; + key_part_map keypart_map= 0; bool cur_covered; bool prev_covered= test(bitmap_is_set(&info->covered_fields, key_part->fieldnr-1)); @@ -7457,7 +7455,8 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { QUICK_RANGE *range; uint flag; - int min_part= key_tree->part-1, max_part=key_tree->part-1; + int min_part= key_tree->part-1, // # of keypart values in min_key buffer + max_part= key_tree->part-1; // # of keypart values in max_key buffer if (key_tree->left != &null_element) { @@ -7488,15 +7487,11 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) - { min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, &tmp_min_flag); - } if (!tmp_max_flag) - { max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, &tmp_max_flag); - } flag=tmp_min_flag | tmp_max_flag; } } @@ -7652,13 +7647,13 @@ bool QUICK_ROR_UNION_SELECT::is_keys_used(const MY_BITMAP *fields) thd Thread handle table Table to access ref ref[_or_null] scan parameters - records Estimate of number of records (needed only to construct + records Estimate of number of records (needed only to construct quick select) NOTES This allocates things in a new memory root, as this may be called many times during a query. - - RETURN + + RETURN Quick select that retrieves the same rows as passed ref scan NULL on error. */ @@ -7694,9 +7689,10 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, !(range= new(alloc) QUICK_RANGE())) goto err; // out of memory - range->min_key=range->max_key=(char*) ref->key_buff; - range->min_length=range->max_length=ref->key_length; - range->min_keypart_map= range->max_keypart_map= (1 << ref->key_parts) - 1; + range->min_key= range->max_key= (char*) ref->key_buff; + range->min_length= range->max_length= ref->key_length; + range->min_keypart_map= range->max_keypart_map= + make_prev_keypart_map(ref->key_parts); range->flag= ((ref->key_length == key_info->key_length && (key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME) ? EQ_RANGE : 0); @@ -7709,7 +7705,7 @@ 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->length= key_info->key_part[part].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; key_part->flag= (uint8) key_info->key_part[part].key_part_flag; @@ -7728,13 +7724,11 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, QUICK_RANGE *null_range; *ref->null_ref_key= 1; // Set null byte then create a range - if (!(null_range= new (alloc) QUICK_RANGE((char*)ref->key_buff, - ref->key_length, - (1 << ref->key_parts) - 1, - (char*)ref->key_buff, - ref->key_length, - (1 << ref->key_parts) - 1, - EQ_RANGE))) + if (!(null_range= new (alloc) + QUICK_RANGE((char*)ref->key_buff, ref->key_length, + make_prev_keypart_map(ref->key_parts), + (char*)ref->key_buff, ref->key_length, + make_prev_keypart_map(ref->key_parts), EQ_RANGE))) goto err; *ref->null_ref_key= 0; // Clear null byte if (insert_dynamic(&quick->ranges,(gptr)&null_range)) @@ -8246,7 +8240,7 @@ end: */ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, - ulonglong keypart_map, + key_part_map keypart_map, byte *cur_prefix) { DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix"); @@ -10502,7 +10496,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() { byte *cur_prefix= seen_first_key ? group_prefix : NULL; if ((result= quick_prefix_select->get_next_prefix(group_prefix_len, - (ULL(1) << group_key_parts) - 1, cur_prefix))) + make_prev_keypart_map(group_key_parts), cur_prefix))) DBUG_RETURN(result); seen_first_key= TRUE; } @@ -10561,8 +10555,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix() int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() { ha_rkey_function find_flag; - uint search_prefix_len; - ulonglong keypart_map; + key_part_map keypart_map; QUICK_RANGE *cur_range; bool found_null= FALSE; int result= HA_ERR_KEY_NOT_FOUND; @@ -10584,8 +10577,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() if (cur_range->flag & NO_MIN_RANGE) { - search_prefix_len= real_prefix_len; - keypart_map= (ULL(1) << real_key_parts) - 1; + keypart_map= make_prev_keypart_map(real_key_parts); find_flag= HA_READ_KEY_EXACT; } else @@ -10593,8 +10585,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() /* Extend the search key with the lower boundary for this range. */ memcpy(group_prefix + real_prefix_len, cur_range->min_key, cur_range->min_length); - search_prefix_len= real_prefix_len + min_max_arg_len; - keypart_map= (ULL(2) << real_key_parts) - 1; + keypart_map= make_keypart_map(real_key_parts); find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ? HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT; @@ -10697,8 +10688,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range() int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() { ha_rkey_function find_flag; - uint search_prefix_len; - ulonglong keypart_map; + key_part_map keypart_map; QUICK_RANGE *cur_range; int result; @@ -10720,8 +10710,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() if (cur_range->flag & NO_MAX_RANGE) { - search_prefix_len= real_prefix_len; - keypart_map= (ULL(1) << real_key_parts) - 1; + keypart_map= make_prev_keypart_map(real_key_parts); find_flag= HA_READ_PREFIX_LAST; } else @@ -10729,8 +10718,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() /* Extend the search key with the upper boundary for this range. */ memcpy(group_prefix + real_prefix_len, cur_range->max_key, cur_range->max_length); - search_prefix_len= real_prefix_len + min_max_arg_len; - keypart_map= (ULL(2) << real_key_parts) - 1; + keypart_map= make_keypart_map(real_key_parts); find_flag= (cur_range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ? HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV; diff --git a/sql/opt_range.h b/sql/opt_range.h index ce98b4609d1..1ad9567cddd 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -37,15 +37,16 @@ class QUICK_RANGE :public Sql_alloc { public: char *min_key,*max_key; uint16 min_length,max_length,flag; - ulonglong min_keypart_map, max_keypart_map; + key_part_map min_keypart_map, // bitmap of used keyparts in min_key + max_keypart_map; // bitmap of used keyparts in max_key #ifdef HAVE_purify uint16 dummy; /* Avoid warnings on 'flag' */ #endif QUICK_RANGE(); /* Full range */ QUICK_RANGE(const char *min_key_arg, uint min_length_arg, - ulonglong min_keypart_map_arg, + key_part_map min_keypart_map_arg, const char *max_key_arg, uint max_length_arg, - ulonglong max_keypart_map_arg, + key_part_map max_keypart_map_arg, uint flag_arg) : min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)), max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)), @@ -65,11 +66,11 @@ class QUICK_RANGE :public Sql_alloc { /* Quick select interface. This class is a parent for all QUICK_*_SELECT and FT_SELECT classes. - + The usage scenario is as follows: 1. Create quick select quick= new QUICK_XXX_SELECT(...); - + 2. Perform lightweight initialization. This can be done in 2 ways: 2.a: Regular initialization if (quick->init()) @@ -80,29 +81,29 @@ class QUICK_RANGE :public Sql_alloc { 2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT if (quick->init_ror_merged_scan()) delete quick; - + 3. Perform zero, one, or more scans. while (...) { // initialize quick select for scan. This may allocate - // buffers and/or prefetch rows. + // buffers and/or prefetch rows. if (quick->reset()) { //the only valid action after failed reset() call is delete delete quick; //abort query } - + // perform the scan do { res= quick->get_next(); } while (res && ...) } - + 4. Delete the select: delete quick; - + */ class QUICK_SELECT_I @@ -128,6 +129,8 @@ public: Max. number of (first) key parts this quick select uses for retrieval. eg. for "(key1p1=c1 AND key1p2=c2) OR key1p1=c2" used_key_parts == 2. Applicable if index!= MAX_KEY. + + For QUICK_GROUP_MIN_MAX_SELECT it includes MIN/MAX argument keyparts. */ uint used_key_parts; @@ -323,7 +326,7 @@ public: int reset(void); int get_next(); void range_end(); - int get_next_prefix(uint prefix_length, ulonglong keypart_map, + int get_next_prefix(uint prefix_length, key_part_map keypart_map, byte *cur_prefix); bool reverse_sorted() { return 0; } bool unique_key_range(); @@ -611,7 +614,7 @@ private: byte *tmp_record; /* Temporary storage for next_min(), next_max(). */ byte *group_prefix; /* Key prefix consisting of the GROUP fields. */ uint group_prefix_len; /* Length of the group prefix. */ - uint group_key_parts; + uint group_key_parts; /* A number of keyparts in the group prefix */ byte *last_prefix; /* Prefix of the last group for detecting EOF. */ bool have_min; /* Specify whether we are computing */ bool have_max; /* a MIN, a MAX, or both. */ @@ -623,7 +626,7 @@ private: uint key_infix_len; DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */ uint real_prefix_len; /* Length of key prefix extended with key_infix. */ - uint real_key_parts; + uint real_key_parts; /* A number of keyparts in the above value. */ List *min_functions; List *max_functions; List_iterator *min_functions_it; diff --git a/sql/sp.cc b/sql/sp.cc index 27b3b2532c3..eef5dc01912 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -218,7 +218,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) key_copy(key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, key, ~ULL(0), + if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) DBUG_RETURN(SP_KEY_NOT_FOUND); @@ -924,7 +924,7 @@ sp_drop_db_routines(THD *thd, char *db) table->file->ha_index_init(0, 1); if (! table->file->index_read(table->record[0], (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr, - (ulonglong)1, HA_READ_KEY_EXACT)) + (key_part_map)1, HA_READ_KEY_EXACT)) { int nxtres; bool deleted= FALSE; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 2b642689281..aaa88071173 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1813,7 +1813,7 @@ static bool update_user_table(THD *thd, TABLE *table, table->key_info->key_length); if (table->file->index_read_idx(table->record[0], 0, - (byte *) user_key, ~ULL(0), + (byte *) user_key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), @@ -1904,7 +1904,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, user_key, ~ULL(0), + if (table->file->index_read_idx(table->record[0], 0, user_key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { /* what == 'N' means revoke */ @@ -2121,7 +2121,7 @@ static int replace_db_table(TABLE *table, const char *db, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0],0, user_key, ~ULL(0), + if (table->file->index_read_idx(table->record[0],0, user_key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { if (what == 'N') @@ -2339,7 +2339,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) col_privs->file->ha_index_init(0, 1); if (col_privs->file->index_read(col_privs->record[0], (byte*) key, - (ulonglong)15, HA_READ_KEY_EXACT)) + (key_part_map)15, HA_READ_KEY_EXACT)) { cols = 0; /* purecov: deadcode */ col_privs->file->ha_index_end(); @@ -2501,7 +2501,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read(table->record[0], user_key, ~(ulonglong)0, + if (table->file->index_read(table->record[0], user_key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { if (revoke_grant) @@ -2577,7 +2577,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, key_prefix_length); - if (table->file->index_read(table->record[0], user_key, (ulonglong)15, + if (table->file->index_read(table->record[0], user_key, (key_part_map)15, HA_READ_KEY_EXACT)) goto end; @@ -2678,7 +2678,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, user_key, ~ULL(0), + if (table->file->index_read_idx(table->record[0], 0, user_key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { /* @@ -2796,13 +2796,13 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); table->field[3]->store(routine_name,(uint) strlen(routine_name), &my_charset_latin1); - table->field[4]->store((longlong)(is_proc ? + table->field[4]->store((longlong)(is_proc ? TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION), TRUE); store_record(table,record[1]); // store at pos 1 if (table->file->index_read_idx(table->record[0], 0, - (byte*) table->field[0]->ptr, ~ULL(0), + (byte*) table->field[0]->ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { /* @@ -5001,7 +5001,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop, key_copy(user_key, table->record[0], table->key_info, key_prefix_length); if ((error= table->file->index_read_idx(table->record[0], 0, - user_key, ULL(3), + user_key, (key_part_map)3, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 9c6c98cb151..cd87330cedb 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -515,7 +515,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } List_iterator it_ke(*key_expr); Item *item; - ulonglong keypart_map; + key_part_map keypart_map; for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++) { my_bitmap_map *old_map; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index aacfd8f8245..b677111c019 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -295,7 +295,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, rkey_id->store((longlong) key_id, TRUE); rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW); int key_res= relations->file->index_read(relations->record[0], - (byte *) buff, (ulonglong)1, + (byte *) buff, (key_part_map)1, HA_READ_KEY_EXACT); for ( ; @@ -309,7 +309,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW); if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff, - (ulonglong)1, HA_READ_KEY_EXACT)) + (key_part_map)1, HA_READ_KEY_EXACT)) { memorize_variant_topic(thd,topics,count,find_fields, names,name,description,example); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 62c4e32409b..e973180eef7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1214,7 +1214,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } key_copy((byte*) key,table->record[0],table->key_info+key_nr,0); if ((error=(table->file->index_read_idx(table->record[1],key_nr, - (byte*) key, ~ULL(0), + (byte*) key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)))) goto err; } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index d7ced748394..70bc9ef23d5 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -943,7 +943,7 @@ my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) table->use_all_columns(); table->field[0]->store(name->str, name->length, system_charset_info); if (! table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, ~ULL(0), + (byte *)table->field[0]->ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { int error; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8661503df8e..8184b2a732e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10980,7 +10980,7 @@ int safe_index_read(JOIN_TAB *tab) TABLE *table= tab->table; if ((error=table->file->index_read(table->record[0], tab->ref.key_buff, - tab_to_keypart_map(tab), + make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT))) return report_error(table, error); return 0; @@ -11119,7 +11119,7 @@ join_read_const(JOIN_TAB *tab) { error=table->file->index_read_idx(table->record[0],tab->ref.key, (byte*) tab->ref.key_buff, - tab_to_keypart_map(tab), + make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); } if (error) @@ -11163,7 +11163,7 @@ join_read_key(JOIN_TAB *tab) } error=table->file->index_read(table->record[0], tab->ref.key_buff, - tab_to_keypart_map(tab), + make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); @@ -11192,7 +11192,7 @@ join_read_always_key(JOIN_TAB *tab) return -1; if ((error=table->file->index_read(table->record[0], tab->ref.key_buff, - tab_to_keypart_map(tab), + make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) @@ -11219,8 +11219,7 @@ join_read_last_key(JOIN_TAB *tab) if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref)) return -1; if ((error=table->file->index_read_last(table->record[0], - tab->ref.key_buff, - tab_to_keypart_map(tab)))) + tab->ref.key_buff, make_prev_keypart_map(tab->ref.key_parts)))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); @@ -11761,7 +11760,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), group->buff[-1]= (char) group->field->is_null(); } if (!table->file->index_read(table->record[1], - join->tmp_table_param.group_buff, ~(ulonglong)0, + join->tmp_table_param.group_buff, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { /* Update old record */ restore_record(table,record[1]); diff --git a/sql/sql_select.h b/sql/sql_select.h index e31fe143573..ca93179f9d9 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -192,7 +192,7 @@ typedef struct st_join_table { JOIN *join; /* Bitmap of nested joins this table is part of */ nested_join_map embedding_map; - + void cleanup(); inline bool is_using_loose_index_scan() { @@ -202,11 +202,6 @@ typedef struct st_join_table { } } JOIN_TAB; -static inline ulonglong tab_to_keypart_map(JOIN_TAB *tab) -{ - return (ULL(1) << tab->ref.key_parts) - 1; -} - enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 1d7c8d5272d..7b3b71cdd9a 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -354,7 +354,7 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options) system_charset_info); if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, ~(ulonglong)0, + (byte *)table->field[0]->ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) @@ -554,7 +554,7 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) /* read index until record is that specified in server_name */ if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, ~(longlong)0, + (byte *)table->field[0]->ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT))) { /* if not found, err */ @@ -926,7 +926,7 @@ int delete_server_record(TABLE *table, table->field[0]->store(server_name, server_name_length, system_charset_info); if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, ~(ulonglong)0, + (byte *)table->field[0]->ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index b0e7831465a..4c584bff72a 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -514,7 +514,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) table->use_all_columns(); table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); if (!table->file->index_read_idx(table->record[0], 0, - (byte*) table->field[0]->ptr, ~ULL(0), + (byte*) table->field[0]->ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { int error; @@ -523,7 +523,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) } close_thread_tables(thd); - rw_unlock(&THR_LOCK_udf); + rw_unlock(&THR_LOCK_udf); DBUG_RETURN(0); err: rw_unlock(&THR_LOCK_udf); diff --git a/sql/table.cc b/sql/table.cc index e4b3be5dbe0..f2bf25e6a75 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2250,7 +2250,7 @@ char *get_field(MEM_ROOT *mem, Field *field) that are present in this value, returns the length of the value */ uint calculate_key_len(TABLE *table, uint key, const byte *buf, - ulonglong keypart_map) + key_part_map keypart_map) { /* works only with key prefixes */ DBUG_ASSERT(((keypart_map + 1) & keypart_map) == 0); diff --git a/sql/table.h b/sql/table.h index d15929e8cba..aa053f207b3 100644 --- a/sql/table.h +++ b/sql/table.h @@ -197,9 +197,9 @@ typedef struct st_table_share uint rowid_field_offset; /* Field_nr +1 to rowid field */ /* Index of auto-updated TIMESTAMP field in field array */ uint primary_key; - uint next_number_index; - uint next_number_key_offset; - uint next_number_keypart; + uint next_number_index; /* autoincrement key number */ + uint next_number_key_offset; /* autoinc keypart offset in a key */ + uint next_number_keypart; /* autoinc keypart number in a key */ uint error, open_errno, errarg; /* error from open_table_def() */ uint column_bitmap_size; uchar frm_version; diff --git a/sql/tztime.cc b/sql/tztime.cc index b9f757faeb8..18161022dc3 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1917,7 +1917,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) (void)table->file->ha_index_init(0, 1); if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - ~(ulonglong)0, HA_READ_KEY_EXACT)) + HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { #ifdef EXTRA_DEBUG /* @@ -1945,7 +1945,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) (void)table->file->ha_index_init(0, 1); if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - ~(ulonglong)0, HA_READ_KEY_EXACT)) + HA_WHOLE_KEY, HA_READ_KEY_EXACT)) { sql_print_error("Can't find description of time zone '%u'", tzid); goto end; @@ -1973,7 +1973,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) (void)table->file->ha_index_init(0, 1); res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - (ulonglong)1, HA_READ_KEY_EXACT); + (key_part_map)1, HA_READ_KEY_EXACT); while (!res) { ttid= (uint)table->field[1]->val_int(); @@ -2045,7 +2045,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) (void)table->file->ha_index_init(0, 1); res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr, - (ulonglong)1, HA_READ_KEY_EXACT); + (key_part_map)1, HA_READ_KEY_EXACT); while (!res) { ttime= (my_time_t)table->field[1]->val_int(); diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index d7e56f91af4..6f07c4183f1 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -152,7 +152,7 @@ THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd, int ha_blackhole::index_read(byte * buf, const byte * key, - ulonglong keypart_map, uint key_len, + key_part_map keypart_map, enum ha_rkey_function find_flag) { DBUG_ENTER("ha_blackhole::index_read"); @@ -161,7 +161,7 @@ int ha_blackhole::index_read(byte * buf, const byte * key, int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key, - ulonglong keypart_map, uint key_len, + key_part_map keypart_map, enum ha_rkey_function find_flag) { DBUG_ENTER("ha_blackhole::index_read_idx"); @@ -170,7 +170,7 @@ int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key, int ha_blackhole::index_read_last(byte * buf, const byte * key, - ulonglong keypart_map) + key_part_map keypart_map) { DBUG_ENTER("ha_blackhole::index_read_last"); DBUG_RETURN(HA_ERR_END_OF_FILE); diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h index cd8b6491dba..2af12b33077 100644 --- a/storage/blackhole/ha_blackhole.h +++ b/storage/blackhole/ha_blackhole.h @@ -64,12 +64,11 @@ public: int rnd_init(bool scan); int rnd_next(byte *buf); int rnd_pos(byte * buf, byte *pos); - int index_read(byte * buf, const byte * key, ulonglong keypart_map, - uint key_len, enum ha_rkey_function find_flag); + int index_read(byte * buf, const byte * key, key_part_map keypart_map, + enum ha_rkey_function find_flag); int index_read_idx(byte * buf, uint idx, const byte * key, - ulonglong keypart_map, uint key_len, - enum ha_rkey_function find_flag); - int index_read_last(byte * buf, const byte * key, ulonglong keypart_map); + key_part_map keypart_map, enum ha_rkey_function find_flag); + int index_read_last(byte * buf, const byte * key, key_part_map keypart_map); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 01d508e3290..999e36a4242 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -415,7 +415,7 @@ int ha_example::delete_row(const byte * buf) */ int ha_example::index_read(byte * buf, const byte * key, - ulonglong keypart_map __attribute__((unused)), + key_part_map keypart_map __attribute__((unused)), enum ha_rkey_function find_flag __attribute__((unused))) { diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h index ee60b412974..9777a478209 100644 --- a/storage/example/ha_example.h +++ b/storage/example/ha_example.h @@ -191,7 +191,7 @@ public: skip it and and MySQL will treat it as not implemented. */ int index_read(byte * buf, const byte * key, - ulonglong keypart_map, enum ha_rkey_function find_flag); + key_part_map keypart_map, enum ha_rkey_function find_flag); /** @brief We implement this in ha_example.cc. It's not an obligatory method; diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 9e6a7aea6c3..5831ec6167a 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -238,7 +238,7 @@ int ha_heap::delete_row(const byte * buf) return res; } -int ha_heap::index_read(byte * buf, const byte * key, ulonglong keypart_map, +int ha_heap::index_read(byte * buf, const byte * key, key_part_map keypart_map, enum ha_rkey_function find_flag) { DBUG_ASSERT(inited==INDEX); @@ -249,7 +249,7 @@ int ha_heap::index_read(byte * buf, const byte * key, ulonglong keypart_map, return error; } -int ha_heap::index_read_last(byte *buf, const byte *key, ulonglong keypart_map) +int ha_heap::index_read_last(byte *buf, const byte *key, key_part_map keypart_map) { DBUG_ASSERT(inited==INDEX); statistic_increment(table->in_use->status_var.ha_read_key_count, @@ -261,7 +261,7 @@ int ha_heap::index_read_last(byte *buf, const byte *key, ulonglong keypart_map) } int ha_heap::index_read_idx(byte * buf, uint index, const byte * key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h index b49ded6e33d..a2d531fc515 100644 --- a/storage/heap/ha_heap.h +++ b/storage/heap/ha_heap.h @@ -75,11 +75,11 @@ public: ulonglong nb_desired_values, ulonglong *first_value, ulonglong *nb_reserved_values); - int index_read(byte * buf, const byte * key, ulonglong keypart_map, + int index_read(byte * buf, const byte * key, key_part_map keypart_map, enum ha_rkey_function find_flag); - int index_read_last(byte *buf, const byte *key, ulonglong keypart_map); + int index_read_last(byte *buf, const byte *key, key_part_map keypart_map); int index_read_idx(byte * buf, uint index, const byte * key, - ulonglong keypart_map, enum ha_rkey_function find_flag); + key_part_map keypart_map, enum ha_rkey_function find_flag); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/heap/heapdef.h b/storage/heap/heapdef.h index d9c3ff147b4..b52a6c60ac6 100644 --- a/storage/heap/heapdef.h +++ b/storage/heap/heapdef.h @@ -90,7 +90,7 @@ extern int hp_rec_key_cmp(HP_KEYDEF *keydef,const byte *rec1, extern int hp_key_cmp(HP_KEYDEF *keydef,const byte *rec, const byte *key); extern void hp_make_key(HP_KEYDEF *keydef,byte *key,const byte *rec); -extern uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key, +extern uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key, const byte *rec, byte *recpos); extern uint hp_rb_key_length(HP_KEYDEF *keydef, const byte *key); extern uint hp_rb_null_key_length(HP_KEYDEF *keydef, const byte *key); @@ -99,8 +99,8 @@ extern my_bool hp_if_null_in_key(HP_KEYDEF *keyinfo, const byte *record); extern int hp_close(register HP_INFO *info); extern void hp_clear(HP_SHARE *info); extern void hp_clear_keys(HP_SHARE *info); -extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, - ulonglong keypart_map); +extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, + key_part_map keypart_map); #ifdef THREAD extern pthread_mutex_t THR_LOCK_heap; #else diff --git a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c index 326f6adea45..fbf3e541372 100644 --- a/storage/heap/hp_hash.c +++ b/storage/heap/hp_hash.c @@ -35,7 +35,7 @@ HA_READ_KEY_EXACT Include the key in the range HA_READ_AFTER_KEY Don't include key in range - max_key.flag can have one of the following values: + max_key.flag can have one of the following values: HA_READ_BEFORE_KEY Don't include key in range HA_READ_AFTER_KEY Include all 'end_key' values in the range @@ -62,7 +62,7 @@ ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key, { custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf, (uchar*) min_key->key, - min_key->length); + min_key->keypart_map); start_pos= tree_record_pos(rb_tree, info->recbuf, min_key->flag, &custom_arg); } @@ -70,12 +70,12 @@ ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key, { start_pos= 0; } - + if (max_key) { custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf, (uchar*) max_key->key, - max_key->length); + max_key->keypart_map); end_pos= tree_record_pos(rb_tree, info->recbuf, max_key->flag, &custom_arg); } @@ -772,7 +772,7 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key, char_length / seg->charset->mbmaxlen); set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */ if (char_length < seg->length) - seg->charset->cset->fill(seg->charset, (char*) key + char_length, + seg->charset->cset->fill(seg->charset, (char*) key + char_length, seg->length - char_length, ' '); } memcpy(key, rec + seg->start, (size_t) char_length); @@ -784,11 +784,11 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key, uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, - ulonglong keypart_map) + key_part_map keypart_map) { HA_KEYSEG *seg, *endseg; uchar *start_key= key; - + for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg && keypart_map; old+= seg->length, seg++) { diff --git a/storage/heap/hp_rkey.c b/storage/heap/hp_rkey.c index 98714bf875f..ced81985f99 100644 --- a/storage/heap/hp_rkey.c +++ b/storage/heap/hp_rkey.c @@ -16,7 +16,7 @@ #include "heapdef.h" int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key, - ulonglong keypart_map, enum ha_rkey_function find_flag) + key_part_map keypart_map, enum ha_rkey_function find_flag) { byte *pos; HP_SHARE *share= info->s; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6feb8e0146d..e9309f4f8b8 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3927,14 +3927,14 @@ statement issued by the user. We also increment trx->n_mysql_tables_in_use. 2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search instructions to prebuilt->template of the table handle instance in -::index_read_old. The template is used to save CPU time in large joins. +::index_read. The template is used to save CPU time in large joins. 3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we allocate a new consistent read view for the trx if it does not yet have one, or in the case of a locking read, set an InnoDB 'intention' table level lock on the table. - 4) We do the SELECT. MySQL may repeatedly call ::index_read_old for the + 4) We do the SELECT. MySQL may repeatedly call ::index_read for the same table handle instance, if it is a join. 5) When the SELECT ends, MySQL removes its intention table level locks @@ -3948,7 +3948,7 @@ table handler in that case has to execute the COMMIT in ::external_lock. B) If the user has explicitly set MySQL table level locks, then MySQL does NOT call ::external_lock at the start of the statement. To determine when we are at the start of a new SQL statement we at the start of -::index_read_old also compare the query id to the latest query id where the +::index_read also compare the query id to the latest query id where the table handle instance was used. If it has changed, we know we are at the start of a new SQL statement. Since the query id can theoretically overwrap, we use this test only as a secondary way of determining the @@ -3985,7 +3985,7 @@ ha_innobase::index_read( int error; ulint ret; - DBUG_ENTER("index_read_old"); + DBUG_ENTER("index_read"); ut_a(prebuilt->trx == (trx_t*) current_thd->ha_data[ht->slot]); @@ -4067,7 +4067,7 @@ ha_innobase::index_read( } /*********************************************************************** -The following functions works like index_read_old, but it find the last +The following functions works like index_read, but it find the last row with the current key value or prefix. */ int @@ -4173,7 +4173,7 @@ ha_innobase::index_read_idx( /*************************************************************************** Reads the next or previous row from a cursor, which must have previously been -positioned using index_read_old. */ +positioned using index_read. */ int ha_innobase::general_fetch( @@ -4222,7 +4222,7 @@ ha_innobase::general_fetch( /*************************************************************************** Reads the next row from a cursor, which must have previously been -positioned using index_read_old. */ +positioned using index_read. */ int ha_innobase::index_next( @@ -4258,7 +4258,7 @@ ha_innobase::index_next_same( /*************************************************************************** Reads the previous row from a cursor, which must have previously been -positioned using index_read_old. */ +positioned using index_read. */ int ha_innobase::index_prev( diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index fb0c3eebc4d..48f1d9b2395 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1555,7 +1555,7 @@ int ha_myisam::delete_row(const byte * buf) return mi_delete(file,buf); } -int ha_myisam::index_read(byte *buf, const byte *key, ulonglong keypart_map, +int ha_myisam::index_read(byte *buf, const byte *key, key_part_map keypart_map, enum ha_rkey_function find_flag) { DBUG_ASSERT(inited==INDEX); @@ -1567,7 +1567,7 @@ int ha_myisam::index_read(byte *buf, const byte *key, ulonglong keypart_map, } int ha_myisam::index_read_idx(byte *buf, uint index, const byte *key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, @@ -1578,7 +1578,7 @@ int ha_myisam::index_read_idx(byte *buf, uint index, const byte *key, } int ha_myisam::index_read_last(byte *buf, const byte *key, - ulonglong keypart_map) + key_part_map keypart_map) { DBUG_ENTER("ha_myisam::index_read_last"); DBUG_ASSERT(inited==INDEX); diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index b66a9e5cca4..647e72d53eb 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -69,11 +69,11 @@ class ha_myisam: public handler int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); int delete_row(const byte * buf); - int index_read(byte *buf, const byte *key, ulonglong keypart_map, + int index_read(byte *buf, const byte *key, key_part_map keypart_map, enum ha_rkey_function find_flag); int index_read_idx(byte *buf, uint index, const byte *key, - ulonglong keypart_map, enum ha_rkey_function find_flag); - int index_read_last(byte *buf, const byte *key, ulonglong keypart_map); + key_part_map keypart_map, enum ha_rkey_function find_flag); + int index_read_last(byte *buf, const byte *key, key_part_map keypart_map); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 5c67404559e..7a4d47954a5 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -532,7 +532,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) mi_extra(info,HA_EXTRA_KEYREAD,0); bzero(info->lastkey,keyinfo->seg->length); if (!mi_rkey(info, info->rec_buff, key, (const byte*) info->lastkey, - ULL(1), HA_READ_KEY_EXACT)) + (key_part_map)1, HA_READ_KEY_EXACT)) { /* Don't count this as a real warning, as myisamchk can't correct it */ uint save=param->warning_printed; diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c index 1b7ba676139..2f4915dec39 100644 --- a/storage/myisam/mi_key.c +++ b/storage/myisam/mi_key.c @@ -216,7 +216,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, */ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, - ulonglong keypart_map, HA_KEYSEG **last_used_keyseg) + key_part_map keypart_map, HA_KEYSEG **last_used_keyseg) { uchar *start_key=key; HA_KEYSEG *keyseg; @@ -225,7 +225,7 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, /* "one part" rtree key is 2*SPDIMS part key in MyISAM */ if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE) - keypart_map= (ULL(1) << (2*SPDIMS)) - 1; + keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1; /* only key prefixes are supported */ DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0); diff --git a/storage/myisam/mi_range.c b/storage/myisam/mi_range.c index 5e5fe3c6b22..2cdb02b2c80 100644 --- a/storage/myisam/mi_range.c +++ b/storage/myisam/mi_range.c @@ -21,7 +21,7 @@ #include "myisamdef.h" #include "rt_index.h" -static ha_rows _mi_record_pos(MI_INFO *, const byte *, ulonglong, +static ha_rows _mi_record_pos(MI_INFO *, const byte *, key_part_map, enum ha_rkey_function); static double _mi_search_pos(MI_INFO *,MI_KEYDEF *,uchar *, uint,uint,my_off_t); static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *,uchar *, uchar *,uint *); @@ -104,11 +104,11 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) res=HA_POS_ERROR; } - + if (info->s->concurrent_insert) rw_unlock(&info->s->key_root_lock[inx]); fast_mi_writeinfo(info); - + DBUG_PRINT("info",("records: %ld",(ulong) (res))); DBUG_RETURN(res); } @@ -117,7 +117,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, /* Find relative position (in records) for key in index-tree */ static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function search_flag) { uint inx=(uint) info->lastinx, nextflag, key_len; diff --git a/storage/myisam/mi_rkey.c b/storage/myisam/mi_rkey.c index 2ff24d565b9..373ab303bf0 100644 --- a/storage/myisam/mi_rkey.c +++ b/storage/myisam/mi_rkey.c @@ -22,7 +22,7 @@ /* Ordinary search_flag is 0 ; Give error if no record with key */ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, - ulonglong keypart_map, enum ha_rkey_function search_flag) + key_part_map keypart_map, enum ha_rkey_function search_flag) { uchar *key_buff; MYISAM_SHARE *share=info->s; diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h index f1ca1754696..7325340b970 100644 --- a/storage/myisam/myisamdef.h +++ b/storage/myisam/myisamdef.h @@ -605,7 +605,7 @@ extern my_off_t _mi_new(MI_INFO *info,MI_KEYDEF *keyinfo,int level); extern uint _mi_make_key(MI_INFO *info,uint keynr,uchar *key, const byte *record,my_off_t filepos); extern uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, - uchar *old, ulonglong keypart_map, + uchar *old, key_part_map keypart_map, HA_KEYSEG **last_used_keyseg); extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf); extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos, diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index df77931ddb5..96f7db6e633 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -179,7 +179,7 @@ int ha_myisammrg::delete_row(const byte * buf) } int ha_myisammrg::index_read(byte * buf, const byte * key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, @@ -190,7 +190,7 @@ int ha_myisammrg::index_read(byte * buf, const byte * key, } int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key, - ulonglong keypart_map, + key_part_map keypart_map, enum ha_rkey_function find_flag) { statistic_increment(table->in_use->status_var.ha_read_key_count, @@ -201,7 +201,7 @@ int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key, } int ha_myisammrg::index_read_last(byte * buf, const byte * key, - ulonglong keypart_map) + key_part_map keypart_map) { statistic_increment(table->in_use->status_var.ha_read_key_count, &LOCK_status); diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index 805a2cb04b6..7bbe659d4b7 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -56,11 +56,11 @@ class ha_myisammrg: public handler int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); int delete_row(const byte * buf); - int index_read(byte * buf, const byte * key, ulonglong keypart_map, + int index_read(byte * buf, const byte * key, key_part_map keypart_map, enum ha_rkey_function find_flag); int index_read_idx(byte * buf, uint index, const byte * key, - ulonglong keypart_map, enum ha_rkey_function find_flag); - int index_read_last(byte * buf, const byte * key, ulonglong keypart_map); + key_part_map keypart_map, enum ha_rkey_function find_flag); + int index_read_last(byte * buf, const byte * key, key_part_map keypart_map); int index_next(byte * buf); int index_prev(byte * buf); int index_first(byte * buf); diff --git a/storage/myisammrg/myrg_rkey.c b/storage/myisammrg/myrg_rkey.c index 2273f7d62b8..0eefe7eb173 100644 --- a/storage/myisammrg/myrg_rkey.c +++ b/storage/myisammrg/myrg_rkey.c @@ -36,7 +36,7 @@ */ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, - ulonglong keypart_map, enum ha_rkey_function search_flag) + key_part_map keypart_map, enum ha_rkey_function search_flag) { byte *key_buff; uint pack_key_length; From e9fb4a686ff2d464e33902624d8425d379ef5016 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Sat, 17 Mar 2007 11:19:21 +0100 Subject: [PATCH 34/34] dbug/dbug.c: unused variable removed include/config-win.h: SIZEOF_INT include/my_global.h: win64 fix support-files/Makefile.am: automake magic --- dbug/dbug.c | 1 - include/config-win.h | 1 + include/my_global.h | 4 +++- support-files/Makefile.am | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dbug/dbug.c b/dbug/dbug.c index c4ae89f837f..e482fd95073 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -2000,7 +2000,6 @@ static char *DbugMalloc(size_t size) static const char *DbugStrTok(const char *s) { - const char *start=s; while (s[0] && (s[0] != ':' || (s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++)))) s++; diff --git a/include/config-win.h b/include/config-win.h index 6735ae1aba1..fadf24c732f 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -172,6 +172,7 @@ typedef uint rf_SetTimer; #endif #define VOID_SIGHANDLER #define SIZEOF_CHAR 1 +#define SIZEOF_INT 4 #define SIZEOF_LONG 4 #define SIZEOF_LONG_LONG 8 #define SIZEOF_OFF_T 8 diff --git a/include/my_global.h b/include/my_global.h index addc2f24e7f..b6c6ff13405 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -1020,8 +1020,10 @@ typedef unsigned long long my_ulonglong; typedef int intptr; #elif SIZEOF_CHARP == SIZEOF_LONG typedef long intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG_LONG +typedef long long intptr; #else -#error sizeof(void *) is neither sizeof(int) nor sizeof(long) +#error sizeof(void *) is neither sizeof(int) nor sizeof(long) nor sizeof(long long) #endif #ifdef USE_RAID diff --git a/support-files/Makefile.am b/support-files/Makefile.am index b3ef3b77b76..b3581d65eb0 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -26,7 +26,7 @@ EXTRA_DIST = mysql.spec.sh \ mysql-log-rotate.sh \ mysql.server.sh \ binary-configure.sh \ - magic \ + magic mysql.m4 \ MySQL-shared-compat.spec.sh \ ndb-config-2-node.ini.sh \ compiler_warnings.supp