diff options
author | unknown <svoj@mysql.com> | 2005-06-28 16:07:16 +0500 |
---|---|---|
committer | unknown <svoj@mysql.com> | 2005-06-28 16:07:16 +0500 |
commit | dc9bf5450508b862b11229bd5f48e14403c90849 (patch) | |
tree | 2a9be970ca27eec9fade7fd4f85fbb737c699b24 /sql | |
parent | 290b841147d7f5538a847c560e11f535eb875001 (diff) | |
parent | ba2261e3fdd753f39ca00ed647a357aab4b1b8d6 (diff) | |
download | mariadb-git-dc9bf5450508b862b11229bd5f48e14403c90849.tar.gz |
Merge svojtovich@bk-internal.mysql.com:/home/bk/mysql-5.1
into mysql.com:/home/svoj/devel/mysql/WL2535-mysql-5.1
storage/myisam/ft_boolean_search.c:
Auto merged
Diffstat (limited to 'sql')
69 files changed, 1878 insertions, 1370 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index b9a9bdaec74..0b6610fab55 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -112,8 +112,8 @@ DEFS = -DMYSQL_SERVER \ -DDATADIR="\"$(MYSQLDATAdir)\"" \ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \ @DEFS@ -# Don't put lex_hash.h in BUILT_SOURCES as this will give infinite recursion -BUILT_SOURCES = sql_yacc.cc sql_yacc.h + +BUILT_SOURCES = sql_yacc.cc sql_yacc.h lex_hash.h EXTRA_DIST = udf_example.cc $(BUILT_SOURCES) DISTCLEANFILES = lex_hash.h AM_YFLAGS = -d @@ -132,9 +132,6 @@ link_sources: mysql_tzinfo_to_sql.cc rm -f my_time.c @LN_CP_F@ ../sql-common/my_time.c my_time.c -gen_lex_hash.o: gen_lex_hash.cc lex.h - $(CXXCOMPILE) -c $(INCLUDES) $< - mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES) $(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $< @@ -149,13 +146,9 @@ sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS) @echo "If it fails, re-run configure with --with-low-memory" $(CXXCOMPILE) $(LM_CFLAGS) -c $< -lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h - $(MAKE) gen_lex_hash$(EXEEXT) +lex_hash.h: gen_lex_hash$(EXEEXT) ./gen_lex_hash$(EXEEXT) > $@ -# Hack to ensure that lex_hash.h is built early -sql_lex.o: lex_hash.h - # For testing of udf_example.so; Works on platforms with gcc # (This is not part of our build process but only provided as an example) udf_example.so: udf_example.cc diff --git a/sql/field.cc b/sql/field.cc index 78b08fa3cd9..16bf63e96fc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -38,7 +38,7 @@ Instansiate templates and static variables *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List<create_field>; template class List_iterator<create_field>; #endif @@ -982,6 +982,39 @@ Item_result Field::result_merge_type(enum_field_types field_type) Static help functions *****************************************************************************/ + +/* + Check whether a field type can be partially indexed by a key + + This is a static method, rather than a virtual function, because we need + to check the type of a non-Field in mysql_alter_table(). + + SYNOPSIS + type_can_have_key_part() + type field type + + RETURN + TRUE Type can have a prefixed key + FALSE Type can not have a prefixed key +*/ + +bool Field::type_can_have_key_part(enum enum_field_types type) +{ + switch (type) { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + return TRUE; + default: + return FALSE; + } +} + + /* Numeric fields base class constructor */ @@ -1888,7 +1921,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) int_digits_added_zeros=0; } } - tmp_uint= (tmp_dec+(int_digits_end-int_digits_from)+ + tmp_uint= (uint) (tmp_dec+(int_digits_end-int_digits_from)+ (uint)(frac_digits_from-int_digits_tail_from)+ int_digits_added_zeros); } @@ -2447,7 +2480,7 @@ int Field_new_decimal::store(longlong nr) int err; if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, - nr, unsigned_flag, &decimal_value))) + nr, false, &decimal_value))) { if (check_overflow(err)) set_value_on_overflow(&decimal_value, decimal_value.sign()); @@ -5924,14 +5957,6 @@ longlong Field_string::val_int(void) } -my_decimal *Field_longstr::val_decimal(my_decimal *decimal_value) -{ - str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(), - decimal_value); - return decimal_value; -} - - String *Field_string::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -5943,6 +5968,14 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)), } +my_decimal *Field_string::val_decimal(my_decimal *decimal_value) +{ + str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(), + decimal_value); + return decimal_value; +} + + int Field_string::cmp(const char *a_ptr, const char *b_ptr) { uint a_len, b_len; @@ -6256,6 +6289,15 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), } +my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value) +{ + uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); + str2my_decimal(E_DEC_FATAL_ERROR, ptr+length_bytes, length, charset(), + decimal_value); + return decimal_value; +} + + int Field_varstring::cmp(const char *a_ptr, const char *b_ptr) { uint a_length, b_length; @@ -6874,6 +6916,18 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)), } +my_decimal *Field_blob::val_decimal(my_decimal *decimal_value) +{ + char *blob; + memcpy_fixed(&blob, ptr+packlength, sizeof(char*)); + if (!blob) + blob= ""; + str2my_decimal(E_DEC_FATAL_ERROR, blob, get_length(ptr), charset(), + decimal_value); + return decimal_value; +} + + int Field_blob::cmp(const char *a,uint32 a_length, const char *b, uint32 b_length) { @@ -7702,9 +7756,9 @@ bool Field_enum::eq_def(Field *field) for (uint i=0 ; i < from_lib->count ; i++) if (my_strnncoll(field_charset, (const uchar*)typelib->type_names[i], - strlen(typelib->type_names[i]), + (uint) strlen(typelib->type_names[i]), (const uchar*)from_lib->type_names[i], - strlen(from_lib->type_names[i]))) + (uint) strlen(from_lib->type_names[i]))) return 0; return 1; } @@ -8562,7 +8616,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, { char str_nr[22]; char *str_end= longlong10_to_str(nr, str_nr, -10); - make_truncated_value_warning(table->in_use, str_nr, str_end - str_nr, + make_truncated_value_warning(table->in_use, str_nr, + (uint) (str_end - str_nr), ts_type, field_name); } } diff --git a/sql/field.h b/sql/field.h index b99acd43123..f297b17fd67 100644 --- a/sql/field.h +++ b/sql/field.h @@ -25,6 +25,7 @@ #endif #define NOT_FIXED_DEC 31 +#define DATETIME_DEC 6 class Send_field; class Protocol; @@ -123,6 +124,7 @@ public: virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } virtual Item_result cast_to_int_type () const { return result_type(); } + static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); bool eq(Field *field) @@ -384,7 +386,6 @@ public: field_name_arg, table_arg, charset) {} - my_decimal *val_decimal(my_decimal *); int store_decimal(const my_decimal *d); }; @@ -945,6 +946,7 @@ public: enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } #endif enum Item_result cmp_type () const { return INT_RESULT; } + uint decimals() const { return DATETIME_DEC; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); int store(longlong nr); @@ -996,6 +998,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); int cmp(const char *,const char*); void sort_string(char *buff,uint length); void sql_type(String &str) const; @@ -1054,6 +1057,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); int cmp(const char *,const char*); void sort_string(char *buff,uint length); void get_key_image(char *buff,uint length, imagetype type); @@ -1109,6 +1113,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); int cmp(const char *,const char*); int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length); int cmp_binary(const char *a,const char *b, uint32 max_length=~0L); diff --git a/sql/filesort.cc b/sql/filesort.cc index 30ebd8d59e1..75da43afed5 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -631,7 +631,7 @@ static void make_sortkey(register SORTPARAM *param, *to++=1; /* All item->str() to use some extra byte for end null.. */ String tmp((char*) to,sort_field->length+4,cs); - String *res=item->val_str(&tmp); + String *res= item->str_result(&tmp); if (!res) { if (maybe_null) @@ -673,8 +673,8 @@ static void make_sortkey(register SORTPARAM *param, } case INT_RESULT: { - longlong value=item->val_int(); - if (maybe_null) + longlong value= item->val_int_result(); + if (maybe_null) { *to++=1; /* purecov: inspected */ if (item->null_value) @@ -715,7 +715,7 @@ static void make_sortkey(register SORTPARAM *param, } case DECIMAL_RESULT: { - my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf); + my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf); if (maybe_null) { if (item->null_value) @@ -733,7 +733,7 @@ static void make_sortkey(register SORTPARAM *param, } case REAL_RESULT: { - double value= item->val_real(); + double value= item->val_result(); if (maybe_null) { if (item->null_value) diff --git a/sql/gstream.cc b/sql/gstream.cc index f7d11d76b0c..4083cb2fe71 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -83,7 +83,7 @@ bool Gis_read_stream::get_next_number(double *d) } *d = my_strntod(m_charset, (char *)m_cur, - m_limit-m_cur, &endptr, &err); + (uint) (m_limit-m_cur), &endptr, &err); if (err) return 1; if (endptr) @@ -115,6 +115,6 @@ bool Gis_read_stream::check_next_symbol(char symbol) void Gis_read_stream::set_error_msg(const char *msg) { size_t len= strlen(msg); // ok in this context - m_err_msg= (char *) my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR)); + m_err_msg= (char *) my_realloc(m_err_msg, (uint) len + 1, MYF(MY_ALLOW_ZERO_PTR)); memcpy(m_err_msg, msg, len + 1); } diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 16cbd782f0c..568fb727e63 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -948,12 +948,6 @@ int ha_berkeley::write_row(byte * record) for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) { key_map changed_keys(0); - if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) - { - if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */ - break; /* purecov: deadcode */ - DBUG_PRINT("trans",("starting subtransaction")); /* purecov: deadcode */ - } if (!(error=file->put(file, sub_trans, create_key(&prim_key, primary_key, key_buff, record), &row, key_type[primary_key]))) @@ -983,12 +977,7 @@ int ha_berkeley::write_row(byte * record) if (using_ignore) { int new_error = 0; - if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS) - { - DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */ - new_error=txn_abort(sub_trans); /* purecov: deadcode */ - } - else if (!changed_keys.is_clear_all()) + if (!changed_keys.is_clear_all()) { new_error = 0; for (uint keynr=0; @@ -1010,11 +999,6 @@ int ha_berkeley::write_row(byte * record) } } } - else if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) - { - DBUG_PRINT("trans",("committing subtransaction")); /* purecov: deadcode */ - error=txn_commit(sub_trans, 0); /* purecov: deadcode */ - } if (error != DB_LOCK_DEADLOCK) break; } @@ -1090,8 +1074,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, { // Probably a duplicated key; restore old key and row if needed last_dup_key=primary_key; - if (local_using_ignore && - !(thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) + if (local_using_ignore) { int new_error; if ((new_error=pack_row(&row, old_row, 0)) || @@ -1202,12 +1185,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) { key_map changed_keys(0); - if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) - { - if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */ - break; /* purecov: deadcode */ - DBUG_PRINT("trans",("starting subtransaction")); /* purecov: deadcode */ - } /* Start by updating the primary key */ if (!(error=update_primary_key(sub_trans, primary_key_changed, old_row, &old_prim_key, @@ -1223,15 +1200,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) { if ((error=remove_key(sub_trans, keynr, old_row, &old_prim_key))) { - if (using_ignore && /* purecov: inspected */ - (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) - { - int new_error; - DBUG_PRINT("trans",("aborting subtransaction")); - new_error=txn_abort(sub_trans); - if (new_error) - error = new_error; - } table->insert_or_update= 0; DBUG_RETURN(error); // Fatal error /* purecov: inspected */ } @@ -1254,12 +1222,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) if (using_ignore) { int new_error = 0; - if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS) - { - DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */ - new_error=txn_abort(sub_trans); /* purecov: deadcode */ - } - else if (!changed_keys.is_clear_all()) + if (!changed_keys.is_clear_all()) new_error=restore_keys(transaction, &changed_keys, primary_key, old_row, &old_prim_key, new_row, &prim_key, thd_options); @@ -1271,11 +1234,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) } } } - else if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) - { - DBUG_PRINT("trans",("committing subtransaction")); /* purecov: deadcode */ - error=txn_commit(sub_trans, 0); /* purecov: deadcode */ - } if (error != DB_LOCK_DEADLOCK) break; } @@ -1385,34 +1343,11 @@ int ha_berkeley::delete_row(const byte * record) DB_TXN *sub_trans = transaction; for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) { - if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS) - { - if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */ - break; /* purecov: deadcode */ - DBUG_PRINT("trans",("starting sub transaction")); /* purecov: deadcode */ - } error=remove_keys(sub_trans, record, &row, &prim_key, &keys); - if (!error && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)) - { - DBUG_PRINT("trans",("ending sub transaction")); /* purecov: deadcode */ - error=txn_commit(sub_trans, 0); /* purecov: deadcode */ - } if (error) { /* purecov: inspected */ DBUG_PRINT("error",("Got error %d",error)); - if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS) - { - /* retry */ - int new_error; - DBUG_PRINT("trans",("aborting subtransaction")); - if ((new_error=txn_abort(sub_trans))) - { - error=new_error; // This shouldn't happen - break; - } - } - else - break; // No retry - return error + break; // No retry - return error } if (error != DB_LOCK_DEADLOCK) break; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 844612e0643..c18ca5d7915 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -462,6 +462,12 @@ static int check_foreign_data_source(FEDERATED_SHARE *share) } else { + /* + Since we do not support transactions at this version, we can let the client + API silently reconnect. For future versions, we will need more logic to deal + with transactions + */ + mysql->reconnect= 1; /* Note: I am not using INORMATION_SCHEMA because this needs to work with < 5.0 if we can connect, then make sure the table exists @@ -988,6 +994,12 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql)); DBUG_RETURN(ER_CONNECT_TO_MASTER); } + /* + Since we do not support transactions at this version, we can let the client + API silently reconnect. For future versions, we will need more logic to deal + with transactions + */ + mysql->reconnect= 1; DBUG_RETURN(0); } diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 5d50270ec5b..2aa065e0d96 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -57,6 +57,7 @@ public: } const key_map *keys_to_use_for_scanning() { return &btree_keys; } uint max_supported_keys() const { return MAX_KEY; } + uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; } double scan_time() { return (double) (records+deleted) / 20.0+10; } double read_time(uint index, uint ranges, ha_rows rows) { return (double) rows / 20.0+1; } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0210e2b768f..78b70d9876a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -146,8 +146,7 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_buffer_pool_awe_mem_mb, innobase_buffer_pool_size, innobase_additional_mem_pool_size, innobase_file_io_threads, innobase_lock_wait_timeout, - innobase_thread_concurrency, innobase_force_recovery, - innobase_open_files; + innobase_force_recovery, innobase_open_files; /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -327,7 +326,7 @@ innodb_srv_conc_enter_innodb( /*=========================*/ trx_t* trx) /* in: transaction handle */ { - if (srv_thread_concurrency >= 500) { + if (UNIV_LIKELY(srv_thread_concurrency >= 20)) { return; } @@ -344,7 +343,7 @@ innodb_srv_conc_exit_innodb( /*========================*/ trx_t* trx) /* in: transaction handle */ { - if (srv_thread_concurrency >= 500) { + if (UNIV_LIKELY(srv_thread_concurrency >= 20)) { return; } @@ -564,7 +563,7 @@ innobase_mysql_print_thd( thd = (const THD*) input_thd; fprintf(f, "MySQL thread id %lu, query id %lu", - thd->thread_id, thd->query_id); + thd->thread_id, (ulong) thd->query_id); if (thd->host) { putc(' ', f); fputs(thd->host, f); @@ -1041,7 +1040,19 @@ mysql_get_identifier_quote_char( return(EOF); } return(get_quote_char_for_identifier((THD*) trx->mysql_thd, - name, namelen)); + name, (int) namelen)); +} + +/************************************************************************** +Determines if the currently running transaction has been interrupted. */ +extern "C" +ibool +trx_is_interrupted( +/*===============*/ + /* out: TRUE if interrupted */ + trx_t* trx) /* in: transaction */ +{ + return(trx && trx->mysql_thd && ((THD*) trx->mysql_thd)->killed); } /************************************************************************** @@ -1302,8 +1313,8 @@ innobase_init(void) data_mysql_default_charset_coll = (ulint)default_charset_info->number; - data_mysql_latin1_swedish_charset_coll = - (ulint)my_charset_latin1.number; + ut_a(DATA_MYSQL_LATIN1_SWEDISH_CHARSET_COLL == + my_charset_latin1.number); /* Store the latin1_swedish_ci character ordering table to InnoDB. For non-latin1_swedish_ci charsets we use the MySQL comparison functions, @@ -1794,7 +1805,7 @@ try_again: fprintf(stderr, "InnoDB: This transaction needs it to be sent up to\n" "InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name, - (uint)trx->repl_wait_binlog_pos); + (ulong)trx->repl_wait_binlog_pos); innobase_repl_state = 0; @@ -2022,7 +2033,7 @@ innobase_rollback_to_savepoint( longlong2str((ulonglong)savepoint, name, 36); - error = trx_rollback_to_savepoint_for_mysql(trx, name, + error = (int) trx_rollback_to_savepoint_for_mysql(trx, name, &mysql_binlog_cache_pos); DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); } @@ -2051,7 +2062,7 @@ innobase_release_savepoint( longlong2str((ulonglong)savepoint, name, 36); - error = trx_release_savepoint_for_mysql(trx, name); + error = (int) trx_release_savepoint_for_mysql(trx, name); DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); } @@ -2092,7 +2103,7 @@ innobase_savepoint( char name[64]; longlong2str((ulonglong)savepoint,name,36); - error = trx_savepoint_for_mysql(trx, name, (ib_longlong)0); + error = (int) trx_savepoint_for_mysql(trx, name, (ib_longlong)0); DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); } @@ -2663,7 +2674,7 @@ innobase_read_from_2_little_endian( /* out: value */ const mysql_byte* buf) /* in: from where to read */ { - return((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))); + return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))); } /*********************************************************************** @@ -2867,6 +2878,8 @@ build_template( ibool fetch_all_in_key = FALSE; ibool fetch_primary_key_cols = FALSE; ulint i; + /* byte offset of the end of last requested column */ + ulint mysql_prefix_len = 0; if (prebuilt->select_lock_type == LOCK_X) { /* We always retrieve the whole clustered index record if we @@ -2988,6 +3001,11 @@ build_template( get_field_offset(table, field); templ->mysql_col_len = (ulint) field->pack_length(); + if (mysql_prefix_len < templ->mysql_col_offset + + templ->mysql_col_len) { + mysql_prefix_len = templ->mysql_col_offset + + templ->mysql_col_len; + } templ->type = index->table->cols[i].type.mtype; templ->mysql_type = (ulint)field->type(); @@ -3010,6 +3028,7 @@ skip_field: } prebuilt->n_template = n_requested_fields; + prebuilt->mysql_prefix_len = mysql_prefix_len; if (index != clust_index && prebuilt->need_to_access_clustered) { /* Change rec_field_no's to correspond to the clustered index @@ -3081,7 +3100,7 @@ ha_innobase::write_row( being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */ dict_table_t* src_table; - ibool mode; + ulint mode; num_write_row = 0; @@ -3744,7 +3763,7 @@ ha_innobase::index_read( match_mode = ROW_SEL_EXACT_PREFIX; } - last_match_mode = match_mode; + last_match_mode = (uint) match_mode; innodb_srv_conc_enter_innodb(prebuilt->trx); @@ -3764,7 +3783,7 @@ ha_innobase::index_read( error = HA_ERR_KEY_NOT_FOUND; table->status = STATUS_NOT_FOUND; } else { - error = convert_error_code_to_mysql(ret, user_thd); + error = convert_error_code_to_mysql((int) ret, user_thd); table->status = STATUS_NOT_FOUND; } @@ -3916,7 +3935,7 @@ ha_innobase::general_fetch( error = HA_ERR_END_OF_FILE; table->status = STATUS_NOT_FOUND; } else { - error = convert_error_code_to_mysql(ret, user_thd); + error = convert_error_code_to_mysql((int) ret, user_thd); table->status = STATUS_NOT_FOUND; } @@ -4865,7 +4884,7 @@ innobase_drop_database( } ptr++; - namebuf = my_malloc(len + 2, MYF(0)); + namebuf = my_malloc((uint) len + 2, MYF(0)); memcpy(namebuf, ptr, len); namebuf[len] = '/'; @@ -5431,7 +5450,7 @@ ha_innobase::update_table_comment( info on foreign keys */ const char* comment)/* in: table comment defined by user */ { - uint length = strlen(comment); + uint length = (uint) strlen(comment); char* str; row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; @@ -5483,7 +5502,7 @@ ha_innobase::update_table_comment( *pos++ = ' '; } rewind(file); - flen = fread(pos, 1, flen, file); + flen = (uint) fread(pos, 1, flen, file); pos[flen] = 0; } @@ -5546,7 +5565,7 @@ ha_innobase::get_foreign_key_create_info(void) if (str) { rewind(file); - flen = fread(str, 1, flen, file); + flen = (uint) fread(str, 1, flen, file); str[flen] = 0; } @@ -5586,8 +5605,8 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list) while (tmp_buff[i] != '/') i++; tmp_buff+= i + 1; - f_key_info.forein_id= make_lex_string(thd, 0, - tmp_buff, strlen(tmp_buff), 1); + f_key_info.forein_id= make_lex_string(thd, 0, tmp_buff, + (uint) strlen(tmp_buff), 1); tmp_buff= foreign->referenced_table_name; i= 0; while (tmp_buff[i] != '/') @@ -5595,16 +5614,16 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list) f_key_info.referenced_db= make_lex_string(thd, 0, tmp_buff, i, 1); tmp_buff+= i + 1; - f_key_info.referenced_table= make_lex_string(thd, 0, - tmp_buff, strlen(tmp_buff), 1); + f_key_info.referenced_table= make_lex_string(thd, 0, tmp_buff, + (uint) strlen(tmp_buff), 1); for (i= 0;;) { tmp_buff= foreign->foreign_col_names[i]; - name= make_lex_string(thd, name, tmp_buff, strlen(tmp_buff), 1); + name= make_lex_string(thd, name, tmp_buff, (uint) strlen(tmp_buff), 1); f_key_info.foreign_fields.push_back(name); tmp_buff= foreign->referenced_col_names[i]; - name= make_lex_string(thd, name, tmp_buff, strlen(tmp_buff), 1); + name= make_lex_string(thd, name, tmp_buff, (uint) strlen(tmp_buff), 1); f_key_info.referenced_fields.push_back(name); if (++i >= foreign->n_fields) break; @@ -5992,12 +6011,12 @@ ha_innobase::external_lock( ulint error; error = row_lock_table_for_mysql(prebuilt, - NULL, LOCK_TABLE_EXP); + NULL, 0); if (error != DB_SUCCESS) { error = convert_error_code_to_mysql( - error, user_thd); - DBUG_RETURN(error); + (int) error, user_thd); + DBUG_RETURN((int) error); } } @@ -6012,9 +6031,6 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use--; prebuilt->mysql_has_locked = FALSE; - if (trx->n_lock_table_exp) { - row_unlock_tables_for_mysql(trx); - } /* If the MySQL lock count drops to zero we know that the current SQL statement has ended */ @@ -6056,7 +6072,7 @@ user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */ int ha_innobase::transactional_table_lock( /*==================================*/ - /* out: 0 */ + /* out: error code */ THD* thd, /* in: handle to the user thread */ int lock_type) /* in: lock type */ { @@ -6120,12 +6136,11 @@ ha_innobase::transactional_table_lock( if (thd->in_lock_tables && thd->variables.innodb_table_locks) { ulint error = DB_SUCCESS; - error = row_lock_table_for_mysql(prebuilt,NULL, - LOCK_TABLE_TRANSACTIONAL); + error = row_lock_table_for_mysql(prebuilt, NULL, 0); if (error != DB_SUCCESS) { - error = convert_error_code_to_mysql(error, user_thd); - DBUG_RETURN(error); + error = convert_error_code_to_mysql((int) error, user_thd); + DBUG_RETURN((int) error); } if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { @@ -6215,22 +6230,22 @@ innodb_show_status( rewind(srv_monitor_file); if (flen < MAX_STATUS_SIZE) { /* Display the entire output. */ - flen = fread(str, 1, flen, srv_monitor_file); + flen = (long) fread(str, 1, flen, srv_monitor_file); } else if (trx_list_end < (ulint) flen && trx_list_start < trx_list_end && trx_list_start + (flen - trx_list_end) < MAX_STATUS_SIZE - sizeof truncated_msg - 1) { /* Omit the beginning of the list of active transactions. */ - long len = fread(str, 1, trx_list_start, srv_monitor_file); + long len = (long) fread(str, 1, trx_list_start, srv_monitor_file); memcpy(str + len, truncated_msg, sizeof truncated_msg - 1); len += sizeof truncated_msg - 1; usable_len = (MAX_STATUS_SIZE - 1) - len; fseek(srv_monitor_file, flen - usable_len, SEEK_SET); - len += fread(str + len, 1, usable_len, srv_monitor_file); + len += (long) fread(str + len, 1, usable_len, srv_monitor_file); flen = len; } else { /* Omit the end of the output. */ - flen = fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file); + flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file); } mutex_exit_noninline(&srv_monitor_file_mutex); @@ -6792,7 +6807,7 @@ innobase_get_at_most_n_mbchars( ulint n_chars; /* number of characters in prefix */ CHARSET_INFO* charset; /* charset used in the field */ - charset = get_charset(charset_id, MYF(MY_WME)); + charset = get_charset((uint) charset_id, MYF(MY_WME)); ut_ad(charset); ut_ad(charset->mbmaxlen); @@ -6826,7 +6841,7 @@ innobase_get_at_most_n_mbchars( whole string. */ char_length = my_charpos(charset, str, - str + data_len, n_chars); + str + data_len, (int) n_chars); if (char_length > data_len) { char_length = data_len; } @@ -6949,7 +6964,7 @@ innobase_xa_prepare( ut_ad(trx->active_trans); - error = trx_prepare_for_mysql(trx); + error = (int) trx_prepare_for_mysql(trx); } else { /* We just mark the SQL statement ended and do not do a transaction prepare */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index f18d527e6b3..98496e748b4 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -228,7 +228,7 @@ extern long innobase_log_file_size, innobase_log_buffer_size; extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size; extern long innobase_buffer_pool_awe_mem_mb; extern long innobase_file_io_threads, innobase_lock_wait_timeout; -extern long innobase_force_recovery, innobase_thread_concurrency; +extern long innobase_force_recovery; extern long innobase_open_files; extern char *innobase_data_home_dir, *innobase_data_file_path; extern char *innobase_log_group_home_dir, *innobase_log_arch_dir; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 3f756eab0ee..27023ba4c64 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1068,7 +1068,7 @@ bool ha_myisam::check_and_repair(THD *thd) old_query_length= thd->query_length; pthread_mutex_lock(&LOCK_thread_count); thd->query= (char*) table->s->table_name; - thd->query_length= strlen(table->s->table_name); + thd->query_length= (uint32) strlen(table->s->table_name); pthread_mutex_unlock(&LOCK_thread_count); if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt)) diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index ec185c43fb8..794f1c62dd7 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -466,7 +466,7 @@ void ha_myisammrg::append_create_info(String *packet) MYRG_TABLE *open_table,*first; current_db= table->s->db; - db_length= strlen(current_db); + db_length= (uint) strlen(current_db); for (first=open_table=file->open_tables ; open_table != file->end_table ; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index f823dc97356..f1dbedc1af1 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -41,7 +41,7 @@ static const int parallelism= 0; // Default value for max number of transactions // createable against NDB from this handler -static const int max_transactions= 256; +static const int max_transactions= 3; // should really be 2 but there is a transaction to much allocated when loch table is used static const char *ha_ndb_ext=".ndb"; @@ -511,8 +511,13 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d", err.code, res)); if (res == HA_ERR_FOUND_DUPP_KEY) - m_dupkey= table->s->primary_key; - + { + if (m_rows_to_insert == 1) + m_dupkey= table->s->primary_key; + else + // We are batching inserts, offending key is not available + m_dupkey= (uint) -1; + } DBUG_RETURN(res); } @@ -540,13 +545,12 @@ bool ha_ndbcluster::get_error_message(int error, } +#ifndef DBUG_OFF /* Check if type is supported by NDB. - TODO Use this once in open(), not in every operation - */ -static inline bool ndb_supported_type(enum_field_types type) +static bool ndb_supported_type(enum_field_types type) { switch (type) { case MYSQL_TYPE_TINY: @@ -581,6 +585,7 @@ static inline bool ndb_supported_type(enum_field_types type) } return FALSE; } +#endif /* !DBUG_OFF */ /* @@ -610,15 +615,10 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, pack_len)); DBUG_DUMP("key", (char*)field_ptr, pack_len); - if (ndb_supported_type(field->type())) - { - if (! (field->flags & BLOB_FLAG)) - // Common implementation for most field types - DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0); - } - // Unhandled field types - DBUG_PRINT("error", ("Field type %d not supported", field->type())); - DBUG_RETURN(2); + DBUG_ASSERT(ndb_supported_type(field->type())); + DBUG_ASSERT(! (field->flags & BLOB_FLAG)); + // Common implementation for most field types + DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0); } @@ -637,7 +637,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, pack_len, field->is_null()?"Y":"N")); DBUG_DUMP("value", (char*) field_ptr, pack_len); - if (ndb_supported_type(field->type())) + DBUG_ASSERT(ndb_supported_type(field->type())); { // ndb currently does not support size 0 uint32 empty_field; @@ -715,9 +715,6 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, } DBUG_RETURN(1); } - // Unhandled field types - DBUG_PRINT("error", ("Field type %d not supported", field->type())); - DBUG_RETURN(2); } @@ -812,9 +809,8 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, if (field != NULL) { - DBUG_ASSERT(buf); - if (ndb_supported_type(field->type())) - { + DBUG_ASSERT(buf); + DBUG_ASSERT(ndb_supported_type(field->type())); DBUG_ASSERT(field->ptr != NULL); if (! (field->flags & BLOB_FLAG)) { @@ -845,10 +841,6 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_RETURN(ndb_blob->setActiveHook(g_get_ndb_blobs_value, arg) != 0); } DBUG_RETURN(1); - } - // Unhandled field types - DBUG_PRINT("error", ("Field type %d not supported", field->type())); - DBUG_RETURN(2); } // Used for hidden key only @@ -3040,6 +3032,13 @@ double ha_ndbcluster::scan_time() DBUG_RETURN(res); } +/* + Convert MySQL table locks into locks supported by Ndb Cluster. + Note that MySQL Cluster does currently not support distributed + table locks, so to be safe one should set cluster in Single + User Mode, before relying on table locks when updating tables + from several MySQL servers +*/ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, THR_LOCK_DATA **to, @@ -3055,7 +3054,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, /* Since NDB does not currently have table locks this is treated as a ordinary lock */ - if ((lock_type >= TL_WRITE_ALLOW_WRITE && + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && lock_type <= TL_WRITE) && !thd->in_lock_tables) lock_type= TL_WRITE_ALLOW_WRITE; @@ -4611,7 +4610,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, List_iterator_fast<char> it2(create_list); while ((file_name=it2++)) { - DBUG_PRINT("info", ("Table %s need discovery", name)); + DBUG_PRINT("info", ("Table %s need discovery", file_name)); if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0) files->push_back(thd->strdup(file_name)); } @@ -6302,6 +6301,7 @@ void ndb_serialize_cond(const Item *item, void *arg) case(REAL_RESULT): context->expect_only(Item::REAL_ITEM); context->expect(Item::DECIMAL_ITEM); + context->expect(Item::INT_ITEM); break; case(INT_RESULT): context->expect_only(Item::INT_ITEM); @@ -6310,6 +6310,7 @@ void ndb_serialize_cond(const Item *item, void *arg) case(DECIMAL_RESULT): context->expect_only(Item::DECIMAL_ITEM); context->expect(Item::REAL_ITEM); + context->expect(Item::INT_ITEM); break; default: break; @@ -6712,6 +6713,8 @@ void ndb_serialize_cond(const Item *item, void *arg) // We have not seen the field argument yet context->expect_only(Item::FIELD_ITEM); context->expect_only_field_result(INT_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(DECIMAL_RESULT); } else { diff --git a/sql/handler.cc b/sql/handler.cc index 555b6ccc1cb..06a1c09fcc8 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -165,12 +165,22 @@ my_bool ha_storage_engine_is_enabled(enum db_type database_type) /* Use other database handler if databasehandler is not incompiled */ -enum db_type ha_checktype(enum db_type database_type) +enum db_type ha_checktype(THD *thd, enum db_type database_type, + bool no_substitute, bool report_error) { - THD *thd; if (ha_storage_engine_is_enabled(database_type)) return database_type; + if (no_substitute) + { + if (report_error) + { + const char *engine_name= ha_get_storage_engine(database_type); + my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name); + } + return DB_TYPE_UNKNOWN; + } + switch (database_type) { #ifndef NO_HASH case DB_TYPE_HASH: @@ -182,7 +192,6 @@ enum db_type ha_checktype(enum db_type database_type) break; } - thd= current_thd; return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ? (enum db_type) thd->variables.table_type : ((enum db_type) global_system_variables.table_type != diff --git a/sql/handler.h b/sql/handler.h index 0013013cdf8..f4efdd0ed8a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1029,7 +1029,8 @@ extern ulong total_ha, total_ha_2pc; enum db_type ha_resolve_by_name(const char *name, uint namelen); const char *ha_get_storage_engine(enum db_type db_type); handler *get_new_handler(TABLE *table, enum db_type db_type); -enum db_type ha_checktype(enum db_type database_type); +enum db_type ha_checktype(THD *thd, enum db_type database_type, + bool no_substitute, bool report_error); /* basic stuff */ int ha_init(void); diff --git a/sql/item.cc b/sql/item.cc index 0e68ba48118..ec685982304 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -307,13 +307,14 @@ void *Item::operator new(size_t size, Item *reuse, uint *rsize) return (void *)reuse; } if (rsize) - (*rsize)= size; + (*rsize)= (uint) size; return (void *)sql_alloc((uint)size); } Item::Item(): rsize(0), name(0), orig_name(0), name_length(0), fixed(0), + is_autogenerated_name(TRUE), collation(&my_charset_bin, DERIVATION_COERCIBLE) { marker= 0; @@ -337,6 +338,7 @@ Item::Item(): place == IN_HAVING) thd->lex->current_select->select_n_having_items++; } + item_flags= 0; } /* @@ -357,7 +359,8 @@ Item::Item(THD *thd, Item *item): unsigned_flag(item->unsigned_flag), with_sum_func(item->with_sum_func), fixed(item->fixed), - collation(item->collation) + collation(item->collation), + item_flags(item->item_flags) { next= thd->free_list; // Put in free list thd->free_list= this; @@ -382,7 +385,7 @@ void Item::print_item_w_name(String *str) { THD *thd= current_thd; str->append(" AS ", 4); - append_identifier(thd, str, name, strlen(name)); + append_identifier(thd, str, name, (uint) strlen(name)); } } @@ -1132,27 +1135,27 @@ void Item_ident::print(String *str) if (!table_name || !field_name) { const char *nm= field_name ? field_name : name ? name : "tmp_field"; - append_identifier(thd, str, nm, strlen(nm)); + append_identifier(thd, str, nm, (uint) strlen(nm)); return; } if (db_name && db_name[0] && !alias_name_used) { - append_identifier(thd, str, d_name, strlen(d_name)); + append_identifier(thd, str, d_name, (uint) strlen(d_name)); str->append('.'); - append_identifier(thd, str, t_name, strlen(t_name)); + append_identifier(thd, str, t_name, (uint) strlen(t_name)); str->append('.'); - append_identifier(thd, str, field_name, strlen(field_name)); + append_identifier(thd, str, field_name, (uint) strlen(field_name)); } else { if (table_name[0]) { - append_identifier(thd, str, t_name, strlen(t_name)); + append_identifier(thd, str, t_name, (uint) strlen(t_name)); str->append('.'); - append_identifier(thd, str, field_name, strlen(field_name)); + append_identifier(thd, str, field_name, (uint) strlen(field_name)); } else - append_identifier(thd, str, field_name, strlen(field_name)); + append_identifier(thd, str, field_name, (uint) strlen(field_name)); } } @@ -2179,7 +2182,7 @@ const String *Item_param::query_val_str(String* str) const ptr+= escape_string_for_mysql(str_value.charset(), ptr, 0, str_value.ptr(), str_value.length()); *ptr++= '\''; - str->length(ptr - buf); + str->length((uint32) (ptr - buf)); break; } case NULL_VALUE: @@ -4365,6 +4368,28 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) return val; } +int Item_ref::save_in_field(Field *to, bool no_conversions) +{ + int res; + if(result_field){ + if (result_field->is_null()) + { + null_value= 1; + return set_field_to_null_with_conversions(to, no_conversions); + } + else + { + to->set_notnull(); + field_conv(to, result_field); + null_value= 0; + } + return 0; + } + res= (*ref)->save_in_field(to, no_conversions); + null_value= (*ref)->null_value; + return res; +} + void Item_ref_null_helper::print(String *str) { @@ -4448,6 +4473,7 @@ bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items) { + Item *real_arg; Item_field *field_arg; Field *def_field; DBUG_ASSERT(fixed == 0); @@ -4459,17 +4485,15 @@ bool Item_default_value::fix_fields(THD *thd, } if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) return TRUE; - - if (arg->type() == REF_ITEM) + + real_arg= arg->real_item(); + if (real_arg->type() != FIELD_ITEM) { - Item_ref *ref= (Item_ref *)arg; - if (ref->ref[0]->type() != FIELD_ITEM) - { - return TRUE; - } - arg= ref->ref[0]; + my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); + return TRUE; } - field_arg= (Item_field *)arg; + + field_arg= (Item_field *)real_arg; if (field_arg->field->flags & NO_DEFAULT_VALUE_FLAG) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name); @@ -4602,7 +4626,8 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table) Try to find field by its name and if it will be found set field_idx properly. */ - (void)find_field_in_real_table(thd, table, field_name, strlen(field_name), + (void)find_field_in_real_table(thd, table, field_name, + (uint) strlen(field_name), 0, 0, &field_idx); thd->set_query_id= save_set_query_id; triggers= table->triggers; @@ -5392,7 +5417,7 @@ void Item_result_field::cleanup() ** Instantiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List<Item>; template class List_iterator<Item>; template class List_iterator_fast<Item>; diff --git a/sql/item.h b/sql/item.h index 1d8f44d4e29..c8180b4932a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -225,6 +225,11 @@ typedef Item* (Item::*Item_transformer) (byte *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); +/* + See comments for sql_yacc.yy: insert_update_elem rule + */ +#define MY_ITEM_PREFER_1ST_TABLE 1 + class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); @@ -269,7 +274,10 @@ public: my_bool unsigned_flag; my_bool with_sum_func; my_bool fixed; /* If item fixed with fix_fields */ + my_bool is_autogenerated_name; /* indicate was name of this Item + autogenerated or set by user */ DTCollation collation; + uint8 item_flags; /* Flags on how item should be processed */ // alloc & destruct is done as start of select using sql_alloc Item(); @@ -288,7 +296,7 @@ public: name=0; #endif } /*lint -e1509 */ - void set_name(const char *str,uint length, CHARSET_INFO *cs); + void set_name(const char *str, uint length, CHARSET_INFO *cs); void rename(char *new_name); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup(); @@ -337,6 +345,11 @@ public: */ virtual longlong val_int()=0; /* + This is just a shortcut to avoid the cast. You should still use + unsigned_flag to check the sign of the item. + */ + inline ulonglong val_uint() { return (ulonglong) val_int(); } + /* Return string representation of this item object. SYNOPSIS @@ -463,6 +476,18 @@ public: */ virtual bool const_during_execution() const { return (used_tables() & ~PARAM_TABLE_BIT) == 0; } + /* + This is an essential method for correct functioning of VIEWS. + To save a view in an .frm file we need its unequivocal + definition in SQL that takes into account sql_mode and + environmental settings. Currently such definition is restored + by traversing through the parsed tree of a view and + print()'ing SQL syntax of every node to a String buffer. This + method is used to print the SQL definition of an item. The + second use of this method is for EXPLAIN EXTENDED, to print + the SQL of a query after all optimizations of the parsed tree + have been done. + */ virtual void print(String *str_arg) { str_arg->append(full_name()); } void print_item_w_name(String *); virtual void update_used_tables() {} @@ -565,6 +590,11 @@ public: cleanup(); delete this; } + virtual bool set_flags_processor(byte *args) + { + this->item_flags|= *((uint8*)args); + return false; + } virtual bool is_splocal() { return 0; } /* Needed for error checking */ }; @@ -625,7 +655,7 @@ public: Item *it= this_item(); if (name) - it->set_name(name, strlen(name), system_charset_info); + it->set_name(name, (uint) strlen(name), system_charset_info); else it->set_name(m_name.str, m_name.length, system_charset_info); it->make_field(field); @@ -699,10 +729,6 @@ public: void cleanup(); bool remove_dependence_processor(byte * arg); void print(String *str); - - friend bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, - const char *table_name, List_iterator<Item> *it, - bool any_privileges, bool allocate_view_names); }; class Item_equal; @@ -980,10 +1006,10 @@ public: longlong value; Item_int(int32 i,uint length=11) :value((longlong) i) { max_length=length; fixed= 1; } -#ifdef HAVE_LONG_LONG Item_int(longlong i,uint length=21) :value(i) { max_length=length; fixed= 1; } -#endif + Item_int(ulonglong i, uint length= 21) :value((longlong)i) + { max_length=length; fixed= 1; unsigned_flag= 1; } Item_int(const char *str_arg,longlong i,uint length) :value(i) { max_length=length; name=(char*) str_arg; fixed= 1; } Item_int(const char *str_arg, uint length=64); @@ -1021,9 +1047,8 @@ class Item_uint :public Item_int { public: Item_uint(const char *str_arg, uint length); + Item_uint(uint32 i) :Item_int((ulonglong) i, 10) {} Item_uint(const char *str_arg, longlong i, uint length); - Item_uint(uint32 i) :Item_int((longlong) i, 10) - { unsigned_flag= 1; } double val_real() { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } String *val_str(String*); @@ -1154,7 +1179,7 @@ public: collation.set(cs, dv); str_value.set_or_copy_aligned(str,length,cs); max_length= str_value.numchars()*cs->mbmaxlen; - set_name(name_par,0,cs); + set_name(name_par, 0, cs); decimals=NOT_FIXED_DEC; // it is constant => can be used without fix_fields (and frequently used) fixed= 1; @@ -1331,8 +1356,7 @@ public: bool send(Protocol *prot, String *tmp); void make_field(Send_field *field) { (*ref)->make_field(field); } bool fix_fields(THD *, struct st_table_list *, Item **); - int save_in_field(Field *field, bool no_conversions) - { return (*ref)->save_in_field(field, no_conversions); } + int save_in_field(Field *field, bool no_conversions); void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } @@ -1348,7 +1372,10 @@ public: { (*ref)->save_in_field(result_field, no_conversions); } - Item *real_item() { return *ref; } + Item *real_item() + { + return (*ref)->real_item(); + } bool walk(Item_processor processor, byte *arg) { return (*ref)->walk(processor, arg); } void print(String *str); @@ -1474,7 +1501,7 @@ public: str_value.length(), &end_not_used, &err_not_used)); } longlong val_int() - { + { int err; return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err); } @@ -1489,62 +1516,62 @@ public: }; -class Item_buff :public Sql_alloc +class Cached_item :public Sql_alloc { public: my_bool null_value; - Item_buff() :null_value(0) {} + Cached_item() :null_value(0) {} virtual bool cmp(void)=0; - virtual ~Item_buff(); /*line -e1509 */ + virtual ~Cached_item(); /*line -e1509 */ }; -class Item_str_buff :public Item_buff +class Cached_item_str :public Cached_item { Item *item; String value,tmp_value; public: - Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {} + Cached_item_str(THD *thd, Item *arg); bool cmp(void); - ~Item_str_buff(); // Deallocate String:s + ~Cached_item_str(); // Deallocate String:s }; -class Item_real_buff :public Item_buff +class Cached_item_real :public Cached_item { Item *item; double value; public: - Item_real_buff(Item *item_par) :item(item_par),value(0.0) {} + Cached_item_real(Item *item_par) :item(item_par),value(0.0) {} bool cmp(void); }; -class Item_int_buff :public Item_buff +class Cached_item_int :public Cached_item { Item *item; longlong value; public: - Item_int_buff(Item *item_par) :item(item_par),value(0) {} + Cached_item_int(Item *item_par) :item(item_par),value(0) {} bool cmp(void); }; -class Item_decimal_buff :public Item_buff +class Cached_item_decimal :public Cached_item { Item *item; my_decimal value; public: - Item_decimal_buff(Item *item_par); + Cached_item_decimal(Item *item_par); bool cmp(void); }; -class Item_field_buff :public Item_buff +class Cached_item_field :public Cached_item { char *buff; Field *field; uint length; public: - Item_field_buff(Item_field *item) + Cached_item_field(Item_field *item) { field=item->field; buff= (char*) sql_calloc(length=field->pack_length()); @@ -1566,7 +1593,7 @@ public: void print(String *str); int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } - + bool walk(Item_processor processor, byte *args) { return arg->walk(processor, args) || @@ -1872,7 +1899,7 @@ void mark_select_range_as_dependent(THD *thd, Field *found_field, Item *found_item, Item_ident *resolved_item); -extern Item_buff *new_Item_buff(Item *item); +extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); extern bool field_is_equal_to_item(Field *field,Item *item); diff --git a/sql/item_buff.cc b/sql/item_buff.cc index af17d377e31..a67e420170a 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -20,23 +20,23 @@ #include "mysql_priv.h" /* -** Create right type of item_buffer for an item +** Create right type of Cached_item for an item */ -Item_buff *new_Item_buff(Item *item) +Cached_item *new_Cached_item(THD *thd, Item *item) { if (item->type() == Item::FIELD_ITEM && !(((Item_field *) item)->field->flags & BLOB_FLAG)) - return new Item_field_buff((Item_field *) item); + return new Cached_item_field((Item_field *) item); switch (item->result_type()) { case STRING_RESULT: - return new Item_str_buff((Item_field *) item); + return new Cached_item_str(thd, (Item_field *) item); case INT_RESULT: - return new Item_int_buff((Item_field *) item); + return new Cached_item_int((Item_field *) item); case REAL_RESULT: - return new Item_real_buff(item); + return new Cached_item_real(item); case DECIMAL_RESULT: - return new Item_decimal_buff(item); + return new Cached_item_decimal(item); case ROW_RESULT: default: DBUG_ASSERT(0); @@ -44,19 +44,24 @@ Item_buff *new_Item_buff(Item *item) } } -Item_buff::~Item_buff() {} +Cached_item::~Cached_item() {} /* ** Compare with old value and replace value with new value ** Return true if values have changed */ -bool Item_str_buff::cmp(void) +Cached_item_str::Cached_item_str(THD *thd, Item *arg) + :item(arg), value(min(arg->max_length, thd->variables.max_sort_length)) +{} + +bool Cached_item_str::cmp(void) { String *res; bool tmp; - res=item->val_str(&tmp_value); + if ((res=item->val_str(&tmp_value))) + res->length(min(res->length(), value.alloced_length())); if (null_value != item->null_value) { if ((null_value= item->null_value)) @@ -72,12 +77,12 @@ bool Item_str_buff::cmp(void) return tmp; } -Item_str_buff::~Item_str_buff() +Cached_item_str::~Cached_item_str() { item=0; // Safety } -bool Item_real_buff::cmp(void) +bool Cached_item_real::cmp(void) { double nr= item->val_real(); if (null_value != item->null_value || nr != value) @@ -89,7 +94,7 @@ bool Item_real_buff::cmp(void) return FALSE; } -bool Item_int_buff::cmp(void) +bool Cached_item_int::cmp(void) { longlong nr=item->val_int(); if (null_value != item->null_value || nr != value) @@ -102,7 +107,7 @@ bool Item_int_buff::cmp(void) } -bool Item_field_buff::cmp(void) +bool Cached_item_field::cmp(void) { bool tmp= field->cmp(buff) != 0; // This is not a blob! if (tmp) @@ -116,14 +121,14 @@ bool Item_field_buff::cmp(void) } -Item_decimal_buff::Item_decimal_buff(Item *it) +Cached_item_decimal::Cached_item_decimal(Item *it) :item(it) { my_decimal_set_zero(&value); } -bool Item_decimal_buff::cmp() +bool Cached_item_decimal::cmp() { my_decimal tmp; my_decimal *ptmp= item->val_decimal(&tmp); @@ -141,7 +146,7 @@ bool Item_decimal_buff::cmp() ** Instansiate templates *****************************************************************************/ -#ifdef __GNUC__ -template class List<Item_buff>; -template class List_iterator<Item_buff>; +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +template class List<Cached_item>; +template class List_iterator<Cached_item>; #endif diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 28ab38c5aed..5a2e14eef2e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -649,7 +649,7 @@ bool Item_in_optimizer::fix_left(THD *thd, If it is preparation PS only then we do not know values of parameters => cant't get there values and do not need that values. */ - if (!thd->only_prepare()) + if (!thd->current_arena->is_stmt_prepare()) cache->store(args[0]); if (cache->cols() == 1) { @@ -1109,12 +1109,14 @@ void Item_func_between::print(String *str) void Item_func_ifnull::fix_length_and_dec() { + agg_result_type(&hybrid_type, args, 2); maybe_null=args[1]->maybe_null; decimals= max(args[0]->decimals, args[1]->decimals); - max_length= (max(args[0]->max_length - args[0]->decimals, - args[1]->max_length - args[1]->decimals) + - decimals); - agg_result_type(&hybrid_type, args, 2); + max_length= (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) ? + (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + decimals) : + max(args[0]->max_length, args[1]->max_length); + switch (hybrid_type) { case STRING_RESULT: agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); @@ -1225,16 +1227,7 @@ Item_func_if::fix_length_and_dec() { maybe_null=args[1]->maybe_null || args[2]->maybe_null; decimals= max(args[1]->decimals, args[2]->decimals); - if (decimals == NOT_FIXED_DEC) - { - max_length= max(args[1]->max_length, args[2]->max_length); - } - else - { - max_length= (max(args[1]->max_length - args[1]->decimals, - args[2]->max_length - args[2]->decimals) + - decimals); - } + enum Item_result arg1_type=args[1]->result_type(); enum Item_result arg2_type=args[2]->result_type(); bool null1=args[1]->const_item() && args[1]->null_value; @@ -1263,6 +1256,11 @@ Item_func_if::fix_length_and_dec() collation.set(&my_charset_bin); // Number } } + max_length= + (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ? + (max(args[1]->max_length - args[1]->decimals, + args[2]->max_length - args[2]->decimals) + decimals) : + max(args[1]->max_length, args[2]->max_length); } @@ -1408,9 +1406,7 @@ Item_func_nullif::val_decimal(my_decimal * decimal_value) bool Item_func_nullif::is_null() { - if (!cmp.compare()) - return (null_value=1); - return 0; + return (null_value= (!cmp.compare() ? 1 : args[0]->null_value)); } /* @@ -2796,10 +2792,11 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) if (canDoTurboBM) { pattern = first + 1; - pattern_len = len - 2; + pattern_len = (int) len - 2; DBUG_PRINT("info", ("Initializing pattern: '%s'", first)); - int *suff = (int*) thd->alloc(sizeof(int)*((pattern_len + 1)*2+ - alphabet_size)); + int *suff = (int*) thd->alloc((int) (sizeof(int)* + ((pattern_len + 1)*2+ + alphabet_size))); bmGs = suff + pattern_len + 1; bmBc = bmGs + pattern_len + 1; turboBM_compute_good_suffix_shifts(suff); diff --git a/sql/item_func.cc b/sql/item_func.cc index 68292859504..57f68bbc2a0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -161,7 +161,7 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, } THD *thd= current_thd; - Item_arena *arena, backup; + Query_arena *arena, backup; bool res= FALSE; /* In case we're in statement prepare, create conversion item @@ -879,11 +879,11 @@ longlong Item_func_numhybrid::val_int() return (longlong)real_op(); case STRING_RESULT: { - char *end_not_used; int err_not_used; String *res= str_op(&str_value); + char *end= (char*) res->ptr() + res->length(); CHARSET_INFO *cs= str_value.charset(); - return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end_not_used, + return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end, &err_not_used) : 0); } default: @@ -1022,7 +1022,8 @@ longlong Item_func_unsigned::val_int() String *Item_decimal_typecast::val_str(String *str) { my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); - my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf); + if (null_value) + return NULL; my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str); return str; } @@ -1032,6 +1033,8 @@ double Item_decimal_typecast::val_real() { my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); double res; + if (null_value) + return 0.0; my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res); return res; } @@ -1041,6 +1044,8 @@ longlong Item_decimal_typecast::val_int() { my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); longlong res; + if (null_value) + return 0; my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res); return res; } @@ -1049,11 +1054,21 @@ longlong Item_decimal_typecast::val_int() my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) { my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf); + if ((null_value= args[0]->null_value)) + return NULL; my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec); return dec; } +void Item_decimal_typecast::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as decimal)", 12); +} + + double Item_func_plus::real_op() { double value= args[0]->val_real() + args[1]->val_real(); @@ -1876,7 +1891,8 @@ void Item_func_round::fix_length_and_dec() max_length= float_length(decimals); break; case INT_RESULT: - if (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)) + if ((decimals_to_set==0) && + (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))) { /* Here we can keep INT_RESULT */ hybrid_type= INT_RESULT; @@ -1890,18 +1906,12 @@ void Item_func_round::fix_length_and_dec() hybrid_type= DECIMAL_RESULT; int decimals_delta= args[0]->decimals - decimals_to_set; int precision= args[0]->decimal_precision(); - if (decimals_delta > 0) - { - int length_increase= truncate ? 0:1; - precision-= decimals_delta - length_increase; - decimals= decimals_to_set; - } - else - /* Decimals to set is bigger that the original scale */ - /* we keep original decimals value */ - decimals= args[0]->decimals; + int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1; + + precision-= decimals_delta - length_increase; + decimals= decimals_to_set; max_length= my_decimal_precision_to_length(precision, decimals, - unsigned_flag); + unsigned_flag); break; } default: @@ -4109,7 +4119,7 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const return 1; // Same item is same. /* Check if other type is also a get_user_var() object */ if (item->type() != FUNC_ITEM || - ((Item_func*) item)->func_name() != func_name()) + ((Item_func*) item)->functype() != functype()) return 0; Item_func_get_user_var *other=(Item_func_get_user_var*) item; return (name.length == other->name.length && @@ -4610,7 +4620,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name, if (!(item=var->item(thd, var_type, &null_lex_string))) return 0; // Impossible thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - item->set_name(item_name, 0, system_charset_info); // Will use original name + item->set_name(item_name, 0, system_charset_info); // Will use original name return item; } @@ -4697,6 +4707,16 @@ Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) dummy_table= (TABLE*) sql_calloc(sizeof(TABLE)); } +void +Item_func_sp::cleanup() +{ + if (result_field) + { + delete result_field; + result_field= NULL; + } + Item_func::cleanup(); +} const char * Item_func_sp::func_name() const @@ -4723,6 +4743,7 @@ Item_func_sp::func_name() const Field * Item_func_sp::sp_result_field(void) const { + Field *field; DBUG_ENTER("Item_func_sp::sp_result_field"); if (!m_sp) @@ -4744,7 +4765,8 @@ Item_func_sp::sp_result_field(void) const share->table_cache_key = empty_name; share->table_name = empty_name; } - DBUG_RETURN(m_sp->make_field(max_length, name, dummy_table)); + field= m_sp->make_field(max_length, name, dummy_table); + DBUG_RETURN(field); } diff --git a/sql/item_func.h b/sql/item_func.h index f0c7e25ad53..e0f14ceac75 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -54,7 +54,8 @@ public: SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, - GUSERVAR_FUNC}; + GUSERVAR_FUNC, COLLATE_FUNC, + EXTRACT_FUNC, CHAR_TYPECAST_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -123,7 +124,17 @@ public: virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; } virtual bool have_rev_func() const { return 0; } virtual Item *key_item() const { return args[0]; } - virtual const char *func_name() const { return "?"; } + /* + This method is used for debug purposes to print the name of an + item to the debug log. The second use of this method is as + a helper function of print(), where it is applicable. + To suit both goals it should return a meaningful, + distinguishable and sintactically correct string. This method + should not be used for runtime type identification, use enum + {Sum}Functype and Item_func::functype()/Item_sum::sum_func() + instead. + */ + virtual const char *func_name() const= 0; virtual bool const_item() const { return const_item_cache; } inline Item **arguments() const { return args; } void set_arguments(List<Item> &list); @@ -306,6 +317,8 @@ public: enum Item_result result_type () const { return DECIMAL_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } void fix_length_and_dec() {}; + const char *func_name() const { return "decimal_typecast"; } + void print(String *); }; @@ -506,7 +519,7 @@ public: class Item_func_acos :public Item_dec_func { - public: +public: Item_func_acos(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "acos"; } @@ -514,7 +527,7 @@ class Item_func_acos :public Item_dec_func class Item_func_asin :public Item_dec_func { - public: +public: Item_func_asin(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "asin"; } @@ -522,7 +535,7 @@ class Item_func_asin :public Item_dec_func class Item_func_atan :public Item_dec_func { - public: +public: Item_func_atan(Item *a) :Item_dec_func(a) {} Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {} double val_real(); @@ -531,7 +544,7 @@ class Item_func_atan :public Item_dec_func class Item_func_cos :public Item_dec_func { - public: +public: Item_func_cos(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "cos"; } @@ -539,7 +552,7 @@ class Item_func_cos :public Item_dec_func class Item_func_sin :public Item_dec_func { - public: +public: Item_func_sin(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "sin"; } @@ -547,7 +560,7 @@ class Item_func_sin :public Item_dec_func class Item_func_tan :public Item_dec_func { - public: +public: Item_func_tan(Item *a) :Item_dec_func(a) {} double val_real(); const char *func_name() const { return "tan"; } @@ -634,7 +647,7 @@ class Item_func_units :public Item_real_func { char *name; double mul,add; - public: +public: Item_func_units(char *name_arg,Item *a,double mul_arg,double add_arg) :Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {} double val_real(); @@ -853,7 +866,7 @@ public: class Item_func_benchmark :public Item_int_func { ulong loop_count; - public: +public: Item_func_benchmark(ulong loop_count_arg,Item *expr) :Item_int_func(expr), loop_count(loop_count_arg) {} @@ -868,7 +881,7 @@ class Item_func_benchmark :public Item_int_func class Item_udf_func :public Item_func { - protected: +protected: udf_handler udf; public: @@ -1046,7 +1059,7 @@ class Item_func_get_lock :public Item_int_func class Item_func_release_lock :public Item_int_func { String value; - public: +public: Item_func_release_lock(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "release_lock"; } @@ -1058,7 +1071,7 @@ class Item_func_release_lock :public Item_int_func class Item_master_pos_wait :public Item_int_func { String value; - public: +public: Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {} Item_master_pos_wait(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} longlong val_int(); @@ -1308,13 +1321,7 @@ public: virtual ~Item_func_sp() {} - void cleanup() - { - if (result_field) - delete result_field; - Item_func::cleanup(); - result_field= NULL; - } + void cleanup(); const char *func_name() const; @@ -1330,7 +1337,7 @@ public: { if (execute(&result_field)) return (longlong) 0; - return result_field->val_int(); + return result_field->val_int(); } double val_real() diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d3327a0e41f..9f7a44f6f47 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1668,22 +1668,36 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org) String *Item_func_format::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - double nr= args[0]->val_real(); - uint32 length,str_length,dec; + uint32 length, str_length ,dec; int diff; - if ((null_value=args[0]->null_value)) - return 0; /* purecov: inspected */ - nr= my_double_round(nr, decimals, FALSE); + DBUG_ASSERT(fixed == 1); dec= decimals ? decimals+1 : 0; - /* Here default_charset() is right as this is not an automatic conversion */ - str->set(nr,decimals, default_charset()); - if (isnan(nr)) - return str; - str_length=str->length(); - if (nr < 0) - str_length--; // Don't count sign + if (args[0]->result_type() == DECIMAL_RESULT || + args[0]->result_type() == INT_RESULT) + { + my_decimal dec_val, rnd_dec, *res; + res= args[0]->val_decimal(&dec_val); + my_decimal_round(E_DEC_FATAL_ERROR, res, decimals, false, &rnd_dec); + my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str); + str_length= str->length(); + if (rnd_dec.sign()) + str_length--; + } + else + { + double nr= args[0]->val_real(); + if ((null_value=args[0]->null_value)) + return 0; /* purecov: inspected */ + nr= my_double_round(nr, decimals, FALSE); + /* Here default_charset() is right as this is not an automatic conversion */ + str->set(nr,decimals, default_charset()); + if (isnan(nr)) + return str; + str_length=str->length(); + if (nr < 0) + str_length--; // Don't count sign + } /* We need this test to handle 'nan' values */ if (str_length >= dec+4) { @@ -2283,7 +2297,7 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const return 0; Item_func *item_func=(Item_func*) item; if (arg_count != item_func->arg_count || - func_name() != item_func->func_name()) + functype() != item_func->functype()) return 0; Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item; if (collation.collation != item_func_sc->collation.collation) diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6df90cebdff..8d2eb269915 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -573,6 +573,7 @@ public: max_length=args[0]->max_length; } void print(String *str); + const char *func_name() const { return "cast_as_binary"; } }; @@ -648,6 +649,7 @@ public: void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } + enum Functype func_type() const { return COLLATE_FUNC; } void print(String *str); Item_field *filed_for_view_update() { diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1569b6f2f12..393cb87c113 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -340,7 +340,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) return RES_OK; SELECT_LEX *select_lex= join->select_lex; - Item_arena *arena= thd->current_arena; + Query_arena *arena= thd->current_arena; if (!select_lex->master_unit()->first_select()->next_select() && !select_lex->table_list.elements && @@ -600,8 +600,8 @@ void Item_exists_subselect::fix_length_and_dec() decimals= 0; max_length= 1; max_columns= engine->cols(); - /* We need only 1 row to determinate existence */ - unit->global_parameters->select_limit= 1; + /* We need only 1 row to determine existence */ + unit->global_parameters->select_limit= new Item_int((int32) 1); } double Item_exists_subselect::val_real() @@ -1164,7 +1164,7 @@ Item_in_subselect::select_transformer(JOIN *join) Item_subselect::trans_res Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) { - Item_arena *arena, backup; + Query_arena *arena, backup; SELECT_LEX *current= thd->lex->current_select, *up; const char *save_where= thd->where; Item_subselect::trans_res res= RES_ERROR; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index f7a158ceb5a..76f94801b49 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -86,7 +86,6 @@ void Item_sum::make_field(Send_field *tmp_field) void Item_sum::print(String *str) { str->append(func_name()); - str->append('('); for (uint i=0 ; i < arg_count ; i++) { if (i) @@ -2425,13 +2424,6 @@ longlong Item_sum_count_distinct::val_int() } -void Item_sum_count_distinct::print(String *str) -{ - str->append("count(distinct ", 15); - args[0]->print(str); - str->append(')'); -} - /**************************************************************************** ** Functions to handle dynamic loadable aggregates ** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su> @@ -2466,6 +2458,20 @@ void Item_udf_sum::cleanup() } +void Item_udf_sum::print(String *str) +{ + str->append(func_name()); + str->append('('); + for (uint i=0 ; i < arg_count ; i++) + { + if (i) + str->append(','); + args[i]->print(str); + } + str->append(')'); +} + + Item *Item_sum_udf_float::copy_or_same(THD* thd) { return new (thd->mem_root) Item_sum_udf_float(thd, this); diff --git a/sql/item_sum.h b/sql/item_sum.h index bb5d31b4b4f..b9a90ee5de5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -81,7 +81,22 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - virtual const char *func_name() const { return "?"; } + /* + This method is used for debug purposes to print the name of an + item to the debug log. The second use of this method is as + a helper function of print(), where it is applicable. + To suit both goals it should return a meaningful, + distinguishable and sintactically correct string. This method + should not be used for runtime type identification, use enum + {Sum}Functype and Item_func::functype()/Item_sum::sum_func() + instead. + + NOTE: for Items inherited from Item_sum, func_name() return part of + function name till first argument (including '(') to make difference in + names for functions with 'distinct' clause and without 'distinct' and + also to make printing of items inherited from Item_sum uniform. + */ + virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) { return new Item_field(field);} table_map used_tables() const { return ~(table_map) 0; } /* Not used */ @@ -159,7 +174,7 @@ public: void reset_field(); void update_field(); void no_rows_in_result() {} - const char *func_name() const { return "sum"; } + const char *func_name() const { return "sum("; } Item *copy_or_same(THD* thd); }; @@ -200,7 +215,6 @@ public: enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } void reset_field() {} // not used void update_field() {} // not used - const char *func_name() const { return "sum_distinct"; } virtual void no_rows_in_result() {} void fix_length_and_dec(); enum Item_result result_type () const { return val.traits->type(); } @@ -224,7 +238,7 @@ public: Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {} enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } - const char *func_name() const { return "sum_distinct"; } + const char *func_name() const { return "sum(distinct "; } Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); } }; @@ -243,7 +257,7 @@ public: void fix_length_and_dec(); virtual void calculate_val_and_count(); enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; } - const char *func_name() const { return "avg_distinct"; } + const char *func_name() const { return "avg(distinct "; } Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); } }; @@ -272,7 +286,7 @@ class Item_sum_count :public Item_sum_int void reset_field(); void cleanup(); void update_field(); - const char *func_name() const { return "count"; } + const char *func_name() const { return "count("; } Item *copy_or_same(THD* thd); }; @@ -326,12 +340,11 @@ public: longlong val_int(); void reset_field() { return ;} // Never called void update_field() { return ; } // Never called - const char *func_name() const { return "count_distinct"; } + const char *func_name() const { return "count(distinct "; } bool setup(THD *thd); void make_unique(); Item *copy_or_same(THD* thd); void no_rows_in_result() {} - void print(String *str); }; @@ -389,7 +402,7 @@ public: Item *result_item(Field *field) { return new Item_avg_field(hybrid_type, this); } void no_rows_in_result() {} - const char *func_name() const { return "avg"; } + const char *func_name() const { return "avg("; } Item *copy_or_same(THD* thd); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; @@ -466,7 +479,7 @@ public: Item *result_item(Field *field) { return new Item_variance_field(this); } void no_rows_in_result() {} - const char *func_name() const { return "variance"; } + const char *func_name() const { return "variance("; } Item *copy_or_same(THD* thd); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); enum Item_result result_type () const { return hybrid_type; } @@ -501,7 +514,7 @@ class Item_sum_std :public Item_sum_variance double val_real(); Item *result_item(Field *field) { return new Item_std_field(this); } - const char *func_name() const { return "std"; } + const char *func_name() const { return "std("; } Item *copy_or_same(THD* thd); enum Item_result result_type () const { return REAL_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} @@ -565,7 +578,7 @@ public: enum Sumfunctype sum_func () const {return MIN_FUNC;} bool add(); - const char *func_name() const { return "min"; } + const char *func_name() const { return "min("; } Item *copy_or_same(THD* thd); }; @@ -578,7 +591,7 @@ public: enum Sumfunctype sum_func () const {return MAX_FUNC;} bool add(); - const char *func_name() const { return "max"; } + const char *func_name() const { return "max("; } Item *copy_or_same(THD* thd); }; @@ -609,7 +622,7 @@ public: Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_or(THD *thd, Item_sum_or *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_or"; } + const char *func_name() const { return "bit_or("; } Item *copy_or_same(THD* thd); }; @@ -620,7 +633,7 @@ class Item_sum_and :public Item_sum_bit Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {} Item_sum_and(THD *thd, Item_sum_and *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_and"; } + const char *func_name() const { return "bit_and("; } Item *copy_or_same(THD* thd); }; @@ -630,7 +643,7 @@ class Item_sum_xor :public Item_sum_bit Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} Item_sum_xor(THD *thd, Item_sum_xor *item) :Item_sum_bit(thd, item) {} bool add(); - const char *func_name() const { return "bit_xor"; } + const char *func_name() const { return "bit_xor("; } Item *copy_or_same(THD* thd); }; @@ -668,6 +681,7 @@ public: void reset_field() {}; void update_field() {}; void cleanup(); + void print(String *str); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 564c5e4b9cc..19386c15835 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2158,7 +2158,7 @@ bool Item_extract::eq(const Item *item, bool binary_cmp) const if (this == item) return 1; if (item->type() != FUNC_ITEM || - func_name() != ((Item_func*)item)->func_name()) + functype() != ((Item_func*)item)->functype()) return 0; Item_extract* ie= (Item_extract*)item; @@ -2176,7 +2176,7 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const if (this == item) return 1; if (item->type() != FUNC_ITEM || - func_name() != ((Item_func*)item)->func_name()) + functype() != ((Item_func*)item)->functype()) return 0; Item_char_typecast *cast= (Item_char_typecast*)item; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index c8fb2b39836..a6dd9f7da91 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -503,7 +503,8 @@ public: Item_func_date_format(Item *a,Item *b,bool is_time_format_arg) :Item_str_func(a,b),is_time_format(is_time_format_arg) {} String *val_str(String *str); - const char *func_name() const { return "date_format"; } + const char *func_name() const + { return is_time_format ? "time_format" : "date_format"; } void fix_length_and_dec(); uint format_length(const String *format); }; @@ -637,6 +638,7 @@ class Item_extract :public Item_int_func Item_extract(interval_type type_arg, Item *a) :Item_int_func(a), int_type(type_arg) {} longlong val_int(); + enum Functype functype() const { return EXTRACT_FUNC; } const char *func_name() const { return "extract"; } void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; @@ -689,6 +691,7 @@ class Item_char_typecast :public Item_typecast public: Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg) :Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {} + enum Functype functype() const { return CHAR_TYPECAST_FUNC; } bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "cast_as_char"; } const char* cast_type() const { return "char"; }; @@ -790,6 +793,7 @@ public: return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin)); } void print(String *str); + const char *func_name() const { return "add_time"; } }; class Item_func_timediff :public Item_str_func diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 14b2e8d53bb..e95aa35101e 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -30,6 +30,7 @@ public: double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } void print(String *str) { str->append("0.0", 3); } + const char *func_name() const { return "unique_users"; } }; @@ -58,4 +59,5 @@ public: } void print(String *str) { str->append("0.0", 3); } Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); + const char *func_name() const { return "sum_unique_users"; } }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 3b6b3cda0b4..08aedfb3f63 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -708,7 +708,7 @@ failed my_b_read")); Log_event *res= 0; #ifndef max_allowed_packet THD *thd=current_thd; - uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~0; + uint max_allowed_packet= thd ? thd->variables.max_allowed_packet : ~(ulong)0; #endif if (data_len > max_allowed_packet) diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 27fd33cffbe..b65e6aedaa2 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -290,6 +290,11 @@ int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) inline void my_decimal_neg(decimal_t *arg) { + if (decimal_is_zero(arg)) + { + arg->sign= 0; + return; + } decimal_neg(arg); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c5753a7f114..2b185dbc13b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -218,66 +218,75 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */ #define TEST_NO_STACKTRACE 512 #define TEST_SIGINT 1024 /* Allow sigint on threads */ -#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in some - places */ +#define TEST_SYNCHRONIZATION 2048 /* get server to do sleep in + some places */ #endif -/* +/* This is included in the server and in the client. Options for select set by the yacc parser (stored in lex->options). - None of the 32 defines below should have its value changed, or this will - break replication. + + XXX: + log_event.h defines OPTIONS_WRITTEN_TO_BIN_LOG to specify what THD + options list are written into binlog. These options can NOT change their + values, or it will break replication between version. + + context is encoded as following: + SELECT - SELECT_LEX_NODE::options + THD - THD::options + intern - neither. used only as + func(..., select_node->options | thd->options | OPTION_XXX, ...) + + TODO: separate three contexts above, move them to separate bitfields. */ -#define SELECT_DISTINCT (1L << 0) -#define SELECT_STRAIGHT_JOIN (1L << 1) -#define SELECT_DESCRIBE (1L << 2) -#define SELECT_SMALL_RESULT (1L << 3) -#define SELECT_BIG_RESULT (1L << 4) -#define OPTION_FOUND_ROWS (1L << 5) -#define OPTION_TO_QUERY_CACHE (1L << 6) -#define SELECT_NO_JOIN_CACHE (1L << 7) /* Intern */ -#define OPTION_BIG_TABLES (1L << 8) /* for SQL OPTION */ -#define OPTION_BIG_SELECTS (1L << 9) /* for SQL OPTION */ -#define OPTION_LOG_OFF (1L << 10) -#define OPTION_UPDATE_LOG (1L << 11) /* update log flag */ -#define TMP_TABLE_ALL_COLUMNS (1L << 12) -#define OPTION_WARNINGS (1L << 13) -#define OPTION_AUTO_IS_NULL (1L << 14) -#define OPTION_FOUND_COMMENT (1L << 15) -#define OPTION_SAFE_UPDATES (1L << 16) -#define OPTION_BUFFER_RESULT (1L << 17) -#define OPTION_BIN_LOG (1L << 18) -#define OPTION_NOT_AUTOCOMMIT (1L << 19) -#define OPTION_BEGIN (1L << 20) -#define OPTION_TABLE_LOCK (1L << 21) -#define OPTION_QUICK (1L << 22) -#define OPTION_QUOTE_SHOW_CREATE (1L << 23) -#define OPTION_INTERNAL_SUBTRANSACTIONS (1L << 24) +#define SELECT_DISTINCT (1L << 0) // SELECT, user +#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user +#define SELECT_DESCRIBE (1L << 2) // SELECT, user +#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user +#define SELECT_BIG_RESULT (1L << 4) // SELECT, user +#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user +#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user +#define SELECT_NO_JOIN_CACHE (1L << 7) // intern +#define OPTION_BIG_TABLES (1L << 8) // THD, user +#define OPTION_BIG_SELECTS (1L << 9) // THD, user +#define OPTION_LOG_OFF (1L << 10) // THD, user +#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused +#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern +#define OPTION_WARNINGS (1L << 13) // THD, user +#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog +#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser +#define OPTION_SAFE_UPDATES (1L << 16) // THD, user +#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user +#define OPTION_BIN_LOG (1L << 18) // THD, user +#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user +#define OPTION_BEGIN (1L << 20) // THD, intern +#define OPTION_TABLE_LOCK (1L << 21) // THD, intern +#define OPTION_QUICK (1L << 22) // SELECT (for DELETE) +#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user + +/* Thr following is used to detect a conflict with DISTINCT + in the user query has requested */ +#define SELECT_ALL (1L << 24) // SELECT, user, parser /* Set if we are updating a non-transaction safe table */ -#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) +#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern /* The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ -#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) +#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog /* The following speeds up inserts to InnoDB tables by suppressing unique key checks in some cases */ -#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) -#define SELECT_NO_UNLOCK (1L << 28) -#define OPTION_SCHEMA_TABLE (1L << 29) +#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog +#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern +#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern /* Flag set if setup_tables already done */ -#define OPTION_SETUP_TABLES_DONE (1L << 30) - -/* Options for select set by the yacc parser (stored in lex->options2). */ - - -/* The following is used to detect a conflict with DISTINCT - in the user query has requested */ -#define SELECT_ALL (1L << 0) +#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern +/* If not set then the thread will ignore all warnings with level notes. */ +#define OPTION_SQL_NOTES (1L << 31) // THD, user -/* - Maximum length of time zone name that we support +/* + Maximum length of time zone name that we support (Time zone name is char(64) in db). mysqlbinlog needs it. */ #define MAX_TIME_ZONE_NAME_LENGTH 72 @@ -285,13 +294,10 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; /* The rest of the file is included in the server only */ #ifndef MYSQL_CLIENT -/* If not set then the thread will ignore all warnings with level notes. */ -#define OPTION_SQL_NOTES (1L << 31) - /* Bits for different SQL modes modes (including ANSI mode) */ -#define MODE_REAL_AS_FLOAT 1 -#define MODE_PIPES_AS_CONCAT 2 -#define MODE_ANSI_QUOTES 4 +#define MODE_REAL_AS_FLOAT 1 +#define MODE_PIPES_AS_CONCAT 2 +#define MODE_ANSI_QUOTES 4 #define MODE_IGNORE_SPACE 8 #define MODE_NOT_USED 16 #define MODE_ONLY_FULL_GROUP_BY 32 @@ -319,6 +325,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2) #define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2) #define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2) +#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2) /* Replication uses 8 bytes to store SQL_MODE in the binary log. The day you use strictly more than 64 bits by adding one more define above, you should @@ -340,6 +347,8 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define UNCACHEABLE_SIDEEFFECT 4 // forcing to save JOIN for explain #define UNCACHEABLE_EXPLAIN 8 +/* Don't evaluate subqueries in prepare even if they're not correlated */ +#define UNCACHEABLE_PREPARE 16 #ifdef EXTRA_DEBUG /* @@ -484,7 +493,7 @@ bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list); 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, uint *table_count); +bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); bool mysql_multi_update_prepare(THD *thd); bool mysql_multi_delete_prepare(THD *thd); bool mysql_insert_select_prepare(THD *thd); @@ -551,8 +560,6 @@ struct Query_cache_query_flags #define query_cache_invalidate_by_MyISAM_filename_ref NULL #endif /*HAVE_QUERY_CACHE*/ -#define prepare_execute(A) ((A)->command == COM_EXECUTE) - bool 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); @@ -579,6 +586,7 @@ void mysql_init_query(THD *thd, uchar *buf, uint length); bool mysql_new_select(LEX *lex, bool move_down); void create_select_for_variable(const char *var_name); void mysql_init_multi_delete(LEX *lex); +bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); void free_max_user_conn(void); @@ -590,6 +598,7 @@ bool mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); +void log_slow_statement(THD *thd); bool check_dup(const char *db, const char *name, TABLE_LIST *tables); bool table_cache_init(void); @@ -832,10 +841,10 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, void mysql_stmt_execute(THD *thd, char *packet, uint packet_length); void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name); void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length); -void mysql_stmt_free(THD *thd, char *packet); +void mysql_stmt_close(THD *thd, char *packet); void mysql_stmt_reset(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); -void reset_stmt_for_execute(THD *thd, LEX *lex); +void reinit_stmt_before_use(THD *thd, LEX *lex); void init_stmt_after_parse(THD*, LEX*); /* sql_handler.cc */ @@ -885,8 +894,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, List<String> *index_list); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, - List_iterator<Item> *it, bool any_privileges, - bool allocate_view_names); + List_iterator<Item> *it, bool any_privileges); bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert); int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, @@ -1107,6 +1115,7 @@ extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern my_bool opt_readonly, lower_case_file_system; extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; +extern my_bool opt_log_slow_admin_statements; extern my_bool sp_automatic_privileges, opt_noacl; extern my_bool opt_old_style_user_limits, trust_routine_creators; extern uint opt_crash_binlog_innodb; @@ -1220,7 +1229,7 @@ int openfrm(THD *thd, const char *name,const char *alias,uint filestat, int readfrm(const char *name, const void** data, uint* length); int writefrm(const char* name, const void* data, uint len); int closefrm(TABLE *table); -db_type get_table_type(const char *name); +db_type get_table_type(THD *thd, const char *name); int read_string(File file, gptr *to, uint length); void free_blobs(TABLE *table); int set_zone(int nr,int min_zone,int max_zone); @@ -1277,7 +1286,7 @@ ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames, const char *newname); ulong next_io_size(ulong pos); void append_unescaped(String *res, const char *pos, uint length); -int create_frm(char *name,uint reclength,uchar *fileinfo, +int create_frm(THD *thd, char *name,uint reclength,uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys); void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form); int rename_file_ext(const char * from,const char * to,const char * ext); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 69aba3abd42..6a1d04fa69a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -230,6 +230,7 @@ static const char *sql_mode_names[] = "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "STRICT_TRANS_TABLES", "STRICT_ALL_TABLES", "NO_ZERO_IN_DATE", "NO_ZERO_DATE", "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO", "TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE", + "NO_ENGINE_SUBSTITUTION", NullS }; TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"", @@ -327,6 +328,7 @@ ulong opt_ndb_nodeid; my_bool opt_readonly, use_temp_pool, relay_log_purge; my_bool opt_sync_frm, opt_allow_suspicious_udfs; my_bool opt_secure_auth= 0; +my_bool opt_log_slow_admin_statements= 0; my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; uint opt_large_page_size= 0; @@ -1272,19 +1274,6 @@ static void server_init(void) int arg=1; DBUG_ENTER("server_init"); -#ifdef __WIN__ - if (!opt_disable_networking) - { - WSADATA WsaData; - if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData)) - { - /* errors are not read yet, so we use test here */ - my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0)); - unireg_abort(1); - } - } -#endif /* __WIN__ */ - set_ports(); if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap) @@ -3018,6 +3007,21 @@ int main(int argc, char **argv) } #endif +#ifdef __WIN__ +/* Before performing any socket operation (like retrieving hostname */ +/* in init_common_variables we have to call WSAStartup */ + if (!opt_disable_networking) + { + WSADATA WsaData; + if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData)) + { + /* errors are not read yet, so we use test here */ + my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0)); + unireg_abort(1); + } + } +#endif /* __WIN__ */ + if (init_common_variables(MYSQL_CONFIG_NAME, argc, argv, load_default_groups)) unireg_abort(1); // Will do exit @@ -3098,6 +3102,11 @@ You should consider changing lower_case_table_names to 1 or 2", lower_case_table_names= 0; } + /* Reset table_alias_charset, now that lower_case_table_names is set. */ + table_alias_charset= (lower_case_table_names ? + files_charset_info : + &my_charset_bin); + select_thread=pthread_self(); select_thread_in_use=1; init_ssl(); @@ -4328,7 +4337,8 @@ enum options_mysqld OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET, OPT_ENABLE_LARGE_PAGES, OPT_TIMED_MUTEXES, - OPT_OLD_STYLE_USER_LIMITS + OPT_OLD_STYLE_USER_LIMITS, + OPT_LOG_SLOW_ADMIN_STATEMENTS }; @@ -4653,7 +4663,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, "Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES, - "Log queries that are executed without benefit of any index.", + "Log queries that are executed without benefit of any index to the slow log if it is open.", (gptr*) &opt_log_queries_not_using_indexes, (gptr*) &opt_log_queries_not_using_indexes, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-short-format", OPT_SHORT_LOG_FORMAT, @@ -4664,8 +4674,13 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, "Tells the slave to log the updates from the slave thread to the binary log. You will need to turn it on if you plan to daisy-chain the slaves.", (gptr*) &opt_log_slave_updates, (gptr*) &opt_log_slave_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"log-slow-admin-statements", OPT_LOG_SLOW_ADMIN_STATEMENTS, + "Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to the slow log if it is open.", + (gptr*) &opt_log_slow_admin_statements, + (gptr*) &opt_log_slow_admin_statements, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-slow-queries", OPT_SLOW_QUERY_LOG, - "Log slow queries to this log file. Defaults logging to hostname-slow.log file.", + "Log slow queries to this log file. Defaults logging to hostname-slow.log file. Must be enabled to activate other slow log options.", (gptr*) &opt_slow_logname, (gptr*) &opt_slow_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-tc", OPT_LOG_TC, @@ -5225,7 +5240,7 @@ log and this option does nothing anymore.", {"innodb_thread_concurrency", OPT_INNODB_THREAD_CONCURRENCY, "Helps in performance tuning in heavily concurrent environments.", (gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency, - 0, GET_LONG, REQUIRED_ARG, 8, 1, 1000, 0, 1, 0}, + 0, GET_LONG, REQUIRED_ARG, 20, 1, 1000, 0, 1, 0}, {"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY, "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0" " disable a sleep", @@ -5376,7 +5391,7 @@ The minimum value for this variable is 4096.", (gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, 6, 2, 8, 0, 1, 0}, {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, - "Depricated option", + "Deprecated option", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, (gptr*) &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH, @@ -5713,6 +5728,12 @@ struct show_var_st status_vars[]= { {"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS}, {"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS}, {"Com_slave_stop", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_STOP]), SHOW_LONG_STATUS}, + {"Com_stmt_prepare", (char*) offsetof(STATUS_VAR, com_stmt_prepare), SHOW_LONG_STATUS}, + {"Com_stmt_execute", (char*) offsetof(STATUS_VAR, com_stmt_execute), SHOW_LONG_STATUS}, + {"Com_stmt_fetch", (char*) offsetof(STATUS_VAR, com_stmt_fetch), SHOW_LONG_STATUS}, + {"Com_stmt_send_long_data", (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS}, + {"Com_stmt_reset", (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS}, + {"Com_stmt_close", (char*) offsetof(STATUS_VAR, com_stmt_close), SHOW_LONG_STATUS}, {"Com_truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS}, {"Com_unlock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNLOCK_TABLES]), SHOW_LONG_STATUS}, {"Com_update", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UPDATE]), SHOW_LONG_STATUS}, @@ -6314,6 +6335,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_SLOW_QUERY_LOG: opt_slow_log=1; break; + case (int) OPT_LOG_SLOW_ADMIN_STATEMENTS: + opt_log_slow_admin_statements= 1; + break; case (int) OPT_SKIP_NEW: opt_specialflag|= SPECIAL_NO_NEW_FUNC; delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; @@ -6702,6 +6726,9 @@ static void get_options(int argc,char **argv) if (opt_bdb) sql_print_warning("this binary does not contain BDB storage engine"); #endif + if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes) && + !opt_slow_log) + sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set"); /* Check that the default storage engine is actually available. @@ -6771,9 +6798,6 @@ static void get_options(int argc,char **argv) /* Set global variables based on startup options */ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size); - table_alias_charset= (lower_case_table_names ? - files_charset_info : - &my_charset_bin); if (opt_short_log_format) opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; @@ -7025,7 +7049,7 @@ static void create_pid_file() Instantiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION /* Used templates */ template class I_List<THD>; template class I_List_iterator<THD>; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index da359b0aebd..7645ce39eea 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2598,12 +2598,12 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info, { tuple_arg= scan->sel_arg; /* Here we use the length of the first key part */ - tuple_arg->store_min(key_part->length, &key_ptr, 0); + tuple_arg->store_min(key_part->store_length, &key_ptr, 0); } while (tuple_arg->next_key_part != sel_arg) { tuple_arg= tuple_arg->next_key_part; - tuple_arg->store_min(key_part[tuple_arg->part].length, &key_ptr, 0); + tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0); } min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val); records= (info->param->table->file-> @@ -7617,8 +7617,8 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts, *records= num_groups; DBUG_PRINT("info", - ("records=%u, keys/block=%u, keys/group=%u, records=%u, blocks=%u", - table_records, keys_per_block, keys_per_group, records, + ("table rows=%u, keys/block=%u, keys/group=%u, result rows=%u, blocks=%u", + table_records, keys_per_block, keys_per_group, *records, num_blocks)); DBUG_VOID_RETURN; } @@ -8125,6 +8125,15 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() DBUG_ASSERT((have_max && !have_min) || (have_max && have_min && (max_res == 0))); } + /* + If this is a just a GROUP BY or DISTINCT without MIN or MAX and there + are equality predicates for the key parts after the group, find the + first sub-group with the extended prefix. + */ + if (!have_min && !have_max && key_infix_len > 0) + result= file->index_read(record, group_prefix, real_prefix_len, + HA_READ_KEY_EXACT); + result= have_min ? min_res : have_max ? max_res : result; } while (result == HA_ERR_KEY_NOT_FOUND && is_last_prefix != 0); @@ -8151,9 +8160,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() QUICK_GROUP_MIN_MAX_SELECT::next_min() DESCRIPTION - Load the prefix of the next group into group_prefix and find the minimal - key within this group such that the key satisfies the query conditions and - NULL semantics. The found key is loaded into this->record. + Find the minimal key within this group such that the key satisfies the query + conditions and NULL semantics. The found key is loaded into this->record. IMPLEMENTATION Depending on the values of min_max_ranges.elements, key_infix_len, and @@ -8237,9 +8245,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min() QUICK_GROUP_MIN_MAX_SELECT::next_max() DESCRIPTION - If there was no previous next_min call to determine the next group prefix, - then load the next prefix into group_prefix, then lookup the maximal key of - the group, and store it into this->record. + Lookup the maximal key of the group, and store it into this->record. RETURN 0 on success @@ -8917,7 +8923,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose) ** Instantiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List<QUICK_RANGE>; template class List_iterator<QUICK_RANGE>; #endif diff --git a/sql/password.c b/sql/password.c index 79675ade30b..60cc0ac0c97 100644 --- a/sql/password.c +++ b/sql/password.c @@ -146,7 +146,7 @@ void hash_password(ulong *result, const char *password, uint password_len) void make_scrambled_password_323(char *to, const char *password) { ulong hash_res[2]; - hash_password(hash_res, password, strlen(password)); + hash_password(hash_res, password, (uint) strlen(password)); sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]); } @@ -172,7 +172,7 @@ void scramble_323(char *to, const char *message, const char *password) { char extra, *to_start=to; const char *message_end= message + SCRAMBLE_LENGTH_323; - hash_password(hash_pass,password, strlen(password)); + hash_password(hash_pass,password, (uint) strlen(password)); hash_password(hash_message, message, SCRAMBLE_LENGTH_323); randominit(&rand_st,hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]); @@ -394,7 +394,7 @@ make_scrambled_password(char *to, const char *password) sha1_reset(&sha1_context); /* stage 1: hash password */ - sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password)); sha1_result(&sha1_context, (uint8 *) to); /* stage 2: hash stage1 output */ sha1_reset(&sha1_context); @@ -433,7 +433,7 @@ scramble(char *to, const char *message, const char *password) sha1_reset(&sha1_context); /* stage 1: hash password */ - sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password)); sha1_result(&sha1_context, hash_stage1); /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */ sha1_reset(&sha1_context); diff --git a/sql/set_var.cc b/sql/set_var.cc index 3f8c8ea2508..1c0de702e4e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1616,7 +1616,10 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) if (var->value->result_type() == STRING_RESULT) { if (!(res= var->value->val_str(&str))) + { + strmake(buff, "NULL", 4); goto err; + } var->save_result.ulong_value= ((ulong) find_set(enum_names, res->c_ptr(), res->length(), @@ -3128,7 +3131,7 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var) if (!(res=var->value->val_str(&str)) || !(var->save_result.ulong_value= (ulong) (db_type= ha_resolve_by_name(res->ptr(), res->length()))) || - ha_checktype(db_type) != db_type) + ha_checktype(thd, db_type, 1, 0) != db_type) { value= res ? res->c_ptr() : "NULL"; goto err; @@ -3403,7 +3406,7 @@ bool process_key_caches(int (* func) (const char *name, KEY_CACHE *)) Used templates ****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List<set_var_base>; template class List_iterator_fast<set_var_base>; template class I_List_iterator<NAMED_LIST>; diff --git a/sql/set_var.h b/sql/set_var.h index 56690c46131..a6532323b34 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -786,7 +786,8 @@ public: if (value_arg && value_arg->type() == Item::FIELD_ITEM) { Item_field *item= (Item_field*) value_arg; - if (!(value=new Item_string(item->field_name, strlen(item->field_name), + if (!(value=new Item_string(item->field_name, + (uint) strlen(item->field_name), item->collation.collation))) value=value_arg; /* Give error message later */ } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a020cadc084..fcc04c950aa 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5347,14 +5347,14 @@ ER_SP_NO_RETSET_IN_FUNC 0A000 ER_CANT_CREATE_GEOMETRY_OBJECT 22003 eng "Cannot get geometry object from data you send to the GEOMETRY field" ER_FAILED_ROUTINE_BREAK_BINLOG - eng "A routine failed and is declared to modify data and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes" + eng "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes" ER_BINLOG_UNSAFE_ROUTINE - eng "This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" + eng "This routine has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" ER_BINLOG_CREATE_ROUTINE_NEED_SUPER - eng "You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" + eng "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" ER_EXEC_STMT_WITH_OPEN_CURSOR eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it." ER_STMT_HAS_NO_OPEN_CURSOR - eng "The statement (%d) has no open cursor." + eng "The statement (%lu) has no open cursor." ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG eng "Explicit or implicit commit is not allowed in stored function or trigger." diff --git a/sql/slave.cc b/sql/slave.cc index 46b028cc431..a0779543148 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4617,7 +4617,7 @@ end: } -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class I_List_iterator<i_string>; template class I_List_iterator<i_string_pair>; #endif diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1e5bd5b5b8c..29cee6da4d3 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -310,16 +310,16 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() - :Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE), + :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), + m_returns_cs(NULL), m_has_return(FALSE), m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); - extern byte + extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first); DBUG_ENTER("sp_head::sp_head"); - state= INITIALIZED; m_backpatch.empty(); m_lex.empty(); hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); @@ -533,17 +533,35 @@ sp_head::destroy() } +/* + * This is only used for result fields from functions (both during + * fix_length_and_dec() and evaluation). + * + * Since the current mem_root during a will be freed and the result + * field will be used by the caller, we have to put it in the caller's + * or main mem_root. + */ Field * sp_head::make_field(uint max_length, const char *name, TABLE *dummy) { Field *field; + MEM_ROOT *tmp_mem_root; + THD *thd; DBUG_ENTER("sp_head::make_field"); + + thd= current_thd; + tmp_mem_root= thd->mem_root; + if (thd->spcont && thd->spcont->callers_mem_root) + thd->mem_root= thd->spcont->callers_mem_root; + else + thd->mem_root= &thd->main_mem_root; field= ::make_field((char *)0, !m_returns_len ? max_length : m_returns_len, (uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs, (enum Field::geometry_type)0, Field::NONE, m_returns_typelib, name ? name : (const char *)m_name.str, dummy); + thd->mem_root= tmp_mem_root; DBUG_RETURN(field); } @@ -556,7 +574,7 @@ sp_head::execute(THD *thd) sp_rcontext *ctx; int ret= 0; uint ip= 0; - Item_arena *old_arena; + Query_arena *old_arena; query_id_t old_query_id; TABLE *old_derived_tables; LEX *old_lex; @@ -618,7 +636,21 @@ sp_head::execute(THD *thd) break; DBUG_PRINT("execute", ("Instruction %u", ip)); thd->set_time(); // Make current_time() et al work - ret= i->execute(thd, &ip); + { + /* + We have to substitute free_list of executing statement to + current_arena to store there all new items created during execution + (for example '*' expanding, or items made during permanent subquery + transformation) + Note: Every statement have to have all its items listed in free_list + for correct cleaning them up + */ + Item *save_free_list= thd->current_arena->free_list; + thd->current_arena->free_list= i->free_list; + ret= i->execute(thd, &ip); + i->free_list= thd->current_arena->free_list; + thd->current_arena->free_list= save_free_list; + } if (i->free_list) cleanup_items(i->free_list); // Check if an exception has occurred and a handler has been found @@ -664,6 +696,7 @@ sp_head::execute(THD *thd) cleanup_items(thd->current_arena->free_list); thd->current_arena= old_arena; + state= EXECUTED; done: DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d", @@ -695,6 +728,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) sp_rcontext *nctx = NULL; uint i; int ret; + MEM_ROOT *old_mem_root, call_mem_root; + Item *old_free_list, *call_free_list; if (argcount != params) { @@ -705,9 +740,16 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) DBUG_RETURN(-1); } + init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + old_mem_root= thd->mem_root; + thd->mem_root= &call_mem_root; + old_free_list= thd->free_list; // Keep the old list + thd->free_list= NULL; // Start a new one + // QQ Should have some error checking here? (types, etc...) nctx= new sp_rcontext(csize, hmax, cmax); - for (i= 0 ; i < params && i < argcount ; i++) + nctx->callers_mem_root= old_mem_root; + for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL); @@ -735,13 +777,20 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) ret= execute(thd); + // Partially restore context now. + // We still need the call mem root and free list for processing + // of the result. + call_free_list= thd->free_list; + thd->free_list= old_free_list; + thd->mem_root= old_mem_root; + if (m_type == TYPE_ENUM_FUNCTION && ret == 0) { /* We need result only in function but not in trigger */ Item *it= nctx->get_result(); if (it) - *resp= it; + *resp= sp_eval_func_item(thd, &it, m_returns, NULL); else { my_error(ER_SP_NORETURNEND, MYF(0), m_name.str); @@ -751,6 +800,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) nctx->pop_all_cursors(); // To avoid memory leaks after an error thd->spcont= octx; + + // Now get rid of the rest of the callee context + cleanup_items(call_free_list); + free_items(call_free_list); + free_root(&call_mem_root, MYF(0)); + DBUG_RETURN(ret); } @@ -780,6 +835,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx + MEM_ROOT *old_mem_root, call_mem_root; + Item *old_free_list, *call_free_list; if (args->elements != params) { @@ -788,6 +845,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) DBUG_RETURN(-1); } + init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + old_mem_root= thd->mem_root; + thd->mem_root= &call_mem_root; + old_free_list= thd->free_list; // Keep the old list + thd->free_list= NULL; // Start a new one + if (csize > 0 || hmax > 0 || cmax > 0) { Item_null *nit= NULL; // Re-use this, and only create if needed @@ -853,9 +916,16 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) if (! ret) ret= execute(thd); + // Partially restore context now. + // We still need the call mem root and free list for processing + // of out parameters. + call_free_list= thd->free_list; + thd->free_list= old_free_list; + thd->mem_root= old_mem_root; + if (!ret && csize > 0) { - List_iterator_fast<Item> li(*args); + List_iterator<Item> li(*args); Item *it; // Copy back all OUT or INOUT values to the previous frame, or @@ -867,8 +937,34 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) if (pvar->mode != sp_param_in) { if (it->is_splocal()) - octx->set_item(static_cast<Item_splocal *>(it)->get_offset(), - nctx->get_item(i)); + { + // Have to copy the item to the caller's mem_root + Item *copy; + uint offset= static_cast<Item_splocal *>(it)->get_offset(); + Item *val= nctx->get_item(i); + Item *orig= octx->get_item(offset); + Item *o_item_next; + Item *o_free_list= thd->free_list; + LINT_INIT(o_item_next); + + if (orig) + o_item_next= orig->next; + copy= sp_eval_func_item(thd, &val, pvar->type, orig); // Copy + if (!copy) + { + ret= -1; + break; + } + if (copy != orig) + octx->set_item(offset, copy); + if (orig && copy == orig) + { + // A reused item slot, where the constructor put it in the + // free_list, so we have to restore the list. + thd->free_list= o_free_list; + copy->next= o_item_next; + } + } else { Item_func_get_user_var *guv= item_is_user_var(it); @@ -899,6 +995,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) nctx->pop_all_cursors(); // To avoid memory leaks after an error thd->spcont= octx; + // Now get rid of the rest of the callee context + cleanup_items(call_free_list); + free_items(call_free_list); + thd->lex->unit.cleanup(); + free_root(&call_mem_root, MYF(0)); + DBUG_RETURN(ret); } @@ -1077,7 +1179,7 @@ sp_head::restore_thd_mem_root(THD *thd) DBUG_ENTER("sp_head::restore_thd_mem_root"); Item *flist= free_list; // The old list set_item_arena(thd); // Get new free_list and mem_root - state= INITIALIZED; + state= INITIALIZED_FOR_SP; DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", (ulong) &mem_root, (ulong) &thd->mem_root)); @@ -1355,7 +1457,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, implemented at the same time as ability not to store LEX for instruction if it is not really used. */ - reset_stmt_for_execute(thd, m_lex); + reinit_stmt_before_use(thd, m_lex); /* If requested check whenever we have access to tables in LEX's table list @@ -2225,7 +2327,7 @@ sp_head::add_used_tables_to_table_list(THD *thd, TABLE_LIST ***query_tables_last_ptr) { uint i; - Item_arena *arena, backup; + Query_arena *arena, backup; bool result= FALSE; DBUG_ENTER("sp_head::add_used_tables_to_table_list"); diff --git a/sql/sp_head.h b/sql/sp_head.h index 49eabce246b..2c75a320f30 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -74,11 +74,12 @@ sp_name * sp_name_current_db_new(THD *thd, LEX_STRING name); -class sp_head :private Item_arena +class sp_head :private Query_arena { sp_head(const sp_head &); /* Prevent use of these */ void operator=(sp_head &); + MEM_ROOT main_mem_root; public: int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE @@ -377,6 +378,10 @@ public: return (uint)m_lex->sql_command; } + void disable_query_cache() + { + m_lex->safe_to_cache_query= 0; + } private: LEX *m_lex; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 6f2165539d7..aacb9254753 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -32,6 +32,7 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) : m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0), m_hfound(-1), m_ccount(0) { + callers_mem_root= NULL; in_handler= FALSE; m_frame= (Item **)sql_alloc(fsize * sizeof(Item*)); m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t)); @@ -168,6 +169,17 @@ sp_rcontext::pop_cursors(uint count) * */ +sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper) + :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL) +{ + /* + currsor can't be stored in QC, so we should prevent opening QC for + try to write results which are absent. + */ + lex_keeper->disable_query_cache(); +} + + /* pre_open cursor diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index ba5fa950dc3..b188805435f 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -47,6 +47,7 @@ class sp_rcontext : public Sql_alloc public: + MEM_ROOT *callers_mem_root; // Used to store result fields bool in_handler; sp_rcontext(uint fsize, uint hmax, uint cmax); @@ -202,11 +203,7 @@ class sp_cursor : public Sql_alloc { public: - sp_cursor(sp_lex_keeper *lex_keeper) - : m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL) - { - /* Empty */ - } + sp_cursor(sp_lex_keeper *lex_keeper); virtual ~sp_cursor() { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 28b841435c8..5e2df88f91e 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -187,7 +187,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ACL_HOST host; update_hostname(&host.host,get_field(&mem, table->field[0])); host.db= get_field(&mem, table->field[1]); - if (lower_case_table_names) + if (lower_case_table_names && host.db) { /* convert db to lower case and give a warning if the db wasn't @@ -209,7 +209,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { sql_print_warning("'host' entry '%s|%s' " "ignored in --skip-name-resolve mode.", - host.host.hostname, host.db, host.host.hostname); + host.host.hostname, host.db?host.db:""); continue; } #ifndef TO_BE_REMOVED @@ -277,7 +277,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { sql_print_warning("'user' entry '%s@%s' " "ignored in --skip-name-resolve mode.", - user.user, user.host.hostname, user.host.hostname); + user.user, user.host.hostname); continue; } @@ -413,7 +413,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { sql_print_warning("'db' entry '%s %s@%s' " "ignored in --skip-name-resolve mode.", - db.db, db.user, db.host.hostname, db.host.hostname); + db.db, db.user, db.host.hostname); continue; } db.access=get_access(table,3); @@ -3232,7 +3232,7 @@ my_bool grant_init(THD *org_thd) sql_print_warning("'procs_priv' entry '%s %s@%s' " "ignored in --skip-name-resolve mode.", mem_check->tname, mem_check->user, - mem_check->host, mem_check->host); + mem_check->host); continue; } } @@ -5172,7 +5172,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) grant_proc->db, grant_proc->tname, is_proc, - ~0, 1)) + ~(ulong)0, 1)) { revoked= 1; continue; @@ -5240,7 +5240,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, lex_user.host.length= strlen(grant_proc->host.hostname); if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user, grant_proc->db, grant_proc->tname, - is_proc, ~0, 1)) + is_proc, ~(ulong)0, 1)) { revoked= 1; continue; @@ -5325,7 +5325,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, Instantiate used templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List_iterator<LEX_COLUMN>; template class List_iterator<LEX_USER>; template class List<LEX_COLUMN>; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1d49b47761b..b112ca971c3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -42,7 +42,6 @@ static my_bool open_new_frm(const char *path, const char *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc, MEM_ROOT *mem_root); -static void relink_tables_for_multidelete(THD *thd); extern "C" byte *table_cache_key(const byte *record,uint *length, my_bool not_used __attribute__((unused))) @@ -2089,7 +2088,6 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling))) DBUG_RETURN(TRUE); /* purecov: inspected */ - relink_tables_for_multidelete(thd); DBUG_RETURN(0); } @@ -2119,37 +2117,11 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables) if (open_tables(thd, &tables, &counter) || mysql_handle_derived(thd->lex, &mysql_derived_prepare)) DBUG_RETURN(TRUE); /* purecov: inspected */ - relink_tables_for_multidelete(thd); // Not really needed, but DBUG_RETURN(0); } /* - Let us propagate pointers to open tables from global table list - to table lists for multi-delete -*/ - -static void relink_tables_for_multidelete(THD *thd) -{ - if (thd->lex->all_selects_list->next_select_in_list()) - { - for (SELECT_LEX *sl= thd->lex->all_selects_list; - sl; - sl= sl->next_select_in_list()) - { - for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first; - cursor; - cursor=cursor->next_local) - { - if (cursor->correspondent_table) - cursor->table= cursor->correspondent_table->table; - } - } - } -} - - -/* Mark all real tables in the list as free for reuse. SYNOPSIS @@ -2656,7 +2628,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, uint length=(uint) strlen(name); char name_buff[NAME_LEN+1]; - if (item->cached_table) { /* @@ -2723,10 +2694,13 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, db= name_buff; } + bool search_global= item->item_flags & MY_ITEM_PREFER_1ST_TABLE; if (table_name && table_name[0]) { /* Qualified field */ - bool found_table=0; - for (; tables; tables= tables->next_local) + bool found_table=0; + uint table_idx= 0; + for (; tables; tables= search_global?tables->next_global:tables->next_local, + table_idx++) { /* TODO; Ensure that db and tables->db always points to something ! */ if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && @@ -2762,6 +2736,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found=find; + if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) + break; } } } @@ -2786,9 +2762,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; return (Field*) 0; } - bool allow_rowid= tables && !tables->next_local; // Only one table - for (; tables ; tables= tables->next_local) + uint table_idx= 0; + for (; tables ; tables= search_global?tables->next_global:tables->next_local, + table_idx++) { if (!tables->table && !tables->ancestor) { @@ -2823,7 +2800,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); return (Field*) 0; } - found=field; + found= field; + if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) + break; } } if (found) @@ -3050,7 +3029,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, Item *item; List_iterator<Item> it(fields); - Item_arena *arena, backup; + Query_arena *arena, backup; DBUG_ENTER("setup_wild"); /* @@ -3081,7 +3060,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, } else if (insert_fields(thd,tables,((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it, - any_privileges, arena != 0)) + any_privileges)) { if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -3334,8 +3313,6 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, any_privileges 0 If we should ensure that we have SELECT privileges for all columns 1 If any privilege is ok - allocate_view_names if true view names will be copied to current Item_arena - memory (made for SP/PS) RETURN 0 ok 'it' is updated to point at last inserted @@ -3345,7 +3322,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, bool insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it, - bool any_privileges, bool allocate_view_names) + bool any_privileges) { /* allocate variables on stack to avoid pool alloaction */ Field_iterator_table table_iter; @@ -3536,25 +3513,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, field->query_id=thd->query_id; table->used_keys.intersect(field->part_of_key); } - else if (allocate_view_names && - thd->lex->current_select->first_execution) - { - Item_field *item; - if (alias_used) - item= new Item_field(0, - thd->strdup(tables->alias), - thd->strdup(field_name)); - else - item= new Item_field(thd->strdup(tables->view_db.str), - thd->strdup(tables->view_name.str), - thd->strdup(field_name)); - /* - during cleunup() this item will be put in list to replace - expression from VIEW - */ - thd->nocheck_register_item_tree_change(it->ref(), item, - thd->mem_root); - } } /* All fields are used in case if usual tables (in case of view used @@ -3594,7 +3552,7 @@ err: int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { SELECT_LEX *select_lex= thd->lex->current_select; - Item_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->current_arena, backup; bool save_wrapper= thd->lex->current_select->no_wrap_view_item; TABLE_LIST *table= NULL; // For HP compilers DBUG_ENTER("setup_conds"); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 438bfdbcb73..8abd7cbbe7d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -49,7 +49,7 @@ char internal_table_name[2]= "*"; ** Instansiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION /* Used templates */ template class List<Key>; template class List_iterator<Key>; @@ -156,9 +156,15 @@ bool foreign_key_prefix(Key *a, Key *b) /**************************************************************************** ** Thread specific functions ****************************************************************************/ +/* + Pass nominal parameters to Statement constructor only to ensure that + the destructor works OK in case of error. The main_mem_root will be + re-initialized in init(). +*/ THD::THD() - :user_time(0), global_read_lock(0), is_fatal_error(0), + :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), + user_time(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE), @@ -420,8 +426,6 @@ THD::~THD() #ifndef DBUG_OFF dbug_sentry= THD_SENTRY_GONE; #endif - /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */ - clear_alloc_root(&stmt_backup.main_mem_root); DBUG_VOID_RETURN; } @@ -714,8 +718,10 @@ int THD::send_explain_fields(select_result *result) CHARSET_INFO *cs= system_charset_info; field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("select_type", 19, cs)); - field_list.push_back(new Item_empty_string("table", NAME_LEN, cs)); - field_list.push_back(new Item_empty_string("type", 10, cs)); + field_list.push_back(item= new Item_empty_string("table", NAME_LEN, cs)); + item->maybe_null= 1; + field_list.push_back(item= new Item_empty_string("type", 10, cs)); + item->maybe_null= 1; field_list.push_back(item=new Item_empty_string("possible_keys", NAME_LEN*MAX_KEY, cs)); item->maybe_null=1; @@ -727,7 +733,9 @@ int THD::send_explain_fields(select_result *result) field_list.push_back(item=new Item_empty_string("ref", NAME_LEN*MAX_REF_PARTS, cs)); item->maybe_null=1; - field_list.push_back(new Item_return_int("rows", 10, MYSQL_TYPE_LONGLONG)); + field_list.push_back(item= new Item_return_int("rows", 10, + MYSQL_TYPE_LONGLONG)); + item->maybe_null= 1; field_list.push_back(new Item_empty_string("Extra", 255, cs)); return (result->send_fields(field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)); @@ -1470,53 +1478,7 @@ void select_dumpvar::cleanup() } -/* - Create arena for already constructed THD. - - SYNOPSYS - Item_arena() - thd - thread for which arena is created - - DESCRIPTION - Create arena for already existing THD using its variables as parameters - for memory root initialization. -*/ -Item_arena::Item_arena(THD* thd) - :free_list(0), mem_root(&main_mem_root), - state(INITIALIZED) -{ - init_sql_alloc(&main_mem_root, - thd->variables.query_alloc_block_size, - thd->variables.query_prealloc_size); -} - - -/* - Create arena and optionally initialize memory root. - - SYNOPSYS - Item_arena() - init_mem_root - whenever we need to initialize memory root - - DESCRIPTION - Create arena and optionally initialize memory root with minimal - possible parameters. - - NOTE - We use this constructor when arena is part of THD, but reinitialize - its memory root in THD::init_for_queries() before execution of real - statements. -*/ -Item_arena::Item_arena(bool init_mem_root) - :free_list(0), mem_root(&main_mem_root), - state(CONVENTIONAL_EXECUTION) -{ - if (init_mem_root) - init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); -} - - -Item_arena::Type Item_arena::type() const +Query_arena::Type Query_arena::type() const { DBUG_ASSERT(0); /* Should never be called */ return STATEMENT; @@ -1527,9 +1489,10 @@ Item_arena::Type Item_arena::type() const Statement functions */ -Statement::Statement(THD *thd) - :Item_arena(thd), - id(++thd->statement_id_counter), +Statement::Statement(enum enum_state state_arg, ulong id_arg, + ulong alloc_block_size, ulong prealloc_size) + :Query_arena(&main_mem_root, state_arg), + id(id_arg), set_query_id(1), allow_sum_func(0), lex(&main_lex), @@ -1538,28 +1501,11 @@ Statement::Statement(THD *thd) cursor(0) { name.str= NULL; + init_sql_alloc(&main_mem_root, alloc_block_size, prealloc_size); } -/* - This constructor is called when statement is a subobject of THD: - Some variables are initialized in THD::init due to locking problems - This statement object will be used to -*/ -Statement::Statement() - :Item_arena((bool)TRUE), - id(0), - set_query_id(1), - allow_sum_func(0), /* initialized later */ - lex(&main_lex), - query(0), /* these two are set */ - query_length(0), /* in alloc_query() */ - cursor(0) -{ -} - - -Item_arena::Type Statement::type() const +Query_arena::Type Statement::type() const { return STATEMENT; } @@ -1607,9 +1553,9 @@ void THD::end_statement() } -void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup) +void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) { - DBUG_ENTER("Item_arena::set_n_backup_item_arena"); + DBUG_ENTER("Query_arena::set_n_backup_item_arena"); DBUG_ASSERT(backup_arena == 0); backup->set_item_arena(this); set_item_arena(set); @@ -1620,28 +1566,18 @@ void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup) } -void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup) +void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup) { - DBUG_ENTER("Item_arena::restore_backup_item_arena"); + DBUG_ENTER("Query_arena::restore_backup_item_arena"); set->set_item_arena(this); set_item_arena(backup); #ifndef DBUG_OFF backup_arena= 0; #endif -#ifdef NOT_NEEDED_NOW - /* - Reset backup mem_root to avoid its freeing. - Since Item_arena's mem_root is freed only when it is part of Statement - we need this only if we use some Statement's arena as backup storage. - But we do this only with THD::stmt_backup and this Statement is specially - handled in this respect. So this code is not really needed now. - */ - clear_alloc_root(&backup->mem_root); -#endif DBUG_VOID_RETURN; } -void Item_arena::set_item_arena(Item_arena *set) +void Query_arena::set_item_arena(Query_arena *set) { mem_root= set->mem_root; free_list= set->free_list; @@ -1650,6 +1586,11 @@ void Item_arena::set_item_arena(Item_arena *set) Statement::~Statement() { + /* + We must free `main_mem_root', not `mem_root' (pointer), to work + correctly if this statement is used as a backup statement, + for which `mem_root' may point to some other statement. + */ free_root(&main_mem_root, MYF(0)); } diff --git a/sql/sql_class.h b/sql/sql_class.h index c258380cd3d..fbc5e5f85bf 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -632,6 +632,13 @@ typedef struct system_status_var ulong filesort_range_count; ulong filesort_rows; ulong filesort_scan_count; + /* Ppepared statements and binary protocol */ + ulong com_stmt_prepare; + ulong com_stmt_execute; + ulong com_stmt_send_long_data; + ulong com_stmt_fetch; + ulong com_stmt_reset; + ulong com_stmt_close; double last_query_cost; } STATUS_VAR; @@ -641,13 +648,13 @@ typedef struct system_status_var variable in system_status_var */ -#define last_system_status_var filesort_scan_count +#define last_system_status_var com_stmt_close void free_tmp_table(THD *thd, TABLE *entry); -class Item_arena +class Query_arena { public: /* @@ -655,17 +662,16 @@ public: itself to the list on creation (see Item::Item() for details)) */ Item *free_list; - MEM_ROOT main_mem_root; MEM_ROOT *mem_root; // Pointer to current memroot #ifndef DBUG_OFF bool backup_arena; #endif - enum enum_state + enum enum_state { - INITIALIZED= 0, PREPARED= 1, EXECUTED= 3, CONVENTIONAL_EXECUTION= 2, - ERROR= -1 + INITIALIZED= 0, INITIALIZED_FOR_SP= 1, PREPARED= 2, + CONVENTIONAL_EXECUTION= 3, EXECUTED= 4, ERROR= -1 }; - + enum_state state; /* We build without RTTI, so dynamic_cast can't be used. */ @@ -674,24 +680,20 @@ public: STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE }; + Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : + free_list(0), mem_root(mem_root_arg), state(state_arg) + {} /* - This constructor is used only when Item_arena is created as - backup storage for another instance of Item_arena. - */ - Item_arena() {}; - /* - Create arena for already constructed THD using its variables as - parameters for memory root initialization. - */ - Item_arena(THD *thd); - /* - Create arena and optionally init memory root with minimal values. - Particularly used if Item_arena is part of Statement. + This constructor is used only when Query_arena is created as + backup storage for another instance of Query_arena. */ - Item_arena(bool init_mem_root); + Query_arena() {}; virtual Type type() const; - virtual ~Item_arena() {}; + virtual ~Query_arena() {}; + inline bool is_stmt_prepare() const { return state == INITIALIZED; } + inline bool is_first_sp_execute() const + { return state == INITIALIZED_FOR_SP; } inline bool is_stmt_prepare_or_first_sp_execute() const { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } @@ -699,6 +701,7 @@ public: { return state == PREPARED || state == EXECUTED; } inline bool is_conventional() const { return state == CONVENTIONAL_EXECUTION; } + inline gptr alloc(unsigned int size) { return alloc_root(mem_root,size); } inline gptr calloc(unsigned int size) { @@ -721,9 +724,9 @@ public: return ptr; } - void set_n_backup_item_arena(Item_arena *set, Item_arena *backup); - void restore_backup_item_arena(Item_arena *set, Item_arena *backup); - void set_item_arena(Item_arena *set); + void set_n_backup_item_arena(Query_arena *set, Query_arena *backup); + void restore_backup_item_arena(Query_arena *set, Query_arena *backup); + void set_item_arena(Query_arena *set); }; @@ -743,12 +746,13 @@ class Cursor; be used explicitly. */ -class Statement: public Item_arena +class Statement: public Query_arena { Statement(const Statement &rhs); /* not implemented: */ Statement &operator=(const Statement &rhs); /* non-copyable */ public: - /* FIXME: must be private */ + /* FIXME: these must be protected */ + MEM_ROOT main_mem_root; LEX main_lex; /* @@ -813,13 +817,11 @@ public: public: - /* - This constructor is called when statement is a subobject of THD: - some variables are initialized in THD::init due to locking problems - */ - Statement(); + /* This constructor is called for backup statements */ + Statement() { clear_alloc_root(&main_mem_root); } - Statement(THD *thd); + Statement(enum enum_state state_arg, ulong id_arg, + ulong alloc_block_size, ulong prealloc_size); virtual ~Statement(); /* Assign execution context (note: not all members) of given stmt to self */ @@ -962,11 +964,6 @@ public: /* all prepared statements and cursors of this connection */ Statement_map stmt_map; /* - keeps THD state while it is used for active statement - Note: we perform special cleanup for it in THD destructor. - */ - Statement stmt_backup; - /* A pointer to the stack frame of handle_one_connection(), which is called first in the thread for handling a client */ @@ -1046,7 +1043,7 @@ public: #endif struct st_my_thread_var *mysys_var; /* - Type of current query: COM_PREPARE, COM_QUERY, etc. Set from + Type of current query: COM_STMT_PREPARE, COM_QUERY, etc. Set from first byte of the packet in do_command() */ enum enum_server_command command; @@ -1114,9 +1111,9 @@ public: Item_change_list change_list; /* - Current prepared Item_arena if there one, or 0 + Current prepared Query_arena if there one, or 0 */ - Item_arena *current_arena; + Query_arena *current_arena; /* next_insert_id is set on SET INSERT_ID= #. This is used as the next generated auto_increment value in handler.cc @@ -1193,7 +1190,7 @@ public: bool query_error, bootstrap, cleanup_done; bool tmp_table_used; bool charset_is_system_charset, charset_is_collation_connection; - bool slow_command; + bool enable_slow_log; /* enable slow log for current statement */ bool no_trans_update, abort_on_warning; bool got_warning; /* Set on call to push_warning() */ bool no_warnings_for_error; /* no warnings on call to my_error() */ @@ -1338,13 +1335,9 @@ public: return 0; #endif } - inline bool only_prepare() - { - return command == COM_PREPARE; - } inline bool fill_derived_tables() { - return !only_prepare() && !lex->only_view_structure(); + return !current_arena->is_stmt_prepare() && !lex->only_view_structure(); } inline gptr trans_alloc(unsigned int size) { @@ -1377,20 +1370,20 @@ public: inline void fatal_error() { is_fatal_error= 1; - net.report_error= 1; + net.report_error= 1; DBUG_PRINT("error",("Fatal error set")); } inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); - inline Item_arena *change_arena_if_needed(Item_arena *backup) + inline Query_arena *change_arena_if_needed(Query_arena *backup) { /* use new arena if we are in a prepared statements and we have not already changed to use this arena. */ if (!current_arena->is_conventional() && - mem_root != ¤t_arena->main_mem_root) + mem_root != current_arena->mem_root) { set_n_backup_item_arena(current_arena, backup); return current_arena; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7ad490599db..e6f980859ab 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -808,7 +808,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) if (!dont_send_ok) { db_type table_type; - if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN) + if ((table_type=get_table_type(thd, path)) == DB_TYPE_UNKNOWN) { my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 2ae293c1bff..e1d701936cf 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -217,6 +217,8 @@ exit: queries defined. After temporary table is filled, if this is not EXPLAIN, then the entire unit / node is deleted. unit is deleted if UNION is used for derived table and node is deleted is it is a simple SELECT. + If you use this function, make sure it's not called at prepare. + Due to evaluation of LIMIT clause it can not be used at prepared stage. RETURN 0 ok @@ -245,11 +247,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) } else { - unit->offset_limit_cnt= first_select->offset_limit; - unit->select_limit_cnt= first_select->select_limit+ - first_select->offset_limit; - if (unit->select_limit_cnt < first_select->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; + unit->set_limit(first_select); if (unit->select_limit_cnt == HA_POS_ERROR) first_select->options&= ~OPTION_FOUND_ROWS; diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 293b695d199..8a12339ccee 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -225,21 +225,21 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show) MYSQL_ERROR *err; SELECT_LEX *sel= &thd->lex->select_lex; - ha_rows offset= sel->offset_limit, limit= sel->select_limit; + SELECT_LEX_UNIT *unit= &thd->lex->unit; + ha_rows idx= 0; Protocol *protocol=thd->protocol; - + + unit->set_limit(sel); + List_iterator_fast<MYSQL_ERROR> it(thd->warn_list); while ((err= it++)) { /* Skip levels that the user is not interested in */ if (!(levels_to_show & ((ulong) 1 << err->level))) continue; - if (offset) - { - offset--; + if (++idx <= unit->offset_limit_cnt) continue; - } - if (limit-- == 0) + if (idx > unit->select_limit_cnt) break; protocol->prepare_for_resend(); protocol->store(warning_level_names[err->level], diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 1aa034ce61c..e905f93b860 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -321,8 +321,8 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) key_expr ha_rkey_mode cond - select_limit - offset_limit + select_limit_cnt + offset_limit_cnt RETURN FALSE ok @@ -333,7 +333,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr, enum ha_rkey_function ha_rkey_mode, Item *cond, - ha_rows select_limit,ha_rows offset_limit) + ha_rows select_limit_cnt, ha_rows offset_limit_cnt) { TABLE_LIST *hash_tables; TABLE *table; @@ -413,8 +413,6 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) goto err0; - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it - if (keyname) { if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0) @@ -422,14 +420,11 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias); goto err0; } - table->file->ha_index_or_rnd_end(); - table->file->ha_index_init(keyno); } - if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0)) + if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0)) goto err0; - select_limit+=offset_limit; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); HANDLER_TABLES_HACK(thd); @@ -447,12 +442,25 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, table->file->init_table_handle_for_HANDLER(); - for (num_rows=0; num_rows < select_limit; ) + for (num_rows=0; num_rows < select_limit_cnt; ) { switch (mode) { + case RNEXT: + if (table->file->inited != handler::NONE) + { + error=keyname ? + table->file->index_next(table->record[0]) : + table->file->rnd_next(table->record[0]); + break; + } + /* else fall through */ case RFIRST: if (keyname) + { + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); error= table->file->index_first(table->record[0]); + } else { table->file->ha_index_or_rnd_end(); @@ -461,20 +469,21 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } mode=RNEXT; break; + case RPREV: + DBUG_ASSERT(keyname != 0); + if (table->file->inited != handler::NONE) + { + error=table->file->index_prev(table->record[0]); + break; + } + /* else fall through */ case RLAST: DBUG_ASSERT(keyname != 0); + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); error= table->file->index_last(table->record[0]); mode=RPREV; break; - case RNEXT: - error= (keyname ? - table->file->index_next(table->record[0]) : - table->file->rnd_next(table->record[0])); - break; - case RPREV: - DBUG_ASSERT(keyname != 0); - error= table->file->index_prev(table->record[0]); - break; case RNEXT_SAME: /* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */ DBUG_ASSERT(keyname != 0); @@ -509,6 +518,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len)))) goto err; + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); key_copy(key, table->record[0], table->key_info + keyno, key_len); error= table->file->index_read(table->record[0], key,key_len,ha_rkey_mode); @@ -535,7 +546,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } if (cond && !cond->val_int()) continue; - if (num_rows >= offset_limit) + if (num_rows >= offset_limit_cnt) { Item *item; protocol->prepare_for_resend(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c3c51afc03b..b1bb7c7e14b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2001,10 +2001,22 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, int select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { + int res; + LEX *lex= thd->lex; + SELECT_LEX *lex_current_select_save= lex->current_select; DBUG_ENTER("select_insert::prepare"); unit= u; - if (check_insert_fields(thd, table_list, *fields, values, !insert_into_view)) + /* + Since table in which we are going to insert is added to the first + select, LEX::current_select should point to the first select while + we are fixing fields from insert list. + */ + lex->current_select= &lex->select_lex; + res= check_insert_fields(thd, table_list, *fields, values, + !insert_into_view); + lex->current_select= lex_current_select_save; + if (res) DBUG_RETURN(1); /* if it is INSERT into join view then check_insert_fields already found @@ -2016,12 +2028,12 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) Is table which we are changing used somewhere in other parts of query */ - if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) && + if (!(lex->current_select->options & OPTION_BUFFER_RESULT) && unique_table(table_list, table_list->next_global)) { /* Using same table for INSERT and SELECT */ - thd->lex->current_select->options|= OPTION_BUFFER_RESULT; - thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT; + lex->current_select->options|= OPTION_BUFFER_RESULT; + lex->current_select->join->select_options|= OPTION_BUFFER_RESULT; } else { @@ -2120,9 +2132,12 @@ bool select_insert::send_data(List<Item> &values) } if (!(error= write_record(thd, table, &info))) { - if (table->triggers) + if (table->triggers || info.handle_duplicates == DUP_UPDATE) { /* + Restore fields of the record since it is possible that they were + changed by ON DUPLICATE KEY UPDATE clause. + If triggers exist then whey can modify some fields which were not originally touched by INSERT ... SELECT, so we have to restore their original values for the next row. @@ -2375,11 +2390,11 @@ void select_create::abort() Instansiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List_iterator_fast<List_item>; #ifndef EMBEDDED_LIBRARY template class I_List<delayed_insert>; template class I_List_iterator<delayed_insert>; template class I_List<delayed_row>; #endif /* EMBEDDED_LIBRARY */ -#endif /* __GNUC__ */ +#endif /* HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index eb33fda02f7..08f0c3badf7 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -135,7 +135,6 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0; lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list); lex->select_lex.options= 0; - lex->select_lex.options2= 0; lex->select_lex.init_order(); lex->select_lex.group_list.empty(); lex->describe= 0; @@ -968,7 +967,7 @@ int yylex(void *arg, void *yythd) { THD* thd= (THD*)yythd; if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && - (thd->command != COM_PREPARE)) + (thd->command != COM_STMT_PREPARE)) { lex->safe_to_cache_query= 0; lex->found_semicolon=(char*) lex->ptr; @@ -1065,7 +1064,6 @@ int yylex(void *arg, void *yythd) void st_select_lex_node::init_query() { options= 0; - options2= 0; linkage= UNSPECIFIED_TYPE; no_error= no_table_names_allowed= 0; uncacheable= 0; @@ -1129,7 +1127,6 @@ void st_select_lex::init_select() table_join_options= 0; in_sum_expr= with_wild= 0; options= 0; - options2= 0; braces= 0; when_list.empty(); expr_list.empty(); @@ -1141,8 +1138,9 @@ void st_select_lex::init_select() order_list.elements= 0; order_list.first= 0; order_list.next= (byte**) &order_list.first; - select_limit= HA_POS_ERROR; - offset_limit= 0; + /* Set limit and offset to default values */ + select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ + offset_limit= 0; /* denotes the default offset = 0 */ with_sum_func= 0; } @@ -1366,7 +1364,7 @@ ulong st_select_lex_node::get_table_join_options() */ bool st_select_lex::test_limit() { - if (select_limit != HA_POS_ERROR) + if (select_limit != 0) { my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LIMIT & IN/ALL/ANY/SOME subquery"); @@ -1486,8 +1484,8 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) We have to create array in prepared statement memory if it is prepared statement */ - Item_arena *arena= thd->current_arena; - return (ref_pointer_array= + Query_arena *arena= thd->current_arena; + return (ref_pointer_array= (Item **)arena->alloc(sizeof(Item*) * (item_list.elements + select_n_having_items + @@ -1554,24 +1552,20 @@ void st_select_lex::print_limit(THD *thd, String *str) item->substype() == Item_subselect::IN_SUBS || item->substype() == Item_subselect::ALL_SUBS)) { - DBUG_ASSERT(!item->fixed || select_limit == 1L && offset_limit == 0L); + DBUG_ASSERT(!item->fixed || + select_limit->val_int() == LL(1) && offset_limit == 0); return; } if (explicit_limit) { str->append(" limit ", 7); - char buff[20]; - // latin1 is good enough for numbers - String st(buff, sizeof(buff), &my_charset_latin1); - st.set((ulonglong)select_limit, &my_charset_latin1); - str->append(st); if (offset_limit) { + offset_limit->print(str); str->append(','); - st.set((ulonglong)select_limit, &my_charset_latin1); - str->append(st); } + select_limit->print(str); } } @@ -1622,7 +1616,7 @@ bool st_lex::can_be_merged() select_lex.with_sum_func == 0 && select_lex.table_list.elements >= 1 && !(select_lex.options & SELECT_DISTINCT) && - select_lex.select_limit == HA_POS_ERROR); + select_lex.select_limit == 0); } @@ -1759,11 +1753,16 @@ bool st_lex::need_correct_ident() values - SELECT_LEX with initial values for counters */ -void st_select_lex_unit::set_limit(SELECT_LEX *values) +void st_select_lex_unit::set_limit(SELECT_LEX *sl) { - offset_limit_cnt= values->offset_limit; - select_limit_cnt= values->select_limit+values->offset_limit; - if (select_limit_cnt < values->select_limit) + ulonglong select_limit_val; + + DBUG_ASSERT(! thd->current_arena->is_stmt_prepare()); + select_limit_val= sl->select_limit ? sl->select_limit->val_uint() : + HA_POS_ERROR; + offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0); + select_limit_cnt= select_limit_val + offset_limit_cnt; + if (select_limit_cnt < select_limit_val) select_limit_cnt= HA_POS_ERROR; // no limit } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9dd37c65cde..86539dd8c5e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -114,6 +114,14 @@ enum enum_sp_data_access SP_MODIFIES_SQL_DATA }; +const LEX_STRING sp_data_access_name[]= +{ + { (char*) STRING_WITH_LEN("") }, + { (char*) STRING_WITH_LEN("CONTAINS SQL") }, + { (char*) STRING_WITH_LEN("NO SQL") }, + { (char*) STRING_WITH_LEN("READS SQL DATA") }, + { (char*) STRING_WITH_LEN("MODIFIES SQL DATA") } +}; #define DERIVED_SUBQUERY 1 #define DERIVED_VIEW 2 @@ -297,13 +305,13 @@ protected: public: uint32 options; - uint32 options2; /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT UNCACHEABLE_RAND UNCACHEABLE_SIDEEFFECT UNCACHEABLE_EXPLAIN + UNCACHEABLE_PREPARE */ uint8 uncacheable; enum sub_select_type linkage; @@ -489,7 +497,7 @@ public: List<List_item> expr_list; List<List_item> when_list; /* WHEN clause (expression) */ SQL_LIST *gorder_list; - ha_rows select_limit, offset_limit; /* LIMIT clause parameters */ + Item *select_limit, *offset_limit; /* LIMIT clause parameters */ // Arrays of pointers to top elements of all_fields list Item **ref_pointer_array; @@ -522,7 +530,19 @@ public: query processing end even if we use temporary table */ bool subquery_in_having; - bool first_execution; /* first execution in SP or PS */ + /* + This variable is required to ensure proper work of subqueries and + stored procedures. Generally, one should use the states of + Query_arena to determine if it's a statement prepare or first + execution of a stored procedure. However, in case when there was an + error during the first execution of a stored procedure, the SP body + is not expelled from the SP cache. Therefore, a deeply nested + subquery might be left unoptimized. So we need this per-subquery + variable to inidicate the optimization/execution state of every + subquery. Prepared statements work OK in that regard, as in + case of an error during prepare the PS is not created. + */ + bool first_execution; bool first_cond_optimization; /* do not wrap view fields with Item_ref */ bool no_wrap_view_item; @@ -751,7 +771,12 @@ typedef struct st_lex uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; uint slave_thd_opt, start_transaction_opt; - uint table_count; /* used when usual update transformed in multiupdate */ + /* + In LEX representing update which were transformed to multi-update + stores total number of tables. For LEX representing multi-delete + holds number of tables from which we will delete records. + */ + uint table_count; uint8 describe; uint8 derived_tables; uint8 create_view_algorithm; diff --git a/sql/sql_map.cc b/sql/sql_map.cc index 9346f3df305..56b4b765355 100644 --- a/sql/sql_map.cc +++ b/sql/sql_map.cc @@ -138,7 +138,7 @@ void unmap_file(mapped_files *map) ** Instansiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION /* Used templates */ template class I_List<mapped_files>; template class I_List_iterator<mapped_files>; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f4ecb9c9ceb..788d12cb898 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -72,7 +72,6 @@ static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); -static void log_slow_query(THD *thd); const char *any_db="*any*"; // Special symbol for check_access @@ -1512,10 +1511,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->command=command; /* - Commands which will always take a long time should be marked with - this so that they will not get logged to the slow query log + Commands which always take a long time are logged into + the slow log only if opt_log_slow_admin_statements is set. */ - thd->slow_command=FALSE; + thd->enable_slow_log= TRUE; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); VOID(pthread_mutex_lock(&LOCK_thread_count)); @@ -1555,7 +1554,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, uint tbl_len= *(uchar*) (packet + db_len + 1); statistic_increment(thd->status_var.com_other, &LOCK_status); - thd->slow_command= TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; db= thd->alloc(db_len + tbl_len + 2); tbl_name= strmake(db, packet + 1, db_len)+1; strmake(tbl_name, packet + db_len + 2, tbl_len); @@ -1639,32 +1638,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } break; } - case COM_EXECUTE: + case COM_STMT_EXECUTE: { mysql_stmt_execute(thd, packet, packet_length); break; } - case COM_FETCH: + case COM_STMT_FETCH: { mysql_stmt_fetch(thd, packet, packet_length); break; } - case COM_LONG_DATA: + case COM_STMT_SEND_LONG_DATA: { mysql_stmt_get_longdata(thd, packet, packet_length); break; } - case COM_PREPARE: + case COM_STMT_PREPARE: { mysql_stmt_prepare(thd, packet, packet_length, 0); break; } - case COM_CLOSE_STMT: + case COM_STMT_CLOSE: { - mysql_stmt_free(thd, packet); + mysql_stmt_close(thd, packet); break; } - case COM_RESET_STMT: + case COM_STMT_RESET: { mysql_stmt_reset(thd, packet); break; @@ -1693,7 +1692,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif ulong length= (ulong)(packet_end-packet); - log_slow_query(thd); + log_slow_statement(thd); /* Remove garbage at start of query */ while (my_isspace(thd->charset(), *packet) && length > 0) @@ -1862,7 +1861,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, uint32 slave_server_id; statistic_increment(thd->status_var.com_other,&LOCK_status); - thd->slow_command = TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; if (check_global_access(thd, REPL_SLAVE_ACL)) break; @@ -2047,7 +2046,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (thd->net.report_error) net_send_error(thd); - log_slow_query(thd); + log_slow_statement(thd); thd->proc_info="cleaning up"; VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list @@ -2063,13 +2062,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } -static void log_slow_query(THD *thd) +void log_slow_statement(THD *thd) { time_t start_of_query=thd->start_time; thd->end_time(); // Set start time - /* If not reading from backup and if the query took too long */ - if (!thd->slow_command && !thd->user_time) // do not log 'slow_command' queries + /* + Do not log administrative statements unless the appropriate option is + set; do not log into slow log if reading from backup. + */ + if (thd->enable_slow_log && !thd->user_time) { thd->proc_info="logging slow query"; @@ -2201,7 +2203,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, /* Read query from packet and store in thd->query - Used in COM_QUERY and COM_PREPARE + Used in COM_QUERY and COM_STMT_PREPARE DESCRIPTION Sets the following THD variables: @@ -2378,7 +2380,8 @@ mysql_execute_command(THD *thd) { SELECT_LEX *param= lex->unit.global_parameters; if (!param->explicit_limit) - param->select_limit= thd->variables.select_limit; + param->select_limit= + new Item_int((ulonglong)thd->variables.select_limit); } select_result *result=lex->result; @@ -2502,7 +2505,7 @@ mysql_execute_command(THD *thd) lex->prepared_stmt_name.str, query_len, query_str)); } - thd->command= COM_PREPARE; + thd->command= COM_STMT_PREPARE; if (!(res= mysql_stmt_prepare(thd, query_str, query_len + 1, &lex->prepared_stmt_name))) send_ok(thd, 0L, 0L, "Statement prepared"); @@ -2523,6 +2526,8 @@ mysql_execute_command(THD *thd) DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", lex->prepared_stmt_name.length, lex->prepared_stmt_name.str)); + /* We account deallocate in the same manner as mysql_stmt_close */ + statistic_increment(thd->status_var.com_stmt_close, &LOCK_status); if ((stmt= thd->stmt_map.find_by_name(&lex->prepared_stmt_name))) { thd->stmt_map.erase(stmt); @@ -2640,7 +2645,7 @@ mysql_execute_command(THD *thd) check_table_access(thd, SELECT_ACL, all_tables, 0) || check_global_access(thd, FILE_ACL)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_backup_table(thd, first_table); break; @@ -2652,7 +2657,7 @@ mysql_execute_command(THD *thd) check_table_access(thd, INSERT_ACL, all_tables, 0) || check_global_access(thd, FILE_ACL)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_restore_table(thd, first_table); break; } @@ -2767,6 +2772,20 @@ mysql_execute_command(THD *thd) case SQLCOM_CREATE_TABLE: { + /* If CREATE TABLE of non-temporary table, do implicit commit */ + if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) + { + if (end_active_trans(thd)) + { + res= -1; + break; + } + } + else + { + /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ + thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; + } DBUG_ASSERT(first_table == all_tables && first_table != 0); bool link_to_local; // Skip first table, which is the table we are creating @@ -2909,7 +2928,7 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; if (end_active_trans(thd)) goto error; else @@ -2998,7 +3017,7 @@ end_with_restore_list: goto error; else { - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_alter_table(thd, select_lex->db, lex->name, &lex->create_info, first_table, lex->create_list, @@ -3097,7 +3116,7 @@ end_with_restore_list: if (check_db_used(thd, all_tables) || check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_repair_table(thd, first_table, &lex->check_opt); /* ! we write after unlocking the table */ if (!res && !lex->no_write_to_binlog) @@ -3117,7 +3136,7 @@ end_with_restore_list: if (check_db_used(thd, all_tables) || check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_check_table(thd, first_table, &lex->check_opt); break; } @@ -3127,7 +3146,7 @@ end_with_restore_list: if (check_db_used(thd, all_tables) || check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_analyze_table(thd, first_table, &lex->check_opt); /* ! we write after unlocking the table */ if (!res && !lex->no_write_to_binlog) @@ -3148,7 +3167,7 @@ end_with_restore_list: if (check_db_used(thd, all_tables) || check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) goto error; /* purecov: inspected */ - thd->slow_command=TRUE; + thd->enable_slow_log= opt_log_slow_admin_statements; res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? mysql_recreate_table(thd, first_table, 1) : mysql_optimize_table(thd, first_table, &lex->check_opt); @@ -3168,13 +3187,15 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (update_precheck(thd, all_tables)) break; + DBUG_ASSERT(select_lex->offset_limit == 0); + unit->set_limit(select_lex); res= (result= mysql_update(thd, all_tables, select_lex->item_list, lex->value_list, select_lex->where, select_lex->order_list.elements, (ORDER *) select_lex->order_list.first, - select_lex->select_limit, + unit->select_limit_cnt, lex->duplicates, lex->ignore)); /* mysql_update return 2 if we need to switch to multi-update */ if (result != 2) @@ -3259,6 +3280,11 @@ end_with_restore_list: break; } case SQLCOM_TRUNCATE: + if (end_active_trans(thd)) + { + res= -1; + break; + } DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_one_table_access(thd, DELETE_ACL, all_tables)) goto error; @@ -3280,9 +3306,11 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= delete_precheck(thd, all_tables))) break; + DBUG_ASSERT(select_lex->offset_limit == 0); + unit->set_limit(select_lex); res = mysql_delete(thd, all_tables, select_lex->where, &select_lex->order_list, - select_lex->select_limit, select_lex->options); + unit->select_limit_cnt, select_lex->options); break; } case SQLCOM_DELETE_MULTI: @@ -3290,10 +3318,9 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; - uint table_count; multi_delete *result; - if ((res= multi_delete_precheck(thd, all_tables, &table_count))) + if ((res= multi_delete_precheck(thd, all_tables))) break; /* condition will be TRUE on SP re-excuting */ @@ -3310,7 +3337,7 @@ end_with_restore_list: goto error; if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, - table_count))) + lex->table_count))) { res= mysql_select(thd, &select_lex->ref_pointer_array, select_lex->get_table_list(), @@ -3351,6 +3378,9 @@ end_with_restore_list: */ if (thd->slave_thread) lex->drop_if_exists= 1; + + /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ + thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; } res= mysql_rm_table(thd, first_table, lex->drop_if_exists, lex->drop_temporary); @@ -3489,6 +3519,11 @@ end_with_restore_list: break; case SQLCOM_CREATE_DB: { + if (end_active_trans(thd)) + { + res= -1; + break; + } char *alias; if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) { @@ -3519,6 +3554,11 @@ end_with_restore_list: } case SQLCOM_DROP_DB: { + if (end_active_trans(thd)) + { + res= -1; + break; + } if (check_db_name(lex->name)) { my_error(ER_WRONG_DB_NAME, MYF(0), lex->name); @@ -3869,9 +3909,10 @@ end_with_restore_list: */ if (check_db_used(thd, all_tables)) goto error; + unit->set_limit(select_lex); res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str, lex->insert_list, lex->ha_rkey_mode, select_lex->where, - select_lex->select_limit, select_lex->offset_limit); + unit->select_limit_cnt, unit->offset_limit_cnt); break; case SQLCOM_BEGIN: @@ -5153,7 +5194,6 @@ mysql_init_select(LEX *lex) { SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); - select_lex->select_limit= HA_POS_ERROR; lex->orig_sql_command= SQLCOM_END; lex->wild= 0; if (select_lex == &lex->select_lex) @@ -5168,25 +5208,28 @@ bool mysql_new_select(LEX *lex, bool move_down) { SELECT_LEX *select_lex; + THD *thd= lex->thd; DBUG_ENTER("mysql_new_select"); - if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX())) + if (!(select_lex= new (thd->mem_root) SELECT_LEX())) DBUG_RETURN(1); - select_lex->select_number= ++lex->thd->select_number; + select_lex->select_number= ++thd->select_number; select_lex->init_query(); select_lex->init_select(); select_lex->parent_lex= lex; + if (thd->current_arena->is_stmt_prepare()) + select_lex->uncacheable|= UNCACHEABLE_PREPARE; if (move_down) { SELECT_LEX_UNIT *unit; lex->subqueries= TRUE; /* first select_lex of subselect or derived table */ - if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT())) + if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) DBUG_RETURN(1); unit->init_query(); unit->init_select(); - unit->thd= lex->thd; + unit->thd= thd; unit->include_down(lex->current_select); unit->link_next= 0; unit->link_prev= 0; @@ -5210,14 +5253,14 @@ mysql_new_select(LEX *lex, bool move_down) as far as we included SELECT_LEX for UNION unit should have fake SELECT_LEX for UNION processing */ - if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX())) + if (!(fake= unit->fake_select_lex= new (thd->mem_root) SELECT_LEX())) DBUG_RETURN(1); fake->include_standalone(unit, (SELECT_LEX_NODE**)&unit->fake_select_lex); fake->select_number= INT_MAX; fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; - fake->select_limit= HA_POS_ERROR; + fake->select_limit= 0; } } @@ -5265,8 +5308,8 @@ void mysql_init_multi_delete(LEX *lex) { lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); - lex->select_lex.select_limit= lex->unit.select_limit_cnt= - HA_POS_ERROR; + lex->select_lex.select_limit= 0; + lex->unit.select_limit_cnt= HA_POS_ERROR; lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list); lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ; lex->query_tables= 0; @@ -6780,8 +6823,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) if (select_lex->order_list.elements) msg= "ORDER BY"; - else if (select_lex->select_limit && select_lex->select_limit != - HA_POS_ERROR) + else if (select_lex->select_limit) msg= "LIMIT"; if (msg) { @@ -6798,23 +6840,19 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) multi_delete_precheck() thd Thread handler tables Global/local table list - table_count Pointer to table counter RETURN VALUE FALSE OK TRUE error */ -bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) +bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) { SELECT_LEX *select_lex= &thd->lex->select_lex; TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first; - TABLE_LIST *target_tbl; DBUG_ENTER("multi_delete_precheck"); - *table_count= 0; - /* sql_yacc guarantees that tables and aux_tables are not zero */ DBUG_ASSERT(aux_tables != 0); if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) || @@ -6827,9 +6865,35 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); DBUG_RETURN(TRUE); } - for (target_tbl= aux_tables; target_tbl; target_tbl= target_tbl->next_local) + DBUG_RETURN(FALSE); +} + + +/* + Link tables in auxilary table list of multi-delete with corresponding + elements in main table list, and set proper locks for them. + + SYNOPSIS + multi_delete_set_locks_and_link_aux_tables() + lex - pointer to LEX representing multi-delete + + RETURN VALUE + FALSE - success + TRUE - error +*/ + +bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) +{ + TABLE_LIST *tables= (TABLE_LIST*)lex->select_lex.table_list.first; + TABLE_LIST *target_tbl; + DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables"); + + lex->table_count= 0; + + for (target_tbl= (TABLE_LIST *)lex->auxilliary_table_list.first; + target_tbl; target_tbl= target_tbl->next_local) { - (*table_count)++; + lex->table_count++; /* All tables in aux_tables must be found in FROM PART */ TABLE_LIST *walk; for (walk= tables; walk; walk= walk->next_local) @@ -6847,14 +6911,6 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) } walk->lock_type= target_tbl->lock_type; target_tbl->correspondent_table= walk; // Remember corresponding table - - /* in case of subselects, we need to set lock_type in - * corresponding table in list of all tables */ - if (walk->correspondent_table) - { - target_tbl->correspondent_table= walk->correspondent_table; - walk->correspondent_table->lock_type= walk->lock_type; - } } DBUG_RETURN(FALSE); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 1521b206e0d..eeea493d868 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -15,18 +15,18 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /********************************************************************** -This file contains the implementation of prepare and executes. +This file contains the implementation of prepare and executes. Prepare: - - Server gets the query from client with command 'COM_PREPARE'; + - Server gets the query from client with command 'COM_STMT_PREPARE'; in the following format: - [COM_PREPARE:1] [query] - - Parse the query and recognize any parameter markers '?' and + [COM_STMT_PREPARE:1] [query] + - Parse the query and recognize any parameter markers '?' and store its information list in lex->param_list - - Allocate a new statement for this prepare; and keep this in + - Allocate a new statement for this prepare; and keep this in 'thd->prepared_statements' pool. - - Without executing the query, return back to client the total + - Without executing the query, return back to client the total number of parameters along with result-set metadata information (if any) in the following format: [STMT_ID:4] @@ -34,35 +34,36 @@ Prepare: [Param_count:2] [Columns meta info] (if Column_count > 0) [Params meta info] (if Param_count > 0 ) (TODO : 4.1.1) - + Prepare-execute: - - Server gets the command 'COM_EXECUTE' to execute the + - Server gets the command 'COM_STMT_EXECUTE' to execute the previously prepared query. If there is any param markers; then client will send the data in the following format: - [COM_EXECUTE:1] + [COM_STMT_EXECUTE:1] [STMT_ID:4] [NULL_BITS:(param_count+7)/8)] [TYPES_SUPPLIED_BY_CLIENT(0/1):1] [[length]data] - [[length]data] .. [[length]data]. - (Note: Except for string/binary types; all other types will not be + [[length]data] .. [[length]data]. + (Note: Except for string/binary types; all other types will not be supplied with length field) - - Replace the param items with this new data. If it is a first execute + - Replace the param items with this new data. If it is a first execute or types altered by client; then setup the conversion routines. - - Execute the query without re-parsing and send back the results + - Execute the query without re-parsing and send back the results to client Long data handling: - - Server gets the long data in pieces with command type 'COM_LONG_DATA'. + - Server gets the long data in pieces with command type + 'COM_STMT_SEND_LONG_DATA'. - The packet recieved will have the format as: - [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][data] + [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data] - data from the packet is appended to long data value buffer for this placeholder. - It's up to the client to check for read data ended. The server doesn't - care; and also server doesn't notify to the client that it got the - data or not; if there is any error; then during execute; the error + care; and also server doesn't notify to the client that it got the + data or not; if there is any error; then during execute; the error will be returned ***********************************************************************/ @@ -97,14 +98,14 @@ public: #else bool (*set_params_data)(Prepared_statement *st, String *expanded_query); #endif - bool (*set_params_from_vars)(Prepared_statement *stmt, + bool (*set_params_from_vars)(Prepared_statement *stmt, List<LEX_STRING>& varnames, String *expanded_query); public: Prepared_statement(THD *thd_arg); virtual ~Prepared_statement(); void setup_set_params(); - virtual Item_arena::Type type() const; + virtual Query_arena::Type type() const; }; static void execute_stmt(THD *thd, Prepared_statement *stmt, @@ -132,7 +133,7 @@ find_prepared_statement(THD *thd, ulong id, const char *where) { Statement *stmt= thd->stmt_map.find(id); - if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT) + if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT) { char llbuf[22]; my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf), @@ -167,7 +168,7 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) Send types and names of placeholders to the client XXX: fix this nasty upcast from List<Item_param> to List<Item> */ - DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || + DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || (stmt->param_count && stmt->thd->protocol_simple.send_fields((List<Item> *) &stmt->lex->param_list, @@ -220,7 +221,7 @@ static ulong get_param_length(uchar **packet, ulong len) } if (len < 5) return 0; - (*packet)+=9; // Must be 254 when here + (*packet)+=9; // Must be 254 when here /* In our client-server protocol all numbers bigger than 2^24 stored as 8 bytes with uint8korr. Here we always know that @@ -242,7 +243,7 @@ static ulong get_param_length(uchar **packet, ulong len) pos input data buffer len length of data in the buffer - All these functions read the data from pos, convert it to requested type + All these functions read the data from pos, convert it to requested type and assign to param; pos is advanced to predefined length. Make a note that the NULL handling is examined at first execution @@ -260,7 +261,7 @@ static void set_param_tiny(Item_param *param, uchar **pos, ulong len) return; #endif int8 value= (int8) **pos; - param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) : + param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) : (longlong) value, 4); *pos+= 1; } @@ -480,7 +481,7 @@ static void set_param_str(Item_param *param, uchar **pos, ulong len) } -#undef get_param_length +#undef get_param_length static void setup_one_conversion_function(THD *thd, Item_param *param, uchar param_type) @@ -583,12 +584,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, #ifndef EMBEDDED_LIBRARY /* - Update the parameter markers by reading data from client packet + Update the parameter markers by reading data from client packet and if binary/update log is set, generate the valid query. */ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, - uchar *read_pos, uchar *data_end, + uchar *read_pos, uchar *data_end, String *query) { THD *thd= stmt->thd; @@ -596,14 +597,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, Item_param **end= begin + stmt->param_count; uint32 length= 0; - String str; + String str; const String *res; - DBUG_ENTER("insert_params_withlog"); + DBUG_ENTER("insert_params_withlog"); if (query->copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); - + for (Item_param **it= begin; it < end; ++it) { Item_param *param= *it; @@ -624,7 +625,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, if (query->replace(param->pos_in_query+length, 1, *res)) DBUG_RETURN(1); - + length+= res->length()-1; } DBUG_RETURN(0); @@ -632,13 +633,13 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, static bool insert_params(Prepared_statement *stmt, uchar *null_array, - uchar *read_pos, uchar *data_end, + uchar *read_pos, uchar *data_end, String *expanded_query) { Item_param **begin= stmt->param_array; Item_param **end= begin + stmt->param_count; - DBUG_ENTER("insert_params"); + DBUG_ENTER("insert_params"); for (Item_param **it= begin; it < end; ++it) { @@ -672,7 +673,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt, if (*read_pos++) //types supplied / first execute { /* - First execute or types altered by the client, setup the + First execute or types altered by the client, setup the conversion routines for all parameters (one time) */ Item_param **it= stmt->param_array; @@ -720,8 +721,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query) uchar *buff= (uchar*) client_param->buffer; param->unsigned_flag= client_param->is_unsigned; param->set_param_func(param, &buff, - client_param->length ? - *client_param->length : + client_param->length ? + *client_param->length : client_param->buffer_length); } } @@ -747,7 +748,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) if (query->copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); - + for (; it < end; ++it, ++client_param) { Item_param *param= *it; @@ -759,10 +760,10 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query) else { uchar *buff= (uchar*)client_param->buffer; - param->unsigned_flag= client_param->is_unsigned; + param->unsigned_flag= client_param->is_unsigned; param->set_param_func(param, &buff, - client_param->length ? - *client_param->length : + client_param->length ? + *client_param->length : client_param->buffer_length); } } @@ -839,7 +840,8 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, DBUG_ENTER("insert_params_from_vars"); List_iterator<LEX_STRING> var_it(varnames); - String str; + String buf; + const String *val; uint32 length= 0; if (query->copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); @@ -850,52 +852,56 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, varname= var_it++; if (get_var_with_binlog(stmt->thd, *varname, &entry)) DBUG_RETURN(1); - DBUG_ASSERT(entry != 0); if (param->set_from_user_var(stmt->thd, entry)) DBUG_RETURN(1); /* Insert @'escaped-varname' instead of parameter in the query */ - char *buf, *ptr; - str.length(0); - if (str.reserve(entry->name.length*2+3)) - DBUG_RETURN(1); + if (entry) + { + char *begin, *ptr; + buf.length(0); + if (buf.reserve(entry->name.length*2+3)) + DBUG_RETURN(1); - buf= str.c_ptr_quick(); - ptr= buf; - *ptr++= '@'; - *ptr++= '\''; - ptr+= - escape_string_for_mysql(&my_charset_utf8_general_ci, - ptr, 0, entry->name.str, entry->name.length); - *ptr++= '\''; - str.length(ptr - buf); + begin= ptr= buf.c_ptr_quick(); + *ptr++= '@'; + *ptr++= '\''; + ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci, + ptr, 0, entry->name.str, + entry->name.length); + *ptr++= '\''; + buf.length(ptr - begin); + val= &buf; + } + else + val= &my_null_string; if (param->convert_str_value(stmt->thd)) DBUG_RETURN(1); /* out of memory */ - if (query->replace(param->pos_in_query+length, 1, str)) + if (query->replace(param->pos_in_query+length, 1, *val)) DBUG_RETURN(1); - length+= str.length()-1; + length+= val->length()-1; } DBUG_RETURN(0); } /* - Validate INSERT statement: + Validate INSERT statement: SYNOPSIS mysql_test_insert() - stmt prepared statemen handler - tables global/local table list + stmt prepared statemen handler + tables global/local table list RETURN VALUE - FALSE OK - TRUE error + FALSE success + TRUE error, error message is set in THD */ static bool mysql_test_insert(Prepared_statement *stmt, TABLE_LIST *table_list, - List<Item> &fields, + List<Item> &fields, List<List_item> &values_list, List<Item> &update_fields, List<Item> &update_values, @@ -905,11 +911,10 @@ static bool mysql_test_insert(Prepared_statement *stmt, LEX *lex= stmt->lex; List_iterator_fast<List_item> its(values_list); List_item *values; - bool res; DBUG_ENTER("mysql_test_insert"); - if ((res= insert_precheck(thd, table_list))) - DBUG_RETURN(res); + if (insert_precheck(thd, table_list)) + goto error; /* open temporary memory pool for temporary data allocated by derived @@ -920,10 +925,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, TL_WRITE_DELAYED as having two such locks can cause table corruption. */ if (open_normal_and_derived_tables(thd, table_list)) - { - DBUG_RETURN(TRUE); - } - + goto error; if ((values= its++)) { @@ -937,17 +939,14 @@ static bool mysql_test_insert(Prepared_statement *stmt, table_list->table->insert_values=(byte *)1; } - if ((res= mysql_prepare_insert(thd, table_list, table_list->table, - fields, values, update_fields, - update_values, duplic, - &unused_conds, FALSE))) + if (mysql_prepare_insert(thd, table_list, table_list->table, fields, + values, update_fields, update_values, duplic, + &unused_conds, FALSE)) goto error; value_count= values->elements; its.rewind(); - res= TRUE; - if (table_list->lock_type == TL_WRITE_DELAYED && !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED)) { @@ -965,15 +964,14 @@ static bool mysql_test_insert(Prepared_statement *stmt, goto error; } if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) - goto error; + goto error; } } + DBUG_RETURN(FALSE); - res= FALSE; error: - lex->unit.cleanup(); /* insert_values is cleared in open_table */ - DBUG_RETURN(res); + DBUG_RETURN(TRUE); } @@ -982,14 +980,15 @@ error: SYNOPSIS mysql_test_update() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE 0 success + 1 error, error message is set in THD 2 convert to multi_update - 1 error */ + static int mysql_test_update(Prepared_statement *stmt, TABLE_LIST *table_list) { @@ -998,74 +997,65 @@ static int mysql_test_update(Prepared_statement *stmt, uint table_count= 0; SELECT_LEX *select= &stmt->lex->select_lex; #ifndef NO_EMBEDDED_ACCESS_CHECKS - uint want_privilege; + uint want_privilege; #endif DBUG_ENTER("mysql_test_update"); if (update_precheck(thd, table_list)) - DBUG_RETURN(1); + goto error; - if (!open_tables(thd, &table_list, &table_count)) + if (open_tables(thd, &table_list, &table_count)) + goto error; + + if (table_list->multitable_view) { - if (table_list->multitable_view) - { - DBUG_ASSERT(table_list->view != 0); - DBUG_PRINT("info", ("Switch to multi-update")); - /* pass counter value */ - thd->lex->table_count= table_count; - /* convert to multiupdate */ - return 2; - } + DBUG_ASSERT(table_list->view != 0); + DBUG_PRINT("info", ("Switch to multi-update")); + /* pass counter value */ + thd->lex->table_count= table_count; + /* convert to multiupdate */ + DBUG_RETURN(2); + } - /* - thd->fill_derived_tables() is false here for sure (because it is - preparation of PS, so we even do not check it - */ - if (lock_tables(thd, table_list, table_count) || - mysql_handle_derived(thd->lex, &mysql_derived_prepare)) - DBUG_RETURN(1); + /* + thd->fill_derived_tables() is false here for sure (because it is + preparation of PS, so we even do not check it). + */ + if (lock_tables(thd, table_list, table_count) || + mysql_handle_derived(thd->lex, &mysql_derived_prepare)) + goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* TABLE_LIST contain right privilages request */ want_privilege= table_list->grant.want_privilege; #endif - if (!(res= mysql_prepare_update(thd, table_list, - &select->where, - select->order_list.elements, - (ORDER *) select->order_list.first))) - { + if (mysql_prepare_update(thd, table_list, &select->where, + select->order_list.elements, + (ORDER *) select->order_list.first)) + goto error; + #ifndef NO_EMBEDDED_ACCESS_CHECKS - table_list->grant.want_privilege= - table_list->table->grant.want_privilege= - want_privilege; + table_list->grant.want_privilege= want_privilege; + table_list->table->grant.want_privilege= want_privilege; #endif - thd->lex->select_lex.no_wrap_view_item= 1; - if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0)) - { - res= 1; - thd->lex->select_lex.no_wrap_view_item= 0; - } - else - { - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= 1; + res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0); + thd->lex->select_lex.no_wrap_view_item= 0; + if (res) + goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS - /* Check values */ - table_list->grant.want_privilege= - table_list->table->grant.want_privilege= - (SELECT_ACL & ~table_list->table->grant.privilege); + /* Check values */ + table_list->grant.want_privilege= + table_list->table->grant.want_privilege= + (SELECT_ACL & ~table_list->table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, - stmt->lex->value_list, 0, 0, 0)) - res= 1; - } - } - stmt->lex->unit.cleanup(); - } - else - res= 1; - /* TODO: here we should send types of placeholders to the client. */ - DBUG_RETURN(res); + if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0)) + goto error; + /* TODO: here we should send types of placeholders to the client. */ + DBUG_RETURN(0); +error: + DBUG_RETURN(1); } @@ -1074,38 +1064,34 @@ static int mysql_test_update(Prepared_statement *stmt, SYNOPSIS mysql_test_delete() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE FALSE success - TRUE error + TRUE error, error message is set in THD */ -static int mysql_test_delete(Prepared_statement *stmt, - TABLE_LIST *table_list) + +static bool mysql_test_delete(Prepared_statement *stmt, + TABLE_LIST *table_list) { THD *thd= stmt->thd; LEX *lex= stmt->lex; DBUG_ENTER("mysql_test_delete"); - if (delete_precheck(thd, table_list)) - DBUG_RETURN(TRUE); + if (delete_precheck(thd, table_list) || + open_and_lock_tables(thd, table_list)) + goto error; - if (!open_and_lock_tables(thd, table_list)) + if (!table_list->table) { - bool res; - if (!table_list->table) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); - DBUG_RETURN(-1); - } - - res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where); - lex->unit.cleanup(); - DBUG_RETURN(res); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + goto error; } - /* TODO: here we should send types of placeholders to the client. */ + + DBUG_RETURN(mysql_prepare_delete(thd, table_list, &lex->select_lex.where)); +error: DBUG_RETURN(TRUE); } @@ -1113,25 +1099,24 @@ static int mysql_test_delete(Prepared_statement *stmt, /* Validate SELECT statement. In case of success, if this query is not EXPLAIN, send column list info - back to client. + back to client. SYNOPSIS mysql_test_select() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE FALSE success TRUE error, sent to client */ -static int mysql_test_select(Prepared_statement *stmt, - TABLE_LIST *tables, bool text_protocol) +static bool mysql_test_select(Prepared_statement *stmt, + TABLE_LIST *tables, bool text_protocol) { THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX_UNIT *unit= &lex->unit; - bool result; DBUG_ENTER("mysql_test_select"); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1139,19 +1124,20 @@ static int mysql_test_select(Prepared_statement *stmt, if (tables) { if (check_table_access(thd, privilege, tables,0)) - DBUG_RETURN(TRUE); + goto error; } else if (check_access(thd, privilege, any_db,0,0,0)) - DBUG_RETURN(TRUE); + goto error; #endif - result= TRUE; if (!lex->result && !(lex->result= new (stmt->mem_root) select_send)) - goto err; + { + my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send)); + goto error; + } if (open_and_lock_tables(thd, tables)) - goto err; - + goto error; thd->used_tables= 0; // Updated by setup_fields @@ -1161,15 +1147,13 @@ static int mysql_test_select(Prepared_statement *stmt, usual, and we pass 0 as setup_tables_done_option */ if (unit->prepare(thd, 0, 0, "")) - { - goto err_prep; - } + goto error; if (!text_protocol) { if (lex->describe) { if (send_prep_stmt(stmt, 0) || thd->protocol->flush()) - goto err_prep; + goto error; } else { @@ -1179,7 +1163,7 @@ static int mysql_test_select(Prepared_statement *stmt, /* Change columns if a procedure like analyse() */ if (unit->last_procedure && unit->last_procedure->change_columns(fields)) - goto err_prep; + goto error; /* We can use lex->result as it should've been @@ -1188,15 +1172,12 @@ static int mysql_test_select(Prepared_statement *stmt, if (send_prep_stmt(stmt, lex->result->field_count(fields)) || lex->result->send_fields(fields, Protocol::SEND_EOF) || thd->protocol->flush()) - goto err_prep; + goto error; } } - result= FALSE; // ok - -err_prep: - unit->cleanup(); -err: - DBUG_RETURN(result); + DBUG_RETURN(FALSE); +error: + DBUG_RETURN(TRUE); } @@ -1205,32 +1186,28 @@ err: SYNOPSIS mysql_test_do_fields() - stmt prepared statemen handler - tables list of tables queries - values list of expressions + stmt prepared statemen handler + tables list of tables queries + values list of expressions RETURN VALUE FALSE success - TRUE error, sent to client + TRUE error, error message is set in THD */ static bool mysql_test_do_fields(Prepared_statement *stmt, - TABLE_LIST *tables, - List<Item> *values) + TABLE_LIST *tables, + List<Item> *values) { - DBUG_ENTER("mysql_test_do_fields"); THD *thd= stmt->thd; - bool res; + + DBUG_ENTER("mysql_test_do_fields"); if (tables && check_table_access(thd, SELECT_ACL, tables, 0)) DBUG_RETURN(TRUE); if (open_and_lock_tables(thd, tables)) - { DBUG_RETURN(TRUE); - } - res= setup_fields(thd, 0, 0, *values, 0, 0, 0); - stmt->lex->unit.cleanup(); - DBUG_RETURN(res); + DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0)); } @@ -1239,14 +1216,15 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, SYNOPSIS mysql_test_set_fields() - stmt prepared statemen handler - tables list of tables queries - values list of expressions + stmt prepared statemen handler + tables list of tables queries + values list of expressions RETURN VALUE FALSE success TRUE error */ + static bool mysql_test_set_fields(Prepared_statement *stmt, TABLE_LIST *tables, List<set_var_base> *var_list) @@ -1255,25 +1233,19 @@ static bool mysql_test_set_fields(Prepared_statement *stmt, List_iterator_fast<set_var_base> it(*var_list); THD *thd= stmt->thd; set_var_base *var; - bool res; - - if (tables && check_table_access(thd, SELECT_ACL, tables, 0)) - DBUG_RETURN(TRUE); - if ((res= open_and_lock_tables(thd, tables))) + if (tables && check_table_access(thd, SELECT_ACL, tables, 0) || + open_and_lock_tables(thd, tables)) goto error; + while ((var= it++)) { if (var->light_check(thd)) - { - stmt->lex->unit.cleanup(); - res= TRUE; goto error; - } } + DBUG_RETURN(FALSE); error: - stmt->lex->unit.cleanup(); - DBUG_RETURN(res); + DBUG_RETURN(TRUE); } @@ -1294,7 +1266,7 @@ error: RETURN VALUE FALSE success - TRUE error + TRUE error, error message is set in THD */ static bool select_like_stmt_test(Prepared_statement *stmt, @@ -1304,24 +1276,16 @@ static bool select_like_stmt_test(Prepared_statement *stmt, DBUG_ENTER("select_like_stmt_test"); THD *thd= stmt->thd; LEX *lex= stmt->lex; - bool res= FALSE; - if (specific_prepare && (res= (*specific_prepare)(thd))) - goto end; + if (specific_prepare && (*specific_prepare)(thd)) + DBUG_RETURN(TRUE); thd->used_tables= 0; // Updated by setup_fields - // JOIN::prepare calls - if (lex->unit.prepare(thd, 0, setup_tables_done_option, "")) - { - res= TRUE; - } -end: - lex->unit.cleanup(); - DBUG_RETURN(res); + /* Calls JOIN::prepare */ + DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option, "")); } - /* Check internal SELECT of the prepared command (with opening and locking tables used). @@ -1365,29 +1329,30 @@ select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt, SYNOPSIS mysql_test_create_table() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE - 0 success - 1 error, sent to client - -1 error, not sent to client + FALSE success + TRUE error, error message is set in THD */ -static int mysql_test_create_table(Prepared_statement *stmt) +static bool mysql_test_create_table(Prepared_statement *stmt) { DBUG_ENTER("mysql_test_create_table"); THD *thd= stmt->thd; LEX *lex= stmt->lex; SELECT_LEX *select_lex= &lex->select_lex; - int res= 0; + bool res= FALSE; /* Skip first table, which is the table we are creating */ bool link_to_local; TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local); TABLE_LIST *tables= lex->query_tables; - if (!(res= create_table_precheck(thd, tables, create_table)) && - select_lex->item_list.elements) + if (create_table_precheck(thd, tables, create_table)) + DBUG_RETURN(TRUE); + + if (select_lex->item_list.elements) { select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0); @@ -1405,8 +1370,8 @@ static int mysql_test_create_table(Prepared_statement *stmt) SYNOPSIS mysql_test_multiupdate() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries converted converted to multi-update from usual update RETURN VALUE @@ -1415,7 +1380,7 @@ static int mysql_test_create_table(Prepared_statement *stmt) */ static bool mysql_test_multiupdate(Prepared_statement *stmt, - TABLE_LIST *tables, + TABLE_LIST *tables, bool converted) { /* if we switched from normal update, rights are checked */ @@ -1432,37 +1397,38 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt, SYNOPSIS mysql_test_multidelete() - stmt prepared statemen handler - tables list of tables queries + stmt prepared statemen handler + tables list of tables queries RETURN VALUE 0 success - 1 error, sent to client - -1 error, not sent to client + 1 error, error message in THD is set. */ -static int mysql_test_multidelete(Prepared_statement *stmt, - TABLE_LIST *tables) + +static bool mysql_test_multidelete(Prepared_statement *stmt, + TABLE_LIST *tables) { - int res; stmt->thd->lex->current_select= &stmt->thd->lex->select_lex; if (add_item_to_list(stmt->thd, new Item_null())) - return -1; - - uint fake_counter; - if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) - return res; - if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables, - &mysql_multi_delete_prepare, - OPTION_SETUP_TABLES_DONE))) - return res; + { + my_error(ER_OUTOFMEMORY, MYF(0), 0); + goto error; + } + + if (multi_delete_precheck(stmt->thd, tables) || + select_like_stmt_test_with_open_n_lock(stmt, tables, + &mysql_multi_delete_prepare, + OPTION_SETUP_TABLES_DONE)) + goto error; if (!tables->table) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - tables->view_db.str, tables->view_name.str); - return -1; + tables->view_db.str, tables->view_name.str); + goto error; } - return 0; - + return FALSE; +error: + return TRUE; } @@ -1498,8 +1464,8 @@ static bool mysql_insert_select_prepare_tester(THD *thd) SYNOPSIS mysql_test_insert_select() - stmt prepared statemen handler - tables list of tables of query + stmt prepared statemen handler + tables list of tables of query RETURN VALUE 0 success @@ -1508,7 +1474,7 @@ static bool mysql_insert_select_prepare_tester(THD *thd) */ static int mysql_test_insert_select(Prepared_statement *stmt, - TABLE_LIST *tables) + TABLE_LIST *tables) { int res; LEX *lex= stmt->lex; @@ -1520,8 +1486,8 @@ static int mysql_test_insert_select(Prepared_statement *stmt, tables->table->insert_values=(byte *)1; } - if ((res= insert_precheck(stmt->thd, tables))) - return res; + if (insert_precheck(stmt->thd, tables)) + return 1; /* store it, because mysql_insert_select_prepare_tester change it */ first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first; @@ -1552,12 +1518,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt, by calling fix_fields. RETURN VALUE - 0 success - 1 error, sent to client + FALSE success, statement metadata is sent to client + TRUE error, error message is set (but not sent) */ -static int check_prepared_statement(Prepared_statement *stmt, - bool text_protocol) +static bool check_prepared_statement(Prepared_statement *stmt, + bool text_protocol) { THD *thd= stmt->thd; LEX *lex= stmt->lex; @@ -1576,14 +1542,14 @@ static int check_prepared_statement(Prepared_statement *stmt, case SQLCOM_REPLACE: case SQLCOM_INSERT: res= mysql_test_insert(stmt, tables, lex->field_list, - lex->many_values, - select_lex->item_list, lex->value_list, - lex->duplicates); + lex->many_values, + select_lex->item_list, lex->value_list, + lex->duplicates); break; case SQLCOM_UPDATE: res= mysql_test_update(stmt, tables); - /* mysql_test_update return 2 if we need to switch to multi-update */ + /* mysql_test_update returns 2 if we need to switch to multi-update */ if (res != 2) break; @@ -1599,12 +1565,12 @@ static int check_prepared_statement(Prepared_statement *stmt, if ((res= mysql_test_select(stmt, tables, text_protocol))) goto error; /* Statement and field info has already been sent */ - DBUG_RETURN(0); + DBUG_RETURN(FALSE); case SQLCOM_CREATE_TABLE: res= mysql_test_create_table(stmt); break; - + case SQLCOM_DO: res= mysql_test_do_fields(stmt, tables, lex->insert_list); break; @@ -1650,18 +1616,15 @@ static int check_prepared_statement(Prepared_statement *stmt, break; default: - /* - All other is not supported yet - */ - res= -1; + /* All other statements are not supported yet. */ my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0)); goto error; } if (res == 0) - DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) || - thd->protocol->flush())); + DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) || + thd->protocol->flush())); error: - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } /* @@ -1699,45 +1662,64 @@ static bool init_param_array(Prepared_statement *stmt) return FALSE; } + +/* Cleanup PS after execute/prepare and restore THD state */ + +static void cleanup_stmt_and_thd_after_use(Statement *stmt, THD *thd) +{ + stmt->lex->unit.cleanup(); + cleanup_items(stmt->free_list); + thd->rollback_item_tree_changes(); + thd->cleanup_after_query(); +} + /* Given a query string with parameter markers, create a Prepared Statement from it and send PS info back to the client. - + SYNOPSIS mysql_stmt_prepare() - packet query to be prepared - packet_length query string length, including ignored trailing NULL or + packet query to be prepared + packet_length query string length, including ignored trailing NULL or quote char. name NULL or statement name. For unnamed statements binary PS - protocol is used, for named statements text protocol is + protocol is used, for named statements text protocol is used. RETURN FALSE OK, statement prepared successfully TRUE Error NOTES - This function parses the query and sends the total number of parameters - and resultset metadata information back to client (if any), without - executing the query i.e. without any log/disk writes. This allows the - queries to be re-executed without re-parsing during execute. + This function parses the query and sends the total number of parameters + and resultset metadata information back to client (if any), without + executing the query i.e. without any log/disk writes. This allows the + queries to be re-executed without re-parsing during execute. If parameter markers are found in the query, then store the information - using Item_param along with maintaining a list in lex->param_array, so - that a fast and direct retrieval can be made without going through all + using Item_param along with maintaining a list in lex->param_array, so + that a fast and direct retrieval can be made without going through all field items. - + */ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, LEX_STRING *name) { LEX *lex; + Statement stmt_backup; Prepared_statement *stmt= new Prepared_statement(thd); bool error; DBUG_ENTER("mysql_stmt_prepare"); DBUG_PRINT("prep_query", ("%s", packet)); + /* + If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql. + However, it seems handy if com_stmt_prepare is increased always, + no matter what kind of prepare is processed. + */ + statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status); + if (stmt == 0) DBUG_RETURN(TRUE); @@ -1758,19 +1740,19 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, DBUG_RETURN(TRUE); } - thd->set_n_backup_statement(stmt, &thd->stmt_backup); - thd->set_n_backup_item_arena(stmt, &thd->stmt_backup); + thd->set_n_backup_statement(stmt, &stmt_backup); + thd->set_n_backup_item_arena(stmt, &stmt_backup); if (alloc_query(thd, packet, packet_length)) { - thd->restore_backup_statement(stmt, &thd->stmt_backup); - thd->restore_backup_item_arena(stmt, &thd->stmt_backup); + thd->restore_backup_statement(stmt, &stmt_backup); + thd->restore_backup_item_arena(stmt, &stmt_backup); /* Statement map deletes statement on erase */ thd->stmt_map.erase(stmt); DBUG_RETURN(TRUE); } - mysql_log.write(thd, COM_PREPARE, "[%lu] %s", stmt->id, packet); + mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, packet); thd->current_arena= stmt; mysql_init_query(thd, (uchar *) thd->query, thd->query_length); @@ -1789,7 +1771,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, transformation can be reused on execute, we set again thd->mem_root from stmt->mem_root (see setup_wild for one place where we do that). */ - thd->restore_backup_item_arena(stmt, &thd->stmt_backup); + thd->restore_backup_item_arena(stmt, &stmt_backup); if (!error) error= check_prepared_statement(stmt, test(name)); @@ -1804,10 +1786,8 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, } lex_end(lex); close_thread_tables(thd); - thd->restore_backup_statement(stmt, &thd->stmt_backup); - cleanup_items(stmt->free_list); - thd->rollback_item_tree_changes(); - thd->cleanup_after_query(); + cleanup_stmt_and_thd_after_use(stmt, thd); + thd->restore_backup_statement(stmt, &stmt_backup); thd->current_arena= thd; if (error) @@ -1820,7 +1800,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, { stmt->setup_set_params(); init_stmt_after_parse(thd, stmt->lex); - stmt->state= Item_arena::PREPARED; + stmt->state= Query_arena::PREPARED; } DBUG_RETURN(!stmt); } @@ -1838,7 +1818,10 @@ void init_stmt_after_parse(THD *thd, LEX *lex) optimisation. */ for (; sl; sl= sl->next_select_in_list()) + { sl->prep_where= sl->where; + sl->uncacheable&= ~UNCACHEABLE_PREPARE; + } for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global) table->prep_on_expr= table->on_expr; @@ -1847,10 +1830,10 @@ void init_stmt_after_parse(THD *thd, LEX *lex) /* Reinit prepared statement/stored procedure before execution */ -void reset_stmt_for_execute(THD *thd, LEX *lex) +void reinit_stmt_before_use(THD *thd, LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; - DBUG_ENTER("reset_stmt_for_execute"); + DBUG_ENTER("reinit_stmt_before_use"); if (lex->empty_field_list_on_rset) { @@ -1894,8 +1877,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) } /* - TODO: When the new table structure is ready, then have a status bit - to indicate the table is altered, and re-do the setup_* + TODO: When the new table structure is ready, then have a status bit + to indicate the table is altered, and re-do the setup_* and open the tables back. */ /* @@ -1904,8 +1887,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) they have their own table list). */ for (TABLE_LIST *tables= lex->query_tables; - tables; - tables= tables->next_global) + tables; + tables= tables->next_global) { /* Reset old pointers to TABLEs: they are not valid since the tables @@ -1936,10 +1919,10 @@ void reset_stmt_for_execute(THD *thd, LEX *lex) /* Clears parameters from data left from previous execution or long data - + SYNOPSIS reset_stmt_params() - stmt prepared statement for which parameters should be reset + stmt prepared statement for which parameters should be reset */ static void reset_stmt_params(Prepared_statement *stmt) @@ -1967,6 +1950,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) { ulong stmt_id= uint4korr(packet); ulong flags= (ulong) ((uchar) packet[4]); + Statement stmt_backup; Cursor *cursor; /* Query text for binary log, or empty string if the query is not put into @@ -1981,13 +1965,14 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) packet+= 9; /* stmt_id + 5 bytes of flags */ + statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute"))) DBUG_VOID_RETURN; DBUG_PRINT("exec_query:", ("%s", stmt->query)); /* Check if we got an error when sending long data */ - if (stmt->state == Item_arena::ERROR) + if (stmt->state == Query_arena::ERROR) { my_message(stmt->last_errno, stmt->last_error, MYF(0)); DBUG_VOID_RETURN; @@ -2019,7 +2004,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) { DBUG_PRINT("info",("Using READ_ONLY cursor")); if (!cursor && - !(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor())) + !(cursor= stmt->cursor= new (stmt->mem_root) Cursor(thd))) DBUG_VOID_RETURN; /* If lex->result is set, mysql_execute_command will use it */ stmt->lex->result= &cursor->result; @@ -2036,17 +2021,16 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) } #else /* - In embedded library we re-install conversion routines each time - we set params, and also we don't need to parse packet. + In embedded library we re-install conversion routines each time + we set params, and also we don't need to parse packet. So we do it in one function. */ if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query)) goto set_params_data_err; #endif - thd->stmt_backup.set_statement(thd); - thd->set_statement(stmt); + thd->set_n_backup_statement(stmt, &stmt_backup); thd->current_arena= stmt; - reset_stmt_for_execute(thd, stmt->lex); + reinit_stmt_before_use(thd, stmt->lex); /* From now cursors assume that thd->mem_root is clean */ if (expanded_query.length() && alloc_query(thd, (char *)expanded_query.ptr(), @@ -2055,10 +2039,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) my_error(ER_OUTOFMEMORY, 0, expanded_query.length()); goto err; } - - mysql_log.write(thd, COM_EXECUTE, "[%lu] %s", stmt->id, - expanded_query.length() ? expanded_query.c_ptr() : - stmt->query); + mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query); thd->protocol= &thd->protocol_prep; // Switch to binary protocol if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -2070,20 +2051,21 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) if (cursor && cursor->is_open()) { + /* + It's safer if we grab THD state after mysql_execute_command is + finished and not in Cursor::open(), because currently the call to + Cursor::open is buried deep in JOIN::exec of the top level join. + */ cursor->init_from_thd(thd); - cursor->state= stmt->state; } else { - thd->lex->unit.cleanup(); - cleanup_items(stmt->free_list); + close_thread_tables(thd); + cleanup_stmt_and_thd_after_use(stmt, thd); reset_stmt_params(stmt); - close_thread_tables(thd); /* to close derived tables */ - thd->rollback_item_tree_changes(); - thd->cleanup_after_query(); } - thd->set_statement(&thd->stmt_backup); + thd->set_statement(&stmt_backup); thd->current_arena= thd; DBUG_VOID_RETURN; @@ -2108,9 +2090,12 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) binary log. */ String expanded_query; + Statement stmt_backup; DBUG_ENTER("mysql_sql_stmt_execute"); DBUG_ASSERT(thd->free_list == NULL); + /* See comment for statistic_increment in mysql_stmt_prepare */ + statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status); if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name))) { @@ -2127,15 +2112,16 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name) /* Must go before setting variables, as it clears thd->user_var_events */ mysql_reset_thd_for_next_command(thd); - thd->set_n_backup_statement(stmt, &thd->stmt_backup); - thd->set_statement(stmt); + thd->set_n_backup_statement(stmt, &stmt_backup); if (stmt->set_params_from_vars(stmt, - thd->stmt_backup.lex->prepared_stmt_params, + stmt_backup.lex->prepared_stmt_params, &expanded_query)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE"); } + thd->command= COM_STMT_EXECUTE; /* For nice messages in general log */ execute_stmt(thd, stmt, &expanded_query); + thd->set_statement(&stmt_backup); DBUG_VOID_RETURN; } @@ -2158,7 +2144,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, { DBUG_ENTER("execute_stmt"); - reset_stmt_for_execute(thd, stmt->lex); + reinit_stmt_before_use(thd, stmt->lex); if (expanded_query->length() && alloc_query(thd, (char *)expanded_query->ptr(), @@ -2167,6 +2153,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, my_error(ER_OUTOFMEMORY, MYF(0), expanded_query->length()); DBUG_VOID_RETURN; } + mysql_log.write(thd, thd->command, "[%lu] %s", stmt->id, thd->query); /* At first execution of prepared statement we will perform logical transformations of the query tree (i.e. negations elimination). @@ -2179,30 +2166,34 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, mysql_execute_command(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); + /* + 'start_time' is set in dispatch_command, but THD::query will + be freed when we return from this function. So let's log the slow + query here. + */ + log_slow_statement(thd); + /* Prevent from second logging in the end of dispatch_command */ + thd->enable_slow_log= FALSE; - thd->lex->unit.cleanup(); - thd->current_arena= thd; - cleanup_items(stmt->free_list); - thd->rollback_item_tree_changes(); - reset_stmt_params(stmt); close_thread_tables(thd); // to close derived tables - thd->set_statement(&thd->stmt_backup); - thd->cleanup_after_query(); + cleanup_stmt_and_thd_after_use(stmt, thd); + reset_stmt_params(stmt); + thd->current_arena= thd; - if (stmt->state == Item_arena::PREPARED) - stmt->state= Item_arena::EXECUTED; + if (stmt->state == Query_arena::PREPARED) + stmt->state= Query_arena::EXECUTED; DBUG_VOID_RETURN; } /* - COM_FETCH handler: fetches requested amount of rows from cursor + COM_STMT_FETCH handler: fetches requested amount of rows from cursor SYNOPSIS mysql_stmt_fetch() - thd Thread handler - packet Packet from client (with stmt_id & num_rows) - packet_length Length of packet + thd Thread handler + packet Packet from client (with stmt_id & num_rows) + packet_length Length of packet */ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) @@ -2210,37 +2201,43 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) /* assume there is always place for 8-16 bytes */ ulong stmt_id= uint4korr(packet); ulong num_rows= uint4korr(packet+4); - Statement *stmt; + Prepared_statement *stmt; + Statement stmt_backup; DBUG_ENTER("mysql_stmt_fetch"); + statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) DBUG_VOID_RETURN; if (!stmt->cursor || !stmt->cursor->is_open()) { - my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0)); + my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id); DBUG_VOID_RETURN; } thd->current_arena= stmt; - thd->set_n_backup_statement(stmt, &thd->stmt_backup); - stmt->cursor->init_thd(thd); + thd->set_n_backup_statement(stmt, &stmt_backup); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), QUERY_PRIOR); - thd->protocol= &thd->protocol_prep; // Switch to binary protocol + thd->protocol= &thd->protocol_prep; // Switch to binary protocol stmt->cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - /* Restore THD state */ - stmt->cursor->reset_thd(thd); - thd->restore_backup_statement(stmt, &thd->stmt_backup); + thd->restore_backup_statement(stmt, &stmt_backup); thd->current_arena= thd; + if (!stmt->cursor->is_open()) + { + /* We're done with the fetch: reset PS for next execution */ + cleanup_stmt_and_thd_after_use(stmt, thd); + reset_stmt_params(stmt); + } + DBUG_VOID_RETURN; } @@ -2250,7 +2247,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) SYNOPSIS mysql_stmt_reset() thd Thread handle - packet Packet with stmt id + packet Packet with stmt id DESCRIPTION This function resets statement to the state it was right after prepare. @@ -2269,40 +2266,42 @@ void mysql_stmt_reset(THD *thd, char *packet) Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_reset"); + statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; if (stmt->cursor && stmt->cursor->is_open()) stmt->cursor->close(); - stmt->state= Item_arena::PREPARED; + stmt->state= Query_arena::PREPARED; - /* - Clear parameters from data which could be set by + /* + Clear parameters from data which could be set by mysql_stmt_send_long_data() call. */ reset_stmt_params(stmt); mysql_reset_thd_for_next_command(thd); send_ok(thd); - + DBUG_VOID_RETURN; } /* Delete a prepared statement from memory. - Note: we don't send any reply to that command. + Note: we don't send any reply to that command. */ -void mysql_stmt_free(THD *thd, char *packet) +void mysql_stmt_close(THD *thd, char *packet) { /* There is always space for 4 bytes in packet buffer */ ulong stmt_id= uint4korr(packet); Prepared_statement *stmt; - DBUG_ENTER("mysql_stmt_free"); + DBUG_ENTER("mysql_stmt_close"); + statistic_increment(thd->status_var.com_stmt_close, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) DBUG_VOID_RETURN; @@ -2317,9 +2316,9 @@ void mysql_stmt_free(THD *thd, char *packet) SYNOPSIS mysql_stmt_get_longdata() - thd Thread handle - pos String to append - packet_length Length of string + thd Thread handle + pos String to append + packet_length Length of string DESCRIPTION Get a part of a long data. @@ -2338,9 +2337,10 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) Prepared_statement *stmt; Item_param *param; char *packet_end= packet + packet_length - 1; - + DBUG_ENTER("mysql_stmt_get_longdata"); + statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status); #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER) @@ -2363,7 +2363,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) if (param_number >= stmt->param_count) { /* Error will be sent in execute call */ - stmt->state= Item_arena::ERROR; + stmt->state= Query_arena::ERROR; stmt->last_errno= ER_WRONG_ARGUMENTS; sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "mysql_stmt_send_long_data"); @@ -2379,7 +2379,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) if (param->set_longdata(thd->extra_data, thd->extra_length)) #endif { - stmt->state= Item_arena::ERROR; + stmt->state= Query_arena::ERROR; stmt->last_errno= ER_OUTOFMEMORY; sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0); } @@ -2388,7 +2388,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) Prepared_statement::Prepared_statement(THD *thd_arg) - :Statement(thd_arg), + :Statement(INITIALIZED, ++thd_arg->statement_id_counter, + thd_arg->variables.query_alloc_block_size, + thd_arg->variables.query_prealloc_size), thd(thd_arg), param_array(0), param_count(0), @@ -2397,10 +2399,12 @@ Prepared_statement::Prepared_statement(THD *thd_arg) *last_error= '\0'; } + void Prepared_statement::setup_set_params() { /* Setup binary logging */ - if (mysql_bin_log.is_open() && is_update_query(lex->sql_command)) + if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) || + mysql_log.is_open() || mysql_slow_log.is_open()) { set_params_from_vars= insert_params_from_vars_with_log; #ifndef EMBEDDED_LIBRARY @@ -2430,7 +2434,7 @@ Prepared_statement::~Prepared_statement() } -Item_arena::Type Prepared_statement::type() const +Query_arena::Type Prepared_statement::type() const { return PREPARED_STATEMENT; } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 8fe17198cf0..3880aa428b9 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -164,7 +164,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) ren_table->db, old_alias, reg_ext); unpack_filename(name, name); - if ((table_type=get_table_type(name)) == DB_TYPE_UNKNOWN) + if ((table_type=get_table_type(thd, name)) == DB_TYPE_UNKNOWN) { my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno); if (!skip_error) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 1dcdf159f8f..dbefbb34b4a 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1317,6 +1317,7 @@ bool mysql_show_binlog_events(THD* thd) if (mysql_bin_log.is_open()) { LEX_MASTER_INFO *lex_mi= &thd->lex->mi; + SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows event_count, limit_start, limit_end; my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly char search_file_name[FN_REFLEN], *name; @@ -1325,8 +1326,9 @@ bool mysql_show_binlog_events(THD* thd) LOG_INFO linfo; Log_event* ev; - limit_start= thd->lex->current_select->offset_limit; - limit_end= thd->lex->current_select->select_limit + limit_start; + unit->set_limit(thd->lex->current_select); + limit_start= unit->offset_limit_cnt; + limit_end= unit->select_limit_cnt; name= search_file_name; if (log_file_name) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8b5b4d7b224..bea68bf4da5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28,6 +28,8 @@ #include <hash.h> #include <ft_global.h> +typedef uint32 cache_rec_length_type; + const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "MAYBE_REF","ALL","range","index","fulltext", "ref_or_null","unique_subquery","index_subquery", @@ -136,7 +138,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); static enum_nested_loop_state end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int test_if_group_changed(List<Item_buff> &list); +static int test_if_group_changed(List<Cached_item> &list); static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); static int join_read_const(JOIN_TAB *tab); @@ -580,7 +582,7 @@ JOIN::optimize() MEMROOT for prepared statements and stored procedures. */ - Item_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->current_arena, backup; if (arena->is_conventional()) arena= 0; // For easier test else @@ -812,9 +814,14 @@ JOIN::optimize() DBUG_RETURN(1); } simple_group= 0; - group_list= remove_const(this, group_list, conds, - rollup.state == ROLLUP::STATE_NONE, - &simple_group); + { + ORDER *old_group_list; + group_list= remove_const(this, (old_group_list= group_list), conds, + rollup.state == ROLLUP::STATE_NONE, + &simple_group); + if (old_group_list && !group_list) + select_distinct= 0; + } if (!group_list && group) { order=0; // The output has only one row @@ -1697,7 +1704,16 @@ JOIN::cleanup() /************************* Cursor ******************************************/ - + +Cursor::Cursor(THD *thd) + :Query_arena(&main_mem_root, INITIALIZED), + join(0), unit(0) +{ + /* We will overwrite it at open anyway. */ + init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); +} + + void Cursor::init_from_thd(THD *thd) { @@ -1705,10 +1721,11 @@ Cursor::init_from_thd(THD *thd) We need to save and reset thd->mem_root, otherwise it'll be freed later in mysql_parse. - We can't just change the thd->mem_root here as we want to keep the things - that is already allocated in thd->mem_root for Cursor::fetch() + We can't just change the thd->mem_root here as we want to keep the + things that are already allocated in thd->mem_root for Cursor::fetch() */ main_mem_root= *thd->mem_root; + state= thd->current_arena->state; /* Allocate new memory root for thd */ init_sql_alloc(thd->mem_root, thd->variables.query_alloc_block_size, @@ -1731,24 +1748,6 @@ Cursor::init_from_thd(THD *thd) What problems can we have with it if cursor is open? TODO: must be fixed because of the prelocked mode. */ - /* - TODO: grab thd->free_list here? - */ -} - - -void -Cursor::init_thd(THD *thd) -{ - DBUG_ASSERT(thd->derived_tables == 0); - thd->derived_tables= derived_tables; - - DBUG_ASSERT(thd->open_tables == 0); - thd->open_tables= open_tables; - - DBUG_ASSERT(thd->lock== 0); - thd->lock= lock; - thd->query_id= query_id; } @@ -1821,11 +1820,19 @@ Cursor::fetch(ulong num_rows) THD *thd= join->thd; JOIN_TAB *join_tab= join->join_tab + join->const_tables; enum_nested_loop_state error= NESTED_LOOP_OK; + Query_arena backup_arena; DBUG_ENTER("Cursor::fetch"); DBUG_PRINT("enter",("rows: %lu", num_rows)); + DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 && + thd->lock == 0); + + thd->derived_tables= derived_tables; + thd->open_tables= open_tables; + thd->lock= lock; + thd->query_id= query_id; /* save references to memory, allocated during fetch */ - thd->set_n_backup_item_arena(this, &thd->stmt_backup); + thd->set_n_backup_item_arena(this, &backup_arena); join->fetch_limit+= num_rows; @@ -1841,7 +1848,10 @@ Cursor::fetch(ulong num_rows) ha_release_temporary_latches(thd); #endif - thd->restore_backup_item_arena(this, &thd->stmt_backup); + thd->restore_backup_item_arena(this, &backup_arena); + DBUG_ASSERT(thd->free_list == 0); + reset_thd(thd); + if (error == NESTED_LOOP_CURSOR_LIMIT) { /* Fetch limit worked, possibly more rows are there */ @@ -1882,8 +1892,8 @@ Cursor::close() join->cleanup(); delete join; } - /* XXX: Another hack: closing tables used in the cursor */ { + /* XXX: Another hack: closing tables used in the cursor */ DBUG_ASSERT(lock || open_tables || derived_tables); TABLE *tmp_derived_tables= thd->derived_tables; @@ -2161,7 +2171,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if (*s->on_expr_ref) { /* s is the only inner table of an outer join */ - if (!table->file->records) + if (!table->file->records && !embedding) { // Empty table s->dependent= 0; // Ignore LEFT JOIN depend. set_position(join,const_count++,s,(KEYUSE*) 0); @@ -6273,7 +6283,7 @@ public: COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {} }; -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class I_List<COND_CMP>; template class I_List_iterator<COND_CMP>; template class List<Item_func_match>; @@ -7067,7 +7077,7 @@ static COND* substitute_for_best_equal_field(COND *cond, List_iterator_fast<Item_equal> it(cond_equal->current_level); while ((item_equal= it++)) { - eliminate_item_equal(cond, cond_equal->upper_levels, item_equal); + cond= eliminate_item_equal(cond, cond_equal->upper_levels, item_equal); } } } @@ -7960,6 +7970,19 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, modify_item ? (Item_field*) item : NULL, convert_blob_length); } + case Item::REF_ITEM: + if ( item->real_item()->type() == Item::FIELD_ITEM) + { + Item_field *field= (Item_field*) *((Item_ref*)item)->ref; + Field *new_field= create_tmp_field_from_field(thd, + (*from_field= field->field), + item->name, table, + NULL, + convert_blob_length); + if (modify_item) + item->set_result_field(new_field); + return new_field; + } case Item::FUNC_ITEM: case Item::COND_ITEM: case Item::FIELD_AVG_ITEM: @@ -7971,7 +7994,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::REAL_ITEM: case Item::DECIMAL_ITEM: case Item::STRING_ITEM: - case Item::REF_ITEM: case Item::NULL_ITEM: case Item::VARBIN_ITEM: return create_tmp_field_from_item(thd, item, table, copy_func, modify_item, @@ -10080,7 +10102,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { join->do_send_rows= 0; if (join->unit->fake_select_lex) - join->unit->fake_select_lex->select_limit= HA_POS_ERROR; + join->unit->fake_select_lex->select_limit= 0; DBUG_RETURN(NESTED_LOOP_OK); } } @@ -11597,7 +11619,7 @@ used_blob_length(CACHE_FIELD **ptr) static bool store_record_in_cache(JOIN_CACHE *cache) { - ulong length; + cache_rec_length_type length; uchar *pos; CACHE_FIELD *copy,*end_field; bool last_record; @@ -11642,9 +11664,9 @@ store_record_in_cache(JOIN_CACHE *cache) end > str && end[-1] == ' ' ; end--) ; length=(uint) (end-str); - memcpy(pos+1,str,length); - *pos=(uchar) length; - pos+=length+1; + memcpy(pos+sizeof(length), str, length); + memcpy_fixed(pos, &length, sizeof(length)); + pos+= length+sizeof(length); } else { @@ -11678,7 +11700,7 @@ static void read_cached_record(JOIN_TAB *tab) { uchar *pos; - uint length; + cache_rec_length_type length; bool last_record; CACHE_FIELD *copy,*end_field; @@ -11707,9 +11729,10 @@ read_cached_record(JOIN_TAB *tab) { if (copy->strip) { - memcpy(copy->str,pos+1,length=(uint) *pos); - memset(copy->str+length,' ',copy->length-length); - pos+=1+length; + memcpy_fixed(&length, pos, sizeof(length)); + memcpy(copy->str, pos+sizeof(length), length); + memset(copy->str+length, ' ', copy->length-length); + pos+= sizeof(length)+length; } else { @@ -11788,11 +11811,11 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) ref_pointer_array. RETURN - 0 if OK - 1 if error occurred + FALSE if OK + TRUE if error occurred */ -static int +static bool find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ORDER *order, List<Item> &fields, List<Item> &all_fields, bool is_group_field) @@ -11809,13 +11832,13 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, { my_error(ER_BAD_FIELD_ERROR, MYF(0), order_item->full_name(), thd->where); - return 1; + return TRUE; } order->item= ref_pointer_array + count - 1; order->in_field_list= 1; order->counter= count; order->counter_used= 1; - return 0; + return FALSE; } /* Lookup the current GROUP/ORDER field in the SELECT clause. */ uint counter; @@ -11823,7 +11846,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, select_item= find_item_in_list(order_item, fields, &counter, REPORT_EXCEPT_NOT_FOUND, &unaliased); if (!select_item) - return 1; /* Some error occured. */ + return TRUE; /* The item is not unique, or some other error occured. */ /* Check whether the resolved field is not ambiguos. */ @@ -11837,7 +11860,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, */ if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables, order->item)) - return 1; + return TRUE; /* Lookup the current GROUP field in the FROM clause. */ order_item_type= order_item->type(); @@ -11877,27 +11900,42 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, { order->item= ref_pointer_array + counter; order->in_field_list=1; - return 0; + return FALSE; } + else + /* + There is a field with the same name in the FROM clause. This is the field + that will be chosen. In this case we issue a warning so the user knows + that the field from the FROM clause overshadows the column reference from + the SELECT list. + */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR, + ER(ER_NON_UNIQ_ERROR), from_field->field_name, + current_thd->where); } order->in_field_list=0; /* + The call to order_item->fix_fields() means that here we resolve 'order_item' + to a column from a table in the list 'tables', or to a column in some outer + query. Exactly because of the second case we come to this point even if + (select_item == not_found_item), inspite of that fix_fields() calls + find_item_in_list() one more time. + We check order_item->fixed because Item_func_group_concat can put arguments for which fix_fields already was called. - - 'it' reassigned in if condition because fix_field can change it. */ if (!order_item->fixed && (order_item->fix_fields(thd, tables, order->item) || (order_item= *order->item)->check_cols(1) || thd->is_fatal_error)) - return 1; // Wrong field + return TRUE; /* Wrong field. */ + uint el= all_fields.elements; - all_fields.push_front(order_item); // Add new field to field list + all_fields.push_front(order_item); /* Add new field to field list. */ ref_pointer_array[el]= order_item; order->item= ref_pointer_array + el; - return 0; + return FALSE; } @@ -12284,7 +12322,7 @@ alloc_group_fields(JOIN *join,ORDER *group) { for (; group ; group=group->next) { - Item_buff *tmp=new_Item_buff(*group->item); + Cached_item *tmp=new_Cached_item(join->thd, *group->item); if (!tmp || join->group_fields.push_front(tmp)) return TRUE; } @@ -12295,12 +12333,12 @@ alloc_group_fields(JOIN *join,ORDER *group) static int -test_if_group_changed(List<Item_buff> &list) +test_if_group_changed(List<Cached_item> &list) { DBUG_ENTER("test_if_group_changed"); - List_iterator<Item_buff> li(list); + List_iterator<Cached_item> li(list); int idx= -1,i; - Item_buff *buff; + Cached_item *buff; for (i=(int) list.elements-1 ; (buff=li++) ; i--) { diff --git a/sql/sql_select.h b/sql/sql_select.h index 49ac58e913b..e5266944251 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -178,7 +178,7 @@ class JOIN :public Sql_alloc table_map const_table_map,found_const_table_map,outer_join; ha_rows send_records,found_records,examined_rows,row_limit, select_limit; /* - Used to fetch no more than given amount of rows per one + Used to fetch no more than given amount of rows per one fetch operation of server side cursor. The value is checked in end_send and end_send_group in fashion, similar to offset_limit_cnt: @@ -190,7 +190,7 @@ class JOIN :public Sql_alloc POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; double best_read; List<Item> *fields; - List<Item_buff> group_fields, group_fields_cache; + List<Cached_item> group_fields, group_fields_cache; TABLE *tmp_table; // used to store 2 possible tmp table of SELECT TABLE *exec_tmp_table1, *exec_tmp_table2; @@ -370,8 +370,9 @@ class JOIN :public Sql_alloc statement for many cursors. */ -class Cursor: public Sql_alloc, public Item_arena +class Cursor: public Sql_alloc, public Query_arena { + MEM_ROOT main_mem_root; JOIN *join; SELECT_LEX_UNIT *unit; @@ -386,8 +387,6 @@ public: /* Temporary implementation as now we replace THD state by value */ /* Save THD state into cursor */ void init_from_thd(THD *thd); - /* Restore THD from cursor to continue cursor execution */ - void init_thd(THD *thd); /* bzero cursor state in THD */ void reset_thd(THD *thd); @@ -398,7 +397,7 @@ public: void close(); void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } - Cursor() :Item_arena(TRUE), join(0), unit(0) {} + Cursor(THD *thd); ~Cursor(); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1e34f32184a..12025c82da6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -348,7 +348,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) table_list->table_name)); /* Only one table for now, but VIEW can involve several tables */ - if (open_and_lock_tables(thd, table_list)) + if (open_normal_and_derived_tables(thd, table_list)) { DBUG_RETURN(TRUE); } @@ -448,25 +448,32 @@ bool mysqld_show_create_db(THD *thd, char *dbname, DBUG_RETURN(TRUE); } #endif - - (void) sprintf(path,"%s/%s",mysql_data_home, dbname); - length=unpack_dirname(path,path); // Convert if not unix - found_libchar= 0; - if (length && path[length-1] == FN_LIBCHAR) + if (!my_strcasecmp(system_charset_info, dbname, + information_schema_name.str)) { - found_libchar= 1; - path[length-1]=0; // remove ending '\' + dbname= information_schema_name.str; + create.default_table_charset= system_charset_info; } - if (access(path,F_OK)) + else { - my_error(ER_BAD_DB_ERROR, MYF(0), dbname); - DBUG_RETURN(TRUE); + (void) sprintf(path,"%s/%s",mysql_data_home, dbname); + length=unpack_dirname(path,path); // Convert if not unix + found_libchar= 0; + if (length && path[length-1] == FN_LIBCHAR) + { + found_libchar= 1; + path[length-1]=0; // remove ending '\' + } + if (access(path,F_OK)) + { + my_error(ER_BAD_DB_ERROR, MYF(0), dbname); + DBUG_RETURN(TRUE); + } + if (found_libchar) + path[length-1]= FN_LIBCHAR; + strmov(path+length, MY_DB_OPT_FILE); + load_db_opt(thd, path, &create); } - if (found_libchar) - path[length-1]= FN_LIBCHAR; - strmov(path+length, MY_DB_OPT_FILE); - load_db_opt(thd, path, &create); - List<Item> field_list; field_list.push_back(new Item_empty_string("Database",NAME_LEN)); field_list.push_back(new Item_empty_string("Create Database",1024)); @@ -540,8 +547,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) DBUG_ENTER("mysqld_list_fields"); DBUG_PRINT("enter",("table: %s",table_list->table_name)); - table_list->lock_type= TL_UNLOCK; - if (open_and_lock_tables(thd, table_list)) + if (open_normal_and_derived_tables(thd, table_list)) DBUG_VOID_RETURN; table= table_list->table; @@ -1096,7 +1102,7 @@ public: char *query; }; -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class I_List<thread_info>; #endif @@ -1945,7 +1951,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) bool res; lex->all_selects_list= lsel; - res= open_and_lock_tables(thd, show_table_list); + res= open_normal_and_derived_tables(thd, show_table_list); if (schema_table->process_table(thd, show_table_list, table, res, show_table_list->db, show_table_list->alias)) @@ -2050,7 +2056,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) show_table_list->lock_type= lock_type; lex->all_selects_list= &sel; lex->derived_tables= 0; - res= open_and_lock_tables(thd, show_table_list); + res= open_normal_and_derived_tables(thd, show_table_list); if (schema_table->process_table(thd, show_table_list, table, res, base_name, show_table_list->alias)) @@ -2646,6 +2652,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, restore_record(table, s->default_values); if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0)) { + int enum_idx= proc_table->field[5]->val_int(); table->field[3]->store(sp_name, strlen(sp_name), cs); get_field(thd->mem_root, proc_table->field[3], &tmp_string); table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs); @@ -2667,10 +2674,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, table->field[10]->store("SQL", 3, cs); get_field(thd->mem_root, proc_table->field[6], &tmp_string); table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); - if (proc_table->field[5]->val_int() == SP_CONTAINS_SQL) - { - table->field[12]->store("CONTAINS SQL", 12 , cs); - } + table->field[12]->store(sp_data_access_name[enum_idx].str, + sp_data_access_name[enum_idx].length , cs); get_field(thd->mem_root, proc_table->field[7], &tmp_string); table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); bzero((char *)&time, sizeof(time)); @@ -3874,7 +3879,7 @@ ST_SCHEMA_TABLE schema_tables[]= }; -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List_iterator_fast<char>; template class List<char>; #endif diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5e1e76e2a40..e34718ec05a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -39,6 +39,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, uint order_num, ORDER *order, ha_rows *copied,ha_rows *deleted); static bool prepare_blob_field(THD *thd, create_field *sql_field); +static bool check_engine(THD *thd, const char *table_name, + enum db_type *new_engine); /* @@ -268,7 +270,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, else { char *end; - db_type table_type= get_table_type(path); + db_type table_type= get_table_type(thd, path); *(end=fn_ext(path))=0; // Remove extension for delete error= ha_delete_table(thd, table_type, path, table->table_name, !dont_log_query); @@ -1490,7 +1492,6 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, KEY *key_info_buffer; handler *file; bool error= TRUE; - enum db_type new_db_type; DBUG_ENTER("mysql_create_table"); /* Check for duplicate fields and check type of table to create */ @@ -1500,16 +1501,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, MYF(0)); DBUG_RETURN(TRUE); } - if ((new_db_type= ha_checktype(create_info->db_type)) != - create_info->db_type) - { - create_info->db_type= new_db_type; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_USING_OTHER_HANDLER, - ER(ER_WARN_USING_OTHER_HANDLER), - ha_get_storage_engine(new_db_type), - table_name); - } + if (check_engine(thd, table_name, &create_info->db_type)) + DBUG_RETURN(TRUE); db_options= create_info->table_options; if (create_info->row_type == ROW_TYPE_DYNAMIC) db_options|=HA_OPTION_PACK_RECORD; @@ -2590,28 +2583,33 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, char src_path[FN_REFLEN], dst_path[FN_REFLEN]; char *db= table->db; char *table_name= table->table_name; - char *src_db= thd->db; + char *src_db; char *src_table= table_ident->table.str; int err; bool res= TRUE; TABLE_LIST src_tables_list; DBUG_ENTER("mysql_create_like_table"); + src_db= table_ident->db.str ? table_ident->db.str : thd->db; /* Validate the source table */ if (table_ident->table.length > NAME_LEN || (table_ident->table.length && - check_table_name(src_table,table_ident->table.length)) || - table_ident->db.str && check_db_name((src_db= table_ident->db.str))) + check_table_name(src_table,table_ident->table.length))) { my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); DBUG_RETURN(TRUE); } + if (!src_db || check_db_name(src_db)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL"); + DBUG_RETURN(-1); + } bzero((gptr)&src_tables_list, sizeof(src_tables_list)); - src_tables_list.db= table_ident->db.str ? table_ident->db.str : thd->db; - src_tables_list.table_name= table_ident->table.str; + src_tables_list.db= src_db; + src_tables_list.table_name= src_table; if (lock_and_wait_for_table_name(thd, &src_tables_list)) goto err; @@ -3121,16 +3119,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, old_db_type= table->s->db_type; if (create_info->db_type == DB_TYPE_DEFAULT) create_info->db_type= old_db_type; - if ((new_db_type= ha_checktype(create_info->db_type)) != - create_info->db_type) - { - create_info->db_type= new_db_type; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_USING_OTHER_HANDLER, - ER(ER_WARN_USING_OTHER_HANDLER), - ha_get_storage_engine(new_db_type), - new_name); - } + if (check_engine(thd, new_name, &create_info->db_type)) + DBUG_RETURN(TRUE); + new_db_type= create_info->db_type; if (create_info->row_type == ROW_TYPE_NOT_USED) create_info->row_type= table->s->row_type; @@ -3394,12 +3385,25 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, continue; // Field is removed uint key_part_length=key_part->length; if (cfield->field) // Not new field - { // Check if sub key - if (cfield->field->type() != FIELD_TYPE_BLOB && - (cfield->field->pack_length() == key_part_length || - cfield->length <= key_part_length / - key_part->field->charset()->mbmaxlen)) - key_part_length=0; // Use whole field + { + /* + If the field can't have only a part used in a key according to its + new type, or should not be used partially according to its + previous type, or the field length is less than the key part + length, unset the key part length. + + We also unset the key part length if it is the same as the + old field's length, so the whole new field will be used. + + BLOBs may have cfield->length == 0, which is why we test it before + checking whether cfield->length < key_part_length (in chars). + */ + if (!Field::type_can_have_key_part(cfield->field->type()) || + !Field::type_can_have_key_part(cfield->sql_type) || + cfield->field->field_length == key_part_length || + (cfield->length && (cfield->length < key_part_length / + key_part->field->charset()->mbmaxlen))) + key_part_length= 0; // Use whole field } key_part_length /= key_part->field->charset()->mbmaxlen; key_parts.push_back(new key_part_spec(cfield->field_name, @@ -4117,3 +4121,24 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) table->table=0; DBUG_RETURN(TRUE); } + +static bool check_engine(THD *thd, const char *table_name, + enum db_type *new_engine) +{ + enum db_type req_engine= *new_engine; + bool no_substitution= + test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION); + if ((*new_engine= + ha_checktype(thd, req_engine, no_substitution, 1)) == DB_TYPE_UNKNOWN) + return TRUE; + + if (req_engine != *new_engine) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_USING_OTHER_HANDLER, + ER(ER_WARN_USING_OTHER_HANDLER), + ha_get_storage_engine(*new_engine), + table_name); + } + return FALSE; +} diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 56401ced67c..f59d7fffe85 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -274,7 +274,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, all collations together for UNION. */ List_iterator_fast<Item> tp(types); - Item_arena *arena= thd->current_arena; + Query_arena *arena= thd->current_arena; Item *type; while ((type= tp++)) @@ -308,7 +308,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (!item_list.elements) { Field **field; - Item_arena *tmp_arena,backup; + Query_arena *tmp_arena,backup; tmp_arena= thd->change_arena_if_needed(&backup); for (field= table->field; *field; field++) @@ -448,7 +448,7 @@ bool st_select_lex_unit::exec() table->no_keyread=1; } res= sl->join->error; - offset_limit_cnt= sl->offset_limit; + offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : 0; if (!res) { examined_rows+= thd->examined_row_count; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 289bf9d28a3..0b351407c13 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -36,6 +36,61 @@ TYPELIB updatable_views_with_limit_typelib= /* + Make a unique name for an anonymous view column + SYNOPSIS + target reference to the item for which a new name has to be made + item_list list of items within which we should check uniqueness of + the created name + last_element the last element of the list above + + NOTE + Unique names are generated by adding 'My_exp_' to the old name of the + column. In case the name that was created this way already exists, we + add a numeric postfix to its end (i.e. "1") and increase the number + until the name becomes unique. If the generated name is longer than + NAME_LEN, it is truncated. +*/ + +static void make_unique_view_field_name(Item *target, + List<Item> &item_list, + Item *last_element) +{ + char *name= (target->orig_name ? + target->orig_name : + target->name); + uint name_len; + uint attempt= 0; + char buff[NAME_LEN+1]; + for (;; attempt++) + { + Item *check; + List_iterator_fast<Item> itc(item_list); + bool ok= TRUE; + + if (attempt) + name_len= my_snprintf(buff, NAME_LEN, "My_exp_%d_%s", attempt, name); + else + name_len= my_snprintf(buff, NAME_LEN, "My_exp_%s", name); + + do + { + check= itc++; + if (check != target && + my_strcasecmp(system_charset_info, buff, check->name) == 0) + { + ok= FALSE; + break; + } + } while (check != last_element); + if (ok) + break; + } + + target->orig_name= target->name; + target->set_name(buff, name_len, system_charset_info); +} + +/* Creating/altering VIEW procedure SYNOPSIS @@ -240,24 +295,36 @@ bool mysql_create_view(THD *thd, goto err; } while ((item= it++, name= nm++)) + { item->set_name(name->str, name->length, system_charset_info); + item->is_autogenerated_name= FALSE; + } } /* Test absence of duplicates names */ { Item *item; List_iterator_fast<Item> it(select_lex->item_list); - it++; while ((item= it++)) { Item *check; List_iterator_fast<Item> itc(select_lex->item_list); + /* treat underlying fields like set by user names */ + if (item->real_item()->type() == Item::FIELD_ITEM) + item->is_autogenerated_name= FALSE; while ((check= itc++) && check != item) { - if (strcmp(item->name, check->name) == 0) + if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) { - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); - DBUG_RETURN(TRUE); + if (item->is_autogenerated_name) + make_unique_view_field_name(item, select_lex->item_list, item); + else if (check->is_autogenerated_name) + make_unique_view_field_name(check, select_lex->item_list, item); + else + { + my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + DBUG_RETURN(TRUE); + } } } } @@ -579,7 +646,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) For now we assume that tables will not be changed during PS life (it will be TRUE as far as we make new table cache). */ - Item_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->current_arena, backup; if (arena->is_conventional()) arena= 0; else @@ -1000,8 +1067,9 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) we do not support updatable UNIONs in VIEW, so we can check just limit of LEX::select_lex */ - if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT || - thd->lex->select_lex.select_limit == HA_POS_ERROR) + if ((!view->view && !view->belong_to_view) || + thd->lex->sql_command == SQLCOM_INSERT || + thd->lex->select_lex.select_limit == 0) DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */ table= view->table; if (view->belong_to_view) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 88afab0bbe8..edca9cf3c5f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -52,7 +52,7 @@ const LEX_STRING null_lex_str={0,0}; ER_WARN_DEPRECATED_SYNTAX, \ ER(ER_WARN_DEPRECATED_SYNTAX), (A), (B)); -#define TEST_ASSERT(A) \ +#define YYERROR_UNLESS(A) \ if (!(A)) \ { \ yyerror(ER(ER_SYNTAX_ERROR)); \ @@ -721,7 +721,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); signed_literal now_or_signed_literal opt_escape sp_opt_default simple_ident_nospvar simple_ident_q - field_or_var + field_or_var limit_option %type <item_num> NUM_literal @@ -914,11 +914,16 @@ deallocate: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_PREPARE) + if (thd->command == COM_STMT_PREPARE) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "DEALLOCATE"); + YYABORT; + } lex->sql_command= SQLCOM_DEALLOCATE_PREPARE; lex->prepared_stmt_name= $3; }; @@ -934,11 +939,16 @@ prepare: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_PREPARE) + if (thd->command == COM_STMT_PREPARE) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "PREPARE"); + YYABORT; + } lex->sql_command= SQLCOM_PREPARE; lex->prepared_stmt_name= $2; }; @@ -964,11 +974,16 @@ execute: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_PREPARE) + if (thd->command == COM_STMT_PREPARE) { yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } + if (lex->sphead) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "EXECUTE"); + YYABORT; + } lex->sql_command= SQLCOM_EXECUTE; lex->prepared_stmt_name= $2; } @@ -4014,7 +4029,7 @@ select_options: /* empty*/ | select_option_list { - if (Select->options & SELECT_DISTINCT && Select->options2 & SELECT_ALL) + if (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL) { my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT"); YYABORT; @@ -4054,7 +4069,7 @@ select_option: { Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; } - | ALL { Select->options2|= SELECT_ALL; } + | ALL { Select->options|= SELECT_ALL; } ; select_lock_type: @@ -4092,7 +4107,10 @@ select_item: if (add_item_to_list(YYTHD, $2)) YYABORT; if ($4.str) - $2->set_name($4.str,$4.length,system_charset_info); + { + $2->set_name($4.str, $4.length, system_charset_info); + $2->is_autogenerated_name= FALSE; + } else if (!$2->name) { char *str = $1; if (str[-1] == '`') @@ -4898,9 +4916,12 @@ udf_expr: remember_name expr remember_end select_alias { if ($4.str) - $2->set_name($4.str,$4.length,system_charset_info); + { + $2->set_name($4.str, $4.length, system_charset_info); + $2->is_autogenerated_name= FALSE; + } else - $2->set_name($1,(uint) ($3 - $1), YYTHD->charset()); + $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); $$= $2; } ; @@ -5079,7 +5100,7 @@ table_ref: ; join_table_list: - derived_table_list { TEST_ASSERT($$=$1); } + derived_table_list { YYERROR_UNLESS($$=$1); } ; /* Warning - may return NULL in case of incomplete SELECT */ @@ -5087,39 +5108,41 @@ derived_table_list: table_ref { $$=$1; } | derived_table_list ',' table_ref { - TEST_ASSERT($1 && ($$=$3)); + YYERROR_UNLESS($1 && ($$=$3)); } ; join_table: - table_ref normal_join table_ref { TEST_ASSERT($1 && ($$=$3)); } + table_ref normal_join table_ref { YYERROR_UNLESS($1 && ($$=$3)); } | table_ref STRAIGHT_JOIN table_factor - { TEST_ASSERT($1 && ($$=$3)); $3->straight=1; } + { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; } | table_ref normal_join table_ref ON expr - { TEST_ASSERT($1 && ($$=$3)); add_join_on($3,$5); } + { YYERROR_UNLESS($1 && ($$=$3)); add_join_on($3,$5); } + | table_ref STRAIGHT_JOIN table_factor ON expr + { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; add_join_on($3,$5); } | table_ref normal_join table_ref USING { SELECT_LEX *sel= Select; - TEST_ASSERT($1 && $3); + YYERROR_UNLESS($1 && $3); sel->save_names_for_using_list($1, $3); } '(' using_list ')' { add_join_on($3,$7); $$=$3; } | table_ref LEFT opt_outer JOIN_SYM table_ref ON expr - { TEST_ASSERT($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } + { YYERROR_UNLESS($1 && $5); add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | table_ref LEFT opt_outer JOIN_SYM table_factor { SELECT_LEX *sel= Select; - TEST_ASSERT($1 && $5); + YYERROR_UNLESS($1 && $5); sel->save_names_for_using_list($1, $5); } USING '(' using_list ')' { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor { - TEST_ASSERT($1 && $6); + YYERROR_UNLESS($1 && $6); add_join_natural($1,$6); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; @@ -5127,7 +5150,7 @@ join_table: | table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr { LEX *lex= Lex; - TEST_ASSERT($1 && $5); + YYERROR_UNLESS($1 && $5); if (!($$= lex->current_select->convert_right_join())) YYABORT; add_join_on($$, $7); @@ -5135,7 +5158,7 @@ join_table: | table_ref RIGHT opt_outer JOIN_SYM table_factor { SELECT_LEX *sel= Select; - TEST_ASSERT($1 && $5); + YYERROR_UNLESS($1 && $5); sel->save_names_for_using_list($1, $5); } USING '(' using_list ')' @@ -5147,14 +5170,14 @@ join_table: } | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor { - TEST_ASSERT($1 && $6); + YYERROR_UNLESS($1 && $6); add_join_natural($6,$1); LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; } | table_ref NATURAL JOIN_SYM table_factor - { TEST_ASSERT($1 && ($$=$4)); add_join_natural($1,$4); }; + { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4); }; normal_join: @@ -5183,7 +5206,7 @@ table_factor: sel->add_joined_table($$); } | '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}' - { TEST_ASSERT($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } + { YYERROR_UNLESS($3 && $7); add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } | select_derived_init get_select_lex select_derived2 { LEX *lex= Lex; @@ -5564,8 +5587,8 @@ opt_limit_clause_init: { LEX *lex= Lex; SELECT_LEX *sel= lex->current_select; - sel->offset_limit= 0L; - sel->select_limit= HA_POS_ERROR; + sel->offset_limit= 0; + sel->select_limit= 0; } | limit_clause {} ; @@ -5580,21 +5603,21 @@ limit_clause: ; limit_options: - ulong_num + limit_option { SELECT_LEX *sel= Select; sel->select_limit= $1; - sel->offset_limit= 0L; + sel->offset_limit= 0; sel->explicit_limit= 1; } - | ulong_num ',' ulong_num + | limit_option ',' limit_option { SELECT_LEX *sel= Select; sel->select_limit= $3; sel->offset_limit= $1; sel->explicit_limit= 1; } - | ulong_num OFFSET_SYM ulong_num + | limit_option OFFSET_SYM limit_option { SELECT_LEX *sel= Select; sel->select_limit= $1; @@ -5602,18 +5625,23 @@ limit_options: sel->explicit_limit= 1; } ; - +limit_option: + param_marker + | ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); } + | LONG_NUM { $$= new Item_uint($1.str, $1.length); } + | NUM { $$= new Item_uint($1.str, $1.length); } + ; delete_limit_clause: /* empty */ { LEX *lex=Lex; - lex->current_select->select_limit= HA_POS_ERROR; + lex->current_select->select_limit= 0; } - | LIMIT ulonglong_num + | LIMIT limit_option { SELECT_LEX *sel= Select; - sel->select_limit= (ha_rows) $2; + sel->select_limit= $2; sel->explicit_limit= 1; }; @@ -5669,7 +5697,8 @@ procedure_item: if (add_proc_to_list(lex->thd, $2)) YYABORT; if (!$2->name) - $2->set_name($1,(uint) ((char*) lex->tok_end - $1), YYTHD->charset()); + $2->set_name($1,(uint) ((char*) lex->tok_end - $1), + YYTHD->charset()); } ; @@ -6091,9 +6120,24 @@ insert_update_elem: simple_ident_nospvar equal expr_or_default { LEX *lex= Lex; + uint8 tmp= MY_ITEM_PREFER_1ST_TABLE; if (lex->update_list.push_back($1) || lex->value_list.push_back($3)) YYABORT; + /* + INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY + UPDATE a= a + b1.b + + Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items + to prevent find_field_in_tables() doing further item searching + if it finds item occurence in first table in insert_table_list. + This allows to avoid ambiguity in resolving 'a' field in + example above. + */ + $1->walk(&Item::set_flags_processor, + (byte *) &tmp); + $3->walk(&Item::set_flags_processor, + (byte *) &tmp); }; opt_low_priority: @@ -6127,10 +6171,17 @@ single_multi: | table_wild_list { mysql_init_multi_delete(Lex); } FROM join_table_list where_clause + { + if (multi_delete_set_locks_and_link_aux_tables(Lex)) + YYABORT; + } | FROM table_wild_list { mysql_init_multi_delete(Lex); } USING join_table_list where_clause - {} + { + if (multi_delete_set_locks_and_link_aux_tables(Lex)) + YYABORT; + } ; table_wild_list: @@ -6873,7 +6924,7 @@ param_marker: { THD *thd=YYTHD; LEX *lex= thd->lex; - if (thd->command == COM_PREPARE) + if (thd->command == COM_STMT_PREPARE) { Item_param *item= new Item_param((uint) (lex->tok_start - (uchar *) thd->query)); @@ -7980,8 +8031,8 @@ handler: LEX *lex=Lex; lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ - lex->current_select->select_limit= 1; - lex->current_select->offset_limit= 0L; + lex->current_select->select_limit= new Item_int((int32) 1); + lex->current_select->offset_limit= 0; if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; } @@ -8702,21 +8753,21 @@ xa: XA_SYM begin_or_start xid opt_join_or_resume xid: text_string { - TEST_ASSERT($1->length() <= MAXGTRIDSIZE); + YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE); if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID)))) YYABORT; Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0); } | text_string ',' text_string { - TEST_ASSERT($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE); + YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE); if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID)))) YYABORT; Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length()); } | text_string ',' text_string ',' ulong_num { - TEST_ASSERT($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE); + YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE); if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID)))) YYABORT; Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length()); diff --git a/sql/structs.h b/sql/structs.h index 8f053f20776..03176b47360 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,6 +20,8 @@ struct st_table; class Field; +#define STRING_WITH_LEN(X) X, (sizeof(X)-1) + typedef struct st_lex_string { char *str; diff --git a/sql/table.cc b/sql/table.cc index 234fdbf5ef3..4ddaeeea248 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -163,7 +163,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, if (share->frm_version == FRM_VER_TRUE_VARCHAR -1 && head[33] == 5) share->frm_version= FRM_VER_TRUE_VARCHAR; - share->db_type= ha_checktype((enum db_type) (uint) *(head+3)); + share->db_type= ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0); share->db_create_options= db_create_options=uint2korr(head+30); share->db_options_in_use= share->db_create_options; share->mysql_version= uint4korr(head+51); @@ -1344,8 +1344,8 @@ void append_unescaped(String *res, const char *pos, uint length) /* Create a .frm file */ -File create_frm(register my_string name, uint reclength, uchar *fileinfo, - HA_CREATE_INFO *create_info, uint keys) +File create_frm(THD *thd, register my_string name, uint reclength, + uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys) { register File file; ulong length; @@ -1378,7 +1378,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, fileinfo[1]= 1; fileinfo[2]= FRM_VER+3+ test(create_info->varchar); - fileinfo[3]= (uchar) ha_checktype(create_info->db_type); + fileinfo[3]= (uchar) ha_checktype(thd,create_info->db_type,0,0); fileinfo[4]=1; int2store(fileinfo+6,IO_SIZE); /* Next block starts here */ key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16; @@ -1640,7 +1640,7 @@ bool check_column_name(const char *name) ** Get type of table from .frm file */ -db_type get_table_type(const char *name) +db_type get_table_type(THD *thd, const char *name) { File file; uchar head[4]; @@ -1656,7 +1656,7 @@ db_type get_table_type(const char *name) (head[2] != FRM_VER && head[2] != FRM_VER+1 && (head[2] < FRM_VER+3 || head[2] > FRM_VER+4))) DBUG_RETURN(DB_TYPE_UNKNOWN); - DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3))); + DBUG_RETURN(ha_checktype(thd,(enum db_type) (uint) *(head+3),0,0)); } @@ -1929,7 +1929,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, (check_opt_type == VIEW_CHECK_CASCADED && ancestor->check_option)) { - Item_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->current_arena, backup; TABLE_LIST *tbl= this; if (arena->is_conventional()) arena= 0; // For easier test @@ -2019,7 +2019,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, /* full text function moving to current select */ if (view->select_lex.ftfunc_list->elements) { - Item_arena *arena= thd->current_arena, backup; + Query_arena *arena= thd->current_arena, backup; if (arena->is_conventional()) arena= 0; // For easier test else @@ -2239,7 +2239,7 @@ const char *Field_iterator_view::name() ** Instansiate templates *****************************************************************************/ -#ifdef __GNUC__ +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class List<String>; template class List_iterator<String>; #endif diff --git a/sql/unireg.cc b/sql/unireg.cc index a93f358c011..2ea79d92e37 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -113,7 +113,7 @@ bool mysql_create_frm(THD *thd, my_string file_name, } reclength=uint2korr(forminfo+266); - if ((file=create_frm(file_name, reclength, fileinfo, + if ((file=create_frm(thd, file_name, reclength, fileinfo, create_info, keys)) < 0) { my_free((gptr) screen_buff,MYF(0)); |