sql_update.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. /* Update of records */
  17. #include "mysql_priv.h"
  18. #include "sql_acl.h"
  19. #define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
  20. /* Return 0 if row hasn't changed */
  21. static bool compare_record(TABLE *table, ulong query_id)
  22. {
  23.   if (!table->blob_fields)
  24.     return cmp_record(table,1);
  25.   if (memcmp(table->null_flags,
  26.      table->null_flags+table->rec_buff_length,
  27.      table->null_bytes))
  28.     return 1; // Diff in NULL value
  29.   for (Field **ptr=table->field ; *ptr ; ptr++)
  30.   {
  31.     if ((*ptr)->query_id == query_id &&
  32. (*ptr)->cmp_binary_offset(table->rec_buff_length))
  33.       return 1;
  34.   }
  35.   return 0;
  36. }
  37. int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
  38.  List<Item> &values, COND *conds,
  39.  ha_rows limit,
  40.  enum enum_duplicates handle_duplicates,
  41.  thr_lock_type lock_type)
  42. {
  43.   bool  using_limit=limit != HA_POS_ERROR;
  44.   bool used_key_is_modified, using_transactions;
  45.   int error=0;
  46.   uint save_time_stamp, used_index, want_privilege;
  47.   ulong query_id=thd->query_id, timestamp_query_id;
  48.   key_map old_used_keys;
  49.   TABLE *table;
  50.   SQL_SELECT *select;
  51.   READ_RECORD info;
  52.   DBUG_ENTER("mysql_update");
  53.   LINT_INIT(used_index);
  54.   LINT_INIT(timestamp_query_id);
  55.   if (!(table = open_ltable(thd,table_list,lock_type)))
  56.     DBUG_RETURN(-1); /* purecov: inspected */
  57.   save_time_stamp=table->time_stamp;
  58.   table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  59.   thd->proc_info="init";
  60.   /* Calculate "table->used_keys" based on the WHERE */
  61.   table->used_keys=table->keys_in_use;
  62.   table->quick_keys=0;
  63.   want_privilege=table->grant.want_privilege;
  64.   table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
  65.   if (setup_conds(thd,table_list,&conds))
  66.     DBUG_RETURN(-1); /* purecov: inspected */
  67.   old_used_keys=table->used_keys; // Keys used in WHERE
  68.   /*
  69.     Change the query_id for the timestamp column so that we can
  70.     check if this is modified directly
  71.   */
  72.   if (table->timestamp_field)
  73.   {
  74.     timestamp_query_id=table->timestamp_field->query_id;
  75.     table->timestamp_field->query_id=thd->query_id-1;
  76.   }
  77.   /* Check the fields we are going to modify */
  78.   table->grant.want_privilege=want_privilege;
  79.   if (setup_fields(thd,table_list,fields,1,0))
  80.     DBUG_RETURN(-1); /* purecov: inspected */
  81.   if (table->timestamp_field)
  82.   {
  83.     // Don't set timestamp column if this is modified
  84.     if (table->timestamp_field->query_id == thd->query_id)
  85.       table->time_stamp=0;
  86.     else
  87.       table->timestamp_field->query_id=timestamp_query_id;
  88.   }
  89.   /* Check values */
  90.   table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
  91.   if (setup_fields(thd,table_list,values,0,0))
  92.   {
  93.     table->time_stamp=save_time_stamp; // Restore timestamp pointer
  94.     DBUG_RETURN(-1); /* purecov: inspected */
  95.   }
  96.   // Don't count on usage of 'only index' when calculating which key to use
  97.   table->used_keys=0;
  98.   select=make_select(table,0,0,conds,&error);
  99.   if (error ||
  100.       (select && select->check_quick(test(thd->options & SQL_SAFE_UPDATES),
  101.      limit)))
  102.   {
  103.     delete select;
  104.     table->time_stamp=save_time_stamp; // Restore timestamp pointer
  105.     if (error)
  106.     {
  107.       DBUG_RETURN(-1); // Error in where
  108.     }
  109.     send_ok(&thd->net); // No matching records
  110.     DBUG_RETURN(0);
  111.   }
  112.   /* If running in safe sql mode, don't allow updates without keys */
  113.   if (!table->quick_keys)
  114.   {
  115.     thd->lex.options|=QUERY_NO_INDEX_USED;
  116.     if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR)
  117.     {
  118.       delete select;
  119.       table->time_stamp=save_time_stamp;
  120.       send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
  121.       DBUG_RETURN(1);
  122.     }
  123.   }
  124.   /* Check if we are modifying a key that we are used to search with */
  125.   if (select && select->quick)
  126.     used_key_is_modified= (!select->quick->unique_key_range() &&
  127.    check_if_key_used(table,
  128.      (used_index=select->quick->index),
  129.      fields));
  130.   else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
  131.     used_key_is_modified=check_if_key_used(table, used_index, fields);
  132.   else
  133.     used_key_is_modified=0;
  134.   if (used_key_is_modified)
  135.   {
  136.     /*
  137.     ** We can't update table directly;  We must first search after all
  138.     ** matching rows before updating the table!
  139.     */
  140.     table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
  141.     IO_CACHE tempfile;
  142.     if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
  143.   DISK_BUFFER_SIZE, MYF(MY_WME)))
  144.     {
  145.       delete select; /* purecov: inspected */
  146.       table->time_stamp=save_time_stamp; // Restore timestamp pointer /* purecov: inspected */
  147.       DBUG_RETURN(-1);
  148.     }
  149.     if (old_used_keys & ((key_map) 1 << used_index))
  150.     {
  151.       table->key_read=1;
  152.       table->file->extra(HA_EXTRA_KEYREAD);
  153.     }
  154.     init_read_record(&info,thd,table,select,0,1);
  155.     thd->proc_info="searching";
  156.     while (!(error=info.read_record(&info)) && !thd->killed)
  157.     {
  158.       if (!(select && select->skipp_record()))
  159.       {
  160. table->file->position(table->record[0]);
  161. if (my_b_write(&tempfile,table->file->ref,
  162.        table->file->ref_length))
  163. {
  164.   error=1; /* purecov: inspected */
  165.   break; /* purecov: inspected */
  166. }
  167.       }
  168.       else
  169.       {
  170. if (!(test_flags & 512)) /* For debugging */   
  171. {
  172.   DBUG_DUMP("record",(char*) table->record[0],table->reclength);
  173. }
  174.       }
  175.     }
  176.     end_read_record(&info);
  177.     if (table->key_read)
  178.     {
  179.       table->key_read=0;
  180.       table->file->extra(HA_EXTRA_NO_KEYREAD);
  181.     }
  182.     /* Change select to use tempfile */
  183.     if (select)
  184.     {
  185.       delete select->quick;
  186.       if (select->free_cond)
  187. delete select->cond;
  188.       select->quick=0;
  189.       select->cond=0;
  190.     }
  191.     else
  192.     {      
  193.       select= new SQL_SELECT;
  194.       select->head=table;
  195.     }
  196.     if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
  197.       error=1; /* purecov: inspected */
  198.     select->file=tempfile; // Read row ptrs from this file
  199.     if (error >= 0)
  200.     {
  201.       delete select;
  202.       table->time_stamp=save_time_stamp; // Restore timestamp pointer
  203.       DBUG_RETURN(-1);
  204.     }
  205.   }
  206.   if (!(test_flags & TEST_READCHECK)) /* For debugging */
  207.     VOID(table->file->extra(HA_EXTRA_NO_READCHECK));
  208.   if (handle_duplicates == DUP_IGNORE)
  209.     table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
  210.   init_read_record(&info,thd,table,select,0,1);
  211.   ha_rows updated=0L,found=0L;
  212.   thd->count_cuted_fields=1; /* calc cuted fields */
  213.   thd->cuted_fields=0L;
  214.   thd->proc_info="updating";
  215.   query_id=thd->query_id;
  216.   while (!(error=info.read_record(&info)) && !thd->killed)
  217.   {
  218.     if (!(select && select->skipp_record()))
  219.     {
  220.       store_record(table,1);
  221.       if (fill_record(fields,values))
  222. break; /* purecov: inspected */
  223.       found++;
  224.       if (compare_record(table, query_id))
  225.       {
  226. if (!(error=table->file->update_row((byte*) table->record[1],
  227.     (byte*) table->record[0])))
  228. {
  229.   updated++;
  230.   if (!--limit && using_limit)
  231.   {
  232.     error= -1;
  233.     break;
  234.   }
  235. }
  236. else if (handle_duplicates != DUP_IGNORE ||
  237.  error != HA_ERR_FOUND_DUPP_KEY)
  238. {
  239.   table->file->print_error(error,MYF(0));
  240.   error= 1;
  241.   break;
  242. }
  243.       }
  244.     }
  245.   }
  246.   end_read_record(&info);
  247.   thd->proc_info="end";
  248.   VOID(table->file->extra(HA_EXTRA_READCHECK));
  249.   VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
  250.   table->time_stamp=save_time_stamp; // Restore auto timestamp pointer
  251.   using_transactions=table->file->has_transactions();
  252.   if (updated && (error <= 0 || !using_transactions))
  253.   {
  254.     mysql_update_log.write(thd,thd->query,thd->query_length);
  255.     if (mysql_bin_log.is_open())
  256.     {
  257.       Query_log_event qinfo(thd, thd->query, using_transactions);
  258.       if (mysql_bin_log.write(&qinfo) && using_transactions)
  259. error=1;
  260.     }
  261.     if (!using_transactions)
  262.       thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
  263.   }
  264.   if (using_transactions && ha_autocommit_or_rollback(thd, error >= 0))
  265.     error=1;
  266.   if (thd->lock)
  267.   {
  268.     mysql_unlock_tables(thd, thd->lock);
  269.     thd->lock=0;
  270.   }
  271.   delete select;
  272.   if (error >= 0)
  273.     send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
  274.   else
  275.   {
  276.     char buff[80];
  277.     sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
  278.     (long) thd->cuted_fields);
  279.     send_ok(&thd->net,
  280.     (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
  281.     thd->insert_id_used ? thd->insert_id() : 0L,buff);
  282.     DBUG_PRINT("info",("%d records updated",updated));
  283.   }
  284.   thd->count_cuted_fields=0; /* calc cuted fields */
  285.   DBUG_RETURN(0);
  286. }