~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Stewart Smith
  • Date: 2008-10-15 04:21:24 UTC
  • mto: This revision was merged to the branch mainline in revision 516.
  • Revision ID: stewart@flamingspork.com-20081015042124-kdmb74bcbky1k1nz
remove my_pthread_[gs]etspecific

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Delete of records and truncate of tables.
18
18
 
19
19
  Multi-table deletes were introduced by Monty and Sinisa
20
20
*/
21
 
#include <config.h>
 
21
#include <drizzled/server_includes.h>
22
22
#include <drizzled/sql_select.h>
23
 
#include <drizzled/error.h>
24
 
#include <drizzled/probes.h>
25
 
#include <drizzled/sql_parse.h>
26
 
#include <drizzled/sql_base.h>
27
 
#include <drizzled/lock.h>
28
 
#include <drizzled/probes.h>
29
 
#include <drizzled/optimizer/range.h>
30
 
#include <drizzled/records.h>
31
 
#include <drizzled/internal/iocache.h>
32
 
#include <drizzled/transaction_services.h>
33
 
#include <drizzled/filesort.h>
34
 
 
35
 
namespace drizzled
36
 
{
 
23
#include <drizzled/drizzled_error_messages.h>
37
24
 
38
25
/**
39
26
  Implement DELETE SQL word.
43
30
  end of dispatch_command().
44
31
*/
45
32
 
46
 
bool delete_query(Session *session, TableList *table_list, COND *conds,
47
 
                  SQL_LIST *order, ha_rows limit, uint64_t,
 
33
bool mysql_delete(THD *thd, TableList *table_list, COND *conds,
 
34
                  SQL_LIST *order, ha_rows limit, uint64_t options,
48
35
                  bool reset_auto_increment)
49
36
{
50
 
  int           error;
 
37
  bool          will_batch;
 
38
  int           error, loc_error;
51
39
  Table         *table;
52
 
  optimizer::SqlSelect *select= NULL;
53
 
  ReadRecord    info;
 
40
  SQL_SELECT    *select=0;
 
41
  READ_RECORD   info;
54
42
  bool          using_limit=limit != HA_POS_ERROR;
55
 
  bool          transactional_table, const_cond;
 
43
  bool          transactional_table, safe_update, const_cond;
56
44
  bool          const_cond_result;
57
45
  ha_rows       deleted= 0;
58
46
  uint32_t usable_index= MAX_KEY;
59
 
  Select_Lex   *select_lex= &session->getLex()->select_lex;
60
 
  Session::killed_state_t killed_status= Session::NOT_KILLED;
 
47
  SELECT_LEX   *select_lex= &thd->lex->select_lex;
 
48
  THD::killed_state killed_status= THD::NOT_KILLED;
 
49
  
61
50
 
62
 
  if (session->openTablesLock(table_list))
 
51
  if (open_and_lock_tables(thd, table_list))
 
52
    return(true);
 
53
  /* TODO look at this error */
 
54
  if (!(table= table_list->table))
63
55
  {
64
 
    DRIZZLE_DELETE_DONE(1, 0);
65
 
    return true;
 
56
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), "", "");
 
57
    return(true);
66
58
  }
67
 
 
68
 
  table= table_list->table;
69
 
  assert(table);
70
 
 
71
 
  session->set_proc_info("init");
 
59
  thd->set_proc_info("init");
72
60
  table->map=1;
73
61
 
74
 
  if (prepare_delete(session, table_list, &conds))
75
 
  {
76
 
    DRIZZLE_DELETE_DONE(1, 0);
77
 
    return true;
78
 
  }
 
62
  if (mysql_prepare_delete(thd, table_list, &conds))
 
63
    goto err;
79
64
 
80
65
  /* check ORDER BY even if it can be ignored */
81
66
  if (order && order->elements)
84
69
    List<Item>   fields;
85
70
    List<Item>   all_fields;
86
71
 
 
72
    memset(&tables, 0, sizeof(tables));
87
73
    tables.table = table;
88
74
    tables.alias = table_list->alias;
89
75
 
90
 
      if (select_lex->setup_ref_array(session, order->elements) ||
91
 
          setup_order(session, select_lex->ref_pointer_array, &tables,
92
 
                    fields, all_fields, (Order*) order->first))
93
 
      {
94
 
        delete select;
95
 
        free_underlaid_joins(session, &session->getLex()->select_lex);
96
 
        DRIZZLE_DELETE_DONE(1, 0);
97
 
 
98
 
        return true;
99
 
      }
 
76
      if (select_lex->setup_ref_array(thd, order->elements) ||
 
77
          setup_order(thd, select_lex->ref_pointer_array, &tables,
 
78
                    fields, all_fields, (order_st*) order->first))
 
79
    {
 
80
      delete select;
 
81
      free_underlaid_joins(thd, &thd->lex->select_lex);
 
82
      goto err;
 
83
    }
100
84
  }
101
85
 
102
86
  const_cond= (!conds || conds->const_item());
 
87
  safe_update=test(thd->options & OPTION_SAFE_UPDATES);
 
88
  if (safe_update && const_cond)
 
89
  {
 
90
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
91
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
92
    goto err;
 
93
  }
