~ubuntu-branches/ubuntu/maverick/mysql-5.1/maverick-proposed

« back to all changes in this revision

Viewing changes to sql/sql_update.cc

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-22 14:16:05 UTC
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: package-import@ubuntu.com-20120222141605-nxlu9yzc6attylc2
Tags: upstream-5.1.61
ImportĀ upstreamĀ versionĀ 5.1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 
1
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2
2
 
3
3
   This program is free software; you can redistribute it and/or modify
4
4
   it under the terms of the GNU General Public License as published by
25
25
#include "sql_trigger.h"
26
26
#include "debug_sync.h"
27
27
 
28
 
/* Return 0 if row hasn't changed */
29
 
 
30
 
bool compare_record(TABLE *table)
 
28
 
 
29
/**
 
30
   True if the table's input and output record buffers are comparable using
 
31
   compare_records(TABLE*).
 
32
 */
 
33
bool records_are_comparable(const TABLE *table) {
 
34
  return ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) == 0) ||
 
35
    bitmap_is_subset(table->write_set, table->read_set);
 
36
}
 
37
 
 
38
 
 
39
/**
 
40
   Compares the input and outbut record buffers of the table to see if a row
 
41
   has changed. The algorithm iterates over updated columns and if they are
 
42
   nullable compares NULL bits in the buffer before comparing actual
 
43
   data. Special care must be taken to compare only the relevant NULL bits and
 
44
   mask out all others as they may be undefined. The storage engine will not
 
45
   and should not touch them.
 
46
 
 
47
   @param table The table to evaluate.
 
48
 
 
49
   @return true if row has changed.
 
50
   @return false otherwise.
 
51
*/
 
52
bool compare_records(const TABLE *table)
31
53
{
 
54
  DBUG_ASSERT(records_are_comparable(table));
 
55
 
 
56
  if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) != 0)
 
57
  {
 
58
    /*
 
59
      Storage engine may not have read all columns of the record.  Fields
 
60
      (including NULL bits) not in the write_set may not have been read and
 
61
      can therefore not be compared.
 
62
    */ 
 
63
    for (Field **ptr= table->field ; *ptr != NULL; ptr++)
 
64
    {
 
65
      Field *field= *ptr;
 
66
      if (bitmap_is_set(table->write_set, field->field_index))
 
67
      {
 
68
        if (field->real_maybe_null())
 
69
        {
 
70
          uchar null_byte_index= field->null_ptr - table->record[0];
 
71
          
 
72
          if (((table->record[0][null_byte_index]) & field->null_bit) !=
 
73
              ((table->record[1][null_byte_index]) & field->null_bit))
 
74
            return TRUE;
 
75
        }
 
76
        if (field->cmp_binary_offset(table->s->rec_buff_length))
 
77
          return TRUE;
 
78
      }
 
79
    }
 
80
    return FALSE;
 
81
  }
 
82
  
 
83
  /* 
 
84
     The storage engine has read all columns, so it's safe to compare all bits
 
85
     including those not in the write_set. This is cheaper than the field-by-field
 
86
     comparison done above.
 
87
  */ 
32
88
  if (table->s->blob_fields + table->s->varchar_fields == 0)
 
89
    // Fixed-size record: do bitwise comparison of the records 
33
90
    return cmp_record(table,record[1]);
34
91
  /* Compare null bits */
