From: Mattias Jonsson Date: May 29 2012 12:53pm Subject: bzr push into mysql-trunk branch (mattias.jonsson:3903 to 3904) WL#4443 List-Archive: http://lists.mysql.com/commits/144003 Message-Id: <201205291253.q4TCrWhD010017@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3904 Mattias Jonsson 2012-05-29 WL#4443 Addressed some minor review comments from dlenev: - Removed get_timestamp_field from ndb code. - Added comments. - Removed Item_func_sp::can_be_evaluated_now, since it was the same as the default implementation. - Removed unneccesary check of has_subquery when is_const_item_pruned was set. - Reverted refactor of default_record function. modified: mysql-test/r/partition_locking.result mysql-test/t/partition_locking.test sql/ha_ndbcluster.cc sql/item.h sql/item_func.cc sql/item_func.h sql/opt_range.cc sql/partition_info.cc sql/partition_info.h sql/sql_executor.cc sql/sql_insert.cc sql/sql_insert.h sql/sql_partition_admin.cc 3903 Mattias Jonsson 2012-05-22 [merge] WL#4443: Remove scalability problem with many lock's and external lock's on partitioned tables with many partitions Merged into the latest mysql-trunk. removed: mysql-test/r/grant_cache_ps_prot.result mysql-test/t/grant_cache_ps_prot.test added: mysql-test/collections/mysql-trunk-wl4443.push mysql-test/include/partition_default_functions.inc mysql-test/r/partition_locking.result mysql-test/t/partition_locking.test renamed: mysql-test/r/grant_cache_no_prot.result => mysql-test/r/grant_cache.result mysql-test/t/grant_cache_no_prot.test => mysql-test/t/grant_cache.test modified: include/my_bitmap.h include/my_time.h mysql-test/include/commit.inc mysql-test/include/grant_cache.inc mysql-test/include/handler.inc mysql-test/r/commit_1innodb.result mysql-test/r/explain.result mysql-test/r/func_if.result mysql-test/r/handler_innodb.result mysql-test/r/handler_myisam.result mysql-test/r/innodb_explain_json_non_select_all.result mysql-test/r/innodb_explain_json_non_select_none.result mysql-test/r/innodb_explain_non_select_all.result mysql-test/r/innodb_explain_non_select_none.result mysql-test/r/myisam_explain_json_non_select_all.result mysql-test/r/myisam_explain_json_non_select_none.result mysql-test/r/myisam_explain_non_select_all.result mysql-test/r/myisam_explain_non_select_none.result mysql-test/r/partition_binlog.result mysql-test/r/partition_explicit_prune.result mysql-test/r/partition_pruning.result mysql-test/r/partition_truncate.result mysql-test/r/type_date.result mysql-test/suite/binlog/r/binlog_unsafe.result mysql-test/suite/opt_trace/r/bugs_no_prot_all.result mysql-test/suite/opt_trace/r/bugs_no_prot_none.result mysql-test/suite/opt_trace/r/bugs_ps_prot_all.result mysql-test/suite/opt_trace/r/bugs_ps_prot_none.result mysql-test/suite/parts/inc/partition-dml-1-9.inc mysql-test/suite/parts/r/partition-dml-1-9-innodb.result mysql-test/suite/parts/r/partition-dml-1-9-myisam.result mysql-test/suite/parts/r/partition_debug_sync_innodb.result mysql-test/suite/parts/t/partition_debug_sync_innodb.test mysql-test/suite/perfschema/r/part_table_io.result mysql-test/suite/perfschema/r/stage_mdl_function.result mysql-test/t/explain.test mysql-test/t/partition_binlog.test mysql-test/t/partition_explicit_prune.test mysql-test/t/partition_pruning.test mysql-test/t/partition_truncate.test mysql-test/t/type_date.test mysys/my_bitmap.c sql/ha_partition.cc sql/ha_partition.h sql/handler.cc sql/handler.h sql/item.cc sql/item.h sql/item_cmpfunc.cc sql/item_func.cc sql/item_func.h sql/item_strfunc.h sql/item_subselect.cc sql/opt_explain.cc sql/opt_range.cc sql/partition_info.cc sql/partition_info.h sql/rpl_info_table_access.cc sql/share/errmsg-utf8.txt sql/sp.cc sql/sql_base.cc sql/sql_base.h sql/sql_cache.h sql/sql_class.h sql/sql_data_change.h sql/sql_delete.cc sql/sql_executor.cc sql/sql_handler.cc sql/sql_insert.cc sql/sql_insert.h sql/sql_lex.cc sql/sql_lex.h sql/sql_optimizer.cc sql/sql_parse.cc sql/sql_parse.h sql/sql_partition.cc sql/sql_partition.h sql/sql_partition_admin.cc sql/sql_prepare.cc sql/sql_resolver.cc sql/sql_select.cc sql/sql_select.h sql/sql_show.cc sql/sql_tmp_table.cc sql/sql_trigger.cc sql/sql_trigger.h sql/sql_union.cc sql/sql_update.cc sql/sql_view.cc sql/table.cc sql/table.h unittest/gunit/my_bitmap-t.cc mysql-test/r/grant_cache.result mysql-test/t/grant_cache.test === modified file 'mysql-test/r/partition_locking.result' --- a/mysql-test/r/partition_locking.result revid:mattias.jonsson@stripped +++ b/mysql-test/r/partition_locking.result revid:mattias.jonsson@stripped @@ -3307,7 +3307,6 @@ HANDLER_WRITE 18 # # Test of views # -# Found bug#13559657 (partition selection does not work with views) FLUSH STATUS; CREATE VIEW v1_25 AS SELECT a, b FROM t1 PARTITION (p2, p5); SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS @@ -3396,7 +3395,6 @@ HANDLER_COMMIT 1 HANDLER_EXTERNAL_LOCK 4 HANDLER_WRITE 18 # 4 locks (1 table, 1 partition lock/unlock) -# Bug#13559657, this should fail! FLUSH STATUS; INSERT INTO v1_25_check VALUES (30, "Insert in v1_25_check fail"); ERROR HY000: Found a row not matching the given partition set === modified file 'mysql-test/t/partition_locking.test' --- a/mysql-test/t/partition_locking.test revid:mattias.jonsson@stripped +++ b/mysql-test/t/partition_locking.test revid:mattias.jonsson@stripped @@ -1057,7 +1057,6 @@ eval $get_handler_status_counts; --echo # --echo # Test of views --echo # ---echo # Found bug#13559657 (partition selection does not work with views) FLUSH STATUS; CREATE VIEW v1_25 AS SELECT a, b FROM t1 PARTITION (p2, p5); eval $get_handler_status_counts; @@ -1108,7 +1107,6 @@ INSERT INTO v1_25_check VALUES (31, "Ins eval $get_handler_status_counts; --echo # 4 locks (1 table, 1 partition lock/unlock) ---echo # Bug#13559657, this should fail! FLUSH STATUS; --error ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET INSERT INTO v1_25_check VALUES (30, "Insert in v1_25_check fail"); === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc revid:mattias.jonsson@stripped +++ b/sql/ha_ndbcluster.cc revid:mattias.jonsson@stripped @@ -2173,13 +2173,10 @@ int ha_ndbcluster::check_default_values( { Field* field= table->field[f]; // Use Field struct from MySQLD table rep const NdbDictionary::Column* ndbCol= ndbtab->getColumn(field->field_index); - bool isTimeStampWithAutoValue = ((field->type() == MYSQL_TYPE_TIMESTAMP) && - (field->table->get_timestamp_field() == field)); if ((! (field->flags & (PRI_KEY_FLAG | NO_DEFAULT_VALUE_FLAG))) && - (type_supports_default_value(field->real_type())) && - !isTimeStampWithAutoValue) + (type_supports_default_value(field->real_type()))) { /* We expect Ndb to have a native default for this * column @@ -8576,13 +8573,8 @@ static int create_ndb_column(THD *thd, if (likely( nativeDefaults )) { - /* Ndb does not support auto-set Timestamp default values natively */ - bool isTimeStampWithAutoValue = ((mysql_type == MYSQL_TYPE_TIMESTAMP) && - (field->table->get_timestamp_field() == field)); - if ((!(field->flags & PRI_KEY_FLAG) ) && - type_supports_default_value(mysql_type) && - !isTimeStampWithAutoValue) + type_supports_default_value(mysql_type)) { if (!(field->flags & NO_DEFAULT_VALUE_FLAG)) { === modified file 'sql/item.h' --- a/sql/item.h revid:mattias.jonsson@stripped +++ b/sql/item.h revid:mattias.jonsson@stripped @@ -724,6 +724,14 @@ public: subselect. Computed by fix_fields and updated by update_used_tables. */ + /** + This variable is a cache of 'Needed tables are locked'. True if either + 'No tables locks is needed' or 'Needed tables are locked'. + If tables are used, then it will be set to + current_thd->lex->is_query_tables_locked(). + + It is used when checking const_item()/can_be_evaluated_now(). + */ bool tables_locked_cache; public: // alloc & destruct is done as start of select using sql_alloc === modified file 'sql/item_func.cc' --- a/sql/item_func.cc revid:mattias.jonsson@stripped +++ b/sql/item_func.cc revid:mattias.jonsson@stripped @@ -6969,27 +6969,6 @@ void Item_func_sp::update_used_tables() } -/** - Check if it is OK to evaluate the item now. - - @return true if the item can be evaluated in the current statement state. - @retval true The item can be evaluated now. - @retval false The item can not be evaluated now, - (i.e. depend on non locked table). - - @note Stored procedures can only be evaluated after tables are locked. -*/ - -bool Item_func_sp::can_be_evaluated_now() const -{ - if (tables_locked_cache) - return true; - if (current_thd->lex->is_query_tables_locked()) - const_cast(this)->tables_locked_cache= true; - return tables_locked_cache; -} - - /* uuid_short handling. === modified file 'sql/item_func.h' --- a/sql/item_func.h revid:mattias.jonsson@stripped +++ b/sql/item_func.h revid:mattias.jonsson@stripped @@ -2136,7 +2136,6 @@ public: } virtual void update_null_value(); - virtual bool can_be_evaluated_now() const; }; === modified file 'sql/opt_range.cc' --- a/sql/opt_range.cc revid:mattias.jonsson@stripped +++ b/sql/opt_range.cc revid:mattias.jonsson@stripped @@ -3111,13 +3111,13 @@ bool prune_partitions(THD *thd, TABLE *t } /* - If the prepare stage only had constant items and no subqueries are used, - it is no use of running prune_partitions() twice on the same statement. + If the prepare stage only had constant items (also true when no subqueries + are used before locking), it is no use of running prune_partitions() twice + on the same statement. Since it will not be able to prune anything more than the previous call from the prepare step. */ - if (part_info->is_const_item_pruned && - !pprune_cond->has_subquery()) + if (part_info->is_const_item_pruned) DBUG_RETURN(false); PART_PRUNE_PARAM prune_param; === modified file 'sql/partition_info.cc' --- a/sql/partition_info.cc revid:mattias.jonsson@stripped +++ b/sql/partition_info.cc revid:mattias.jonsson@stripped @@ -25,7 +25,6 @@ #include "sql_acl.h" // *_ACL #include "table.h" // TABLE_LIST #include "my_bitmap.h" // bitmap* -#include "sql_insert.h" // default_record #include "sql_base.h" // fill_record #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -346,7 +345,6 @@ bool partition_info::can_prune_insert(TH If not all partitioning fields are given, we also must set all non given partitioning fields to get correct defaults. - we do this by copy the full default record in default_record(). TODO: If any gain, we could enhance this by only copy the needed default fields by 1) check which fields needs to be set. === modified file 'sql/partition_info.h' --- a/sql/partition_info.h revid:mattias.jonsson@stripped +++ b/sql/partition_info.h revid:mattias.jonsson@stripped @@ -323,6 +323,15 @@ public: COPY_INFO &info, bool copy_default_values, MY_BITMAP *used_partitions); + /** + PRUNE_NO - Unable to prune. + PRUNE_DEFAULTS - Partitioning field is only set to + DEFAULT values, only need to check + pruning for one row where the DEFAULTS + values are set. + PRUNE_YES - Pruning is possible, calculate the used partition set + by evaluate the partition_id on row by row basis. + */ enum enum_can_prune {PRUNE_NO=0, PRUNE_DEFAULTS, PRUNE_YES}; bool can_prune_insert(THD *thd, enum_duplicates duplic, === modified file 'sql/sql_executor.cc' --- a/sql/sql_executor.cc revid:mattias.jonsson@stripped +++ b/sql/sql_executor.cc revid:mattias.jonsson@stripped @@ -4410,6 +4410,8 @@ static int remove_dup_with_compare(THD * DBUG_RETURN(0); err: file->extra(HA_EXTRA_NO_CACHE); + if (file->inited) + (void) file->ha_rnd_end(); if (error) file->print_error(error,MYF(0)); DBUG_RETURN(1); === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc revid:mattias.jonsson@stripped +++ b/sql/sql_insert.cc revid:mattias.jonsson@stripped @@ -617,39 +617,6 @@ create_insert_stmt_from_insert_delayed(T /** - Set default values of record. - - @param copy_default_values Copy default row - (otherwise only delete marker + null bits) - @param table Table the record belongs to -*/ - -void default_record(bool copy_default_values, TABLE *table) -{ - if (copy_default_values) - restore_record(table,s->default_values); // Get empty record - else - { - TABLE_SHARE *share= table->s; - - /* - Fix delete marker. No need to restore rest of record since it will - be overwritten by fill_record() anyway (and fill_record() does not - use default values in this case). - */ - table->record[0][0]= share->default_values[0]; - - /* Fix undefined null_bits. */ - if (share->null_bytes > 1 && share->last_null_bit_pos) - { - table->record[0][share->null_bytes - 1]= - share->default_values[share->null_bytes - 1]; - } - } -} - - -/** INSERT statement implementation @note Like implementations of other DDL/DML in MySQL, this function @@ -817,6 +784,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *t Check the first INSERT value. Do not fail here, since that would break MyISAM behavior of inserting all rows before the failing row. + + PRUNE_DEFAULTS means the partitioning fields are only set to DEFAULT + values, so we only need to check the first INSERT value, since all the + rest will be in the same partition. */ if (table->part_info->set_used_partition(fields, *values, @@ -1006,7 +977,26 @@ bool mysql_insert(THD *thd,TABLE_LIST *t } else { - default_record(thd->lex->used_tables, table); + if (thd->lex->used_tables) // Column used in values() + restore_record(table,s->default_values); // Get empty record + else + { + TABLE_SHARE *share= table->s; + + /* + Fix delete marker. No need to restore rest of record since it will + be overwritten by fill_record() anyway (and fill_record() does not + use default values in this case). + */ + table->record[0][0]= share->default_values[0]; + + /* Fix undefined null_bits. */ + if (share->null_bytes > 1 && share->last_null_bit_pos) + { + table->record[0][share->null_bytes - 1]= + share->default_values[share->null_bytes - 1]; + } + } if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0, table->triggers, TRG_EVENT_INSERT)) @@ -4058,7 +4048,7 @@ select_create::prepare(List &value /** - Lock the newly created table. + Lock the newly created table and prepare it for insertion. @return Operation status. @retval 0 Success === modified file 'sql/sql_insert.h' --- a/sql/sql_insert.h revid:mattias.jonsson@stripped +++ b/sql/sql_insert.h revid:mattias.jonsson@stripped @@ -40,7 +40,6 @@ int check_that_all_fields_are_given_valu void prepare_triggers_for_insert_stmt(TABLE *table); int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update); -void default_record(bool copy_default_values, TABLE *table); void kill_delayed_threads(void); #ifdef EMBEDDED_LIBRARY === modified file 'sql/sql_partition_admin.cc' --- a/sql/sql_partition_admin.cc revid:mattias.jonsson@stripped +++ b/sql/sql_partition_admin.cc revid:mattias.jonsson@stripped @@ -741,7 +741,6 @@ bool Sql_cmd_alter_table_truncate_partit ulong timeout= thd->variables.lock_wait_timeout; TABLE_LIST *first_table= thd->lex->select_lex.table_list.first; Alter_info *alter_info= &thd->lex->alter_info; - MDL_savepoint mdl_savepoint; uint table_counter, i; List partition_names_list; bool binlog_stmt; @@ -768,7 +767,6 @@ bool Sql_cmd_alter_table_truncate_partit if (check_one_table_access(thd, DROP_ACL, first_table)) DBUG_RETURN(TRUE); - mdl_savepoint= thd->mdl_context.mdl_savepoint(); if (open_tables(thd, &first_table, &table_counter, 0)) DBUG_RETURN(true); @@ -783,7 +781,10 @@ bool Sql_cmd_alter_table_truncate_partit } - /* Prune all, but named partitions */ + /* + Prune all, but named partitions, + to avoid excessive calls to external_lock(). + */ List_iterator partition_names_it(alter_info->partition_names); uint num_names= alter_info->partition_names.elements; for (i= 0; i < num_names; i++) No bundle (reason: useless for push emails).