103
94
 
104
 
  select_lex->no_error= session->getLex()->ignore;
 
95
  select_lex->no_error= thd->lex->ignore;
105
96
 
106
97
  const_cond_result= const_cond && (!conds || conds->val_int());
107
 
  if (session->is_error())
 
98
  if (thd->is_error())
108
99
  {
109
100
    /* Error evaluating val_int(). */
110
101
    return(true);
129
120
      - We should not be binlogging this statement row-based, and
130
121
      - there should be no delete triggers associated with the table.
131
122
  */
132
 
  if (!using_limit && const_cond_result)
 
123
  if (!using_limit && const_cond_result &&
 
124
      (thd->lex->sql_command == SQLCOM_TRUNCATE ||
 
125
       (!thd->current_stmt_binlog_row_based)))
133
126
  {
134
 
    /* Update the table->cursor->stats.records number */
135
 
    table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
136
 
    ha_rows const maybe_deleted= table->cursor->stats.records;
137
 
    if (!(error=table->cursor->ha_delete_all_rows()))
 
127
    /* Update the table->file->stats.records number */
 
128
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
129
    ha_rows const maybe_deleted= table->file->stats.records;
 
130
    if (!(error=table->file->ha_delete_all_rows()))
138
131
    {
139
132
      error= -1;                                // ok
140
133
      deleted= maybe_deleted;
142
135
    }
143
136
    if (error != HA_ERR_WRONG_COMMAND)
144
137
    {
145
 
      table->print_error(error,MYF(0));
 
138
      table->file->print_error(error,MYF(0));
146
139
      error=0;
147
140
      goto cleanup;
148
141
    }
151
144
  if (conds)
152
145
  {
153
146
    Item::cond_result result;
154
 
    conds= remove_eq_conds(session, conds, &result);
 
147
    conds= remove_eq_conds(thd, conds, &result);
155
148
    if (result == Item::COND_FALSE)             // Impossible where
156
149
      limit= 0;
157
150
  }
158
151
 
159
 
  /* Update the table->cursor->stats.records number */
160
 
  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
152
  /* Update the table->file->stats.records number */
 
153
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
161
154
 
162
 
  table->covering_keys.reset();
163
 
  table->quick_keys.reset();            // Can't use 'only index'
164
 
  select= optimizer::make_select(table, 0, 0, conds, 0, &error);
 
155
  table->covering_keys.clear_all();
 
156
  table->quick_keys.clear_all();                // Can't use 'only index'
 
157
  select=make_select(table, 0, 0, conds, 0, &error);
165
158
  if (error)
166
 
  {
167
 
    DRIZZLE_DELETE_DONE(1, 0);
168
 
    return true;
169
 
  }
170
 
 
171
 
  if ((select && select->check_quick(session, false, limit)) || !limit)
 
159
    goto err;
 
160
  if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
172
161
  {
173
162
    delete select;
174
 
    free_underlaid_joins(session, select_lex);
175
 
    session->row_count_func= 0;
176
 
    if (session->is_error())
177
 
      return true;
178
 
    DRIZZLE_DELETE_DONE(0, 0);
179
 
    /**
180
 
     * Resetting the Diagnostic area to prevent
181
 
     * lp bug# 439719
182
 
     */
183
 
    session->main_da.reset_diagnostics_area();
184
 
    session->my_ok((ha_rows) session->rowCount());
 
163
    free_underlaid_joins(thd, select_lex);
 
164
    thd->row_count_func= 0;
 
165
    DRIZZLE_DELETE_END();
 
166
    my_ok(thd, (ha_rows) thd->row_count_func);
185
167
    /*
186
168
      We don't need to call reset_auto_increment in this case, because
187
169
      mysql_truncate always gives a NULL conds argument, hence we never
188
170
      get here.
189
171
    */
190
 
    return 0; // Nothing to delete
 
172
    return(0);                          // Nothing to delete
191
173
  }
192
174
 
193
175
  /* If running in safe sql mode, don't allow updates without keys */
194
 
  if (table->quick_keys.none())
 
176
  if (table->quick_keys.is_clear_all())
195
177
  {
196
 
    session->server_status|=SERVER_QUERY_NO_INDEX_USED;
 
178
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
 
179
    if (safe_update && !using_limit)
 
180
    {
 
181
      delete select;
 
182
      free_underlaid_joins(thd, select_lex);
 
183
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
184
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
185
      goto err;
 
186
    }
197
187
  }
 
188
  if (options & OPTION_QUICK)
 
189
    (void) table->file->extra(HA_EXTRA_QUICK);
198
190
 
199
191
  if (order && order->elements)
200
192
  {
201
193
    uint32_t         length= 0;
202
 
    SortField  *sortorder;
 
194
    SORT_FIELD  *sortorder;
203
195
    ha_rows examined_rows;
204
 
 
205
 
    if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
206
 
      usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
 
196
    
 
197
    if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
 
198
      usable_index= get_index_for_order(table, (order_st*)(order->first), limit);
207
199
 
208
200
    if (usable_index == MAX_KEY)
209
201
    {
210
 
      FileSort filesort(*session);
211
 
      table->sort.io_cache= new internal::IO_CACHE;
212
 
 
213
 
 
214
 
      if (not (sortorder= make_unireg_sortorder((Order*) order->first, &length, NULL)) ||
215
 
          (table->sort.found_records = filesort.run(table, sortorder, length,
216
 
                                                    select, HA_POS_ERROR, 1,
217
 
                                                    examined_rows)) == HA_POS_ERROR)
 
202
      table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
 
203
                                                   MYF(MY_FAE | MY_ZEROFILL));
 
204
    
 
205
      if (!(sortorder= make_unireg_sortorder((order_st*) order->first,
 
206
                                             &length, NULL)) ||
 
207
          (table->sort.found_records = filesort(thd, table, sortorder, length,
 
208
                                                select, HA_POS_ERROR, 1,
 
209
                                                &examined_rows))
 
210
          == HA_POS_ERROR)
218
211
      {
219
212
        delete select;
220
 
        free_underlaid_joins(session, &session->getLex()->select_lex);
221
 
 
222
 
        DRIZZLE_DELETE_DONE(1, 0);
223
 
        return true;
 
213
        free_underlaid_joins(thd, &thd->lex->select_lex);
 
214
        goto err;
224
215
      }
225
216
      /*
226
217
        Filesort has already found and selected the rows we want to delete,
227
218
        so we don't need the where clause
228
219
      */
229
220
      delete select;
230
 
      free_underlaid_joins(session, select_lex);
 
221
      free_underlaid_joins(thd, select_lex);
231
222
      select= 0;
232
223
    }
233
224
  }
236
227
  if (select && select->quick && select->quick->reset())
237
228
  {
238
229
    delete select;
239
 
    free_underlaid_joins(session, select_lex);
240
 
    DRIZZLE_DELETE_DONE(1, 0);
241
 
    return true;
 
230
    free_underlaid_joins(thd, select_lex);
 
231
    goto err;
242
232
  }
243
 
 
244
233
  if (usable_index==MAX_KEY)
245
 
  {
246
 
    if ((error= info.init_read_record(session,table,select,1,1)))
247
 
    {
248
 
      table->print_error(error, MYF(0));
249
 
      delete select;
250
 
      free_underlaid_joins(session, select_lex);
251
 
      return true;
252
 
    }
253
 
  }
 
234
    init_read_record(&info,thd,table,select,1,1);
254
235
  else
255
 
  {
256
 
    if ((error= info.init_read_record_idx(session, table, 1, usable_index)))
257
 
    {
258
 
      table->print_error(error, MYF(0));
259
 
      delete select;
260
 
      free_underlaid_joins(session, select_lex);
261
 
      return true;
262
 
    }
263
 
  }
264
 
 
265
 
  session->set_proc_info("updating");
 
236
    init_read_record_idx(&info, thd, table, 1, usable_index);
 
237
 
 
238
  thd->set_proc_info("updating");
 
239
 
 
240
  will_batch= !table->file->start_bulk_delete();
 
241
 
266
242
 
267
243
  table->mark_columns_needed_for_delete();
268
244
 
269
 
  while (!(error=info.read_record(&info)) && !session->getKilled() &&
270
 
         ! session->is_error())
 
245
  while (!(error=info.read_record(&info)) && !thd->killed &&
 
246
         ! thd->is_error())
271
247
  {
272
 
    // session->is_error() is tested to disallow delete row on error
273
 
    if (!(select && select->skip_record())&& ! session->is_error() )
 
248
    // thd->is_error() is tested to disallow delete row on error
 
249
    if (!(select && select->skip_record())&& ! thd->is_error() )
274
250
    {
275
 
      if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
 
251
      if (!(error= table->file->ha_delete_row(table->record[0])))
276
252
      {
277
253
        deleted++;
278
254
        if (!--limit && using_limit)
283
259
      }
284
260
      else
285
261
      {
286
 
        table->print_error(error,MYF(0));
 
262
        table->file->print_error(error,MYF(0));
287
263
        /*
288
264
          In < 4.0.14 we set the error number to 0 here, but that
289
265
          was not sensible, because then MySQL would not roll back the
297
273
      }
298
274
    }
299
275
    else
300
 
      table->cursor->unlock_row();  // Row failed selection, release lock on it
 
276
      table->file->unlock_row();  // Row failed selection, release lock on it
301
277
  }
302
 
  killed_status= session->getKilled();
303
 
  if (killed_status != Session::NOT_KILLED || session->is_error())
 
278
  killed_status= thd->killed;
 
279
  if (killed_status != THD::NOT_KILLED || thd->is_error())
304
280
    error= 1;                                   // Aborted
305
 
 
306
 
  session->set_proc_info("end");
307
 
  info.end_read_record();
308
 
 
309
 
cleanup:
 
281
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
 
282
  {
 
283
    if (error != 1)
 
284
      table->file->print_error(loc_error,MYF(0));
 
285
    error=1;
 
286
  }
 
287
  thd->set_proc_info("end");
 
288
  end_read_record(&info);
 
289
  if (options & OPTION_QUICK)
 
290
    (void) table->file->extra(HA_EXTRA_NORMAL);
310
291
 
311
292
  if (reset_auto_increment && (error < 0))
312
293
  {
314
295
      We're really doing a truncate and need to reset the table's
315
296
      auto-increment counter.
316
297
    */
317
 
    int error2= table->cursor->ha_reset_auto_increment(0);
 
298
    int error2= table->file->ha_reset_auto_increment(0);
318
299
 
319
300
    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
320
301
    {
321
 
      table->print_error(error2, MYF(0));
 
302
      table->file->print_error(error2, MYF(0));
322
303
      error= 1;
323
304
    }
324
305
  }
325
306
 
 
307
cleanup:
 
308
 
326
309
  delete select;
327
 
  transactional_table= table->cursor->has_transactions();
 
310
  transactional_table= table->file->has_transactions();
328
311
 
329
312
  if (!transactional_table && deleted > 0)
330
 
    session->transaction.stmt.markModifiedNonTransData();
331
 
 
 
313
    thd->transaction.stmt.modified_non_trans_table= true;
 
314
  
332
315
  /* See similar binlogging code in sql_update.cc, for comments */
333
 
  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
334
 
  {
335
 
    if (session->transaction.stmt.hasModifiedNonTransData())
336
 
      session->transaction.all.markModifiedNonTransData();
337
 
  }
338
 
  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
339
 
  free_underlaid_joins(session, select_lex);
340
 
 
341
 
  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
342
 
  if (error < 0 || (session->getLex()->ignore && !session->is_fatal_error))
343
 
  {
344
 
    session->row_count_func= deleted;
345
 
    /**
346
 
     * Resetting the Diagnostic area to prevent
347
 
     * lp bug# 439719
348
 
     */
349
 
    session->main_da.reset_diagnostics_area();    
350
 
    session->my_ok((ha_rows) session->rowCount());
351
 
  }
352
 
  session->status_var.deleted_row_count+= deleted;
353
 
 
354
 
  return (error >= 0 || session->is_error());
 
316
  if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
 
317
  {
 
318
    if (mysql_bin_log.is_open())
 
319
    {
 
320
      if (error < 0)
 
321
        thd->clear_error();
 
322
      /*
 
323
        [binlog]: If 'handler::delete_all_rows()' was called and the
 
324
        storage engine does not inject the rows itself, we replicate
 
325
        statement-based; otherwise, 'ha_delete_row()' was used to
 
326
        delete specific rows which we might log row-based.
 
327
      */
 
328
      int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE,
 
329
                                        thd->query, thd->query_length,
 
330
                                        transactional_table, false, killed_status);
 
331
 
 
332
      if (log_result && transactional_table)
 
333
      {
 
334
        error=1;
 
335
      }
 
336
    }
 
337
    if (thd->transaction.stmt.modified_non_trans_table)
 
338
      thd->transaction.all.modified_non_trans_table= true;
 
339
  }
 
340
  assert(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
 
341
  free_underlaid_joins(thd, select_lex);
 
342
 
 
343
  DRIZZLE_DELETE_END();
 
344
  if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error))
 
345
  {
 
346
    thd->row_count_func= deleted;
 
347
    my_ok(thd, (ha_rows) thd->row_count_func);
 
348
  }
 
349
  return(error >= 0 || thd->is_error());
 
350
 
 
351
err:
 
352
  DRIZZLE_DELETE_END();
 
353
  return(true);
355
354
}
356
355
 
