~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL 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; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1 by brian
clean slate
15
16
/*
17
  Delete of records and truncate of tables.
18
19
  Multi-table deletes were introduced by Monty and Sinisa
20
*/
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
21
#include <config.h>
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>
2234.1.4 by Olaf van der Spek
Refactor includes
34
#include <drizzled/sql_lex.h>
2239.1.5 by Olaf van der Spek
Refactor includes
35
#include <drizzled/diagnostics_area.h>
2241.3.1 by Olaf van der Spek
Refactor Session::status_var
36
#include <drizzled/statistics_variables.h>
2241.3.4 by Olaf van der Spek
Refactor Session::transaction
37
#include <drizzled/session/transactions.h>
1 by brian
clean slate
38
2239.1.5 by Olaf van der Spek
Refactor includes
39
namespace drizzled {
1130.1.4 by Monty Taylor
Moved StorageEngine into plugin namespace.
40
1 by brian
clean slate
41
/**
42
  Implement DELETE SQL word.
43
44
  @note Like implementations of other DDL/DML in MySQL, this function
45
  relies on the caller to close the thread tables. This is done in the
46
  end of dispatch_command().
47
*/
48
2026.2.1 by Monty Taylor
Renamed things prefixed mysql_ or mysqld_
49
bool delete_query(Session *session, TableList *table_list, COND *conds,
1237.6.1 by Brian Aker
Remove dead bits in parser/whitespace/etc.
50
                  SQL_LIST *order, ha_rows limit, uint64_t,
1 by brian
clean slate
51
                  bool reset_auto_increment)
52
{
1237.6.1 by Brian Aker
Remove dead bits in parser/whitespace/etc.
53
  int		error;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
54
  Table		*table;
1237.13.3 by Padraig O'Sullivan
Performed numerous style cleanups in range.[cc,h].
55
  optimizer::SqlSelect *select= NULL;
1538 by Brian Aker
Code shuffle on ReadRecord
56
  ReadRecord	info;
1 by brian
clean slate
57
  bool          using_limit=limit != HA_POS_ERROR;
58
  ha_rows	deleted= 0;
482 by Brian Aker
Remove uint.
59
  uint32_t usable_index= MAX_KEY;
2227.4.8 by Olaf van der Spek
Session::lex()
60
  Select_Lex   *select_lex= &session->lex().select_lex;
1910.2.8 by Brian Aker
Enapsulate Kill.
61
  Session::killed_state_t killed_status= Session::NOT_KILLED;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
62
1109.1.3 by Brian Aker
Move names around a bit (to align similar methods)
63
  if (session->openTablesLock(table_list))
1126.10.7 by Padraig O'Sullivan
Added calls to the dtrace delete begin/end probes.
64
  {
65
    DRIZZLE_DELETE_DONE(1, 0);
1109.1.2 by Brian Aker
More from the table patch
66
    return true;
1126.10.7 by Padraig O'Sullivan
Added calls to the dtrace delete begin/end probes.
67
  }
737 by Brian Aker
Updates for dead code removal (and forced assert() in delete).
68
69
  table= table_list->table;
70
  assert(table);
71
520.1.22 by Brian Aker
Second pass of thd cleanup
72
  session->set_proc_info("init");
1 by brian
clean slate
73
  table->map=1;
74
2026.2.1 by Monty Taylor
Renamed things prefixed mysql_ or mysqld_
75
  if (prepare_delete(session, table_list, &conds))
1864.3.21 by Brian Aker
sql_delete removal of goto
76
  {
77
    DRIZZLE_DELETE_DONE(1, 0);
78
    return true;
79
  }
1 by brian
clean slate
80
81
  /* check ORDER BY even if it can be ignored */
82
  if (order && order->elements)
83
  {
327.2.4 by Brian Aker
Refactoring table.h
84
    TableList   tables;
1 by brian
clean slate
85
    List<Item>   fields;
86
    List<Item>   all_fields;
87
88
    tables.table = table;
89
    tables.alias = table_list->alias;
90
2318.6.31 by Olaf van der Spek
Refactor
91
    select_lex->setup_ref_array(session, order->elements);
92
    if (setup_order(session, select_lex->ref_pointer_array, &tables, fields, all_fields, (Order*) order->first))
93
    {
94
      delete select;
95
      free_underlaid_joins(session, &session->lex().select_lex);
96
      DRIZZLE_DELETE_DONE(1, 0);
1864.3.21 by Brian Aker
sql_delete removal of goto
97
2318.6.31 by Olaf van der Spek
Refactor
98
      return true;
99
    }
1 by brian
clean slate
100
  }
101
2318.6.37 by Olaf van der Spek
Refactor
102
  bool const_cond= not conds || conds->const_item();
1 by brian
clean slate
103
2227.4.8 by Olaf van der Spek
Session::lex()
104
  select_lex->no_error= session->lex().ignore;
1 by brian
clean slate
105
2318.6.37 by Olaf van der Spek
Refactor
106
  bool const_cond_result= const_cond && (!conds || conds->val_int());
520.1.22 by Brian Aker
Second pass of thd cleanup
107
  if (session->is_error())
1 by brian
clean slate
108
  {
109
    /* Error evaluating val_int(). */
2318.6.55 by Olaf van der Spek
Refactor
110
    return true;
1 by brian
clean slate
111
  }
112
113
  /*
114
    Test if the user wants to delete all rows and deletion doesn't have
115
    any side-effects (because of triggers), so we can use optimized
116
    handler::delete_all_rows() method.
117
118
    We implement fast TRUNCATE for InnoDB even if triggers are
119
    present.  TRUNCATE ignores triggers.
120
121
    We can use delete_all_rows() if and only if:
122
    - We allow new functions (not using option --skip-new), and are
123
      not in safe mode (not using option --safe-mode)
124
    - There is no limit clause
125
    - The condition is constant
126
    - If there is a condition, then it it produces a non-zero value
127
    - If the current command is DELETE FROM with no where clause
128
      (i.e., not TRUNCATE) then:
129
      - We should not be binlogging this statement row-based, and
130
      - there should be no delete triggers associated with the table.
131
  */
581 by Brian Aker
Second pass through on replication row patch
132
  if (!using_limit && const_cond_result)
1 by brian
clean slate
133
  {
1208.3.2 by brian
Update for Cursor renaming.
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()))
1 by brian
clean slate
138
    {
139
      error= -1;				// ok
140
      deleted= maybe_deleted;
141
      goto cleanup;
142
    }
143
    if (error != HA_ERR_WRONG_COMMAND)
144
    {
1216.1.1 by Brian Aker
Move print_error up to Engine.
145
      table->print_error(error,MYF(0));
1 by brian
clean slate
146
      error=0;
147
      goto cleanup;
148
    }
149
    /* Handler didn't support fast delete; Delete rows one by one */
150
  }
