diff options
author | Chad MILLER <chad@mysql.com> | 2008-07-14 16:16:37 -0400 |
---|---|---|
committer | Chad MILLER <chad@mysql.com> | 2008-07-14 16:16:37 -0400 |
commit | a4e7283a9254c09057c92ec20fc145c52bea1d51 (patch) | |
tree | 6009880c2c51b3422d95a760220fb7a20ebdb3e0 /sql | |
parent | c425bf421da9ffa55d3d568f70508fa12dd07aa0 (diff) | |
parent | 55ab1ef6951428e0be31956e152537dec670e7df (diff) | |
download | mariadb-git-a4e7283a9254c09057c92ec20fc145c52bea1d51.tar.gz |
Merge from 5.0 trunk.
Diffstat (limited to 'sql')
56 files changed, 799 insertions, 349 deletions
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 0d1d821cf17..0b57fe86e62 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -883,7 +883,7 @@ int ha_tina::delete_all_rows() DBUG_ENTER("ha_tina::delete_all_rows"); if (!records_is_known) - return (my_errno=HA_ERR_WRONG_COMMAND); + DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND); /* Invalidate all cached mmap pages */ if (free_mmap(share)) diff --git a/sql/field.cc b/sql/field.cc index 53eafcaf2cc..d840034f8dc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5868,6 +5868,7 @@ check_string_copy_error(Field_str *field, Field_longstr::report_if_important_data() ptr - Truncated rest of string end - End of truncated string + count_spaces - Treat traling spaces as important data RETURN VALUES 0 - None was truncated (or we don't count cut fields) @@ -5877,10 +5878,12 @@ check_string_copy_error(Field_str *field, Check if we lost any important data (anything in a binary string, or any non-space in others). If only trailing spaces was lost, send a truncation note, otherwise send a truncation error. + Silently ignore traling spaces if the count_space parameter is FALSE. */ int -Field_longstr::report_if_important_data(const char *ptr, const char *end) +Field_longstr::report_if_important_data(const char *ptr, const char *end, + bool count_spaces) { if ((ptr < end) && table->in_use->count_cuted_fields) { @@ -5890,10 +5893,13 @@ Field_longstr::report_if_important_data(const char *ptr, const char *end) set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + return 2; } - else /* If we lost only spaces then produce a NOTE, not a WARNING */ + else if (count_spaces) + { /* If we lost only spaces then produce a NOTE, not a WARNING */ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); - return 2; + return 2; + } } return 0; } @@ -5929,7 +5935,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length)) return 2; - return report_if_important_data(from_end_pos, from + length); + return report_if_important_data(from_end_pos, from + length, FALSE); } @@ -6388,7 +6394,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length)) return 2; - return report_if_important_data(from_end_pos, from + length); + return report_if_important_data(from_end_pos, from + length, TRUE); } @@ -6930,6 +6936,7 @@ uint32 Field_blob::get_length(const char *pos) return (uint32) tmp; } } + /* When expanding this, see also MAX_FIELD_BLOBLENGTH. */ return 0; // Impossible } @@ -7024,7 +7031,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length)) return 2; - return report_if_important_data(from_end_pos, from + length); + return report_if_important_data(from_end_pos, from + length, TRUE); oom_error: /* Fatal OOM error */ @@ -8441,8 +8448,20 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP) flags|= NO_DEFAULT_VALUE_FLAG; - if (fld_length && !(length= (uint) atoi(fld_length))) - fld_length= 0; /* purecov: inspected */ + if (fld_length != NULL) + { + errno= 0; + length= strtoul(fld_length, NULL, 10); + if ((errno != 0) || (length > MAX_FIELD_BLOBLENGTH)) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, MAX_FIELD_BLOBLENGTH); + DBUG_RETURN(TRUE); + } + + if (length == 0) + fld_length= 0; /* purecov: inspected */ + } + sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; switch (fld_type) { @@ -8590,7 +8609,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } break; case FIELD_TYPE_TIMESTAMP: - if (!fld_length) + if (fld_length == NULL) { /* Compressed date YYYYMMDDHHMMSS */ length= MAX_DATETIME_COMPRESSED_WIDTH; @@ -8599,12 +8618,21 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, { /* We support only even TIMESTAMP lengths less or equal than 14 - and 19 as length of 4.1 compatible representation. + and 19 as length of 4.1 compatible representation. Silently + shrink it to MAX_DATETIME_COMPRESSED_WIDTH. */ - length= ((length+1)/2)*2; /* purecov: inspected */ - length= min(length, MAX_DATETIME_COMPRESSED_WIDTH); /* purecov: inspected */ + DBUG_ASSERT(MAX_DATETIME_COMPRESSED_WIDTH < UINT_MAX); + if (length != UINT_MAX) /* avoid overflow; is safe because of min() */ + length= ((length+1)/2)*2; + length= min(length, MAX_DATETIME_COMPRESSED_WIDTH); } flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + /* + Since we silently rewrite down to MAX_DATETIME_COMPRESSED_WIDTH bytes, + the parser should not raise errors unless bizzarely large. + */ + max_field_charlength= UINT_MAX; + if (fld_default_value) { /* Grammar allows only NOW() value for ON UPDATE clause */ @@ -8711,7 +8739,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, ((length > max_field_charlength && fld_type != FIELD_TYPE_SET && fld_type != FIELD_TYPE_ENUM && (fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) || - (!length && + ((length == 0) && fld_type != MYSQL_TYPE_STRING && fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY))) { diff --git a/sql/field.h b/sql/field.h index c82d65147ac..8d771a151a7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -455,7 +455,8 @@ public: class Field_longstr :public Field_str { protected: - int report_if_important_data(const char *ptr, const char *end); + int report_if_important_data(const char *ptr, const char *end, + bool count_spaces); public: Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 84eaa82728a..12766b42bc2 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -467,7 +467,7 @@ berkeley_cmp_packed_key(DB *file, const DBT *new_key, const DBT *saved_key) KEY_PART_INFO *key_part= key->key_part, *end=key_part+key->key_parts; uint key_length=new_key->size; - DBUG_DUMP("key_in_index", saved_key_ptr, saved_key->size); + DBUG_DUMP("key_in_index", (uchar *)saved_key_ptr, saved_key->size); for (; key_part != end && (int) key_length > 0; key_part++) { int cmp; @@ -903,7 +903,7 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff, key_length-=key_part->length; } key->size= (u_int32_t) (buff - (char*) key->data); - DBUG_DUMP("key",(char*) key->data, key->size); + DBUG_DUMP("key",(uchar*) key->data, key->size); DBUG_RETURN(key); } @@ -947,7 +947,7 @@ DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff, key_length-=key_part->store_length; } key->size= (u_int32_t) (buff - (char*) key->data); - DBUG_DUMP("key",(char*) key->data, key->size); + DBUG_DUMP("key",(uchar*) key->data, key->size); DBUG_RETURN(key); } @@ -1705,7 +1705,7 @@ DBT *ha_berkeley::get_pos(DBT *to, byte *pos) pos+=key_part->field->packed_col_length((char*) pos,key_part->length); to->size= (uint) (pos- (byte*) to->data); } - DBUG_DUMP("key", (char*) to->data, to->size); + DBUG_DUMP("key", (uchar*) to->data, to->size); return to; } diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index e477686d18e..01ede3d3bd2 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -115,7 +115,7 @@ const char *ha_blackhole::index_type(uint key_number) int ha_blackhole::write_row(byte * buf) { DBUG_ENTER("ha_blackhole::write_row"); - DBUG_RETURN(0); + DBUG_RETURN(table->next_number_field ? update_auto_increment() : 0); } int ha_blackhole::rnd_init(bool scan) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index d414dc34f02..2ccfeba74cb 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1095,7 +1095,7 @@ bool ha_federated::create_where_from_key(String *to, uint store_length= key_part->store_length; uint part_length= min(store_length, length); needs_quotes= 1; - DBUG_DUMP("key, start of loop", (char *) ptr, length); + DBUG_DUMP("key, start of loop", (uchar *)ptr, length); if (key_part->null_bit) { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 2d2007c8fdd..1be6137460b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4250,7 +4250,7 @@ ha_innobase::rnd_pos( int error; uint keynr = active_index; DBUG_ENTER("rnd_pos"); - DBUG_DUMP("key", (char*) pos, ref_length); + DBUG_DUMP("key", (uchar *)pos, ref_length); statistic_increment(current_thd->status_var.ha_read_rnd_count, &LOCK_status); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index a5cdc128724..0a75b328ca0 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -677,7 +677,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", fieldnr, field->field_name, field->type(), pack_len)); - DBUG_DUMP("key", (char*)field_ptr, pack_len); + DBUG_DUMP("key", (uchar*)field_ptr, pack_len); DBUG_ASSERT(ndb_supported_type(field->type())); DBUG_ASSERT(! (field->flags & BLOB_FLAG)); @@ -699,7 +699,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_PRINT("enter", ("%d: %s, type: %u, len=%d, is_null=%s", fieldnr, field->field_name, field->type(), pack_len, field->is_null()?"Y":"N")); - DBUG_DUMP("value", (char*) field_ptr, pack_len); + DBUG_DUMP("value", (uchar*) field_ptr, pack_len); DBUG_ASSERT(ndb_supported_type(field->type())); { @@ -737,7 +737,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, // Set value to NULL DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0)); DBUG_PRINT("info", ("bit field")); - DBUG_DUMP("value", (char*)&bits, pack_len); + DBUG_DUMP("value", (uchar*)&bits, pack_len); #ifdef WORDS_BIGENDIAN /* store lsw first */ bits = ((bits >> 32) & 0x00000000FFFFFFFFLL) @@ -768,7 +768,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_PRINT("value", ("set blob ptr: %p len: %u", blob_ptr, blob_len)); - DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26)); + DBUG_DUMP("value", (uchar*)blob_ptr, min(blob_len, 26)); if (set_blob_value) *set_blob_value= TRUE; @@ -1007,8 +1007,8 @@ int ha_ndbcluster::get_metadata(const char *path) ("metadata, pack_length: %d getFrmLength: %d memcmp: %d", pack_length, tab->getFrmLength(), memcmp(pack_data, tab->getFrmData(), pack_length))); - DBUG_DUMP("pack_data", (char*)pack_data, pack_length); - DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength()); + DBUG_DUMP("pack_data", (uchar*)pack_data, pack_length); + DBUG_DUMP("frm", (uchar*)tab->getFrmData(), tab->getFrmLength()); error= 3; invalidating_ndb_table= FALSE; } @@ -1502,7 +1502,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) int res; DBUG_ENTER("pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); - DBUG_DUMP("key", (char*)key, key_len); + DBUG_DUMP("key", (uchar*)key, key_len); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -1514,7 +1514,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) { // This table has no primary key, use "hidden" primary key DBUG_PRINT("info", ("Using hidden key")); - DBUG_DUMP("key", (char*)key, 8); + DBUG_DUMP("key", (uchar*)key, 8); if (set_hidden_key(op, no_fields, key)) ERR_RETURN(trans->getNdbError()); @@ -1797,7 +1797,7 @@ int ha_ndbcluster::unique_index_read(const byte *key, NdbIndexOperation *op; DBUG_ENTER("ha_ndbcluster::unique_index_read"); DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index)); - DBUG_DUMP("key", (char*)key, key_len); + DBUG_DUMP("key", (uchar*)key, key_len); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -2126,7 +2126,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, { DBUG_PRINT("info", ("key %d:%d offset=%d length=%d last=%d bound=%d", j, i, tot_len, part_len, p.part_last, p.bound_type)); - DBUG_DUMP("info", (const char*)p.part_ptr, part_store_len); + DBUG_DUMP("info", (const uchar*)p.part_ptr, part_store_len); // Set bound if not cancelled via type -1 if (p.bound_type != -1) @@ -2644,7 +2644,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) // Require that the PK for this record has previously been // read into m_ref - DBUG_DUMP("key", m_ref, NDB_HIDDEN_PRIMARY_KEY_LENGTH); + DBUG_DUMP("key", (uchar *)m_ref, NDB_HIDDEN_PRIMARY_KEY_LENGTH); if (set_hidden_key(op, table->s->fields, m_ref)) ERR_RETURN(op->getNdbError()); @@ -2864,8 +2864,6 @@ void ha_ndbcluster::print_results() DBUG_ENTER("print_results"); #ifndef DBUG_OFF - if (!_db_on_) - DBUG_VOID_RETURN; char buf_type[MAX_FIELD_WIDTH], buf_val[MAX_FIELD_WIDTH]; String type(buf_type, sizeof(buf_type), &my_charset_bin); @@ -3341,7 +3339,7 @@ void ha_ndbcluster::position(const byte *record) memcpy(ref, m_ref, ref_length); } - DBUG_DUMP("ref", (char*)ref, ref_length); + DBUG_DUMP("ref", (uchar*)ref, ref_length); DBUG_VOID_RETURN; } @@ -6263,7 +6261,7 @@ static int packfrm(const void *data, uint len, } DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", org_len, comp_len)); - DBUG_DUMP("compressed", (char*)data, org_len); + DBUG_DUMP("compressed", (uchar*)data, org_len); error= 2; blob_len= sizeof(frm_blob_struct::frm_blob_header)+org_len; @@ -6307,7 +6305,7 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len, DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu", ver,complen,orglen)); - DBUG_DUMP("blob->data", (char*) blob->data, complen); + DBUG_DUMP("blob->data", (uchar*) blob->data, complen); if (ver != 1) { diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc index f5b41959b40..37e710acff4 100644 --- a/sql/ha_ndbcluster_cond.cc +++ b/sql/ha_ndbcluster_cond.cc @@ -1419,7 +1419,7 @@ int ha_ndbcluster_cond::generate_scan_filter_from_key(NdbScanOperation *op, uint32 pack_len= field->pack_length(); const byte* ptr= key; DBUG_PRINT("info", ("Filtering value for %s", field->field_name)); - DBUG_DUMP("key", (char*)ptr, pack_len); + DBUG_DUMP("key", (uchar*)ptr, pack_len); if (key_part->null_bit) { DBUG_PRINT("info", ("Generating ISNULL filter")); diff --git a/sql/handler.cc b/sql/handler.cc index bfad10f986f..0de772e366b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1980,6 +1980,8 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) } } } + if (table->s->frm_version != FRM_VER_TRUE_VARCHAR) + return HA_ADMIN_NEEDS_ALTER; return check_for_upgrade(check_opt); } @@ -2348,8 +2350,8 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache) if (!key_cache->key_cache_inited) { pthread_mutex_lock(&LOCK_global_system_variables); - long tmp_buff_size= (long) key_cache->param_buff_size; - long tmp_block_size= (long) key_cache->param_block_size; + ulong tmp_buff_size= (ulong) key_cache->param_buff_size; + uint tmp_block_size= (uint) key_cache->param_block_size; uint division_limit= key_cache->param_division_limit; uint age_threshold= key_cache->param_age_threshold; pthread_mutex_unlock(&LOCK_global_system_variables); diff --git a/sql/handler.h b/sql/handler.h index 74c09d2d9ee..aa3377c3868 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -815,7 +815,7 @@ public: { return HA_ADMIN_NOT_IMPLEMENTED; } /* end of the list of admin commands */ - virtual bool check_and_repair(THD *thd) { return HA_ERR_WRONG_COMMAND; } + virtual bool check_and_repair(THD *thd) { return TRUE; } virtual int dump(THD* thd, int fd = -1) { return HA_ERR_WRONG_COMMAND; } virtual int disable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } virtual int enable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } diff --git a/sql/init.cc b/sql/init.cc index b3b68926683..2dd2031cdaa 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -30,7 +30,7 @@ void unireg_init(ulong options) wild_many='%'; wild_one='_'; wild_prefix='\\'; /* Change to sql syntax */ current_pid=(ulong) getpid(); /* Save for later ref */ - init_time(); /* Init time-functions (read zone) */ + my_init_time(); /* Init time-functions (read zone) */ #ifndef EMBEDDED_LIBRARY my_abort_hook=unireg_abort; /* Abort with close of databases */ #endif diff --git a/sql/item.cc b/sql/item.cc index c5b8d7a89ef..9ff1f8c0084 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3931,9 +3931,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) } if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) goto error; - else if (!ret) - return FALSE; outer_fixed= TRUE; + if (!ret) + goto mark_non_agg_field; } else if (!from_field) goto error; @@ -3945,9 +3945,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) int ret; if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) goto error; - else if (!ret) - return FALSE; outer_fixed= 1; + if (!ret) + goto mark_non_agg_field; } /* @@ -4013,6 +4013,26 @@ bool Item_field::fix_fields(THD *thd, Item **reference) thd->lex->current_select->non_agg_fields.push_back(this); marker= thd->lex->current_select->cur_pos_in_select_list; } +mark_non_agg_field: + if (fixed && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + { + /* + Mark selects according to presence of non aggregated fields. + Fields from outer selects added to the aggregate function + outer_fields list as its unknown at the moment whether it's + aggregated or not. + */ + if (!thd->lex->in_sum_func) + cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + else + { + if (outer_fixed) + thd->lex->in_sum_func->outer_fields.push_back(this); + else if (thd->lex->in_sum_func->nest_level != + thd->lex->current_select->nest_level) + cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + } + } return FALSE; error: @@ -4136,9 +4156,14 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field) String tmp(buff,sizeof(buff), field->charset()), *res; res= (*item)->val_str(&tmp); - field->prepend_zeros(res); - pos= (char *) sql_strmake (res->ptr(), res->length()); - *item= new Item_string(pos, res->length(), field->charset()); + if ((*item)->is_null()) + *item= new Item_null(); + else + { + field->prepend_zeros(res); + pos= (char *) sql_strmake (res->ptr(), res->length()); + *item= new Item_string(pos, res->length(), field->charset()); + } } @@ -5482,13 +5507,16 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(*ref); /* Check if this is an incorrect reference in a group function or forward - reference. Do not issue an error if this is an unnamed reference inside an - aggregate function. + reference. Do not issue an error if this is: + 1. outer reference (will be fixed later by the fix_inner_refs function); + 2. an unnamed reference inside an aggregate function. */ - if (((*ref)->with_sum_func && name && - !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && - current_sel->having_fix_field)) || - !(*ref)->fixed) + if (!((*ref)->type() == REF_ITEM && + ((Item_ref *)(*ref))->ref_type() == OUTER_REF) && + (((*ref)->with_sum_func && name && + !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && + current_sel->having_fix_field)) || + !(*ref)->fixed)) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, ((*ref)->with_sum_func? diff --git a/sql/item_create.cc b/sql/item_create.cc index 60a17c21521..c897b7aef79 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -464,8 +464,42 @@ Item *create_func_cast(Item *a, Cast_target cast_type, case ITEM_CAST_TIME: res= new Item_time_typecast(a); break; case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break; case ITEM_CAST_DECIMAL: - len= c_len ? atoi(c_len) : 0; - dec= c_dec ? atoi(c_dec) : 0; + if (c_len == NULL) + { + len= 0; + } + else + { + ulong decoded_size; + errno= 0; + decoded_size= strtoul(c_len, NULL, 10); + if (errno != 0) + { + my_error(ER_TOO_BIG_PRECISION, MYF(0), c_len, a->name, + DECIMAL_MAX_PRECISION); + return NULL; + } + len= decoded_size; + } + + if (c_dec == NULL) + { + dec= 0; + } + else + { + ulong decoded_size; + errno= 0; + decoded_size= strtoul(c_dec, NULL, 10); + if ((errno != 0) || (decoded_size > UINT_MAX)) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), c_dec, a->name, + DECIMAL_MAX_SCALE); + return NULL; + } + dec= decoded_size; + } + my_decimal_trim(&len, &dec); if (len < dec) { @@ -486,8 +520,25 @@ Item *create_func_cast(Item *a, Cast_target cast_type, } res= new Item_decimal_typecast(a, len, dec); break; + case ITEM_CAST_CHAR: - len= c_len ? atoi(c_len) : -1; + if (c_len == NULL) + { + len= LL(-1); + } + else + { + ulong decoded_size; + errno= 0; + decoded_size= strtoul(c_len, NULL, 10); + if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH)) + { + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH); + return NULL; + } + len= decoded_size; + } + res= new Item_char_typecast(a, len, cs ? cs : current_thd->variables.collation_connection); break; diff --git a/sql/item_func.cc b/sql/item_func.cc index 87e547d1f89..1238efbb653 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5115,7 +5115,7 @@ double Item_func_match::val_real() DBUG_RETURN(-1.0); if (key != NO_SUCH_KEY && table->null_row) /* NULL row from an outer join */ - return 0.0; + DBUG_RETURN(0.0); if (join_key) { diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4e72f117869..c443364ce52 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -294,6 +294,12 @@ String *Item_func_concat::val_str(String *str) { if (!(res=args[i]->val_str(str))) goto null; + /* + CONCAT accumulates its result in the result of its the first + non-empty argument. Because of this we need is_const to be + evaluated only for it. + */ + is_const= args[i]->const_item() || !args[i]->used_tables(); } else { diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b3710841dfb..401751660fd 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1232,7 +1232,11 @@ Item_in_subselect::row_value_transformer(JOIN *join) Item *item_having_part2= 0; for (uint i= 0; i < cols_num; i++) { - DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + DBUG_ASSERT(left_expr->fixed && + select_lex->ref_pointer_array[i]->fixed || + (select_lex->ref_pointer_array[i]->type() == REF_ITEM && + ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == + Item_ref::OUTER_REF)); if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); @@ -1306,7 +1310,11 @@ Item_in_subselect::row_value_transformer(JOIN *join) for (uint i= 0; i < cols_num; i++) { Item *item, *item_isnull; - DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + DBUG_ASSERT(left_expr->fixed && + select_lex->ref_pointer_array[i]->fixed || + (select_lex->ref_pointer_array[i]->type() == REF_ITEM && + ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == + Item_ref::OUTER_REF)); if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); @@ -1434,6 +1442,19 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) DBUG_ENTER("Item_in_subselect::select_in_like_transformer"); + { + /* + IN/SOME/ALL/ANY subqueries aren't support LIMIT clause. Without it + ORDER BY clause becomes meaningless thus we drop it here. + */ + SELECT_LEX *sl= current->master_unit()->first_select(); + for (; sl; sl= sl->next_select()) + { + if (sl->join) + sl->join->order= 0; + } + } + if (changed) { DBUG_RETURN(RES_OK); @@ -1468,6 +1489,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) transformed= 1; arena= thd->activate_stmt_arena_if_needed(&backup); + /* Both transformers call fix_fields() only for Items created inside them, and all that items do not make permanent changes in current item arena diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3d6d46ab3f4..91320d6b56b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -66,6 +66,7 @@ bool Item_sum::init_sum_func_check(THD *thd) aggr_sel= NULL; max_arg_level= -1; max_sum_func_level= -1; + outer_fields.empty(); return FALSE; } @@ -175,6 +176,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) MYF(0)); return TRUE; } + if (in_sum_func) { /* @@ -195,6 +197,68 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) set_if_bigger(in_sum_func->max_sum_func_level, aggr_level); set_if_bigger(in_sum_func->max_sum_func_level, max_sum_func_level); } + + /* + Check that non-aggregated fields and sum functions aren't mixed in the + same select in the ONLY_FULL_GROUP_BY mode. + */ + if (outer_fields.elements) + { + Item_field *field; + /* + Here we compare the nesting level of the select to which an outer field + belongs to with the aggregation level of the sum function. All fields in + the outer_fields list are checked. + + If the nesting level is equal to the aggregation level then the field is + aggregated by this sum function. + If the nesting level is less than the aggregation level then the field + belongs to an outer select. In this case if there is an embedding sum + function add current field to functions outer_fields list. If there is + no embedding function then the current field treated as non aggregated + and the select it belongs to is marked accordingly. + If the nesting level is greater than the aggregation level then it means + that this field was added by an inner sum function. + Consider an example: + + select avg ( <-- we are here, checking outer.f1 + select ( + select sum(outer.f1 + inner.f1) from inner + ) from outer) + from most_outer; + + In this case we check that no aggregate functions are used in the + select the field belongs to. If there are some then an error is + raised. + */ + List_iterator<Item_field> of(outer_fields); + while ((field= of++)) + { + SELECT_LEX *sel= field->cached_table->select_lex; + if (sel->nest_level < aggr_level) + { + if (in_sum_func) + { + /* + Let upper function decide whether this field is a non + aggregated one. + */ + in_sum_func->outer_fields.push_back(field); + } + else + sel->full_group_by_flag|= NON_AGG_FIELD_USED; + } + if (sel->nest_level > aggr_level && + (sel->full_group_by_flag & SUM_FUNC_USED) && + !sel->group_list.elements) + { + my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, + ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); + return TRUE; + } + } + } + aggr_sel->full_group_by_flag|= SUM_FUNC_USED; update_used_tables(); thd->lex->in_sum_func= in_sum_func; return FALSE; @@ -1206,7 +1270,15 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) null_value=1; return NULL; } - sum_dec= Item_sum_sum::val_decimal(&sum_buff); + + /* + For non-DECIMAL hybrid_type the division will be done in + Item_sum_avg::val_real(). + */ + if (hybrid_type != DECIMAL_RESULT) + return val_decimal_from_real(val); + + sum_dec= dec_buffs + curr_dec_buff; int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment); return val; @@ -3150,7 +3222,7 @@ void Item_func_group_concat::clear() no_appended= TRUE; if (tree) reset_tree(tree); - if (distinct) + if (unique_filter) unique_filter->reset(); /* No need to reset the table as we never call write_row */ } diff --git a/sql/item_sum.h b/sql/item_sum.h index bf0abe53eea..d39fc96e254 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -239,6 +239,13 @@ public: int8 max_arg_level; /* max level of unbound column references */ int8 max_sum_func_level;/* max level of aggregation for embedded functions */ bool quick_group; /* If incremental update of fields */ + /* + This list is used by the check for mixing non aggregated fields and + sum functions in the ONLY_FULL_GROUP_BY_MODE. We save all outer fields + directly or indirectly used under this function it as it's unclear + at the moment of fixing outer field whether it's aggregated or not. + */ + List<Item_field> outer_fields; protected: table_map used_tables_cache; diff --git a/sql/lock.cc b/sql/lock.cc index d0576202606..4927146d96b 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -703,7 +703,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, { my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table_ptr[i]->s->db, table_ptr[i]->s->table_name); - return 0; + DBUG_RETURN(0); } } diff --git a/sql/log.cc b/sql/log.cc index 15e8679171c..9e112e46c65 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1180,6 +1180,8 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads) RETURN VALUES 0 ok LOG_INFO_EOF to_log not found + LOG_INFO_FATAL if any other than ENOENT error from + my_stat() or my_delete() */ int MYSQL_LOG::purge_logs(const char *to_log, @@ -1208,33 +1210,75 @@ int MYSQL_LOG::purge_logs(const char *to_log, while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && !log_in_use(log_info.log_file_name)) { - ulong file_size= 0; - if (decrease_log_space) //stat the file we want to delete + MY_STAT s; + if (!my_stat(log_info.log_file_name, &s, MYF(0))) { - MY_STAT s; - - /* - If we could not stat, we can't know the amount - of space that deletion will free. In most cases, - deletion won't work either, so it's not a problem. - */ - if (my_stat(log_info.log_file_name,&s,MYF(0))) - file_size= s.st_size; - else - sql_print_information("Failed to execute my_stat on file '%s'", + if (my_errno == ENOENT) + { + /* + It's not fatal if we can't stat a log file that does not exist; + If we could not stat, we won't delete. + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to execute my_stat on file '%s'", log_info.log_file_name); + my_errno= 0; + } + else + { + /* + Other than ENOENT are fatal + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } + else + { + DBUG_PRINT("info",("purging %s",log_info.log_file_name)); + if (!my_delete(log_info.log_file_name, MYF(0))) + { + if (decrease_log_space) + *decrease_log_space-= s.st_size; + } + else + { + if (my_errno == ENOENT) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to delete file '%s'", + log_info.log_file_name); + my_errno= 0; + } + else + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } } - /* - It's not fatal if we can't delete a log file ; - if we could delete it, take its size into account - */ - DBUG_PRINT("info",("purging %s",log_info.log_file_name)); - if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space) - *decrease_log_space-= file_size; if (find_next_log(&log_info, 0) || exit_loop) break; } - + /* If we get killed -9 here, the sysadmin would have to edit the log index file after restart - otherwise, this should be safe @@ -1263,6 +1307,8 @@ err: RETURN VALUES 0 ok LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated + LOG_INFO_FATAL if any other than ENOENT error from + my_stat() or my_delete() */ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) @@ -1286,11 +1332,66 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) while (strcmp(log_file_name, log_info.log_file_name) && !log_in_use(log_info.log_file_name)) { - /* It's not fatal even if we can't delete a log file */ - if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)) || - stat_area.st_mtime >= purge_time) - break; - my_delete(log_info.log_file_name, MYF(0)); + if (!my_stat(log_info.log_file_name, &stat_area, MYF(0))) + { + if (my_errno == ENOENT) + { + /* + It's not fatal if we can't stat a log file that does not exist. + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to execute my_stat on file '%s'", + log_info.log_file_name); + my_errno= 0; + } + else + { + /* + Other than ENOENT are fatal + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } + else + { + if (stat_area.st_mtime >= purge_time) + break; + if (my_delete(log_info.log_file_name, MYF(0))) + { + if (my_errno == ENOENT) + { + /* It's not fatal even if we can't delete a log file */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to delete file '%s'", + log_info.log_file_name); + my_errno= 0; + } + else + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } + } if (find_next_log(&log_info, 0)) break; } diff --git a/sql/my_decimal.h b/sql/my_decimal.h index c661579ea66..6a0d05921ec 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -164,14 +164,23 @@ inline int check_result_and_overflow(uint mask, int result, my_decimal *val) inline uint my_decimal_length_to_precision(uint length, uint scale, bool unsigned_flag) { - return (uint) (length - (scale>0 ? 1:0) - (unsigned_flag ? 0:1)); + /* Precision can't be negative thus ignore unsigned_flag when length is 0. */ + DBUG_ASSERT(length || !scale); + return (uint) (length - (scale>0 ? 1:0) - + (unsigned_flag || !length ? 0:1)); } inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, bool unsigned_flag) { + /* + When precision is 0 it means that original length was also 0. Thus + unsigned_flag is ignored in this case. + */ + DBUG_ASSERT(precision || !scale); set_if_smaller(precision, DECIMAL_MAX_PRECISION); - return (uint32)(precision + (scale>0 ? 1:0) + (unsigned_flag ? 0:1)); + return (uint32)(precision + (scale>0 ? 1:0) + + (unsigned_flag || !precision ? 0:1)); } inline diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4f27994c13c..f3bda4e5819 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -615,8 +615,8 @@ bool check_merge_table_access(THD *thd, char *db, bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc); bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); -bool mysql_multi_update_prepare(THD *thd); -bool mysql_multi_delete_prepare(THD *thd); +int mysql_multi_update_prepare(THD *thd); +int mysql_multi_delete_prepare(THD *thd); bool mysql_insert_select_prepare(THD *thd); bool update_precheck(THD *thd, TABLE_LIST *tables); bool delete_precheck(THD *thd, TABLE_LIST *tables); @@ -709,7 +709,7 @@ struct Query_cache_query_flags uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); -bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags); @@ -749,7 +749,7 @@ pthread_handler_t handle_one_connection(void *arg); pthread_handler_t handle_bootstrap(void *arg); void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); -bool mysql_execute_command(THD *thd); +int mysql_execute_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); @@ -880,7 +880,7 @@ void prepare_triggers_for_insert_stmt(THD *thd, TABLE *table, enum_duplicates duplic); void mark_fields_used_by_triggers_for_insert_stmt(THD *thd, TABLE *table, enum_duplicates duplic); -bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, ha_rows rows, ulonglong options, bool reset_auto_increment); @@ -1065,6 +1065,13 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, extern Item **not_found_item; /* + A set of constants used for checking non aggregated fields and sum + functions mixture in the ONLY_FULL_GROUP_BY_MODE. +*/ +#define NON_AGG_FIELD_USED 1 +#define SUM_FUNC_USED 2 + +/* This enumeration type is used only by the function find_item_in_list to return the info on how an item has been resolved against a list of possibly aliased items. @@ -1126,7 +1133,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_refresh(THD *thd); int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); -bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); +int open_and_lock_tables(THD *thd,TABLE_LIST *tables); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, @@ -1197,7 +1204,7 @@ inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table, bool eval_const_cond(COND *cond); /* sql_load.cc */ -bool mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list, +int mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list, List<Item> &fields_vars, List<Item> &set_fields, List<Item> &set_values_list, enum enum_duplicates handle_duplicates, bool ignore, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08f881ce8ed..7edc3b91752 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -328,7 +328,7 @@ static bool lower_case_table_names_used= 0; static bool volatile select_thread_in_use, signal_thread_in_use; static bool volatile ready_to_exit; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; -static my_bool opt_bdb, opt_isam, opt_ndbcluster, opt_merge; +static my_bool opt_bdb, opt_isam, opt_ndbcluster, opt_merge, opt_federated; static my_bool opt_short_log_format= 0; static uint kill_cached_threads, wake_thread; static ulong killed_threads, thread_created; @@ -1071,12 +1071,9 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused))) extern "C" sig_handler print_signal_warning(int sig) { - if (!DBUG_IN_USE) - { - if (global_system_variables.log_warnings) - sql_print_warning("Got signal %d from thread %ld", - sig, my_thread_id()); - } + if (global_system_variables.log_warnings) + sql_print_warning("Got signal %d from thread %ld", + sig, my_thread_id()); #ifdef DONT_REMEMBER_SIGNAL my_sigset(sig,print_signal_warning); /* int. thread system calls */ #endif @@ -3623,8 +3620,6 @@ int main(int argc, char **argv) MY_INIT(argv[0]); // init my_sys library & pthreads /* ^^^ Nothing should be before this line! */ - DEBUGGER_OFF; - /* Set signal used to kill MySQL */ #if defined(SIGUSR2) thr_kill_signal= thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2; @@ -4995,7 +4990,8 @@ enum options_mysqld OPT_INNODB_ROLLBACK_ON_TIMEOUT, OPT_SECURE_FILE_PRIV, OPT_KEEP_FILES_ON_CREATE, - OPT_INNODB_ADAPTIVE_HASH_INDEX + OPT_INNODB_ADAPTIVE_HASH_INDEX, + OPT_FEDERATED }; @@ -5181,6 +5177,9 @@ Disable with --skip-external-locking.", 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"federated", OPT_FEDERATED, "Enable Federated storage engine. Disable with \ +--skip-federated.", + (gptr*) &opt_federated, (gptr*) &opt_federated, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, /* We must always support the next option to make scripts like mysqltest easier to do */ {"gdb", OPT_DEBUGGING, @@ -6956,7 +6955,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), switch(optid) { case '#': #ifndef DBUG_OFF - DBUG_PUSH(argument ? argument : default_dbug_option); + DBUG_SET_INITIAL(argument ? argument : default_dbug_option); #endif opt_endinfo=1; /* unireg: memory allocation */ break; @@ -7335,6 +7334,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), else have_merge_db= SHOW_OPTION_DISABLED; break; +#ifdef HAVE_FEDERATED_DB + case OPT_FEDERATED: + if (opt_federated) + have_federated_db= SHOW_OPTION_YES; + else + have_federated_db= SHOW_OPTION_DISABLED; + break; +#endif #ifdef HAVE_BERKELEY_DB case OPT_BDB_NOSYNC: /* Deprecated option */ diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 017a2eb9ecd..a40764577fd 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -394,7 +394,7 @@ my_net_write(NET *net,const char *packet,ulong len) if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE)) return 1; #ifndef DEBUG_DATA_PACKETS - DBUG_DUMP("packet_header",(char*) buff,NET_HEADER_SIZE); + DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE); #endif return test(net_write_buff(net,packet,len)); } @@ -892,7 +892,7 @@ my_real_read(NET *net, ulong *complen) if (i == 0) { /* First parts is packet length */ ulong helping; - DBUG_DUMP("packet_header",(char*) net->buff+net->where_b, + DBUG_DUMP("packet_header", net->buff+net->where_b, NET_HEADER_SIZE); if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index a8cf0f67635..17a4701b515 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4405,52 +4405,70 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, field->type() == FIELD_TYPE_DATETIME)) field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; err= value->save_in_field_no_warnings(field, 1); - if (err > 0 && field->cmp_type() != value->result_type()) + if (err > 0) { - if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && - value->result_type() == item_cmp_type(field->result_type(), - value->result_type())) - - { - tree= new (alloc) SEL_ARG(field, 0, 0); - tree->type= SEL_ARG::IMPOSSIBLE; - goto end; - } - else + if (field->cmp_type() != value->result_type()) { - /* - TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE - for the cases like int_field > 999999999999999999999999 as well. - */ - tree= 0; - if (err == 3 && field->type() == FIELD_TYPE_DATE && - (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || - type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) + if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && + value->result_type() == item_cmp_type(field->result_type(), + value->result_type())) + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + goto end; + } + else { /* - We were saving DATETIME into a DATE column, the conversion went ok - but a non-zero time part was cut off. + TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE + for the cases like int_field > 999999999999999999999999 as well. + */ + tree= 0; + if (err == 3 && field->type() == FIELD_TYPE_DATE && + (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || + type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) + { + /* + We were saving DATETIME into a DATE column, the conversion went ok + but a non-zero time part was cut off. - In MySQL's SQL dialect, DATE and DATETIME are compared as datetime - values. Index over a DATE column uses DATE comparison. Changing - from one comparison to the other is possible: + In MySQL's SQL dialect, DATE and DATETIME are compared as datetime + values. Index over a DATE column uses DATE comparison. Changing + from one comparison to the other is possible: - datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10' - datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10' + datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10' + datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10' - datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10' - datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10' + datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10' + datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10' - but we'll need to convert '>' to '>=' and '<' to '<='. This will - be done together with other types at the end of this function - (grep for field_is_equal_to_item) - */ + but we'll need to convert '>' to '>=' and '<' to '<='. This will + be done together with other types at the end of this function + (grep for field_is_equal_to_item) + */ + } + else + goto end; } - else - goto end; } - } - if (err < 0) + + /* + guaranteed at this point: err > 0; field and const of same type + If an integer got bounded (e.g. to within 0..255 / -128..127) + for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN) + */ + else if (err == 1 && field->result_type() == INT_RESULT) + { + if (type == Item_func::LT_FUNC && (value->val_int() > 0)) + type = Item_func::LE_FUNC; + else if (type == Item_func::GT_FUNC && + !((Field_num*)field)->unsigned_flag && + !((Item_int*)value)->unsigned_flag && + (value->val_int() < 0)) + type = Item_func::GE_FUNC; + } + } + else if (err < 0) { field->table->in_use->variables.sql_mode= orig_sql_mode; /* This happens when we try to insert a NULL field in a not null column */ @@ -9552,8 +9570,6 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, int idx; char buff[1024]; DBUG_ENTER("print_sel_tree"); - if (! _db_on_) - DBUG_VOID_RETURN; String tmp(buff,sizeof(buff),&my_charset_bin); tmp.length(0); @@ -9583,8 +9599,6 @@ static void print_ror_scans_arr(TABLE *table, const char *msg, struct st_ror_scan_info **end) { DBUG_ENTER("print_ror_scans"); - if (! _db_on_) - DBUG_VOID_RETURN; char buff[1024]; String tmp(buff,sizeof(buff),&my_charset_bin); @@ -9647,7 +9661,7 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg) { char buf[MAX_KEY/8+1]; DBUG_ENTER("print_quick"); - if (! _db_on_ || !quick) + if (!quick) DBUG_VOID_RETURN; DBUG_LOCK_FILE; diff --git a/sql/procedure.h b/sql/procedure.h index 850d5c74db4..f1fb433a6ee 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -144,7 +144,7 @@ public: virtual int send_row(List<Item> &fields)=0; virtual bool change_columns(List<Item> &fields)=0; virtual void update_refs(void) {} - virtual bool end_of_records() { return 0; } + virtual int end_of_records() { return 0; } }; Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result, diff --git a/sql/set_var.cc b/sql/set_var.cc index 71a5a26f1d7..eb381bfecf4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2004,7 +2004,7 @@ void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type, { DATE_TIME_FORMAT *old; DBUG_ENTER("sys_var_date_time_format::update2"); - DBUG_DUMP("positions",(char*) new_value->positions, + DBUG_DUMP("positions", new_value->positions, sizeof(new_value->positions)); if (type == OPT_GLOBAL) diff --git a/sql/share/charsets/README b/sql/share/charsets/README index 172d1ee8e1e..3c5b3206faa 100644 --- a/sql/share/charsets/README +++ b/sql/share/charsets/README @@ -1,28 +1,31 @@ -This directory holds configuration files which allow MySQL to work with +This directory holds configuration files that enable MySQL to work with different character sets. It contains: -*.conf - Each conf file contains four tables which describe character types, +charset_name.xml + Each charset_name.xml file contains information for a simple character + set. The information in the file describes character types, lower- and upper-case equivalencies and sorting orders for the character values in the set. -Index - The Index file lists all of the available charset configurations. +Index.xml + The Index.xml file lists all of the available charset configurations, + including collations. - Each charset is paired with a number. The number is stored - IN THE DATABASE TABLE FILES and must not be changed. Always - add new character sets to the end of the list, so that the - numbers of the other character sets will not be changed. + Each collation must have a unique number. The number is stored + IN THE DATABASE TABLE FILES and must not be changed. + + The max-id attribute of the <charsets> element must be set to + the largest collation number. Compiled in or configuration file? When should a character set be compiled in to MySQL's string library - (libmystrings), and when should it be placed in a configuration - file? + (libmystrings), and when should it be placed in a charset_name.xml + configuration file? If the character set requires the strcoll functions or is a multi-byte character set, it MUST be compiled in to the string library. If it does not require these functions, it should be - placed in a configuration file. + placed in a charset_name.xml configuration file. If the character set uses any one of the strcoll functions, it must define all of them. Likewise, if the set uses one of the @@ -30,11 +33,7 @@ Compiled in or configuration file? more information on how to add a complex character set to MySQL. Syntax of configuration files - The syntax is very simple. Comments start with a '#' character and - proceed to the end of the line. Words are separated by arbitrary - amounts of whitespace. - - For the character set configuration files, every word must be a - number in hexadecimal format. The ctype array takes up the first - 257 words; the to_lower, to_upper and sort_order arrays take up 256 - words each after that. + The syntax is very simple. Words in <map> array elements are + separated by arbitrary amounts of whitespace. Each word must be a + number in hexadecimal format. The ctype array has 257 words; the + other arrays (lower, upper, etc.) take up 256 words each after that. diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 9e6cf462113..7d345d633c6 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -1771,30 +1771,30 @@ ER_BLOB_USED_AS_KEY 42000 S1009 swe "En BLOB '%-.64s' kan inte vara nyckel med den använda tabelltypen" ukr "BLOB ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ" ER_TOO_BIG_FIELDLENGTH 42000 S1009 - cze "P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB" - dan "For stor feltlængde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet" - nla "Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type BLOB" - eng "Column length too big for column '%-.64s' (max = %d); use BLOB or TEXT instead" - jps "column '%-.64s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %d ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚‚¾‚³‚¢.", - est "Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi" - fre "Champ '%-.64s' trop long (max = %d). Utilisez un BLOB" - ger "Feldlänge für Feld '%-.64s' zu groß (maximal %d). BLOB- oder TEXT-Spaltentyp verwenden!" - greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB" - hun "A(z) '%-.64s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb." - ita "La colonna '%-.64s' e` troppo grande (max=%d). Utilizza un BLOB." - jpn "column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤." - kor "Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä." - nor "For stor nøkkellengde for kolonne '%-.64s' (maks = %d). Bruk BLOB istedenfor" - norwegian-ny "For stor nykkellengde for felt '%-.64s' (maks = %d). Bruk BLOB istadenfor" - pol "Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %d). W zamian u¿yj typu BLOB" - por "Comprimento da coluna '%-.64s' grande demais (max = %d); use BLOB em seu lugar" - rum "Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine" - rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.64s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ" - serbian "Previše podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje" - slo "Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %d). Pou¾ite BLOB" - spa "Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar BLOB en su lugar" - swe "För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället" - ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.64s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB" + cze "P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %lu). Pou¾ijte BLOB" + dan "For stor feltlængde for kolonne '%-.64s' (maks = %lu). Brug BLOB i stedet" + nla "Te grote kolomlengte voor '%-.64s' (max = %lu). Maak hiervoor gebruik van het type BLOB" + eng "Column length too big for column '%-.64s' (max = %lu); use BLOB or TEXT instead" + jps "column '%-.64s' ‚Í,Šm•Û‚·‚é column ‚Ì‘å‚«‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %lu ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚‚¾‚³‚¢.", + est "Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %lu). Kasuta BLOB väljatüüpi" + fre "Champ '%-.64s' trop long (max = %lu). Utilisez un BLOB" + ger "Feldlänge für Feld '%-.64s' zu groß (maximal %lu). BLOB- oder TEXT-Spaltentyp verwenden!" + greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %lu). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB" + hun "A(z) '%-.64s' oszlop tul hosszu. (maximum = %lu). Hasznaljon BLOB tipust inkabb." + ita "La colonna '%-.64s' e` troppo grande (max=%lu). Utilizza un BLOB." + jpn "column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %lu ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤." + kor "Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %lu). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä." + nor "For stor nøkkellengde for kolonne '%-.64s' (maks = %lu). Bruk BLOB istedenfor" + norwegian-ny "For stor nykkellengde for felt '%-.64s' (maks = %lu). Bruk BLOB istadenfor" + pol "Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %lu). W zamian u¿yj typu BLOB" + por "Comprimento da coluna '%-.64s' grande demais (max = %lu); use BLOB em seu lugar" + rum "Lungimea coloanei '%-.64s' este prea lunga (maximum = %lu). Foloseste BLOB mai bine" + rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.64s' (ÍÁËÓÉÍÕÍ = %lu). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ" + serbian "Previše podataka za kolonu '%-.64s' (maksimum je %lu). Upotrebite BLOB polje" + slo "Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %lu). Pou¾ite BLOB" + spa "Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %lu).Usar BLOB en su lugar" + swe "För stor kolumnlängd angiven för '%-.64s' (max= %lu). Använd en BLOB instället" + ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.64s' (max = %lu). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB" ER_WRONG_AUTO_KEY 42000 S1009 cze "M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè" dan "Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret" @@ -5508,11 +5508,11 @@ ER_SP_NO_RECURSION eng "Recursive stored functions and triggers are not allowed." ger "Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt" ER_TOO_BIG_SCALE 42000 S1009 - eng "Too big scale %d specified for column '%-.64s'. Maximum is %d." - ger "Zu großer Skalierungsfaktor %d für Feld '%-.64s' angegeben. Maximum ist %d" + eng "Too big scale %lu specified for column '%-.64s'. Maximum is %d." + ger "Zu großer Skalierungsfaktor %lu für Feld '%-.64s' angegeben. Maximum ist %d" ER_TOO_BIG_PRECISION 42000 S1009 - eng "Too big precision %d specified for column '%-.64s'. Maximum is %d." - ger "Zu große Genauigkeit %d für Feld '%-.64s' angegeben. Maximum ist %d" + eng "Too big precision %lu specified for column '%-.64s'. Maximum is %lu." + ger "Zu große Genauigkeit %lu für Feld '%-.64s' angegeben. Maximum ist %lu" ER_M_BIGGER_THAN_D 42000 S1009 eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.64s')." ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.64s')" @@ -5550,8 +5550,8 @@ ER_WARN_CANT_DROP_DEFAULT_KEYCACHE eng "Cannot drop default keycache" ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden" ER_TOO_BIG_DISPLAYWIDTH 42000 S1009 - eng "Display width out of range for column '%-.64s' (max = %d)" - ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.64s' (Maximum: %d)" + eng "Display width out of range for column '%-.64s' (max = %lu)" + ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.64s' (Maximum: %lu)" ER_XAER_DUPID XAE08 eng "XAER_DUPID: The XID already exists" ger "XAER_DUPID: Die XID existiert bereits" @@ -5641,3 +5641,7 @@ ER_NAME_BECOMES_EMPTY eng "Name '%-.64s' has become ''" ER_AMBIGUOUS_FIELD_TERM eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" +ER_LOAD_DATA_INVALID_COLUMN + eng "Invalid column reference (%-.64s) in LOAD DATA" +ER_LOG_PURGE_NO_FILE + eng "Being purged log %s was not found" diff --git a/sql/sp.cc b/sql/sp.cc index 7224d3c4f0e..2392cabb220 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -25,7 +25,8 @@ static bool create_string(THD *thd, String *buf, int sp_type, - sp_name *name, + const char *db, ulong dblen, + const char *name, ulong namelen, const char *params, ulong paramslen, const char *returns, ulong returnslen, const char *body, ulong bodylen, @@ -426,12 +427,13 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, */ if (!create_string(thd, &defstr, - type, - name, - params, strlen(params), - returns, strlen(returns), - body, strlen(body), - &chistics, &definer_user_name, &definer_host_name)) + type, + NULL, 0, + name->m_name.str, name->m_name.length, + params, strlen(params), + returns, strlen(returns), + body, strlen(body), + &chistics, &definer_user_name, &definer_host_name)) { ret= SP_INTERNAL_ERROR; goto end; @@ -518,6 +520,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) DBUG_ENTER("db_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length, sp->m_name.str)); + String retstr(64); if (!(table= open_proc_table_for_update(thd))) ret= SP_OPEN_TABLE_FAILED; @@ -568,7 +571,6 @@ db_create_routine(THD *thd, int type, sp_head *sp) store(sp->m_params.str, sp->m_params.length, system_charset_info); if (sp->m_type == TYPE_ENUM_FUNCTION) { - String retstr(64); sp_returns_type(thd, retstr, sp); table->field[MYSQL_PROC_FIELD_RETURNS]-> store(retstr.ptr(), retstr.length(), system_charset_info); @@ -625,13 +627,21 @@ db_create_routine(THD *thd, int type, sp_head *sp) String log_query; log_query.set_charset(system_charset_info); - log_query.append(STRING_WITH_LEN("CREATE ")); - append_definer(thd, &log_query, &thd->lex->definer->user, - &thd->lex->definer->host); - log_query.append(thd->lex->stmt_definition_begin, - (char *)sp->m_body_begin - - thd->lex->stmt_definition_begin + - sp->m_body.length); + + if (!create_string(thd, &log_query, + sp->m_type, + (sp->m_explicit_name ? sp->m_db.str : NULL), + (sp->m_explicit_name ? sp->m_db.length : 0), + sp->m_name.str, sp->m_name.length, + sp->m_params.str, sp->m_params.length, + retstr.c_ptr(), retstr.length(), + sp->m_body.str, sp->m_body.length, + sp->m_chistics, &(thd->lex->definer->user), + &(thd->lex->definer->host))) + { + ret= SP_INTERNAL_ERROR; + goto done; + } /* Such a statement can always go directly to binlog, no trans cache */ Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0, @@ -1797,17 +1807,18 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, */ static bool create_string(THD *thd, String *buf, - int type, - sp_name *name, - const char *params, ulong paramslen, - const char *returns, ulong returnslen, - const char *body, ulong bodylen, - st_sp_chistics *chistics, + int type, + const char *db, ulong dblen, + const char *name, ulong namelen, + const char *params, ulong paramslen, + const char *returns, ulong returnslen, + const char *body, ulong bodylen, + st_sp_chistics *chistics, const LEX_STRING *definer_user, const LEX_STRING *definer_host) { /* Make some room to begin with */ - if (buf->alloc(100 + name->m_qname.length + paramslen + returnslen + bodylen + + if (buf->alloc(100 + dblen + 1 + namelen + paramslen + returnslen + bodylen + chistics->comment.length + 10 /* length of " DEFINER= "*/ + USER_HOST_BUFF_SIZE)) return FALSE; @@ -1818,7 +1829,12 @@ create_string(THD *thd, String *buf, buf->append(STRING_WITH_LEN("FUNCTION ")); else buf->append(STRING_WITH_LEN("PROCEDURE ")); - append_identifier(thd, buf, name->m_name.str, name->m_name.length); + if (dblen > 0) + { + append_identifier(thd, buf, db, dblen); + buf->append('.'); + } + append_identifier(thd, buf, name, namelen); buf->append('('); buf->append(params, paramslen); buf->append(')'); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f7119323055..4556d70e4c3 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -522,6 +522,8 @@ sp_head::init(LEX *lex) m_qname.str= NULL; m_qname.length= 0; + m_explicit_name= false; + m_db.str= NULL; m_db.length= 0; @@ -564,6 +566,8 @@ sp_head::init_sp_name(THD *thd, sp_name *spname) m_name.str= strmake_root(thd->mem_root, spname->m_name.str, spname->m_name.length); + m_explicit_name= spname->m_explicit_name; + if (spname->m_qname.length == 0) spname->init_qname(thd); diff --git a/sql/sp_head.h b/sql/sp_head.h index 0e710196603..11ff7160c03 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -121,6 +121,7 @@ public: st_sp_chistics *m_chistics; ulong m_sql_mode; // For SHOW CREATE and execution LEX_STRING m_qname; // db.name + bool m_explicit_name; /**< Prepend the db name? */ /** Key representing routine in the set of stored routines used by statement. [routine_type]db.name\0 diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e9504f423ad..7592986ef81 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1382,7 +1382,7 @@ bool acl_check_host(const char *host, const char *ip) 1 ERROR ; In this case the error is sent to the client. */ -bool check_change_password(THD *thd, const char *host, const char *user, +int check_change_password(THD *thd, const char *host, const char *user, char *new_password, uint new_password_len) { if (!initialized) @@ -2763,7 +2763,7 @@ table_error: TRUE error */ -bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, +int mysql_table_grant(THD *thd, TABLE_LIST *table_list, List <LEX_USER> &user_list, List <LEX_COLUMN> &columns, ulong rights, bool revoke_grant) @@ -2880,6 +2880,12 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, } #endif + /* + The lock api is depending on the thd->lex variable which needs to be + re-initialized. + */ + Query_tables_list backup; + thd->lex->reset_n_backup_query_tables_list(&backup); if (simple_open_n_lock_tables(thd,tables)) { // Should never happen close_thread_tables(thd); /* purecov: deadcode */ @@ -3018,6 +3024,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, send_ok(thd); /* Tables are automatically closed */ + thd->lex->restore_backup_query_tables_list(&backup); DBUG_RETURN(result); } @@ -5805,7 +5812,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, < 0 Error. Error message not yet sent. */ -bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, +int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc) { Security_context *sctx= thd->security_ctx; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index b2007ccdf47..1efcd2e3b6b 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -183,13 +183,13 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, char *ip, char *db); bool acl_check_host(const char *host, const char *ip); -bool check_change_password(THD *thd, const char *host, const char *user, +int check_change_password(THD *thd, const char *host, const char *user, char *password, uint password_len); bool change_password(THD *thd, const char *host, const char *user, char *password); bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list, ulong rights, bool revoke); -bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list, +int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list, List <LEX_COLUMN> &column_list, ulong rights, bool revoke); bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc, @@ -225,7 +225,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table); bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc); -bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, +int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc); bool check_routine_level_acl(THD *thd, const char *db, const char *name, bool is_proc); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 95a7fb3d34d..4b3264069b5 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -195,13 +195,13 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) */ for (; str != end && my_isspace(system_charset_info, *str); str++) ; if (str == end) - return 0; + DBUG_RETURN(0); if (*str == '-') { info->negative = 1; if (++str == end || *str == '0') // converting -0 to a number - return 0; // might lose information + DBUG_RETURN(0); // might lose information } else info->negative = 0; @@ -219,33 +219,33 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) int error; info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error); if (info->integers == 1) - return 0; // a single number can't be zerofill + DBUG_RETURN(0); // a single number can't be zerofill info->maybe_zerofill = 1; - return 1; // a zerofill number, or an integer + DBUG_RETURN(1); // a zerofill number, or an integer } if (*str == '.' || *str == 'e' || *str == 'E') { if (info->zerofill) // can't be zerofill anymore - return 0; + DBUG_RETURN(0); if ((str + 1) == end) // number was something like '123[.eE]' { char *endpos= (char*) str; int error; info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error); - return 1; + DBUG_RETURN(1); } if (*str == 'e' || *str == 'E') // number may be something like '1e+50' { str++; if (*str != '-' && *str != '+') - return 0; + DBUG_RETURN(0); for (str++; str != end && my_isdigit(system_charset_info,*str); str++) ; if (str == end) { info->is_float = 1; // we can't use variable decimals here - return 1; + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end if (str == end) // number was something like '123.000' @@ -253,17 +253,17 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) char *endpos= (char*) str; int error; info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error); - return 1; + DBUG_RETURN(1); } for (; str != end && my_isdigit(system_charset_info,*str); str++) info->decimals++; if (str == end) { info->dval = my_atof(begin); - return 1; + DBUG_RETURN(1); } } - return 0; + DBUG_RETURN(0); } @@ -683,7 +683,7 @@ int analyse::send_row(List<Item> &field_list __attribute__((unused))) } // analyse::send_row -bool analyse::end_of_records() +int analyse::end_of_records() { field_info **f = f_info; char buff[MAX_FIELD_WIDTH]; diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 21a37209e89..2a4226b2d95 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -350,7 +350,7 @@ public: virtual bool change_columns(List<Item> &fields); virtual int send_row(List<Item> &fields); virtual void end_group(void) {} - virtual bool end_of_records(void); + virtual int end_of_records(void); friend Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 89c16b7e54c..9cdcc2bbb75 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3046,7 +3046,7 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) The lock will automaticaly be freed by close_thread_tables() */ -bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) +int open_and_lock_tables(THD *thd, TABLE_LIST *tables) { uint counter; bool need_reopen; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 226117f4e2f..6da6925e82d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -639,6 +639,13 @@ void THD::cleanup_after_query() { clear_next_insert_id= 0; next_insert_id= 0; + + /* + BUG#33029, if one statement in a SP set this member to 1, all + statment after this statement in the SP would be considered used + INSERT_ID value, reset this member after each query to fix this. + */ + insert_id_used= 0; } /* Reset rand_used so that detection of calls to rand() will save random diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 91b0c02d23b..e25ede1be03 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -449,7 +449,7 @@ bool load_db_opt_by_name(THD *thd, const char *db_name, */ -bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) { char path[FN_REFLEN+16]; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index eeb77cef583..b9177f65ad5 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -375,7 +375,7 @@ cleanup: FALSE OK TRUE error */ -bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) { Item *fake_conds= 0; SELECT_LEX *select_lex= &thd->lex->select_lex; @@ -438,7 +438,7 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) TRUE Error */ -bool mysql_multi_delete_prepare(THD *thd) +int mysql_multi_delete_prepare(THD *thd) { LEX *lex= thd->lex; TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxiliary_table_list.first; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f2a539fd02b..68c402d9895 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -708,9 +708,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, error=0; id=0; + thd_proc_info(thd, "update"); if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + if (duplic == DUP_REPLACE) { if (!table->triggers || !table->triggers->has_delete_triggers()) @@ -736,8 +738,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, values_list.elements, and - if nothing else - to initialize the code to make the call of end_bulk_insert() below safe. */ - if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode) - table->file->start_bulk_insert(values_list.elements); +#ifndef EMBEDDED_LIBRARY + if (lock_type != TL_WRITE_DELAYED) +#endif /* EMBEDDED_LIBRARY */ + { + if (duplic != DUP_ERROR || ignore) + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + if (!thd->prelocked_mode) + table->file->start_bulk_insert(values_list.elements); + } thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | @@ -863,6 +872,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, else if (table->next_number_field && info.copied) id=table->next_number_field->val_int(); // Return auto_increment value + if (duplic != DUP_ERROR || ignore) + table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + transactional_table= table->file->has_transactions(); if ((changed= (info.copied || info.deleted || info.updated))) @@ -942,8 +954,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->next_insert_id=0; // Reset this if wrongly used table->auto_increment_field_not_null= FALSE; - if (duplic != DUP_ERROR || ignore) - table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); if (duplic == DUP_REPLACE && (!table->triggers || !table->triggers->has_delete_triggers())) table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); @@ -1283,7 +1293,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds); select_lex->first_execution= 0; } - if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) + /* + Only call extra() handler method if we are not performing a DELAYED + operation. It will instead be executed by delayed insert thread. + */ + if ((duplic == DUP_UPDATE || duplic == DUP_REPLACE) && + (table->reginfo.lock_type != TL_WRITE_DELAYED)) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); DBUG_RETURN(FALSE); } @@ -2453,6 +2468,9 @@ bool Delayed_insert::handle_inserts(void) info.ignore= row->ignore; info.handle_duplicates= row->dup; + if (info.handle_duplicates == DUP_UPDATE || + info.handle_duplicates == DUP_REPLACE) + table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); if (info.ignore || info.handle_duplicates != DUP_ERROR) { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b669919dba6..468bae02b13 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1253,6 +1253,7 @@ void st_select_lex::init_select() non_agg_fields.empty(); cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); + full_group_by_flag= 0; } /* @@ -1491,8 +1492,6 @@ bool st_select_lex::test_limit() "LIMIT & IN/ALL/ANY/SOME subquery"); return(1); } - // no sense in ORDER BY without LIMIT - order_list.empty(); return(0); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 890c18121bd..6878e2a4694 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -616,7 +616,16 @@ public: joins on the right. */ List<String> *prev_join_using; - + /* + Bitmap used in the ONLY_FULL_GROUP_BY_MODE to prevent mixture of aggregate + functions and non aggregated fields when GROUP BY list is absent. + Bits: + 0 - non aggregated fields are used in this select, + defined as NON_AGG_FIELD_USED. + 1 - aggregate functions are used in this select, + defined as SUM_FUNC_USED. + */ + uint8 full_group_by_flag; void init_query(); void init_select(); st_select_lex_unit* master_unit(); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d687ceff393..e9fd04dff15 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -110,7 +110,7 @@ static bool write_execute_load_query_log_event(THD *thd, TRUE - error / FALSE - success */ -bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, +int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, List<Item> &fields_vars, List<Item> &set_fields, List<Item> &set_values, enum enum_duplicates handle_duplicates, bool ignore, @@ -233,9 +233,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, while ((item= it++)) { - if (item->type() == Item::FIELD_ITEM) + Item *real_item= item->real_item(); + + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field*)item)->field; + Field *field= ((Item_field*)real_item)->field; if (field->flags & BLOB_FLAG) { use_blobs= 1; @@ -244,7 +246,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else tot_length+= field->field_length; } - else + else if (item->type() == Item::STRING_ITEM) use_vars= 1; } if (use_blobs && !ex->line_term->length() && !field_term->length()) @@ -705,6 +707,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { uint length; byte *pos; + Item *real_item; if (read_info.read_field()) break; @@ -716,14 +719,17 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, pos=read_info.row_start; length=(uint) (read_info.row_end-pos); + real_item= item->real_item(); + if (!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL"))) || (length == 1 && read_info.found_null)) { - if (item->type() == Item::FIELD_ITEM) + + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name, @@ -740,25 +746,39 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_WARN_NULL_TO_NOTNULL, 1); } } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_null_value( read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } + continue; } - if (item->type() == Item::FIELD_ITEM) + if (real_item->type() == Item::FIELD_ITEM) { - - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker if (field == table->next_number_field) table->auto_increment_field_not_null= TRUE; field->store((char*) pos, length, read_info.read_charset); } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, - read_info.read_charset); + read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } } if (read_info.error) break; @@ -774,9 +794,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { - if (item->type() == Item::FIELD_ITEM) + Item *real_item= item->real_item(); + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name, @@ -796,9 +817,16 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_WARN_TOO_FEW_RECORDS, ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_null_value( read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dee3f2b5b22..ccd131e5f90 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2538,10 +2538,10 @@ static void reset_one_shot_variables(THD *thd) TRUE Error */ -bool +int mysql_execute_command(THD *thd) { - bool res= FALSE; + int res= FALSE; bool need_start_waiting= FALSE; // have protection against global read lock int up_result= 0; LEX *lex= thd->lex; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 33eeff03d0a..ae6764254cd 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1403,7 +1403,7 @@ error: */ static bool select_like_stmt_test(Prepared_statement *stmt, - bool (*specific_prepare)(THD *thd), + int (*specific_prepare)(THD *thd), ulong setup_tables_done_option) { DBUG_ENTER("select_like_stmt_test"); @@ -1441,7 +1441,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt, static bool select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt, TABLE_LIST *tables, - bool (*specific_prepare)(THD *thd), + int (*specific_prepare)(THD *thd), ulong setup_tables_done_option) { DBUG_ENTER("select_like_stmt_test_with_open_n_lock"); @@ -1630,7 +1630,7 @@ error: because mysql_handle_derived uses local tables lists. */ -static bool mysql_insert_select_prepare_tester(THD *thd) +static int mysql_insert_select_prepare_tester(THD *thd) { SELECT_LEX *first_select= &thd->lex->select_lex; TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)-> diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d6e1582544e..9492fd5337a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -568,37 +568,13 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check if there are references to un-aggregated columns when computing aggregate functions with implicit grouping (there is no GROUP BY). - TODO: Add check of calculation of GROUP functions and fields: - SELECT COUNT(*)+table.col1 from table1; */ - if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && + select_lex->full_group_by_flag == (NON_AGG_FIELD_USED | SUM_FUNC_USED)) { - if (!group_list) - { - uint flag=0; - List_iterator_fast<Item> it(fields_list); - Item *item; - while ((item= it++)) - { - if (item->with_sum_func) - flag|=1; - else if (!(flag & 2) && !item->const_during_execution()) - flag|=2; - } - if (having) - { - if (having->with_sum_func) - flag |= 1; - else if (!having->const_during_execution()) - flag |= 2; - } - if (flag == 3) - { - my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, - ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); - DBUG_RETURN(-1); - } - } + my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, + ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); + DBUG_RETURN(-1); } { /* Caclulate the number of groups */ @@ -857,6 +833,7 @@ JOIN::optimize() "Impossible HAVING" : "Impossible WHERE")); zero_result_cause= having_value == Item::COND_FALSE ? "Impossible HAVING" : "Impossible WHERE"; + tables= 0; error= 0; DBUG_RETURN(0); } @@ -2138,11 +2115,12 @@ JOIN::exec() /* With EXPLAIN EXTENDED we have to restore original ref_array for a derived table which is always materialized. - Otherwise we would not be able to print the query correctly. + We also need to do this when we have temp table(s). + Otherwise we would not be able to print the query correctly. */ - if (items0 && - (thd->lex->describe & DESCRIBE_EXTENDED) && - select_lex->linkage == DERIVED_TABLE_TYPE) + if (items0 && (thd->lex->describe & DESCRIBE_EXTENDED) && + (select_lex->linkage == DERIVED_TABLE_TYPE || + exec_tmp_table1 || exec_tmp_table2)) set_items_ref_array(items0); DBUG_VOID_RETURN; @@ -14482,7 +14460,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, ifield->db_name= iref->db_name; } #ifndef DBUG_OFF - if (_db_on_ && !item_field->name) + if (!item_field->name) { char buff[256]; String str(buff,sizeof(buff),&my_charset_bin); @@ -15818,6 +15796,14 @@ void st_select_lex::print(THD *thd, String *str) /* go through join tree */ print_join(thd, str, &top_join_list); } + else if (where) + { + /* + "SELECT 1 FROM DUAL WHERE 2" should not be printed as + "SELECT 1 WHERE 2": the 1st syntax is valid, but the 2nd is not. + */ + str->append(STRING_WITH_LEN(" from DUAL ")); + } // Where Item *cur_where= where; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1eb6838d98e..1230e8df494 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4105,9 +4105,11 @@ bool get_schema_tables_result(JOIN *join, { result= 1; join->error= 1; + tab->read_record.file= table_list->table->file; table_list->schema_table_state= executed_place; break; } + tab->read_record.file= table_list->table->file; table_list->schema_table_state= executed_place; } } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 48bdfd87f9f..accd943a05b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2118,6 +2118,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, const char **ext= table->file->bas_ext(); MY_STAT stat_info; + if (table->s->frm_version != FRM_VER_TRUE_VARCHAR) + { + error= send_check_errmsg(thd, table_list, "repair", + "Failed reparing incompatible .FRM file"); + goto end; + } + /* Check if this is a table type that stores index and data separately, like ISAM or MyISAM. We assume fixed order of engine file name diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 25a0540e4dd..da5e118b069 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -444,7 +444,9 @@ bool st_select_lex_unit::exec() } /* re-enabling indexes for next subselect iteration */ if (union_distinct && table->file->enable_indexes(HA_KEY_SWITCH_ALL)) + { DBUG_ASSERT(0); + } } for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e4965748e24..7c619092df1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -716,7 +716,7 @@ static table_map get_table_map(List<Item> *items) TRUE Error */ -bool mysql_multi_update_prepare(THD *thd) +int mysql_multi_update_prepare(THD *thd) { LEX *lex= thd->lex; TABLE_LIST *table_list= lex->query_tables; @@ -1440,6 +1440,12 @@ bool multi_update::send_data(List<Item> ¬_used_values) tbl->file->position(tbl->record[0]); memcpy((char*) tmp_table->field[field_num]->ptr, (char*) tbl->file->ref, tbl->file->ref_length); + /* + For outer joins a rowid field may have no NOT_NULL_FLAG, + so we have to reset NULL bit for this field. + (set_notnull() resets NULL bit only if available). + */ + tmp_table->field[field_num]->set_notnull(); field_num++; } while ((tbl= tbl_it++)); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 3056109e86b..fee71e01c78 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -649,7 +649,11 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, buff.append(')'); } buff.append(STRING_WITH_LEN(" AS ")); - buff.append(views->source.str, views->source.length); + buff.append(views->query.str, views->query.length); + if (views->with_check == VIEW_CHECK_LOCAL) + buff.append(STRING_WITH_LEN(" WITH LOCAL CHECK OPTION")); + else if (views->with_check == VIEW_CHECK_CASCADED) + buff.append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION")); Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE); mysql_bin_log.write(&qinfo); @@ -926,8 +930,6 @@ loop_out: } DBUG_RETURN(0); err: - view->query.str= NULL; - view->query.length= 0; view->md5.str= NULL; view->md5.length= 0; DBUG_RETURN(error); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6eae98e14db..02692855c4d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1187,7 +1187,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); single_multi table_wild_list table_wild_one opt_wild union_clause union_list precision subselect_start opt_and charset - subselect_end select_var_list select_var_list_init help opt_len + subselect_end select_var_list select_var_list_init help opt_field_length field_length opt_extended_describe prepare prepare_src execute deallocate statement sp_suid @@ -3144,45 +3144,38 @@ field_spec: }; type: - int_type opt_len field_options { $$=$1; } + int_type opt_field_length field_options { $$=$1; } | real_type opt_precision field_options { $$=$1; } | FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; } | BIT_SYM { Lex->length= (char*) "1"; $$=FIELD_TYPE_BIT; } - | BIT_SYM '(' NUM ')' { Lex->length= $3.str; - $$=FIELD_TYPE_BIT; } + | BIT_SYM field_length { $$=FIELD_TYPE_BIT; } | BOOL_SYM { Lex->length=(char*) "1"; $$=FIELD_TYPE_TINY; } | BOOLEAN_SYM { Lex->length=(char*) "1"; $$=FIELD_TYPE_TINY; } - | char '(' NUM ')' opt_binary { Lex->length=$3.str; - $$=FIELD_TYPE_STRING; } + | char field_length opt_binary { $$=FIELD_TYPE_STRING; } | char opt_binary { Lex->length=(char*) "1"; $$=FIELD_TYPE_STRING; } - | nchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str; - $$=FIELD_TYPE_STRING; + | nchar field_length opt_bin_mod { $$=FIELD_TYPE_STRING; Lex->charset=national_charset_info; } | nchar opt_bin_mod { Lex->length=(char*) "1"; $$=FIELD_TYPE_STRING; Lex->charset=national_charset_info; } - | BINARY '(' NUM ')' { Lex->length=$3.str; - Lex->charset=&my_charset_bin; + | BINARY field_length { Lex->charset=&my_charset_bin; $$=FIELD_TYPE_STRING; } | BINARY { Lex->length= (char*) "1"; Lex->charset=&my_charset_bin; $$=FIELD_TYPE_STRING; } - | varchar '(' NUM ')' opt_binary { Lex->length=$3.str; - $$= MYSQL_TYPE_VARCHAR; } - | nvarchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str; - $$= MYSQL_TYPE_VARCHAR; + | varchar field_length opt_binary { $$= MYSQL_TYPE_VARCHAR; } + | nvarchar field_length opt_bin_mod { $$= MYSQL_TYPE_VARCHAR; Lex->charset=national_charset_info; } - | VARBINARY '(' NUM ')' { Lex->length=$3.str; - Lex->charset=&my_charset_bin; + | VARBINARY field_length { Lex->charset=&my_charset_bin; $$= MYSQL_TYPE_VARCHAR; } - | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; } + | YEAR_SYM opt_field_length field_options { $$=FIELD_TYPE_YEAR; } | DATE_SYM { $$=FIELD_TYPE_DATE; } | TIME_SYM { $$=FIELD_TYPE_TIME; } - | TIMESTAMP opt_len + | TIMESTAMP opt_field_length { if (YYTHD->variables.sql_mode & MODE_MAXDB) $$=FIELD_TYPE_DATETIME; @@ -3198,7 +3191,7 @@ type: | DATETIME { $$=FIELD_TYPE_DATETIME; } | TINYBLOB { Lex->charset=&my_charset_bin; $$=FIELD_TYPE_TINY_BLOB; } - | BLOB_SYM opt_len { Lex->charset=&my_charset_bin; + | BLOB_SYM opt_field_length { Lex->charset=&my_charset_bin; $$=FIELD_TYPE_BLOB; } | spatial_type { @@ -3220,7 +3213,7 @@ type: $$=FIELD_TYPE_MEDIUM_BLOB; } | LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } | TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_BLOB; } - | TEXT_SYM opt_len opt_binary { $$=FIELD_TYPE_BLOB; } + | TEXT_SYM opt_field_length opt_binary { $$=FIELD_TYPE_BLOB; } | MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } | LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; } | DECIMAL_SYM float_options field_options @@ -3293,7 +3286,7 @@ real_type: float_options: /* empty */ { Lex->dec=Lex->length= (char*)0; } - | '(' NUM ')' { Lex->length=$2.str; Lex->dec= (char*)0; } + | field_length { Lex->dec= (char*)0; } | precision {}; precision: @@ -3316,9 +3309,15 @@ field_option: | UNSIGNED { Lex->type|= UNSIGNED_FLAG;} | ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; }; -opt_len: - /* empty */ { Lex->length=(char*) 0; } /* use default length */ - | '(' NUM ')' { Lex->length= $2.str; }; +opt_field_length: + /* empty */ { Lex->length=(char*) NULL; } /* use default length */ + | field_length {}; + +field_length: + '(' LONG_NUM ')' { Lex->length= $2.str; } + | '(' ULONGLONG_NUM ')' { Lex->length= $2.str; } + | '(' DECIMAL_NUM ')' { Lex->length= $2.str; } + | '(' NUM ')' { Lex->length= $2.str; }; opt_precision: /* empty */ {} @@ -5587,9 +5586,9 @@ in_sum_expr: }; cast_type: - BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } - | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; } - | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } + BINARY opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } + | CHAR_SYM opt_field_length opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; } + | NCHAR_SYM opt_field_length { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; } | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } diff --git a/sql/tztime.cc b/sql/tztime.cc index bedbf921cae..709e3b64752 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1035,7 +1035,7 @@ public: return lowest possible my_time_t in case of ambiguity or if we provide time corresponding to the time-gap. - You should call init_time() function before using this function. + You should call my_init_time() function before using this function. RETURN VALUE Corresponding my_time_t value or 0 in case of error @@ -2278,7 +2278,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) DBUG_ENTER("my_tz_find"); DBUG_PRINT("enter", ("time zone name='%s'", - name ? ((String *)name)->c_ptr() : "NULL")); + name ? ((String *)name)->c_ptr_safe() : "NULL")); DBUG_ASSERT(!time_zone_tables_exist || tz_tables || current_thd->slave_thread); @@ -2757,7 +2757,7 @@ main(int argc, char **argv) } printf("gmt_sec_to_TIME = localtime for time_t in [1000000000,1100000000) range\n"); - init_time(); + my_init_time(); /* Be careful here! my_system_gmt_sec doesn't fully handle unnormalized diff --git a/sql/unireg.h b/sql/unireg.h index d8301060cc4..1326b22c8c9 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -60,6 +60,7 @@ #define MAX_MBWIDTH 3 /* Max multibyte sequence */ #define MAX_FIELD_CHARLENGTH 255 #define MAX_FIELD_VARCHARLENGTH 65535 +#define MAX_FIELD_BLOBLENGTH UINT_MAX32 /* cf field_blob::get_length() */ #define CONVERT_IF_BIGGER_TO_BLOB 512 /* Used for CREATE ... SELECT */ /* Max column width +1 */ |