357
356
 
359
358
  Prepare items in DELETE statement
360
359
 
361
360
  SYNOPSIS
362
 
    prepare_delete()
363
 
    session                     - thread handler
 
361
    mysql_prepare_delete()
 
362
    thd                 - thread handler
364
363
    table_list          - global/local table list
365
364
    conds               - conditions
366
365
 
368
367
    false OK
369
368
    true  error
370
369
*/
371
 
int prepare_delete(Session *session, TableList *table_list, Item **conds)
 
370
int mysql_prepare_delete(THD *thd, TableList *table_list, Item **conds)
372
371
{
373
 
  Select_Lex *select_lex= &session->getLex()->select_lex;
374
 
 
 
372
  SELECT_LEX *select_lex= &thd->lex->select_lex;
 
373
  
375
374
  List<Item> all_fields;
376
375
 
377
 
  session->getLex()->allow_sum_func= 0;
378
 
  if (setup_tables_and_check_access(session, &session->getLex()->select_lex.context,
379
 
                                    &session->getLex()->select_lex.top_join_list,
380
 
                                    table_list,
 
376
  /*
 
377
    Statement-based replication of DELETE ... LIMIT is not safe as order of
 
378
    rows is not defined, so in mixed mode we go to row-based.
 
379
 
 
380
    Note that we may consider a statement as safe if ORDER BY primary_key
 
381
    is present. However it may confuse users to see very similiar statements
 
382
    replicated differently.
 
383
  */
 
384
  if (thd->lex->current_select->select_limit)
 
385
  {
 
386
    thd->lex->set_stmt_unsafe();
 
387
    thd->set_current_stmt_binlog_row_based_if_mixed();
 
388
  }
 
389
  thd->lex->allow_sum_func= 0;
 
390
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
 
391
                                    &thd->lex->select_lex.top_join_list,
 
392
                                    table_list, 
381
393
                                    &select_lex->leaf_tables, false) ||
382
 
      session->setup_conds(table_list, conds))
 
394
      setup_conds(thd, table_list, select_lex->leaf_tables, conds))
