home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / sql_update.cpp < prev    next >
C/C++ Source or Header  |  2000-11-22  |  8KB  |  272 lines

  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.  
  17.  
  18. /* Update of records */
  19.  
  20. #include "mysql_priv.h"
  21. #include "sql_acl.h"
  22.  
  23. /* Return 0 if row hasn't changed */
  24.  
  25. static bool compare_record(TABLE *table)
  26. {
  27.   if (!table->blob_fields)
  28.     return cmp_record(table,1);
  29.   ulong current_query_id=current_thd->query_id;
  30.  
  31.   if (memcmp(table->null_flags,
  32.          table->null_flags+table->rec_buff_length,
  33.          table->null_bytes))
  34.     return 1;                    // Diff in NULL value
  35.   for (Field **ptr=table->field ; *ptr ; ptr++)
  36.   {
  37.     if ((*ptr)->query_id == current_query_id &&
  38.     (*ptr)->cmp_binary_offset(table->rec_buff_length))
  39.       return 1;
  40.   }
  41.   return 0;
  42. }
  43.  
  44.  
  45. int mysql_update(THD *thd,TABLE_LIST *table_list,List<Item> &fields,
  46.          List<Item> &values, COND *conds,
  47.          ha_rows limit,
  48.          enum enum_duplicates handle_duplicates,
  49.          thr_lock_type lock_type)
  50. {
  51.   bool         using_limit=limit != HA_POS_ERROR;
  52.   bool        used_key_is_modified;
  53.   int        error=0;
  54.   uint        save_time_stamp, used_index;
  55.   key_map    old_used_keys;
  56.   TABLE        *table;
  57.   SQL_SELECT    *select;
  58.   READ_RECORD    info;
  59.   DBUG_ENTER("mysql_update");
  60.   LINT_INIT(used_index);
  61.  
  62.   if (!(table = open_ltable(thd,table_list,lock_type)))
  63.     DBUG_RETURN(-1);
  64.   save_time_stamp=table->time_stamp;
  65.   table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  66.   thd->proc_info="init";
  67.  
  68.   /*
  69.   ** Find the offsets of the given fields and condition
  70.   */
  71.  
  72.   if (setup_fields(thd,table_list,fields,1,0))
  73.     DBUG_RETURN(-1);
  74.   table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
  75.   if (table->timestamp_field &&            // Don't set timestamp if used
  76.       table->timestamp_field->query_id == thd->query_id)
  77.     table->time_stamp=0;
  78.   table->used_keys=table->keys_in_use;
  79.   table->quick_keys=0;
  80.   if (setup_fields(thd,table_list,values,0,0) ||
  81.       setup_conds(thd,table_list,&conds))
  82.   {
  83.     table->time_stamp=save_time_stamp;        // Restore timestamp pointer
  84.     DBUG_RETURN(-1);                /* purecov: inspected */
  85.   }
  86.   old_used_keys=table->used_keys;
  87.   table->used_keys=0;                // Can't use 'only index'
  88.   select=make_select(table,0,0,conds,&error);
  89.   if (error ||
  90.       (select && select->check_quick(test(thd->options & SQL_SAFE_UPDATES),
  91.                      limit)))
  92.   {
  93.     delete select;
  94.     table->time_stamp=save_time_stamp;        // Restore timestamp pointer
  95.     if (error)
  96.     {
  97.       DBUG_RETURN(-1);                // Error in where
  98.     }
  99.     send_ok(&thd->net);                // No matching records
  100.     DBUG_RETURN(0);
  101.   }
  102.   /* If running in safe sql mode, don't allow updates without keys */
  103.   if (!table->quick_keys)
  104.   {
  105.     thd->lex.options|=OPTION_NO_INDEX_USED;
  106.     if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR)
  107.     {
  108.       delete select;
  109.       table->time_stamp=save_time_stamp;
  110.       send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
  111.       DBUG_RETURN(1);
  112.     }
  113.   }
  114.   /* Check if we are modifying a key that we are used to search with */
  115.   if (select && select->quick)
  116.     used_key_is_modified= (!select->quick->unique_key_range() &&
  117.                check_if_key_used(table,
  118.                          (used_index=select->quick->index),
  119.                          fields));
  120.   else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
  121.     used_key_is_modified=check_if_key_used(table, used_index, fields);
  122.   else
  123.     used_key_is_modified=0;
  124.   if (used_key_is_modified)
  125.   {
  126.     /*
  127.     ** We can't update table directly;  We must first search after all
  128.     ** matching rows before updating the table!
  129.     */
  130.     IO_CACHE tempfile;
  131.     if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
  132.               DISK_BUFFER_SIZE, MYF(MY_WME)))
  133.     {
  134.       delete select;
  135.       table->time_stamp=save_time_stamp;    // Restore timestamp pointer
  136.       DBUG_RETURN(-1);
  137.     }
  138.     if (old_used_keys & ((key_map) 1 << used_index))
  139.     {
  140.       table->key_read=1;
  141.       table->file->extra(HA_EXTRA_KEYREAD);
  142.     }
  143.     init_read_record(&info,thd,table,select,0,1);
  144.     thd->proc_info="searching";
  145.  
  146.     while (!(error=info.read_record(&info)) && !thd->killed)
  147.     {
  148.       if (!(select && select->skipp_record()))
  149.       {
  150.     table->file->position(table->record[0]);
  151.     if (my_b_write(&tempfile,table->file->ref,
  152.                table->file->ref_length))
  153.     {
  154.       error=1;
  155.       break;
  156.     }
  157.       }
  158.       else
  159.       {
  160.     if (!(test_flags & 512))        /* For debugging */      
  161.     {
  162.       DBUG_DUMP("record",(char*) table->record[0],table->reclength);
  163.     }
  164.       }
  165.     }
  166.     end_read_record(&info);
  167.     if (table->key_read)
  168.     {
  169.       table->key_read=0;
  170.       table->file->extra(HA_EXTRA_NO_KEYREAD);
  171.     }
  172.     /* Change select to use tempfile */
  173.     if (select)
  174.     {
  175.       delete select->quick;
  176.       if (select->free_cond)
  177.     delete select->cond;
  178.       select->quick=0;
  179.       select->cond=0;
  180.     }
  181.     else
  182.     {      
  183.       select= new SQL_SELECT;
  184.       select->head=table;
  185.     }
  186.     if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
  187.       error=1;
  188.     select->file=tempfile;            // Read row ptrs from this file
  189.     if (error >= 0)
  190.     {
  191.       delete select;
  192.       table->time_stamp=save_time_stamp;    // Restore timestamp pointer
  193.       DBUG_RETURN(-1);    
  194.     }
  195.   }
  196.  
  197.   if (!(test_flags & TEST_READCHECK))        /* For debugging */
  198.     VOID(table->file->extra(HA_EXTRA_NO_READCHECK));
  199.   init_read_record(&info,thd,table,select,0,1);
  200.  
  201.   ha_rows updated=0L,found=0L;
  202.   thd->count_cuted_fields=1;            /* calc cuted fields */
  203.   thd->cuted_fields=0L;
  204.   thd->proc_info="updating";
  205.  
  206.   while (!(error=info.read_record(&info)) && !thd->killed)
  207.   {
  208.     if (!(select && select->skipp_record()))
  209.     {
  210.       store_record(table,1);
  211.       if (fill_record(fields,values))
  212.     break;
  213.       found++;
  214.       if (compare_record(table))
  215.       {
  216.     if (!(error=table->file->update_row((byte*) table->record[1],
  217.                         (byte*) table->record[0])))
  218.     {
  219.       updated++;
  220.       if (!--limit && using_limit)
  221.       {
  222.         error= -1;
  223.         break;
  224.       }
  225.     }
  226.     else if (handle_duplicates != DUP_IGNORE ||
  227.          error != HA_ERR_FOUND_DUPP_KEY)
  228.     {
  229.       table->file->print_error(error,MYF(0));
  230.       error= 1;
  231.       break;
  232.     }
  233.       }
  234.     }
  235.   }
  236.   end_read_record(&info);
  237.   thd->proc_info="end";
  238.   VOID(table->file->extra(HA_EXTRA_READCHECK));
  239.   table->time_stamp=save_time_stamp;    // Restore auto timestamp pointer
  240.   if (updated)
  241.   {
  242.     mysql_update_log.write(thd,thd->query,thd->query_length);
  243.     if (mysql_bin_log.is_open())
  244.     {
  245.       Query_log_event qinfo(thd, thd->query);
  246.       mysql_bin_log.write(&qinfo);
  247.     }
  248.   }
  249.   if (ha_autocommit_or_rollback(thd, error >= 0))
  250.     error=1;
  251.   if (thd->lock)
  252.   {
  253.     mysql_unlock_tables(thd, thd->lock);
  254.     thd->lock=0;
  255.   }
  256.   delete select;
  257.   if (error >= 0)
  258.     send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
  259.   else
  260.   {
  261.     char buff[80];
  262.     sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
  263.         (long) thd->cuted_fields);
  264.     send_ok(&thd->net,
  265.         (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
  266.         thd->insert_id_used ? thd->insert_id() : 0L,buff);
  267.     DBUG_PRINT("info",("%d records updated",updated));
  268.   }
  269.   thd->count_cuted_fields=0;            /* calc cuted fields */
  270.   DBUG_RETURN(0);
  271. }
  272.