diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 3d4b1dbd46d..23610be36c4 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -332,29 +332,35 @@ t1 1 a 2 b A 5 NULL NULL YES BTREE t1 1 c_2 1 c A 5 NULL NULL YES BTREE t1 1 c_2 2 a A 5 NULL NULL BTREE explain select * from t1,t2 where t1.a=t2.a; -table type possible_keys key key_len ref rows Extra -t1 ALL a NULL NULL NULL 5 -t2 ALL a NULL NULL NULL 2 Using where +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 +1 SIMPLE t2 ALL a NULL NULL NULL 2 Using where explain select * from t1,t2 force index(a) where t1.a=t2.a; -table type possible_keys key key_len ref rows Extra -t2 ALL a NULL NULL NULL 2 -t1 ALL a NULL NULL NULL 5 Using where +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL a NULL NULL NULL 2 +1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a; -table type possible_keys key key_len ref rows Extra -t2 ALL a NULL NULL NULL 2 -t1 ref a a 4 t2.a 3 +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL a NULL NULL NULL 2 +1 SIMPLE t1 ref a a 4 t2.a 3 explain select * from t1,t2 where t1.b=t2.b; -table type possible_keys key key_len ref rows Extra -t2 ALL b NULL NULL NULL 2 -t1 ref b b 5 t2.b 1 Using where +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL b NULL NULL NULL 2 +1 SIMPLE t1 ref b b 5 t2.b 1 Using where explain select * from t1,t2 force index(c) where t1.a=t2.a; -table type possible_keys key key_len ref rows Extra -t1 ALL a NULL NULL NULL 5 -t2 ALL NULL NULL NULL NULL 2 Using where +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where explain select * from t1 where a=0 or a=2; -table type possible_keys key key_len ref rows Extra -t1 ALL a NULL NULL NULL 5 Using where +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 5 Using where explain select * from t1 force index (a) where a=0 or a=2; -table type possible_keys key key_len ref rows Extra -t1 range a a 4 NULL 4 Using where +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 4 NULL 4 Using where +explain select * from t1 where c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref c,c_2 c 5 const 1 Using where +explain select * from t1 use index() where c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where drop table t1,t2; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 7b541d98cef..ed08b1cbacb 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -349,4 +349,6 @@ explain select * from t1,t2 where t1.b=t2.b; explain select * from t1,t2 force index(c) where t1.a=t2.a; explain select * from t1 where a=0 or a=2; explain select * from t1 force index (a) where a=0 or a=2; +explain select * from t1 where c=1; +explain select * from t1 use index() where c=1; drop table t1,t2; diff --git a/mysys/my_handler.c b/mysys/my_handler.c index 2d51ab13f69..2fd7f1fcdee 100644 --- a/mysys/my_handler.c +++ b/mysys/my_handler.c @@ -40,15 +40,33 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, return (int) (a_length-b_length); } -#define FCMP(A,B) ((int) (A) - (int) (B)) /* Compare two keys - Returns <0, 0, >0 acording to which is bigger - Key_length specifies length of key to use. Number-keys can't be splited - If flag <> SEARCH_FIND compare also position + + SYNOPSIS + ha_key_cmp() + keyseg Key segments of key to compare + a First key to compare, in format from _mi_pack_key() + This is normally key specified by user + b Second key to compare. This is always from a row + key_length Length of key to compare. This can be shorter than + a to just compare sub keys + next_flag How keys should be compared + If bit SEARCH_FIND is not set the keys includes the row + position and this should also be compared + + NOTES + Number-keys can't be splited + + RETURN VALUES + <0 If a < b + 0 If a == b + >0 If a > b */ +#define FCMP(A,B) ((int) (A) - (int) (B)) + int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, register uchar *b, uint key_length, uint nextflag, uint *diff_pos) @@ -59,9 +77,10 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, uint32 u_1,u_2; float f_1,f_2; double d_1,d_2; + uint next_key_length; *diff_pos=0; - for ( ; (int) key_length >0 ; keyseg++) + for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++) { uchar *end; uint piks=! (keyseg->flag & HA_NO_SORT); @@ -81,10 +100,21 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, { if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) nextflag=SEARCH_SAME; /* Allow duplicate keys */ + else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL) + { + /* + This is only used from mi_check() to calculate cardinality. + It can't be used when searching for a key as this would cause + compare of (a,b) and (b,a) to return the same value. + */ + return -1; + } + next_key_length=key_length; continue; /* To next key part */ } } end= a+ min(keyseg->length,key_length); + next_key_length=key_length-keyseg->length; switch ((enum ha_base_keytype) keyseg->type) { case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ @@ -93,12 +123,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && - (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + (flag=mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -107,7 +137,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, else { uint length=(uint) (end-a), a_length=length, b_length=length; - key_length-= keyseg->length; if (!(nextflag & SEARCH_PREFIX)) { while (a_length && a[a_length-1] == ' ') @@ -116,9 +145,9 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, b_length--; } if (piks && - (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + (flag= mi_compare_text(keyseg->charset, a, a_length, b, b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a=end; b+=length; @@ -130,12 +159,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && (flag=compare_bin(a,a_length,b,b_length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -144,11 +173,10 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, else { uint length=keyseg->length; - key_length-= keyseg->length; if (piks && (flag=compare_bin(a,length,b,length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=length; b+=length; @@ -159,12 +187,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && (flag= mi_compare_text(keyseg->charset,a,a_length,b,b_length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -176,12 +204,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, int a_length,b_length,pack_length; get_key_length(a_length,a); get_key_pack_length(b_length,pack_length,b); - key_length-= b_length + pack_length; + next_key_length=key_length-b_length-pack_length; if (piks && (flag=compare_bin(a,a_length,b,b_length, (my_bool) ((nextflag & SEARCH_PREFIX) && - key_length <= 0)))) + next_key_length <= 0)))) return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a+=a_length; b+=b_length; @@ -196,7 +224,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b++; - key_length-= keyseg->length; break; } case HA_KEYTYPE_SHORT_INT: @@ -206,7 +233,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 2; /* sizeof(short int); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_USHORT_INT: { @@ -217,7 +243,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+=2; /* sizeof(short int); */ - key_length-= keyseg->length; break; } case HA_KEYTYPE_LONG_INT: @@ -227,7 +252,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_ULONG_INT: u_1= mi_sint4korr(a); @@ -236,7 +260,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_INT24: l_1=mi_sint3korr(a); @@ -245,7 +268,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; - key_length-= keyseg->length; break; case HA_KEYTYPE_UINT24: l_1=mi_uint3korr(a); @@ -254,7 +276,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; - key_length-= keyseg->length; break; case HA_KEYTYPE_FLOAT: mi_float4get(f_1,a); @@ -263,7 +284,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(float); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_DOUBLE: mi_float8get(d_1,a); @@ -272,13 +292,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; /* sizeof(double); */ - key_length-= keyseg->length; break; case HA_KEYTYPE_NUM: /* Numeric key */ { int swap_flag= 0; int alength,blength; - + if (keyseg->flag & HA_REVERSE_SORT) { swap(uchar*,a,b); @@ -289,7 +308,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, { alength= *a++; blength= *b++; end=a+alength; - key_length-= blength + 1; + next_key_length=key_length-blength-1; } else { @@ -298,9 +317,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, /* remove pre space from keys */ for ( ; alength && *a == ' ' ; a++, alength--) ; for ( ; blength && *b == ' ' ; b++, blength--) ; - key_length-= keyseg->length; } - if (piks) { if (*a == '-') @@ -350,7 +367,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; - key_length-= keyseg->length; break; } case HA_KEYTYPE_ULONGLONG: @@ -362,7 +378,6 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a, return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; - key_length-= keyseg->length; break; } #endif diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c7595c7ec5c..d22d5b8e0af 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1171,13 +1171,14 @@ 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, LEX_STRING *alias, - bool updating, + ulong table_join_options, thr_lock_type flags, List *use_index, List *ignore_index) { return 0; } +ulong st_select_lex_node::get_table_join_options() { return 0; } /* This is used for UNION & subselect to create a new table list of all used @@ -1334,6 +1335,11 @@ List* st_select_lex::get_ignore_index() return ignore_index_ptr; } +ulong st_select_lex::get_table_join_options() +{ + return table_join_options; +} + /* There are st_select_lex::add_table_to_list & st_select_lex::set_lock_for_tables in sql_parse.cc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b32e4489b01..4b6ac927f07 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -243,7 +243,7 @@ public: virtual List* get_item_list(); virtual List* get_use_index(); virtual List* get_ignore_index(); - virtual ulong table_join_options(); + virtual ulong get_table_join_options(); virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_options, @@ -375,7 +375,7 @@ public: List* get_item_list(); List* get_use_index(); List* get_ignore_index(); - ulong table_join_options(); + ulong get_table_join_options(); TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_options, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ce8bd41d3a6..81fb5a6d12c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3598,11 +3598,30 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) } +/* + Add a table to list of used tables + + SYNOPSIS + add_table_to_list() + table Table to add + alias alias for table (or null if no alias) + table_options A set of the following bits: + TL_OPTION_UPDATING Table will be updated + TL_OPTION_FORCE_INDEX Force usage of index + lock_type How table should be locked + use_index List of indexed used in USE INDEX + ignore_index List of indexed used in IGNORE INDEX + + RETURN + 0 Error + # Pointer to TABLE_LIST element added to the total table list +*/ + TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, - bool updating, - thr_lock_type flags, + ulong table_options, + thr_lock_type lock_type, List *use_index, List *ignore_index) { @@ -3659,8 +3678,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } ptr->real_name=table->table.str; ptr->real_name_length=table->table.length; - ptr->lock_type=flags; - ptr->updating=updating; + ptr->lock_type= lock_type; + ptr->updating= test(table_options & TL_OPTION_UPDATING); + ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->derived= (SELECT_LEX_UNIT *) table->sel; if (use_index) ptr->use_index=(List *) thd->memdup((gptr) use_index, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 106fa61e535..79cadff3cc1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1359,7 +1359,7 @@ opt_unique_or_fulltext: key_alg: /* empty */ { $$= HA_KEY_ALG_UNDEF; } | USING opt_btree_or_rtree { $$= $2; }; - | TYPE opt_btree_or_rtree { $$= $2; }; + | TYPE_SYM opt_btree_or_rtree { $$= $2; }; opt_btree_or_rtree: BTREE_SYM { $$= HA_KEY_ALG_BTREE; } @@ -2516,14 +2516,14 @@ join_table: { SELECT_LEX *sel= Select->select_lex(); sel->use_index_ptr=sel->ignore_index_ptr=0; - sel->table_join_ptions= 0; + sel->table_join_options= 0; } table_ident opt_table_alias opt_key_definition { LEX *lex= Lex; SELECT_LEX_NODE *sel= lex->current_select; if (!($$= sel->add_table_to_list(lex->thd, $2, $3, - lex->table_join_options(), + sel->get_table_join_options(), lex->lock_option, sel->get_use_index(), sel->get_ignore_index()))) @@ -2569,6 +2569,13 @@ opt_key_definition: sel->use_index= *$2; sel->use_index_ptr= &sel->use_index; } + | FORCE_SYM key_usage_list + { + SELECT_LEX *sel= Select->select_lex(); + 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->select_lex(); @@ -2578,8 +2585,14 @@ opt_key_definition: key_usage_list: key_or_index { Select->select_lex()->interval_list.empty(); } - '(' key_usage_list2 ')' - { $$= &Select->select_lex()->interval_list; }; + '(' key_list_or_empty ')' + { $$= &Select->select_lex()->interval_list; } + ; + +key_list_or_empty: + /* empty */ {} + | key_usage_list2 {} + ; key_usage_list2: key_usage_list2 ',' ident