151
  if (conds)
152
  {
153
    Item::cond_result result;
520.1.22 by Brian Aker
Second pass of thd cleanup
154
    conds= remove_eq_conds(session, conds, &result);
1 by brian
clean slate
155
    if (result == Item::COND_FALSE)             // Impossible where
156
      limit= 0;
157
  }
158
1208.3.2 by brian
Update for Cursor renaming.
159
  /* Update the table->cursor->stats.records number */
160
  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1 by brian
clean slate
161
1005.2.6 by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<>
162
  table->covering_keys.reset();
163
  table->quick_keys.reset();		// Can't use 'only index'
1237.9.2 by Padraig O'Sullivan
Moved opt_range.[cc,h] into the optimizer directory and namespace and renamed the files to
164
  select= optimizer::make_select(table, 0, 0, conds, 0, &error);
1 by brian
clean slate
165
  if (error)
1864.3.21 by Brian Aker
sql_delete removal of goto
166
  {
167
    DRIZZLE_DELETE_DONE(1, 0);
168
    return true;
169
  }
170
1237.6.1 by Brian Aker
Remove dead bits in parser/whitespace/etc.
171
  if ((select && select->check_quick(session, false, limit)) || !limit)
1 by brian
clean slate
172
  {
173
    delete select;
520.1.22 by Brian Aker
Second pass of thd cleanup
174
    free_underlaid_joins(session, select_lex);
175
    session->row_count_func= 0;
2062.4.1 by Andrew Hutchings
Backport http://bugs.mysql.com/bug.php?id=40113
176
    if (session->is_error())
177
      return true;
1126.10.18 by Padraig O'Sullivan
Various small build fixes for when dtrace is enabled.
178
    DRIZZLE_DELETE_DONE(0, 0);
1124.2.14 by Diego Medina
* On certain UPDATE and DELETE statements, drizzled failed an assert() in
179
    /**
180
     * Resetting the Diagnostic area to prevent
181
     * lp bug# 439719
182
     */
2239.1.4 by Olaf van der Spek
Refactor includes
183
    session->main_da().reset_diagnostics_area();
2148.5.2 by Brian Aker
Additional remove of current_session.
184
    session->my_ok((ha_rows) session->rowCount());
1 by brian
clean slate
185
    /*
186
      We don't need to call reset_auto_increment in this case, because
187
      mysql_truncate always gives a NULL conds argument, hence we never
188
      get here.
189
    */
1126.10.7 by Padraig O'Sullivan
Added calls to the dtrace delete begin/end probes.
190
    return 0; // Nothing to delete
1 by brian
clean slate
191
  }
192
193
  /* If running in safe sql mode, don't allow updates without keys */
1005.2.6 by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<>
194
  if (table->quick_keys.none())
1 by brian
clean slate
195
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
196
    session->server_status|=SERVER_QUERY_NO_INDEX_USED;
1 by brian
clean slate
197
  }
198
199
  if (order && order->elements)
200
  {
1005.2.6 by Monty Taylor
Re-added bitset<> as a replacement for Bitmap<>
201
    if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
1892.3.3 by tdavies
struct order_st changed and renamed to c++ class named:Order
202
      usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
1 by brian
clean slate
203
204
    if (usable_index == MAX_KEY)
205
    {
1905.1.1 by Brian Aker
Adding FileSort class.
206
      FileSort filesort(*session);
2296.1.1 by Mark Atwood
Merge in Fixes of Brian's IOCACHE.
207
      table->sort.io_cache= new internal::io_cache_st;
2318.6.37 by Olaf van der Spek
Refactor
208
      uint32_t length= 0;
209
      SortField* sortorder= make_unireg_sortorder((Order*) order->first, &length, NULL);
210
      ha_rows examined_rows;
2318.6.36 by Olaf van der Spek
Refactor
211
      if ((table->sort.found_records= filesort.run(table, sortorder, length, select, HA_POS_ERROR, 1, examined_rows)) == HA_POS_ERROR)
1 by brian
clean slate
212
      {
213
        delete select;
2227.4.8 by Olaf van der Spek
Session::lex()
214
        free_underlaid_joins(session, &session->lex().select_lex);
1864.3.21 by Brian Aker
sql_delete removal of goto
215
216
        DRIZZLE_DELETE_DONE(1, 0);
217
        return true;
1 by brian
clean slate
218
      }
219
      /*
220
        Filesort has already found and selected the rows we want to delete,
221
        so we don't need the where clause
222
      */
223
      delete select;
520.1.22 by Brian Aker
Second pass of thd cleanup
224
      free_underlaid_joins(session, select_lex);
1 by brian
clean slate
225
      select= 0;
226
    }
227
  }
228
229
  /* If quick select is used, initialize it before retrieving rows. */
230
  if (select && select->quick && select->quick->reset())
231
  {
232
    delete select;
520.1.22 by Brian Aker
Second pass of thd cleanup
233
    free_underlaid_joins(session, select_lex);
1864.3.21 by Brian Aker
sql_delete removal of goto
234
    DRIZZLE_DELETE_DONE(1, 0);
235
    return true;
1 by brian
clean slate
236
  }
1237.6.1 by Brian Aker
Remove dead bits in parser/whitespace/etc.
237
1 by brian
clean slate
238
  if (usable_index==MAX_KEY)
1538 by Brian Aker
Code shuffle on ReadRecord
239
  {
2049.2.1 by Stewart Smith
doStartTableScan() result not checked.
240
    if ((error= info.init_read_record(session,table,select,1,1)))
241
    {
242
      table->print_error(error, MYF(0));
243
      delete select;
244
      free_underlaid_joins(session, select_lex);
245
      return true;
246
    }
1538 by Brian Aker
Code shuffle on ReadRecord
247
  }
1 by brian
clean slate
248
  else
1538 by Brian Aker
Code shuffle on ReadRecord
249
  {
2049.2.7 by Stewart Smith
init_read_record_idx return result should be checked now that it checks startIndexScan result.
250
    if ((error= info.init_read_record_idx(session, table, 1, usable_index)))
251
    {
252
      table->print_error(error, MYF(0));
253
      delete select;
254
      free_underlaid_joins(session, select_lex);
255
      return true;
256
    }
1538 by Brian Aker
Code shuffle on ReadRecord
257
  }
1 by brian
clean slate
258
520.1.22 by Brian Aker
Second pass of thd cleanup
259
  session->set_proc_info("updating");
1 by brian
clean slate
260
261
  table->mark_columns_needed_for_delete();
262
1910.2.8 by Brian Aker
Enapsulate Kill.
263
  while (!(error=info.read_record(&info)) && !session->getKilled() &&
520.1.22 by Brian Aker
Second pass of thd cleanup
264
	 ! session->is_error())
1 by brian
clean slate
265
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
266
    // session->is_error() is tested to disallow delete row on error
267
    if (!(select && select->skip_record())&& ! session->is_error() )
1 by brian
clean slate
268
    {
1672.3.6 by Brian Aker
First pass in encapsulating row
269
      if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
1 by brian
clean slate
270
      {
271
	deleted++;
272
	if (!--limit && using_limit)
273
	{
274
	  error= -1;
275
	  break;
276
	}
277
      }
278
      else
279
      {
1216.1.1 by Brian Aker
Move print_error up to Engine.
280
	table->print_error(error,MYF(0));
1 by brian
clean slate
281
	/*
282
	  In < 4.0.14 we set the error number to 0 here, but that
283
	  was not sensible, because then MySQL would not roll back the
284
	  failed DELETE, and also wrote it to the binlog. For MyISAM
285
	  tables a DELETE probably never should fail (?), but for
286
	  InnoDB it can fail in a FOREIGN KEY error or an
287
	  out-of-tablespace error.
288
	*/
289
 	error= 1;
290
	break;
291
      }
292
    }
293
    else
1208.3.2 by brian
Update for Cursor renaming.
294
      table->cursor->unlock_row();  // Row failed selection, release lock on it
1 by brian
clean slate
295
  }
1910.2.8 by Brian Aker
Enapsulate Kill.
296
  killed_status= session->getKilled();
520.1.22 by Brian Aker
Second pass of thd cleanup
297
  if (killed_status != Session::NOT_KILLED || session->is_error())
1 by brian
clean slate
298
    error= 1;					// Aborted
1237.6.1 by Brian Aker
Remove dead bits in parser/whitespace/etc.
299
520.1.22 by Brian Aker
Second pass of thd cleanup
300
  session->set_proc_info("end");
1538 by Brian Aker
Code shuffle on ReadRecord
301
  info.end_read_record();
1 by brian
clean slate
302
1208.2.2 by Brian Aker
Merge Truncate patch. This fixes all of the "half setup" of Truncate. Still
303
cleanup:
304
1 by brian
clean slate
305
  if (reset_auto_increment && (error < 0))
306
  {
307
    /*
308
      We're really doing a truncate and need to reset the table's
309
      auto-increment counter.
310
    */
1208.3.2 by brian
Update for Cursor renaming.
311
    int error2= table->cursor->ha_reset_auto_increment(0);
1 by brian
clean slate
312
313
    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
314
    {
1216.1.1 by Brian Aker
Move print_error up to Engine.
315
      table->print_error(error2, MYF(0));
1 by brian
clean slate
316
      error= 1;
317
    }
318
  }
319
320
  delete select;
2318.6.37 by Olaf van der Spek
Refactor
321
  bool transactional_table= table->cursor->has_transactions();
1 by brian
clean slate
322
323
  if (!transactional_table && deleted > 0)
1273.1.13 by Jay Pipes
Style cleanup around TransactionContext::modified_non_trans_table and dead code removal
324
    session->transaction.stmt.markModifiedNonTransData();
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
325
1 by brian
clean slate
326
  /* See similar binlogging code in sql_update.cc, for comments */
1273.1.13 by Jay Pipes
Style cleanup around TransactionContext::modified_non_trans_table and dead code removal
327
  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
1 by brian
clean slate
328
  {
1273.1.13 by Jay Pipes
Style cleanup around TransactionContext::modified_non_trans_table and dead code removal
329
    if (session->transaction.stmt.hasModifiedNonTransData())
330
      session->transaction.all.markModifiedNonTransData();
1 by brian
clean slate
331
  }
1273.1.13 by Jay Pipes
Style cleanup around TransactionContext::modified_non_trans_table and dead code removal
332
  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
520.1.22 by Brian Aker
Second pass of thd cleanup
333
  free_underlaid_joins(session, select_lex);
1 by brian
clean slate
334
1126.10.25 by Padraig O'Sullivan
Updated calls to some dtrace probes to cast the parameter to const char *
335
  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
2227.4.8 by Olaf van der Spek
Session::lex()
336
  if (error < 0 || (session->lex().ignore && !session->is_fatal_error))
1 by brian
clean slate
337
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
338
    session->row_count_func= deleted;
