diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_partition.cc | 67 | ||||
-rw-r--r-- | sql/ha_partition.h | 4 | ||||
-rw-r--r-- | sql/item.cc | 11 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 86 | ||||
-rw-r--r-- | sql/item_subselect.cc | 53 | ||||
-rw-r--r-- | sql/net_serv.cc | 12 | ||||
-rw-r--r-- | sql/opt_range.cc | 11 | ||||
-rw-r--r-- | sql/sql_cache.cc | 59 | ||||
-rw-r--r-- | sql/sql_class.cc | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 37 | ||||
-rw-r--r-- | sql/sql_table.cc | 1 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 9 |
12 files changed, 282 insertions, 72 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 624ef1aff5b..ee24a36985e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -232,6 +232,8 @@ void ha_partition::init_handler_variables() m_innodb= FALSE; m_extra_cache= FALSE; m_extra_cache_size= 0; + m_extra_prepare_for_update= FALSE; + m_extra_cache_part_id= NO_CURRENT_PART_ID; m_handler_status= handler_not_initialized; m_low_byte_first= 1; m_part_field_array= NULL; @@ -5380,9 +5382,6 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info, when performing the sequential scan we will check this recorded value and call extra_opt whenever we start scanning a new partition. - monty: Neads to be fixed so that it's passed to all handlers when we - move to another partition during table scan. - HA_EXTRA_NO_CACHE: When performing a UNION SELECT HA_EXTRA_NO_CACHE is called from the flush method in the select_union class. @@ -5394,7 +5393,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info, for. If no cache is in use they will quickly return after finding this out. And we also ensure that all caches are disabled and no one is left by mistake. - In the future this call will probably be deleted an we will instead call + In the future this call will probably be deleted and we will instead call ::reset(); HA_EXTRA_WRITE_CACHE: @@ -5406,8 +5405,9 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info, This is called as part of a multi-table update. When the table to be updated is also scanned then this informs MyISAM handler to drop any caches if dynamic records are used (fixed size records do not care - about this call). We pass this along to all underlying MyISAM handlers - and ignore it for the rest. + about this call). We pass this along to the first partition to scan, and + flag that it is to be called after HA_EXTRA_CACHE when moving to the next + partition to scan. HA_EXTRA_PREPARE_FOR_DROP: Only used by MyISAM, called in preparation for a DROP TABLE. @@ -5554,9 +5554,21 @@ int ha_partition::extra(enum ha_extra_function operation) case HA_EXTRA_PREPARE_FOR_RENAME: DBUG_RETURN(prepare_for_rename()); break; + case HA_EXTRA_PREPARE_FOR_UPDATE: + DBUG_ASSERT(m_extra_cache); + /* + Needs to be run on the first partition in the range now, and + later in late_extra_cache, when switching to a new partition to scan. + */ + m_extra_prepare_for_update= TRUE; + if (m_part_spec.start_part != NO_CURRENT_PART_ID) + { + DBUG_ASSERT(m_extra_cache_part_id == m_part_spec.start_part); + VOID(m_file[m_part_spec.start_part]->extra(HA_EXTRA_PREPARE_FOR_UPDATE)); + } + break; case HA_EXTRA_NORMAL: case HA_EXTRA_QUICK: - case HA_EXTRA_PREPARE_FOR_UPDATE: case HA_EXTRA_FORCE_REOPEN: case HA_EXTRA_PREPARE_FOR_DROP: case HA_EXTRA_FLUSH_CACHE: @@ -5579,10 +5591,22 @@ int ha_partition::extra(enum ha_extra_function operation) break; } case HA_EXTRA_NO_CACHE: + { + int ret= 0; + if (m_extra_cache_part_id != NO_CURRENT_PART_ID) + ret= m_file[m_extra_cache_part_id]->extra(HA_EXTRA_NO_CACHE); + m_extra_cache= FALSE; + m_extra_cache_size= 0; + m_extra_prepare_for_update= FALSE; + m_extra_cache_part_id= NO_CURRENT_PART_ID; + DBUG_RETURN(ret); + } case HA_EXTRA_WRITE_CACHE: { m_extra_cache= FALSE; m_extra_cache_size= 0; + m_extra_prepare_for_update= FALSE; + m_extra_cache_part_id= NO_CURRENT_PART_ID; DBUG_RETURN(loop_extra(operation)); } case HA_EXTRA_IGNORE_NO_KEY: @@ -5710,6 +5734,7 @@ int ha_partition::extra_opt(enum ha_extra_function operation, ulong cachesize) void ha_partition::prepare_extra_cache(uint cachesize) { DBUG_ENTER("ha_partition::prepare_extra_cache()"); + DBUG_PRINT("info", ("cachesize %u", cachesize)); m_extra_cache= TRUE; m_extra_cache_size= cachesize; @@ -5768,16 +5793,18 @@ int ha_partition::loop_extra(enum ha_extra_function operation) { int result= 0, tmp; handler **file; + bool is_select; DBUG_ENTER("ha_partition::loop_extra()"); - /* - TODO, 5.2: this is where you could possibly add optimisations to add the bitmap - _if_ a SELECT. - */ + is_select= (thd_sql_command(ha_thd()) == SQLCOM_SELECT); for (file= m_file; *file; file++) { - if ((tmp= (*file)->extra(operation))) - result= tmp; + if (!is_select || + bitmap_is_set(&(m_part_info->used_partitions), file - m_file)) + { + if ((tmp= (*file)->extra(operation))) + result= tmp; + } } DBUG_RETURN(result); } @@ -5798,14 +5825,22 @@ void ha_partition::late_extra_cache(uint partition_id) { handler *file; DBUG_ENTER("ha_partition::late_extra_cache"); + DBUG_PRINT("info", ("extra_cache %u partid %u size %u", m_extra_cache, + partition_id, m_extra_cache_size)); - if (!m_extra_cache) + if (!m_extra_cache && !m_extra_prepare_for_update) DBUG_VOID_RETURN; file= m_file[partition_id]; if (m_extra_cache_size == 0) VOID(file->extra(HA_EXTRA_CACHE)); else VOID(file->extra_opt(HA_EXTRA_CACHE, m_extra_cache_size)); + if (m_extra_prepare_for_update) + { + DBUG_ASSERT(m_extra_cache); + VOID(file->extra(HA_EXTRA_PREPARE_FOR_UPDATE)); + } + m_extra_cache_part_id= partition_id; DBUG_VOID_RETURN; } @@ -5826,10 +5861,12 @@ void ha_partition::late_extra_no_cache(uint partition_id) handler *file; DBUG_ENTER("ha_partition::late_extra_no_cache"); - if (!m_extra_cache) + if (!m_extra_cache && !m_extra_prepare_for_update) DBUG_VOID_RETURN; file= m_file[partition_id]; VOID(file->extra(HA_EXTRA_NO_CACHE)); + DBUG_ASSERT(partition_id == m_extra_cache_part_id); + m_extra_cache_part_id= NO_CURRENT_PART_ID; DBUG_VOID_RETURN; } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index e3dc7d17c6d..feb2ddb9cfc 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -154,6 +154,10 @@ private: */ bool m_extra_cache; uint m_extra_cache_size; + /* The same goes for HA_EXTRA_PREPARE_FOR_UPDATE */ + bool m_extra_prepare_for_update; + /* Which partition has active cache */ + uint m_extra_cache_part_id; void init_handler_variables(); /* diff --git a/sql/item.cc b/sql/item.cc index 66c5314c16e..61dd8a97dcb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6970,14 +6970,16 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) enum_field_types field_type= field->type(); - if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME) + if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME || + field_type == MYSQL_TYPE_TIMESTAMP) { enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR; if (field_type == MYSQL_TYPE_DATE) type= MYSQL_TIMESTAMP_DATE; - if (field_type == MYSQL_TYPE_DATETIME) + if (field_type == MYSQL_TYPE_DATETIME || + field_type == MYSQL_TYPE_TIMESTAMP) type= MYSQL_TIMESTAMP_DATETIME; const char *field_name= field->field_name; @@ -7404,9 +7406,12 @@ bool Item_cache_row::null_inside() void Item_cache_row::bring_value() { + if (!example) + return; + example->bring_value(); + null_value= example->null_value; for (uint i= 0; i < item_count; i++) values[i]->bring_value(); - return; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fe4616f64d7..6987dd9e053 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1583,6 +1583,13 @@ int Arg_comparator::compare_row() bool was_null= 0; (*a)->bring_value(); (*b)->bring_value(); + + if ((*a)->null_value || (*b)->null_value) + { + owner->null_value= 1; + return -1; + } + uint n= (*a)->cols(); for (uint i= 0; i<n; i++) { @@ -1751,6 +1758,76 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) } +/** + The implementation of optimized \<outer expression\> [NOT] IN \<subquery\> + predicates. The implementation works as follows. + + For the current value of the outer expression + + - If it contains only NULL values, the original (before rewrite by the + Item_in_subselect rewrite methods) inner subquery is non-correlated and + was previously executed, there is no need to re-execute it, and the + previous return value is returned. + + - If it contains NULL values, check if there is a partial match for the + inner query block by evaluating it. For clarity we repeat here the + transformation previously performed on the sub-query. The expression + + <tt> + ( oc_1, ..., oc_n ) + \<in predicate\> + ( SELECT ic_1, ..., ic_n + FROM \<table\> + WHERE \<inner where\> + ) + </tt> + + was transformed into + + <tt> + ( oc_1, ..., oc_n ) + \<in predicate\> + ( SELECT ic_1, ..., ic_n + FROM \<table\> + WHERE \<inner where\> AND ... ( ic_k = oc_k OR ic_k IS NULL ) + HAVING ... NOT ic_k IS NULL + ) + </tt> + + The evaluation will now proceed according to special rules set up + elsewhere. These rules include: + + - The HAVING NOT \<inner column\> IS NULL conditions added by the + aforementioned rewrite methods will detect whether they evaluated (and + rejected) a NULL value and if so, will cause the subquery to evaluate + to NULL. + + - The added WHERE and HAVING conditions are present only for those inner + columns that correspond to outer column that are not NULL at the moment. + + - If there is an eligible index for executing the subquery, the special + access method "Full scan on NULL key" is employed which ensures that + the inner query will detect if there are NULL values resulting from the + inner query. This access method will quietly resort to table scan if it + needs to find NULL values as well. + + - Under these conditions, the sub-query need only be evaluated in order to + find out whether it produced any rows. + + - If it did, we know that there was a partial match since there are + NULL values in the outer row expression. + + - If it did not, the result is FALSE or UNKNOWN. If at least one of the + HAVING sub-predicates rejected a NULL value corresponding to an outer + non-NULL, and hence the inner query block returns UNKNOWN upon + evaluation, there was a partial match and the result is UNKNOWN. + + - If it contains no NULL values, the call is forwarded to the inner query + block. + + @see Item_in_subselect::val_bool() + @see Item_is_not_null_test::val_int() + */ longlong Item_in_optimizer::val_int() { bool tmp; @@ -1804,7 +1881,7 @@ longlong Item_in_optimizer::val_int() all_left_cols_null= false; } - if (!((Item_in_subselect*)args[1])->is_correlated && + if (!item_subs->is_correlated && all_left_cols_null && result_for_null_param != UNKNOWN) { /* @@ -1818,8 +1895,11 @@ longlong Item_in_optimizer::val_int() else { /* The subquery has to be evaluated */ - (void) args[1]->val_bool_result(); - null_value= !item_subs->engine->no_rows(); + (void) item_subs->val_bool_result(); + if (item_subs->engine->no_rows()) + null_value= item_subs->null_value; + else + null_value= TRUE; if (all_left_cols_null) result_for_null_param= null_value; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b93ea6f241b..adce24e7799 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -47,7 +47,7 @@ Item_subselect::Item_subselect(): item value is NULL if select_subselect not changed this value (i.e. some rows will be found returned) */ - null_value= 1; + null_value= TRUE; } @@ -427,9 +427,9 @@ void Item_maxmin_subselect::print(String *str, enum_query_type query_type) void Item_singlerow_subselect::reset() { - null_value= 1; + null_value= TRUE; if (value) - value->null_value= 1; + value->null_value= TRUE; } @@ -566,7 +566,10 @@ bool Item_singlerow_subselect::null_inside() void Item_singlerow_subselect::bring_value() { - exec(); + if (!exec() && assigned()) + null_value= 0; + else + reset(); } double Item_singlerow_subselect::val_real() @@ -574,7 +577,7 @@ double Item_singlerow_subselect::val_real() DBUG_ASSERT(fixed == 1); if (!exec() && !value->null_value) { - null_value= 0; + null_value= FALSE; return value->val_real(); } else @@ -589,7 +592,7 @@ longlong Item_singlerow_subselect::val_int() DBUG_ASSERT(fixed == 1); if (!exec() && !value->null_value) { - null_value= 0; + null_value= FALSE; return value->val_int(); } else @@ -603,7 +606,7 @@ String *Item_singlerow_subselect::val_str(String *str) { if (!exec() && !value->null_value) { - null_value= 0; + null_value= FALSE; return value->val_str(str); } else @@ -618,7 +621,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value) { if (!exec() && !value->null_value) { - null_value= 0; + null_value= FALSE; return value->val_decimal(decimal_value); } else @@ -633,7 +636,7 @@ bool Item_singlerow_subselect::val_bool() { if (!exec() && !value->null_value) { - null_value= 0; + null_value= FALSE; return value->val_bool(); } else @@ -651,7 +654,7 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): bool val_bool(); init(select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; - null_value= 0; //can't be NULL + null_value= FALSE; //can't be NULL maybe_null= 0; //can't be NULL value= 0; DBUG_VOID_RETURN; @@ -814,15 +817,14 @@ double Item_in_subselect::val_real() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); - null_value= 0; + null_value= was_null= FALSE; if (exec()) { reset(); - null_value= 1; return 0; } if (was_null && !value) - null_value= 1; + null_value= TRUE; return (double) value; } @@ -835,15 +837,14 @@ longlong Item_in_subselect::val_int() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); - null_value= 0; + null_value= was_null= FALSE; if (exec()) { reset(); - null_value= 1; return 0; } if (was_null && !value) - null_value= 1; + null_value= TRUE; return value; } @@ -856,16 +857,15 @@ String *Item_in_subselect::val_str(String *str) */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); - null_value= 0; + null_value= was_null= FALSE; if (exec()) { reset(); - null_value= 1; return 0; } if (was_null && !value) { - null_value= 1; + null_value= TRUE; return 0; } str->set((ulonglong)value, &my_charset_bin); @@ -876,20 +876,14 @@ String *Item_in_subselect::val_str(String *str) bool Item_in_subselect::val_bool() { DBUG_ASSERT(fixed == 1); - null_value= 0; + null_value= was_null= FALSE; if (exec()) { reset(); - /* - Must mark the IN predicate as NULL so as to make sure an enclosing NOT - predicate will return FALSE. See the comments in - subselect_uniquesubquery_engine::copy_ref_key for further details. - */ - null_value= 1; return 0; } if (was_null && !value) - null_value= 1; + null_value= TRUE; return value; } @@ -900,16 +894,15 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) method should not be used */ DBUG_ASSERT(0); - null_value= 0; + null_value= was_null= FALSE; DBUG_ASSERT(fixed == 1); if (exec()) { reset(); - null_value= 1; return 0; } if (was_null && !value) - null_value= 1; + null_value= TRUE; int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); return decimal_value; } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 38ab3a70136..f3f6f1bd9a0 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -170,7 +170,17 @@ my_bool net_realloc(NET *net, size_t length) DBUG_ENTER("net_realloc"); DBUG_PRINT("enter",("length: %lu", (ulong) length)); - if (length >= net->max_packet_size) + /* + When compression is off, net->where_b is always 0. + With compression turned on, net->where_b may indicate + that we still have a piece of the previous logical + packet in the buffer, unprocessed. Take it into account + when checking that max_allowed_packet is not exceeded. + This ensures that the client treats max_allowed_packet + limit identically, regardless of compression being on + or off. + */ + if (length >= (net->max_packet_size + net->where_b)) { DBUG_PRINT("error", ("Packet too large. Max size: %lu", net->max_packet_size)); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index eae79e63c19..d4a2bc3b138 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -8451,9 +8451,14 @@ int QUICK_RANGE_SELECT::reset() in_range= FALSE; cur_range= (QUICK_RANGE**) ranges.buffer; - if (file->inited == handler::NONE && (error= file->ha_index_init(index,1))) - DBUG_RETURN(error); - + if (file->inited == handler::NONE) + { + if (in_ror_merged_scan) + head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap); + if ((error= file->ha_index_init(index,1))) + DBUG_RETURN(error); + } + /* Do not allocate the buffers twice. */ if (multi_range_length) { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index fcf4edbdc22..22bdb24fb16 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1330,6 +1330,55 @@ end: } +/** + Send a single memory block from the query cache. + + Respects the client/server protocol limits for the + size of the network packet, and splits a large block + in pieces to ensure that individual piece doesn't exceed + the maximal allowed size of the network packet (16M). + + @param[in] net NET handler + @param[in] packet packet to send + @param[in] len packet length + + @return Operation status + @retval FALSE On success + @retval TRUE On error +*/ +static bool +send_data_in_chunks(NET *net, const uchar *packet, ulong len) +{ + /* + On the client we may require more memory than max_allowed_packet + to keep, both, the truncated last logical packet, and the + compressed next packet. This never (or in practice never) + happens without compression, since without compression it's very + unlikely that a) a truncated logical packet would remain on the + client when it's time to read the next packet b) a subsequent + logical packet that is being read would be so large that + size-of-new-packet + size-of-old-packet-tail > + max_allowed_packet. To remedy this issue, we send data in 1MB + sized packets, that's below the current client default of 16MB + for max_allowed_packet, but large enough to ensure there is no + unnecessary overhead from too many syscalls per result set. + */ + static const ulong MAX_CHUNK_LENGTH= 1024*1024; + + while (len > MAX_CHUNK_LENGTH) + { + if (net_real_write(net, packet, MAX_CHUNK_LENGTH)) + return TRUE; + packet+= MAX_CHUNK_LENGTH; + len-= MAX_CHUNK_LENGTH; + } + if (len && net_real_write(net, packet, len)) + return TRUE; + + return FALSE; +} + + /* Check if the query is in the cache. If it was cached, send it to the user. @@ -1635,11 +1684,11 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", ALIGN_SIZE(sizeof(Query_cache_result))))); Query_cache_result *result = result_block->result(); - if (net_real_write(&thd->net, result->data(), - result_block->used - - result_block->headers_len() - - ALIGN_SIZE(sizeof(Query_cache_result)))) - break; // Client aborted + if (send_data_in_chunks(&thd->net, result->data(), + result_block->used - + result_block->headers_len() - + ALIGN_SIZE(sizeof(Query_cache_result)))) + break; // Client aborted result_block = result_block->next; thd->net.pkt_nr= query->last_pkt_nr; // Keep packet number updated } while (result_block != first_result_block); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7c52e6957cc..44bb6d51c6c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -91,7 +91,9 @@ extern "C" void free_user_var(user_var_entry *entry) bool Key_part_spec::operator==(const Key_part_spec& other) const { - return length == other.length && !strcmp(field_name, other.field_name); + return length == other.length && + !my_strcasecmp(system_charset_info, field_name, + other.field_name); } /** diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4a32ca34790..1a4c12d6940 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1487,6 +1487,15 @@ JOIN::optimize() if (order) { /* + Do we need a temporary table due to the ORDER BY not being equal to + the GROUP BY? The call to test_if_skip_sort_order above tests for the + GROUP BY clause only and hence is not valid in this case. So the + estimated number of rows to be read from the first table is not valid. + We clear it here so that it doesn't show up in EXPLAIN. + */ + if (need_tmp && (select_options & SELECT_DESCRIBE) != 0) + join_tab[const_tables].limit= 0; + /* Force using of tmp table if sorting by a SP or UDF function due to their expensive and probably non-deterministic nature. */ @@ -11157,22 +11166,20 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) if (error == NESTED_LOOP_NO_MORE_ROWS) error= NESTED_LOOP_OK; + if (table == NULL) // If sending data to client + /* + The following will unlock all cursors if the command wasn't an + update command + */ + join->join_free(); // Unlock all cursors if (error == NESTED_LOOP_OK) { /* Sic: this branch works even if rc != 0, e.g. when send_data above returns an error. */ - if (!table) // If sending data to client - { - /* - The following will unlock all cursors if the command wasn't an - update command - */ - join->join_free(); // Unlock all cursors - if (join->result->send_eof()) - rc= 1; // Don't send error - } + if (table == NULL && join->result->send_eof()) // If sending data to client + rc= 1; // Don't send error DBUG_PRINT("info",("%ld records output", (long) join->send_records)); } else @@ -16664,7 +16671,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (tab->select && tab->select->quick) examined_rows= tab->select->quick->records; else if (tab->type == JT_NEXT || tab->type == JT_ALL) - examined_rows= tab->limit ? tab->limit : tab->table->file->records(); + { + if (tab->limit) + examined_rows= tab->limit; + else + { + tab->table->file->info(HA_STATUS_VARIABLE); + examined_rows= tab->table->file->stats.records; + } + } else examined_rows=(ha_rows)join->best_positions[i].records_read; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d3ac2bf0f95..7a7446c7f79 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3325,6 +3325,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_part_info->length=(uint16) length; /* Use packed keys for long strings on the first column */ if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && + !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) && (length >= KEY_DEFAULT_PACK_LENGTH && (sql_field->sql_type == MYSQL_TYPE_STRING || sql_field->sql_type == MYSQL_TYPE_VARCHAR || diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index bf4a46a4c67..9348feaa22a 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1989,6 +1989,7 @@ bool Table_triggers_list::process_triggers(THD *thd, bool err_status; Sub_statement_state statement_state; sp_head *sp_trigger= bodies[event][time_type]; + SELECT_LEX *save_current_select; if (sp_trigger == NULL) return FALSE; @@ -2012,11 +2013,19 @@ bool Table_triggers_list::process_triggers(THD *thd, thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); + /* + Reset current_select before call execute_trigger() and + restore it after return from one. This way error is set + in case of failure during trigger execution. + */ + save_current_select= thd->lex->current_select; + thd->lex->current_select= NULL; err_status= sp_trigger->execute_trigger(thd, &trigger_table->s->db, &trigger_table->s->table_name, &subject_table_grants[event][time_type]); + thd->lex->current_select= save_current_select; thd->restore_sub_statement_state(&statement_state); |