diff options
author | unknown <monty@mysql.com> | 2004-11-04 15:06:24 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2004-11-04 15:06:24 +0200 |
commit | 70d66da883b1d4bc5a9c22737461aba40023d8ff (patch) | |
tree | 9d4d27a72c18ead47fb83bd5ec0e2383cdd34ff6 /sql | |
parent | f662de31e8441a4803b3487ef264a35695820a77 (diff) | |
parent | c9a75ccf1acfc4578496a1606fcf009301366997 (diff) | |
download | mariadb-git-70d66da883b1d4bc5a9c22737461aba40023d8ff.tar.gz |
Merge with 4.1 to get in latest bug fixes
BitKeeper/etc/logging_ok:
auto-union
Docs/Support/texi2html:
Auto merged
include/mysql.h:
Auto merged
include/mysql_com.h:
Auto merged
libmysql/libmysql.c:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/myisamchk.c:
Auto merged
mysql-test/include/ps_modify.inc:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/r/ctype_recoding.result:
Auto merged
mysql-test/r/fulltext.result:
Auto merged
mysql-test/r/gis.result:
Auto merged
mysql-test/r/ndb_blob.result:
Auto merged
mysql-test/r/ps_2myisam.result:
Auto merged
mysql-test/r/ps_3innodb.result:
Auto merged
mysql-test/r/ps_4heap.result:
Auto merged
mysql-test/r/ps_5merge.result:
Auto merged
mysql-test/r/ps_6bdb.result:
Auto merged
mysql-test/r/sql_mode.result:
Auto merged
mysql-test/t/join_outer.test:
Auto merged
mysql-test/t/key.test:
Auto merged
mysql-test/t/range.test:
Auto merged
mysql-test/t/show_check.test:
Auto merged
mysql-test/t/sql_mode.test:
Auto merged
sql/field.cc:
Auto merged
sql/ha_ndbcluster.cc:
Auto merged
sql/ha_ndbcluster.h:
Auto merged
sql/item.h:
Auto merged
sql/item_create.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/item_strfunc.cc:
Auto merged
sql/item_timefunc.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/net_serv.cc:
Auto merged
sql/protocol.cc:
Auto merged
sql/protocol.h:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_handler.cc:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_string.cc:
Auto merged
sql/sql_string.h:
Auto merged
sql/sql_table.cc:
Auto merged
client/mysqltest.c:
Merge with 4.1
mysql-test/r/range.result:
Merge with 4.1
Added missing drop table test
sql/ha_innodb.cc:
Merge with 4.1
sql/item.cc:
Merge with 4.1
sql/item_cmpfunc.cc:
Merge with 4.1
sql/opt_range.cc:
Merge with 4.1
sql/sql_prepare.cc:
Merge with 4.1
tests/client_test.c:
Merge with 4.1
Added code to support --silent
configure.in:
Merge with 4.1
ndb/src/common/util/version.c:
Merge with 4.1
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 19 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 24 | ||||
-rw-r--r-- | sql/ha_ndbcluster.h | 1 | ||||
-rw-r--r-- | sql/item.cc | 126 | ||||
-rw-r--r-- | sql/item.h | 28 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 87 | ||||
-rw-r--r-- | sql/item_create.cc | 5 | ||||
-rw-r--r-- | sql/item_func.cc | 114 | ||||
-rw-r--r-- | sql/item_func.h | 7 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 6 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 74 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 4 | ||||
-rw-r--r-- | sql/mysqld.cc | 9 | ||||
-rw-r--r-- | sql/net_serv.cc | 12 | ||||
-rw-r--r-- | sql/opt_range.cc | 15 | ||||
-rw-r--r-- | sql/protocol.cc | 12 | ||||
-rw-r--r-- | sql/protocol.h | 1 | ||||
-rw-r--r-- | sql/spatial.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.cc | 6 | ||||
-rw-r--r-- | sql/sql_parse.cc | 20 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 17 | ||||
-rw-r--r-- | sql/sql_show.cc | 12 | ||||
-rw-r--r-- | sql/sql_string.cc | 28 | ||||
-rw-r--r-- | sql/sql_string.h | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 16 | ||||
-rw-r--r-- | sql/thr_malloc.cc | 5 |
26 files changed, 445 insertions, 211 deletions
diff --git a/sql/field.cc b/sql/field.cc index 7a8f59c25fe..1275e1bbb8e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -547,7 +547,8 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) /* Convert character set if the old one is multi byte */ if (cs->mbmaxlen > 1) { - tmp.copy(from, len, cs, &my_charset_bin); + uint dummy_errors; + tmp.copy(from, len, cs, &my_charset_bin, &dummy_errors); from= tmp.ptr(); len= tmp.length(); } @@ -4444,6 +4445,7 @@ void Field_string::sort_string(char *to,uint length) void Field_string::sql_type(String &res) const { + THD *thd= table->in_use; CHARSET_INFO *cs=res.charset(); ulong length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(), "%s(%d)", @@ -4454,6 +4456,9 @@ void Field_string::sql_type(String &res) const (has_charset() ? "char" : "binary")), (int) field_length / charset()->mbmaxlen); res.length(length); + if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) && + has_charset() && (charset()->state & MY_CS_BINSORT)) + res.append(" binary"); } char *Field_string::pack(char *to, const char *from, uint max_length) @@ -5530,7 +5535,8 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) /* Convert character set if nesessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { - tmpstr.copy(from, length, cs, field_charset); + uint dummy_errors; + tmpstr.copy(from, length, cs, field_charset, &dummy_errors); from= tmpstr.ptr(); length= tmpstr.length(); } @@ -5678,10 +5684,11 @@ void Field_enum::sql_type(String &res) const bool flag=0; for (const char **pos= typelib->type_names; *pos; pos++) { + uint dummy_errors; if (flag) res.append(','); /* convert to res.charset() == utf8, then quote */ - enum_item.copy(*pos, strlen(*pos), charset(), res.charset()); + enum_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors); append_unescaped(&res, enum_item.ptr(), enum_item.length()); flag= 1; } @@ -5712,7 +5719,8 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) /* Convert character set if nesessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used_offset)) { - tmpstr.copy(from, length, cs, field_charset); + uint dummy_errors; + tmpstr.copy(from, length, cs, field_charset, &dummy_errors); from= tmpstr.ptr(); length= tmpstr.length(); } @@ -5788,10 +5796,11 @@ void Field_set::sql_type(String &res) const bool flag=0; for (const char **pos= typelib->type_names; *pos; pos++) { + uint dummy_errors; if (flag) res.append(','); /* convert to res.charset() == utf8, then quote */ - set_item.copy(*pos, strlen(*pos), charset(), res.charset()); + set_item.copy(*pos, strlen(*pos), charset(), res.charset(), &dummy_errors); append_unescaped(&res, set_item.ptr(), set_item.length()); flag= 1; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 7878684718c..ebbbaf8acc8 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1393,8 +1393,13 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, // Set bound if not cancelled via type -1 if (p.bound_type != -1) - if (op->setBound(field->field_name, p.bound_type, p.bound_ptr)) + { + char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE]; + strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name)); + truncated_field_name[sizeof(truncated_field_name)-1]= '\0'; + if (op->setBound(truncated_field_name, p.bound_type, p.bound_ptr)) ERR_RETURN(op->getNdbError()); + } } } @@ -2653,7 +2658,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) m_use_write= TRUE; } else { - m_ignore_dup_key_not_supported= TRUE; + if (table->keys) + m_ignore_dup_key_not_supported= TRUE; } break; case HA_EXTRA_NO_IGNORE_DUP_KEY: @@ -3112,7 +3118,12 @@ static int create_ndb_column(NDBCOL &col, HA_CREATE_INFO *info) { // Set name - col.setName(field->field_name); + { + char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE]; + strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name)); + truncated_field_name[sizeof(truncated_field_name)-1]= '\0'; + col.setName(truncated_field_name); + } // Get char set CHARSET_INFO *cs= field->charset(); // Set type and sizes @@ -3440,7 +3451,12 @@ int ha_ndbcluster::create_index(const char *name, { Field *field= key_part->field; DBUG_PRINT("info", ("attr: %s", field->field_name)); - ndb_index.addColumnName(field->field_name); + { + char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE]; + strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name)); + truncated_field_name[sizeof(truncated_field_name)-1]= '\0'; + ndb_index.addColumnName(truncated_field_name); + } } if (dict->createIndex(ndb_index)) diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 245d906c5ae..fc1e4390adb 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -26,7 +26,6 @@ #endif #include <ndbapi_limits.h> -#include <ndb_types.h> class Ndb; // Forward declaration class NdbOperation; // Forward declaration diff --git a/sql/item.cc b/sql/item.cc index 6730b0dd4a2..1f90b1842ac 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -261,6 +261,41 @@ bool Item::eq(const Item *item, bool binary_cmp) const } +Item *Item::safe_charset_converter(CHARSET_INFO *tocs) +{ + /* + Don't allow automatic conversion to non-Unicode charsets, + as it potentially loses data. + */ + if (!(tocs->state & MY_CS_UNICODE)) + return NULL; // safe conversion is not possible + return new Item_func_conv_charset(this, tocs); +} + + +Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) +{ + Item_string *conv; + uint conv_errors; + String tmp, cstr, *ostr= val_str(&tmp); + cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors); + if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(), + cstr.charset(), + collation.derivation))) + { + /* + Safe conversion is not possible (or EOM). + We could not convert a string into the requested character set + without data loss. The target charset does not cover all the + characters from the string. Operation cannot be done correctly. + */ + return NULL; + } + conv->str_value.copy(); + return conv; +} + + bool Item_string::eq(const Item *item, bool binary_cmp) const { if (type() == item->type()) @@ -355,7 +390,43 @@ Item_splocal::type() const } -bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion) + +/* + Aggregate two collations together taking + into account their coercibility (aka derivation): + + 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause + 1 == DERIVATION_NONE - a mix of two different collations + 2 == DERIVATION_IMPLICIT - a column + 3 == DERIVATION_COERCIBLE - a string constant + + The most important rules are: + + 1. If collations are the same: + chose this collation, and the strongest derivation. + + 2. If collations are different: + - Character sets may differ, but only if conversion without + data loss is possible. The caller provides flags whether + character set conversion attempts should be done. If no + flags are substituted, then the character sets must be the same. + Currently processed flags are: + MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset + MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value + - two EXPLICIT collations produce an error, e.g. this is wrong: + CONCAT(expr1 collate latin1_swedish_ci, expr2 collate latin1_german_ci) + - the side with smaller derivation value wins, + i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column. + - if derivations are the same, we have DERIVATION_NONE, + we'll wait for an explicit COLLATE clause which possibly can + come from another argument later: for example, this is valid, + but we don't know yet when collecting the first two arguments: + CONCAT(latin1_swedish_ci_column, + latin1_german1_ci_column, + expr COLLATE latin1_german2_ci) +*/ +bool DTCollation::aggregate(DTCollation &dt, uint flags) { nagg++; if (!my_charset_same(collation, dt.collation)) @@ -386,28 +457,37 @@ bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion) else ; // Do nothing } - else if (superset_conversion) + else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && + derivation < dt.derivation && + collation->state & MY_CS_UNICODE) { - if (derivation < dt.derivation && - collation->state & MY_CS_UNICODE) - ; // Do nothing - else if (dt.derivation < derivation && - dt.collation->state & MY_CS_UNICODE) - { - set(dt); - strong= nagg; - } - else - { - // Cannot convert to superset - set(0, DERIVATION_NONE); - return 1; - } + // Do nothing + } + else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && + dt.derivation < derivation && + dt.collation->state & MY_CS_UNICODE) + { + set(dt); + strong= nagg; + } + else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) && + derivation < dt.derivation && + dt.derivation == DERIVATION_COERCIBLE) + { + // Do nothing; + } + else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) && + dt.derivation < derivation && + derivation == DERIVATION_COERCIBLE) + { + set(dt); + strong= nagg; } else { + // Cannot apply conversion set(0, DERIVATION_NONE); - return 1; + return 1; } } else if (derivation < dt.derivation) @@ -830,6 +910,12 @@ String *Item_null::val_str(String *str) } +Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs) +{ + collation.set(tocs); + return this; +} + /*********************** Item_param related ******************************/ /* @@ -925,7 +1011,9 @@ bool Item_param::set_str(const char *str, ulong length) Assign string with no conversion: data is converted only after it's been written to the binary log. */ - if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin)) + uint dummy_errors; + if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin, + &dummy_errors)) DBUG_RETURN(TRUE); state= STRING_VALUE; maybe_null= 0; diff --git a/sql/item.h b/sql/item.h index d3e53af1523..11aeb22b6e5 100644 --- a/sql/item.h +++ b/sql/item.h @@ -38,6 +38,25 @@ enum Derivation DERIVATION_EXPLICIT= 0 }; +/* + Flags for collation aggregation modes: + MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset + MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value + (i.e. constant). + MY_COLL_ALLOW_CONV - allow any kind of conversion + (combintion of the above two) + MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE + (e.g. when aggregating for comparison) + MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV + and MY_COLL_DISALLOW_NONE +*/ + +#define MY_COLL_ALLOW_SUPERSET_CONV 1 +#define MY_COLL_ALLOW_COERCIBLE_CONV 2 +#define MY_COLL_ALLOW_CONV 3 +#define MY_COLL_DISALLOW_NONE 4 +#define MY_COLL_CMP_CONV 7 + class DTCollation { public: CHARSET_INFO *collation; @@ -73,9 +92,9 @@ public: { collation= collation_arg; } void set(Derivation derivation_arg) { derivation= derivation_arg; } - bool aggregate(DTCollation &dt, bool superset_conversion= FALSE); - bool set(DTCollation &dt1, DTCollation &dt2, bool superset_conversion= FALSE) - { set(dt1); return aggregate(dt2, superset_conversion); } + bool aggregate(DTCollation &dt, uint flags= 0); + bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0) + { set(dt1); return aggregate(dt2, flags); } const char *derivation_name() const { switch(derivation) @@ -305,6 +324,7 @@ public: virtual Item_field *filed_for_view_update() { return 0; } virtual Item *neg_transformer(THD *thd) { return NULL; } + virtual Item *safe_charset_converter(CHARSET_INFO *tocs); void delete_self() { cleanup(); @@ -572,6 +592,7 @@ public: Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } void print(String *str) { str->append("NULL", 4); } + Item *safe_charset_converter(CHARSET_INFO *tocs); }; @@ -861,6 +882,7 @@ public: return new Item_string(name, str_value.ptr(), str_value.length(), &my_charset_bin); } + Item *safe_charset_converter(CHARSET_INFO *tocs); String *const_string() { return &str_value; } inline void append(char *str, uint length) { str_value.append(str, length); } void print(String *str); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 467cd8313a4..b08a6fcd2e6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -185,55 +185,14 @@ void Item_bool_func2::fix_length_and_dec() to the collation of A. */ - if (args[0] && args[1]) - { - uint strong= 0; - uint weak= 0; - uint32 dummy_offset; - DTCollation coll; - - if (args[0]->result_type() == STRING_RESULT && - args[1]->result_type() == STRING_RESULT && - String::needs_conversion(0, args[0]->collation.collation, - args[1]->collation.collation, - &dummy_offset) && - !coll.set(args[0]->collation, args[1]->collation, TRUE)) - { - Item* conv= 0; - Item_arena *arena= thd->current_arena, backup; - strong= coll.strong; - weak= strong ? 0 : 1; - /* - In case we're in statement prepare, create conversion item - in its memory: it will be reused on each execute. - */ - if (arena->is_stmt_prepare()) - thd->set_n_backup_item_arena(arena, &backup); - if (args[weak]->type() == STRING_ITEM) - { - String tmp, cstr; - String *ostr= args[weak]->val_str(&tmp); - cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), - args[strong]->collation.collation); - conv= new Item_string(cstr.ptr(),cstr.length(),cstr.charset(), - args[weak]->collation.derivation); - ((Item_string*)conv)->str_value.copy(); - } - else - { - conv= new Item_func_conv_charset(args[weak], - args[strong]->collation.collation); - conv->collation.set(args[weak]->collation.derivation); - conv->fix_fields(thd, 0, &conv); - } - if (arena->is_stmt_prepare()) - thd->restore_backup_item_arena(arena, &backup); - if (args[weak]->type() == FIELD_ITEM) - ((Item_field *)args[weak])->no_const_subst= 1; - args[weak]= conv ? conv : args[weak]; - } - } + DTCollation coll; + if (args[0]->result_type() == STRING_RESULT && + args[1]->result_type() == STRING_RESULT && + agg_arg_charsets(coll, args, 2, MY_COLL_CMP_CONV)) + return; + + // Make a special case of compare with fields to get nicer DATE comparisons if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function. @@ -859,7 +818,7 @@ void Item_func_between::fix_length_and_dec() return; agg_cmp_type(&cmp_type, args, 3); if (cmp_type == STRING_RESULT && - agg_arg_collations_for_comparison(cmp_collation, args, 3)) + agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV)) return; /* @@ -975,7 +934,7 @@ Item_func_ifnull::fix_length_and_dec() decimals=max(args[0]->decimals,args[1]->decimals); agg_result_type(&cached_result_type, args, 2); if (cached_result_type == STRING_RESULT) - agg_arg_collations(collation, args, arg_count); + agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); else if (cached_result_type != REAL_RESULT) decimals= 0; @@ -1071,8 +1030,8 @@ Item_func_if::fix_length_and_dec() agg_result_type(&cached_result_type, args+1, 2); if (cached_result_type == STRING_RESULT) { - if (agg_arg_collations(collation, args+1, 2)) - return; + if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV)) + return; } else { @@ -1331,8 +1290,10 @@ void Item_func_case::fix_length_and_dec() if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; - // Aggregate all THEN and ELSE expression types - // and collations when string result + /* + Aggregate all THEN and ELSE expression types + and collations when string result + */ for (nagg= 0 ; nagg < ncases/2 ; nagg++) agg[nagg]= args[nagg*2+1]; @@ -1342,7 +1303,7 @@ void Item_func_case::fix_length_and_dec() agg_result_type(&cached_result_type, agg, nagg); if ((cached_result_type == STRING_RESULT) && - agg_arg_collations(collation, agg, nagg)) + agg_arg_charsets(collation, agg, nagg, MY_COLL_ALLOW_CONV)) return; @@ -1358,7 +1319,7 @@ void Item_func_case::fix_length_and_dec() nagg++; agg_cmp_type(&cmp_type, agg, nagg); if ((cmp_type == STRING_RESULT) && - agg_arg_collations_for_comparison(cmp_collation, agg, nagg)) + agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV)) return; } @@ -1465,7 +1426,7 @@ void Item_func_coalesce::fix_length_and_dec() set_if_bigger(decimals,args[i]->decimals); } if (cached_result_type == STRING_RESULT) - agg_arg_collations(collation, args, arg_count); + agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV); else if (cached_result_type != REAL_RESULT) decimals= 0; } @@ -1795,14 +1756,13 @@ void Item_func_in::fix_length_and_dec() via creating Item_func_conv_charset(). */ - if (agg_arg_collations_for_comparison(cmp_collation, - args, arg_count, TRUE)) + if (agg_arg_collations_for_comparison(cmp_collation, args, arg_count, + MY_COLL_ALLOW_SUPERSET_CONV)) return; if ((!my_charset_same(args[0]->collation.collation, cmp_collation.collation) || !const_itm)) { - if (agg_arg_collations_for_comparison(cmp_collation, - args, arg_count, FALSE)) + if (agg_arg_collations_for_comparison(cmp_collation, args, arg_count)) return; } else @@ -1821,8 +1781,9 @@ void Item_func_in::fix_length_and_dec() { Item_string *conv; String tmp, cstr, *ostr= arg[0]->val_str(&tmp); + uint dummy_errors; cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), - cmp_collation.collation); + cmp_collation.collation, &dummy_errors); conv= new Item_string(cstr.ptr(),cstr.length(), cstr.charset(), arg[0]->collation.derivation); conv->str_value.copy(); @@ -2449,7 +2410,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) max_length= 1; decimals= 0; - if (agg_arg_collations(cmp_collation, args, 2)) + if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV)) return 1; used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); diff --git a/sql/item_create.cc b/sql/item_create.cc index e21364045ba..cec6de3eede 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -370,7 +370,10 @@ Item *create_func_space(Item *a) { sp= new Item_string("",0,cs); if (sp) - sp->str_value.copy(" ",1,&my_charset_latin1,cs); + { + uint dummy_errors; + sp->str_value.copy(" ", 1, &my_charset_latin1, cs, &dummy_errors); + } } else { diff --git a/sql/item_func.cc b/sql/item_func.cc index 3cc0fd077a4..173b1b3fd82 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -79,7 +79,7 @@ static void my_coll_agg_error(Item** args, uint count, const char *fname) bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count, - bool allow_superset_conversion) + uint flags) { uint i; c.nagg= 0; @@ -87,29 +87,27 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count, c.set(av[0]->collation); for (i= 1; i < count; i++) { - if (c.aggregate(av[i]->collation, allow_superset_conversion)) + if (c.aggregate(av[i]->collation, flags)) { my_coll_agg_error(av, count, func_name()); return TRUE; } } + if ((flags & MY_COLL_DISALLOW_NONE) && + c.derivation == DERIVATION_NONE) + { + my_coll_agg_error(av, count, func_name()); + return TRUE; + } return FALSE; } bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, Item **av, uint count, - bool allow_superset_conv) + uint flags) { - if (agg_arg_collations(c, av, count, allow_superset_conv)) - return TRUE; - - if (c.derivation == DERIVATION_NONE) - { - my_coll_agg_error(av, count, func_name()); - return TRUE; - } - return FALSE; + return (agg_arg_collations(c, av, count, flags | MY_COLL_DISALLOW_NONE)); } @@ -122,6 +120,89 @@ eval_const_cond(COND *cond) } + +/* + Collect arguments' character sets together. + We allow to apply automatic character set conversion in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + (i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column) + - character set of A is either superset for character set of B, + or B is a string constant which can be converted into the + character set of A without data loss. + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + + For functions with more than two arguments: + + collect(A,B,C) ::= collect(collect(A,B),C) +*/ + +bool Item_func::agg_arg_charsets(DTCollation &coll, + Item **args, uint nargs, uint flags) +{ + Item **arg, **last, *safe_args[2]; + if (agg_arg_collations(coll, args, nargs, flags)) + return TRUE; + + /* + For better error reporting: save the first and the second argument. + We need this only if the the number of args is 3 or 2: + - for a longer argument list, "Illegal mix of collations" + doesn't display each argument's characteristics. + - if nargs is 1, then this error cannot happen. + */ + if (nargs >=2 && nargs <= 3) + { + safe_args[0]= args[0]; + safe_args[1]= args[1]; + } + + THD *thd= current_thd; + Item_arena *arena= thd->current_arena, backup; + bool res= FALSE; + /* + In case we're in statement prepare, create conversion item + in its memory: it will be reused on each execute. + */ + if (arena->is_stmt_prepare()) + thd->set_n_backup_item_arena(arena, &backup); + + for (arg= args, last= args + nargs; arg < last; arg++) + { + Item* conv; + uint dummy_offset; + if (!String::needs_conversion(0, coll.collation, + (*arg)->collation.collation, + &dummy_offset)) + continue; + + if (!(conv= (*arg)->safe_charset_converter(coll.collation))) + { + if (nargs >=2 && nargs <= 3) + { + /* restore the original arguments for better error message */ + args[0]= safe_args[0]; + args[1]= safe_args[1]; + } + my_coll_agg_error(args, nargs, func_name()); + res= TRUE; + break; // we cannot return here, we need to restore "arena". + } + conv->fix_fields(thd, 0, &conv); + *arg= conv; + } + if (arena->is_stmt_prepare()) + thd->restore_backup_item_arena(arena, &backup); + return res; +} + + + void Item_func::set_arguments(List<Item> &list) { allowed_arg_cols= 1; @@ -1185,7 +1266,7 @@ void Item_func_min_max::fix_length_and_dec() cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); } if (cmp_type == STRING_RESULT) - agg_arg_collations_for_comparison(collation, args, arg_count); + agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); } @@ -1339,7 +1420,7 @@ longlong Item_func_coercibility::val_int() void Item_func_locate::fix_length_and_dec() { maybe_null=0; max_length=11; - agg_arg_collations_for_comparison(cmp_collation, args, 2); + agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV); } @@ -1438,7 +1519,7 @@ void Item_func_field::fix_length_and_dec() for (uint i=1; i < arg_count ; i++) cmp_type= item_cmp_type(cmp_type, args[i]->result_type()); if (cmp_type == STRING_RESULT) - agg_arg_collations_for_comparison(cmp_collation, args, arg_count); + agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV); } @@ -3003,8 +3084,9 @@ void Item_func_match::init_search(bool no_order) if (ft_tmp->charset() != cmp_collation.collation) { + uint dummy_errors; search_value.copy(ft_tmp->ptr(), ft_tmp->length(), ft_tmp->charset(), - cmp_collation.collation); + cmp_collation.collation, &dummy_errors); ft_tmp= &search_value; } diff --git a/sql/item_func.h b/sql/item_func.h index 3b941c4a40c..602b77ae956 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -146,11 +146,12 @@ public: Item *get_tmp_table_item(THD *thd); bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, - bool allow_superset_conversion= FALSE); + uint flags= 0); bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems, - bool allow_superset_comversion= FALSE); - + uint flags= 0); + bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, + uint flags= 0); bool walk(Item_processor processor, byte *arg); Item *transform(Item_transformer transformer, byte *arg); }; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 935925c1e83..7c3319bbfea 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -148,9 +148,9 @@ String *Item_func_geometry_type::val_str(String *str) swkb->length() - SRID_SIZE))))) return 0; /* String will not move */ - str->set(geom->get_class_info()->m_name.str, - geom->get_class_info()->m_name.length, - default_charset()); + str->copy(geom->get_class_info()->m_name.str, + geom->get_class_info()->m_name.length, + default_charset()); return str; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d015ca36eac..889b00eb6a0 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -346,7 +346,7 @@ void Item_func_concat::fix_length_and_dec() { max_length=0; - if (agg_arg_collations(collation, args, arg_count)) + if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV)) return; for (uint i=0 ; i < arg_count ; i++) @@ -640,10 +640,15 @@ void Item_func_concat_ws::fix_length_and_dec() { max_length=0; - if (agg_arg_collations(collation, args, arg_count)) + if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV)) return; - max_length= arg_count > 1 ? args[0]->max_length * (arg_count - 2) : 0; + /* + arg_count cannot be less than 2, + it is done on parser level in sql_yacc.yy + so, (arg_count - 2) is safe here. + */ + max_length= args[0]->max_length * (arg_count - 2); for (uint i=1 ; i < arg_count ; i++) max_length+=args[i]->max_length; @@ -843,7 +848,7 @@ void Item_func_replace::fix_length_and_dec() maybe_null=1; } - if (agg_arg_collations_for_comparison(collation, args, 3)) + if (agg_arg_charsets(collation, args, 3, MY_COLL_CMP_CONV)) return; } @@ -888,11 +893,13 @@ null: void Item_func_insert::fix_length_and_dec() { - if (collation.set(args[0]->collation, args[3]->collation)) - { - my_coll_agg_error(args[0]->collation, args[3]->collation, func_name()); - return; - } + Item *cargs[2]; + cargs[0]= args[0]; + cargs[1]= args[3]; + if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV)) + return; + args[0]= cargs[0]; + args[3]= cargs[1]; max_length=args[0]->max_length+args[3]->max_length; if (max_length > MAX_BLOB_WIDTH) { @@ -1058,7 +1065,7 @@ void Item_func_substr_index::fix_length_and_dec() { max_length= args[0]->max_length; - if (agg_arg_collations_for_comparison(collation, args, 2)) + if (agg_arg_charsets(collation, args, 2, MY_COLL_CMP_CONV)) return; } @@ -1350,10 +1357,14 @@ void Item_func_trim::fix_length_and_dec() remove.set_ascii(" ",1); } else - if (collation.set(args[1]->collation, args[0]->collation) || - collation.derivation == DERIVATION_NONE) { - my_coll_agg_error(args[1]->collation, args[0]->collation, func_name()); + Item *cargs[2]; + cargs[0]= args[1]; + cargs[1]= args[0]; + if (agg_arg_charsets(collation, cargs, 2, MY_COLL_CMP_CONV)) + return; + args[0]= cargs[1]; + args[1]= cargs[0]; } } @@ -1674,7 +1685,7 @@ void Item_func_elt::fix_length_and_dec() max_length=0; decimals=0; - if (agg_arg_collations(collation, args+1, arg_count-1)) + if (agg_arg_charsets(collation, args+1, arg_count-1, MY_COLL_ALLOW_CONV)) return; for (uint i= 1 ; i < arg_count ; i++) @@ -1750,7 +1761,7 @@ void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - if (agg_arg_collations(collation, args, arg_count)) + if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV)) return; for (uint i=0 ; i < arg_count ; i++) @@ -1958,12 +1969,13 @@ err: void Item_func_rpad::fix_length_and_dec() { - if (collation.set(args[0]->collation, args[2]->collation)) - { - my_coll_agg_error(args[0]->collation, args[2]->collation, func_name()); + Item *cargs[2]; + cargs[0]= args[0]; + cargs[1]= args[2]; + if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV)) return; - } - + args[0]= cargs[0]; + args[2]= cargs[1]; if (args[1]->const_item()) { uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen; @@ -2042,11 +2054,13 @@ String *Item_func_rpad::val_str(String *str) void Item_func_lpad::fix_length_and_dec() { - if (collation.set(args[0]->collation, args[2]->collation)) - { - my_coll_agg_error(args[0]->collation, args[2]->collation, func_name()); + Item *cargs[2]; + cargs[0]= args[0]; + cargs[1]= args[2]; + if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV)) return; - } + args[0]= cargs[0]; + args[2]= cargs[1]; if (args[1]->const_item()) { @@ -2155,13 +2169,14 @@ String *Item_func_conv_charset::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *arg= args[0]->val_str(str); + uint dummy_errors; if (!arg) { null_value=1; return 0; } null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(), - conv_charset); + conv_charset, &dummy_errors); return null_value ? 0 : &str_value; } @@ -2256,11 +2271,12 @@ String *Item_func_charset::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res = args[0]->val_str(str); + uint dummy_errors; if ((null_value=(args[0]->null_value || !res->charset()))) return 0; str->copy(res->charset()->csname,strlen(res->charset()->csname), - &my_charset_latin1, collation.collation); + &my_charset_latin1, collation.collation, &dummy_errors); return str; } @@ -2268,11 +2284,12 @@ String *Item_func_collation::val_str(String *str) { DBUG_ASSERT(fixed == 1); String *res = args[0]->val_str(str); + uint dummy_errors; if ((null_value=(args[0]->null_value || !res->charset()))) return 0; str->copy(res->charset()->name,strlen(res->charset()->name), - &my_charset_latin1, collation.collation); + &my_charset_latin1, collation.collation, &dummy_errors); return str; } @@ -2499,7 +2516,8 @@ void Item_func_export_set::fix_length_and_dec() uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; - if (agg_arg_collations(collation, args+1, min(4,arg_count)-1)) + if (agg_arg_charsets(collation, args+1, min(4,arg_count)-1), + MY_COLL_ALLOW_CONV) return; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 3a25921d84b..fd7a2ea2cb4 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2140,8 +2140,10 @@ String *Item_char_typecast::val_str(String *str) else { // Convert character set if differ + uint dummy_errors; if (!(res1= args[0]->val_str(&tmp_value)) || - str->copy(res1->ptr(), res1->length(),res1->charset(), cast_cs)) + str->copy(res1->ptr(), res1->length(), res1->charset(), + cast_cs, &dummy_errors)) { null_value= 1; return 0; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3d7ab14f13d..6214481e273 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2972,11 +2972,10 @@ we force server id to 2, but this MySQL server will not act as a slave."); exit(1); #ifdef __WIN__ -#define MYSQL_ERR_FILE "mysql.err" if (!opt_console) { - freopen(MYSQL_ERR_FILE,"a+",stdout); - freopen(MYSQL_ERR_FILE,"a+",stderr); + freopen(log_error_file,"a+",stdout); + freopen(log_error_file,"a+",stderr); FreeConsole(); // Remove window } #endif @@ -5132,12 +5131,12 @@ The minimum value for this variable is 4096.", "Persistent buffer for query parsing and execution", (gptr*) &global_system_variables.query_prealloc_size, (gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG, - REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, + REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 16384, ~0L, 0, 1024, 0}, {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE, "Allocation block size for storing ranges during optimization", (gptr*) &global_system_variables.range_alloc_block_size, (gptr*) &max_system_variables.range_alloc_block_size, 0, GET_ULONG, - REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, + REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 4096, ~0L, 0, 1024, 0}, {"read_buffer_size", OPT_RECORD_BUFFER, "Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.", (gptr*) &global_system_variables.read_buff_size, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 27311cb5613..bcb1f8634c0 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -53,19 +53,9 @@ #include <errno.h> #ifdef EMBEDDED_LIBRARY - #undef MYSQL_SERVER - -#ifndef MYSQL_CLIENT +#undef MYSQL_CLIENT #define MYSQL_CLIENT -#endif - -#undef net_flush - -extern "C" { -my_bool net_flush(NET *net); -} - #endif /*EMBEDDED_LIBRARY */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 286d0d01842..b832b33049d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3566,13 +3566,22 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, } /* - We can't use an index when comparing strings of - different collations + 1. Usually we can't use an index if the column collation + differ from the operation collation. + + 2. However, we can reuse a case insensitive index for + the binary searches: + + WHERE latin1_swedish_ci_column = 'a' COLLATE lati1_bin; + + WHERE latin1_swedish_ci_colimn = BINARY 'a ' + */ if (field->result_type() == STRING_RESULT && value->result_type() == STRING_RESULT && key_part->image_type == Field::itRAW && - ((Field_str*)field)->charset() != conf_func->compare_collation()) + ((Field_str*)field)->charset() != conf_func->compare_collation() && + !(conf_func->compare_collation()->state & MY_CS_BINSORT)) DBUG_RETURN(0); optimize_range= field->optimize_range(param->real_keynr[key_part->key], diff --git a/sql/protocol.cc b/sql/protocol.cc index 051eaaf7bda..2b0ae60f944 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -486,6 +486,15 @@ void Protocol::init(THD *thd_arg) } +bool Protocol::flush() +{ +#ifndef EMBEDDED_LIBRARY + return net_flush(&thd->net); +#else + return 0; +#endif +} + /* Send name and type of result to client. @@ -731,7 +740,8 @@ bool Protocol::store_string_aux(const char *from, uint length, fromcs != &my_charset_bin && tocs != &my_charset_bin) { - return convert->copy(from, length, fromcs, tocs) || + uint dummy_errors; + return convert->copy(from, length, fromcs, tocs, &dummy_errors) || net_store_data(convert->ptr(), convert->length()); } return net_store_data(from, length); diff --git a/sql/protocol.h b/sql/protocol.h index 7d390242417..d342af3ee9f 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -74,6 +74,7 @@ public: field_count=item_list->elements; return 0; } + virtual bool flush(); virtual void prepare_for_resend()=0; virtual bool store_null()=0; diff --git a/sql/spatial.cc b/sql/spatial.cc index 0668dd2faab..bcfefd9dde8 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -828,9 +828,7 @@ int Gis_polygon::centroid_xy(double *x, double *y) const if (!first_loop) { - double d_area= res_area - cur_area; - if (d_area <= 0) - return 1; + double d_area= fabs(res_area - cur_area); res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area; res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f5283020b30..5ed5468af2f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -567,13 +567,14 @@ bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs, { DBUG_ENTER("convert_string"); size_s new_length= to_cs->mbmaxlen * from_length; + uint dummy_errors; if (!(to->str= alloc(new_length+1))) { to->length= 0; // Safety fix DBUG_RETURN(1); // EOM } to->length= copy_and_convert((char*) to->str, new_length, to_cs, - from, from_length, from_cs); + from, from_length, from_cs, &dummy_errors); to->str[to->length]=0; // Safety DBUG_RETURN(0); } @@ -596,7 +597,8 @@ bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs, bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) { - if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs)) + uint dummy_errors; + if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors)) return TRUE; /* If convert_buffer >> s copying is more efficient long term */ if (convert_buffer.alloced_length() >= convert_buffer.length() * 2 || diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 60f69b578e9..35bad134127 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -899,18 +899,20 @@ static int check_connection(THD *thd) /* Since 4.1 all database names are stored in utf8 */ if (db) { + uint dummy_errors; db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info, db, strlen(db), - thd->charset())]= 0; + thd->charset(), &dummy_errors)]= 0; db= db_buff; } if (user) { + uint dummy_errors; user_buff[copy_and_convert(user_buff, sizeof(user_buff)-1, system_charset_info, user, strlen(user), - thd->charset())]= '\0'; + thd->charset(), &dummy_errors)]= '\0'; user= user_buff; } @@ -1412,9 +1414,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } #endif /* Convert database name to utf8 */ + uint dummy_errors; db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info, db, strlen(db), - thd->charset())]= 0; + thd->charset(), &dummy_errors)]= 0; db= db_buff; /* Save user and privileges */ @@ -2148,8 +2151,12 @@ mysql_execute_command(THD *thd) } if (need_conversion) - query_len= copy_and_convert(query_str, query_len, to_cs, pstr->ptr(), - pstr->length(), pstr->charset()); + { + uint dummy_errors; + query_len= copy_and_convert(query_str, query_len, to_cs, + pstr->ptr(), pstr->length(), + pstr->charset(), &dummy_errors); + } else memcpy(query_str, pstr->ptr(), pstr->length()); query_str[query_len]= 0; @@ -2716,6 +2723,7 @@ unsent_create_error: { if (mysql_bin_log.is_open()) { + thd->clear_error(); // No binlog error generated Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } @@ -2745,6 +2753,7 @@ unsent_create_error: { if (mysql_bin_log.is_open()) { + thd->clear_error(); // No binlog error generated Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } @@ -2767,6 +2776,7 @@ unsent_create_error: { if (mysql_bin_log.is_open()) { + thd->clear_error(); // No binlog error generated Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index bb2362dd562..d908e63210a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -170,8 +170,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) (stmt->param_count && stmt->thd->protocol_simple.send_fields((List<Item> *) &stmt->lex->param_list, - Protocol::SEND_EOF)) || - net_flush(net)); + Protocol::SEND_EOF))); } #else static bool send_prep_stmt(Prepared_statement *stmt, @@ -1097,7 +1096,7 @@ static int mysql_test_select(Prepared_statement *stmt, { if (lex->describe) { - if (send_prep_stmt(stmt, 0)) + if (send_prep_stmt(stmt, 0) || thd->protocol->flush()) goto err_prep; } else @@ -1115,11 +1114,8 @@ static int mysql_test_select(Prepared_statement *stmt, prepared in unit->prepare call above. */ if (send_prep_stmt(stmt, lex->result->field_count(fields)) || - lex->result->send_fields(fields, Protocol::SEND_EOF) -#ifndef EMBEDDED_LIBRARY - || net_flush(&thd->net) -#endif - ) + lex->result->send_fields(fields, Protocol::SEND_EOF) || + thd->protocol->flush()) goto err_prep; } } @@ -1402,7 +1398,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) enum enum_sql_command sql_command= lex->sql_command; int res= 0; DBUG_ENTER("send_prepare_results"); - DBUG_PRINT("enter",("command: %d, param_count: %ld", sql_command, stmt->param_count)); @@ -1453,6 +1448,7 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) break; case SQLCOM_INSERT_SELECT: + case SQLCOM_REPLACE_SELECT: res= mysql_test_insert_select(stmt, tables); break; @@ -1491,7 +1487,8 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol) goto error; } if (res == 0) - DBUG_RETURN(text_protocol? 0 : send_prep_stmt(stmt, 0)); + DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) || + thd->protocol->flush())); error: if (res < 0) send_error(thd,thd->killed_errno()); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 28e9baa1c36..557ec1bd5d2 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -804,8 +804,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, String def(tmp1,sizeof(tmp1), system_charset_info); type.set(tmp, sizeof(tmp), field->charset()); field->val_str(&type); + uint dummy_errors; def.copy(type.ptr(), type.length(), type.charset(), - system_charset_info); + system_charset_info, &dummy_errors); protocol->store(def.ptr(), def.length(), def.charset()); } else if (field->unireg_check == Field::NEXT_NUMBER || @@ -1177,7 +1178,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS | Protocol::SEND_EOF)) DBUG_VOID_RETURN; - net_flush(&thd->net); + thd->protocol->flush(); DBUG_VOID_RETURN; } @@ -1194,13 +1195,11 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) if (store_create_info(thd, table, packet)) DBUG_RETURN(-1); - //if (protocol->convert) - // protocol->convert->convert((char*) packet->ptr(), packet->length()); if (fd < 0) { if (protocol->write()) DBUG_RETURN(-1); - net_flush(&thd->net); + protocol->flush(); } else { @@ -1436,9 +1435,10 @@ store_create_info(THD *thd, TABLE *table, String *packet) if (type.length()) { String def_val; + uint dummy_errors; /* convert to system_charset_info == utf8 */ def_val.copy(type.ptr(), type.length(), field->charset(), - system_charset_info); + system_charset_info, &dummy_errors); append_unescaped(packet, def_val.ptr(), def_val.length()); } else diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 7d0dd3ca566..69b530911f4 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -121,12 +121,13 @@ bool String::set(ulonglong num, CHARSET_INFO *cs) bool String::set(double num,uint decimals, CHARSET_INFO *cs) { char buff[331]; + uint dummy_errors; str_charset=cs; if (decimals >= NOT_FIXED_DEC) { uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME - return copy(buff, len, &my_charset_latin1, cs); + return copy(buff, len, &my_charset_latin1, cs, &dummy_errors); } #ifdef HAVE_FCONVERT int decpt,sign; @@ -141,7 +142,8 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs) buff[0]='-'; pos=buff; } - return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs); + uint dummy_errors; + return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors); } if (alloc((uint32) ((uint32) decpt+3+decimals))) return TRUE; @@ -191,7 +193,8 @@ end: #else sprintf(buff,"%.*f",(int) decimals,num); #endif - return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs); + return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs, + &dummy_errors); #endif } @@ -336,14 +339,12 @@ bool String::copy(const char *str, uint32 arg_length, uint32 offset; if (!needs_conversion(arg_length, from_cs, to_cs, &offset)) { - if (errors) - *errors= 0; + *errors= 0; return copy(str, arg_length, to_cs); } if ((from_cs == &my_charset_bin) && offset) { - if (errors) - *errors= 0; + *errors= 0; return copy_aligned(str, arg_length, offset, to_cs); } uint32 new_length= to_cs->mbmaxlen*arg_length; @@ -382,7 +383,8 @@ bool String::set_ascii(const char *str, uint32 arg_length) set(str, arg_length, str_charset); return 0; } - return copy(str, arg_length, &my_charset_latin1, str_charset); + uint dummy_errors; + return copy(str, arg_length, &my_charset_latin1, str_charset, &dummy_errors); } @@ -436,10 +438,12 @@ bool String::append(const char *s,uint32 arg_length) if (str_charset->mbminlen > 1) { uint32 add_length=arg_length * str_charset->mbmaxlen; + uint dummy_errors; if (realloc(str_length+ add_length)) return TRUE; str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, - s, arg_length, &my_charset_latin1); + s, arg_length, &my_charset_latin1, + &dummy_errors); return FALSE; } @@ -476,10 +480,11 @@ bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs) if (needs_conversion(arg_length, cs, str_charset, &dummy_offset)) { uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen; + uint dummy_errors; if (realloc(str_length + add_length)) return TRUE; str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, - s, arg_length, cs); + s, arg_length, cs, &dummy_errors); } else { @@ -829,8 +834,7 @@ outp: else break; } - if (errors) - *errors= error_count; + *errors= error_count; return (uint32) (to - to_start); } diff --git a/sql/sql_string.h b/sql/sql_string.h index d6807fa83ad..cb5b1fb25fd 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -29,7 +29,7 @@ int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, - CHARSET_INFO *from_cs, uint *errors= 0); + CHARSET_INFO *from_cs, uint *errors); class String { @@ -199,7 +199,7 @@ public: CHARSET_INFO *cs); bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs); bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, - CHARSET_INFO *csto, uint *errors= 0); + CHARSET_INFO *csto, uint *errors); bool append(const String &s); bool append(const char *s); bool append(const char *s,uint32 arg_length); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 26c483a61a8..f4f9841ead3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1740,6 +1740,12 @@ end: } +/* + RETURN VALUES + 0 Message sent to net (admin operation went ok) + -1 Message should be sent by caller + (admin operation or network communication failed) +*/ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt, const char *operator_name, @@ -1787,9 +1793,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (prepare_func) { switch ((*prepare_func)(thd, table, check_opt)) { - case 1: continue; // error, message written to net - case -1: goto err; // error, message could be written to net - default: ; // should be 0 otherwise + case 1: // error, message written to net + close_thread_tables(thd); + continue; + case -1: // error, message could be written to net + goto err; + default: // should be 0 otherwise + ; } } diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index fa678ec7de2..0df60858bcb 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -108,8 +108,11 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length, memcpy(pos, str, new_length); } else + { + uint dummy_errors; new_length= copy_and_convert((char*) pos, new_length, to_cs, str, - arg_length, from_cs); + arg_length, from_cs, &dummy_errors); + } pos[new_length]= 0; *result_length= new_length; return pos; |