383
395
    return(true);
384
396
  {
385
397
    TableList *duplicate;
386
 
    if ((duplicate= unique_table(table_list, table_list->next_global)))
 
398
    if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
387
399
    {
388
 
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
 
400
      update_non_unique_table_error(table_list, "DELETE", duplicate);
389
401
      return(true);
390
402
    }
391
403
  }
392
404
 
393
405
  if (select_lex->inner_refs_list.elements &&
394
 
    fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
 
406
    fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
 
407
    return(-1);
 
408
 
 
409
  return(false);
 
410
}
 
411
 
 
412
 
 
413
/***************************************************************************
 
414
  Delete multiple tables from join 
 
415
***************************************************************************/
 
416
 
 
417
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
 
418
 
 
419
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
 
420
{
 
421
  handler *file= (handler*)arg;
 
422
  return file->cmp_ref((const unsigned char*)a, (const unsigned char*)b);
 
423
}
 
424
 
 
425
/*
 
426
  make delete specific preparation and checks after opening tables
 
427
 
 
428
  SYNOPSIS
 
429
    mysql_multi_delete_prepare()
 
430
    thd         thread handler
 
431
 
 
432
  RETURN
 
433
    false OK
 
434
    true  Error
 
435
*/
 
436
 
 
437
int mysql_multi_delete_prepare(THD *thd)
 
438
{
 
439
  LEX *lex= thd->lex;
 
440
  TableList *aux_tables= (TableList *)lex->auxiliary_table_list.first;
 
441
  TableList *target_tbl;
 
442
  
 
443
 
 
444
  /*
 
445
    setup_tables() need for VIEWs. JOIN::prepare() will not do it second
 
446
    time.
 
447
 
 
448
    lex->query_tables also point on local list of DELETE SELECT_LEX
 
449
  */
 
450
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
 
451
                                    &thd->lex->select_lex.top_join_list,
 
452
                                    lex->query_tables,
 
453
                                    &lex->select_lex.leaf_tables, false))
395
454
    return(true);
396
455
 
 
456
 
 
457
  /*
 
458
    Multi-delete can't be constructed over-union => we always have
 
459
    single SELECT on top and have to check underlying SELECTs of it
 
460
  */
 
461
  lex->select_lex.exclude_from_table_unique_test= true;
 
462
  /* Fix tables-to-be-deleted-from list to point at opened tables */
 
463
  for (target_tbl= (TableList*) aux_tables;
 
464
       target_tbl;
 
465
       target_tbl= target_tbl->next_local)
 
466
  {
 
467
    if (!(target_tbl->table= target_tbl->correspondent_table->table))
 
468
    {
 
469
      assert(target_tbl->correspondent_table->merge_underlying_list &&
 
470
                  target_tbl->correspondent_table->merge_underlying_list->
 
471
                  next_local);
 
472
      my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), "", "");
 
473
      return(true);
 
474
    }
 
475
 
 
476
    /*
 
477
      Check that table from which we delete is not used somewhere
 
478
      inside subqueries/view.
 
479
    */
 
480
    {
 
481
      TableList *duplicate;
 
482
      if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
 
483
                                   lex->query_tables, 0)))
 
484
      {
 
485
        update_non_unique_table_error(target_tbl->correspondent_table,
 
486
                                      "DELETE", duplicate);
 
487
        return(true);
 
488
      }
 
489
    }
 
490
  }
397
491
  return(false);
398
492
}
399
493
 
400
494
 
 
495
multi_delete::multi_delete(TableList *dt, uint32_t num_of_tables_arg)
 
496
  : delete_tables(dt), deleted(0), found(0),
 
497
    num_of_tables(num_of_tables_arg), error(0),
 
498
    do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
 
499
{
 
500
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
 
501
}
 
502
 
 
503
 
 
504
int
 
505
multi_delete::prepare(List<Item> &values __attribute__((unused)),
 
506
                      SELECT_LEX_UNIT *u)
 
507
{
 
508
  
 
509
  unit= u;
 
510
  do_delete= 1;
 
511
  thd->set_proc_info("deleting from main table");
 
512
  return(0);
 
513
}
 
514
 
 
515
 
 
516
bool
 
517
multi_delete::initialize_tables(JOIN *join)
 
518
{
 
519
  TableList *walk;
 
520
  Unique **tempfiles_ptr;
 
521
  
 
522
 
 
523
  if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
 
524
    return(1);
 
525
 
 
526
  table_map tables_to_delete_from=0;
 
527
  for (walk= delete_tables; walk; walk= walk->next_local)
 
528
    tables_to_delete_from|= walk->table->map;
 
529
 
 
530
  walk= delete_tables;
 
531
  delete_while_scanning= 1;
 
532
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
 
533
       tab < end;
 
534
       tab++)
 
