Applied InnoDB snapshot innodb-5.1-ss2093

Fixes the following bug:

- Bug #32125: Database crash due to ha_innodb.cc:3896: ulint convert_search_mode_to_innobase

  When unknown find_flag is encountered in convert_search_mode_to_innobase()
  do not call assert(0); instead queue a MySQL error using my_error() and
  return the error code PAGE_CUR_UNSUPP. Change the functions that call
  convert_search_mode_to_innobase() to handle that error code by "canceling"
  execution and returning appropriate error code further upstream.
parent f4d05a3c
...@@ -84,16 +84,6 @@ innobase_convert_from_id( ...@@ -84,16 +84,6 @@ innobase_convert_from_id(
ulint len); /* in: length of 'to', in bytes; ulint len); /* in: length of 'to', in bytes;
should be at least 3 * strlen(to) + 1 */ should be at least 3 * strlen(to) + 1 */
/********************************************************************** /**********************************************************************
Removes the filename encoding of a table or database name.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
extern
void
innobase_convert_from_filename(
/*===========================*/
char* s); /* in: identifier; out: decoded identifier */
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively. Compares NUL-terminated UTF-8 strings case insensitively.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
......
...@@ -679,6 +679,9 @@ convert_error_code_to_mysql( ...@@ -679,6 +679,9 @@ convert_error_code_to_mysql(
return(HA_ERR_RECORD_FILE_FULL); return(HA_ERR_RECORD_FILE_FULL);
#endif #endif
} else if (error == DB_UNSUPPORTED) {
return(HA_ERR_UNSUPPORTED);
} else { } else {
return(-1); // Unknown error return(-1); // Unknown error
} }
...@@ -801,23 +804,6 @@ innobase_convert_from_id( ...@@ -801,23 +804,6 @@ innobase_convert_from_id(
system_charset_info, to, (uint) len, &errors); system_charset_info, to, (uint) len, &errors);
} }
/**********************************************************************
Removes the filename encoding of a table or database name.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_filename(
/*===========================*/
char* s) /* in: identifier; out: decoded identifier */
{
uint errors;
strconvert(&my_charset_filename, s,
system_charset_info, s, strlen(s), &errors);
}
/********************************************************************** /**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively. Compares NUL-terminated UTF-8 strings case insensitively.
...@@ -3962,33 +3948,51 @@ convert_search_mode_to_innobase( ...@@ -3962,33 +3948,51 @@ convert_search_mode_to_innobase(
enum ha_rkey_function find_flag) enum ha_rkey_function find_flag)
{ {
switch (find_flag) { switch (find_flag) {
case HA_READ_KEY_EXACT: return(PAGE_CUR_GE); case HA_READ_KEY_EXACT:
/* the above does not require the index to be UNIQUE */ /* this does not require the index to be UNIQUE */
case HA_READ_KEY_OR_NEXT: return(PAGE_CUR_GE); return(PAGE_CUR_GE);
case HA_READ_KEY_OR_PREV: return(PAGE_CUR_LE); case HA_READ_KEY_OR_NEXT:
case HA_READ_AFTER_KEY: return(PAGE_CUR_G); return(PAGE_CUR_GE);
case HA_READ_BEFORE_KEY: return(PAGE_CUR_L); case HA_READ_KEY_OR_PREV:
case HA_READ_PREFIX: return(PAGE_CUR_GE); return(PAGE_CUR_LE);
case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE); case HA_READ_AFTER_KEY:
case HA_READ_PREFIX_LAST_OR_PREV:return(PAGE_CUR_LE); return(PAGE_CUR_G);
/* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always case HA_READ_BEFORE_KEY:
pass a complete-field prefix of a key value as the search return(PAGE_CUR_L);
tuple. I.e., it is not allowed that the last field would case HA_READ_PREFIX:
just contain n first bytes of the full field value. return(PAGE_CUR_GE);
MySQL uses a 'padding' trick to convert LIKE 'abc%' case HA_READ_PREFIX_LAST:
type queries so that it can use as a search tuple return(PAGE_CUR_LE);
a complete-field-prefix of a key value. Thus, the InnoDB case HA_READ_PREFIX_LAST_OR_PREV:
search mode PAGE_CUR_LE_OR_EXTENDS is never used. return(PAGE_CUR_LE);
TODO: when/if MySQL starts to use also partial-field /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
prefixes, we have to deal with stripping of spaces pass a complete-field prefix of a key value as the search
and comparison of non-latin1 char type fields in tuple. I.e., it is not allowed that the last field would
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to just contain n first bytes of the full field value.
work correctly. */ MySQL uses a 'padding' trick to convert LIKE 'abc%'
type queries so that it can use as a search tuple
default: assert(0); a complete-field-prefix of a key value. Thus, the InnoDB
} search mode PAGE_CUR_LE_OR_EXTENDS is never used.
TODO: when/if MySQL starts to use also partial-field
return(0); prefixes, we have to deal with stripping of spaces
and comparison of non-latin1 char type fields in
innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
work correctly. */
case HA_READ_MBR_CONTAIN:
case HA_READ_MBR_INTERSECT:
case HA_READ_MBR_WITHIN:
case HA_READ_MBR_DISJOINT:
case HA_READ_MBR_EQUAL:
my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0));
return(PAGE_CUR_UNSUPP);
/* do not use "default:" in order to produce a gcc warning:
enumeration value '...' not handled in switch
(if -Wswitch or -Wall is used) */
}
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
return(PAGE_CUR_UNSUPP);
} }
/* /*
...@@ -4116,11 +4120,18 @@ ha_innobase::index_read( ...@@ -4116,11 +4120,18 @@ ha_innobase::index_read(
last_match_mode = (uint) match_mode; last_match_mode = (uint) match_mode;
innodb_srv_conc_enter_innodb(prebuilt->trx); if (mode != PAGE_CUR_UNSUPP) {
ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0); innodb_srv_conc_enter_innodb(prebuilt->trx);
innodb_srv_conc_exit_innodb(prebuilt->trx); ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
match_mode, 0);
innodb_srv_conc_exit_innodb(prebuilt->trx);
} else {
ret = DB_UNSUPPORTED;
}
if (ret == DB_SUCCESS) { if (ret == DB_SUCCESS) {
error = 0; error = 0;
...@@ -5470,8 +5481,16 @@ ha_innobase::records_in_range( ...@@ -5470,8 +5481,16 @@ ha_innobase::records_in_range(
mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag : mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
HA_READ_KEY_EXACT); HA_READ_KEY_EXACT);
n_rows = btr_estimate_n_rows_in_range(index, range_start, if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
mode1, range_end, mode2);
n_rows = btr_estimate_n_rows_in_range(index, range_start,
mode1, range_end,
mode2);
} else {
n_rows = 0;
}
dtuple_free_for_mysql(heap1); dtuple_free_for_mysql(heap1);
dtuple_free_for_mysql(heap2); dtuple_free_for_mysql(heap2);
......
...@@ -22,6 +22,7 @@ Created 10/4/1994 Heikki Tuuri ...@@ -22,6 +22,7 @@ Created 10/4/1994 Heikki Tuuri
/* Page cursor search modes; the values must be in this order! */ /* Page cursor search modes; the values must be in this order! */
#define PAGE_CUR_UNSUPP 0
#define PAGE_CUR_G 1 #define PAGE_CUR_G 1
#define PAGE_CUR_GE 2 #define PAGE_CUR_GE 2
#define PAGE_CUR_L 3 #define PAGE_CUR_L 3
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment