~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/opt_range.cc

  • Committer: Jay Pipes
  • Date: 2009-02-28 20:43:31 UTC
  • mto: (910.2.6 mordred-noatomics)
  • mto: This revision was merged to the branch mainline in revision 912.
  • Revision ID: jpipes@serialcoder-20090228204331-6x804cdbfzyy9w8i
Merged in remove-timezone work

Show diffs side-by-side

added added

removed removed

Lines of Context:
111
111
#include <drizzled/field/num.h>
112
112
#include <drizzled/check_stack_overrun.h>
113
113
 
 
114
#include "drizzled/temporal.h" /* Needed in get_mm_leaf() for timestamp -> datetime comparisons */
 
115
 
114
116
#include <string>
115
117
#include CMATH_H
116
118
 
4336
4338
  SEL_ARG *tree= 0;
4337
4339
  MEM_ROOT *alloc= param->mem_root;
4338
4340
  unsigned char *str;
4339
 
  ulong orig_sql_mode;
4340
4341
  int err;
4341
4342
 
4342
4343
  /*
4486
4487
      value->result_type() != STRING_RESULT &&
4487
4488
      field->cmp_type() != value->result_type())
4488
4489
    goto end;
4489
 
  /* For comparison purposes allow invalid dates like 2000-01-32 */
4490
 
  orig_sql_mode= field->table->in_use->variables.sql_mode;
4491
 
  if (value->real_item()->type() == Item::STRING_ITEM &&
4492
 
      (field->type() == DRIZZLE_TYPE_DATE ||
4493
 
       field->type() == DRIZZLE_TYPE_DATETIME))
4494
 
    field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
4495
 
  err= value->save_in_field_no_warnings(field, 1);
 
4490
 
 
4491
  /*
 
4492
   * Some notes from Jay...
 
4493
   *
 
4494
   * OK, so previously, and in MySQL, what the optimizer does here is
 
4495
   * override the sql_mode variable to ignore out-of-range or bad date-
 
4496
   * time values.  It does this because the optimizer is populating the
 
4497
   * field variable with the incoming value from the comparison field, 
 
4498
   * and the value may exceed the bounds of a proper column type.
 
4499
   *
 
4500
   * For instance, assume the following:
 
4501
   *
 
4502
   * CREATE TABLE t1 (ts TIMESTAMP); 
 
4503
   * INSERT INTO t1 ('2009-03-04 00:00:00');
 
4504
   * CREATE TABLE t2 (dt1 DATETIME, dt2 DATETIME); 
 
4505
   * INSERT INT t2 ('2003-12-31 00:00:00','2999-12-31 00:00:00');
 
4506
   *
 
4507
   * If we issue this query:
 
4508
   *
 
4509
   * SELECT * FROM t1, t2 WHERE t1.ts BETWEEN t2.dt1 AND t2.dt2;
 
4510
   *
 
4511
   * We will come into bounds issues.  Field_timestamp::store() will be
 
4512
   * called with a datetime value of "2999-12-31 00:00:00" and will throw
 
4513
   * an error for out-of-bounds.  MySQL solves this via a hack with sql_mode
 
4514
   * but Drizzle always throws errors on bad data storage in a Field class.
 
4515
   *
 
4516
   * Therefore, to get around the problem of the Field class being used for
 
4517
   * "storage" here without actually storing anything...we must check to see 
 
4518
   * if the value being stored in a Field_timestamp here is out of range.  If
 
4519
   * it is, then we must convert to the highest Timestamp value (or lowest,
 
4520
   * depending on whether the datetime is before or after the epoch.
 
4521
   */
 
4522
  if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
 