535
  {
 
536
    if (tab->table->map & tables_to_delete_from)
 
537
    {
 
538
      /* We are going to delete from this table */
 
539
      Table *tbl=walk->table=tab->table;
 
540
      walk= walk->next_local;
 
541
      /* Don't use KEYREAD optimization on this table */
 
542
      tbl->no_keyread=1;
 
543
      /* Don't use record cache */
 
544
      tbl->no_cache= 1;
 
545
      tbl->covering_keys.clear_all();
 
546
      if (tbl->file->has_transactions())
 
547
        transactional_tables= 1;
 
548
      else
 
549
        normal_tables= 1;
 
550
      tbl->prepare_for_position();
 
551
      tbl->mark_columns_needed_for_delete();
 
552
    }
 
553
    else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
 
554
             walk == delete_tables)
 
555
    {
 
556
      /*
 
557
        We are not deleting from the table we are scanning. In this
 
558
        case send_data() shouldn't delete any rows a we may touch
 
559
        the rows in the deleted table many times
 
560
      */
 
561
      delete_while_scanning= 0;
 
562
    }
 
563
  }
 
564
  walk= delete_tables;
 
565
  tempfiles_ptr= tempfiles;
 
566
  if (delete_while_scanning)
 
567
  {
 
568
    table_being_deleted= delete_tables;
 
569
    walk= walk->next_local;
 
570
  }
 
571
  for (;walk ;walk= walk->next_local)
 
572
  {
 
573
    Table *table=walk->table;
 
574
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
 
575
                                  (void *) table->file,
 
576
                                  table->file->ref_length,
 
577
                                  MEM_STRIP_BUF_SIZE);
 
578
  }
 
579
  return(thd->is_fatal_error != 0);
 
580
}
 
581
 
 
582
 
 
583
multi_delete::~multi_delete()
 
584
{
 
585
  for (table_being_deleted= delete_tables;
 
586
       table_being_deleted;
 
587
       table_being_deleted= table_being_deleted->next_local)
 
588
  {
 
589
    Table *table= table_being_deleted->table;
 
590
    table->no_keyread=0;
 
591
  }
 
592
 
 
593
  for (uint32_t counter= 0; counter < num_of_tables; counter++)
 
594
  {
 
595
    if (tempfiles[counter])
 
596
      delete tempfiles[counter];
 
597
  }
 
598
}
 
599
 
 
600
 
 
601
bool multi_delete::send_data(List<Item> &values __attribute__((unused)))
 
602
{
 
603
  int secure_counter= delete_while_scanning ? -1 : 0;
 
604
  TableList *del_table;
 
605
  
 
606
 
 
607
  for (del_table= delete_tables;
 
608
       del_table;
 
609
       del_table= del_table->next_local, secure_counter++)
 
610
  {
 
611
    Table *table= del_table->table;
 
612
 
 
613
    /* Check if we are using outer join and we didn't find the row */
 
614
    if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
 
615
      continue;
 
616
 
 
617
    table->file->position(table->record[0]);
 
618
    found++;
 
619
 
 
620
    if (secure_counter < 0)
 
621
    {
 
622
      /* We are scanning the current table */
 
623
      assert(del_table == table_being_deleted);
 
624
      table->status|= STATUS_DELETED;
 
625
      if (!(error=table->file->ha_delete_row(table->record[0])))
 
626
      {
 
627
        deleted++;
 
628
        if (!table->file->has_transactions())
 
629
          thd->transaction.stmt.modified_non_trans_table= true;
 
630
      }
 
631
      else
 
632
      {
 
633
        table->file->print_error(error,MYF(0));
 
634
        return(1);
 
635
      }
 
636
    }
 
637
    else
 
638
    {
 
639
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
 
640
      if (error)
 
641
      {
 
642
        error= 1;                               // Fatal error
 
643
        return(1);
 
644
      }
 
645
    }
 
646
  }
 
647
  return(0);
 
648
}
 
649
 
 
650
 
 
651
void multi_delete::send_error(uint32_t errcode,const char *err)
 
652
{
 
653
  
 
654
 
 
655
  /* First send error what ever it is ... */
 
656
  my_message(errcode, err, MYF(0));
 
657
 
 
658
  return;
 
659
}
 
660
 
 
661
 
 
662
void multi_delete::abort()
 
663
{
 
664
  
 
665
 
 
666
  /* the error was handled or nothing deleted and no side effects return */
 
667
  if (error_handled ||
 
668
      (!thd->transaction.stmt.modified_non_trans_table && !deleted))
 
669
    return;
 
670
 
 
671
  /*
 
672
    If rows from the first table only has been deleted and it is
 
673
    transactional, just do rollback.
 
674
    The same if all tables are transactional, regardless of where we are.
 
675
    In all other cases do attempt deletes ...
 
676
  */
 
677
  if (do_delete && normal_tables &&
 
678
      (table_being_deleted != delete_tables ||
 
679
       !table_being_deleted->table->file->has_transactions()))
 
680
  {
 
681
    /*
 
682
      We have to execute the recorded do_deletes() and write info into the
 
683
      error log
 
684
    */
 
685
    error= 1;
 
686
    send_eof();
 
687
    assert(error_handled);
 
688
    return;
 
689
  }
 
690
  
 
691
  if (thd->transaction.stmt.modified_non_trans_table)
 
692
  {
 
693
    /* 
 
694
       there is only side effects; to binlog with the error
 
695
    */
 
696
    if (mysql_bin_log.is_open())
 
697
    {
 
698
      thd->binlog_query(THD::ROW_QUERY_TYPE,
 
699
                        thd->query, thd->query_length,
 
700
                        transactional_tables, false);
 
701
    }
 
702
    thd->transaction.all.modified_non_trans_table= true;
 
703
  }
 
704
  return;
 
705
}
 
