]> git.pld-linux.org Git - packages/mysql.git/blobdiff - innodb_stats.patch
- more unpackaged files
[packages/mysql.git] / innodb_stats.patch
index 70af576ce0cf2a25fba1f70f5d6e944bfc462866..8e7902673444bb487e3df67dd17365c709f56a65 100644 (file)
@@ -5,403 +5,8 @@
 #!!! notice !!!
 # Any small change to this file in the main branch
 # should be done or reviewed by the maintainer!
-diff -ruN a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
---- a/storage/innobase/btr/btr0cur.c   2010-12-03 15:49:59.165212710 +0900
-+++ b/storage/innobase/btr/btr0cur.c   2010-12-03 17:19:24.834126874 +0900
-@@ -1010,6 +1010,107 @@
-       }
- }
-+/**********************************************************************//**
-+Positions a cursor at a randomly chosen position within a B-tree
-+after the given path
-+@return TRUE if the position is at the first page, and cursor must point
-+        the first record for used by the caller.*/
-+UNIV_INTERN
-+ibool
-+btr_cur_open_at_rnd_pos_after_path(
-+/*====================*/
-+      dict_index_t*   index,          /*!< in: index */
-+      ulint           latch_mode,     /*!< in: BTR_SEARCH_LEAF, ... */
-+      btr_path_t*     first_rec_path,
-+      btr_cur_t*      cursor,         /*!< in/out: B-tree cursor */
-+      mtr_t*          mtr)            /*!< in: mtr */
-+{
-+      page_cur_t*     page_cursor;
-+      btr_path_t*     slot;
-+      ibool           is_first_rec    = TRUE;
-+      ulint           page_no;
-+      ulint           space;
-+      ulint           zip_size;
-+      ulint           height;
-+      rec_t*          node_ptr;
-+      mem_heap_t*     heap            = NULL;
-+      ulint           offsets_[REC_OFFS_NORMAL_SIZE];
-+      ulint*          offsets         = offsets_;
-+      rec_offs_init(offsets_);
-+
-+      if (latch_mode == BTR_MODIFY_TREE) {
-+              mtr_x_lock(dict_index_get_lock(index), mtr);
-+      } else {
-+              mtr_s_lock(dict_index_get_lock(index), mtr);
-+      }
-+
-+      page_cursor = btr_cur_get_page_cur(cursor);
-+      cursor->index = index;
-+
-+      space = dict_index_get_space(index);
-+      zip_size = dict_table_zip_size(index->table);
-+      page_no = dict_index_get_page(index);
-+
-+      height = ULINT_UNDEFINED;
-+      slot = first_rec_path;
-+
-+      for (;;) {
-+              buf_block_t*    block;
-+              page_t*         page;
-+
-+              block = buf_page_get_gen(space, zip_size, page_no,
-+                                       RW_NO_LATCH, NULL, BUF_GET,
-+                                       __FILE__, __LINE__, mtr);
-+              page = buf_block_get_frame(block);
-+              ut_ad(index->id == btr_page_get_index_id(page));
-+
-+              if (height == ULINT_UNDEFINED) {
-+                      /* We are in the root node */
-+
-+                      height = btr_page_get_level(page, mtr);
-+              }
-+
-+              if (height == 0) {
-+                      btr_cur_latch_leaves(page, space, zip_size, page_no,
-+                                           latch_mode, cursor, mtr);
-+              }
-+
-+              if (is_first_rec && slot->nth_rec != ULINT_UNDEFINED) {
-+                      if (height == 0) {
-+                              /* must open the first rec */
-+                              page_cur_open_on_nth_user_rec(block, page_cursor, slot->nth_rec);
-+                      } else {
-+                              is_first_rec = page_cur_open_on_rnd_user_rec_after_nth(block,
-+                                                              page_cursor, slot->nth_rec);
-+                      }
-+              } else {
-+                      is_first_rec = FALSE;
-+                      page_cur_open_on_rnd_user_rec(block, page_cursor);
-+              }
-+
-+              if (height == 0) {
-+                      break;
-+              }
-+
-+              ut_ad(height > 0);
-+
-+              height--;
-+              slot++;
-+
-+              node_ptr = page_cur_get_rec(page_cursor);
-+              offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
-+                                        ULINT_UNDEFINED, &heap);
-+              /* Go to the child node */
-+              page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
-+      }
-+
-+      if (UNIV_LIKELY_NULL(heap)) {
-+              mem_heap_free(heap);
-+      }
-+
-+      return (is_first_rec);
-+}
-+
- /*==================== B-TREE INSERT =========================*/
- /*************************************************************//**
-@@ -3479,6 +3580,154 @@
- }
- /*******************************************************************//**
-+Estimates the number of pages which have not null value of the key of n_cols.
-+@return       estimated number of pages */
-+UNIV_INTERN
-+ulint
-+btr_estimate_n_pages_not_null(
-+/*=========================*/
-+      dict_index_t*   index,  /*!< in: index */
-+      ulint           n_cols, /*!< in: The cols should be not null */
-+      btr_path_t*     path1)  /*!< in: path1[BTR_PATH_ARRAY_N_SLOTS] */
-+{
-+      dtuple_t*       tuple1;
-+      btr_path_t      path2[BTR_PATH_ARRAY_N_SLOTS];
-+      btr_cur_t       cursor;
-+      btr_path_t*     slot1;
-+      btr_path_t*     slot2;
-+      ibool           diverged;
-+      ibool           diverged_lot;
-+      ulint           divergence_level;
-+      ulint           n_pages;
-+      ulint           i;
-+      mtr_t           mtr;
-+      mem_heap_t*     heap;
-+
-+      heap = mem_heap_create(n_cols * sizeof(dfield_t)
-+                              + sizeof(dtuple_t));
-+
-+      /* make tuple1 (NULL,NULL,,,) from n_cols */
-+      tuple1 = dtuple_create(heap, n_cols);
-+      dict_index_copy_types(tuple1, index, n_cols);
-+
-+      for (i = 0; i < n_cols; i++) {
-+              dfield_set_null(dtuple_get_nth_field(tuple1, i));
-+      }
-+
-+      mtr_start(&mtr);
-+
-+      cursor.path_arr = path1;
-+
-+      btr_cur_search_to_nth_level(index, 0, tuple1, PAGE_CUR_G,
-+                                  BTR_SEARCH_LEAF | BTR_ESTIMATE,
-+                                  &cursor, 0, __FILE__, __LINE__, &mtr);
-+
-+      mtr_commit(&mtr);
-+
-+
-+
-+      mtr_start(&mtr);
-+
-+      cursor.path_arr = path2;
-+
-+      btr_cur_open_at_index_side(FALSE, index,
-+                                 BTR_SEARCH_LEAF | BTR_ESTIMATE,
-+                                 &cursor, &mtr);
-+
-+      mtr_commit(&mtr);
-+
-+      mem_heap_free(heap);
-+
-+      /* We have the path information for the range in path1 and path2 */
-+
-+      n_pages = 1;
-+      diverged = FALSE;           /* This becomes true when the path is not
-+                                  the same any more */
-+      diverged_lot = FALSE;       /* This becomes true when the paths are
-+                                  not the same or adjacent any more */
-+      divergence_level = 1000000; /* This is the level where paths diverged
-+                                  a lot */
-+      for (i = 0; ; i++) {
-+              ut_ad(i < BTR_PATH_ARRAY_N_SLOTS);
-+
-+              slot1 = path1 + i;
-+              slot2 = path2 + i;
-+
-+              if ((slot1 + 1)->nth_rec == ULINT_UNDEFINED
-+                  || (slot2 + 1)->nth_rec == ULINT_UNDEFINED) {
-+
-+                      if (i > divergence_level + 1) {
-+                              /* In trees whose height is > 1 our algorithm
-+                              tends to underestimate: multiply the estimate
-+                              by 2: */
-+
-+                              n_pages = n_pages * 2;
-+                      }
-+
-+                      /* Do not estimate the number of rows in the range
-+                      to over 1 / 2 of the estimated rows in the whole
-+                      table */
-+
-+                      if (n_pages > index->stat_n_leaf_pages / 2) {
-+                              n_pages = index->stat_n_leaf_pages / 2;
-+
-+                              /* If there are just 0 or 1 rows in the table,
-+                              then we estimate all rows are in the range */
-+
-+                              if (n_pages == 0) {
-+                                      n_pages = index->stat_n_leaf_pages;
-+                              }
-+                      }
-+
-+                      return(n_pages);
-+              }
-+
-+              if (!diverged && slot1->nth_rec != slot2->nth_rec) {
-+
-+                      diverged = TRUE;
-+
-+                      if (slot1->nth_rec < slot2->nth_rec) {
-+                              n_pages = slot2->nth_rec - slot1->nth_rec;
-+
-+                              if (n_pages > 1) {
-+                                      diverged_lot = TRUE;
-+                                      divergence_level = i;
-+                              }
-+                      } else {
-+                              /* Maybe the tree has changed between
-+                              searches */
-+
-+                              return(10);
-+                      }
-+
-+              } else if (diverged && !diverged_lot) {
-+
-+                      if (slot1->nth_rec < slot1->n_recs
-+                          || slot2->nth_rec > 1) {
-+
-+                              diverged_lot = TRUE;
-+                              divergence_level = i;
-+
-+                              n_pages = 0;
-+
-+                              if (slot1->nth_rec < slot1->n_recs) {
-+                                      n_pages += slot1->n_recs
-+                                              - slot1->nth_rec;
-+                              }
-+
-+                              if (slot2->nth_rec > 1) {
-+                                      n_pages += slot2->nth_rec - 1;
-+                              }
-+                      }
-+              } else if (diverged_lot) {
-+
-+                      n_pages = (n_pages * (slot1->n_recs + slot2->n_recs))
-+                              / 2;
-+              }
-+      }
-+}
-+
-+/*******************************************************************//**
- Estimates the number of different key values in a given index, for
- each n-column prefix of the index where n <= dict_index_get_n_unique(index).
- The estimates are stored in the array index->stat_n_diff_key_vals. */
-@@ -3507,18 +3756,38 @@
-       ulint           offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
-       ulint*          offsets_rec     = offsets_rec_;
-       ulint*          offsets_next_rec= offsets_next_rec_;
-+      ulint           stats_method    = srv_stats_method;
-+      btr_path_t      first_rec_path[BTR_PATH_ARRAY_N_SLOTS];
-+      ulint           effective_pages; /* effective leaf pages */
-       rec_offs_init(offsets_rec_);
-       rec_offs_init(offsets_next_rec_);
-       n_cols = dict_index_get_n_unique(index);
-+      if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS) {
-+              /* estimate effective pages and path for the first effective record */
-+              /* TODO: make it work also for n_cols > 1. */
-+              effective_pages = btr_estimate_n_pages_not_null(index, 1 /*k*/, first_rec_path);
-+
-+              if (!effective_pages) {
-+                      for (j = 0; j <= n_cols; j++) {
-+                              index->stat_n_diff_key_vals[j] = (ib_int64_t)index->stat_n_leaf_pages;
-+                      }
-+                      return;
-+              } else if (effective_pages > index->stat_n_leaf_pages) {
-+                      effective_pages = index->stat_n_leaf_pages;
-+              }
-+      } else {
-+              effective_pages = index->stat_n_leaf_pages;
-+      }
-+
-       n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
-       /* It makes no sense to test more pages than are contained
-       in the index, thus we lower the number if it is too high */
--      if (srv_stats_sample_pages > index->stat_index_size) {
--              if (index->stat_index_size > 0) {
--                      n_sample_pages = index->stat_index_size;
-+      if (srv_stats_sample_pages > effective_pages) {
-+              if (effective_pages > 0) {
-+                      n_sample_pages = effective_pages;
-               } else {
-                       n_sample_pages = 1;
-               }
-@@ -3530,9 +3799,15 @@
-       for (i = 0; i < n_sample_pages; i++) {
-               rec_t*  supremum;
-+              ibool   is_first_page = TRUE;
-               mtr_start(&mtr);
-+              if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS) {
-+                      is_first_page = btr_cur_open_at_rnd_pos_after_path(index, BTR_SEARCH_LEAF,
-+                                                                      first_rec_path, &cursor, &mtr);
-+              } else {
-               btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
-+              }
-               /* Count the number of different key values for each prefix of
-               the key on this index page. If the prefix does not determine
-@@ -3543,7 +3818,13 @@
-               page = btr_cur_get_page(&cursor);
-               supremum = page_get_supremum_rec(page);
-+              if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS && is_first_page) {
-+                      /* the cursor should be the first record of the page. */
-+                      /* Counting should be started from here. */
-+                      rec = btr_cur_get_rec(&cursor);
-+              } else {
-               rec = page_rec_get_next(page_get_infimum_rec(page));
-+              }
-               if (rec != supremum) {
-                       not_empty_flag = 1;
-@@ -3552,7 +3833,8 @@
-               }
-               while (rec != supremum) {
--                      rec_t*  next_rec = page_rec_get_next(rec);
-+                      rec_t*  next_rec;
-+                      next_rec = page_rec_get_next(rec);
-                       if (next_rec == supremum) {
-                               break;
-                       }
-@@ -3566,7 +3848,10 @@
-                       cmp_rec_rec_with_match(rec, next_rec,
-                                              offsets_rec, offsets_next_rec,
-                                              index, &matched_fields,
--                                             &matched_bytes);
-+                                             &matched_bytes,
-+                              (stats_method==SRV_STATS_METHOD_NULLS_NOT_EQUAL) ?
-+                              SRV_STATS_METHOD_NULLS_NOT_EQUAL :
-+                              SRV_STATS_METHOD_NULLS_EQUAL);
-                       for (j = matched_fields + 1; j <= n_cols; j++) {
-                               /* We add one if this index record has
-@@ -3627,7 +3912,7 @@
-       for (j = 0; j <= n_cols; j++) {
-               index->stat_n_diff_key_vals[j]
-                       = ((n_diff[j]
--                          * (ib_int64_t)index->stat_n_leaf_pages
-+                          * (ib_int64_t)effective_pages
-                           + n_sample_pages - 1
-                           + total_external_size
-                           + not_empty_flag)
-@@ -3642,7 +3927,7 @@
-               different key values, or even more. Let us try to approximate
-               that: */
--              add_on = index->stat_n_leaf_pages
-+              add_on = effective_pages
-                       / (10 * (n_sample_pages
-                                + total_external_size));
-@@ -3651,6 +3936,15 @@
-               }
-               index->stat_n_diff_key_vals[j] += add_on;
-+
-+              if (stats_method == SRV_STATS_METHOD_IGNORE_NULLS) {
-+                      /* index->stat_n_diff_key_vals[k] is used for calc rec_per_key,
-+                      as "stats.records / index->stat_n_diff_key_vals[x]".
-+                      So it should be adjusted to the value which is based on whole of the index. */
-+                      index->stat_n_diff_key_vals[j] =
-+                              index->stat_n_diff_key_vals[j] * (ib_int64_t)index->stat_n_leaf_pages
-+                                      / (ib_int64_t)effective_pages;
-+              }
-       }
-       mem_free(n_diff);
-diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c
---- a/storage/innobase/dict/dict0boot.c        2010-12-03 15:48:03.034036843 +0900
-+++ b/storage/innobase/dict/dict0boot.c        2010-12-03 17:19:24.835112632 +0900
+--- a/storage/innobase/dict/dict0boot.c
++++ b/storage/innobase/dict/dict0boot.c
 @@ -266,6 +266,29 @@
        /* Get the dictionary header */
        dict_hdr = dict_hdr_get(&mtr);
@@ -441,22 +46,26 @@ diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.
  
        index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
                                      DICT_HDR_SPACE,
-@@ -442,6 +465,41 @@
+@@ -442,6 +465,45 @@
                                        FALSE);
        ut_a(error == DB_SUCCESS);
  
 +      /*-------------------------*/