4523
  {
 
4524
    /* 
 
4525
     * The left-side of the range comparison is a timestamp field.  Therefore, 
 
4526
     * we must check to see if the value in the right-hand side is outside the
 
4527
     * range of the UNIX epoch, and cut to the epoch bounds if it is.
 
4528
     */
 
4529
    /* Datetime and date columns are Item::FIELD_ITEM ... and have a result type of STRING_RESULT */
 
4530
    if (value->real_item()->type() == Item::FIELD_ITEM
 
4531
        && value->result_type() == STRING_RESULT)
 
4532
    {
 
4533
      char buff[MAX_DATETIME_FULL_WIDTH];
 
4534
      String tmp(buff, sizeof(buff), &my_charset_bin);
 
4535
      String *res= value->val_str(&tmp);
 
4536
 
 
4537
      if (!res)
 
4538
        goto end;
 
4539
      else
 
4540
      {
 
4541
        /* 
 
4542
         * Create a datetime from the string and compare to fixed timestamp
 
4543
         * instances representing the epoch boundaries.
 
4544
         */
 
4545
        drizzled::DateTime value_datetime;
 
4546
 
 
4547
        if (! value_datetime.from_string(res->c_ptr(), (size_t) res->length()))
 
4548
          goto end;
 
4549
 
 
4550
        drizzled::Timestamp max_timestamp;
 
4551
        drizzled::Timestamp min_timestamp;
 
4552
 
 
4553
        (void) max_timestamp.from_time_t((time_t) INT32_MAX);
 
4554
        (void) min_timestamp.from_time_t((time_t) 0);
 
4555
 
 
4556
        /* We rely on Temporal class operator overloads to do our comparisons. */
 
4557
        if (value_datetime < min_timestamp)
 
4558
        {
 
4559
          /* 
 
4560
           * Datetime in right-hand side column is before UNIX epoch, so adjust to
 
4561
           * lower bound.
 
4562
           */
 
4563
          char new_value_buff[MAX_DATETIME_FULL_WIDTH];
 
4564
          size_t new_value_length;
 
4565
          String new_value_string(new_value_buff, sizeof(new_value_buff), &my_charset_bin);
 
4566
 
 
4567
          min_timestamp.to_string(new_value_string.c_ptr(), &new_value_length);
 
4568
          new_value_string.length(new_value_length);
 
4569
          err= value->save_str_value_in_field(field, &new_value_string);
 
4570
        }
 
4571
        else if (value_datetime > max_timestamp)
 
4572
        {
 
4573
          /*
 
4574
           * Datetime in right hand side column is after UNIX epoch, so adjust
 
4575
           * to the higher bound of the epoch.
 
4576
           */
 
4577
          char new_value_buff[MAX_DATETIME_FULL_WIDTH];
 
4578
          size_t new_value_length;
 
4579
          String new_value_string(new_value_buff, sizeof(new_value_buff), &my_charset_bin);
 
4580
 
 
4581
          max_timestamp.to_string(new_value_string.c_ptr(), &new_value_length);
 
4582
          new_value_string.length(new_value_length);
 
4583
          err= value->save_str_value_in_field(field, &new_value_string);
 
4584
        }
 
4585
        else
 
4586
          err= value->save_in_field(field, 1);
 
4587
      }
 
4588
    }
 
4589
    else /* Not a datetime -> timestamp comparison */
 
4590
      err= value->save_in_field(field, 1);
 
4591
  }
 
4592
  else /* Not a timestamp comparison */
 
4593
    err= value->save_in_field(field, 1);
 
4594
 
4496
4595
  if (err > 0)
4497
4596
  {
4498
4597
    if (field->cmp_type() != value->result_type())
4558
4657
  }
4559
4658
  else if (err < 0)
4560
4659
  {
4561
 
    field->table->in_use->variables.sql_mode= orig_sql_mode;
4562
4660
    /* This happens when we try to insert a NULL field in a not null column */
4563
4661
    tree= &null_element;                        // cmp with NULL is never true
4564
4662
    goto end;
4565
4663
  }
4566
 
  field->table->in_use->variables.sql_mode= orig_sql_mode;
4567
4664
  str= (unsigned char*) alloc_root(alloc, key_part->store_length+1);
4568
4665
  if (!str)
4569
4666
    goto end;