706
 
 
707
 
 
708
 
 
709
/*
 
710
  Do delete from other tables.
 
711
  Returns values:
 
712
        0 ok
 
713
        1 error
 
714
*/
 
715
 
 
716
int multi_delete::do_deletes()
 
717
{
 
718
  int local_error= 0, counter= 0, tmp_error;
 
719
  bool will_batch;
 
720
  
 
721
  assert(do_delete);
 
722
 
 
723
  do_delete= 0;                                 // Mark called
 
724
  if (!found)
 
725
    return(0);
 
726
 
 
727
  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
 
728
                        delete_tables);
 
729
 
 
730
  for (; table_being_deleted;
 
731
       table_being_deleted= table_being_deleted->next_local, counter++)
 
732
  { 
 
733
    ha_rows last_deleted= deleted;
 
734
    Table *table = table_being_deleted->table;
 
735
    if (tempfiles[counter]->get(table))
 
736
    {
 
737
      local_error=1;
 
738
      break;
 
739
    }
 
740
 
 
741
    READ_RECORD info;
 
742
    init_read_record(&info,thd,table,NULL,0,1);
 
743
    /*
 
744
      Ignore any rows not found in reference tables as they may already have
 
745
      been deleted by foreign key handling
 
746
    */
 
747
    info.ignore_not_found_rows= 1;
 
748
    will_batch= !table->file->start_bulk_delete();
 
749
    while (!(local_error=info.read_record(&info)) && !thd->killed)
 
750
    {
 
751
      if ((local_error=table->file->ha_delete_row(table->record[0])))
 
752
      {
 
753
        table->file->print_error(local_error,MYF(0));
 
754
        break;
 
755
      }
 
756
      deleted++;
 
757
    }
 
758
    if (will_batch && (tmp_error= table->file->end_bulk_delete()))
 
759
    {
 
760
      if (!local_error)
 
761
      {
 
762
        local_error= tmp_error;
 
763
        table->file->print_error(local_error,MYF(0));
 
764
      }
 
765
    }
 
766
    if (last_deleted != deleted && !table->file->has_transactions())
 
767
      thd->transaction.stmt.modified_non_trans_table= true;
 
768
    end_read_record(&info);
 
769
    if (thd->killed && !local_error)
 
770
      local_error= 1;
 
771
    if (local_error == -1)                              // End of file
 
772
      local_error = 0;
 
773
  }
 
774
  return(local_error);
 
775
}
 
776
 
 
777
 
 
778
/*
 
779
  Send ok to the client
 
780
 
 
781
  return:  0 sucess
 
782
           1 error
 
783
*/
 
784
 
 
785
bool multi_delete::send_eof()
 
786
{
 
787
  THD::killed_state killed_status= THD::NOT_KILLED;
 
788
  thd->set_proc_info("deleting from reference tables");
 
789
 
 
790
  /* Does deletes for the last n - 1 tables, returns 0 if ok */
 
791
  int local_error= do_deletes();                // returns 0 if success
 
792
 
 
793
  /* compute a total error to know if something failed */
 
794
  local_error= local_error || error;
 
795
  killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
 
796
  /* reset used flags */
 
797
  thd->set_proc_info("end");
 
798
 
 
799
  if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
 
800
  {
 
801
    if (mysql_bin_log.is_open())
 
802
    {
 
803
      if (local_error == 0)
 
804
        thd->clear_error();
 
805
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
 
806
                            thd->query, thd->query_length,
 
807
                            transactional_tables, false, killed_status) &&
 
808
          !normal_tables)
 
809
      {
 
810
        local_error=1;  // Log write failed: roll back the SQL statement
 
811
      }
 
812
    }
 
813
    if (thd->transaction.stmt.modified_non_trans_table)
 
814
      thd->transaction.all.modified_non_trans_table= true;
 
815
  }
 
816
  if (local_error != 0)
 
817
    error_handled= true; // to force early leave from ::send_error()
 
818
 
 
819
  if (!local_error)
 
820
  {
 
821
    thd->row_count_func= deleted;
 
822
    ::my_ok(thd, (ha_rows) thd->row_count_func);
 
823
  }
 
824
  return 0;
 
825
}
 
826
 
 
827
 
401
828
/***************************************************************************
402
829
  TRUNCATE Table
403
830
****************************************************************************/
405
832
/*
406
833
  Optimize delete of all rows by doing a full generate of the table
407
834
  This will work even if the .ISM and .ISD tables are destroyed
 
835
 
 
836
  dont_send_ok should be set if:
 
837
  - We should always wants to generate the table (even if the table type
 
838
    normally can't safely do this.
 
839
  - We don't want an ok to be sent to the end user.
 
840
  - We don't want to log the truncate command
 
841
  - If we want to have a name lock on the table on exit without errors.
408
842
*/
409
843
 