-+      table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 3, 0);
++      table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
 +      table->n_mysql_handles_opened = 1; /* for pin */
 +
 +      dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
 +      dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
 +      dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
++      dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
 +
 +      /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
 +#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
 +#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
 +#endif
++#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
++#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
++#endif
 +
 +      table->id = DICT_STATS_ID;
 +      dict_table_add_to_cache(table, heap);
@@ -483,7 +92,7 @@ diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.
        mtr_commit(&mtr);
        /*-------------------------*/
  
-@@ -455,6 +513,7 @@
+@@ -455,6 +517,7 @@
        dict_load_sys_table(dict_sys->sys_columns);
        dict_load_sys_table(dict_sys->sys_indexes);
        dict_load_sys_table(dict_sys->sys_fields);
@@ -491,10 +100,9 @@ diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.
  
        mutex_exit(&(dict_sys->mutex));
  }
-diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c
---- a/storage/innobase/dict/dict0crea.c        2010-12-03 15:48:03.036081059 +0900
-+++ b/storage/innobase/dict/dict0crea.c        2010-12-03 17:19:24.836964976 +0900
-@@ -508,6 +508,51 @@
+--- a/storage/innobase/dict/dict0crea.c
++++ b/storage/innobase/dict/dict0crea.c
+@@ -508,6 +508,56 @@
  }
  
  /*****************************************************************//**
@@ -519,7 +127,7 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
 +
 +      sys_stats = dict_sys->sys_stats;
 +
-+      entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
++      entry = dtuple_create(heap, 4 + DATA_N_SYS_COLS);
 +
 +      dict_table_copy_types(entry, sys_stats);
 +
@@ -538,6 +146,11 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
 +      ptr = mem_heap_alloc(heap, 8);
 +      mach_write_to_8(ptr, 0); /* initial value is 0 */
 +      dfield_set_data(dfield, ptr, 8);
++      /* 5: NON_NULL_VALS ------------------*/
++      dfield = dtuple_get_nth_field(entry, 3/*NON_NULL_VALS*/);
++      ptr = mem_heap_alloc(heap, 8);
++      mach_write_to_8(ptr, 0); /* initial value is 0 */
++      dfield_set_data(dfield, ptr, 8);
 +
 +      return(entry);
 +}
@@ -546,7 +159,7 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
  Creates the tuple with which the index entry is searched for writing the index
  tree root page number, if such a tree is created.
  @return       the tuple for search */
-@@ -617,6 +662,27 @@
+@@ -617,6 +667,27 @@
  }
  
  /***************************************************************//**
@@ -574,7 +187,7 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
  Creates an index tree for the index if it is not a member of a cluster.
  @return       DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
  static
-@@ -937,6 +1003,49 @@
+@@ -936,6 +1007,49 @@
                                          dict_sys->sys_fields, heap);
        node->field_def->common.parent = node;
  
@@ -624,7 +237,7 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
        node->commit_node = commit_node_create(heap);
        node->commit_node->common.parent = node;
  
-@@ -1087,6 +1196,7 @@
+@@ -1086,6 +1200,7 @@
  
                node->state = INDEX_BUILD_FIELD_DEF;
                node->field_no = 0;
@@ -632,7 +245,7 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
  
                thr->run_node = node->ind_def;
  
-@@ -1132,7 +1242,31 @@
+@@ -1131,7 +1246,31 @@
                        goto function_exit;
                }
  
@@ -665,7 +278,7 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
        }
  
        if (node->state == INDEX_CREATE_INDEX_TREE) {
-@@ -1178,6 +1312,66 @@
+@@ -1177,6 +1316,66 @@
                return(NULL);
        }
  
@@ -732,10 +345,9 @@ diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.
        thr->run_node = que_node_get_parent(node);
  
        return(thr);
-diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
---- a/storage/innobase/dict/dict0dict.c        2010-12-03 15:48:03.040222428 +0900
-+++ b/storage/innobase/dict/dict0dict.c        2010-12-03 17:19:24.841947690 +0900
-@@ -756,7 +756,7 @@
+--- a/storage/innobase/dict/dict0dict.c
++++ b/storage/innobase/dict/dict0dict.c
+@@ -755,7 +755,7 @@
                print an error message and return without doing
                anything. */
                dict_update_statistics(table, TRUE /* only update stats
@@ -744,7 +356,7 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
        }
  
        return(table);
-@@ -4304,6 +4304,240 @@
+@@ -4354,6 +4354,295 @@
  }
  
  /*********************************************************************//**
@@ -796,15 +408,18 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +      ulint           key_cols;
 +      ulint           n_cols;
 +      const rec_t*    rec;
++      ulint           n_fields;
 +      const byte*     field;
 +      ulint           len;
 +      ib_int64_t*     stat_n_diff_key_vals_tmp;
++      ib_int64_t*     stat_n_non_null_key_vals_tmp;
 +      byte*           buf;
 +      ulint           i;
 +      mtr_t           mtr;
 +
 +      n_cols = dict_index_get_n_unique(index);
 +      stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
++      stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
 +
 +      sys_stats = dict_sys->sys_stats;
 +      sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
@@ -840,9 +455,13 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +              }
 +
 +              if (rec_get_deleted_flag(rec, 0)) {
++                      /* don't count */
++                      i--;
 +                      goto next_rec;
 +              }
 +
++              n_fields = rec_get_n_fields_old(rec);
++
 +              field = rec_get_nth_field_old(rec, 1, &len);
 +              ut_a(len == 4);
 +
@@ -854,6 +473,21 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +              ut_a(len == 8);
 +
 +              stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
++
++              if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
++                      field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
++                      ut_a(len == 8);
++
++                      stat_n_non_null_key_vals_tmp[i] = mach_read_from_8(field);
++              } else {
++                      /* not enough fields: should be older */
++                      fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
++                                      " in SYS_STATS seems older format. "
++                                      "Please execute ANALYZE TABLE for it.\n",
++                                      index->table_name, index->name, i, n_cols);
++
++                      stat_n_non_null_key_vals_tmp[i] = ((ib_int64_t)(-1));
++              }
 +next_rec:
 +              btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 +      }
@@ -863,6 +497,12 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +
 +      for (i = 0; i <= n_cols; i++) {
 +              index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
++              if (stat_n_non_null_key_vals_tmp[i] == ((ib_int64_t)(-1))) {
++                      /* approximate value */
++                      index->stat_n_non_null_key_vals[i] = stat_n_diff_key_vals_tmp[n_cols];
++              } else {
++                      index->stat_n_non_null_key_vals[i] = stat_n_non_null_key_vals_tmp[i];
++              }
 +      }
 +}
 +/*===========================================*/
@@ -901,18 +541,22 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +      ulint           n_cols;
 +      ulint           rests;
 +      const rec_t*    rec;
++      ulint           n_fields;
 +      const byte*     field;
 +      ulint           len;
 +      ib_int64_t*     stat_n_diff_key_vals_tmp;
++      ib_int64_t*     stat_n_non_null_key_vals_tmp;
 +      byte*           buf;
 +      ulint           i;
 +      mtr_t           mtr;
 +
 +      n_cols = dict_index_get_n_unique(index);
 +      stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
++      stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
 +
 +      for (i = 0; i <= n_cols; i++) {
 +              stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
++              stat_n_non_null_key_vals_tmp[i] = index->stat_n_non_null_key_vals[i];
 +      }
 +
 +      sys_stats = dict_sys->sys_stats;
@@ -945,7 +589,21 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +                      break;
 +              }
 +
++              btr_pcur_store_position(&pcur, &mtr);
++
 +              if (rec_get_deleted_flag(rec, 0)) {
++                      /* don't count */
++                      i--;
++                      goto next_rec;
++              }
++
++              n_fields = rec_get_n_fields_old(rec);
++
++              if (n_fields <= DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
++                      /* not update for the older smaller format */
++                      fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
++                                      " in SYS_STATS seems older format. Please ANALYZE TABLE it.\n",
++                                      index->table_name, index->name, i, n_cols);
 +                      goto next_rec;
 +              }
 +
@@ -959,9 +617,18 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
 +
 +              mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
 +
++              field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
++              ut_a(len == 8);
++
++              mlog_write_ull((byte*)field, stat_n_non_null_key_vals_tmp[key_cols], &mtr);
++
 +              rests--;
 +
 +next_rec:
++              mtr_commit(&mtr);
++              mtr_start(&mtr);
++              btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr);
++
 +              btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 +      }
 +      btr_pcur_close(&pcur);
@@ -985,7 +652,7 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
  Calculates new estimates for table and index statistics. The statistics
  are used in query optimization. */
  UNIV_INTERN
-@@ -4311,10 +4545,11 @@
+@@ -4361,10 +4650,11 @@
  dict_update_statistics(
  /*===================*/
        dict_table_t*   table,          /*!< in/out: table */
@@ -998,7 +665,7 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
  {
        dict_index_t*   index;
        ulint           sum_of_index_sizes      = 0;
-@@ -4331,6 +4566,27 @@
+@@ -4381,6 +4671,27 @@
                return;
        }
  
@@ -1026,7 +693,7 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
        /* Find out the sizes of the indexes and how many different values
        for the key they approximately have */
  
-@@ -4391,6 +4647,11 @@
+@@ -4445,6 +4756,11 @@
                index = dict_table_get_next_index(index);
        } while (index);
  
@@ -1038,7 +705,86 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
        index = dict_table_get_first_index(table);
  
        table->stat_n_rows = index->stat_n_diff_key_vals[
-@@ -4485,7 +4746,8 @@
+@@ -4462,6 +4778,78 @@
+       dict_table_stats_unlock(table, RW_X_LATCH);
+ }
++/*********************************************************************//**
++*/
++UNIV_INTERN
++ibool
++dict_is_older_statistics(
++/*=====================*/
++      dict_index_t*   index)
++{
++      mem_heap_t*     heap;
++      dict_table_t*   sys_stats;
++      dict_index_t*   sys_index;
++      btr_pcur_t      pcur;
++      dtuple_t*       tuple;
++      dfield_t*       dfield;
++      const rec_t*    rec;
++      ulint           n_fields;
++      ulint           len;
++      byte*           buf;
++      mtr_t           mtr;
++
++      heap = mem_heap_create(100);
++
++      sys_stats = dict_sys->sys_stats;
++      sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
++      ut_a(!dict_table_is_comp(sys_stats));
++
++      tuple = dtuple_create(heap, 1);
++      dfield = dtuple_get_nth_field(tuple, 0);
++
++      buf = mem_heap_alloc(heap, 8);
++      mach_write_to_8(buf, index->id);
++
++      dfield_set_data(dfield, buf, 8);
++      dict_index_copy_types(tuple, sys_index, 1);
++
++      mtr_start(&mtr);
++
++      btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
++                                BTR_SEARCH_LEAF, &pcur, &mtr);
++
++next_rec:
++      rec = btr_pcur_get_rec(&pcur);
++
++      if (!btr_pcur_is_on_user_rec(&pcur)
++          || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
++              != index->id) {
++              /* not found */
++              btr_pcur_close(&pcur);
++              mtr_commit(&mtr);
++              mem_heap_free(heap);
++              /* no statistics == not older statistics */
++              return(FALSE);
++      }
++
++      if (rec_get_deleted_flag(rec, 0)) {
++              btr_pcur_move_to_next_user_rec(&pcur, &mtr);
++              goto next_rec;
++      }
++
++      n_fields = rec_get_n_fields_old(rec);
++
++      btr_pcur_close(&pcur);
++      mtr_commit(&mtr);
++      mem_heap_free(heap);
++
++      if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
++              return(FALSE);
++      } else {
++              return(TRUE);
++      }
++}
++
+ /**********************************************************************//**
+ Prints info of a foreign key constraint. */
+ static
+@@ -4539,7 +4927,8 @@
  
        ut_ad(mutex_own(&(dict_sys->mutex)));
  
@@ -1048,9 +794,8 @@ diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.
  
        dict_table_stats_lock(table, RW_S_LATCH);
  
-diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
---- a/storage/innobase/dict/dict0load.c        2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/dict/dict0load.c        2010-12-03 17:19:24.845947460 +0900
+--- a/storage/innobase/dict/dict0load.c
++++ b/storage/innobase/dict/dict0load.c
 @@ -50,7 +50,8 @@
        "SYS_COLUMNS",
        "SYS_FIELDS",
@@ -1059,9 +804,9 @@ diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.
 +      "SYS_FOREIGN_COLS",
 +      "SYS_STATS"
  };
- /****************************************************************//**
- Compare the name of an index column.
-@@ -343,12 +344,13 @@
+ /* If this flag is TRUE, then we will load the cluster index's (and tables')
+@@ -348,12 +349,13 @@
        }
  
        if ((status & DICT_TABLE_UPDATE_STATS)
@@ -1076,7 +821,7 @@ diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.
        }
  
        return(NULL);
-@@ -582,6 +584,61 @@
+@@ -587,6 +589,75 @@
  //#endif  /* FOREIGN_NOT_USED */
  
  /********************************************************************//**
@@ -1091,16 +836,20 @@ diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.
 +      const rec_t*    rec,            /*!< in: current SYS_STATS rec */
 +      index_id_t*     index_id,       /*!< out: INDEX_ID */
 +      ulint*          key_cols,       /*!< out: KEY_COLS */
-+      ib_uint64_t*    diff_vals)      /*!< out: DIFF_VALS */
++      ib_uint64_t*    diff_vals,      /*!< out: DIFF_VALS */
++      ib_uint64_t*    non_null_vals)  /*!< out: NON_NULL_VALS */
 +{
 +      ulint           len;
 +      const byte*     field;
++      ulint           n_fields;
 +
 +      if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
 +              return("delete-marked record in SYS_STATS");
 +      }
 +
-+      if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
++      n_fields = rec_get_n_fields_old(rec);
++
++      if (UNIV_UNLIKELY(n_fields < 5)) {
 +              return("wrong number of columns in SYS_STATS record");
 +      }
 +
@@ -1132,24 +881,33 @@ diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.
 +      }
 +      *diff_vals = mach_read_from_8(field);
 +
++      if (n_fields < 6) {
++              *non_null_vals = ((ib_uint64_t)(-1));
++      } else {
++              field = rec_get_nth_field_old(rec, 5/*NON_NULL_VALS*/, &len);
++              if (UNIV_UNLIKELY(len != 8)) {
++                      goto err_len;
++              }
++              *non_null_vals = mach_read_from_8(field);
++      }
++
 +      return(NULL);
 +}
 +/********************************************************************//**
  Determine the flags of a table described in SYS_TABLES.
  @return compressed page size in kilobytes; or 0 if the tablespace is
  uncompressed, ULINT_UNDEFINED on error */
-diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
---- a/storage/innobase/handler/ha_innodb.cc    2010-12-03 17:17:03.665960357 +0900
-+++ b/storage/innobase/handler/ha_innodb.cc    2010-12-03 17:22:21.586939783 +0900
-@@ -187,6 +187,7 @@
- static my_bool        innobase_rollback_on_timeout            = FALSE;
+--- a/storage/innobase/handler/ha_innodb.cc
++++ b/storage/innobase/handler/ha_innodb.cc
+@@ -188,6 +188,7 @@
  static my_bool        innobase_create_status_file             = FALSE;
  static my_bool        innobase_stats_on_metadata              = TRUE;
+ static my_bool        innobase_large_prefix                   = FALSE;
 +static my_bool        innobase_use_sys_stats_table            = FALSE;
  
  
  static char*  internal_innobase_data_file_path        = NULL;
-@@ -2388,6 +2389,8 @@
+@@ -2468,6 +2469,8 @@
                goto error;
        }
  
@@ -1158,7 +916,7 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
        /* -------------- Log files ---------------------------*/
  
        /* The default dir for log files is the datadir of MySQL */
-@@ -5192,6 +5195,10 @@
+@@ -5256,6 +5259,10 @@
  
        error = row_insert_for_mysql((byte*) record, prebuilt);
  
@@ -1169,7 +927,7 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
        /* Handle duplicate key errors */
        if (auto_inc_used) {
                ulint           err;
-@@ -5528,6 +5535,10 @@
+@@ -5591,6 +5598,10 @@
                }
        }
  
@@ -1180,7 +938,7 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
        innodb_srv_conc_exit_innodb(trx);
  
        error = convert_error_code_to_mysql(error,
-@@ -5581,6 +5592,10 @@
+@@ -5644,6 +5655,10 @@
  
        error = row_update_for_mysql((byte*) record, prebuilt);
  
@@ -1191,31 +949,31 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
        innodb_srv_conc_exit_innodb(trx);
  
        error = convert_error_code_to_mysql(
-@@ -5899,6 +5914,11 @@
+@@ -5965,6 +5980,11 @@
        case DB_SUCCESS:
                error = 0;
                table->status = 0;
 +#ifdef EXTENDED_FOR_USERSTAT
 +              rows_read++;
-+              if (active_index >= 0 && active_index < MAX_KEY)
++              if (active_index < MAX_KEY)
 +                      index_rows_read[active_index]++;
 +#endif
                break;
        case DB_RECORD_NOT_FOUND:
                error = HA_ERR_KEY_NOT_FOUND;
-@@ -6108,6 +6128,11 @@
+@@ -6196,6 +6216,11 @@
        case DB_SUCCESS:
                error = 0;
                table->status = 0;
 +#ifdef EXTENDED_FOR_USERSTAT
 +              rows_read++;
-+              if (active_index >= 0 && active_index < MAX_KEY)
++              if (active_index < MAX_KEY)
 +                      index_rows_read[active_index]++;
 +#endif
                break;
        case DB_RECORD_NOT_FOUND:
                error = HA_ERR_END_OF_FILE;
-@@ -7999,11 +8024,31 @@
+@@ -8149,11 +8174,35 @@
                        /* In sql_show we call with this flag: update
                        then statistics so that they are up-to-date */
  
@@ -1232,6 +990,10 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
 +                              for (index = dict_table_get_first_index(ib_table);
 +                                   index != NULL;
 +                                   index = dict_table_get_next_index(index)) {
++                                      if (dict_is_older_statistics(index)) {
++                                              row_delete_stats_for_mysql(index, prebuilt->trx);
++                                              innobase_commit_low(prebuilt->trx);
++                                      }
 +                                      row_insert_stats_for_mysql(index, prebuilt->trx);
 +                                      innobase_commit_low(prebuilt->trx);
 +                              }
@@ -1248,7 +1010,7 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
  
                        prebuilt->trx->op_info = "returning various info to MySQL";
                }
-@@ -8081,7 +8126,7 @@
+@@ -8238,7 +8287,7 @@
                are asked by MySQL to avoid locking. Another reason to
                avoid the call is that it uses quite a lot of CPU.
                See Bug#38185. */
@@ -1257,29 +1019,10 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
                    || !(flag & HA_STATUS_VARIABLE_EXTRA)) {
                        /* We do not update delete_length if no
                        locking is requested so the "old" value can
-@@ -11281,6 +11326,45 @@
+@@ -11511,6 +11560,26 @@
    "The number of index pages to sample when calculating statistics (default 8)",
    NULL, NULL, 8, 1, ~0ULL, 0);
  
-+const char *innobase_stats_method_names[]=
-+{
-+  "nulls_equal",
-+  "nulls_unequal",
-+  "nulls_ignored",
-+  NullS
-+};
-+TYPELIB innobase_stats_method_typelib=
-+{
-+  array_elements(innobase_stats_method_names) - 1, "innobase_stats_method_typelib",
-+  innobase_stats_method_names, NULL
-+};
-+static MYSQL_SYSVAR_ENUM(stats_method, srv_stats_method,
-+  PLUGIN_VAR_RQCMDARG,
-+  "Specifies how InnoDB index statistics collection code should threat NULLs. "
-+  "Possible values of name are same to for 'myisam_stats_method'. "
-+  "This is startup parameter.",
-+  NULL, NULL, 0, &innobase_stats_method_typelib);
-+
 +static MYSQL_SYSVAR_ULONG(stats_auto_update, srv_stats_auto_update,
 +  PLUGIN_VAR_RQCMDARG,
 +  "Enable/Disable InnoDB's auto update statistics of indexes. "
@@ -1303,18 +1046,17 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
  static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
    PLUGIN_VAR_OPCMDARG,
    "Enable InnoDB adaptive hash index (enabled by default).  "
-@@ -11604,6 +11688,10 @@
+@@ -11883,6 +11952,9 @@
    MYSQL_SYSVAR(recovery_update_relay_log),
    MYSQL_SYSVAR(rollback_on_timeout),
    MYSQL_SYSVAR(stats_on_metadata),
-+  MYSQL_SYSVAR(stats_method),
 +  MYSQL_SYSVAR(stats_auto_update),
 +  MYSQL_SYSVAR(stats_update_need_lock),
 +  MYSQL_SYSVAR(use_sys_stats_table),
    MYSQL_SYSVAR(stats_sample_pages),
    MYSQL_SYSVAR(adaptive_hash_index),
-   MYSQL_SYSVAR(replication_delay),
-@@ -11672,7 +11760,10 @@
+   MYSQL_SYSVAR(stats_method),
+@@ -11957,7 +12029,10 @@
  i_s_innodb_sys_columns,
  i_s_innodb_sys_fields,
  i_s_innodb_sys_foreign,
@@ -1326,9 +1068,8 @@ diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_
  mysql_declare_plugin_end;
  
  /** @brief Initialize the default value of innodb_commit_concurrency.
-diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
---- a/storage/innobase/handler/i_s.cc  2010-12-03 17:17:03.666956117 +0900
-+++ b/storage/innobase/handler/i_s.cc  2010-12-03 17:19:24.880964526 +0900
+--- a/storage/innobase/handler/i_s.cc
++++ b/storage/innobase/handler/i_s.cc
 @@ -49,6 +49,7 @@
  #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
  #include "trx0rseg.h" /* for trx_rseg_struct */
@@ -1336,9 +1077,9 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +#include "dict0dict.h" /* for dict_sys */
  }
  
- static const char plugin_author[] = "Innobase Oy";
-@@ -3457,6 +3458,203 @@
-       STRUCT_FLD(__reserved1, NULL)
+ #define OK(expr)              \
+@@ -3511,6 +3512,225 @@
+       STRUCT_FLD(flags, 0UL)
  };
  
 +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */
@@ -1371,6 +1112,15 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +       STRUCT_FLD(old_name,           ""),
 +       STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
 +
++#define SYS_STATS_NON_NULL_VALS       3
++      {STRUCT_FLD(field_name,         "NON_NULL_VALS"),
++       STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
++       STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
++       STRUCT_FLD(value,              0),
++       STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED | MY_I_S_MAYBE_NULL),
++       STRUCT_FLD(old_name,           ""),
++       STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
++
 +      END_OF_ST_FIELD_INFO
 +};
 +/**********************************************************************//**
@@ -1384,6 +1134,7 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +      index_id_t      index_id,       /*!< in: INDEX_ID */
 +      ulint           key_cols,       /*!< in: KEY_COLS */
 +      ib_uint64_t     diff_vals,      /*!< in: DIFF_VALS */
++      ib_uint64_t     non_null_vals,  /*!< in: NON_NULL_VALS */
 +      TABLE*          table_to_fill)  /*!< in/out: fill this table */
 +{
 +      Field**         fields;
@@ -1398,6 +1149,13 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +
 +      OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE));
 +
++      if (non_null_vals == ((ib_uint64_t)(-1))) {
++              fields[SYS_STATS_NON_NULL_VALS]->set_null();
++      } else {
++              OK(fields[SYS_STATS_NON_NULL_VALS]->store(longlong(non_null_vals), TRUE));
++              fields[SYS_STATS_NON_NULL_VALS]->set_notnull();
++      }
++
 +      OK(schema_table_store_record(thd, table_to_fill));
 +
 +      DBUG_RETURN(0);
@@ -1436,17 +1194,18 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +              index_id_t      index_id;
 +              ulint           key_cols;
 +              ib_uint64_t     diff_vals;
++              ib_uint64_t     non_null_vals;
 +
 +              /* Extract necessary information from a SYS_FOREIGN_COLS row */
 +              err_msg = dict_process_sys_stats_rec(
-+                      heap, rec, &index_id, &key_cols, &diff_vals);
++                      heap, rec, &index_id, &key_cols, &diff_vals, &non_null_vals);
 +
 +              mtr_commit(&mtr);
 +              mutex_exit(&dict_sys->mutex);
 +
 +              if (!err_msg) {
 +                      i_s_dict_fill_sys_stats(
-+                              thd, index_id, key_cols, diff_vals,
++                              thd, index_id, key_cols, diff_vals, non_null_vals,
 +                              tables->table);
 +              } else {
 +                      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -1505,7 +1264,7 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +
 +      /* plugin author (for SHOW PLUGINS) */
 +      /* const char* */
-+      STRUCT_FLD(author, plugin_author),
++      STRUCT_FLD(author, "Percona"),
 +
 +      /* general descriptive text (for SHOW PLUGINS) */
 +      /* const char* */
@@ -1535,15 +1294,19 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +
 +      /* reserved for dependency checking */
 +      /* void* */
-+      STRUCT_FLD(__reserved1, NULL)
++      STRUCT_FLD(__reserved1, NULL),
++
++      /* flags for plugin */
++      /* unsigned long */
++      STRUCT_FLD(flags, 0UL)
 +};
 +
  /***********************************************************************
  */
  static ST_FIELD_INFO  i_s_innodb_rseg_fields_info[] =
