Hi!
"Sergey" == Sergey Petrunya <psergey@askmonty.org> writes:
Sergey> At file:///home/psergey/dev2/5.3/ Sergey> ------------------------------------------------------------ Sergey> revno: 2892 Sergey> revision-id: psergey@askmonty.org-20110201233314-6j8yc7jrx9425f3b Sergey> parent: sergii@pisem.net-20110114205155-i8poq0jti8o8mob1 Sergey> committer: Sergey Petrunya <psergey@askmonty.org> Sergey> branch nick: 5.3 Sergey> timestamp: Wed 2011-02-02 02:33:14 +0300 Sergey> message: Sergey> BUG#711565 Index Condition Pushdown can make a thread hold MyISAM locks as well as be unKILLable for long time <cut> Sergey> === modified file 'mysql-test/t/myisam_icp.test' Sergey> --- a/mysql-test/t/myisam_icp.test 2011-01-14 13:38:41 +0000 Sergey> +++ b/mysql-test/t/myisam_icp.test 2011-02-01 23:33:14 +0000 Sergey> @@ -4,3 +4,183 @@ Sergey> --source include/icp_tests.inc <cut> Instead of using # for each row, please use --disable_parsing --enable_parsing This makes it easier to enable the test temporarly when testing. <cut> Sergey> === modified file 'sql/multi_range_read.cc' Sergey> --- a/sql/multi_range_read.cc 2010-12-21 23:26:35 +0000 Sergey> +++ b/sql/multi_range_read.cc 2011-02-01 23:33:14 +0000 Sergey> @@ -902,7 +902,7 @@ Sergey> close_second_handler(); Sergey> /* Safety, not really needed but: */ Sergey> strategy= NULL; Sergey> - DBUG_RETURN(1); Sergey> + DBUG_RETURN(res); Sergey> use_default_impl: Sergey> DBUG_ASSERT(primary_file->inited == handler::INDEX); Sergey> === modified file 'sql/sql_base.cc' Sergey> --- a/sql/sql_base.cc 2010-12-06 08:25:44 +0000 Sergey> +++ b/sql/sql_base.cc 2011-02-01 23:33:14 +0000 Sergey> @@ -8283,11 +8283,9 @@ Sergey> List_iterator_fast<Item> f(fields),v(values); Sergey> Item *value, *fld; Sergey> Item_field *field; Sergey> - TABLE *table= 0; Sergey> - List<TABLE> tbl_list; Sergey> + TABLE *table= 0, *vcol_table= 0; Sergey> bool abort_on_warning_saved= thd->abort_on_warning; Sergey> DBUG_ENTER("fill_record"); Sergey> - tbl_list.empty(); Sergey> /* Sergey> Reset the table->auto_increment_field_not_null as it is valid for Sergey> @@ -8310,7 +8308,7 @@ Sergey> f.rewind(); Sergey> } Sergey> else if (thd->lex->unit.insert_table_with_stored_vcol) Sergey> - tbl_list.push_back(thd->lex->unit.insert_table_with_stored_vcol); Sergey> + vcol_table= thd->lex->unit.insert_table_with_stored_vcol; Sergey> while ((fld= f++)) Sergey> { Sergey> if (!(field= fld->filed_for_view_update())) Sergey> @@ -8340,31 +8338,17 @@ Sergey> my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0)); Sergey> goto err; Sergey> } Sergey> - tbl_list.push_back(table); Sergey> + DBUG_ASSERT(vcol_table == 0 || vcol_table == table); Sergey> + vcol_table= table; Sergey> } Sergey> /* Update virtual fields*/ Sergey> thd->abort_on_warning= FALSE; Sergey> - if (tbl_list.head()) Sergey> + if (vcol_table) Sergey> { Sergey> - List_iterator_fast<TABLE> it(tbl_list); Sergey> - TABLE *prev_table= 0; Sergey> - while ((table= it++)) Sergey> + if (vcol_table->vfield) Sergey> { Sergey> - /* Sergey> - Do simple optimization to prevent unnecessary re-generating Sergey> - values for virtual fields Sergey> - */ Sergey> - if (table != prev_table) Sergey> - { Sergey> - prev_table= table; Sergey> - if (table->vfield) Sergey> - { Sergey> - if (update_virtual_fields(thd, table, TRUE)) Sergey> - { Sergey> - goto err; Sergey> - } Sergey> - } Sergey> - } Sergey> + if (update_virtual_fields(thd, vcol_table, TRUE)) Sergey> + goto err; Sergey> } Sergey> } Sergey> thd->abort_on_warning= abort_on_warning_saved; What has the above to do with the IPC patch? In any case, how will the above work when there is more than one table involved in fill_tables ? (By the way, agree that the old code as stupid; There is no reason to add all involved tables to tbl_list (trivial to avoid). Sergey> === modified file 'sql/sql_select.cc' Sergey> --- a/sql/sql_select.cc 2011-01-14 11:03:41 +0000 Sergey> +++ b/sql/sql_select.cc 2011-02-01 23:33:14 +0000 Sergey> @@ -13618,13 +13618,17 @@ Sergey> " cond: %p error: %d", join, join_tab, select_cond, error)); Sergey> if (error > 0 || (join->thd->is_error())) // Fatal error Sergey> DBUG_RETURN(NESTED_LOOP_ERROR); Sergey> + /* Sergey> + Check if we're killed before checking for EOF. This is important because Sergey> + if we're killed while reading a record, the handler will return EOF. Sergey> + */ Please update the comment; We should not send EOF from the handler if the query is killed; There is too many things that can go wrong if we send EOF on killed from the handler. Sergey> + if (join->thd->killed) // Aborted by user Sergey> + { Sergey> + join->thd->send_kill_message(); Sergey> + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ Sergey> + } <cut> Sergey> === modified file 'storage/maria/ma_rkey.c' Sergey> --- a/storage/maria/ma_rkey.c 2011-01-14 11:05:46 +0000 Sergey> +++ b/storage/maria/ma_rkey.c 2011-02-01 23:33:14 +0000 Sergey> @@ -34,7 +34,7 @@ Sergey> HA_KEYSEG *last_used_keyseg; Sergey> uint32 nextflag; Sergey> MARIA_KEY key; Sergey> - int icp_res= 1; Sergey> + ICP_RESULT icp_res= ICP_MATCH; Sergey> DBUG_ENTER("maria_rkey"); Sergey> DBUG_PRINT("enter", ("base: 0x%lx buf: 0x%lx inx: %d search_flag: %d", Sergey> (long) info, (long) buf, inx, search_flag)); Sergey> @@ -115,7 +115,7 @@ Sergey> not satisfied with an out-of-range condition. Sergey> */ Sergey> if ((*share->row_is_visible)(info) && Sergey> - ((icp_res= ma_check_index_cond(info, inx, buf)) != 0)) Sergey> + ((icp_res= ma_check_index_cond(info, inx, buf)) != ICP_NO_MATCH)) Sergey> break; Sergey> /* The key references a concurrently inserted record. */ Sergey> @@ -145,6 +145,19 @@ Sergey> if (_ma_search_next(info, &lastkey, maria_readnext_vec[search_flag], Sergey> info->s->state.key_root[inx])) Sergey> break; /* purecov: inspected */ Sergey> + Sergey> + /* Sergey> + If we are at the last key on the key page, allow writers to Sergey> + access the index. Sergey> + */ Sergey> + if (info->int_keypos >= info->int_maxpos && Sergey> + ma_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + buf= 0; /* Fast abort */ Sergey> + icp_res= ICP_ERROR; We should not return an IPC_ERROR here as this test has nothing to do with IPC. It can also happens when we are scanning for a visible row. Better to just threat this as a normal handler error. See later comments... Sergey> + break; Sergey> + } Sergey> + Sergey> /* Sergey> Check that the found key does still match the search. Sergey> _ma_search_next() delivers the next key regardless of its Sergey> @@ -168,9 +181,9 @@ Sergey> if (share->lock_key_trees) Sergey> rw_unlock(&keyinfo->root_lock); Sergey> - if (info->cur_row.lastpos == HA_OFFSET_ERROR || (icp_res != 1)) Sergey> + if (info->cur_row.lastpos == HA_OFFSET_ERROR || (icp_res != ICP_MATCH)) Sergey> { Sergey> - if (icp_res == 2) Sergey> + if (icp_res == ICP_OUT_OF_RANGE || icp_res == ICP_ERROR) Sergey> { Sergey> info->cur_row.lastpos= HA_OFFSET_ERROR; Sergey> my_errno= HA_ERR_KEY_NOT_FOUND; We should not return HA_ERR_KEY_NOT_FOUND in the case of a real error. (Too big risk we loose the reason that something went wrong). Sergey> +/* Sergey> + Yield to possible other writers during a index scan. Sergey> + Check also if we got killed by the user and if yes, return Sergey> + HA_ERR_LOCK_WAIT_TIMEOUT Sergey> + Sergey> + return 0 ok Sergey> + return 1 Query has been requested to be killed Sergey> +*/ Sergey> + Sergey> +my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx) Sergey> +{ Sergey> + MARIA_SHARE *share; Sergey> + if (ma_killed(info)) Sergey> + { Sergey> + //info->lastpos= HA_OFFSET_ERROR; Sergey> + my_errno= HA_ERR_KEY_NOT_FOUND; Sergey> + return 1; The above is not safe. Please use: info->cur_row.lastpos= HA_OFFSET_ERROR; my_errno= HA_ERR_ABORTED_BY_USER; In this case we can not return HA_ERR_KEY_NOT_FOUND as it's too big risk that the calling code may think that there was really no key and send a result to the client instead of aborting. By sending a fatal error message to the user, we can be sure that the calling code will not ignore it. That is why we probably should introduce HA_ERR_ABORTED_BY_USER. If we do this, then we have to fix that handler::print_error() ignores this error if thd->killed is set. dispatch_command will generate the necessary error message. Sergey> + } Sergey> + Sergey> + if ((share= info->s)->lock_key_trees) Sergey> + { Sergey> + /* Give writers a chance to access index */ Sergey> + rw_unlock(&share->keyinfo[inx].root_lock); Sergey> + rw_rdlock(&share->keyinfo[inx].root_lock); Sergey> + } Sergey> + return 0; Sergey> +} Sergey> + Sergey> === modified file 'storage/maria/ma_rnext.c' Sergey> --- a/storage/maria/ma_rnext.c 2009-12-15 07:16:46 +0000 Sergey> +++ b/storage/maria/ma_rnext.c 2011-02-01 23:33:14 +0000 <cut> Sergey> + if (info->int_keypos >= info->int_maxpos && Sergey> + ma_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + error= 0; Sergey> + icp_res= ICP_ERROR; Sergey> + break; Sergey> + } Same thing as above, don't use IPC_ERROR, treat this as a real error! Sergey> + Sergey> /* Skip rows inserted by other threads since we got a lock */ Sergey> if ((error= _ma_search_next(info, &info->last_key, Sergey> SEARCH_BIGGER, Sergey> @@ -108,10 +120,10 @@ Sergey> info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); Sergey> info->update|= HA_STATE_NEXT_FOUND; Sergey> - if (icp_res == 2) Sergey> + if (icp_res == ICP_OUT_OF_RANGE) Sergey> my_errno=HA_ERR_END_OF_FILE; /* got beyond the end of scanned range */ Sergey> - if (error || icp_res != 1) Sergey> + if (error || icp_res != ICP_MATCH) Sergey> { Sergey> if (my_errno == HA_ERR_KEY_NOT_FOUND) Sergey> my_errno=HA_ERR_END_OF_FILE; Don't return HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND for IPC_ERROR Sergey> === modified file 'storage/maria/ma_rnext_same.c' Sergey> --- a/storage/maria/ma_rnext_same.c 2010-10-30 01:59:39 +0000 Sergey> +++ b/storage/maria/ma_rnext_same.c 2011-02-01 23:33:14 +0000 Sergey> @@ -30,7 +30,7 @@ Sergey> int error; Sergey> uint inx,not_used[2]; Sergey> MARIA_KEYDEF *keyinfo; Sergey> - int icp_res= 1; Sergey> + ICP_RESULT icp_res= ICP_MATCH; Sergey> DBUG_ENTER("maria_rnext_same"); Sergey> if ((int) (inx= info->lastinx) < 0 || Sergey> @@ -80,9 +80,20 @@ Sergey> info->cur_row.lastpos= HA_OFFSET_ERROR; Sergey> break; Sergey> } Sergey> + /* Sergey> + If we are at the last key on the key page, allow writers to Sergey> + access the index. Sergey> + */ Sergey> + if (info->int_keypos >= info->int_maxpos && Sergey> + ma_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + error= 0; Sergey> + icp_res= ICP_ERROR; Sergey> + break; Sergey> + } Same thing as above, don't use IPC_ERROR, treat this as a real error! <cut> Sergey> - if (error || icp_res != 1) Sergey> + if (error || icp_res != ICP_MATCH) Sergey> { Sergey> if (my_errno == HA_ERR_KEY_NOT_FOUND) Sergey> my_errno=HA_ERR_END_OF_FILE; Don't return HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND for IPC_ERROR Sergey> === modified file 'storage/maria/ma_rprev.c' <cut> Sergey> + if (ma_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + error= 0; Sergey> + icp_res= ICP_ERROR; Sergey> + break; Sergey> + } Return a real error! Sergey> + } Sergey> + Sergey> /* Skip rows that are inserted by other threads since we got a lock */ Sergey> if ((error= _ma_search_next(info, &info->last_key, Sergey> SEARCH_SMALLER, Sergey> @@ -66,6 +84,10 @@ Sergey> } Sergey> if (share->lock_key_trees) Sergey> rw_unlock(&keyinfo->root_lock); Sergey> + if (icp_res == ICP_ERROR || icp_res == ICP_OUT_OF_RANGE) Sergey> + { Sergey> + DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE); Don't return HA_ERR_END_OF_FILE in case of IPC_ERROR Sergey> === modified file 'storage/maria/maria_def.h' Sergey> --- a/storage/maria/maria_def.h 2011-01-14 11:03:41 +0000 Sergey> +++ b/storage/maria/maria_def.h 2011-02-01 23:33:14 +0000 Sergey> @@ -505,6 +505,7 @@ Sergey> DYNAMIC_ARRAY pinned_pages; Sergey> /* accumulate indexfile changes between write's */ Sergey> TREE *bulk_insert; Sergey> + void *__external_ref; /* For MariaDB TABLE */ /* psergey-todo: need this?*/ No, we don't need this as we have external_ptr already in Aria that we can use. Sergey> --- a/storage/myisam/mi_rkey.c 2009-12-22 12:33:21 +0000 Sergey> @@ -168,26 +176,37 @@ Sergey> if (share->concurrent_insert) Sergey> rw_unlock(&share->key_root_lock[inx]); Sergey> - /* Calculate length of the found key; Used by mi_rnext_same */ Sergey> - if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg && Sergey> - info->lastpos != HA_OFFSET_ERROR) Sergey> - info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey, Sergey> - last_used_keyseg); Sergey> + info->last_rkey_length= pack_key_length; Sergey> + Sergey> + if (info->lastpos == HA_OFFSET_ERROR) /* No such record */ Sergey> + { Sergey> + /* Sergey> + psergey: what doe the next line do:vv initially there were no writeinfo Sergey> + calls! Sergey> + */ Sergey> + fast_mi_writeinfo(info); The original code had a bug. At start of mi_rkey.c we do fast_mi_readinfo(), which must be followed by a fast_mi_writeinfo() before return, which didn't happen if buf was 0. In the normal case 'read_record()' will do the fast_mi_writeinfo() call for the other cases. Sergey> + if (!buf) Sergey> + DBUG_RETURN(my_errno); Sergey> + } Sergey> else Sergey> + /* Calculate length of the found key; Used by mi_rnext_same */ Sergey> + if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg) Sergey> + info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey, Sergey> + last_used_keyseg); Sergey> + Sergey> + /* Check if we don't want to have record back, only error message */ Sergey> + if (!buf) Sergey> + DBUG_RETURN(0); We have to add fast_mi_writeinfo(info) before the DBUG_RETURN above. Sergey> + if (!(*info->read_record)(info,info->lastpos,buf)) Sergey> + { Sergey> + info->update|= HA_STATE_AKTIV; /* Record is read */ Sergey> + DBUG_RETURN(0); Sergey> + } <cut> Sergey> +my_bool mi_yield_and_check_if_killed(MI_INFO *info, int inx) Sergey> +{ Sergey> + MYISAM_SHARE *share; Sergey> + if (mi_killed(info)) Sergey> + { Sergey> + info->lastpos= HA_OFFSET_ERROR; Sergey> + my_errno= HA_ERR_KEY_NOT_FOUND; HA_ERR_KEY_NOT_FOUND -> HA_ERR_ABORTED_BY_USER Sergey> + return 1; Sergey> + } Sergey> + Sergey> + if ((share= info->s)->concurrent_insert) Sergey> + { Sergey> + /* Give writers a chance to access index */ Sergey> + rw_unlock(&share->key_root_lock[inx]); Sergey> + rw_rdlock(&share->key_root_lock[inx]); Sergey> + } Sergey> + return 0; Sergey> +} Sergey> === modified file 'storage/myisam/mi_rnext.c' Sergey> --- a/storage/myisam/mi_rnext.c 2010-06-26 10:05:41 +0000 Sergey> +++ b/storage/myisam/mi_rnext.c 2011-02-01 23:33:14 +0000 Sergey> @@ -104,6 +104,18 @@ Sergey> (info->index_cond_func && Sergey> (res= mi_check_index_cond(info, inx, buf)) == ICP_NO_MATCH)) Sergey> { Sergey> + /* Sergey> + If we are at the last key on the key page, allow writers to Sergey> + access the index. Sergey> + */ Sergey> + if (info->int_keypos >= info->int_maxpos && Sergey> + mi_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + error= 0; Sergey> + res= ICP_ERROR; Return a real error! Sergey> + break; Sergey> + } Sergey> + Sergey> /* Sergey> Skip rows that are either inserted by other threads since Sergey> we got a lock or do not match pushed index conditions Sergey> @@ -115,7 +127,8 @@ Sergey> info->s->state.key_root[inx]))) Sergey> break; Sergey> } Sergey> - if (!error && res == ICP_OUT_OF_RANGE) Sergey> + Sergey> + if (!error && (res == ICP_OUT_OF_RANGE || res == ICP_ERROR)) Sergey> { Sergey> if (info->s->concurrent_insert) Sergey> rw_unlock(&info->s->key_root_lock[inx]); Return error code in case of ICP_ERROR Sergey> === modified file 'storage/myisam/mi_rnext_same.c' Sergey> --- a/storage/myisam/mi_rnext_same.c 2009-12-22 12:33:21 +0000 Sergey> +++ b/storage/myisam/mi_rnext_same.c 2011-02-01 23:33:14 +0000 Sergey> @@ -63,6 +63,18 @@ Sergey> } Sergey> for (;;) Sergey> { Sergey> + /* Sergey> + If we are at the last key on the key page, allow writers to Sergey> + access the index. Sergey> + */ Sergey> + if (info->int_keypos >= info->int_maxpos && Sergey> + mi_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + error=1; Sergey> + buf= 0; /* Fast abort */ Sergey> + break; Return real error Sergey> + } Sergey> + Sergey> if ((error=_mi_search_next(info,keyinfo,info->lastkey, Sergey> info->lastkey_length,SEARCH_BIGGER, Sergey> info->s->state.key_root[inx]))) Sergey> @@ -87,6 +99,10 @@ Sergey> } Sergey> if (info->s->concurrent_insert) Sergey> rw_unlock(&info->s->key_root_lock[inx]); Sergey> + Sergey> + if (!buf) Sergey> + DBUG_RETURN(my_errno); Sergey> + Remove above; We have to update info->update even if buf is 0 Sergey> /* Don't clear if database-changed */ Sergey> info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); Sergey> info->update|= HA_STATE_NEXT_FOUND | HA_STATE_RNEXT_SAME; Sergey> === modified file 'storage/myisam/mi_rprev.c' Sergey> --- a/storage/myisam/mi_rprev.c 2009-12-15 07:16:46 +0000 Sergey> +++ b/storage/myisam/mi_rprev.c 2011-02-01 23:33:14 +0000 Sergey> @@ -53,12 +53,28 @@ Sergey> if (!error) Sergey> { Sergey> - int res= 0; Sergey> + ICP_RESULT res= 0; Sergey> + my_off_t cur_keypage= info->last_keypage; Sergey> while ((share->concurrent_insert && Sergey> info->lastpos >= info->state->data_file_length) || Sergey> (info->index_cond_func && Sergey> !(res= mi_check_index_cond(info, inx, buf)))) Sergey> { Sergey> + /* Sergey> + If we are at the last (i.e. first?) key on the key page, Sergey> + allow writers to access the index. Sergey> + */ Sergey> + if (info->last_keypage != cur_keypage) Sergey> + { Sergey> + cur_keypage= info->last_keypage; Sergey> + if (mi_yield_and_check_if_killed(info, inx)) Sergey> + { Sergey> + error= 0; Sergey> + res= ICP_ERROR; Sergey> + break; Return error Sergey> + } Sergey> + } Sergey> + Sergey> /* Sergey> Skip rows that are either inserted by other threads since Sergey> we got a lock or do not match pushed index conditions Sergey> @@ -69,7 +85,7 @@ Sergey> share->state.key_root[inx]))) Sergey> break; Sergey> } Sergey> - if (!error && res == 2) Sergey> + if (!error && (res == ICP_OUT_OF_RANGE || res == ICP_ERROR)) Sergey> { Sergey> if (share->concurrent_insert) Sergey> rw_unlock(&share->key_root_lock[inx]); Return error code in case of ICP_ERROR <cut> Sergey> --- a/storage/xtradb/handler/ha_innodb.cc 2011-01-12 12:00:10 +0000 Sergey> +++ b/storage/xtradb/handler/ha_innodb.cc 2011-02-01 23:33:14 +0000 <cut> Sergey> @@ -12094,15 +12102,18 @@ Sergey> See note on ICP_RESULT for return values description. Sergey> */ Sergey> -static int index_cond_func_innodb(void *arg) Sergey> +static xtradb_icp_result_t index_cond_func_innodb(void *arg) Sergey> { Sergey> ha_innobase *h= (ha_innobase*)arg; Sergey> + if (h->is_thd_killed()) Sergey> + return XTRADB_ICP_ERROR; Sergey> + rename to XTRADB_ABORTED_BY_USER; Sergey> if (h->end_range) Sergey> { Sergey> if (h->compare_key2(h->end_range) > 0) Sergey> - return ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */ Sergey> + return XTRADB_ICP_OUT_OF_RANGE; /* caller should return HA_ERR_END_OF_FILE already */ Sergey> } Sergey> - return h->pushed_idx_cond->val_int()? ICP_MATCH : ICP_NO_MATCH; Sergey> + return h->pushed_idx_cond->val_int()? XTRADB_ICP_MATCH : XTRADB_ICP_NO_MATCH; Sergey> } Sergey> C_MODE_END <cut> Sergey> --- a/storage/xtradb/include/row0mysql.h 2010-12-06 08:25:44 +0000 Sergey> +++ b/storage/xtradb/include/row0mysql.h 2011-02-01 23:33:14 +0000 Sergey> @@ -577,7 +577,15 @@ Sergey> #define ROW_PREBUILT_ALLOCATED 78540783 Sergey> #define ROW_PREBUILT_FREED 26423527 Sergey> -typedef int (*index_cond_func_t)(void *param); Sergey> + Sergey> +typedef enum xtradb_icp_result { Sergey> + XTRADB_ICP_ERROR=-1, rename to XTRADB_ABORTED_BY_USER Sergey> + XTRADB_ICP_NO_MATCH=0, Sergey> + XTRADB_ICP_MATCH=1, Sergey> + XTRADB_ICP_OUT_OF_RANGE=2 Sergey> +} xtradb_icp_result_t; Sergey> + Sergey> +typedef xtradb_icp_result_t (*index_cond_func_t)(void *param); Sergey> /** A struct for (sometimes lazily) prebuilt structures in an Innobase table Sergey> handle used within MySQL; these are used to save CPU time. */ Sergey> === modified file 'storage/xtradb/row/row0sel.c' Sergey> --- a/storage/xtradb/row/row0sel.c 2010-12-06 17:44:17 +0000 Sergey> +++ b/storage/xtradb/row/row0sel.c 2011-02-01 23:33:14 +0000 Sergey> @@ -4396,12 +4396,13 @@ Sergey> */ Sergey> ut_ad(ib_res); Sergey> res= prebuilt->idx_cond_func(prebuilt->idx_cond_func_arg); Sergey> - if (res == 0) Sergey> + if (res == XTRADB_ICP_NO_MATCH) Sergey> goto next_rec; Sergey> - if (res == 2) { Sergey> + if (res == XTRADB_ICP_OUT_OF_RANGE || res == XTRADB_ICP_ERROR) { Sergey> err = DB_RECORD_NOT_FOUND; Sergey> goto idx_cond_failed; Don't return DB_RECORD_NOT_FOUND in case of XTRADB_ICP_ERROR. Return an actual error like DB_ABORTED_BY_USER which can be translated to HA_ERR_ABORTED_BY_USER. Regards, Monty