Commit 24ea59cf authored by unknown's avatar unknown
Browse files

Merge mysql.com:/home/mydev/mysql-5.0

into mysql.com:/home/mydev/mysql-5.0-wl2126


include/my_base.h:
  Auto merged
sql/handler.cc:
  Auto merged
sql/mysqld.cc:
  Auto merged
parents bec3feaa 8d11c01c
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -376,6 +376,15 @@ enum data_file_type {

/* For key ranges */

#define NO_MIN_RANGE	1
#define NO_MAX_RANGE	2
#define NEAR_MIN	4
#define NEAR_MAX	8
#define UNIQUE_RANGE	16
#define EQ_RANGE	32
#define NULL_RANGE	64
#define GEOM_FLAG      128

typedef struct st_key_range
{
  const byte *key;
@@ -383,6 +392,14 @@ typedef struct st_key_range
  enum ha_rkey_function flag;
} key_range;

typedef struct st_key_multi_range
{
  key_range start_key;
  key_range end_key;
  char  *ptr;                 /* Free to use by caller (ptr to row etc) */
  uint  range_flag;           /* key range flags see above */
} KEY_MULTI_RANGE;


/* For number of records */
#ifdef BIG_TABLES
+125 −0
Original line number Diff line number Diff line
@@ -1786,6 +1786,131 @@ int ha_table_exists(THD* thd, const char* db, const char* name)
#endif


/*
  Read the first row of a multi-range set.

  SYNOPSIS
    read_multi_range_first()
    found_range_p       Returns a pointer to the element in 'ranges' that
                        corresponds to the returned row.
    ranges              An array of KEY_MULTI_RANGE range descriptions.
    range_count         Number of ranges in 'ranges'.
    sorted		If result should be sorted per key.
    buffer              A HANDLER_BUFFER for internal handler usage.

  NOTES
    Record is read into table->record[0].
    *found_range_p returns a valid value only if read_multi_range_first()
    returns 0.
    Sorting is done within each range. If you want an overall sort, enter
    'ranges' with sorted ranges.

  RETURN
    0			OK, found a row
    HA_ERR_END_OF_FILE	No rows in range
    #			Error code
*/

int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
                                    KEY_MULTI_RANGE *ranges, uint range_count,
                                    bool sorted, HANDLER_BUFFER *buffer)
{
  int result= HA_ERR_END_OF_FILE;
  DBUG_ENTER("handler::read_multi_range_first");
  multi_range_sorted= sorted;
  multi_range_buffer= buffer;

  for (multi_range_curr= ranges, multi_range_end= ranges + range_count;
       multi_range_curr < multi_range_end;
       multi_range_curr++)
  {
    result= read_range_first(multi_range_curr->start_key.length ?
                             &multi_range_curr->start_key : 0,
                             multi_range_curr->end_key.length ?
                             &multi_range_curr->end_key : 0,
                             test(multi_range_curr->range_flag & EQ_RANGE),
                             multi_range_sorted);
    if (result != HA_ERR_END_OF_FILE)
      break;
  }

  *found_range_p= multi_range_curr;
  DBUG_PRINT("exit",("result %d", result));
  DBUG_RETURN(result);
}


/*
  Read the next row of a multi-range set.

  SYNOPSIS
    read_multi_range_next()
    found_range_p       Returns a pointer to the element in 'ranges' that
                        corresponds to the returned row.

  NOTES
    Record is read into table->record[0].
    *found_range_p returns a valid value only if read_multi_range_next()
    returns 0.

  RETURN
    0			OK, found a row
    HA_ERR_END_OF_FILE	No (more) rows in range
    #			Error code
*/

int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
{
  int result;
  DBUG_ENTER("handler::read_multi_range_next");

  /* We should not be called after the last call returned EOF. */
  DBUG_ASSERT(multi_range_curr < multi_range_end);

  do
  {
    /* Save a call if there can be only one row in range. */
    if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE))
    {
      result= read_range_next();

      /* On success or non-EOF errors jump to the end. */
      if (result != HA_ERR_END_OF_FILE)
        break;
    }
    else
    {
      /*
        We need to set this for the last range only, but checking this
        condition is more expensive than just setting the result code.
      */
      result= HA_ERR_END_OF_FILE;
    }

    /* Try the next range(s) until one matches a record. */
    for (multi_range_curr++;
         multi_range_curr < multi_range_end;
         multi_range_curr++)
    {
      result= read_range_first(multi_range_curr->start_key.length ?
                               &multi_range_curr->start_key : 0,
                               multi_range_curr->end_key.length ?
                               &multi_range_curr->end_key : 0,
                               test(multi_range_curr->range_flag & EQ_RANGE),
                               multi_range_sorted);
      if (result != HA_ERR_END_OF_FILE)
        break;
    }
  }
  while ((result == HA_ERR_END_OF_FILE) &&
         (multi_range_curr < multi_range_end));

  *found_range_p= multi_range_curr;
  DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result));
  DBUG_RETURN(result);
}