-@@ -3619,3 +3817,347 @@
-       /* void* */
-       STRUCT_FLD(__reserved1, NULL)
+@@ -3677,3 +3897,349 @@
+       /* unsigned long */
+       STRUCT_FLD(flags, 0UL),
  };
 +
 +/***********************************************************************
@@ -1863,7 +1626,7 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +      STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
 +      STRUCT_FLD(info, &i_s_info),
 +      STRUCT_FLD(name, "INNODB_TABLE_STATS"),
-+      STRUCT_FLD(author, plugin_author),
++      STRUCT_FLD(author, "Percona"),
 +      STRUCT_FLD(descr, "InnoDB table statistics in memory"),
 +      STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
 +      STRUCT_FLD(init, i_s_innodb_table_stats_init),
@@ -1871,7 +1634,8 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +      STRUCT_FLD(version, 0x0100 /* 1.0 */),
 +      STRUCT_FLD(status_vars, NULL),
 +      STRUCT_FLD(system_vars, NULL),
-+      STRUCT_FLD(__reserved1, NULL)
++      STRUCT_FLD(__reserved1, NULL),
++      STRUCT_FLD(flags, 0UL)
 +};
 +
 +UNIV_INTERN struct st_mysql_plugin    i_s_innodb_index_stats =
@@ -1879,7 +1643,7 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +      STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
 +      STRUCT_FLD(info, &i_s_info),
 +      STRUCT_FLD(name, "INNODB_INDEX_STATS"),
-+      STRUCT_FLD(author, plugin_author),
++      STRUCT_FLD(author, "Percona"),
 +      STRUCT_FLD(descr, "InnoDB index statistics in memory"),
 +      STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
 +      STRUCT_FLD(init, i_s_innodb_index_stats_init),
@@ -1887,12 +1651,12 @@ diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
 +      STRUCT_FLD(version, 0x0100 /* 1.0 */),
 +      STRUCT_FLD(status_vars, NULL),
 +      STRUCT_FLD(system_vars, NULL),
-+      STRUCT_FLD(__reserved1, NULL)
++      STRUCT_FLD(__reserved1, NULL),
++      STRUCT_FLD(flags, 0UL)
 +};
-diff -ruN a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h
---- a/storage/innobase/handler/i_s.h   2010-12-03 17:17:03.668953884 +0900
-+++ b/storage/innobase/handler/i_s.h   2010-12-03 17:19:24.882947826 +0900
-@@ -41,5 +41,8 @@
+--- a/storage/innobase/handler/i_s.h
++++ b/storage/innobase/handler/i_s.h
+@@ -43,5 +43,8 @@
  extern struct st_mysql_plugin   i_s_innodb_sys_foreign;
  extern struct st_mysql_plugin   i_s_innodb_sys_foreign_cols;
  extern struct st_mysql_plugin i_s_innodb_rseg;
@@ -1901,9 +1665,8 @@ diff -ruN a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h
 +extern struct st_mysql_plugin i_s_innodb_index_stats;
  
  #endif /* i_s_h */
-diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h
---- a/storage/innobase/include/dict0boot.h     2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/dict0boot.h     2010-12-03 17:19:24.885947372 +0900
+--- a/storage/innobase/include/dict0boot.h
++++ b/storage/innobase/include/dict0boot.h
 @@ -104,6 +104,7 @@
  #define DICT_COLUMNS_ID               2
  #define DICT_INDEXES_ID               3
@@ -1925,12 +1688,13 @@ diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict
 +#define       DICT_HDR_XTRADB_MARK    256     /* Flag to distinguish expansion of XtraDB */
  /*-------------------------------------------------------------*/
  
- /* The field number of the page number field in the sys_indexes table
-@@ -144,11 +148,15 @@
+ /* The field numbers in the SYS_TABLES clustered index */
+@@ -146,11 +150,16 @@
  #define DICT_SYS_INDEXES_TYPE_FIELD    6
  #define DICT_SYS_INDEXES_NAME_FIELD    4
  
 +#define DICT_SYS_STATS_DIFF_VALS_FIELD         4
++#define DICT_SYS_STATS_NON_NULL_VALS_FIELD    5
 +
  /* When a row id which is zero modulo this number (which must be a power of
  two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
@@ -1942,9 +1706,8 @@ diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict
  #ifndef UNIV_NONINL
  #include "dict0boot.ic"
  #endif
-diff -ruN a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
---- a/storage/innobase/include/dict0crea.h     2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/dict0crea.h     2010-12-03 17:19:24.886949643 +0900
+--- a/storage/innobase/include/dict0crea.h
++++ b/storage/innobase/include/dict0crea.h
 @@ -53,6 +53,14 @@
        dict_index_t*   index,  /*!< in: index to create, built as a memory data
                                structure */
@@ -1998,10 +1761,9 @@ diff -ruN a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict
  
  #ifndef UNIV_NONINL
  #include "dict0crea.ic"
-diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
---- a/storage/innobase/include/dict0dict.h     2010-12-03 15:48:03.073024387 +0900
-+++ b/storage/innobase/include/dict0dict.h     2010-12-03 17:19:24.888965622 +0900
-@@ -1084,10 +1084,11 @@
+--- a/storage/innobase/include/dict0dict.h
++++ b/storage/innobase/include/dict0dict.h
+@@ -1126,10 +1126,18 @@
  dict_update_statistics(
  /*===================*/
        dict_table_t*   table,          /*!< in/out: table */
@@ -2011,10 +1773,17 @@ diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict
                                        not been initialized yet, otherwise
                                        do nothing */
 +      ibool           sync);
++/*********************************************************************//**
++*/
++UNIV_INTERN
++ibool
++dict_is_older_statistics(
++/*=====================*/
++      dict_index_t*   index);
  /********************************************************************//**
  Reserves the dictionary system mutex for MySQL. */
  UNIV_INTERN
-@@ -1202,6 +1203,7 @@
+@@ -1244,6 +1252,7 @@
        dict_table_t*   sys_columns;    /*!< SYS_COLUMNS table */
        dict_table_t*   sys_indexes;    /*!< SYS_INDEXES table */
        dict_table_t*   sys_fields;     /*!< SYS_FIELDS table */
@@ -2022,9 +1791,8 @@ diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict
  };
  #endif /* !UNIV_HOTBACKUP */
  
-diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
---- a/storage/innobase/include/dict0load.h     2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/dict0load.h     2010-12-03 17:19:24.889947481 +0900
+--- a/storage/innobase/include/dict0load.h
++++ b/storage/innobase/include/dict0load.h
 @@ -41,6 +41,7 @@
        SYS_FIELDS,
        SYS_FOREIGN,
@@ -2033,7 +1801,7 @@ diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict
  
        /* This must be last item. Defines the number of system tables. */
        SYS_NUM_SYSTEM_TABLES
-@@ -319,6 +320,19 @@
+@@ -327,6 +328,20 @@
        const char**    ref_col_name,   /*!< out: referenced column name
                                        in referenced table */
        ulint*          pos);           /*!< out: column position */
@@ -2049,39 +1817,13 @@ diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict
 +      const rec_t*    rec,            /*!< in: current SYS_STATS rec */
 +      index_id_t*     index_id,       /*!< out: INDEX_ID */
 +      ulint*          key_cols,       /*!< out: KEY_COLS */
-+      ib_uint64_t*    diff_vals);     /*!< out: DIFF_VALS */
++      ib_uint64_t*    diff_vals,      /*!< out: DIFF_VALS */
++      ib_uint64_t*    non_null_vals); /*!< out: NON_NULL_VALS */
  #ifndef UNIV_NONINL
  #include "dict0load.ic"
  #endif
-diff -ruN a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
---- a/storage/innobase/include/page0cur.h      2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/page0cur.h      2010-12-03 17:19:24.891954511 +0900
-@@ -293,6 +293,22 @@
- /*==========================*/
-       buf_block_t*    block,  /*!< in: page */
-       page_cur_t*     cursor);/*!< out: page cursor */
-+
-+UNIV_INTERN
-+void
-+page_cur_open_on_nth_user_rec(
-+/*==========================*/
-+      buf_block_t*    block,  /*!< in: page */
-+      page_cur_t*     cursor, /*!< out: page cursor */
-+      ulint           nth);
-+
-+UNIV_INTERN
-+ibool
-+page_cur_open_on_rnd_user_rec_after_nth(
-+/*==========================*/
-+      buf_block_t*    block,  /*!< in: page */
-+      page_cur_t*     cursor, /*!< out: page cursor */
-+      ulint           nth);
- #endif /* !UNIV_HOTBACKUP */
- /***********************************************************//**
- Parses a log record of a record insert on a page.
-diff -ruN a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
---- a/storage/innobase/include/que0que.h       2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/que0que.h       2010-12-03 17:19:24.892947946 +0900
+--- a/storage/innobase/include/que0que.h
++++ b/storage/innobase/include/que0que.h
 @@ -492,6 +492,8 @@
  #define QUE_NODE_CALL         31
  #define QUE_NODE_EXIT         32
@@ -2091,36 +1833,9 @@ diff -ruN a/storage/innobase/include/que0que.h b/storage/innobase/include/que0qu
  /* Query thread states */
  #define QUE_THR_RUNNING               1
  #define QUE_THR_PROCEDURE_WAIT        2