410
 
bool truncate(Session& session, TableList *table_list)
 
844
bool mysql_truncate(THD *thd, TableList *table_list, bool dont_send_ok)
411
845
{
 
846
  HA_CREATE_INFO create_info;
 
847
  char path[FN_REFLEN];
 
848
  Table *table;
412
849
  bool error;
413
 
  TransactionServices &transaction_services= TransactionServices::singleton();
414
 
 
415
 
  uint64_t save_options= session.options;
 
850
  uint32_t path_length;
 
851
  
 
852
 
 
853
  memset(&create_info, 0, sizeof(create_info));
 
854
  /* If it is a temporary table, close and regenerate it */
 
855
  if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
 
856
  {
 
857
    handlerton *table_type= table->s->db_type();
 
858
    TABLE_SHARE *share= table->s;
 
859
    bool frm_only= (share->tmp_table == TMP_TABLE_FRM_FILE_ONLY);
 
860
 
 
861
    if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
 
862
      goto trunc_by_del;
 
863
 
 
864
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
 
865
    
 
866
    close_temporary_table(thd, table, 0, 0);    // Don't free share
 
867
    ha_create_table(thd, share->normalized_path.str,
 
868
                    share->db.str, share->table_name.str, &create_info, 1);
 
869
    // We don't need to call invalidate() because this table is not in cache
 
870
    if ((error= (int) !(open_temporary_table(thd, share->path.str,
 
871
                                             share->db.str,
 
872
                                             share->table_name.str, 1,
 
873
                                             OTM_OPEN))))
 
874
      (void) rm_temporary_table(table_type, path, frm_only);
 
875
    free_table_share(share);
 
876
    free((char*) table);
 
877
    /*
 
878
      If we return here we will not have logged the truncation to the bin log
 
879
      and we will not my_ok() to the client.
 
880
    */
 
881
    goto end;
 
882
  }
 
883
 
 
884
  path_length= build_table_filename(path, sizeof(path), table_list->db,
 
885
                                    table_list->table_name, reg_ext, 0);
 
886
 
 
887
  if (!dont_send_ok)
 
888
    goto trunc_by_del;
 
889
 
 
890
  // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
 
891
  // crashes, replacement works.  *(path + path_length - reg_ext_length)=
 
892
  // '\0';
 
893
  path[path_length - reg_ext_length] = 0;
 
894
  pthread_mutex_lock(&LOCK_open);
 
895
  error= ha_create_table(thd, path, table_list->db, table_list->table_name,
 
896
                         &create_info, 1);
 
897
  pthread_mutex_unlock(&LOCK_open);
 
898
 
 
899
end:
 
900
  if (!dont_send_ok)
 
901
  {
 
902
    if (!error)
 
903
    {
 
904
      /*
 
905
        TRUNCATE must always be statement-based binlogged (not row-based) so
 
906
        we don't test current_stmt_binlog_row_based.
 
907
      */
 
908
      write_bin_log(thd, true, thd->query, thd->query_length);
 
909
      my_ok(thd);               // This should return record count
 
910
    }
 
911
    pthread_mutex_lock(&LOCK_open);
 
912
    unlock_table_name(thd, table_list);
 
913
    pthread_mutex_unlock(&LOCK_open);
 
914
  }
 
915
  else if (error)
 
916
  {
 
917
    pthread_mutex_lock(&LOCK_open);
 
918
    unlock_table_name(thd, table_list);
 
919
    pthread_mutex_unlock(&LOCK_open);
 
920
  }
 
921
  return(error);
 
922
 
 
923
trunc_by_del:
 
924
  /* Probably InnoDB table */
 
925
  uint64_t save_options= thd->options;
416
926
  table_list->lock_type= TL_WRITE;
417
 
  session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
418
 
  init_select(session.getLex());
419
 
  error= delete_query(&session, table_list, (COND*) 0, (SQL_LIST*) 0,
 
927
  thd->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
 
928
  ha_enable_transaction(thd, false);
 
929
  mysql_init_select(thd->lex);
 
930
  bool save_binlog_row_based= thd->current_stmt_binlog_row_based;
 
931
  thd->clear_current_stmt_binlog_row_based();
 
932
  error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
420
933
                      HA_POS_ERROR, 0L, true);
 
934
  ha_enable_transaction(thd, true);
421
935
  /*
422
936
    Safety, in case the engine ignored ha_enable_transaction(false)
423
 
    above. Also clears session->transaction.*.
 
937
    above. Also clears thd->transaction.*.
424
938
  */
425
 
  error= transaction_services.autocommitOrRollback(session, error);
426
 
  session.options= save_options;
427
 
 
428
 
  return error;
 
939
  error= ha_autocommit_or_rollback(thd, error);
 
940
  ha_commit(thd);
 
941
  thd->options= save_options;
 
942
  thd->current_stmt_binlog_row_based= save_binlog_row_based;
 
943
  return(error);
429
944
}
430
 
 
431
 
} /* namespace drizzled */