1124.2.14 by Diego Medina
* On certain UPDATE and DELETE statements, drizzled failed an assert() in
339
    /**
340
     * Resetting the Diagnostic area to prevent
341
     * lp bug# 439719
342
     */
2239.1.4 by Olaf van der Spek
Refactor includes
343
    session->main_da().reset_diagnostics_area();
2148.5.2 by Brian Aker
Additional remove of current_session.
344
    session->my_ok((ha_rows) session->rowCount());
1 by brian
clean slate
345
  }
1625.2.2 by Joe Daly
add counter logic for rows sent/received/inserted/updated
346
  session->status_var.deleted_row_count+= deleted;
1864.3.21 by Brian Aker
sql_delete removal of goto
347
1126.10.7 by Padraig O'Sullivan
Added calls to the dtrace delete begin/end probes.
348
  return (error >= 0 || session->is_error());
1 by brian
clean slate
349
}
350
351
352
/*
353
  Prepare items in DELETE statement
354
355
  SYNOPSIS
2026.2.1 by Monty Taylor
Renamed things prefixed mysql_ or mysqld_
356
    prepare_delete()
520.1.22 by Brian Aker
Second pass of thd cleanup
357
    session			- thread handler
1 by brian
clean slate
358
    table_list		- global/local table list
359
    conds		- conditions
360
361
  RETURN VALUE
163 by Brian Aker
Merge Monty's code.
362
    false OK
363
    true  error
1 by brian
clean slate
364
*/
2026.2.1 by Monty Taylor
Renamed things prefixed mysql_ or mysqld_
365
int prepare_delete(Session *session, TableList *table_list, Item **conds)
1 by brian
clean slate
366
{
2227.4.8 by Olaf van der Spek
Session::lex()
367
  Select_Lex *select_lex= &session->lex().select_lex;
368
  session->lex().allow_sum_func= 0;
2318.6.37 by Olaf van der Spek
Refactor
369
  if (setup_tables_and_check_access(session, &session->lex().select_lex.context, &select_lex->top_join_list, 
370
    table_list, &select_lex->leaf_tables, false) ||
1109.1.5 by Brian Aker
More extraction from sql_base
371
      session->setup_conds(table_list, conds))
2318.6.55 by Olaf van der Spek
Refactor
372
    return true;
2318.6.37 by Olaf van der Spek
Refactor
373
374
  if (unique_table(table_list, table_list->next_global))
1 by brian
clean slate
375
  {
2318.6.37 by Olaf van der Spek
Refactor
376
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
2318.6.55 by Olaf van der Spek
Refactor
377
    return true;
1 by brian
clean slate
378
  }
2318.6.37 by Olaf van der Spek
Refactor
379
  List<Item> all_fields;
380
  if (select_lex->inner_refs_list.size() && fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
2318.6.55 by Olaf van der Spek
Refactor
381
    return true;
382
  return false;
1 by brian
clean slate
383
}
384
385
386
/***************************************************************************
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
387
  TRUNCATE Table
1 by brian
clean slate
388
****************************************************************************/
389
390
/*
391
  Optimize delete of all rows by doing a full generate of the table
392
  This will work even if the .ISM and .ISD tables are destroyed
393
*/
394
2026.2.1 by Monty Taylor
Renamed things prefixed mysql_ or mysqld_
395
bool truncate(Session& session, TableList *table_list)
1 by brian
clean slate
396
{
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
397
  uint64_t save_options= session.options;
1 by brian
clean slate
398
  table_list->lock_type= TL_WRITE;
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
399
  session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
2227.4.10 by Olaf van der Spek
Session::lex()
400
  init_select(&session.lex());
2318.6.37 by Olaf van der Spek
Refactor
401
  int error= delete_query(&session, table_list, (COND*) 0, (SQL_LIST*) 0, HA_POS_ERROR, 0L, true);
1 by brian
clean slate
402
  /*
163 by Brian Aker
Merge Monty's code.
403
    Safety, in case the engine ignored ha_enable_transaction(false)
520.1.22 by Brian Aker
Second pass of thd cleanup
404
    above. Also clears session->transaction.*.
1 by brian
clean slate
405
  */
2318.6.62 by Olaf van der Spek
Refactor
406
  error= TransactionServices::autocommitOrRollback(session, error);
1183.1.29 by Brian Aker
Clean up interface so that Truncate sets the propper engine when
407
  session.options= save_options;
1208.2.2 by Brian Aker
Merge Truncate patch. This fixes all of the "half setup" of Truncate. Still
408
  return error;
1 by brian
clean slate
409
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
410
411
} /* namespace drizzled */