-diff -ruN a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
---- a/storage/innobase/include/rem0cmp.h       2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/rem0cmp.h       2010-12-03 17:19:24.893953395 +0900
-@@ -169,10 +169,11 @@
-                               matched fields; when the function returns,
-                               contains the value the for current
-                               comparison */
--      ulint*          matched_bytes);/*!< in/out: number of already matched
-+      ulint*          matched_bytes, /*!< in/out: number of already matched
-                               bytes within the first field not completely
-                               matched; when the function returns, contains
-                               the value for the current comparison */
-+      ulint           stats_method);
- /*************************************************************//**
- This function is used to compare two physical records. Only the common
- first fields are compared.
-diff -ruN a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic
---- a/storage/innobase/include/rem0cmp.ic      2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/rem0cmp.ic      2010-12-03 17:19:24.902983425 +0900
-@@ -87,5 +87,5 @@
-       ulint   match_b         = 0;
-       return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
--                                    &match_f, &match_b));
-+                                    &match_f, &match_b, 0));
- }
-diff -ruN a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
---- a/storage/innobase/include/row0mysql.h     2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/include/row0mysql.h     2010-12-03 17:19:24.904973020 +0900
-@@ -387,6 +387,14 @@
+--- a/storage/innobase/include/row0mysql.h
++++ b/storage/innobase/include/row0mysql.h
+@@ -387,6 +387,22 @@
                                        then checked for not being too
                                        large. */
  /*********************************************************************//**
@@ -2131,108 +1846,32 @@ diff -ruN a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0
 +/*=======================*/
 +      dict_index_t*   index,
 +      trx_t*          trx);
++/*********************************************************************//**
++*/
++UNIV_INTERN
++int
++row_delete_stats_for_mysql(
++/*=======================*/
++      dict_index_t*   index,
++      trx_t*          trx);
 +/*********************************************************************//**
  Scans a table create SQL string and adds to the data dictionary
  the foreign key constraints declared in the string. This function
  should be called after the indexes for a table have been created.
-diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
---- a/storage/innobase/include/srv0srv.h       2010-12-03 15:53:54.622036720 +0900
-+++ b/storage/innobase/include/srv0srv.h       2010-12-03 17:19:24.906953188 +0900
-@@ -209,6 +209,13 @@
+--- a/storage/innobase/include/srv0srv.h
++++ b/storage/innobase/include/srv0srv.h
+@@ -216,6 +216,9 @@
  extern ibool  srv_innodb_status;
  
  extern unsigned long long     srv_stats_sample_pages;
-+extern ulint  srv_stats_method;
-+#define SRV_STATS_METHOD_NULLS_EQUAL     0
-+#define SRV_STATS_METHOD_NULLS_NOT_EQUAL 1
-+#define SRV_STATS_METHOD_IGNORE_NULLS    2
 +extern ulint  srv_stats_auto_update;
 +extern ulint  srv_stats_update_need_lock;
 +extern ibool  srv_use_sys_stats_table;
  
  extern ibool  srv_use_doublewrite_buf;
  extern ibool  srv_use_checksums;
-diff -ruN a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c
---- a/storage/innobase/page/page0cur.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/page/page0cur.c 2010-12-03 17:19:24.908973357 +0900
-@@ -564,6 +564,74 @@
-       } while (rnd--);
- }
-+UNIV_INTERN
-+void
-+page_cur_open_on_nth_user_rec(
-+/*==========================*/
-+      buf_block_t*    block,  /*!< in: page */
-+      page_cur_t*     cursor, /*!< out: page cursor */
-+      ulint           nth)
-+{
-+      ulint   n_recs = page_get_n_recs(buf_block_get_frame(block));
-+
-+      page_cur_set_before_first(block, cursor);
-+
-+      if (UNIV_UNLIKELY(n_recs == 0)) {
-+
-+              return;
-+      }
-+
-+      nth--;
-+
-+      if (nth >= n_recs) {
-+              nth = n_recs - 1;
-+      }
-+
-+      do {
-+              page_cur_move_to_next(cursor);
-+      } while (nth--);
-+}
-+
-+UNIV_INTERN
-+ibool
-+page_cur_open_on_rnd_user_rec_after_nth(
-+/*==========================*/
-+      buf_block_t*    block,  /*!< in: page */
-+      page_cur_t*     cursor, /*!< out: page cursor */
-+      ulint           nth)
-+{
-+      ulint   rnd;
-+      ulint   n_recs = page_get_n_recs(buf_block_get_frame(block));
-+      ibool   ret;
-+
-+      page_cur_set_before_first(block, cursor);
-+
-+      if (UNIV_UNLIKELY(n_recs == 0)) {
-+
-+              return (FALSE);
-+      }
-+
-+      nth--;
-+
-+      if (nth >= n_recs) {
-+              nth = n_recs - 1;
-+      }
-+
-+      rnd = (ulint) (nth + page_cur_lcg_prng() % (n_recs - nth));
-+
-+      if (rnd == nth) {
-+              ret = TRUE;
-+      } else {
-+              ret = FALSE;
-+      }
-+
-+      do {
-+              page_cur_move_to_next(cursor);
-+      } while (rnd--);
-+
-+      return (ret);
-+}
-+
- /***********************************************************//**
- Writes the log record of a record insert on a page. */
- static
-diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c
---- a/storage/innobase/que/que0que.c   2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/que/que0que.c   2010-12-03 17:19:24.910953422 +0900
+--- a/storage/innobase/que/que0que.c
++++ b/storage/innobase/que/que0que.c
 @@ -621,11 +621,21 @@
  
                que_graph_free_recursive(cre_ind->ind_def);