35
92
  if (memcmp(table->null_flags,
186
243
  bool          using_limit= limit != HA_POS_ERROR;
187
244
  bool          safe_update= test(thd->options & OPTION_SAFE_UPDATES);
188
245
  bool          used_key_is_modified, transactional_table, will_batch;
189
 
  bool          can_compare_record;
190
246
  int           res;
191
247
  int           error, loc_error;
192
248
  uint          used_index= MAX_KEY, dup_key_found;
473
529
      while (!(error=info.read_record(&info)) && !thd->killed)
474
530
      {
475
531
        thd->examined_row_count++;
476
 
        if (!(select && select->skip_record()))
 
532
        bool skip_record= FALSE;
 
533
        if (select && select->skip_record(thd, &skip_record))
 
534
        {
 
535
          error= 1;
 
536
          table->file->unlock_row();
 
537
          break;
 
538
        }
 
539
        if (!skip_record)
477
540
        {
478
541
          if (table->file->was_semi_consistent_read())
479
542
            continue;  /* repeat the read of the same row if it still exists */
568
631
  if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)
569
632
    table->prepare_for_position();
570
633
 
571
 
  /*
572
 
    We can use compare_record() to optimize away updates if
573
 
    the table handler is returning all columns OR if
574
 
    if all updated columns are read
575
 
  */
576
 
  can_compare_record= (!(table->file->ha_table_flags() &
577
 
                         HA_PARTIAL_COLUMN_READ) ||
578
 
                       bitmap_is_subset(table->write_set, table->read_set));
579
 
 
580
634
  while (!(error=info.read_record(&info)) && !thd->killed)
581
635
  {
582
636
    thd->examined_row_count++;
583
 
    if (!(select && select->skip_record()))
 
637
    bool skip_record;
 
638
    if (!select || (!select->skip_record(thd, &skip_record) && !skip_record))
584
639
    {
585
640
      if (table->file->was_semi_consistent_read())
586
641
        continue;  /* repeat the read of the same row if it still exists */
593
648
 
594
649
      found++;
595
650
 
596
 
      if (!can_compare_record || compare_record(table))
 
651
      if (!records_are_comparable(table) || compare_records(table))
597
652
      {
598
653
        if ((res= table_list->view_check_option(thd, ignore)) !=
599
654
            VIEW_CHECK_OK)
1191
1246
}
1192
1247
 
1193
1248
 
1194
 
/**
1195
 
   Implementation of the safe update options during UPDATE IGNORE. This syntax
1196
 
   causes an UPDATE statement to ignore all errors. In safe update mode,
1197
 
   however, we must never ignore the ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE. There
1198
 
   is a special hook in my_message_sql that will otherwise delete all errors
1199
 
   when the IGNORE option is specified. 
1200
 
 
1201
 
   In the future, all IGNORE handling should be used with this class and all
1202
 
   traces of the hack outlined below should be removed.
1203
 
 
1204
 
   - The parser detects IGNORE option and sets thd->lex->ignore= 1
1205
 
   
1206
 
   - In JOIN::optimize, if this is set, then 
1207
 
     thd->lex->current_select->no_error gets set.
1208
 
 
1209
 
   - In my_message_sql(), if the flag above is set then any error is
1210
 
     unconditionally converted to a warning.
1211
 
 
1212
 
   We are moving in the direction of using Internal_error_handler subclasses
1213
 
   to do all such error tweaking, please continue this effort if new bugs
1214
 
   appear.
1215
 
 */
1216
 
class Safe_dml_handler : public Internal_error_handler {
1217
 
 
1218
 
private:
1219
 
  bool m_handled_error;
1220
 
 
1221
 
public:
1222
 
  explicit Safe_dml_handler() : m_handled_error(FALSE) {}
1223
 
 
1224
 
  bool handle_error(uint sql_errno,
1225
 
                    const char *message,
1226
 
                    MYSQL_ERROR::enum_warning_level level,
1227
 
                    THD *thd)
1228
 
  {
1229
 
    if (level == MYSQL_ERROR::WARN_LEVEL_ERROR &&
1230
 
        sql_errno == ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE)
1231
 
        
1232
 
    {      
1233
 
      thd->main_da.set_error_status(thd, sql_errno, message);
1234
 
      m_handled_error= TRUE;
1235
 
      return TRUE;
1236
 
    }
1237
 
    return FALSE;
1238
 
  }
1239
 
 
1240
 
  bool handled_error() { return m_handled_error; }
1241
 
 
1242
 
};
1243
 
 
1244
1249
/*
1245
1250
  Setup multi-update handling and call SELECT to do the join
1246
1251
*/
1270
1275
 
1271
1276
  List<Item> total_list;
1272
1277
 
1273
 
  Safe_dml_handler handler;
1274
 
  bool using_handler= thd->options & OPTION_SAFE_UPDATES;
1275
 
  if (using_handler)
1276
 
    thd->push_internal_handler(&handler);
1277
 
 
1278
1278
  res= mysql_select(thd, &select_lex->ref_pointer_array,
1279
1279
                    table_list, select_lex->with_wild,
1280
1280
                    total_list,
1284
1284
                    OPTION_SETUP_TABLES_DONE,
1285
1285
                    result, unit, select_lex);
1286
1286
 
1287
 
  if (using_handler)
1288
 
  {
1289
 
    Internal_error_handler *top_handler;
1290
 
    top_handler= thd->pop_internal_handler();
1291
 
    DBUG_ASSERT(&handler == top_handler);
1292
 
  }
1293
 
 
1294
1287
  DBUG_PRINT("info",("res: %d  report_error: %d", res, (int) thd->is_error()));
1295
1288
  res|= thd->is_error();
1296
 
  /*
1297
 
    Todo: remove below code and make Safe_dml_handler do error processing
1298
 
    instead. That way we can return the actual error instead of
1299
 
    ER_UNKNOWN_ERROR.
1300
 
  */
1301
 
  if (unlikely(res) && (!using_handler || !handler.handled_error()))
 
1289
  if (unlikely(res))
1302
1290
  {
1303
1291
    /* If we had a another error reported earlier then this will be ignored */
1304
1292
    result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
1754
1742
    if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
1755
1743
      continue;
1756
1744
 
1757
 
    /*
1758
 
      We can use compare_record() to optimize away updates if
1759
 
      the table handler is returning all columns OR if
1760
 
      if all updated columns are read
1761
 
    */
1762
1745
    if (table == table_to_update)
1763
1746
    {
1764
 
      bool can_compare_record;
1765
 
      can_compare_record= (!(table->file->ha_table_flags() &
1766
 
                             HA_PARTIAL_COLUMN_READ) ||
1767
 
                           bitmap_is_subset(table->write_set,
1768
 
                                            table->read_set));
1769
1747
      table->status|= STATUS_UPDATED;
1770
1748
      store_record(table,record[1]);
1771
1749
      if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
1780
1758
      */
1781
1759
      table->auto_increment_field_not_null= FALSE;
1782
1760
      found++;
1783
 
      if (!can_compare_record || compare_record(table))
 
1761
      if (!records_are_comparable(table) || compare_records(table))
1784
1762
      {
1785
1763
        int error;
1786
1764
        if ((error= cur_table->view_check_option(thd, ignore)) !=
1967
1945
    DBUG_RETURN(0);
1968
1946
  for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
1969
1947
  {
1970
 
    bool can_compare_record;
1971
1948
    uint offset= cur_table->shared;
1972
1949
 
1973
1950
    table = cur_table->table;
2004
1981
    if ((local_error = tmp_table->file->ha_rnd_init(1)))
2005
1982
      goto err;
2006
1983
 
2007
 
    can_compare_record= (!(table->file->ha_table_flags() &
2008
 
                           HA_PARTIAL_COLUMN_READ) ||
2009
 
                         bitmap_is_subset(table->write_set,
2010
 
                                          table->read_set));
2011
 
 
2012
1984
    for (;;)
2013
1985
    {
2014
1986
      if (thd->killed && trans_safe)
2049
2021
                                            TRG_ACTION_BEFORE, TRUE))
2050
2022
        goto err2;
2051
2023
 
2052
 
      if (!can_compare_record || compare_record(table))
 
2024
      if (!records_are_comparable(table) || compare_records(table))
2053
2025
      {
2054
2026
        int error;
2055
2027
        if ((error= cur_table->view_check_option(thd, ignore)) !=