/*
  Read first row between two ranges.
  Store ranges for future calls to read_range_next
+26 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@
#define HA_FILE_BASED	       (1 << 26)
#define HA_NO_VARCHAR	       (1 << 27)
#define HA_CAN_BIT_FIELD       (1 << 28) /* supports bit fields */
#define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */


/* bits in index_flags(index_number) for what you can do with index */
@@ -276,6 +277,21 @@ typedef struct st_ha_check_opt
} HA_CHECK_OPT;


/*
  This is a buffer area that the handler can use to store rows.
  'end_of_used_area' should be kept updated after calls to
  read-functions so that other parts of the code can use the
  remaining area (until next read calls is issued).
*/

typedef struct st_handler_buffer
{
  const byte *buffer;         /* Buffer one can start using */
  const byte *buffer_end;     /* End of buffer */
  byte *end_of_used_area;     /* End of area that was used by handler */
} HANDLER_BUFFER;


class handler :public Sql_alloc
{
 protected:
@@ -310,6 +326,12 @@ class handler :public Sql_alloc
  time_t check_time;
  time_t update_time;

  /* The following are for read_multi_range */
  bool multi_range_sorted;
  KEY_MULTI_RANGE *multi_range_curr;
  KEY_MULTI_RANGE *multi_range_end;
  HANDLER_BUFFER *multi_range_buffer;

  /* The following are for read_range() */
  key_range save_end_range, *end_range;
  KEY_PART_INFO *range_key_part;
@@ -421,6 +443,10 @@ class handler :public Sql_alloc
  virtual int index_next_same(byte *buf, const byte *key, uint keylen);
  virtual int index_read_last(byte * buf, const byte * key, uint key_len)
   { return (my_errno=HA_ERR_WRONG_COMMAND); }
  virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
                                     KEY_MULTI_RANGE *ranges, uint range_count,
                                     bool sorted, HANDLER_BUFFER *buffer);
  virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
  virtual int read_range_first(const key_range *start_key,
                               const key_range *end_key,
                               bool eq_range, bool sorted);
+6 −1
Original line number Diff line number Diff line
@@ -4143,7 +4143,7 @@ enum options_mysqld
  OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
  OPT_MAX_LENGTH_FOR_SORT_DATA,
  OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
  OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
  OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
  OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
  OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
  OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
@@ -5139,6 +5139,11 @@ The minimum value for this variable is 4096.",
   "After this many write locks, allow some read locks to run in between.",
   (gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG,
   REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0},
  {"multi_range_count", OPT_MULTI_RANGE_COUNT,
   "Number of key ranges to request at once.",
   (gptr*) &global_system_variables.multi_range_count,
   (gptr*) &max_system_variables.multi_range_count, 0,
   GET_ULONG, REQUIRED_ARG, 256, 1, ~0L, 0, 1, 0},
  {"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
   "Block size to be used for MyISAM index pages.",
   (gptr*) &opt_myisam_block_size,
+188 −55
Original line number Diff line number Diff line
@@ -712,7 +712,7 @@ QUICK_SELECT_I::QUICK_SELECT_I()

QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
                                       bool no_alloc, MEM_ROOT *parent_alloc)
  :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0)
  :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0),in_range(0)
{
  sorted= 0;
  index= key_nr;
@@ -720,6 +720,13 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
  key_part_info= head->key_info[index].key_part;
  my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16);

  /* 'thd' is not accessible in QUICK_RANGE_SELECT::get_next_init(). */
  multi_range_bufsiz= thd->variables.read_rnd_buff_size;
  multi_range_count= thd->variables.multi_range_count;
  multi_range_length= 0;
  multi_range= NULL;
  multi_range_buff= NULL;

  if (!no_alloc && !parent_alloc)
  {
    // Allocates everything through the internal memroot
@@ -736,6 +743,10 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
int QUICK_RANGE_SELECT::init()
{
  DBUG_ENTER("QUICK_RANGE_SELECT::init");

  if ((error= get_next_init()))
    DBUG_RETURN(error);

  if (file->inited == handler::NONE)
    DBUG_RETURN(error= file->ha_index_init(index));
  error= 0;
@@ -771,6 +782,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
    delete_dynamic(&ranges); /* ranges are allocated in alloc */
    free_root(&alloc,MYF(0));
  }
  if (multi_range)
    my_free((char*) multi_range, MYF(0));
  if (multi_range_buff)
    my_free((char*) multi_range_buff, MYF(0));
  DBUG_VOID_RETURN;
}

@@ -5872,58 +5887,178 @@ int QUICK_ROR_UNION_SELECT::get_next()
  DBUG_RETURN(error);
}

	/* get next possible record using quick-struct */

/*
  Initialize data structures needed by get_next().

  SYNOPSIS
    QUICK_RANGE_SELECT::get_next_init()

  DESCRIPTION
    This is called from get_next() at its first call for an object.
    It allocates memory buffers and sets size variables.

  RETURN
    0           OK.
    != 0        Error.
*/

int QUICK_RANGE_SELECT::get_next_init(void)
{
  uint  mrange_bufsiz;
  byte  *mrange_buff;
  DBUG_ENTER("QUICK_RANGE_SELECT::get_next_init");

  /* Do not allocate the buffers twice. */
  if (multi_range_length)
  {
    DBUG_ASSERT(multi_range_length == min(multi_range_count, ranges.elements));
    DBUG_RETURN(0);
  }

  /* If the ranges are not yet initialized, wait for the next call. */
  if (! ranges.elements)
  {
    DBUG_RETURN(0);
  }

  /*
    Allocate the ranges array.
  */
  multi_range_length= min(multi_range_count, ranges.elements);
  DBUG_ASSERT(multi_range_length > 0);
  while (multi_range_length && ! (multi_range= (KEY_MULTI_RANGE*)
                                  my_malloc(multi_range_length *
                                            sizeof(KEY_MULTI_RANGE),
                                            MYF(MY_WME))))
  {
    /* Try to shrink the buffers until it is 0. */
    multi_range_length/= 2;
  }
  if (! multi_range)
  {
    multi_range_length= 0;
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }

  /*
    Allocate the handler buffer if necessary.
  */
  if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER)
  {
    mrange_bufsiz= min(multi_range_bufsiz,
                       QUICK_SELECT_I::records * head->reclength);

    while (mrange_bufsiz &&
           ! my_multi_malloc(MYF(MY_WME),
                             &multi_range_buff, sizeof(*multi_range_buff),
                             &mrange_buff, mrange_bufsiz,
                             NullS))
    {
      /* Try to shrink the buffers until both are 0. */
      mrange_bufsiz/= 2;
    }
    if (! multi_range_buff)
    {
      my_free((char*) multi_range, MYF(0));
      multi_range= NULL;
      multi_range_length= 0;
      DBUG_RETURN(HA_ERR_OUT_OF_MEM);
    }

    /* Initialize the handler buffer. */
    multi_range_buff->buffer= mrange_buff;
    multi_range_buff->buffer_end= mrange_buff + mrange_bufsiz;
    multi_range_buff->end_of_used_area= mrange_buff;
  }

  /* Initialize the current QUICK_RANGE pointer. */
  cur_range= (QUICK_RANGE**) ranges.buffer;
  DBUG_RETURN(0);
}


/*
  Get next possible record using quick-struct.

  SYNOPSIS
    QUICK_RANGE_SELECT::get_next()

  NOTES
    Record is read into table->record[0]

  RETURN
    0			Found row
    HA_ERR_END_OF_FILE	No (more) rows in range
    #			Error code
*/

int QUICK_RANGE_SELECT::get_next()
{
  int             result;
  KEY_MULTI_RANGE *mrange;
  key_range       *start_key;
  key_range       *end_key;
  DBUG_ENTER("QUICK_RANGE_SELECT::get_next");
  DBUG_ASSERT(multi_range_length && multi_range &&
              (cur_range >= (QUICK_RANGE**) ranges.buffer) &&
              (cur_range <= (QUICK_RANGE**) ranges.buffer + ranges.elements));

  for (;;)
  {
    int result;
    key_range start_key, end_key;
    if (range)
    if (in_range)
    {
      // Already read through key
      result= file->read_range_next();
      /* We did already start to read this key. */
      result= file->read_multi_range_next(&mrange);
      if (result != HA_ERR_END_OF_FILE)
      {
        in_range= ! result;
	DBUG_RETURN(result);
      }
    }

    if (!cur_range)
      range= *(cur_range= (QUICK_RANGE**) ranges.buffer);
    else
      range=
        (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
        (QUICK_RANGE*) 0 : *(++cur_range);

    if (!range)
      DBUG_RETURN(HA_ERR_END_OF_FILE);		// All ranges used
    uint count= min(multi_range_length, ranges.elements -
                    (cur_range - (QUICK_RANGE**) ranges.buffer));
    if (count == 0)
    {
      /* Ranges have already been used up before. None is left for read. */
      in_range= FALSE;
      DBUG_RETURN(HA_ERR_END_OF_FILE);
    }
    KEY_MULTI_RANGE *mrange_slot, *mrange_end;
    for (mrange_slot= multi_range, mrange_end= mrange_slot+count;
         mrange_slot < mrange_end;
         mrange_slot++)
    {
      start_key= &mrange_slot->start_key;
      end_key= &mrange_slot->end_key;
      range= *(cur_range++);

    start_key.key=    (const byte*) range->min_key;
    start_key.length= range->min_length;
    start_key.flag=   ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
      start_key->key=    (const byte*) range->min_key;
      start_key->length= range->min_length;
      start_key->flag=   ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
                          (range->flag & EQ_RANGE) ?
                          HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
    end_key.key=      (const byte*) range->max_key;
    end_key.length=   range->max_length;
      end_key->key=      (const byte*) range->max_key;
      end_key->length=   range->max_length;
      /*
      We use READ_AFTER_KEY here because if we are reading on a key
      prefix we want to find all keys with this prefix
        We use HA_READ_AFTER_KEY here because if we are reading on a key
        prefix. We want to find all keys with this prefix.
      */
    end_key.flag=     (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
      end_key->flag=     (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
                          HA_READ_AFTER_KEY);

    result= file->read_range_first(range->min_length ? &start_key : 0,
				   range->max_length ? &end_key : 0,
                                   test(range->flag & EQ_RANGE),
				   sorted);
    if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
      range=0;				// Stop searching
      mrange_slot->range_flag= range->flag;
    }

    result= file->read_multi_range_first(&mrange, multi_range, count,
                                         sorted, multi_range_buff);
    if (result != HA_ERR_END_OF_FILE)
    {
      in_range= ! result;
      DBUG_RETURN(result);
    range=0;				// No matching rows; go to next range
    }
    in_range= FALSE; /* No matching rows; go to next set of ranges. */
  }
}

@@ -5974,15 +6109,14 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
        DBUG_RETURN(result);
    }

    if (!cur_range)
      range= *(cur_range= (QUICK_RANGE**) ranges.buffer); /* First range. */
    else
      range=
        (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
        (QUICK_RANGE*) 0 : *(++cur_range);                /* Next range. */

    if (!range)
      DBUG_RETURN(HA_ERR_END_OF_FILE);		// All ranges used
    uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer);
    if (count == 0)
    {
      /* Ranges have already been used up before. None is left for read. */
      range= 0;
      DBUG_RETURN(HA_ERR_END_OF_FILE);
    }
    range= *(cur_range++);

    start_key.key=    (const byte*) range->min_key;
    start_key.length= min(range->min_length, prefix_length);
@@ -6030,15 +6164,14 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
	DBUG_RETURN(result);
    }

   if (!cur_range)
      range= *(cur_range= (QUICK_RANGE**) ranges.buffer);
    else
      range=
        (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ?
        (QUICK_RANGE*) 0 : *(++cur_range);

    if (!range)
      DBUG_RETURN(HA_ERR_END_OF_FILE);		// All ranges used
    uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer);
    if (count == 0)
    {
      /* Ranges have already been used up before. None is left for read. */
      range= 0;
      DBUG_RETURN(HA_ERR_END_OF_FILE);
    }
    range= *(cur_range++);

    result= file->index_read(record,
			     (byte*) range->min_key,
Loading