@@ -2273,39 +1912,20 @@ diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c
        } else if (type == QUE_NODE_ROW_PRINTF) {
                thr = row_printf_step(thr);
        } else {
-diff -ruN a/storage/innobase/rem/rem0cmp.c b/storage/innobase/rem/rem0cmp.c
---- a/storage/innobase/rem/rem0cmp.c   2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/rem/rem0cmp.c   2010-12-03 17:19:24.911953579 +0900
-@@ -866,10 +866,11 @@
-                               matched fields; when the function returns,
-                               contains the value the for current
-                               comparison */
--      ulint*          matched_bytes) /*!< in/out: number of already matched
-+      ulint*          matched_bytes, /*!< in/out: number of already matched
-                               bytes within the first field not completely
-                               matched; when the function returns, contains
-                               the value for the current comparison */
-+      ulint           stats_method)
- {
-       ulint           rec1_n_fields;  /* the number of fields in rec */
-       ulint           rec1_f_len;     /* length of current field in rec */
-@@ -962,7 +963,11 @@
-                               if (rec1_f_len == rec2_f_len) {
--                                      goto next_field;
-+                                      if (stats_method == SRV_STATS_METHOD_NULLS_EQUAL) {
-+                                              goto next_field;
-+                                      } else {
-+                                              ret = -1;
-+                                      }
-                               } else if (rec2_f_len == UNIV_SQL_NULL) {
+--- a/storage/innobase/row/row0ins.c
++++ b/storage/innobase/row/row0ins.c
+@@ -2018,6 +2018,8 @@
+       }
  
-diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
---- a/storage/innobase/row/row0merge.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/row/row0merge.c 2010-12-03 17:19:24.914955391 +0900
-@@ -2020,6 +2020,8 @@
+ #ifdef UNIV_DEBUG
++      if (!srv_use_sys_stats_table
++          || index != UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes))
+       {
+               page_t* page = btr_cur_get_page(&cursor);
+               rec_t*  first_rec = page_rec_get_next(
+--- a/storage/innobase/row/row0merge.c
++++ b/storage/innobase/row/row0merge.c
+@@ -2019,6 +2019,8 @@
                "UPDATE SYS_INDEXES SET NAME=CONCAT('"
                TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
                "COMMIT WORK;\n"
@@ -2314,10 +1934,9 @@ diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
                /* Drop the field definitions of the index. */
                "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
                /* Drop the index definition and the B-tree. */
-diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
---- a/storage/innobase/row/row0mysql.c 2010-11-03 07:01:13.000000000 +0900
-+++ b/storage/innobase/row/row0mysql.c 2010-12-03 17:19:24.918953476 +0900
-@@ -921,6 +921,9 @@
+--- a/storage/innobase/row/row0mysql.c
++++ b/storage/innobase/row/row0mysql.c
+@@ -922,6 +922,9 @@
  
        table->stat_modified_counter = counter + 1;
  
@@ -2327,7 +1946,7 @@ diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
        /* Calculate new statistics if 1 / 16 of table has been modified
        since the last time a statistics batch was run, or if
        stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
-@@ -931,7 +934,7 @@
+@@ -932,7 +935,7 @@
            || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
  
                dict_update_statistics(table, FALSE /* update even if stats
@@ -2336,7 +1955,7 @@ diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
        }
  }
  
-@@ -2103,6 +2106,45 @@
+@@ -2077,6 +2080,71 @@
  }
  
  /*********************************************************************//**
@@ -2353,7 +1972,7 @@ diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
 +      que_thr_t*      thr;
 +      ulint           err;
 +
-+      ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
++      //ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
 +
 +      trx->op_info = "try to insert rows to SYS_STATS";
 +
@@ -2378,11 +1997,37 @@ diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
 +      return((int) err);
 +}
 +
++/*********************************************************************//**
++*/
++UNIV_INTERN
++int
++row_delete_stats_for_mysql(
++/*=============================*/
++      dict_index_t*   index,
++      trx_t*          trx)
++{
++      pars_info_t*    info    = pars_info_create();
++
++      trx->op_info = "delete rows from SYS_STATS";
++
++      trx_start_if_not_started(trx);
++      trx->error_state = DB_SUCCESS;
++
++      pars_info_add_ull_literal(info, "indexid", index->id);
++
++      return((int) que_eval_sql(info,
++                                "PROCEDURE DELETE_STATISTICS_PROC () IS\n"
++                                "BEGIN\n"
++                                "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
++                                "END;\n"
++                                , TRUE, trx));
++}
++
 +/*********************************************************************//**
  Scans a table create SQL string and adds to the data dictionary
  the foreign key constraints declared in the string. This function
  should be called after the indexes for a table have been created.
-@@ -3022,7 +3064,7 @@
+@@ -3001,7 +3069,7 @@
        dict_table_autoinc_initialize(table, 1);
        dict_table_autoinc_unlock(table);
        dict_update_statistics(table, FALSE /* update even if stats are
@@ -2391,7 +2036,7 @@ diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
  
        trx_commit_for_mysql(trx);
  
-@@ -3324,6 +3366,8 @@
+@@ -3312,6 +3380,8 @@
                           "       IF (SQL % NOTFOUND) THEN\n"
                           "               found := 0;\n"
                           "       ELSE\n"
@@ -2400,17 +2045,128 @@ diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
                           "               DELETE FROM SYS_FIELDS\n"
                           "               WHERE INDEX_ID = index_id;\n"
                           "               DELETE FROM SYS_INDEXES\n"
-diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
---- a/storage/innobase/srv/srv0srv.c   2010-12-03 15:53:54.625288512 +0900
-+++ b/storage/innobase/srv/srv0srv.c   2010-12-03 17:19:24.922953561 +0900
-@@ -397,6 +397,10 @@
+--- a/storage/innobase/row/row0row.c
++++ b/storage/innobase/row/row0row.c
+@@ -364,6 +364,14 @@
+       rec_len = rec_offs_n_fields(offsets);
++      if (srv_use_sys_stats_table
++          && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)) {
++              if (rec_len < dict_index_get_n_fields(index)) {
++                      /* the new record should be extended */
++                      rec_len = dict_index_get_n_fields(index);
++              }
++      }
++
+       entry = dtuple_create(heap, rec_len);
+       dtuple_set_n_fields_cmp(entry,
+@@ -375,6 +383,14 @@
+       for (i = 0; i < rec_len; i++) {
+               dfield = dtuple_get_nth_field(entry, i);
++
++              if (srv_use_sys_stats_table
++                  && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
++                  && i >= rec_offs_n_fields(offsets)) {
++                      dfield_set_null(dfield);
++                      continue;
++              }
++
+               field = rec_get_nth_field(rec, offsets, i, &len);
+               dfield_set_data(dfield, field, len);
+--- a/storage/innobase/row/row0upd.c
++++ b/storage/innobase/row/row0upd.c
+@@ -439,6 +439,12 @@
+                               0);
+               }
++              if (srv_use_sys_stats_table
++                  && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
++                  && upd_field->field_no >= rec_offs_n_fields(offsets)) {
++                      return(TRUE);
++              }
++
+               old_len = rec_offs_nth_size(offsets, upd_field->field_no);
+               if (rec_offs_comp(offsets)
+@@ -879,6 +885,18 @@
+       for (i = 0; i < dtuple_get_n_fields(entry); i++) {
++              if (srv_use_sys_stats_table
++                  && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
++                  && i >= rec_offs_n_fields(offsets)) {
++                      dfield = dtuple_get_nth_field(entry, i);
++
++                      upd_field = upd_get_nth_field(update, n_diff);
++                      dfield_copy(&(upd_field->new_val), dfield);
++                      upd_field_set_field_no(upd_field, i, index, trx);
++                      n_diff++;
++                      goto skip_compare;
++              }
++
+               data = rec_get_nth_field(rec, offsets, i, &len);
+               dfield = dtuple_get_nth_field(entry, i);
+--- a/storage/innobase/srv/srv0srv.c
++++ b/storage/innobase/srv/srv0srv.c
+@@ -400,6 +400,9 @@
  /* When estimating number of different key values in an index, sample
  this many index pages */
  UNIV_INTERN unsigned long long        srv_stats_sample_pages = 8;
-+UNIV_INTERN ulint     srv_stats_method = 0;
 +UNIV_INTERN ulint     srv_stats_auto_update = 1;
 +UNIV_INTERN ulint     srv_stats_update_need_lock = 1;
 +UNIV_INTERN ibool     srv_use_sys_stats_table = FALSE;
  
  UNIV_INTERN ibool     srv_use_doublewrite_buf = TRUE;
  UNIV_INTERN ibool     srv_use_checksums = TRUE;
+--- a/storage/innobase/trx/trx0rec.c
++++ b/storage/innobase/trx/trx0rec.c
+@@ -669,14 +669,27 @@
+       /* Save to the undo log the old values of the columns to be updated. */
+       if (update) {
++              ulint   extended = 0;
++
+               if (trx_undo_left(undo_page, ptr) < 5) {
+                       return(0);
+               }
+-              ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
++              if (srv_use_sys_stats_table
++                  && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)) {
++                      for (i = 0; i < upd_get_n_fields(update); i++) {
++                              ulint   pos = upd_get_nth_field(update, i)->field_no;
++
++                              if (pos >= rec_offs_n_fields(offsets)) {
++                                      extended++;
++                              }
++                      }
++              }
++
++              ptr += mach_write_compressed(ptr, upd_get_n_fields(update) - extended);
+-              for (i = 0; i < upd_get_n_fields(update); i++) {
++              for (i = 0; i < upd_get_n_fields(update) - extended; i++) {
+                       ulint   pos = upd_get_nth_field(update, i)->field_no;
+--- /dev/null
++++ b/mysql-test/r/percona_innodb_use_sys_stats_table.result
+@@ -0,0 +1,3 @@
++show variables like 'innodb_use_sys_stats%';
++Variable_name Value
++innodb_use_sys_stats_table    ON
+--- /dev/null
++++ b/mysql-test/t/percona_innodb_use_sys_stats_table-master.opt
+@@ -0,0 +1 @@
++--innodb_use_sys_stats_table
+--- /dev/null
++++ b/mysql-test/t/percona_innodb_use_sys_stats_table.test
+@@ -0,0 +1,2 @@
++--source include/have_innodb.inc
++show variables like 'innodb_use_sys_stats%';
This page took 0.110392 seconds and 4 git commands to generate.