~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 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
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/**
17
  @file handler.cc
18
19
  Handler-calling-functions
20
*/
21
243.1.17 by Jay Pipes
FINAL PHASE removal of mysql_priv.h (Bye, bye my friend.)
22
#include <drizzled/server_includes.h>
1 by brian
clean slate
23
#include "rpl_filter.h"
202.3.6 by Monty Taylor
First pass at gettexizing the error messages.
24
#include <drizzled/drizzled_error_messages.h>
1 by brian
clean slate
25
26
/*
27
  While we have legacy_db_type, we have this array to
28
  check for dups and to find handlerton from legacy_db_type.
29
  Remove when legacy_db_type is finally gone
30
*/
31
st_plugin_int *hton2plugin[MAX_HA];
32
33
static handlerton *installed_htons[128];
34
461 by Monty Taylor
Removed NullS. bu-bye.
35
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NULL,0}, {NULL,0} };
1 by brian
clean slate
36
37
/* number of entries in handlertons[] */
61 by Brian Aker
Conversion of handler type.
38
uint32_t total_ha= 0;
1 by brian
clean slate
39
/* number of storage engines (from handlertons[]) that support 2pc */
61 by Brian Aker
Conversion of handler type.
40
uint32_t total_ha_2pc= 0;
1 by brian
clean slate
41
/* size of savepoint storage area (see ha_init) */
61 by Brian Aker
Conversion of handler type.
42
uint32_t savepoint_alloc_size= 0;
1 by brian
clean slate
43
44
static const LEX_STRING sys_table_aliases[]=
45
{
46
  { C_STRING_WITH_LEN("INNOBASE") },  { C_STRING_WITH_LEN("INNODB") },
47
  { C_STRING_WITH_LEN("HEAP") },      { C_STRING_WITH_LEN("MEMORY") },
461 by Monty Taylor
Removed NullS. bu-bye.
48
  {NULL, 0}
1 by brian
clean slate
49
};
50
51
const char *ha_row_type[] = {
52
  "", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "PAGE", "?","?","?"
53
};
54
55
const char *tx_isolation_names[] =
56
{ "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE",
461 by Monty Taylor
Removed NullS. bu-bye.
57
  NULL};
1 by brian
clean slate
58
TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
59
			       tx_isolation_names, NULL};
60
61
static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
482 by Brian Aker
Remove uint.
62
uint32_t known_extensions_id= 0;
1 by brian
clean slate
63
64
65
520.1.22 by Brian Aker
Second pass of thd cleanup
66
static plugin_ref ha_default_plugin(Session *session)
1 by brian
clean slate
67
{
520.1.22 by Brian Aker
Second pass of thd cleanup
68
  if (session->variables.table_plugin)
69
    return session->variables.table_plugin;
70
  return my_plugin_lock(session, &global_system_variables.table_plugin);
1 by brian
clean slate
71
}
72
73
74
/**
75
  Return the default storage engine handlerton for thread
76
520.1.22 by Brian Aker
Second pass of thd cleanup
77
  @param ha_default_handlerton(session)
78
  @param session         current thread
1 by brian
clean slate
79
80
  @return
81
    pointer to handlerton
82
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
83
handlerton *ha_default_handlerton(Session *session)
1 by brian
clean slate
84
{
520.1.22 by Brian Aker
Second pass of thd cleanup
85
  plugin_ref plugin= ha_default_plugin(session);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
86
  assert(plugin);
1 by brian
clean slate
87
  handlerton *hton= plugin_data(plugin, handlerton*);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
88
  assert(hton);
1 by brian
clean slate
89
  return hton;
90
}
91
92
93
/**
94
  Return the storage engine handlerton for the supplied name
95
  
520.1.22 by Brian Aker
Second pass of thd cleanup
96
  @param session         current thread
1 by brian
clean slate
97
  @param name        name of storage engine
98
  
99
  @return
100
    pointer to storage engine plugin handle
101
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
102
plugin_ref ha_resolve_by_name(Session *session, const LEX_STRING *name)
1 by brian
clean slate
103
{
104
  const LEX_STRING *table_alias;
105
  plugin_ref plugin;
106
107
redo:
108
  /* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
520.1.22 by Brian Aker
Second pass of thd cleanup
109
  if (session && !my_charset_utf8_general_ci.coll->strnncoll(&my_charset_utf8_general_ci,
481 by Brian Aker
Remove all of uchar.
110
                           (const unsigned char *)name->str, name->length,
111
                           (const unsigned char *)STRING_WITH_LEN("DEFAULT"), 0))
520.1.22 by Brian Aker
Second pass of thd cleanup
112
    return ha_default_plugin(session);
1 by brian
clean slate
113
520.1.22 by Brian Aker
Second pass of thd cleanup
114
  if ((plugin= my_plugin_lock_by_name(session, name, DRIZZLE_STORAGE_ENGINE_PLUGIN)))
1 by brian
clean slate
115
  {
116
    handlerton *hton= plugin_data(plugin, handlerton *);
117
    if (!(hton->flags & HTON_NOT_USER_SELECTABLE))
118
      return plugin;
119
      
120
    /*
121
      unlocking plugin immediately after locking is relatively low cost.
122
    */
520.1.22 by Brian Aker
Second pass of thd cleanup
123
    plugin_unlock(session, plugin);
1 by brian
clean slate
124
  }
125
126
  /*
127
    We check for the historical aliases.
128
  */
129
  for (table_alias= sys_table_aliases; table_alias->str; table_alias+= 2)
130
  {
383.1.12 by Brian Aker
Much closer toward UTF8 being around all the time...
131
    if (!my_strnncoll(&my_charset_utf8_general_ci,
481 by Brian Aker
Remove all of uchar.
132
                      (const unsigned char *)name->str, name->length,
133
                      (const unsigned char *)table_alias->str, table_alias->length))
1 by brian
clean slate
134
    {
135
      name= table_alias + 1;
136
      goto redo;
137
    }
138
  }
139
140
  return NULL;
141
}
142
143
520.1.22 by Brian Aker
Second pass of thd cleanup
144
plugin_ref ha_lock_engine(Session *session, handlerton *hton)
1 by brian
clean slate
145
{
146
  if (hton)
147
  {
148
    st_plugin_int **plugin= hton2plugin + hton->slot;
149
    
520.1.22 by Brian Aker
Second pass of thd cleanup
150
    return my_plugin_lock(session, &plugin);
1 by brian
clean slate
151
  }
152
  return NULL;
153
}
154
155
520.1.22 by Brian Aker
Second pass of thd cleanup
156
handlerton *ha_resolve_by_legacy_type(Session *session, enum legacy_db_type db_type)
1 by brian
clean slate
157
{
158
  plugin_ref plugin;
159
  switch (db_type) {
160
  case DB_TYPE_DEFAULT:
520.1.22 by Brian Aker
Second pass of thd cleanup
161
    return ha_default_handlerton(session);
1 by brian
clean slate
162
  default:
163
    if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
520.1.22 by Brian Aker
Second pass of thd cleanup
164
        (plugin= ha_lock_engine(session, installed_htons[db_type])))
1 by brian
clean slate
165
      return plugin_data(plugin, handlerton*);
166
    /* fall through */
167
  case DB_TYPE_UNKNOWN:
168
    return NULL;
169
  }
170
}
171
172
173
/**
174
  Use other database handler if databasehandler is not compiled in.
175
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
176
handlerton *ha_checktype(Session *session, enum legacy_db_type database_type,
1 by brian
clean slate
177
                          bool no_substitute, bool report_error)
178
{
520.1.22 by Brian Aker
Second pass of thd cleanup
179
  handlerton *hton= ha_resolve_by_legacy_type(session, database_type);
1 by brian
clean slate
180
  if (ha_storage_engine_is_enabled(hton))
181
    return hton;
182
183
  if (no_substitute)
184
  {
185
    if (report_error)
186
    {
187
      const char *engine_name= ha_resolve_storage_engine_name(hton);
188
      my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name);
189
    }
190
    return NULL;
191
  }
192
520.1.22 by Brian Aker
Second pass of thd cleanup
193
  return ha_default_handlerton(session);
1 by brian
clean slate
194
} /* ha_checktype */
195
196
197
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
198
                         handlerton *db_type)
199
{
200
  handler *file;
201
202
  if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
203
  {
204
    if ((file= db_type->create(db_type, share, alloc)))
205
      file->init();
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
206
    return(file);
1 by brian
clean slate
207
  }
208
  /*
209
    Try the default table type
520.1.22 by Brian Aker
Second pass of thd cleanup
210
    Here the call to current_session() is ok as we call this function a lot of
1 by brian
clean slate
211
    times but we enter this branch very seldom.
212
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
213
  return(get_new_handler(share, alloc, ha_default_handlerton(current_session)));
1 by brian
clean slate
214
}
215
216
217
/**
218
  Register handler error messages for use with my_error().
219
220
  @retval
221
    0           OK
222
  @retval
223
    !=0         Error
224
*/
225
226
int ha_init_errors(void)
227
{
228
#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg)
229
  const char    **errmsgs;
230
231
  /* Allocate a pointer array for the error message strings. */
232
  /* Zerofill it to avoid uninitialized gaps. */
233
  if (! (errmsgs= (const char**) my_malloc(HA_ERR_ERRORS * sizeof(char*),
234
                                           MYF(MY_WME | MY_ZEROFILL))))
235
    return 1;
236
237
  /* Set the dedicated error messages. */
238
  SETMSG(HA_ERR_KEY_NOT_FOUND,          ER(ER_KEY_NOT_FOUND));
239
  SETMSG(HA_ERR_FOUND_DUPP_KEY,         ER(ER_DUP_KEY));
240
  SETMSG(HA_ERR_RECORD_CHANGED,         "Update wich is recoverable");
241
  SETMSG(HA_ERR_WRONG_INDEX,            "Wrong index given to function");
242
  SETMSG(HA_ERR_CRASHED,                ER(ER_NOT_KEYFILE));
243
  SETMSG(HA_ERR_WRONG_IN_RECORD,        ER(ER_CRASHED_ON_USAGE));
244
  SETMSG(HA_ERR_OUT_OF_MEM,             "Table handler out of memory");
245
  SETMSG(HA_ERR_NOT_A_TABLE,            "Incorrect file format '%.64s'");
246
  SETMSG(HA_ERR_WRONG_COMMAND,          "Command not supported");
247
  SETMSG(HA_ERR_OLD_FILE,               ER(ER_OLD_KEYFILE));
248
  SETMSG(HA_ERR_NO_ACTIVE_RECORD,       "No record read in update");
249
  SETMSG(HA_ERR_RECORD_DELETED,         "Intern record deleted");
250
  SETMSG(HA_ERR_RECORD_FILE_FULL,       ER(ER_RECORD_FILE_FULL));
251
  SETMSG(HA_ERR_INDEX_FILE_FULL,        "No more room in index file '%.64s'");
252
  SETMSG(HA_ERR_END_OF_FILE,            "End in next/prev/first/last");
253
  SETMSG(HA_ERR_UNSUPPORTED,            ER(ER_ILLEGAL_HA));
254
  SETMSG(HA_ERR_TO_BIG_ROW,             "Too big row");
255
  SETMSG(HA_WRONG_CREATE_OPTION,        "Wrong create option");
256
  SETMSG(HA_ERR_FOUND_DUPP_UNIQUE,      ER(ER_DUP_UNIQUE));
257
  SETMSG(HA_ERR_UNKNOWN_CHARSET,        "Can't open charset");
258
  SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF,    ER(ER_WRONG_MRG_TABLE));
259
  SETMSG(HA_ERR_CRASHED_ON_REPAIR,      ER(ER_CRASHED_ON_REPAIR));
260
  SETMSG(HA_ERR_CRASHED_ON_USAGE,       ER(ER_CRASHED_ON_USAGE));
261
  SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT,      ER(ER_LOCK_WAIT_TIMEOUT));
262
  SETMSG(HA_ERR_LOCK_TABLE_FULL,        ER(ER_LOCK_TABLE_FULL));
263
  SETMSG(HA_ERR_READ_ONLY_TRANSACTION,  ER(ER_READ_ONLY_TRANSACTION));
264
  SETMSG(HA_ERR_LOCK_DEADLOCK,          ER(ER_LOCK_DEADLOCK));
265
  SETMSG(HA_ERR_CANNOT_ADD_FOREIGN,     ER(ER_CANNOT_ADD_FOREIGN));
266
  SETMSG(HA_ERR_NO_REFERENCED_ROW,      ER(ER_NO_REFERENCED_ROW_2));
267
  SETMSG(HA_ERR_ROW_IS_REFERENCED,      ER(ER_ROW_IS_REFERENCED_2));
268
  SETMSG(HA_ERR_NO_SAVEPOINT,           "No savepoint with that name");
269
  SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE,  "Non unique key block size");
270
  SETMSG(HA_ERR_NO_SUCH_TABLE,          "No such table: '%.64s'");
271
  SETMSG(HA_ERR_TABLE_EXIST,            ER(ER_TABLE_EXISTS_ERROR));
272
  SETMSG(HA_ERR_NO_CONNECTION,          "Could not connect to storage engine");
273
  SETMSG(HA_ERR_TABLE_DEF_CHANGED,      ER(ER_TABLE_DEF_CHANGED));
274
  SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY,  "FK constraint would lead to duplicate key");
275
  SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE,    ER(ER_TABLE_NEEDS_UPGRADE));
276
  SETMSG(HA_ERR_TABLE_READONLY,         ER(ER_OPEN_AS_READONLY));
277
  SETMSG(HA_ERR_AUTOINC_READ_FAILED,    ER(ER_AUTOINC_READ_FAILED));
278
  SETMSG(HA_ERR_AUTOINC_ERANGE,         ER(ER_WARN_DATA_OUT_OF_RANGE));
279
280
  /* Register the error messages for use with my_error(). */
281
  return my_error_register(errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
282
}
283
284
285
/**
286
  Unregister handler error messages.
287
288
  @retval
289
    0           OK
290
  @retval
291
    !=0         Error
292
*/
293
static int ha_finish_errors(void)
294
{
295
  const char    **errmsgs;
296
297
  /* Allocate a pointer array for the error message strings. */
298
  if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
299
    return 1;
481 by Brian Aker
Remove all of uchar.
300
  free((unsigned char*) errmsgs);
1 by brian
clean slate
301
  return 0;
302
}
303
304
305
int ha_finalize_handlerton(st_plugin_int *plugin)
306
{
307
  handlerton *hton= (handlerton *)plugin->data;
308
309
  switch (hton->state)
310
  {
311
  case SHOW_OPTION_NO:
312
  case SHOW_OPTION_DISABLED:
313
    break;
314
  case SHOW_OPTION_YES:
315
    if (installed_htons[hton->db_type] == hton)
316
      installed_htons[hton->db_type]= NULL;
317
    break;
318
  };
319
224.2.3 by Brian Aker
Fix for memory leak in shutdown/restart of an engine (not fixed in 5.1)
320
  if (hton && plugin->plugin->deinit)
321
    (void)plugin->plugin->deinit(hton);
1 by brian
clean slate
322
481 by Brian Aker
Remove all of uchar.
323
  free((unsigned char*)hton);
1 by brian
clean slate
324
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
325
  return(0);
1 by brian
clean slate
326
}
327
328
329
int ha_initialize_handlerton(st_plugin_int *plugin)
330
{
331
  handlerton *hton;
332
333
  hton= (handlerton *)my_malloc(sizeof(handlerton),
334
                                MYF(MY_WME | MY_ZEROFILL));
335
  /* 
336
    FIXME: the MY_ZEROFILL flag above doesn't zero all the bytes.
337
    
338
    This was detected after adding get_backup_engine member to handlerton
339
    structure. Apparently get_backup_engine was not NULL even though it was
340
    not initialized.
341
   */
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
342
  memset(hton, 0, sizeof(hton));
1 by brian
clean slate
343
  /* Historical Requirement */
344
  plugin->data= hton; // shortcut for the future
345
  if (plugin->plugin->init)
346
  {
347
    if (plugin->plugin->init(hton))
348
    {
338 by Monty Taylor
Tagged more strings.
349
      sql_print_error(_("Plugin '%s' init function returned error."),
1 by brian
clean slate
350
                      plugin->name.str);
351
      goto err;
352
    }
353
  }
354
355
  /*
356
    the switch below and hton->state should be removed when
357
    command-line options for plugins will be implemented
358
  */
359
  switch (hton->state) {
360
  case SHOW_OPTION_NO:
361
    break;
362
  case SHOW_OPTION_YES:
363
    {
482 by Brian Aker
Remove uint.
364
      uint32_t tmp;
1 by brian
clean slate
365
      /* now check the db_type for conflict */
366
      if (hton->db_type <= DB_TYPE_UNKNOWN ||
367
          hton->db_type >= DB_TYPE_DEFAULT ||
368
          installed_htons[hton->db_type])
369
      {
370
        int idx= (int) DB_TYPE_FIRST_DYNAMIC;
371
372
        while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
373
          idx++;
374
375
        if (idx == (int) DB_TYPE_DEFAULT)
376
        {
338 by Monty Taylor
Tagged more strings.
377
          sql_print_warning(_("Too many storage engines!"));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
378
          return(1);
1 by brian
clean slate
379
        }
380
        if (hton->db_type != DB_TYPE_UNKNOWN)
338 by Monty Taylor
Tagged more strings.
381
          sql_print_warning(_("Storage engine '%s' has conflicting typecode. "
382
                            "Assigning value %d."), plugin->plugin->name, idx);
1 by brian
clean slate
383
        hton->db_type= (enum legacy_db_type) idx;
384
      }
385
      installed_htons[hton->db_type]= hton;
386
      tmp= hton->savepoint_offset;
387
      hton->savepoint_offset= savepoint_alloc_size;
388
      savepoint_alloc_size+= tmp;
389
      hton->slot= total_ha++;
390
      hton2plugin[hton->slot]=plugin;
391
      if (hton->prepare)
392
        total_ha_2pc++;
393
      break;
394
    }
395
    /* fall through */
396
  default:
397
    hton->state= SHOW_OPTION_DISABLED;
398
    break;
399
  }
400
  
401
  /* 
402
    This is entirely for legacy. We will create a new "disk based" hton and a 
403
    "memory" hton which will be configurable longterm. We should be able to 
404
    remove partition and myisammrg.
405
  */
409 by Brian Aker
First pass to dump legacy types (wow! this has been a long time coming)
406
  if (strcmp(plugin->plugin->name, "MEMORY") == 0)
1 by brian
clean slate
407
    heap_hton= hton;
409 by Brian Aker
First pass to dump legacy types (wow! this has been a long time coming)
408
409
  if (strcmp(plugin->plugin->name, "MyISAM") == 0)
1 by brian
clean slate
410
    myisam_hton= hton;
411
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
412
  return(0);
1 by brian
clean slate
413
err:
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
414
  return(1);
1 by brian
clean slate
415
}
416
417
int ha_init()
418
{
419
  int error= 0;
420
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
421
  assert(total_ha < MAX_HA);
1 by brian
clean slate
422
  /*
423
    Check if there is a transaction-capable storage engine besides the
424
    binary log (which is considered a transaction-capable storage engine in
425
    counting total_ha)
426
  */
61 by Brian Aker
Conversion of handler type.
427
  opt_using_transactions= total_ha>(uint32_t)opt_bin_log;
1 by brian
clean slate
428
  savepoint_alloc_size+= sizeof(SAVEPOINT);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
429
  return(error);
1 by brian
clean slate
430
}
431
432
int ha_end()
433
{
434
  int error= 0;
435
436
  /* 
437
    This should be eventualy based  on the graceful shutdown flag.
438
    So if flag is equal to HA_PANIC_CLOSE, the deallocate
439
    the errors.
440
  */
441
  if (ha_finish_errors())
442
    error= 1;
443
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
444
  return(error);
1 by brian
clean slate
445
}
446
520.1.21 by Brian Aker
THD -> Session rename
447
static bool dropdb_handlerton(Session *unused1 __attribute__((unused)),
149 by Brian Aker
More bool conversion.
448
                              plugin_ref plugin,
449
                              void *path)
1 by brian
clean slate
450
{
451
  handlerton *hton= plugin_data(plugin, handlerton *);
452
  if (hton->state == SHOW_OPTION_YES && hton->drop_database)
453
    hton->drop_database(hton, (char *)path);
56 by brian
Next pass of true/false update.
454
  return false;
1 by brian
clean slate
455
}
456
457
458
void ha_drop_database(char* path)
459
{
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
460
  plugin_foreach(NULL, dropdb_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, path);
1 by brian
clean slate
461
}
462
463
520.1.22 by Brian Aker
Second pass of thd cleanup
464
static bool closecon_handlerton(Session *session, plugin_ref plugin,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
465
                                void *unused __attribute__((unused)))
1 by brian
clean slate
466
{
467
  handlerton *hton= plugin_data(plugin, handlerton *);
468
  /*
469
    there's no need to rollback here as all transactions must
470
    be rolled back already
471
  */
472
  if (hton->state == SHOW_OPTION_YES && hton->close_connection &&
520.1.22 by Brian Aker
Second pass of thd cleanup
473
      session_get_ha_data(session, hton))
474
    hton->close_connection(hton, session);
56 by brian
Next pass of true/false update.
475
  return false;
1 by brian
clean slate
476
}
477
478
479
/**
480
  @note
481
    don't bother to rollback here, it's done already
482
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
483
void ha_close_connection(Session* session)
1 by brian
clean slate
484
{
520.1.22 by Brian Aker
Second pass of thd cleanup
485
  plugin_foreach(session, closecon_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, 0);
1 by brian
clean slate
486
}
487
488
/* ========================================================================
489
 ======================= TRANSACTIONS ===================================*/
490
491
/**
492
  Transaction handling in the server
493
  ==================================
494
495
  In each client connection, MySQL maintains two transactional
496
  states:
497
  - a statement transaction,
498
  - a standard, also called normal transaction.
499
500
  Historical note
501
  ---------------
502
  "Statement transaction" is a non-standard term that comes
503
  from the times when MySQL supported BerkeleyDB storage engine.
504
505
  First of all, it should be said that in BerkeleyDB auto-commit
506
  mode auto-commits operations that are atomic to the storage
507
  engine itself, such as a write of a record, and are too
508
  high-granular to be atomic from the application perspective
509
  (MySQL). One SQL statement could involve many BerkeleyDB
510
  auto-committed operations and thus BerkeleyDB auto-commit was of
511
  little use to MySQL.
512
513
  Secondly, instead of SQL standard savepoints, BerkeleyDB
514
  provided the concept of "nested transactions". In a nutshell,
515
  transactions could be arbitrarily nested, but when the parent
516
  transaction was committed or aborted, all its child (nested)
517
  transactions were handled committed or aborted as well.
518
  Commit of a nested transaction, in turn, made its changes
519
  visible, but not durable: it destroyed the nested transaction,
520
  all its changes would become available to the parent and
521
  currently active nested transactions of this parent.
522
523
  So the mechanism of nested transactions was employed to
524
  provide "all or nothing" guarantee of SQL statements
525
  required by the standard.
526
  A nested transaction would be created at start of each SQL
527
  statement, and destroyed (committed or aborted) at statement
528
  end. Such nested transaction was internally referred to as
529
  a "statement transaction" and gave birth to the term.
530
531
  <Historical note ends>
532
533
  Since then a statement transaction is started for each statement
534
  that accesses transactional tables or uses the binary log.  If
535
  the statement succeeds, the statement transaction is committed.
536
  If the statement fails, the transaction is rolled back. Commits
537
  of statement transactions are not durable -- each such
538
  transaction is nested in the normal transaction, and if the
539
  normal transaction is rolled back, the effects of all enclosed
540
  statement transactions are undone as well.  Technically,
541
  a statement transaction can be viewed as a savepoint which is
542
  maintained automatically in order to make effects of one
543
  statement atomic.
544
545
  The normal transaction is started by the user and is ended
546
  usually upon a user request as well. The normal transaction
547
  encloses transactions of all statements issued between
548
  its beginning and its end.
549
  In autocommit mode, the normal transaction is equivalent
550
  to the statement transaction.
551
552
  Since MySQL supports PSEA (pluggable storage engine
553
  architecture), more than one transactional engine can be
554
  active at a time. Hence transactions, from the server
555
  point of view, are always distributed. In particular,
556
  transactional state is maintained independently for each
557
  engine. In order to commit a transaction the two phase
558
  commit protocol is employed.
559
560
  Not all statements are executed in context of a transaction.
561
  Administrative and status information statements do not modify
562
  engine data, and thus do not start a statement transaction and
563
  also have no effect on the normal transaction. Examples of such
564
  statements are SHOW STATUS and RESET SLAVE.
565
566
  Similarly DDL statements are not transactional,
567
  and therefore a transaction is [almost] never started for a DDL
568
  statement. The difference between a DDL statement and a purely
569
  administrative statement though is that a DDL statement always
570
  commits the current transaction before proceeding, if there is
571
  any.
572
573
  At last, SQL statements that work with non-transactional
574
  engines also have no effect on the transaction state of the
575
  connection. Even though they are written to the binary log,
576
  and the binary log is, overall, transactional, the writes
577
  are done in "write-through" mode, directly to the binlog
578
  file, followed with a OS cache sync, in other words,
579
  bypassing the binlog undo log (translog).
580
  They do not commit the current normal transaction.
581
  A failure of a statement that uses non-transactional tables
582
  would cause a rollback of the statement transaction, but
583
  in case there no non-transactional tables are used,
584
  no statement transaction is started.
585
586
  Data layout
587
  -----------
588
589
  The server stores its transaction-related data in
520.1.22 by Brian Aker
Second pass of thd cleanup
590
  session->transaction. This structure has two members of type
520.1.21 by Brian Aker
THD -> Session rename
591
  Session_TRANS. These members correspond to the statement and
1 by brian
clean slate
592
  normal transactions respectively:
593
520.1.22 by Brian Aker
Second pass of thd cleanup
594
  - session->transaction.stmt contains a list of engines
1 by brian
clean slate
595
  that are participating in the given statement
520.1.22 by Brian Aker
Second pass of thd cleanup
596
  - session->transaction.all contains a list of engines that
1 by brian
clean slate
597
  have participated in any of the statement transactions started
598
  within the context of the normal transaction.
599
  Each element of the list contains a pointer to the storage
600
  engine, engine-specific transactional data, and engine-specific
601
  transaction flags.
602
520.1.22 by Brian Aker
Second pass of thd cleanup
603
  In autocommit mode session->transaction.all is empty.
604
  Instead, data of session->transaction.stmt is
1 by brian
clean slate
605
  used to commit/rollback the normal transaction.
606
607
  The list of registered engines has a few important properties:
608
  - no engine is registered in the list twice
609
  - engines are present in the list a reverse temporal order --
610
  new participants are always added to the beginning of the list.
611
612
  Transaction life cycle
613
  ----------------------
614
520.1.22 by Brian Aker
Second pass of thd cleanup
615
  When a new connection is established, session->transaction
1 by brian
clean slate
616
  members are initialized to an empty state.
617
  If a statement uses any tables, all affected engines
618
  are registered in the statement engine list. In
619
  non-autocommit mode, the same engines are registered in
620
  the normal transaction list.
621
  At the end of the statement, the server issues a commit
622
  or a roll back for all engines in the statement list.
623
  At this point transaction flags of an engine, if any, are
624
  propagated from the statement list to the list of the normal
625
  transaction.
626
  When commit/rollback is finished, the statement list is
627
  cleared. It will be filled in again by the next statement,
628
  and emptied again at the next statement's end.
629
630
  The normal transaction is committed in a similar way
520.1.22 by Brian Aker
Second pass of thd cleanup
631
  (by going over all engines in session->transaction.all list)
1 by brian
clean slate
632
  but at different times:
633
  - upon COMMIT SQL statement is issued by the user
634
  - implicitly, by the server, at the beginning of a DDL statement
635
  or SET AUTOCOMMIT={0|1} statement.
636
637
  The normal transaction can be rolled back as well:
638
  - if the user has requested so, by issuing ROLLBACK SQL
639
  statement
640
  - if one of the storage engines requested a rollback
520.1.22 by Brian Aker
Second pass of thd cleanup
641
  by setting session->transaction_rollback_request. This may
1 by brian
clean slate
642
  happen in case, e.g., when the transaction in the engine was
643
  chosen a victim of the internal deadlock resolution algorithm
644
  and rolled back internally. When such a situation happens, there
645
  is little the server can do and the only option is to rollback
646
  transactions in all other participating engines.  In this case
647
  the rollback is accompanied by an error sent to the user.
648
649
  As follows from the use cases above, the normal transaction
650
  is never committed when there is an outstanding statement
651
  transaction. In most cases there is no conflict, since
652
  commits of the normal transaction are issued by a stand-alone
653
  administrative or DDL statement, thus no outstanding statement
654
  transaction of the previous statement exists. Besides,
655
  all statements that manipulate with the normal transaction
656
  are prohibited in stored functions and triggers, therefore
657
  no conflicting situation can occur in a sub-statement either.
658
  The remaining rare cases when the server explicitly has
659
  to commit the statement transaction prior to committing the normal
660
  one cover error-handling scenarios (see for example
661
  SQLCOM_LOCK_TABLES).
662
663
  When committing a statement or a normal transaction, the server
664
  either uses the two-phase commit protocol, or issues a commit
665
  in each engine independently. The two-phase commit protocol
666
  is used only if:
667
  - all participating engines support two-phase commit (provide
668
    handlerton::prepare PSEA API call) and
669
  - transactions in at least two engines modify data (i.e. are
670
  not read-only).
671
672
  Note that the two phase commit is used for
673
  statement transactions, even though they are not durable anyway.
674
  This is done to ensure logical consistency of data in a multiple-
675
  engine transaction.
676
  For example, imagine that some day MySQL supports unique
677
  constraint checks deferred till the end of statement. In such
678
  case a commit in one of the engines may yield ER_DUP_KEY,
679
  and MySQL should be able to gracefully abort statement
680
  transactions of other participants.
681
682
  After the normal transaction has been committed,
520.1.22 by Brian Aker
Second pass of thd cleanup
683
  session->transaction.all list is cleared.
1 by brian
clean slate
684
685
  When a connection is closed, the current normal transaction, if
686
  any, is rolled back.
687
688
  Roles and responsibilities
689
  --------------------------
690
691
  The server has no way to know that an engine participates in
692
  the statement and a transaction has been started
693
  in it unless the engine says so. Thus, in order to be
694
  a part of a transaction, the engine must "register" itself.
695
  This is done by invoking trans_register_ha() server call.
696
  Normally the engine registers itself whenever handler::external_lock()
697
  is called. trans_register_ha() can be invoked many times: if
698
  an engine is already registered, the call does nothing.
699
  In case autocommit is not set, the engine must register itself
700
  twice -- both in the statement list and in the normal transaction
701
  list.
702
  In which list to register is a parameter of trans_register_ha().
703
704
  Note, that although the registration interface in itself is
705
  fairly clear, the current usage practice often leads to undesired
706
  effects. E.g. since a call to trans_register_ha() in most engines
707
  is embedded into implementation of handler::external_lock(), some
708
  DDL statements start a transaction (at least from the server
709
  point of view) even though they are not expected to. E.g.
710
  CREATE TABLE does not start a transaction, since
711
  handler::external_lock() is never called during CREATE TABLE. But
712
  CREATE TABLE ... SELECT does, since handler::external_lock() is
713
  called for the table that is being selected from. This has no
714
  practical effects currently, but must be kept in mind
715
  nevertheless.
716
717
  Once an engine is registered, the server will do the rest
718
  of the work.
719
720
  During statement execution, whenever any of data-modifying
721
  PSEA API methods is used, e.g. handler::write_row() or
722
  handler::update_row(), the read-write flag is raised in the
723
  statement transaction for the involved engine.
724
  Currently All PSEA calls are "traced", and the data can not be
725
  changed in a way other than issuing a PSEA call. Important:
726
  unless this invariant is preserved the server will not know that
727
  a transaction in a given engine is read-write and will not
728
  involve the two-phase commit protocol!
729
730
  At the end of a statement, server call
731
  ha_autocommit_or_rollback() is invoked. This call in turn
732
  invokes handlerton::prepare() for every involved engine.
733
  Prepare is followed by a call to handlerton::commit_one_phase()
734
  If a one-phase commit will suffice, handlerton::prepare() is not
735
  invoked and the server only calls handlerton::commit_one_phase().
736
  At statement commit, the statement-related read-write engine
737
  flag is propagated to the corresponding flag in the normal
738
  transaction.  When the commit is complete, the list of registered
739
  engines is cleared.
740
741
  Rollback is handled in a similar fashion.
742
743
  Additional notes on DDL and the normal transaction.
744
  ---------------------------------------------------
745
746
  DDLs and operations with non-transactional engines
520.1.22 by Brian Aker
Second pass of thd cleanup
747
  do not "register" in session->transaction lists, and thus do not
1 by brian
clean slate
748
  modify the transaction state. Besides, each DDL in
749
  MySQL is prefixed with an implicit normal transaction commit
750
  (a call to end_active_trans()), and thus leaves nothing
751
  to modify.
752
  However, as it has been pointed out with CREATE TABLE .. SELECT,
753
  some DDL statements can start a *new* transaction.
754
755
  Behaviour of the server in this case is currently badly
756
  defined.
757
  DDL statements use a form of "semantic" logging
758
  to maintain atomicity: if CREATE TABLE .. SELECT failed,
759
  the newly created table is deleted.
760
  In addition, some DDL statements issue interim transaction
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
761
  commits: e.g. ALTER Table issues a commit after data is copied
1 by brian
clean slate
762
  from the original table to the internal temporary table. Other
763
  statements, e.g. CREATE TABLE ... SELECT do not always commit
764
  after itself.
765
  And finally there is a group of DDL statements such as
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
766
  RENAME/DROP Table that doesn't start a new transaction
1 by brian
clean slate
767
  and doesn't commit.
768
769
  This diversity makes it hard to say what will happen if
770
  by chance a stored function is invoked during a DDL --
771
  whether any modifications it makes will be committed or not
772
  is not clear. Fortunately, SQL grammar of few DDLs allows
773
  invocation of a stored function.
774
775
  A consistent behaviour is perhaps to always commit the normal
776
  transaction after all DDLs, just like the statement transaction
777
  is always committed at the end of all statements.
778
*/
779
780
/**
781
  Register a storage engine for a transaction.
782
783
  Every storage engine MUST call this function when it starts
784
  a transaction or a statement (that is it must be called both for the
785
  "beginning of transaction" and "beginning of statement").
786
  Only storage engines registered for the transaction/statement
787
  will know when to commit/rollback it.
788
789
  @note
790
    trans_register_ha is idempotent - storage engine may register many
791
    times per transaction.
792
793
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
794
void trans_register_ha(Session *session, bool all, handlerton *ht_arg)
1 by brian
clean slate
795
{
520.1.21 by Brian Aker
THD -> Session rename
796
  Session_TRANS *trans;
1 by brian
clean slate
797
  Ha_trx_info *ha_info;
798
799
  if (all)
800
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
801
    trans= &session->transaction.all;
802
    session->server_status|= SERVER_STATUS_IN_TRANS;
1 by brian
clean slate
803
  }
804
  else
520.1.22 by Brian Aker
Second pass of thd cleanup
805
    trans= &session->transaction.stmt;
1 by brian
clean slate
806
520.1.22 by Brian Aker
Second pass of thd cleanup
807
  ha_info= session->ha_data[ht_arg->slot].ha_info + static_cast<unsigned>(all);
1 by brian
clean slate
808
809
  if (ha_info->is_started())
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
810
    return; /* already registered, return */
1 by brian
clean slate
811
812
  ha_info->register_ha(trans, ht_arg);
813
814
  trans->no_2pc|=(ht_arg->prepare==0);
520.1.22 by Brian Aker
Second pass of thd cleanup
815
  if (session->transaction.xid_state.xid.is_null())
816
    session->transaction.xid_state.xid.set(session->query_id);
1 by brian
clean slate
817
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
818
  return;
1 by brian
clean slate
819
}
820
821
/**
822
  @retval
823
    0   ok
824
  @retval
825
    1   error, transaction was rolled back
826
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
827
int ha_prepare(Session *session)
1 by brian
clean slate
828
{
829
  int error=0, all=1;
520.1.22 by Brian Aker
Second pass of thd cleanup
830
  Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
1 by brian
clean slate
831
  Ha_trx_info *ha_info= trans->ha_list;
832
  if (ha_info)
833
  {
834
    for (; ha_info; ha_info= ha_info->next())
835
    {
836
      int err;
837
      handlerton *ht= ha_info->ht();
520.1.22 by Brian Aker
Second pass of thd cleanup
838
      status_var_increment(session->status_var.ha_prepare_count);
1 by brian
clean slate
839
      if (ht->prepare)
840
      {
520.1.22 by Brian Aker
Second pass of thd cleanup
841
        if ((err= ht->prepare(ht, session, all)))
1 by brian
clean slate
842
        {
843
          my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
520.1.22 by Brian Aker
Second pass of thd cleanup
844
          ha_rollback_trans(session, all);
1 by brian
clean slate
845
          error=1;
846
          break;
847
        }
848
      }
849
      else
850
      {
520.1.22 by Brian Aker
Second pass of thd cleanup
851
        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
852
                            ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
853
                            ha_resolve_storage_engine_name(ht));
854
      }
855
    }
856
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
857
  return(error);
1 by brian
clean slate
858
}
859
860
/**
861
  Check if we can skip the two-phase commit.
862
863
  A helper function to evaluate if two-phase commit is mandatory.
864
  As a side effect, propagates the read-only/read-write flags
865
  of the statement transaction to its enclosing normal transaction.
866
56 by brian
Next pass of true/false update.
867
  @retval true   we must run a two-phase commit. Returned
1 by brian
clean slate
868
                 if we have at least two engines with read-write changes.
56 by brian
Next pass of true/false update.
869
  @retval false  Don't need two-phase commit. Even if we have two
1 by brian
clean slate
870
                 transactional engines, we can run two independent
871
                 commits if changes in one of the engines are read-only.
872
*/
873
874
static
875
bool
520.1.22 by Brian Aker
Second pass of thd cleanup
876
ha_check_and_coalesce_trx_read_only(Session *session, Ha_trx_info *ha_list,
1 by brian
clean slate
877
                                    bool all)
878
{
879
  /* The number of storage engines that have actual changes. */
880
  unsigned rw_ha_count= 0;
881
  Ha_trx_info *ha_info;
882
883
  for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
884
  {
885
    if (ha_info->is_trx_read_write())
886
      ++rw_ha_count;
887
888
    if (! all)
889
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
890
      Ha_trx_info *ha_info_all= &session->ha_data[ha_info->ht()->slot].ha_info[1];
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
891
      assert(ha_info != ha_info_all);
1 by brian
clean slate
892
      /*
893
        Merge read-only/read-write information about statement
894
        transaction to its enclosing normal transaction. Do this
895
        only if in a real transaction -- that is, if we know
520.1.22 by Brian Aker
Second pass of thd cleanup
896
        that ha_info_all is registered in session->transaction.all.
1 by brian
clean slate
897
        Since otherwise we only clutter the normal transaction flags.
898
      */
56 by brian
Next pass of true/false update.
899
      if (ha_info_all->is_started()) /* false if autocommit. */
1 by brian
clean slate
900
        ha_info_all->coalesce_trx_with(ha_info);
901
    }
902
    else if (rw_ha_count > 1)
903
    {
904
      /*
905
        It is a normal transaction, so we don't need to merge read/write
906
        information up, and the need for two-phase commit has been
907
        already established. Break the loop prematurely.
908
      */
909
      break;
910
    }
911
  }
912
  return rw_ha_count > 1;
913
}
914
915
916
/**
917
  @retval
918
    0   ok
919
  @retval
920
    1   transaction was rolled back
921
  @retval
922
    2   error during commit, data may be inconsistent
923
924
  @todo
925
    Since we don't support nested statement transactions in 5.0,
926
    we can't commit or rollback stmt transactions while we are inside
927
    stored functions or triggers. So we simply do nothing now.
928
    TODO: This should be fixed in later ( >= 5.1) releases.
929
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
930
int ha_commit_trans(Session *session, bool all)
1 by brian
clean slate
931
{
932
  int error= 0, cookie= 0;
933
  /*
934
    'all' means that this is either an explicit commit issued by
935
    user, or an implicit commit issued by a DDL.
936
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
937
  Session_TRANS *trans= all ? &session->transaction.all : &session->transaction.stmt;
938
  bool is_real_trans= all || session->transaction.all.ha_list == 0;
1 by brian
clean slate
939
  Ha_trx_info *ha_info= trans->ha_list;
520.1.22 by Brian Aker
Second pass of thd cleanup
940
  my_xid xid= session->transaction.xid_state.xid.get_my_xid();
1 by brian
clean slate
941
942
  /*
943
    We must not commit the normal transaction if a statement
944
    transaction is pending. Otherwise statement transaction
945
    flags will not get propagated to its normal transaction's
946
    counterpart.
947
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
948
  assert(session->transaction.stmt.ha_list == NULL ||
949
              trans == &session->transaction.stmt);
1 by brian
clean slate
950
951
  if (ha_info)
952
  {
953
    bool must_2pc;
954
520.1.22 by Brian Aker
Second pass of thd cleanup
955
    if (is_real_trans && wait_if_global_read_lock(session, 0, 0))
1 by brian
clean slate
956
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
957
      ha_rollback_trans(session, all);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
958
      return(1);
1 by brian
clean slate
959
    }
960
961
    if (   is_real_trans
962
        && opt_readonly
520.1.22 by Brian Aker
Second pass of thd cleanup
963
        && ! session->slave_thread
1 by brian
clean slate
964
       )
965
    {
966
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
520.1.22 by Brian Aker
Second pass of thd cleanup
967
      ha_rollback_trans(session, all);
1 by brian
clean slate
968
      error= 1;
969
      goto end;
970
    }
971
520.1.22 by Brian Aker
Second pass of thd cleanup
972
    must_2pc= ha_check_and_coalesce_trx_read_only(session, ha_info, all);
1 by brian
clean slate
973
974
    if (!trans->no_2pc && must_2pc)
975
    {
976
      for (; ha_info && !error; ha_info= ha_info->next())
977
      {
978
        int err;
979
        handlerton *ht= ha_info->ht();
980
        /*
981
          Do not call two-phase commit if this particular
982
          transaction is read-only. This allows for simpler
983
          implementation in engines that are always read-only.
984
        */
985
        if (! ha_info->is_trx_read_write())
986
          continue;
987
        /*
988
          Sic: we know that prepare() is not NULL since otherwise
989
          trans->no_2pc would have been set.
990
        */
520.1.22 by Brian Aker
Second pass of thd cleanup
991
        if ((err= ht->prepare(ht, session, all)))
1 by brian
clean slate
992
        {
993
          my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
994
          error= 1;
995
        }
520.1.22 by Brian Aker
Second pass of thd cleanup
996
        status_var_increment(session->status_var.ha_prepare_count);
1 by brian
clean slate
997
      }
998
      if (error || (is_real_trans && xid &&
520.1.22 by Brian Aker
Second pass of thd cleanup
999
                    (error= !(cookie= tc_log->log_xid(session, xid)))))
1 by brian
clean slate
1000
      {
520.1.22 by Brian Aker
Second pass of thd cleanup
1001
        ha_rollback_trans(session, all);
1 by brian
clean slate
1002
        error= 1;
1003
        goto end;
1004
      }
1005
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1006
    error=ha_commit_one_phase(session, all) ? (cookie ? 2 : 1) : 0;
1 by brian
clean slate
1007
    if (cookie)
1008
      tc_log->unlog(cookie, xid);
1009
end:
1010
    if (is_real_trans)
520.1.22 by Brian Aker
Second pass of thd cleanup
1011
      start_waiting_global_read_lock(session);
1 by brian
clean slate
1012
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1013
  return(error);
1 by brian
clean slate
1014
}
1015
1016
/**
1017
  @note
1018
  This function does not care about global read lock. A caller should.
1019
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1020
int ha_commit_one_phase(Session *session, bool all)
1 by brian
clean slate
1021
{
1022
  int error=0;
520.1.22 by Brian Aker
Second pass of thd cleanup
1023
  Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
1024
  bool is_real_trans=all || session->transaction.all.ha_list == 0;
1 by brian
clean slate
1025
  Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
1026
  if (ha_info)
1027
  {
1028
    for (; ha_info; ha_info= ha_info_next)
1029
    {
1030
      int err;
1031
      handlerton *ht= ha_info->ht();
520.1.22 by Brian Aker
Second pass of thd cleanup
1032
      if ((err= ht->commit(ht, session, all)))
1 by brian
clean slate
1033
      {
1034
        my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
1035
        error=1;
1036
      }
520.1.22 by Brian Aker
Second pass of thd cleanup
1037
      status_var_increment(session->status_var.ha_commit_count);
1 by brian
clean slate
1038
      ha_info_next= ha_info->next();
1039
      ha_info->reset(); /* keep it conveniently zero-filled */
1040
    }
1041
    trans->ha_list= 0;
1042
    trans->no_2pc=0;
1043
    if (is_real_trans)
520.1.22 by Brian Aker
Second pass of thd cleanup
1044
      session->transaction.xid_state.xid.null();
1 by brian
clean slate
1045
    if (all)
1046
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
1047
      session->variables.tx_isolation=session->session_tx_isolation;
1048
      session->transaction.cleanup();
1 by brian
clean slate
1049
    }
1050
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1051
  return(error);
1 by brian
clean slate
1052
}
1053
1054
520.1.22 by Brian Aker
Second pass of thd cleanup
1055
int ha_rollback_trans(Session *session, bool all)
1 by brian
clean slate
1056
{
1057
  int error=0;
520.1.22 by Brian Aker
Second pass of thd cleanup
1058
  Session_TRANS *trans=all ? &session->transaction.all : &session->transaction.stmt;
1 by brian
clean slate
1059
  Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
520.1.22 by Brian Aker
Second pass of thd cleanup
1060
  bool is_real_trans=all || session->transaction.all.ha_list == 0;
1 by brian
clean slate
1061
1062
  /*
1063
    We must not rollback the normal transaction if a statement
1064
    transaction is pending.
1065
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
1066
  assert(session->transaction.stmt.ha_list == NULL ||
1067
              trans == &session->transaction.stmt);
1 by brian
clean slate
1068
1069
  if (ha_info)
1070
  {
1071
    for (; ha_info; ha_info= ha_info_next)
1072
    {
1073
      int err;
1074
      handlerton *ht= ha_info->ht();
520.1.22 by Brian Aker
Second pass of thd cleanup
1075
      if ((err= ht->rollback(ht, session, all)))
1 by brian
clean slate
1076
      { // cannot happen
1077
        my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
1078
        error=1;
1079
      }
520.1.22 by Brian Aker
Second pass of thd cleanup
1080
      status_var_increment(session->status_var.ha_rollback_count);
1 by brian
clean slate
1081
      ha_info_next= ha_info->next();
1082
      ha_info->reset(); /* keep it conveniently zero-filled */
1083
    }
1084
    trans->ha_list= 0;
1085
    trans->no_2pc=0;
1086
    if (is_real_trans)
520.1.22 by Brian Aker
Second pass of thd cleanup
1087
      session->transaction.xid_state.xid.null();
1 by brian
clean slate
1088
    if (all)
1089
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
1090
      session->variables.tx_isolation=session->session_tx_isolation;
1091
      session->transaction.cleanup();
1 by brian
clean slate
1092
    }
1093
  }
1094
  if (all)
520.1.22 by Brian Aker
Second pass of thd cleanup
1095
    session->transaction_rollback_request= false;
1 by brian
clean slate
1096
1097
  /*
1098
    If a non-transactional table was updated, warn; don't warn if this is a
1099
    slave thread (because when a slave thread executes a ROLLBACK, it has
1100
    been read from the binary log, so it's 100% sure and normal to produce
1101
    error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
1102
    slave SQL thread, it would not stop the thread but just be printed in
1103
    the error log; but we don't want users to wonder why they have this
1104
    message in the error log, so we don't send it.
1105
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
1106
  if (is_real_trans && session->transaction.all.modified_non_trans_table &&
1107
      !session->slave_thread && session->killed != Session::KILL_CONNECTION)
1108
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1 by brian
clean slate
1109
                 ER_WARNING_NOT_COMPLETE_ROLLBACK,
1110
                 ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1111
  return(error);
1 by brian
clean slate
1112
}
1113
1114
/**
1115
  This is used to commit or rollback a single statement depending on
1116
  the value of error.
1117
1118
  @note
1119
    Note that if the autocommit is on, then the following call inside
1120
    InnoDB will commit or rollback the whole transaction (= the statement). The
1121
    autocommit mechanism built into InnoDB is based on counting locks, but if
1122
    the user has used LOCK TABLES then that mechanism does not know to do the
1123
    commit.
1124
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1125
int ha_autocommit_or_rollback(Session *session, int error)
1 by brian
clean slate
1126
{
520.1.22 by Brian Aker
Second pass of thd cleanup
1127
  if (session->transaction.stmt.ha_list)
1 by brian
clean slate
1128
  {
1129
    if (!error)
1130
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
1131
      if (ha_commit_trans(session, 0))
1 by brian
clean slate
1132
	error=1;
1133
    }
1134
    else 
1135
    {
520.1.22 by Brian Aker
Second pass of thd cleanup
1136
      (void) ha_rollback_trans(session, 0);
1137
      if (session->transaction_rollback_request)
1138
        (void) ha_rollback(session);
1 by brian
clean slate
1139
    }
1140
520.1.22 by Brian Aker
Second pass of thd cleanup
1141
    session->variables.tx_isolation=session->session_tx_isolation;
1 by brian
clean slate
1142
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1143
  return(error);
1 by brian
clean slate
1144
}
1145
1146
1147
struct xahton_st {
1148
  XID *xid;
1149
  int result;
1150
};
1151
520.1.21 by Brian Aker
THD -> Session rename
1152
static bool xacommit_handlerton(Session *unused1 __attribute__((unused)),
149 by Brian Aker
More bool conversion.
1153
                                plugin_ref plugin,
1154
                                void *arg)
1 by brian
clean slate
1155
{
1156
  handlerton *hton= plugin_data(plugin, handlerton *);
1157
  if (hton->state == SHOW_OPTION_YES && hton->recover)
1158
  {
1159
    hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid);
1160
    ((struct xahton_st *)arg)->result= 0;
1161
  }
56 by brian
Next pass of true/false update.
1162
  return false;
1 by brian
clean slate
1163
}
1164
520.1.21 by Brian Aker
THD -> Session rename
1165
static bool xarollback_handlerton(Session *unused1 __attribute__((unused)),
149 by Brian Aker
More bool conversion.
1166
                                  plugin_ref plugin,
1167
                                  void *arg)
1 by brian
clean slate
1168
{
1169
  handlerton *hton= plugin_data(plugin, handlerton *);
1170
  if (hton->state == SHOW_OPTION_YES && hton->recover)
1171
  {
1172
    hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid);
1173
    ((struct xahton_st *)arg)->result= 0;
1174
  }
56 by brian
Next pass of true/false update.
1175
  return false;
1 by brian
clean slate
1176
}
1177
1178
1179
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
1180
{
1181
  struct xahton_st xaop;
1182
  xaop.xid= xid;
1183
  xaop.result= 1;
1184
1185
  plugin_foreach(NULL, commit ? xacommit_handlerton : xarollback_handlerton,
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1186
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &xaop);
1 by brian
clean slate
1187
1188
  return xaop.result;
1189
}
1190
1191
/**
1192
  recover() step of xa.
1193
1194
  @note
1195
    there are three modes of operation:
1196
    - automatic recover after a crash
1197
    in this case commit_list != 0, tc_heuristic_recover==0
1198
    all xids from commit_list are committed, others are rolled back
1199
    - manual (heuristic) recover
1200
    in this case commit_list==0, tc_heuristic_recover != 0
1201
    DBA has explicitly specified that all prepared transactions should
1202
    be committed (or rolled back).
1203
    - no recovery (MySQL did not detect a crash)
1204
    in this case commit_list==0, tc_heuristic_recover == 0
1205
    there should be no prepared transactions in this case.
1206
*/
1207
struct xarecover_st
1208
{
1209
  int len, found_foreign_xids, found_my_xids;
1210
  XID *list;
1211
  HASH *commit_list;
1212
  bool dry_run;
1213
};
1214
520.1.21 by Brian Aker
THD -> Session rename
1215
static bool xarecover_handlerton(Session *unused __attribute__((unused)),
149 by Brian Aker
More bool conversion.
1216
                                 plugin_ref plugin,
1217
                                 void *arg)
1 by brian
clean slate
1218
{
1219
  handlerton *hton= plugin_data(plugin, handlerton *);
1220
  struct xarecover_st *info= (struct xarecover_st *) arg;
1221
  int got;
1222
1223
  if (hton->state == SHOW_OPTION_YES && hton->recover)
1224
  {
1225
    while ((got= hton->recover(hton, info->list, info->len)) > 0 )
1226
    {
338 by Monty Taylor
Tagged more strings.
1227
      sql_print_information(_("Found %d prepared transaction(s) in %s"),
1 by brian
clean slate
1228
                            got, ha_resolve_storage_engine_name(hton));
1229
      for (int i=0; i < got; i ++)
1230
      {
1231
        my_xid x=info->list[i].get_my_xid();
1232
        if (!x) // not "mine" - that is generated by external TM
1233
        {
1234
          xid_cache_insert(info->list+i, XA_PREPARED);
1235
          info->found_foreign_xids++;
1236
          continue;
1237
        }
1238
        if (info->dry_run)
1239
        {
1240
          info->found_my_xids++;
1241
          continue;
1242
        }
1243
        // recovery mode
1244
        if (info->commit_list ?
481 by Brian Aker
Remove all of uchar.
1245
            hash_search(info->commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
1 by brian
clean slate
1246
            tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
1247
        {
1248
          hton->commit_by_xid(hton, info->list+i);
1249
        }
1250
        else
1251
        {
1252
          hton->rollback_by_xid(hton, info->list+i);
1253
        }
1254
      }
1255
      if (got < info->len)
1256
        break;
1257
    }
1258
  }
56 by brian
Next pass of true/false update.
1259
  return false;
1 by brian
clean slate
1260
}
1261
1262
int ha_recover(HASH *commit_list)
1263
{
1264
  struct xarecover_st info;
1265
  info.found_foreign_xids= info.found_my_xids= 0;
1266
  info.commit_list= commit_list;
1267
  info.dry_run= (info.commit_list==0 && tc_heuristic_recover==0);
1268
  info.list= NULL;
1269
1270
  /* commit_list and tc_heuristic_recover cannot be set both */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1271
  assert(info.commit_list==0 || tc_heuristic_recover==0);
1 by brian
clean slate
1272
  /* if either is set, total_ha_2pc must be set too */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1273
  assert(info.dry_run || total_ha_2pc>(uint32_t)opt_bin_log);
1 by brian
clean slate
1274
61 by Brian Aker
Conversion of handler type.
1275
  if (total_ha_2pc <= (uint32_t)opt_bin_log)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1276
    return(0);
1 by brian
clean slate
1277
1278
  if (info.commit_list)
338 by Monty Taylor
Tagged more strings.
1279
    sql_print_information(_("Starting crash recovery..."));
1 by brian
clean slate
1280
1281
1282
#ifndef WILL_BE_DELETED_LATER
1283
1284
  /*
1285
    for now, only InnoDB supports 2pc. It means we can always safely
1286
    rollback all pending transactions, without risking inconsistent data
1287
  */
1288
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1289
  assert(total_ha_2pc == (uint32_t) opt_bin_log+1); // only InnoDB and binlog
1 by brian
clean slate
1290
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
56 by brian
Next pass of true/false update.
1291
  info.dry_run=false;
1 by brian
clean slate
1292
#endif
1293
1294
1295
  for (info.len= MAX_XID_LIST_SIZE ; 
1296
       info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2)
1297
  {
1298
    info.list=(XID *)my_malloc(info.len*sizeof(XID), MYF(0));
1299
  }
1300
  if (!info.list)
1301
  {
1302
    sql_print_error(ER(ER_OUTOFMEMORY), info.len*sizeof(XID));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1303
    return(1);
1 by brian
clean slate
1304
  }
1305
1306
  plugin_foreach(NULL, xarecover_handlerton, 
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1307
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &info);
1 by brian
clean slate
1308
481 by Brian Aker
Remove all of uchar.
1309
  free((unsigned char*)info.list);
1 by brian
clean slate
1310
  if (info.found_foreign_xids)
338 by Monty Taylor
Tagged more strings.
1311
    sql_print_warning(_("Found %d prepared XA transactions"), 
1 by brian
clean slate
1312
                      info.found_foreign_xids);
1313
  if (info.dry_run && info.found_my_xids)
1314
  {
338 by Monty Taylor
Tagged more strings.
1315
    sql_print_error(_("Found %d prepared transactions! It means that drizzled "
1316
                    "was not shut down properly last time and critical "
1317
                    "recovery information (last binlog or %s file) was "
1318
                    "manually deleted after a crash. You have to start "
1319
                    "drizzled with the --tc-heuristic-recover switch to "
1320
                    "commit or rollback pending transactions."),
1 by brian
clean slate
1321
                    info.found_my_xids, opt_tc_log_file);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1322
    return(1);
1 by brian
clean slate
1323
  }
1324
  if (info.commit_list)
338 by Monty Taylor
Tagged more strings.
1325
    sql_print_information(_("Crash recovery finished."));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1326
  return(0);
1 by brian
clean slate
1327
}
1328
1329
/**
1330
  return the list of XID's to a client, the same way SHOW commands do.
1331
1332
  @note
1333
    I didn't find in XA specs that an RM cannot return the same XID twice,
1334
    so mysql_xa_recover does not filter XID's to ensure uniqueness.
1335
    It can be easily fixed later, if necessary.
1336
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1337
bool mysql_xa_recover(Session *session)
1 by brian
clean slate
1338
{
1339
  List<Item> field_list;
520.1.22 by Brian Aker
Second pass of thd cleanup
1340
  Protocol *protocol= session->protocol;
1 by brian
clean slate
1341
  int i=0;
1342
  XID_STATE *xs;
1343
1344
  field_list.push_back(new Item_int("formatID", 0, MY_INT32_NUM_DECIMAL_DIGITS));
1345
  field_list.push_back(new Item_int("gtrid_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
1346
  field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
1347
  field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
1348
1349
  if (protocol->send_fields(&field_list,
1350
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1351
    return(1);
1 by brian
clean slate
1352
1353
  pthread_mutex_lock(&LOCK_xid_cache);
1354
  while ((xs= (XID_STATE*)hash_element(&xid_cache, i++)))
1355
  {
1356
    if (xs->xa_state==XA_PREPARED)
1357
    {
1358
      protocol->prepare_for_resend();
152 by Brian Aker
longlong replacement
1359
      protocol->store_int64_t((int64_t)xs->xid.formatID, false);
1360
      protocol->store_int64_t((int64_t)xs->xid.gtrid_length, false);
1361
      protocol->store_int64_t((int64_t)xs->xid.bqual_length, false);
1 by brian
clean slate
1362
      protocol->store(xs->xid.data, xs->xid.gtrid_length+xs->xid.bqual_length,
1363
                      &my_charset_bin);
1364
      if (protocol->write())
1365
      {
1366
        pthread_mutex_unlock(&LOCK_xid_cache);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1367
        return(1);
1 by brian
clean slate
1368
      }
1369
    }
1370
  }
1371
1372
  pthread_mutex_unlock(&LOCK_xid_cache);
520.1.22 by Brian Aker
Second pass of thd cleanup
1373
  my_eof(session);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1374
  return(0);
1 by brian
clean slate
1375
}
1376
1377
/**
1378
  @details
1379
  This function should be called when MySQL sends rows of a SELECT result set
1380
  or the EOF mark to the client. It releases a possible adaptive hash index
520.1.22 by Brian Aker
Second pass of thd cleanup
1381
  S-latch held by session in InnoDB and also releases a possible InnoDB query
1382
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
1 by brian
clean slate
1383
  keep them over several calls of the InnoDB handler interface when a join
1384
  is executed. But when we let the control to pass to the client they have
1385
  to be released because if the application program uses mysql_use_result(),
1386
  it may deadlock on the S-latch if the application on another connection
1387
  performs another SQL query. In MySQL-4.1 this is even more important because
1388
  there a connection can have several SELECT queries open at the same time.
1389
520.1.22 by Brian Aker
Second pass of thd cleanup
1390
  @param session           the thread handle of the current connection
1 by brian
clean slate
1391
1392
  @return
1393
    always 0
1394
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1395
static bool release_temporary_latches(Session *session, plugin_ref plugin,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1396
                                      void *unused __attribute__((unused)))
1 by brian
clean slate
1397
{
1398
  handlerton *hton= plugin_data(plugin, handlerton *);
1399
1400
  if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches)
520.1.22 by Brian Aker
Second pass of thd cleanup
1401
    hton->release_temporary_latches(hton, session);
1 by brian
clean slate
1402
56 by brian
Next pass of true/false update.
1403
  return false;
1 by brian
clean slate
1404
}
1405
1406
520.1.22 by Brian Aker
Second pass of thd cleanup
1407
int ha_release_temporary_latches(Session *session)
1 by brian
clean slate
1408
{
520.1.22 by Brian Aker
Second pass of thd cleanup
1409
  plugin_foreach(session, release_temporary_latches, DRIZZLE_STORAGE_ENGINE_PLUGIN, 
1 by brian
clean slate
1410
                 NULL);
1411
1412
  return 0;
1413
}
1414
520.1.22 by Brian Aker
Second pass of thd cleanup
1415
int ha_rollback_to_savepoint(Session *session, SAVEPOINT *sv)
1 by brian
clean slate
1416
{
1417
  int error=0;
520.1.22 by Brian Aker
Second pass of thd cleanup
1418
  Session_TRANS *trans= &session->transaction.all;
1 by brian
clean slate
1419
  Ha_trx_info *ha_info, *ha_info_next;
1420
1421
  trans->no_2pc=0;
1422
  /*
1423
    rolling back to savepoint in all storage engines that were part of the
1424
    transaction when the savepoint was set
1425
  */
1426
  for (ha_info= sv->ha_list; ha_info; ha_info= ha_info->next())
1427
  {
1428
    int err;
1429
    handlerton *ht= ha_info->ht();
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1430
    assert(ht);
1431
    assert(ht->savepoint_set != 0);
520.1.22 by Brian Aker
Second pass of thd cleanup
1432
    if ((err= ht->savepoint_rollback(ht, session,
481 by Brian Aker
Remove all of uchar.
1433
                                     (unsigned char *)(sv+1)+ht->savepoint_offset)))
1 by brian
clean slate
1434
    { // cannot happen
1435
      my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
1436
      error=1;
1437
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1438
    status_var_increment(session->status_var.ha_savepoint_rollback_count);
1 by brian
clean slate
1439
    trans->no_2pc|= ht->prepare == 0;
1440
  }
1441
  /*
1442
    rolling back the transaction in all storage engines that were not part of
1443
    the transaction when the savepoint was set
1444
  */
1445
  for (ha_info= trans->ha_list; ha_info != sv->ha_list;
1446
       ha_info= ha_info_next)
1447
  {
1448
    int err;
1449
    handlerton *ht= ha_info->ht();
520.1.22 by Brian Aker
Second pass of thd cleanup
1450
    if ((err= ht->rollback(ht, session, !(0))))
1 by brian
clean slate
1451
    { // cannot happen
1452
      my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
1453
      error=1;
1454
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1455
    status_var_increment(session->status_var.ha_rollback_count);
1 by brian
clean slate
1456
    ha_info_next= ha_info->next();
1457
    ha_info->reset(); /* keep it conveniently zero-filled */
1458
  }
1459
  trans->ha_list= sv->ha_list;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1460
  return(error);
1 by brian
clean slate
1461
}
1462
1463
/**
1464
  @note
1465
  according to the sql standard (ISO/IEC 9075-2:2003)
1466
  section "4.33.4 SQL-statements and transaction states",
1467
  SAVEPOINT is *not* transaction-initiating SQL-statement
1468
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1469
int ha_savepoint(Session *session, SAVEPOINT *sv)
1 by brian
clean slate
1470
{
1471
  int error=0;
520.1.22 by Brian Aker
Second pass of thd cleanup
1472
  Session_TRANS *trans= &session->transaction.all;
1 by brian
clean slate
1473
  Ha_trx_info *ha_info= trans->ha_list;
1474
  for (; ha_info; ha_info= ha_info->next())
1475
  {
1476
    int err;
1477
    handlerton *ht= ha_info->ht();
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1478
    assert(ht);
1 by brian
clean slate
1479
    if (! ht->savepoint_set)
1480
    {
1481
      my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
1482
      error=1;
1483
      break;
1484
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1485
    if ((err= ht->savepoint_set(ht, session, (unsigned char *)(sv+1)+ht->savepoint_offset)))
1 by brian
clean slate
1486
    { // cannot happen
1487
      my_error(ER_GET_ERRNO, MYF(0), err);
1488
      error=1;
1489
    }
520.1.22 by Brian Aker
Second pass of thd cleanup
1490
    status_var_increment(session->status_var.ha_savepoint_count);
1 by brian
clean slate
1491
  }
1492
  /*
1493
    Remember the list of registered storage engines. All new
1494
    engines are prepended to the beginning of the list.
1495
  */
1496
  sv->ha_list= trans->ha_list;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1497
  return(error);
1 by brian
clean slate
1498
}
1499
520.1.22 by Brian Aker
Second pass of thd cleanup
1500
int ha_release_savepoint(Session *session, SAVEPOINT *sv)
1 by brian
clean slate
1501
{
1502
  int error=0;
1503
  Ha_trx_info *ha_info= sv->ha_list;
1504
1505
  for (; ha_info; ha_info= ha_info->next())
1506
  {
1507
    int err;
1508
    handlerton *ht= ha_info->ht();
1509
    /* Savepoint life time is enclosed into transaction life time. */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1510
    assert(ht);
1 by brian
clean slate
1511
    if (!ht->savepoint_release)
1512
      continue;
520.1.22 by Brian Aker
Second pass of thd cleanup
1513
    if ((err= ht->savepoint_release(ht, session,
481 by Brian Aker
Remove all of uchar.
1514
                                    (unsigned char *)(sv+1) + ht->savepoint_offset)))
1 by brian
clean slate
1515
    { // cannot happen
1516
      my_error(ER_GET_ERRNO, MYF(0), err);
1517
      error=1;
1518
    }
1519
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1520
  return(error);
1 by brian
clean slate
1521
}
1522
1523
520.1.22 by Brian Aker
Second pass of thd cleanup
1524
static bool snapshot_handlerton(Session *session, plugin_ref plugin, void *arg)
1 by brian
clean slate
1525
{
1526
  handlerton *hton= plugin_data(plugin, handlerton *);
1527
  if (hton->state == SHOW_OPTION_YES &&
1528
      hton->start_consistent_snapshot)
1529
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
1530
    hton->start_consistent_snapshot(hton, session);
1 by brian
clean slate
1531
    *((bool *)arg)= false;
1532
  }
56 by brian
Next pass of true/false update.
1533
  return false;
1 by brian
clean slate
1534
}
1535
520.1.22 by Brian Aker
Second pass of thd cleanup
1536
int ha_start_consistent_snapshot(Session *session)
1 by brian
clean slate
1537
{
1538
  bool warn= true;
1539
520.1.22 by Brian Aker
Second pass of thd cleanup
1540
  plugin_foreach(session, snapshot_handlerton, DRIZZLE_STORAGE_ENGINE_PLUGIN, &warn);
1 by brian
clean slate
1541
1542
  /*
1543
    Same idea as when one wants to CREATE TABLE in one engine which does not
1544
    exist:
1545
  */
1546
  if (warn)
520.1.22 by Brian Aker
Second pass of thd cleanup
1547
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1 by brian
clean slate
1548
                 "This MySQL server does not support any "
1549
                 "consistent-read capable storage engine");
1550
  return 0;
1551
}
1552
1553
520.1.22 by Brian Aker
Second pass of thd cleanup
1554
static bool flush_handlerton(Session *session __attribute__((unused)),
149 by Brian Aker
More bool conversion.
1555
                             plugin_ref plugin,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
1556
                             void *arg __attribute__((unused)))
1 by brian
clean slate
1557
{
1558
  handlerton *hton= plugin_data(plugin, handlerton *);
1559
  if (hton->state == SHOW_OPTION_YES && hton->flush_logs && 
1560
      hton->flush_logs(hton))
56 by brian
Next pass of true/false update.
1561
    return true;
1562
  return false;
1 by brian
clean slate
1563
}
1564
1565
1566
bool ha_flush_logs(handlerton *db_type)
1567
{
1568
  if (db_type == NULL)
1569
  {
1570
    if (plugin_foreach(NULL, flush_handlerton,
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
1571
                          DRIZZLE_STORAGE_ENGINE_PLUGIN, 0))
56 by brian
Next pass of true/false update.
1572
      return true;
1 by brian
clean slate
1573
  }
1574
  else
1575
  {
1576
    if (db_type->state != SHOW_OPTION_YES ||
1577
        (db_type->flush_logs && db_type->flush_logs(db_type)))
56 by brian
Next pass of true/false update.
1578
      return true;
1 by brian
clean slate
1579
  }
56 by brian
Next pass of true/false update.
1580
  return false;
1 by brian
clean slate
1581
}
1582
1583
static const char *check_lowercase_names(handler *file, const char *path,
1584
                                         char *tmp_path)
1585
{
1586
  if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
1587
    return path;
1588
1589
  /* Ensure that table handler get path in lower case */
1590
  if (tmp_path != path)
411.1.1 by Brian Aker
Work on removing GNU specific calls.
1591
    my_stpcpy(tmp_path, path);
1 by brian
clean slate
1592
1593
  /*
1594
    we only should turn into lowercase database/table part
1595
    so start the process after homedirectory
1596
  */
1597
  my_casedn_str(files_charset_info, tmp_path + mysql_data_home_len);
1598
  return tmp_path;
1599
}
1600
1601
1602
/**
1603
  An interceptor to hijack the text of the error message without
1604
  setting an error in the thread. We need the text to present it
1605
  in the form of a warning to the user.
1606
*/
1607
1608
struct Ha_delete_table_error_handler: public Internal_error_handler
1609
{
1610
public:
482 by Brian Aker
Remove uint.
1611
  virtual bool handle_error(uint32_t sql_errno,
1 by brian
clean slate
1612
                            const char *message,
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
1613
                            DRIZZLE_ERROR::enum_warning_level level,
520.1.22 by Brian Aker
Second pass of thd cleanup
1614
                            Session *session);
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
1615
  char buff[DRIZZLE_ERRMSG_SIZE];
1 by brian
clean slate
1616
};
1617
1618
1619
bool
1620
Ha_delete_table_error_handler::
482 by Brian Aker
Remove uint.
1621
handle_error(uint32_t sql_errno  __attribute__((unused)),
1 by brian
clean slate
1622
             const char *message,
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
1623
             DRIZZLE_ERROR::enum_warning_level level __attribute__((unused)),
520.1.22 by Brian Aker
Second pass of thd cleanup
1624
             Session *session __attribute__((unused)))
1 by brian
clean slate
1625
{
1626
  /* Grab the error message */
1627
  strmake(buff, message, sizeof(buff)-1);
56 by brian
Next pass of true/false update.
1628
  return true;
1 by brian
clean slate
1629
}
1630
1631
1632
/**
1633
  This should return ENOENT if the file doesn't exists.
1634
  The .frm file will be deleted only if we return 0 or ENOENT
1635
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
1636
int ha_delete_table(Session *session, handlerton *table_type, const char *path,
1 by brian
clean slate
1637
                    const char *db, const char *alias, bool generate_warning)
1638
{
1639
  handler *file;
1640
  char tmp_path[FN_REFLEN];
1641
  int error;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1642
  Table dummy_table;
1 by brian
clean slate
1643
  TABLE_SHARE dummy_share;
1644
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
1645
  memset(&dummy_table, 0, sizeof(dummy_table));
1646
  memset(&dummy_share, 0, sizeof(dummy_share));
1 by brian
clean slate
1647
  dummy_table.s= &dummy_share;
1648
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1649
  /* DB_TYPE_UNKNOWN is used in ALTER Table when renaming only .frm files */
1 by brian
clean slate
1650
  if (table_type == NULL ||
520.1.22 by Brian Aker
Second pass of thd cleanup
1651
      ! (file=get_new_handler((TABLE_SHARE*)0, session->mem_root, table_type)))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1652
    return(ENOENT);
1 by brian
clean slate
1653
1654
  path= check_lowercase_names(file, path, tmp_path);
1655
  if ((error= file->ha_delete_table(path)) && generate_warning)
1656
  {
1657
    /*
1658
      Because file->print_error() use my_error() to generate the error message
1659
      we use an internal error handler to intercept it and store the text
1660
      in a temporary buffer. Later the message will be presented to user
1661
      as a warning.
1662
    */
1663
    Ha_delete_table_error_handler ha_delete_table_error_handler;
1664
1665
    /* Fill up strucutures that print_error may need */
1666
    dummy_share.path.str= (char*) path;
1667
    dummy_share.path.length= strlen(path);
1668
    dummy_share.db.str= (char*) db;
1669
    dummy_share.db.length= strlen(db);
1670
    dummy_share.table_name.str= (char*) alias;
1671
    dummy_share.table_name.length= strlen(alias);
1672
    dummy_table.alias= alias;
1673
1674
    file->change_table_ptr(&dummy_table, &dummy_share);
1675
520.1.22 by Brian Aker
Second pass of thd cleanup
1676
    session->push_internal_handler(&ha_delete_table_error_handler);
1 by brian
clean slate
1677
    file->print_error(error, 0);
1678
520.1.22 by Brian Aker
Second pass of thd cleanup
1679
    session->pop_internal_handler();
1 by brian
clean slate
1680
1681
    /*
1682
      XXX: should we convert *all* errors to warnings here?
1683
      What if the error is fatal?
1684
    */
520.1.22 by Brian Aker
Second pass of thd cleanup
1685
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
1 by brian
clean slate
1686
                ha_delete_table_error_handler.buff);
1687
  }
1688
  delete file;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1689
  return(error);
1 by brian
clean slate
1690
}
1691
1692
/****************************************************************************
1693
** General handler functions
1694
****************************************************************************/
1695
handler *handler::clone(MEM_ROOT *mem_root)
1696
{
1697
  handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
1698
  /*
1699
    Allocate handler->ref here because otherwise ha_open will allocate it
1700
    on this->table->mem_root and we will not be able to reclaim that memory 
1701
    when the clone handler object is destroyed.
1702
  */
481 by Brian Aker
Remove all of uchar.
1703
  if (!(new_handler->ref= (unsigned char*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
1 by brian
clean slate
1704
    return NULL;
1705
  if (new_handler && !new_handler->ha_open(table,
1706
                                           table->s->normalized_path.str,
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1707
                                           table->getDBStat(),
1 by brian
clean slate
1708
                                           HA_OPEN_IGNORE_IF_LOCKED))
1709
    return new_handler;
1710
  return NULL;
1711
}
1712
1713
1714
1715
void handler::ha_statistic_increment(ulong SSV::*offset) const
1716
{
1717
  status_var_increment(table->in_use->status_var.*offset);
1718
}
1719
520.1.22 by Brian Aker
Second pass of thd cleanup
1720
void **handler::ha_data(Session *session) const
1 by brian
clean slate
1721
{
520.1.22 by Brian Aker
Second pass of thd cleanup
1722
  return session_ha_data(session, ht);
1 by brian
clean slate
1723
}
1724
520.1.22 by Brian Aker
Second pass of thd cleanup
1725
Session *handler::ha_session(void) const
1 by brian
clean slate
1726
{
520.1.22 by Brian Aker
Second pass of thd cleanup
1727
  assert(!table || !table->in_use || table->in_use == current_session);
1728
  return (table && table->in_use) ? table->in_use : current_session;
1 by brian
clean slate
1729
}
1730
1731
/**
1732
  Open database-handler.
1733
1734
  Try O_RDONLY if cannot open as O_RDWR
1735
  Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set
1736
*/
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
1737
int handler::ha_open(Table *table_arg, const char *name, int mode,
1 by brian
clean slate
1738
                     int test_if_locked)
1739
{
1740
  int error;
1741
1742
  table= table_arg;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1743
  assert(table->s == table_share);
1744
  assert(alloc_root_inited(&table->mem_root));
1 by brian
clean slate
1745
1746
  if ((error=open(name,mode,test_if_locked)))
1747
  {
1748
    if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
1749
	(table->db_stat & HA_TRY_READ_ONLY))
1750
    {
1751
      table->db_stat|=HA_READ_ONLY;
1752
      error=open(name,O_RDONLY,test_if_locked);
1753
    }
1754
  }
1755
  if (error)
1756
  {
1757
    my_errno= error;                            /* Safeguard */
1758
  }
1759
  else
1760
  {
1761
    if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
1762
      table->db_stat|=HA_READ_ONLY;
1763
    (void) extra(HA_EXTRA_NO_READCHECK);	// Not needed in SQL
1764
1765
    /* ref is already allocated for us if we're called from handler::clone() */
481 by Brian Aker
Remove all of uchar.
1766
    if (!ref && !(ref= (unsigned char*) alloc_root(&table->mem_root, 
1 by brian
clean slate
1767
                                          ALIGN_SIZE(ref_length)*2)))
1768
    {
1769
      close();
1770
      error=HA_ERR_OUT_OF_MEM;
1771
    }
1772
    else
1773
      dup_ref=ref+ALIGN_SIZE(ref_length);
1774
    cached_table_flags= table_flags();
1775
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1776
  return(error);
1 by brian
clean slate
1777
}
1778
1779
/**
1780
  one has to use this method when to find
1781
  random position by record as the plain
1782
  position() call doesn't work for some
1783
  handlers for random position
1784
*/
1785
481 by Brian Aker
Remove all of uchar.
1786
int handler::rnd_pos_by_record(unsigned char *record)
1 by brian
clean slate
1787
{
1788
  register int error;
1789
1790
  position(record);
1791
  if (inited && (error= ha_index_end()))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1792
    return(error);
56 by brian
Next pass of true/false update.
1793
  if ((error= ha_rnd_init(false)))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1794
    return(error);
1 by brian
clean slate
1795
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1796
  return(rnd_pos(record, ref));
1 by brian
clean slate
1797
}
1798
1799
/**
1800
  Read first row (only) from a table.
1801
1802
  This is never called for InnoDB tables, as these table types
1803
  has the HA_STATS_RECORDS_IS_EXACT set.
1804
*/
482 by Brian Aker
Remove uint.
1805
int handler::read_first_row(unsigned char * buf, uint32_t primary_key)
1 by brian
clean slate
1806
{
1807
  register int error;
1808
1809
  ha_statistic_increment(&SSV::ha_read_first_count);
1810
1811
  /*
1812
    If there is very few deleted rows in the table, find the first row by
1813
    scanning the table.
1814
    TODO remove the test for HA_READ_ORDER
1815
  */
1816
  if (stats.deleted < 10 || primary_key >= MAX_KEY ||
1817
      !(index_flags(primary_key, 0, 0) & HA_READ_ORDER))
1818
  {
1819
    (void) ha_rnd_init(1);
1820
    while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
1821
    (void) ha_rnd_end();
1822
  }
1823
  else
1824
  {
1825
    /* Find the first row through the primary key */
1826
    (void) ha_index_init(primary_key, 0);
1827
    error=index_first(buf);
1828
    (void) ha_index_end();
1829
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1830
  return(error);
1 by brian
clean slate
1831
}
1832
1833
/**
1834
  Generate the next auto-increment number based on increment and offset.
1835
  computes the lowest number
1836
  - strictly greater than "nr"
1837
  - of the form: auto_increment_offset + N * auto_increment_increment
1838
1839
  In most cases increment= offset= 1, in which case we get:
1840
  @verbatim 1,2,3,4,5,... @endverbatim
1841
    If increment=10 and offset=5 and previous number is 1, we get:
1842
  @verbatim 1,5,15,25,35,... @endverbatim
1843
*/
1844
inline uint64_t
1845
compute_next_insert_id(uint64_t nr,struct system_variables *variables)
1846
{
1847
  if (variables->auto_increment_increment == 1)
1848
    return (nr+1); // optimization of the formula below
1849
  nr= (((nr+ variables->auto_increment_increment -
1850
         variables->auto_increment_offset)) /
1851
       (uint64_t) variables->auto_increment_increment);
1852
  return (nr* (uint64_t) variables->auto_increment_increment +
1853
          variables->auto_increment_offset);
1854
}
1855
1856
1857
void handler::adjust_next_insert_id_after_explicit_value(uint64_t nr)
1858
{
1859
  /*
520.1.21 by Brian Aker
THD -> Session rename
1860
    If we have set Session::next_insert_id previously and plan to insert an
1 by brian
clean slate
1861
    explicitely-specified value larger than this, we need to increase
520.1.21 by Brian Aker
THD -> Session rename
1862
    Session::next_insert_id to be greater than the explicit value.
1 by brian
clean slate
1863
  */
1864
  if ((next_insert_id > 0) && (nr >= next_insert_id))
1865
    set_next_insert_id(compute_next_insert_id(nr, &table->in_use->variables));
1866
}
1867
1868
1869
/**
1870
  Compute a previous insert id
1871
1872
  Computes the largest number X:
1873
  - smaller than or equal to "nr"
1874
  - of the form: auto_increment_offset + N * auto_increment_increment
1875
    where N>=0.
1876
1877
  @param nr            Number to "round down"
1878
  @param variables     variables struct containing auto_increment_increment and
1879
                       auto_increment_offset
1880
1881
  @return
1882
    The number X if it exists, "nr" otherwise.
1883
*/
1884
inline uint64_t
1885
prev_insert_id(uint64_t nr, struct system_variables *variables)
1886
{
1887
  if (unlikely(nr < variables->auto_increment_offset))
1888
  {
1889
    /*
1890
      There's nothing good we can do here. That is a pathological case, where
1891
      the offset is larger than the column's max possible value, i.e. not even
1892
      the first sequence value may be inserted. User will receive warning.
1893
    */
1894
    return nr;
1895
  }
1896
  if (variables->auto_increment_increment == 1)
1897
    return nr; // optimization of the formula below
1898
  nr= (((nr - variables->auto_increment_offset)) /
1899
       (uint64_t) variables->auto_increment_increment);
1900
  return (nr * (uint64_t) variables->auto_increment_increment +
1901
          variables->auto_increment_offset);
1902
}
1903
1904
1905
/**
1906
  Update the auto_increment field if necessary.
1907
1908
  Updates columns with type NEXT_NUMBER if:
1909
1910
  - If column value is set to NULL (in which case
1911
    auto_increment_field_not_null is 0)
1912
  - If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not
1913
    set. In the future we will only set NEXT_NUMBER fields if one sets them
1914
    to NULL (or they are not included in the insert list).
1915
1916
    In those cases, we check if the currently reserved interval still has
1917
    values we have not used. If yes, we pick the smallest one and use it.
1918
    Otherwise:
1919
1920
  - If a list of intervals has been provided to the statement via SET
1921
    INSERT_ID or via an Intvar_log_event (in a replication slave), we pick the
1922
    first unused interval from this list, consider it as reserved.
1923
1924
  - Otherwise we set the column for the first row to the value
1925
    next_insert_id(get_auto_increment(column))) which is usually
1926
    max-used-column-value+1.
1927
    We call get_auto_increment() for the first row in a multi-row
1928
    statement. get_auto_increment() will tell us the interval of values it
1929
    reserved for us.
1930
1931
  - In both cases, for the following rows we use those reserved values without
1932
    calling the handler again (we just progress in the interval, computing
1933
    each new value from the previous one). Until we have exhausted them, then
1934
    we either take the next provided interval or call get_auto_increment()
1935
    again to reserve a new interval.
1936
1937
  - In both cases, the reserved intervals are remembered in
520.1.22 by Brian Aker
Second pass of thd cleanup
1938
    session->auto_inc_intervals_in_cur_stmt_for_binlog if statement-based
1 by brian
clean slate
1939
    binlogging; the last reserved interval is remembered in
1940
    auto_inc_interval_for_cur_row.
1941
1942
    The idea is that generated auto_increment values are predictable and
1943
    independent of the column values in the table.  This is needed to be
1944
    able to replicate into a table that already has rows with a higher
1945
    auto-increment value than the one that is inserted.
1946
1947
    After we have already generated an auto-increment number and the user
1948
    inserts a column with a higher value than the last used one, we will
1949
    start counting from the inserted value.
1950
1951
    This function's "outputs" are: the table's auto_increment field is filled
520.1.22 by Brian Aker
Second pass of thd cleanup
1952
    with a value, session->next_insert_id is filled with the value to use for the
1 by brian
clean slate
1953
    next row, if a value was autogenerated for the current row it is stored in
520.1.22 by Brian Aker
Second pass of thd cleanup
1954
    session->insert_id_for_cur_row, if get_auto_increment() was called
1955
    session->auto_inc_interval_for_cur_row is modified, if that interval is not
1956
    present in session->auto_inc_intervals_in_cur_stmt_for_binlog it is added to
1 by brian
clean slate
1957
    this list.
1958
1959
  @todo
1960
    Replace all references to "next number" or NEXT_NUMBER to
1961
    "auto_increment", everywhere (see below: there is
1962
    table->auto_increment_field_not_null, and there also exists
1963
    table->next_number_field, it's not consistent).
1964
1965
  @retval
1966
    0	ok
1967
  @retval
1968
    HA_ERR_AUTOINC_READ_FAILED  get_auto_increment() was called and
1969
    returned ~(uint64_t) 0
1970
  @retval
1971
    HA_ERR_AUTOINC_ERANGE storing value in field caused strict mode
1972
    failure.
1973
*/
1974
1975
#define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here
1976
#define AUTO_INC_DEFAULT_NB_MAX_BITS 16
1977
#define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1)
1978
1979
int handler::update_auto_increment()
1980
{
1981
  uint64_t nr, nb_reserved_values;
56 by brian
Next pass of true/false update.
1982
  bool append= false;
520.1.22 by Brian Aker
Second pass of thd cleanup
1983
  Session *session= table->in_use;
1984
  struct system_variables *variables= &session->variables;
1 by brian
clean slate
1985
1986
  /*
1987
    next_insert_id is a "cursor" into the reserved interval, it may go greater
1988
    than the interval, but not smaller.
1989
  */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
1990
  assert(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
1 by brian
clean slate
1991
359 by Brian Aker
More modes removed. 0 always becomes new number again
1992
  if ((nr= table->next_number_field->val_int()) != 0)
1 by brian
clean slate
1993
  {
1994
    /*
1995
      Update next_insert_id if we had already generated a value in this
1996
      statement (case of INSERT VALUES(null),(3763),(null):
1997
      the last NULL needs to insert 3764, not the value of the first NULL plus
1998
      1).
1999
    */
2000
    adjust_next_insert_id_after_explicit_value(nr);
2001
    insert_id_for_cur_row= 0; // didn't generate anything
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2002
    return(0);
1 by brian
clean slate
2003
  }
2004
2005
  if ((nr= next_insert_id) >= auto_inc_interval_for_cur_row.maximum())
2006
  {
2007
    /* next_insert_id is beyond what is reserved, so we reserve more. */
2008
    const Discrete_interval *forced=
520.1.22 by Brian Aker
Second pass of thd cleanup
2009
      session->auto_inc_intervals_forced.get_next();
1 by brian
clean slate
2010
    if (forced != NULL)
2011
    {
2012
      nr= forced->minimum();
2013
      nb_reserved_values= forced->values();
2014
    }
2015
    else
2016
    {
2017
      /*
2018
        handler::estimation_rows_to_insert was set by
2019
        handler::ha_start_bulk_insert(); if 0 it means "unknown".
2020
      */
482 by Brian Aker
Remove uint.
2021
      uint32_t nb_already_reserved_intervals=
520.1.22 by Brian Aker
Second pass of thd cleanup
2022
        session->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements();
1 by brian
clean slate
2023
      uint64_t nb_desired_values;
2024
      /*
2025
        If an estimation was given to the engine:
2026
        - use it.
2027
        - if we already reserved numbers, it means the estimation was
2028
        not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_ROWS the 2nd
2029
        time, twice that the 3rd time etc.
2030
        If no estimation was given, use those increasing defaults from the
2031
        start, starting from AUTO_INC_DEFAULT_NB_ROWS.
2032
        Don't go beyond a max to not reserve "way too much" (because
2033
        reservation means potentially losing unused values).
2034
      */
2035
      if (nb_already_reserved_intervals == 0 &&
2036
          (estimation_rows_to_insert > 0))
2037
        nb_desired_values= estimation_rows_to_insert;
2038
      else /* go with the increasing defaults */
2039
      {
2040
        /* avoid overflow in formula, with this if() */
2041
        if (nb_already_reserved_intervals <= AUTO_INC_DEFAULT_NB_MAX_BITS)
2042
        {
2043
          nb_desired_values= AUTO_INC_DEFAULT_NB_ROWS * 
2044
            (1 << nb_already_reserved_intervals);
2045
          set_if_smaller(nb_desired_values, AUTO_INC_DEFAULT_NB_MAX);
2046
        }
2047
        else
2048
          nb_desired_values= AUTO_INC_DEFAULT_NB_MAX;
2049
      }
2050
      /* This call ignores all its parameters but nr, currently */
2051
      get_auto_increment(variables->auto_increment_offset,
2052
                         variables->auto_increment_increment,
2053
                         nb_desired_values, &nr,
2054
                         &nb_reserved_values);
2055
      if (nr == ~(uint64_t) 0)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2056
        return(HA_ERR_AUTOINC_READ_FAILED);  // Mark failure
1 by brian
clean slate
2057
      
2058
      /*
2059
        That rounding below should not be needed when all engines actually
2060
        respect offset and increment in get_auto_increment(). But they don't
2061
        so we still do it. Wonder if for the not-first-in-index we should do
2062
        it. Hope that this rounding didn't push us out of the interval; even
2063
        if it did we cannot do anything about it (calling the engine again
2064
        will not help as we inserted no row).
2065
      */
2066
      nr= compute_next_insert_id(nr-1, variables);
2067
    }
2068
    
2069
    if (table->s->next_number_keypart == 0)
2070
    {
2071
      /* We must defer the appending until "nr" has been possibly truncated */
56 by brian
Next pass of true/false update.
2072
      append= true;
1 by brian
clean slate
2073
    }
2074
  }
2075
152 by Brian Aker
longlong replacement
2076
  if (unlikely(table->next_number_field->store((int64_t) nr, true)))
1 by brian
clean slate
2077
  {
2078
    /*
2079
      first test if the query was aborted due to strict mode constraints
2080
    */
520.1.22 by Brian Aker
Second pass of thd cleanup
2081
    if (session->killed == Session::KILL_BAD_DATA)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2082
      return(HA_ERR_AUTOINC_ERANGE);
1 by brian
clean slate
2083
2084
    /*
2085
      field refused this value (overflow) and truncated it, use the result of
2086
      the truncation (which is going to be inserted); however we try to
2087
      decrease it to honour auto_increment_* variables.
2088
      That will shift the left bound of the reserved interval, we don't
2089
      bother shifting the right bound (anyway any other value from this
2090
      interval will cause a duplicate key).
2091
    */
2092
    nr= prev_insert_id(table->next_number_field->val_int(), variables);
152 by Brian Aker
longlong replacement
2093
    if (unlikely(table->next_number_field->store((int64_t) nr, true)))
1 by brian
clean slate
2094
      nr= table->next_number_field->val_int();
2095
  }
2096
  if (append)
2097
  {
2098
    auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values,
2099
                                          variables->auto_increment_increment);
2100
    /* Row-based replication does not need to store intervals in binlog */
520.1.22 by Brian Aker
Second pass of thd cleanup
2101
    if (!session->current_stmt_binlog_row_based)
2102
        session->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
1 by brian
clean slate
2103
                                                              auto_inc_interval_for_cur_row.values(),
2104
                                                              variables->auto_increment_increment);
2105
  }
2106
2107
  /*
2108
    Record this autogenerated value. If the caller then
2109
    succeeds to insert this value, it will call
2110
    record_first_successful_insert_id_in_cur_stmt()
2111
    which will set first_successful_insert_id_in_cur_stmt if it's not
2112
    already set.
2113
  */
2114
  insert_id_for_cur_row= nr;
2115
  /*
2116
    Set next insert id to point to next auto-increment value to be able to
2117
    handle multi-row statements.
2118
  */
2119
  set_next_insert_id(compute_next_insert_id(nr, variables));
2120
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2121
  return(0);
1 by brian
clean slate
2122
}
2123
2124
2125
/**
2126
  MySQL signal that it changed the column bitmap
2127
2128
  This is for handlers that needs to setup their own column bitmaps.
2129
  Normally the handler should set up their own column bitmaps in
2130
  index_init() or rnd_init() and in any column_bitmaps_signal() call after
2131
  this.
2132
2133
  The handler is allowed to do changes to the bitmap after a index_init or
2134
  rnd_init() call is made as after this, MySQL will not use the bitmap
2135
  for any program logic checking.
2136
*/
2137
void handler::column_bitmaps_signal()
2138
{
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2139
  return;
1 by brian
clean slate
2140
}
2141
2142
2143
/**
2144
  Reserves an interval of auto_increment values from the handler.
2145
2146
  offset and increment means that we want values to be of the form
2147
  offset + N * increment, where N>=0 is integer.
2148
  If the function sets *first_value to ~(uint64_t)0 it means an error.
163 by Brian Aker
Merge Monty's code.
2149
  If the function sets *nb_reserved_values to UINT64_MAX it means it has
1 by brian
clean slate
2150
  reserved to "positive infinite".
2151
2152
  @param offset
2153
  @param increment
2154
  @param nb_desired_values   how many values we want
2155
  @param first_value         (OUT) the first value reserved by the handler
2156
  @param nb_reserved_values  (OUT) how many values the handler reserved
2157
*/
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
2158
void handler::get_auto_increment(uint64_t offset __attribute__((unused)),
2159
                                 uint64_t increment __attribute__((unused)),
2160
                                 uint64_t nb_desired_values __attribute__((unused)),
1 by brian
clean slate
2161
                                 uint64_t *first_value,
2162
                                 uint64_t *nb_reserved_values)
2163
{
2164
  uint64_t nr;
2165
  int error;
2166
2167
  (void) extra(HA_EXTRA_KEYREAD);
2168
  table->mark_columns_used_by_index_no_reset(table->s->next_number_index,
2169
                                        table->read_set);
2170
  column_bitmaps_signal();
2171
  index_init(table->s->next_number_index, 1);
2172
  if (table->s->next_number_keypart == 0)
2173
  {						// Autoincrement at key-start
2174
    error=index_last(table->record[1]);
2175
    /*
2176
      MySQL implicitely assumes such method does locking (as MySQL decides to
2177
      use nr+increment without checking again with the handler, in
2178
      handler::update_auto_increment()), so reserves to infinite.
2179
    */
163 by Brian Aker
Merge Monty's code.
2180
    *nb_reserved_values= UINT64_MAX;
1 by brian
clean slate
2181
  }
2182
  else
2183
  {
481 by Brian Aker
Remove all of uchar.
2184
    unsigned char key[MAX_KEY_LENGTH];
1 by brian
clean slate
2185
    key_copy(key, table->record[0],
2186
             table->key_info + table->s->next_number_index,
2187
             table->s->next_number_key_offset);
2188
    error= index_read_map(table->record[1], key,
2189
                          make_prev_keypart_map(table->s->next_number_keypart),
2190
                          HA_READ_PREFIX_LAST);
2191
    /*
2192
      MySQL needs to call us for next row: assume we are inserting ("a",null)
2193
      here, we return 3, and next this statement will want to insert
2194
      ("b",null): there is no reason why ("b",3+1) would be the good row to
2195
      insert: maybe it already exists, maybe 3+1 is too large...
2196
    */
2197
    *nb_reserved_values= 1;
2198
  }
2199
2200
  if (error)
2201
    nr=1;
2202
  else
2203
    nr= ((uint64_t) table->next_number_field->
2204
         val_int_offset(table->s->rec_buff_length)+1);
2205
  index_end();
2206
  (void) extra(HA_EXTRA_NO_KEYREAD);
2207
  *first_value= nr;
2208
}
2209
2210
2211
void handler::ha_release_auto_increment()
2212
{
2213
  release_auto_increment();
2214
  insert_id_for_cur_row= 0;
2215
  auto_inc_interval_for_cur_row.replace(0, 0, 0);
2216
  if (next_insert_id > 0)
2217
  {
2218
    next_insert_id= 0;
2219
    /*
2220
      this statement used forced auto_increment values if there were some,
2221
      wipe them away for other statements.
2222
    */
2223
    table->in_use->auto_inc_intervals_forced.empty();
2224
  }
2225
}
2226
2227
482 by Brian Aker
Remove uint.
2228
void handler::print_keydup_error(uint32_t key_nr, const char *msg)
1 by brian
clean slate
2229
{
2230
  /* Write the duplicated key in the error message */
2231
  char key[MAX_KEY_LENGTH];
2232
  String str(key,sizeof(key),system_charset_info);
2233
2234
  if (key_nr == MAX_KEY)
2235
  {
2236
    /* Key is unknown */
2237
    str.copy("", 0, system_charset_info);
2238
    my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
2239
  }
2240
  else
2241
  {
2242
    /* Table is opened and defined at this point */
2243
    key_unpack(&str,table,(uint) key_nr);
482 by Brian Aker
Remove uint.
2244
    uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint) strlen(msg);
1 by brian
clean slate
2245
    if (str.length() >= max_length)
2246
    {
2247
      str.length(max_length-4);
2248
      str.append(STRING_WITH_LEN("..."));
2249
    }
2250
    my_printf_error(ER_DUP_ENTRY, msg,
2251
		    MYF(0), str.c_ptr(), table->key_info[key_nr].name);
2252
  }
2253
}
2254
2255
2256
/**
2257
  Print error that we got from handler function.
2258
2259
  @note
2260
    In case of delete table it's only safe to use the following parts of
2261
    the 'table' structure:
2262
    - table->s->path
2263
    - table->alias
2264
*/
2265
void handler::print_error(int error, myf errflag)
2266
{
2267
  int textno=ER_GET_ERRNO;
2268
  switch (error) {
2269
  case EACCES:
2270
    textno=ER_OPEN_AS_READONLY;
2271
    break;
2272
  case EAGAIN:
2273
    textno=ER_FILE_USED;
2274
    break;
2275
  case ENOENT:
2276
    textno=ER_FILE_NOT_FOUND;
2277
    break;
2278
  case HA_ERR_KEY_NOT_FOUND:
2279
  case HA_ERR_NO_ACTIVE_RECORD:
2280
  case HA_ERR_END_OF_FILE:
2281
    textno=ER_KEY_NOT_FOUND;
2282
    break;
2283
  case HA_ERR_WRONG_MRG_TABLE_DEF:
2284
    textno=ER_WRONG_MRG_TABLE;
2285
    break;
2286
  case HA_ERR_FOUND_DUPP_KEY:
2287
  {
482 by Brian Aker
Remove uint.
2288
    uint32_t key_nr=get_dup_key(error);
1 by brian
clean slate
2289
    if ((int) key_nr >= 0)
2290
    {
2291
      print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2292
      return;
1 by brian
clean slate
2293
    }
2294
    textno=ER_DUP_KEY;
2295
    break;
2296
  }
2297
  case HA_ERR_FOREIGN_DUPLICATE_KEY:
2298
  {
482 by Brian Aker
Remove uint.
2299
    uint32_t key_nr= get_dup_key(error);
1 by brian
clean slate
2300
    if ((int) key_nr >= 0)
2301
    {
482 by Brian Aker
Remove uint.
2302
      uint32_t max_length;
1 by brian
clean slate
2303
      /* Write the key in the error message */
2304
      char key[MAX_KEY_LENGTH];
2305
      String str(key,sizeof(key),system_charset_info);
2306
      /* Table is opened and defined at this point */
2307
      key_unpack(&str,table,(uint) key_nr);
261.4.1 by Felipe
- Renamed MYSQL_ERROR to DRIZZLE_ERROR.
2308
      max_length= (DRIZZLE_ERRMSG_SIZE-
1 by brian
clean slate
2309
                   (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
2310
      if (str.length() >= max_length)
2311
      {
2312
        str.length(max_length-4);
2313
        str.append(STRING_WITH_LEN("..."));
2314
      }
2315
      my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str,
2316
        str.c_ptr(), key_nr+1);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2317
      return;
1 by brian
clean slate
2318
    }
2319
    textno= ER_DUP_KEY;
2320
    break;
2321
  }
2322
  case HA_ERR_FOUND_DUPP_UNIQUE:
2323
    textno=ER_DUP_UNIQUE;
2324
    break;
2325
  case HA_ERR_RECORD_CHANGED:
2326
    textno=ER_CHECKREAD;
2327
    break;
2328
  case HA_ERR_CRASHED:
2329
    textno=ER_NOT_KEYFILE;
2330
    break;
2331
  case HA_ERR_WRONG_IN_RECORD:
2332
    textno= ER_CRASHED_ON_USAGE;
2333
    break;
2334
  case HA_ERR_CRASHED_ON_USAGE:
2335
    textno=ER_CRASHED_ON_USAGE;
2336
    break;
2337
  case HA_ERR_NOT_A_TABLE:
2338
    textno= error;
2339
    break;
2340
  case HA_ERR_CRASHED_ON_REPAIR:
2341
    textno=ER_CRASHED_ON_REPAIR;
2342
    break;
2343
  case HA_ERR_OUT_OF_MEM:
2344
    textno=ER_OUT_OF_RESOURCES;
2345
    break;
2346
  case HA_ERR_WRONG_COMMAND:
2347
    textno=ER_ILLEGAL_HA;
2348
    break;
2349
  case HA_ERR_OLD_FILE:
2350
    textno=ER_OLD_KEYFILE;
2351
    break;
2352
  case HA_ERR_UNSUPPORTED:
2353
    textno=ER_UNSUPPORTED_EXTENSION;
2354
    break;
2355
  case HA_ERR_RECORD_FILE_FULL:
2356
  case HA_ERR_INDEX_FILE_FULL:
2357
    textno=ER_RECORD_FILE_FULL;
2358
    break;
2359
  case HA_ERR_LOCK_WAIT_TIMEOUT:
2360
    textno=ER_LOCK_WAIT_TIMEOUT;
2361
    break;
2362
  case HA_ERR_LOCK_TABLE_FULL:
2363
    textno=ER_LOCK_TABLE_FULL;
2364
    break;
2365
  case HA_ERR_LOCK_DEADLOCK:
2366
    textno=ER_LOCK_DEADLOCK;
2367
    break;
2368
  case HA_ERR_READ_ONLY_TRANSACTION:
2369
    textno=ER_READ_ONLY_TRANSACTION;
2370
    break;
2371
  case HA_ERR_CANNOT_ADD_FOREIGN:
2372
    textno=ER_CANNOT_ADD_FOREIGN;
2373
    break;
2374
  case HA_ERR_ROW_IS_REFERENCED:
2375
  {
2376
    String str;
2377
    get_error_message(error, &str);
2378
    my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2379
    return;
1 by brian
clean slate
2380
  }
2381
  case HA_ERR_NO_REFERENCED_ROW:
2382
  {
2383
    String str;
2384
    get_error_message(error, &str);
2385
    my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2386
    return;
1 by brian
clean slate
2387
  }
2388
  case HA_ERR_TABLE_DEF_CHANGED:
2389
    textno=ER_TABLE_DEF_CHANGED;
2390
    break;
2391
  case HA_ERR_NO_SUCH_TABLE:
2392
    my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
2393
             table_share->table_name.str);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2394
    return;
1 by brian
clean slate
2395
  case HA_ERR_RBR_LOGGING_FAILED:
2396
    textno= ER_BINLOG_ROW_LOGGING_FAILED;
2397
    break;
2398
  case HA_ERR_DROP_INDEX_FK:
2399
  {
2400
    const char *ptr= "???";
482 by Brian Aker
Remove uint.
2401
    uint32_t key_nr= get_dup_key(error);
1 by brian
clean slate
2402
    if ((int) key_nr >= 0)
2403
      ptr= table->key_info[key_nr].name;
2404
    my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2405
    return;
1 by brian
clean slate
2406
  }
2407
  case HA_ERR_TABLE_NEEDS_UPGRADE:
2408
    textno=ER_TABLE_NEEDS_UPGRADE;
2409
    break;
2410
  case HA_ERR_TABLE_READONLY:
2411
    textno= ER_OPEN_AS_READONLY;
2412
    break;
2413
  case HA_ERR_AUTOINC_READ_FAILED:
2414
    textno= ER_AUTOINC_READ_FAILED;
2415
    break;
2416
  case HA_ERR_AUTOINC_ERANGE:
2417
    textno= ER_WARN_DATA_OUT_OF_RANGE;
2418
    break;
2419
  case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
2420
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
2421
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2422
    return;
1 by brian
clean slate
2423
    break;
2424
  default:
2425
    {
2426
      /* The error was "unknown" to this function.
2427
	 Ask handler if it has got a message for this error */
56 by brian
Next pass of true/false update.
2428
      bool temporary= false;
1 by brian
clean slate
2429
      String str;
2430
      temporary= get_error_message(error, &str);
2431
      if (!str.is_empty())
2432
      {
2433
	const char* engine= table_type();
2434
	if (temporary)
2435
	  my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine);
2436
	else
2437
	  my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine);
2438
      }
2439
      else
2440
	my_error(ER_GET_ERRNO,errflag,error);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2441
      return;
1 by brian
clean slate
2442
    }
2443
  }
2444
  my_error(textno, errflag, table_share->table_name.str, error);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2445
  return;
1 by brian
clean slate
2446
}
2447
2448
2449
/**
2450
  Return an error message specific to this handler.
2451
2452
  @param error  error code previously returned by handler
2453
  @param buf    pointer to String where to add error message
2454
2455
  @return
2456
    Returns true if this is a temporary error
2457
*/
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
2458
bool handler::get_error_message(int error __attribute__((unused)),
2459
                                String* buf __attribute__((unused)))
1 by brian
clean slate
2460
{
56 by brian
Next pass of true/false update.
2461
  return false;
1 by brian
clean slate
2462
}
2463
2464
2465
int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt)
2466
{
2467
  KEY *keyinfo, *keyend;
2468
  KEY_PART_INFO *keypart, *keypartend;
2469
2470
  if (!table->s->mysql_version)
2471
  {
2472
    /* check for blob-in-key error */
2473
    keyinfo= table->key_info;
2474
    keyend= table->key_info + table->s->keys;
2475
    for (; keyinfo < keyend; keyinfo++)
2476
    {
2477
      keypart= keyinfo->key_part;
2478
      keypartend= keypart + keyinfo->key_parts;
2479
      for (; keypart < keypartend; keypart++)
2480
      {
2481
        if (!keypart->fieldnr)
2482
          continue;
2483
        Field *field= table->field[keypart->fieldnr-1];
212.2.2 by Patrick Galbraith
Renamed FIELD_TYPE to DRIZZLE_TYPE
2484
        if (field->type() == DRIZZLE_TYPE_BLOB)
1 by brian
clean slate
2485
        {
2486
          if (check_opt->sql_flags & TT_FOR_UPGRADE)
2487
            check_opt->flags= T_MEDIUM;
2488
          return HA_ADMIN_NEEDS_CHECK;
2489
        }
2490
      }
2491
    }
2492
  }
2493
  return check_for_upgrade(check_opt);
2494
}
2495
2496
2497
/* Code left, but Drizzle has no legacy yet (while MySQL did) */
2498
int handler::check_old_types()
2499
{
2500
  return 0;
2501
}
2502
2503
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
2504
static bool update_frm_version(Table *table)
1 by brian
clean slate
2505
{
2506
  char path[FN_REFLEN];
2507
  File file;
31 by Brian Aker
Removed my versions of pread/pwrite from the Kernel
2508
  bool result= true;
1 by brian
clean slate
2509
2510
  /*
2511
    No need to update frm version in case table was created or checked
2512
    by server with the same version. This also ensures that we do not
2513
    update frm version for temporary tables as this code doesn't support
2514
    temporary tables.
2515
  */
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
2516
  if (table->s->mysql_version == DRIZZLE_VERSION_ID)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2517
    return(0);
1 by brian
clean slate
2518
461 by Monty Taylor
Removed NullS. bu-bye.
2519
  strxmov(path, table->s->normalized_path.str, reg_ext, NULL);
1 by brian
clean slate
2520
492.1.14 by Monty Taylor
Removed O_BINARY and FILE_BINARY.
2521
  if ((file= my_open(path, O_RDWR, MYF(MY_WME))) >= 0)
1 by brian
clean slate
2522
  {
481 by Brian Aker
Remove all of uchar.
2523
    unsigned char version[4];
1 by brian
clean slate
2524
    char *key= table->s->table_cache_key.str;
482 by Brian Aker
Remove uint.
2525
    uint32_t key_length= table->s->table_cache_key.length;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
2526
    Table *entry;
1 by brian
clean slate
2527
    HASH_SEARCH_STATE state;
2528
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
2529
    int4store(version, DRIZZLE_VERSION_ID);
1 by brian
clean slate
2530
481 by Brian Aker
Remove all of uchar.
2531
    if (pwrite(file, (unsigned char*)version, 4, 51L) == 0)
31 by Brian Aker
Removed my versions of pread/pwrite from the Kernel
2532
    {
2533
      result= false;
1 by brian
clean slate
2534
      goto err;
31 by Brian Aker
Removed my versions of pread/pwrite from the Kernel
2535
    }
1 by brian
clean slate
2536
481 by Brian Aker
Remove all of uchar.
2537
    for (entry=(Table*) hash_first(&open_cache,(unsigned char*) key,key_length, &state);
1 by brian
clean slate
2538
         entry;
481 by Brian Aker
Remove all of uchar.
2539
         entry= (Table*) hash_next(&open_cache,(unsigned char*) key,key_length, &state))
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
2540
      entry->s->mysql_version= DRIZZLE_VERSION_ID;
1 by brian
clean slate
2541
  }
2542
err:
2543
  if (file >= 0)
398.1.10 by Monty Taylor
Actually removed VOID() this time.
2544
    my_close(file,MYF(MY_WME));
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2545
  return(result);
1 by brian
clean slate
2546
}
2547
2548
2549
2550
/**
2551
  @return
2552
    key if error because of duplicated keys
2553
*/
482 by Brian Aker
Remove uint.
2554
uint32_t handler::get_dup_key(int error)
1 by brian
clean slate
2555
{
2556
  table->file->errkey  = (uint) -1;
2557
  if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY ||
2558
      error == HA_ERR_FOUND_DUPP_UNIQUE ||
2559
      error == HA_ERR_DROP_INDEX_FK)
2560
    info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2561
  return(table->file->errkey);
1 by brian
clean slate
2562
}
2563
2564
2565
/**
2566
  Delete all files with extension from bas_ext().
2567
2568
  @param name		Base name of table
2569
2570
  @note
2571
    We assume that the handler may return more extensions than
2572
    was actually used for the file.
2573
2574
  @retval
2575
    0   If we successfully deleted at least one file from base_ext and
2576
    didn't get any other errors than ENOENT
2577
  @retval
2578
    !0  Error
2579
*/
2580
int handler::delete_table(const char *name)
2581
{
2582
  int error= 0;
2583
  int enoent_or_zero= ENOENT;                   // Error if no file was deleted
2584
  char buff[FN_REFLEN];
2585
2586
  for (const char **ext=bas_ext(); *ext ; ext++)
2587
  {
2588
    fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
2589
    if (my_delete_with_symlink(buff, MYF(0)))
2590
    {
2591
      if ((error= my_errno) != ENOENT)
2592
	break;
2593
    }
2594
    else
2595
      enoent_or_zero= 0;                        // No error for ENOENT
2596
    error= enoent_or_zero;
2597
  }
2598
  return error;
2599
}
2600
2601
2602
int handler::rename_table(const char * from, const char * to)
2603
{
2604
  int error= 0;
2605
  for (const char **ext= bas_ext(); *ext ; ext++)
2606
  {
2607
    if (rename_file_ext(from, to, *ext))
2608
    {
2609
      if ((error=my_errno) != ENOENT)
2610
	break;
2611
      error= 0;
2612
    }
2613
  }
2614
  return error;
2615
}
2616
2617
2618
void handler::drop_table(const char *name)
2619
{
2620
  close();
2621
  delete_table(name);
2622
}
2623
2624
2625
/**
2626
  Performs checks upon the table.
2627
520.1.22 by Brian Aker
Second pass of thd cleanup
2628
  @param session                thread doing CHECK Table operation
1 by brian
clean slate
2629
  @param check_opt          options from the parser
2630
2631
  @retval
2632
    HA_ADMIN_OK               Successful upgrade
2633
  @retval
2634
    HA_ADMIN_NEEDS_UPGRADE    Table has structures requiring upgrade
2635
  @retval
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
2636
    HA_ADMIN_NEEDS_ALTER      Table has structures requiring ALTER Table
1 by brian
clean slate
2637
  @retval
2638
    HA_ADMIN_NOT_IMPLEMENTED
2639
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
2640
int handler::ha_check(Session *session, HA_CHECK_OPT *check_opt)
1 by brian
clean slate
2641
{
2642
  int error;
2643
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
2644
  if ((table->s->mysql_version >= DRIZZLE_VERSION_ID) &&
1 by brian
clean slate
2645
      (check_opt->sql_flags & TT_FOR_UPGRADE))
2646
    return 0;
2647
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
2648
  if (table->s->mysql_version < DRIZZLE_VERSION_ID)
1 by brian
clean slate
2649
  {
2650
    if ((error= check_old_types()))
2651
      return error;
2652
    error= ha_check_for_upgrade(check_opt);
2653
    if (error && (error != HA_ADMIN_NEEDS_CHECK))
2654
      return error;
2655
    if (!error && (check_opt->sql_flags & TT_FOR_UPGRADE))
2656
      return 0;
2657
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
2658
  if ((error= check(session, check_opt)))
1 by brian
clean slate
2659
    return error;
2660
  return update_frm_version(table);
2661
}
2662
2663
/**
2664
  A helper function to mark a transaction read-write,
2665
  if it is started.
2666
*/
2667
2668
inline
2669
void
2670
handler::mark_trx_read_write()
2671
{
520.1.22 by Brian Aker
Second pass of thd cleanup
2672
  Ha_trx_info *ha_info= &ha_session()->ha_data[ht->slot].ha_info[0];
1 by brian
clean slate
2673
  /*
2674
    When a storage engine method is called, the transaction must
2675
    have been started, unless it's a DDL call, for which the
2676
    storage engine starts the transaction internally, and commits
2677
    it internally, without registering in the ha_list.
2678
    Unfortunately here we can't know know for sure if the engine
2679
    has registered the transaction or not, so we must check.
2680
  */
2681
  if (ha_info->is_started())
2682
  {
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2683
    assert(has_transactions());
1 by brian
clean slate
2684
    /*
2685
      table_share can be NULL in ha_delete_table(). See implementation
2686
      of standalone function ha_delete_table() in sql_base.cc.
2687
    */
2688
    if (table_share == NULL || table_share->tmp_table == NO_TMP_TABLE)
2689
      ha_info->set_trx_read_write();
2690
  }
2691
}
2692
2693
2694
/**
2695
  Repair table: public interface.
2696
2697
  @sa handler::repair()
2698
*/
2699
520.1.22 by Brian Aker
Second pass of thd cleanup
2700
int handler::ha_repair(Session* session, HA_CHECK_OPT* check_opt)
1 by brian
clean slate
2701
{
2702
  int result;
2703
2704
  mark_trx_read_write();
2705
520.1.22 by Brian Aker
Second pass of thd cleanup
2706
  if ((result= repair(session, check_opt)))
1 by brian
clean slate
2707
    return result;
2708
  return update_frm_version(table);
2709
}
2710
2711
2712
/**
2713
  Bulk update row: public interface.
2714
2715
  @sa handler::bulk_update_row()
2716
*/
2717
2718
int
481 by Brian Aker
Remove all of uchar.
2719
handler::ha_bulk_update_row(const unsigned char *old_data, unsigned char *new_data,
482 by Brian Aker
Remove uint.
2720
                            uint32_t *dup_key_found)
1 by brian
clean slate
2721
{
2722
  mark_trx_read_write();
2723
2724
  return bulk_update_row(old_data, new_data, dup_key_found);
2725
}
2726
2727
2728
/**
2729
  Delete all rows: public interface.
2730
2731
  @sa handler::delete_all_rows()
2732
*/
2733
2734
int
2735
handler::ha_delete_all_rows()
2736
{
2737
  mark_trx_read_write();
2738
2739
  return delete_all_rows();
2740
}
2741
2742
2743
/**
2744
  Reset auto increment: public interface.
2745
2746
  @sa handler::reset_auto_increment()
2747
*/
2748
2749
int
2750
handler::ha_reset_auto_increment(uint64_t value)
2751
{
2752
  mark_trx_read_write();
2753
2754
  return reset_auto_increment(value);
2755
}
2756
2757
2758
/**
2759
  Optimize table: public interface.
2760
2761
  @sa handler::optimize()
2762
*/
2763
2764
int
520.1.22 by Brian Aker
Second pass of thd cleanup
2765
handler::ha_optimize(Session* session, HA_CHECK_OPT* check_opt)
1 by brian
clean slate
2766
{
2767
  mark_trx_read_write();
2768
520.1.22 by Brian Aker
Second pass of thd cleanup
2769
  return optimize(session, check_opt);
1 by brian
clean slate
2770
}
2771
2772
2773
/**
2774
  Analyze table: public interface.
2775
2776
  @sa handler::analyze()
2777
*/
2778
2779
int
520.1.22 by Brian Aker
Second pass of thd cleanup
2780
handler::ha_analyze(Session* session, HA_CHECK_OPT* check_opt)
1 by brian
clean slate
2781
{
2782
  mark_trx_read_write();
2783
520.1.22 by Brian Aker
Second pass of thd cleanup
2784
  return analyze(session, check_opt);
1 by brian
clean slate
2785
}
2786
2787
2788
/**
2789
  Check and repair table: public interface.
2790
2791
  @sa handler::check_and_repair()
2792
*/
2793
2794
bool
520.1.22 by Brian Aker
Second pass of thd cleanup
2795
handler::ha_check_and_repair(Session *session)
1 by brian
clean slate
2796
{
2797
  mark_trx_read_write();
2798
520.1.22 by Brian Aker
Second pass of thd cleanup
2799
  return check_and_repair(session);
1 by brian
clean slate
2800
}
2801
2802
2803
/**
2804
  Disable indexes: public interface.
2805
2806
  @sa handler::disable_indexes()
2807
*/
2808
2809
int
482 by Brian Aker
Remove uint.
2810
handler::ha_disable_indexes(uint32_t mode)
1 by brian
clean slate
2811
{
2812
  mark_trx_read_write();
2813
2814
  return disable_indexes(mode);
2815
}
2816
2817
2818
/**
2819
  Enable indexes: public interface.
2820
2821
  @sa handler::enable_indexes()
2822
*/
2823
2824
int
482 by Brian Aker
Remove uint.
2825
handler::ha_enable_indexes(uint32_t mode)
1 by brian
clean slate
2826
{
2827
  mark_trx_read_write();
2828
2829
  return enable_indexes(mode);
2830
}
2831
2832
2833
/**
2834
  Discard or import tablespace: public interface.
2835
2836
  @sa handler::discard_or_import_tablespace()
2837
*/
2838
2839
int
200 by Brian Aker
my_bool from handler and set_var
2840
handler::ha_discard_or_import_tablespace(bool discard)
1 by brian
clean slate
2841
{
2842
  mark_trx_read_write();
2843
2844
  return discard_or_import_tablespace(discard);
2845
}
2846
2847
2848
/**
2849
  Prepare for alter: public interface.
2850
2851
  Called to prepare an *online* ALTER.
2852
2853
  @sa handler::prepare_for_alter()
2854
*/
2855
2856
void
2857
handler::ha_prepare_for_alter()
2858
{
2859
  mark_trx_read_write();
2860
2861
  prepare_for_alter();
2862
}
2863
2864
2865
/**
2866
  Rename table: public interface.
2867
2868
  @sa handler::rename_table()
2869
*/
2870
2871
int
2872
handler::ha_rename_table(const char *from, const char *to)
2873
{
2874
  mark_trx_read_write();
2875
2876
  return rename_table(from, to);
2877
}
2878
2879
2880
/**
2881
  Delete table: public interface.
2882
2883
  @sa handler::delete_table()
2884
*/
2885
2886
int
2887
handler::ha_delete_table(const char *name)
2888
{
2889
  mark_trx_read_write();
2890
2891
  return delete_table(name);
2892
}
2893
2894
2895
/**
2896
  Drop table in the engine: public interface.
2897
2898
  @sa handler::drop_table()
2899
*/
2900
2901
void
2902
handler::ha_drop_table(const char *name)
2903
{
2904
  mark_trx_read_write();
2905
2906
  return drop_table(name);
2907
}
2908
2909
2910
/**
2911
  Create a table in the engine: public interface.
2912
2913
  @sa handler::create()
2914
*/
2915
2916
int
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
2917
handler::ha_create(const char *name, Table *form, HA_CREATE_INFO *info)
1 by brian
clean slate
2918
{
2919
  mark_trx_read_write();
2920
2921
  return create(name, form, info);
2922
}
2923
2924
2925
/**
2926
  Create handler files for CREATE TABLE: public interface.
2927
2928
  @sa handler::create_handler_files()
2929
*/
2930
2931
int
2932
handler::ha_create_handler_files(const char *name, const char *old_name,
2933
                        int action_flag, HA_CREATE_INFO *info)
2934
{
2935
  mark_trx_read_write();
2936
2937
  return create_handler_files(name, old_name, action_flag, info);
2938
}
2939
2940
2941
/**
2942
  Tell the storage engine that it is allowed to "disable transaction" in the
2943
  handler. It is a hint that ACID is not required - it is used in NDB for
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
2944
  ALTER Table, for example, when data are copied to temporary table.
1 by brian
clean slate
2945
  A storage engine may treat this hint any way it likes. NDB for example
2946
  starts to commit every now and then automatically.
2947
  This hint can be safely ignored.
2948
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
2949
int ha_enable_transaction(Session *session, bool on)
1 by brian
clean slate
2950
{
2951
  int error=0;
2952
520.1.22 by Brian Aker
Second pass of thd cleanup
2953
  if ((session->transaction.on= on))
1 by brian
clean slate
2954
  {
2955
    /*
2956
      Now all storage engines should have transaction handling enabled.
2957
      But some may have it enabled all the time - "disabling" transactions
2958
      is an optimization hint that storage engine is free to ignore.
2959
      So, let's commit an open transaction (if any) now.
2960
    */
520.1.22 by Brian Aker
Second pass of thd cleanup
2961
    if (!(error= ha_commit_trans(session, 0)))
2962
      error= end_trans(session, COMMIT);
1 by brian
clean slate
2963
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2964
  return(error);
1 by brian
clean slate
2965
}
2966
482 by Brian Aker
Remove uint.
2967
int handler::index_next_same(unsigned char *buf, const unsigned char *key, uint32_t keylen)
1 by brian
clean slate
2968
{
2969
  int error;
2970
  if (!(error=index_next(buf)))
2971
  {
2972
    my_ptrdiff_t ptrdiff= buf - table->record[0];
481 by Brian Aker
Remove all of uchar.
2973
    unsigned char *save_record_0= NULL;
1 by brian
clean slate
2974
    KEY *key_info= NULL;
2975
    KEY_PART_INFO *key_part;
2976
    KEY_PART_INFO *key_part_end= NULL;
2977
2978
    /*
2979
      key_cmp_if_same() compares table->record[0] against 'key'.
2980
      In parts it uses table->record[0] directly, in parts it uses
2981
      field objects with their local pointers into table->record[0].
2982
      If 'buf' is distinct from table->record[0], we need to move
2983
      all record references. This is table->record[0] itself and
2984
      the field pointers of the fields used in this key.
2985
    */
2986
    if (ptrdiff)
2987
    {
2988
      save_record_0= table->record[0];
2989
      table->record[0]= buf;
2990
      key_info= table->key_info + active_index;
2991
      key_part= key_info->key_part;
2992
      key_part_end= key_part + key_info->key_parts;
2993
      for (; key_part < key_part_end; key_part++)
2994
      {
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
2995
        assert(key_part->field);
1 by brian
clean slate
2996
        key_part->field->move_field_offset(ptrdiff);
2997
      }
2998
    }
2999
3000
    if (key_cmp_if_same(table, key, active_index, keylen))
3001
    {
3002
      table->status=STATUS_NOT_FOUND;
3003
      error=HA_ERR_END_OF_FILE;
3004
    }
3005
3006
    /* Move back if necessary. */
3007
    if (ptrdiff)
3008
    {
3009
      table->record[0]= save_record_0;
3010
      for (key_part= key_info->key_part; key_part < key_part_end; key_part++)
3011
        key_part->field->move_field_offset(-ptrdiff);
3012
    }
3013
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3014
  return(error);
1 by brian
clean slate
3015
}
3016
3017
3018
/****************************************************************************
3019
** Some general functions that isn't in the handler class
3020
****************************************************************************/
3021
3022
/**
3023
  Initiates table-file and calls appropriate database-creator.
3024
3025
  @retval
3026
   0  ok
3027
  @retval
3028
   1  error
3029
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
3030
int ha_create_table(Session *session, const char *path,
1 by brian
clean slate
3031
                    const char *db, const char *table_name,
3032
                    HA_CREATE_INFO *create_info,
3033
		    bool update_create_info)
3034
{
3035
  int error= 1;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
3036
  Table table;
1 by brian
clean slate
3037
  char name_buff[FN_REFLEN];
3038
  const char *name;
3039
  TABLE_SHARE share;
3040
  
520.1.22 by Brian Aker
Second pass of thd cleanup
3041
  init_tmp_table_share(session, &share, db, 0, table_name, path);
3042
  if (open_table_def(session, &share, 0) ||
3043
      open_table_from_share(session, &share, "", 0, (uint) READ_ALL, 0, &table,
1 by brian
clean slate
3044
                            OTM_CREATE))
3045
    goto err;
3046
3047
  if (update_create_info)
327.1.2 by Brian Aker
Commiting next pass of Table class cleanup.
3048
    table.updateCreateInfo(create_info);
1 by brian
clean slate
3049
3050
  name= check_lowercase_names(table.file, share.path.str, name_buff);
3051
3052
  error= table.file->ha_create(name, &table, create_info);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
3053
  closefrm(&table, 0);
1 by brian
clean slate
3054
  if (error)
3055
  {
461 by Monty Taylor
Removed NullS. bu-bye.
3056
    strxmov(name_buff, db, ".", table_name, NULL);
1 by brian
clean slate
3057
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
3058
  }
3059
err:
3060
  free_table_share(&share);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3061
  return(error != 0);
1 by brian
clean slate
3062
}
3063
3064
/**
3065
  Try to discover table from engine.
3066
3067
  @note
3068
    If found, write the frm file to disk.
3069
3070
  @retval
3071
  -1    Table did not exists
3072
  @retval
3073
   0    Table created ok
3074
  @retval
3075
   > 0  Error, table existed but could not be created
3076
*/
520.1.22 by Brian Aker
Second pass of thd cleanup
3077
int ha_create_table_from_engine(Session* session, const char *db, const char *name)
1 by brian
clean slate
3078
{
3079
  int error;
481 by Brian Aker
Remove all of uchar.
3080
  unsigned char *frmblob;
1 by brian
clean slate
3081
  size_t frmlen;
3082
  char path[FN_REFLEN];
3083
  HA_CREATE_INFO create_info;
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
3084
  Table table;
1 by brian
clean slate
3085
  TABLE_SHARE share;
3086
212.6.6 by Mats Kindahl
Removing redundant use of casts in drizzled/ for memcmp(), memcpy(), memset(), and memmove().
3087
  memset(&create_info, 0, sizeof(create_info));
520.1.22 by Brian Aker
Second pass of thd cleanup
3088
  if ((error= ha_discover(session, db, name, &frmblob, &frmlen)))
1 by brian
clean slate
3089
  {
3090
    /* Table could not be discovered and thus not created */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3091
    return(error);
1 by brian
clean slate
3092
  }
3093
3094
  /*
3095
    Table exists in handler and could be discovered
3096
    frmblob and frmlen are set, write the frm to disk
3097
  */
3098
3099
  build_table_filename(path, FN_REFLEN-1, db, name, "", 0);
3100
  // Save the frm file
3101
  error= writefrm(path, frmblob, frmlen);
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
3102
  free(frmblob);
1 by brian
clean slate
3103
  if (error)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3104
    return(2);
1 by brian
clean slate
3105
520.1.22 by Brian Aker
Second pass of thd cleanup
3106
  init_tmp_table_share(session, &share, db, 0, name, path);
3107
  if (open_table_def(session, &share, 0))
1 by brian
clean slate
3108
  {
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3109
    return(3);
1 by brian
clean slate
3110
  }
520.1.22 by Brian Aker
Second pass of thd cleanup
3111
  if (open_table_from_share(session, &share, "" ,0, 0, 0, &table, OTM_OPEN))
1 by brian
clean slate
3112
  {
3113
    free_table_share(&share);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3114
    return(3);
1 by brian
clean slate
3115
  }
3116
327.1.2 by Brian Aker
Commiting next pass of Table class cleanup.
3117
  table.updateCreateInfo(&create_info);
1 by brian
clean slate
3118
  create_info.table_options|= HA_OPTION_CREATE_FROM_ENGINE;
3119
3120
  check_lowercase_names(table.file, path, path);
3121
  error=table.file->ha_create(path, &table, &create_info);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
3122
  closefrm(&table, 1);
1 by brian
clean slate
3123
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3124
  return(error != 0);
1 by brian
clean slate
3125
}
3126
3127
void st_ha_check_opt::init()
3128
{
3129
  flags= sql_flags= 0;
520.1.22 by Brian Aker
Second pass of thd cleanup
3130
  sort_buffer_size = current_session->variables.myisam_sort_buff_size;
1 by brian
clean slate
3131
}
3132
3133
3134
/*****************************************************************************
3135
  Key cache handling.
3136
3137
  This code is only relevant for ISAM/MyISAM tables
3138
3139
  key_cache->cache may be 0 only in the case where a key cache is not
3140
  initialized or when we where not able to init the key cache in a previous
3141
  call to ha_init_key_cache() (probably out of memory)
3142
*****************************************************************************/
3143
3144
/**
3145
  Init a key cache if it has not been initied before.
3146
*/
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
3147
int ha_init_key_cache(const char *name __attribute__((unused)),
77.1.15 by Monty Taylor
Bunch of warning cleanups.
3148
                      KEY_CACHE *key_cache)
1 by brian
clean slate
3149
{
3150
  if (!key_cache->key_cache_inited)
3151
  {
3152
    pthread_mutex_lock(&LOCK_global_system_variables);
61 by Brian Aker
Conversion of handler type.
3153
    uint32_t tmp_buff_size= (uint32_t) key_cache->param_buff_size;
482 by Brian Aker
Remove uint.
3154
    uint32_t tmp_block_size= (uint) key_cache->param_block_size;
3155
    uint32_t division_limit= key_cache->param_division_limit;
3156
    uint32_t age_threshold=  key_cache->param_age_threshold;
1 by brian
clean slate
3157
    pthread_mutex_unlock(&LOCK_global_system_variables);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3158
    return(!init_key_cache(key_cache,
1 by brian
clean slate
3159
				tmp_block_size,
3160
				tmp_buff_size,
3161
				division_limit, age_threshold));
3162
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3163
  return(0);
1 by brian
clean slate
3164
}
3165
3166
3167
/**
3168
  Resize key cache.
3169
*/
3170
int ha_resize_key_cache(KEY_CACHE *key_cache)
3171
{
3172
  if (key_cache->key_cache_inited)
3173
  {
3174
    pthread_mutex_lock(&LOCK_global_system_variables);
3175
    long tmp_buff_size= (long) key_cache->param_buff_size;
3176
    long tmp_block_size= (long) key_cache->param_block_size;
482 by Brian Aker
Remove uint.
3177
    uint32_t division_limit= key_cache->param_division_limit;
3178
    uint32_t age_threshold=  key_cache->param_age_threshold;
1 by brian
clean slate
3179
    pthread_mutex_unlock(&LOCK_global_system_variables);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3180
    return(!resize_key_cache(key_cache, tmp_block_size,
1 by brian
clean slate
3181
				  tmp_buff_size,
3182
				  division_limit, age_threshold));
3183
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3184
  return(0);
1 by brian
clean slate
3185
}
3186
3187
3188
/**
3189
  Change parameters for key cache (like size)
3190
*/
3191
int ha_change_key_cache_param(KEY_CACHE *key_cache)
3192
{
3193
  if (key_cache->key_cache_inited)
3194
  {
3195
    pthread_mutex_lock(&LOCK_global_system_variables);
482 by Brian Aker
Remove uint.
3196
    uint32_t division_limit= key_cache->param_division_limit;
3197
    uint32_t age_threshold=  key_cache->param_age_threshold;
1 by brian
clean slate
3198
    pthread_mutex_unlock(&LOCK_global_system_variables);
3199
    change_key_cache_param(key_cache, division_limit, age_threshold);
3200
  }
3201
  return 0;
3202
}
3203
3204
/**
3205
  Free memory allocated by a key cache.
3206
*/
3207
int ha_end_key_cache(KEY_CACHE *key_cache)
3208
{
3209
  end_key_cache(key_cache, 1);		// Can never fail
3210
  return 0;
3211
}
3212
3213
/**
3214
  Move all tables from one key cache to another one.
3215
*/
3216
int ha_change_key_cache(KEY_CACHE *old_key_cache,
3217
			KEY_CACHE *new_key_cache)
3218
{
3219
  mi_change_key_cache(old_key_cache, new_key_cache);
3220
  return 0;
3221
}
3222
3223
3224
/**
3225
  Try to discover one table from handler(s).
3226
3227
  @retval
3228
    -1   Table did not exists
3229
  @retval
3230
    0   OK. In this case *frmblob and *frmlen are set
3231
  @retval
3232
    >0   error.  frmblob and frmlen may not be set
3233
*/
3234
struct st_discover_args
3235
{
3236
  const char *db;
3237
  const char *name;
481 by Brian Aker
Remove all of uchar.
3238
  unsigned char **frmblob; 
1 by brian
clean slate
3239
  size_t *frmlen;
3240
};
3241
520.1.22 by Brian Aker
Second pass of thd cleanup
3242
static bool discover_handlerton(Session *session, plugin_ref plugin,
149 by Brian Aker
More bool conversion.
3243
                                void *arg)
1 by brian
clean slate
3244
{
3245
  st_discover_args *vargs= (st_discover_args *)arg;
3246
  handlerton *hton= plugin_data(plugin, handlerton *);
3247
  if (hton->state == SHOW_OPTION_YES && hton->discover &&
520.1.22 by Brian Aker
Second pass of thd cleanup
3248
      (!(hton->discover(hton, session, vargs->db, vargs->name, 
1 by brian
clean slate
3249
                        vargs->frmblob, 
3250
                        vargs->frmlen))))
56 by brian
Next pass of true/false update.
3251
    return true;
1 by brian
clean slate
3252
56 by brian
Next pass of true/false update.
3253
  return false;
1 by brian
clean slate
3254
}
3255
520.1.22 by Brian Aker
Second pass of thd cleanup
3256
int ha_discover(Session *session, const char *db, const char *name,
481 by Brian Aker
Remove all of uchar.
3257
		unsigned char **frmblob, size_t *frmlen)
1 by brian
clean slate
3258
{
3259
  int error= -1; // Table does not exist in any handler
3260
  st_discover_args args= {db, name, frmblob, frmlen};
3261
3262
  if (is_prefix(name,tmp_file_prefix)) /* skip temporary tables */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3263
    return(error);
1 by brian
clean slate
3264
520.1.22 by Brian Aker
Second pass of thd cleanup
3265
  if (plugin_foreach(session, discover_handlerton,
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
3266
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &args))
1 by brian
clean slate
3267
    error= 0;
3268
3269
  if (!error)
520.1.22 by Brian Aker
Second pass of thd cleanup
3270
    status_var_increment(session->status_var.ha_discover_count);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3271
  return(error);
1 by brian
clean slate
3272
}
3273
3274
3275
/**
3276
  Call this function in order to give the handler the possiblity
3277
  to ask engine if there are any new tables that should be written to disk
3278
  or any dropped tables that need to be removed from disk
3279
*/
3280
struct st_find_files_args
3281
{
3282
  const char *db;
3283
  const char *path;
3284
  const char *wild;
3285
  bool dir;
3286
  List<LEX_STRING> *files;
3287
};
3288
3289
/**
3290
  Ask handler if the table exists in engine.
3291
  @retval
3292
    HA_ERR_NO_SUCH_TABLE     Table does not exist
3293
  @retval
3294
    HA_ERR_TABLE_EXIST       Table exists
3295
  @retval
3296
    \#                  Error code
3297
*/
3298
struct st_table_exists_in_engine_args
3299
{
3300
  const char *db;
3301
  const char *name;
3302
  int err;
3303
};
3304
520.1.22 by Brian Aker
Second pass of thd cleanup
3305
static bool table_exists_in_engine_handlerton(Session *session, plugin_ref plugin,
149 by Brian Aker
More bool conversion.
3306
                                              void *arg)
1 by brian
clean slate
3307
{
3308
  st_table_exists_in_engine_args *vargs= (st_table_exists_in_engine_args *)arg;
3309
  handlerton *hton= plugin_data(plugin, handlerton *);
3310
3311
  int err= HA_ERR_NO_SUCH_TABLE;
3312
3313
  if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine)
520.1.22 by Brian Aker
Second pass of thd cleanup
3314
    err = hton->table_exists_in_engine(hton, session, vargs->db, vargs->name);
1 by brian
clean slate
3315
3316
  vargs->err = err;
3317
  if (vargs->err == HA_ERR_TABLE_EXIST)
56 by brian
Next pass of true/false update.
3318
    return true;
1 by brian
clean slate
3319
56 by brian
Next pass of true/false update.
3320
  return false;
1 by brian
clean slate
3321
}
3322
520.1.22 by Brian Aker
Second pass of thd cleanup
3323
int ha_table_exists_in_engine(Session* session, const char* db, const char* name)
1 by brian
clean slate
3324
{
3325
  st_table_exists_in_engine_args args= {db, name, HA_ERR_NO_SUCH_TABLE};
520.1.22 by Brian Aker
Second pass of thd cleanup
3326
  plugin_foreach(session, table_exists_in_engine_handlerton,
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
3327
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &args);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3328
  return(args.err);
1 by brian
clean slate
3329
}
3330
3331
/**
3332
  Calculate cost of 'index only' scan for given index and number of records
3333
3334
  @param keynr    Index number
3335
  @param records  Estimated number of records to be retrieved
3336
3337
  @note
3338
    It is assumed that we will read trough the whole key range and that all
3339
    key blocks are half full (normally things are much better). It is also
3340
    assumed that each time we read the next key from the index, the handler
3341
    performs a random seek, thus the cost is proportional to the number of
3342
    blocks read.
3343
3344
  @todo
3345
    Consider joining this function and handler::read_time() into one
3346
    handler::read_time(keynr, records, ranges, bool index_only) function.
3347
3348
  @return
3349
    Estimated cost of 'index only' scan
3350
*/
3351
482 by Brian Aker
Remove uint.
3352
double handler::index_only_read_time(uint32_t keynr, double records)
1 by brian
clean slate
3353
{
3354
  double read_time;
482 by Brian Aker
Remove uint.
3355
  uint32_t keys_per_block= (stats.block_size/2/
1 by brian
clean slate
3356
			(table->key_info[keynr].key_length + ref_length) + 1);
3357
  read_time=((double) (records + keys_per_block-1) /
3358
             (double) keys_per_block);
3359
  return read_time;
3360
}
3361
3362
3363
/****************************************************************************
3364
 * Default MRR implementation (MRR to non-MRR converter)
3365
 ***************************************************************************/
3366
3367
/**
3368
  Get cost and other information about MRR scan over a known list of ranges
3369
3370
  Calculate estimated cost and other information about an MRR scan for given
3371
  sequence of ranges.
3372
3373
  @param keyno           Index number
3374
  @param seq             Range sequence to be traversed
3375
  @param seq_init_param  First parameter for seq->init()
3376
  @param n_ranges_arg    Number of ranges in the sequence, or 0 if the caller
3377
                         can't efficiently determine it
3378
  @param bufsz    INOUT  IN:  Size of the buffer available for use
3379
                         OUT: Size of the buffer that is expected to be actually
3380
                              used, or 0 if buffer is not needed.
3381
  @param flags    INOUT  A combination of HA_MRR_* flags
3382
  @param cost     OUT    Estimated cost of MRR access
3383
3384
  @note
3385
    This method (or an overriding one in a derived class) must check for
520.1.22 by Brian Aker
Second pass of thd cleanup
3386
    session->killed and return HA_POS_ERROR if it is not zero. This is required
1 by brian
clean slate
3387
    for a user to be able to interrupt the calculation by killing the
3388
    connection/query.
3389
3390
  @retval
3391
    HA_POS_ERROR  Error or the engine is unable to perform the requested
3392
                  scan. Values of OUT parameters are undefined.
3393
  @retval
3394
    other         OK, *cost contains cost of the scan, *bufsz and *flags
3395
                  contain scan parameters.
3396
*/
3397
77.1.15 by Monty Taylor
Bunch of warning cleanups.
3398
ha_rows
482 by Brian Aker
Remove uint.
3399
handler::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
77.1.15 by Monty Taylor
Bunch of warning cleanups.
3400
                                     void *seq_init_param,
482 by Brian Aker
Remove uint.
3401
                                     uint32_t n_ranges_arg __attribute__((unused)),
3402
                                     uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1 by brian
clean slate
3403
{
3404
  KEY_MULTI_RANGE range;
3405
  range_seq_t seq_it;
3406
  ha_rows rows, total_rows= 0;
482 by Brian Aker
Remove uint.
3407
  uint32_t n_ranges=0;
520.1.22 by Brian Aker
Second pass of thd cleanup
3408
  Session *session= current_session;
1 by brian
clean slate
3409
  
3410
  /* Default MRR implementation doesn't need buffer */
3411
  *bufsz= 0;
3412
3413
  seq_it= seq->init(seq_init_param, n_ranges, *flags);
3414
  while (!seq->next(seq_it, &range))
3415
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
3416
    if (unlikely(session->killed != 0))
1 by brian
clean slate
3417
      return HA_POS_ERROR;
3418
    
3419
    n_ranges++;
3420
    key_range *min_endp, *max_endp;
3421
    {
3422
      min_endp= range.start_key.length? &range.start_key : NULL;
3423
      max_endp= range.end_key.length? &range.end_key : NULL;
3424
    }
3425
    if ((range.range_flag & UNIQUE_RANGE) && !(range.range_flag & NULL_RANGE))
3426
      rows= 1; /* there can be at most one row */
3427
    else
3428
    {
3429
      if (HA_POS_ERROR == (rows= this->records_in_range(keyno, min_endp, 
3430
                                                        max_endp)))
3431
      {
3432
        /* Can't scan one range => can't do MRR scan at all */
3433
        total_rows= HA_POS_ERROR;
3434
        break;
3435
      }
3436
    }
3437
    total_rows += rows;
3438
  }
3439
  
3440
  if (total_rows != HA_POS_ERROR)
3441
  {
3442
    /* The following calculation is the same as in multi_range_read_info(): */
3443
    *flags |= HA_MRR_USE_DEFAULT_IMPL;
3444
    cost->zero();
3445
    cost->avg_io_cost= 1; /* assume random seeks */
3446
    if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2)
3447
      cost->io_count= index_only_read_time(keyno, (uint)total_rows);
3448
    else
3449
      cost->io_count= read_time(keyno, n_ranges, total_rows);
3450
    cost->cpu_cost= (double) total_rows / TIME_FOR_COMPARE + 0.01;
3451
  }
3452
  return total_rows;
3453
}
3454
3455
3456
/**
3457
  Get cost and other information about MRR scan over some sequence of ranges
3458
3459
  Calculate estimated cost and other information about an MRR scan for some
3460
  sequence of ranges.
3461
3462
  The ranges themselves will be known only at execution phase. When this
3463
  function is called we only know number of ranges and a (rough) E(#records)
3464
  within those ranges.
3465
3466
  Currently this function is only called for "n-keypart singlepoint" ranges,
3467
  i.e. each range is "keypart1=someconst1 AND ... AND keypartN=someconstN"
3468
3469
  The flags parameter is a combination of those flags: HA_MRR_SORTED,
3470
  HA_MRR_INDEX_ONLY, HA_MRR_NO_ASSOCIATION, HA_MRR_LIMITS.
3471
3472
  @param keyno           Index number
3473
  @param n_ranges        Estimated number of ranges (i.e. intervals) in the
3474
                         range sequence.
3475
  @param n_rows          Estimated total number of records contained within all
3476
                         of the ranges
3477
  @param bufsz    INOUT  IN:  Size of the buffer available for use
3478
                         OUT: Size of the buffer that will be actually used, or
3479
                              0 if buffer is not needed.
3480
  @param flags    INOUT  A combination of HA_MRR_* flags
3481
  @param cost     OUT    Estimated cost of MRR access
3482
3483
  @retval
3484
    0     OK, *cost contains cost of the scan, *bufsz and *flags contain scan
3485
          parameters.
3486
  @retval
3487
    other Error or can't perform the requested scan
3488
*/
3489
482 by Brian Aker
Remove uint.
3490
int handler::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t n_rows,
3491
                                   uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1 by brian
clean slate
3492
{
3493
  *bufsz= 0; /* Default implementation doesn't need a buffer */
3494
3495
  *flags |= HA_MRR_USE_DEFAULT_IMPL;
3496
3497
  cost->zero();
3498
  cost->avg_io_cost= 1; /* assume random seeks */
3499
3500
  /* Produce the same cost as non-MRR code does */
3501
  if (*flags & HA_MRR_INDEX_ONLY)
3502
    cost->io_count= index_only_read_time(keyno, n_rows);
3503
  else
3504
    cost->io_count= read_time(keyno, n_ranges, n_rows);
3505
  return 0;
3506
}
3507
3508
3509
/**
3510
  Initialize the MRR scan
3511
3512
  Initialize the MRR scan. This function may do heavyweight scan 
3513
  initialization like row prefetching/sorting/etc (NOTE: but better not do
3514
  it here as we may not need it, e.g. if we never satisfy WHERE clause on
3515
  previous tables. For many implementations it would be natural to do such
3516
  initializations in the first multi_read_range_next() call)
3517
3518
  mode is a combination of the following flags: HA_MRR_SORTED,
3519
  HA_MRR_INDEX_ONLY, HA_MRR_NO_ASSOCIATION 
3520
3521
  @param seq             Range sequence to be traversed
3522
  @param seq_init_param  First parameter for seq->init()
3523
  @param n_ranges        Number of ranges in the sequence
3524
  @param mode            Flags, see the description section for the details
3525
  @param buf             INOUT: memory buffer to be used
3526
3527
  @note
3528
    One must have called index_init() before calling this function. Several
3529
    multi_range_read_init() calls may be made in course of one query.
3530
3531
    Until WL#2623 is done (see its text, section 3.2), the following will 
3532
    also hold:
3533
    The caller will guarantee that if "seq->init == mrr_ranges_array_init"
3534
    then seq_init_param is an array of n_ranges KEY_MULTI_RANGE structures.
3535
    This property will only be used by NDB handler until WL#2623 is done.
3536
     
3537
    Buffer memory management is done according to the following scenario:
3538
    The caller allocates the buffer and provides it to the callee by filling
3539
    the members of HANDLER_BUFFER structure.
3540
    The callee consumes all or some fraction of the provided buffer space, and
3541
    sets the HANDLER_BUFFER members accordingly.
3542
    The callee may use the buffer memory until the next multi_range_read_init()
3543
    call is made, all records have been read, or until index_end() call is
3544
    made, whichever comes first.
3545
3546
  @retval 0  OK
3547
  @retval 1  Error
3548
*/
3549
3550
int
3551
handler::multi_range_read_init(RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
482 by Brian Aker
Remove uint.
3552
                               uint32_t n_ranges, uint32_t mode,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
3553
                               HANDLER_BUFFER *buf __attribute__((unused)))
1 by brian
clean slate
3554
{
3555
  mrr_iter= seq_funcs->init(seq_init_param, n_ranges, mode);
3556
  mrr_funcs= *seq_funcs;
3557
  mrr_is_output_sorted= test(mode & HA_MRR_SORTED);
56 by brian
Next pass of true/false update.
3558
  mrr_have_range= false;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3559
  return(0);
1 by brian
clean slate
3560
}
3561
3562
3563
/**
3564
  Get next record in MRR scan
3565
3566
  Default MRR implementation: read the next record
3567
3568
  @param range_info  OUT  Undefined if HA_MRR_NO_ASSOCIATION flag is in effect
3569
                          Otherwise, the opaque value associated with the range
3570
                          that contains the returned record.
3571
3572
  @retval 0      OK
3573
  @retval other  Error code
3574
*/
3575
3576
int handler::multi_range_read_next(char **range_info)
3577
{
3578
  int result= 0;
236.2.2 by rbradfor
Using correct coding standards for variable initialization
3579
  int range_res= 0;
1 by brian
clean slate
3580
3581
  if (!mrr_have_range)
3582
  {
56 by brian
Next pass of true/false update.
3583
    mrr_have_range= true;
1 by brian
clean slate
3584
    goto start;
3585
  }
3586
3587
  do
3588
  {
3589
    /* Save a call if there can be only one row in range. */
3590
    if (mrr_cur_range.range_flag != (UNIQUE_RANGE | EQ_RANGE))
3591
    {
3592
      result= read_range_next();
3593
      /* On success or non-EOF errors jump to the end. */
3594
      if (result != HA_ERR_END_OF_FILE)
3595
        break;
3596
    }
3597
    else
3598
    {
3599
      if (was_semi_consistent_read())
3600
        goto scan_it_again;
3601
      /*
3602
        We need to set this for the last range only, but checking this
3603
        condition is more expensive than just setting the result code.
3604
      */
3605
      result= HA_ERR_END_OF_FILE;
3606
    }
3607
3608
start:
3609
    /* Try the next range(s) until one matches a record. */
3610
    while (!(range_res= mrr_funcs.next(mrr_iter, &mrr_cur_range)))
3611
    {
3612
scan_it_again:
3613
      result= read_range_first(mrr_cur_range.start_key.keypart_map ?
3614
                                 &mrr_cur_range.start_key : 0,
3615
                               mrr_cur_range.end_key.keypart_map ?
3616
                                 &mrr_cur_range.end_key : 0,
3617
                               test(mrr_cur_range.range_flag & EQ_RANGE),
3618
                               mrr_is_output_sorted);
3619
      if (result != HA_ERR_END_OF_FILE)
3620
        break;
3621
    }
3622
  }
3623
  while ((result == HA_ERR_END_OF_FILE) && !range_res);
3624
3625
  *range_info= mrr_cur_range.ptr;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3626
  return(result);
1 by brian
clean slate
3627
}
3628
3629
3630
/* **************************************************************************
3631
 * DS-MRR implementation 
3632
 ***************************************************************************/
3633
3634
/**
3635
  DS-MRR: Initialize and start MRR scan
3636
3637
  Initialize and start the MRR scan. Depending on the mode parameter, this
3638
  may use default or DS-MRR implementation.
3639
3640
  @param h               Table handler to be used
3641
  @param key             Index to be used
3642
  @param seq_funcs       Interval sequence enumeration functions
3643
  @param seq_init_param  Interval sequence enumeration parameter
3644
  @param n_ranges        Number of ranges in the sequence.
3645
  @param mode            HA_MRR_* modes to use
3646
  @param buf             INOUT Buffer to use
3647
3648
  @retval 0     Ok, Scan started.
3649
  @retval other Error
3650
*/
3651
3652
int DsMrr_impl::dsmrr_init(handler *h, KEY *key,
3653
                           RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
482 by Brian Aker
Remove uint.
3654
                           uint32_t n_ranges, uint32_t mode, HANDLER_BUFFER *buf)
1 by brian
clean slate
3655
{
482 by Brian Aker
Remove uint.
3656
  uint32_t elem_size;
3657
  uint32_t keyno;
1 by brian
clean slate
3658
  Item *pushed_cond= NULL;
3659
  handler *new_h2;
3660
  keyno= h->active_index;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3661
  assert(h2 == NULL);
1 by brian
clean slate
3662
  if (mode & HA_MRR_USE_DEFAULT_IMPL || mode & HA_MRR_SORTED)
3663
  {
56 by brian
Next pass of true/false update.
3664
    use_default_impl= true;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3665
    return(h->handler::multi_range_read_init(seq_funcs, seq_init_param,
1 by brian
clean slate
3666
                                                  n_ranges, mode, buf));
3667
  }
3668
  rowids_buf= buf->buffer;
3669
  //psergey-todo: don't add key_length as it is not needed anymore
3670
  rowids_buf += key->key_length + h->ref_length;
3671
3672
  is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
3673
  rowids_buf_end= buf->buffer_end;
3674
  
3675
  elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*);
3676
  rowids_buf_last= rowids_buf + 
3677
                      ((rowids_buf_end - rowids_buf)/ elem_size)*
3678
                      elem_size;
3679
  rowids_buf_end= rowids_buf_last;
3680
3681
  /* Create a separate handler object to do rndpos() calls. */
520.1.22 by Brian Aker
Second pass of thd cleanup
3682
  Session *session= current_session;
3683
  if (!(new_h2= h->clone(session->mem_root)) || 
3684
      new_h2->ha_external_lock(session, F_RDLCK))
1 by brian
clean slate
3685
  {
3686
    delete new_h2;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3687
    return(1);
1 by brian
clean slate
3688
  }
3689
3690
  if (keyno == h->pushed_idx_cond_keyno)
3691
    pushed_cond= h->pushed_idx_cond;
3692
  if (h->ha_index_end())
3693
  {
3694
    new_h2= h2;
3695
    goto error;
3696
  }
3697
3698
  h2= new_h2;
3699
  table->prepare_for_position();
3700
  new_h2->extra(HA_EXTRA_KEYREAD);
3701
56 by brian
Next pass of true/false update.
3702
  if (h2->ha_index_init(keyno, false) || 
1 by brian
clean slate
3703
      h2->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges,
3704
                                         mode, buf))
3705
    goto error;
56 by brian
Next pass of true/false update.
3706
  use_default_impl= false;
1 by brian
clean slate
3707
  
3708
  if (pushed_cond)
3709
    h2->idx_cond_push(keyno, pushed_cond);
3710
  if (dsmrr_fill_buffer(new_h2))
3711
    goto error;
3712
3713
  /*
3714
    If the above call has scanned through all intervals in *seq, then
3715
    adjust *buf to indicate that the remaining buffer space will not be used.
3716
  */
3717
  if (dsmrr_eof) 
3718
    buf->end_of_used_area= rowids_buf_last;
3719
56 by brian
Next pass of true/false update.
3720
  if (h->ha_rnd_init(false))
1 by brian
clean slate
3721
    goto error;
3722
  
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3723
  return(0);
1 by brian
clean slate
3724
error:
3725
  h2->ha_index_or_rnd_end();
520.1.22 by Brian Aker
Second pass of thd cleanup
3726
  h2->ha_external_lock(session, F_UNLCK);
1 by brian
clean slate
3727
  h2->close();
3728
  delete h2;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3729
  return(1);
1 by brian
clean slate
3730
}
3731
3732
3733
void DsMrr_impl::dsmrr_close()
3734
{
3735
  if (h2)
3736
  {
520.1.22 by Brian Aker
Second pass of thd cleanup
3737
    h2->ha_external_lock(current_session, F_UNLCK);
1 by brian
clean slate
3738
    h2->close();
3739
    delete h2;
3740
    h2= NULL;
3741
  }
56 by brian
Next pass of true/false update.
3742
  use_default_impl= true;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3743
  return;
1 by brian
clean slate
3744
}
3745
3746
481 by Brian Aker
Remove all of uchar.
3747
static int rowid_cmp(void *h, unsigned char *a, unsigned char *b)
1 by brian
clean slate
3748
{
3749
  return ((handler*)h)->cmp_ref(a, b);
3750
}
3751
3752
3753
/**
3754
  DS-MRR: Fill the buffer with rowids and sort it by rowid
3755
3756
  {This is an internal function of DiskSweep MRR implementation}
3757
  Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into 
3758
  buffer. When the buffer is full or scan is completed, sort the buffer by 
3759
  rowid and return.
3760
  
3761
  The function assumes that rowids buffer is empty when it is invoked. 
3762
  
3763
  @param h  Table handler
3764
3765
  @retval 0      OK, the next portion of rowids is in the buffer,
3766
                 properly ordered
3767
  @retval other  Error
3768
*/
3769
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
3770
int DsMrr_impl::dsmrr_fill_buffer(handler *unused __attribute__((unused)))
1 by brian
clean slate
3771
{
3772
  char *range_info;
236.2.1 by rbradfor
Mac OS/X with darwin ports corrected uninitialized variable warnings
3773
  int res = 0;
1 by brian
clean slate
3774
3775
  rowids_buf_cur= rowids_buf;
3776
  while ((rowids_buf_cur < rowids_buf_end) && 
3777
         !(res= h2->handler::multi_range_read_next(&range_info)))
3778
  {
3779
    /* Put rowid, or {rowid, range_id} pair into the buffer */
3780
    h2->position(table->record[0]);
3781
    memcpy(rowids_buf_cur, h2->ref, h2->ref_length);
3782
    rowids_buf_cur += h->ref_length;
3783
3784
    if (is_mrr_assoc)
3785
    {
3786
      memcpy(rowids_buf_cur, &range_info, sizeof(void*));
3787
      rowids_buf_cur += sizeof(void*);
3788
    }
3789
  }
3790
3791
  if (res && res != HA_ERR_END_OF_FILE)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3792
    return(res); 
1 by brian
clean slate
3793
  dsmrr_eof= test(res == HA_ERR_END_OF_FILE);
3794
3795
  /* Sort the buffer contents by rowid */
482 by Brian Aker
Remove uint.
3796
  uint32_t elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*);
3797
  uint32_t n_rowids= (rowids_buf_cur - rowids_buf) / elem_size;
1 by brian
clean slate
3798
  
3799
  my_qsort2(rowids_buf, n_rowids, elem_size, (qsort2_cmp)rowid_cmp,
3800
            (void*)h);
3801
  rowids_buf_last= rowids_buf_cur;
3802
  rowids_buf_cur=  rowids_buf;
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3803
  return(0);
1 by brian
clean slate
3804
}
3805
3806
3807
/**
3808
  DS-MRR implementation: multi_range_read_next() function
3809
*/
3810
3811
int DsMrr_impl::dsmrr_next(handler *h, char **range_info)
3812
{
3813
  int res;
3814
  
3815
  if (use_default_impl)
3816
    return h->handler::multi_range_read_next(range_info);
3817
    
3818
  if (rowids_buf_cur == rowids_buf_last)
3819
  {
3820
    if (dsmrr_eof)
3821
    {
3822
      res= HA_ERR_END_OF_FILE;
3823
      goto end;
3824
    }
3825
    res= dsmrr_fill_buffer(h);
3826
    if (res)
3827
      goto end;
3828
  }
3829
  
3830
  /* Return EOF if there are no rowids in the buffer after re-fill attempt */
3831
  if (rowids_buf_cur == rowids_buf_last)
3832
  {
3833
    res= HA_ERR_END_OF_FILE;
3834
    goto end;
3835
  }
3836
3837
  res= h->rnd_pos(table->record[0], rowids_buf_cur);
3838
  rowids_buf_cur += h->ref_length;
3839
  if (is_mrr_assoc)
3840
  {
3841
    memcpy(range_info, rowids_buf_cur, sizeof(void*));
3842
    rowids_buf_cur += sizeof(void*);
3843
  }
3844
3845
end:
3846
  if (res)
3847
    dsmrr_close();
3848
  return res;
3849
}
3850
3851
3852
/**
3853
  DS-MRR implementation: multi_range_read_info() function
3854
*/
482 by Brian Aker
Remove uint.
3855
int DsMrr_impl::dsmrr_info(uint32_t keyno, uint32_t n_ranges, uint32_t rows, uint32_t *bufsz,
3856
                           uint32_t *flags, COST_VECT *cost)
1 by brian
clean slate
3857
{  
3858
  int res;
482 by Brian Aker
Remove uint.
3859
  uint32_t def_flags= *flags;
3860
  uint32_t def_bufsz= *bufsz;
1 by brian
clean slate
3861
3862
  /* Get cost/flags/mem_usage of default MRR implementation */
3863
  res= h->handler::multi_range_read_info(keyno, n_ranges, rows, &def_bufsz,
3864
                                         &def_flags, cost);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
3865
  assert(!res);
1 by brian
clean slate
3866
3867
  if ((*flags & HA_MRR_USE_DEFAULT_IMPL) || 
3868
      choose_mrr_impl(keyno, rows, &def_flags, &def_bufsz, cost))
3869
  {
3870
    /* Default implementation is choosen */
3871
    *flags= def_flags;
3872
    *bufsz= def_bufsz;
3873
  }
3874
  return 0;
3875
}
3876
3877
3878
/**
3879
  DS-MRR Implementation: multi_range_read_info_const() function
3880
*/
3881
482 by Brian Aker
Remove uint.
3882
ha_rows DsMrr_impl::dsmrr_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
3883
                                 void *seq_init_param, uint32_t n_ranges, 
3884
                                 uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1 by brian
clean slate
3885
{
3886
  ha_rows rows;
482 by Brian Aker
Remove uint.
3887
  uint32_t def_flags= *flags;
3888
  uint32_t def_bufsz= *bufsz;
1 by brian
clean slate
3889
  /* Get cost/flags/mem_usage of default MRR implementation */
3890
  rows= h->handler::multi_range_read_info_const(keyno, seq, seq_init_param,
3891
                                                n_ranges, &def_bufsz, 
3892
                                                &def_flags, cost);
3893
  if (rows == HA_POS_ERROR)
3894
  {
3895
    /* Default implementation can't perform MRR scan => we can't either */
3896
    return rows;
3897
  }
3898
3899
  /*
3900
    If HA_MRR_USE_DEFAULT_IMPL has been passed to us, that is an order to
3901
    use the default MRR implementation (we need it for UPDATE/DELETE).
3902
    Otherwise, make a choice based on cost and @@optimizer_use_mrr.
3903
  */
3904
  if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
3905
      choose_mrr_impl(keyno, rows, flags, bufsz, cost))
3906
  {
3907
    *flags= def_flags;
3908
    *bufsz= def_bufsz;
3909
  }
3910
  else
3911
  {
3912
    *flags &= ~HA_MRR_USE_DEFAULT_IMPL;
3913
  }
3914
  return rows;
3915
}
3916
3917
3918
/**
3919
  Check if key has partially-covered columns
3920
3921
  We can't use DS-MRR to perform range scans when the ranges are over
3922
  partially-covered keys, because we'll not have full key part values
3923
  (we'll have their prefixes from the index) and will not be able to check
3924
  if we've reached the end the range.
3925
3926
  @param keyno  Key to check
3927
3928
  @todo
3929
    Allow use of DS-MRR in cases where the index has partially-covered
3930
    components but they are not used for scanning.
3931
56 by brian
Next pass of true/false update.
3932
  @retval true   Yes
3933
  @retval false  No
1 by brian
clean slate
3934
*/
3935
482 by Brian Aker
Remove uint.
3936
bool DsMrr_impl::key_uses_partial_cols(uint32_t keyno)
1 by brian
clean slate
3937
{
3938
  KEY_PART_INFO *kp= table->key_info[keyno].key_part;
3939
  KEY_PART_INFO *kp_end= kp + table->key_info[keyno].key_parts;
3940
  for (; kp != kp_end; kp++)
3941
  {
3942
    if (!kp->field->part_of_key.is_set(keyno))
56 by brian
Next pass of true/false update.
3943
      return true;
1 by brian
clean slate
3944
  }
56 by brian
Next pass of true/false update.
3945
  return false;
1 by brian
clean slate
3946
}
3947
3948
3949
/**
3950
  DS-MRR Internals: Choose between Default MRR implementation and DS-MRR
3951
3952
  Make the choice between using Default MRR implementation and DS-MRR.
3953
  This function contains common functionality factored out of dsmrr_info()
3954
  and dsmrr_info_const(). The function assumes that the default MRR
3955
  implementation's applicability requirements are satisfied.
3956
3957
  @param keyno       Index number
3958
  @param rows        E(full rows to be retrieved)
3959
  @param flags  IN   MRR flags provided by the MRR user
3960
                OUT  If DS-MRR is choosen, flags of DS-MRR implementation
3961
                     else the value is not modified
3962
  @param bufsz  IN   If DS-MRR is choosen, buffer use of DS-MRR implementation
3963
                     else the value is not modified
3964
  @param cost   IN   Cost of default MRR implementation
3965
                OUT  If DS-MRR is choosen, cost of DS-MRR scan
3966
                     else the value is not modified
3967
56 by brian
Next pass of true/false update.
3968
  @retval true   Default MRR implementation should be used
3969
  @retval false  DS-MRR implementation should be used
1 by brian
clean slate
3970
*/
3971
482 by Brian Aker
Remove uint.
3972
bool DsMrr_impl::choose_mrr_impl(uint32_t keyno, ha_rows rows, uint32_t *flags,
3973
                                 uint32_t *bufsz, COST_VECT *cost)
1 by brian
clean slate
3974
{
3975
  COST_VECT dsmrr_cost;
3976
  bool res;
520.1.22 by Brian Aker
Second pass of thd cleanup
3977
  Session *session= current_session;
3978
  if ((session->variables.optimizer_use_mrr == 2) || 
1 by brian
clean slate
3979
      (*flags & HA_MRR_INDEX_ONLY) || (*flags & HA_MRR_SORTED) ||
3980
      (keyno == table->s->primary_key && 
3981
       h->primary_key_is_clustered()) || 
3982
       key_uses_partial_cols(keyno))
3983
  {
3984
    /* Use the default implementation */
3985
    *flags |= HA_MRR_USE_DEFAULT_IMPL;
56 by brian
Next pass of true/false update.
3986
    return true;
1 by brian
clean slate
3987
  }
3988
  
482 by Brian Aker
Remove uint.
3989
  uint32_t add_len= table->key_info[keyno].key_length + h->ref_length; 
1 by brian
clean slate
3990
  *bufsz -= add_len;
3991
  if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
56 by brian
Next pass of true/false update.
3992
    return true;
1 by brian
clean slate
3993
  *bufsz += add_len;
3994
  
3995
  bool force_dsmrr;
3996
  /* 
3997
    If @@optimizer_use_mrr==force, then set cost of DS-MRR to be minimum of
3998
    DS-MRR and Default implementations cost. This allows one to force use of
3999
    DS-MRR whenever it is applicable without affecting other cost-based
4000
    choices.
4001
  */
520.1.22 by Brian Aker
Second pass of thd cleanup
4002
  if ((force_dsmrr= (session->variables.optimizer_use_mrr == 1)) &&
1 by brian
clean slate
4003
      dsmrr_cost.total_cost() > cost->total_cost())
4004
    dsmrr_cost= *cost;
4005
4006
  if (force_dsmrr || dsmrr_cost.total_cost() <= cost->total_cost())
4007
  {
4008
    *flags &= ~HA_MRR_USE_DEFAULT_IMPL;  /* Use the DS-MRR implementation */
4009
    *flags &= ~HA_MRR_SORTED;          /* We will return unordered output */
4010
    *cost= dsmrr_cost;
56 by brian
Next pass of true/false update.
4011
    res= false;
1 by brian
clean slate
4012
  }
4013
  else
4014
  {
4015
    /* Use the default MRR implementation */
56 by brian
Next pass of true/false update.
4016
    res= true;
1 by brian
clean slate
4017
  }
4018
  return res;
4019
}
4020
4021
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
4022
static void get_sort_and_sweep_cost(Table *table, ha_rows nrows, COST_VECT *cost);
1 by brian
clean slate
4023
4024
4025
/**
4026
  Get cost of DS-MRR scan
4027
4028
  @param keynr              Index to be used
4029
  @param rows               E(Number of rows to be scanned)
4030
  @param flags              Scan parameters (HA_MRR_* flags)
4031
  @param buffer_size INOUT  Buffer size
4032
  @param cost        OUT    The cost
4033
56 by brian
Next pass of true/false update.
4034
  @retval false  OK
4035
  @retval true   Error, DS-MRR cannot be used (the buffer is too small
1 by brian
clean slate
4036
                 for even 1 rowid)
4037
*/
4038
482 by Brian Aker
Remove uint.
4039
bool DsMrr_impl::get_disk_sweep_mrr_cost(uint32_t keynr, ha_rows rows, uint32_t flags,
4040
                                         uint32_t *buffer_size, COST_VECT *cost)
1 by brian
clean slate
4041
{
61 by Brian Aker
Conversion of handler type.
4042
  uint32_t max_buff_entries, elem_size;
1 by brian
clean slate
4043
  ha_rows rows_in_full_step, rows_in_last_step;
482 by Brian Aker
Remove uint.
4044
  uint32_t n_full_steps;
1 by brian
clean slate
4045
  double index_read_cost;
4046
4047
  elem_size= h->ref_length + sizeof(void*) * (!test(flags & HA_MRR_NO_ASSOCIATION));
4048
  max_buff_entries = *buffer_size / elem_size;
4049
4050
  if (!max_buff_entries)
56 by brian
Next pass of true/false update.
4051
    return true; /* Buffer has not enough space for even 1 rowid */
1 by brian
clean slate
4052
4053
  /* Number of iterations we'll make with full buffer */
4054
  n_full_steps= (uint)floor(rows2double(rows) / max_buff_entries);
4055
  
4056
  /* 
4057
    Get numbers of rows we'll be processing in 
4058
     - non-last sweep, with full buffer 
4059
     - last iteration, with non-full buffer
4060
  */
4061
  rows_in_full_step= max_buff_entries;
4062
  rows_in_last_step= rows % max_buff_entries;
4063
  
4064
  /* Adjust buffer size if we expect to use only part of the buffer */
4065
  if (n_full_steps)
4066
  {
4067
    get_sort_and_sweep_cost(table, rows, cost);
4068
    cost->multiply(n_full_steps);
4069
  }
4070
  else
4071
  {
4072
    cost->zero();
398.1.4 by Monty Taylor
Renamed max/min.
4073
    *buffer_size= cmax((ulong)*buffer_size, 
1 by brian
clean slate
4074
                      (size_t)(1.2*rows_in_last_step) * elem_size + 
4075
                      h->ref_length + table->key_info[keynr].key_length);
4076
  }
4077
  
4078
  COST_VECT last_step_cost;
4079
  get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
4080
  cost->add(&last_step_cost);
4081
 
4082
  if (n_full_steps != 0)
4083
    cost->mem_cost= *buffer_size;
4084
  else
4085
    cost->mem_cost= (double)rows_in_last_step * elem_size;
4086
  
4087
  /* Total cost of all index accesses */
4088
  index_read_cost= h->index_only_read_time(keynr, (double)rows);
4089
  cost->add_io(index_read_cost, 1 /* Random seeks */);
56 by brian
Next pass of true/false update.
4090
  return false;
1 by brian
clean slate
4091
}
4092
4093
4094
/* 
4095
  Get cost of one sort-and-sweep step
4096
4097
  SYNOPSIS
4098
    get_sort_and_sweep_cost()
4099
      table       Table being accessed
4100
      nrows       Number of rows to be sorted and retrieved
4101
      cost   OUT  The cost
4102
4103
  DESCRIPTION
4104
    Get cost of these operations:
4105
     - sort an array of #nrows ROWIDs using qsort
4106
     - read #nrows records from table in a sweep.
4107
*/
4108
4109
static 
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
4110
void get_sort_and_sweep_cost(Table *table, ha_rows nrows, COST_VECT *cost)
1 by brian
clean slate
4111
{
4112
  if (nrows)
4113
  {
56 by brian
Next pass of true/false update.
4114
    get_sweep_read_cost(table, nrows, false, cost);
1 by brian
clean slate
4115
    /* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */
4116
    double cmp_op= rows2double(nrows) * (1.0 / TIME_FOR_COMPARE_ROWID);
4117
    if (cmp_op < 3)
4118
      cmp_op= 3;
4119
    cost->cpu_cost += cmp_op * log2(cmp_op);
4120
  }
4121
  else
4122
    cost->zero();
4123
}
4124
4125
4126
/**
4127
  Get cost of reading nrows table records in a "disk sweep"
4128
4129
  A disk sweep read is a sequence of handler->rnd_pos(rowid) calls that made
4130
  for an ordered sequence of rowids.
4131
4132
  We assume hard disk IO. The read is performed as follows:
4133
4134
   1. The disk head is moved to the needed cylinder
4135
   2. The controller waits for the plate to rotate
4136
   3. The data is transferred
4137
4138
  Time to do #3 is insignificant compared to #2+#1.
4139
4140
  Time to move the disk head is proportional to head travel distance.
4141
4142
  Time to wait for the plate to rotate depends on whether the disk head
4143
  was moved or not. 
4144
4145
  If disk head wasn't moved, the wait time is proportional to distance
4146
  between the previous block and the block we're reading.
4147
4148
  If the head was moved, we don't know how much we'll need to wait for the
4149
  plate to rotate. We assume the wait time to be a variate with a mean of
4150
  0.5 of full rotation time.
4151
4152
  Our cost units are "random disk seeks". The cost of random disk seek is
4153
  actually not a constant, it depends one range of cylinders we're going
4154
  to access. We make it constant by introducing a fuzzy concept of "typical 
4155
  datafile length" (it's fuzzy as it's hard to tell whether it should
4156
  include index file, temp.tables etc). Then random seek cost is:
4157
4158
    1 = half_rotation_cost + move_cost * 1/3 * typical_data_file_length
4159
4160
  We define half_rotation_cost as DISK_SEEK_BASE_COST=0.9.
4161
4162
  @param table             Table to be accessed
4163
  @param nrows             Number of rows to retrieve
56 by brian
Next pass of true/false update.
4164
  @param interrupted       true <=> Assume that the disk sweep will be
4165
                           interrupted by other disk IO. false - otherwise.
1 by brian
clean slate
4166
  @param cost         OUT  The cost.
4167
*/
4168
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
4169
void get_sweep_read_cost(Table *table, ha_rows nrows, bool interrupted, 
1 by brian
clean slate
4170
                         COST_VECT *cost)
4171
{
4172
  cost->zero();
4173
  if (table->file->primary_key_is_clustered())
4174
  {
4175
    cost->io_count= table->file->read_time(table->s->primary_key,
4176
                                           (uint) nrows, nrows);
4177
  }
4178
  else
4179
  {
4180
    double n_blocks=
151 by Brian Aker
Ulonglong to uint64_t
4181
      ceil(uint64_t2double(table->file->stats.data_file_length) / IO_SIZE);
1 by brian
clean slate
4182
    double busy_blocks=
4183
      n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, rows2double(nrows)));
4184
    if (busy_blocks < 1.0)
4185
      busy_blocks= 1.0;
4186
4187
    cost->io_count= busy_blocks;
4188
4189
    if (!interrupted)
4190
    {
4191
      /* Assume reading is done in one 'sweep' */
4192
      cost->avg_io_cost= (DISK_SEEK_BASE_COST +
4193
                          DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
4194
    }
4195
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4196
  return;
1 by brian
clean slate
4197
}
4198
4199
4200
/* **************************************************************************
4201
 * DS-MRR implementation ends
4202
 ***************************************************************************/
4203
4204
/**
4205
  Read first row between two ranges.
4206
4207
  @param start_key		Start key. Is 0 if no min range
4208
  @param end_key		End key.  Is 0 if no max range
4209
  @param eq_range_arg	        Set to 1 if start_key == end_key
4210
  @param sorted		Set to 1 if result should be sorted per key
4211
4212
  @note
4213
    Record is read into table->record[0]
4214
4215
  @retval
4216
    0			Found row
4217
  @retval
4218
    HA_ERR_END_OF_FILE	No rows in range
4219
  @retval
4220
    \#			Error code
4221
*/
4222
int handler::read_range_first(const key_range *start_key,
4223
			      const key_range *end_key,
4224
			      bool eq_range_arg,
212.1.3 by Monty Taylor
Renamed __attribute__((__unused__)) to __attribute__((unused)).
4225
                              bool sorted  __attribute__((unused)))
1 by brian
clean slate
4226
{
4227
  int result;
4228
4229
  eq_range= eq_range_arg;
4230
  end_range= 0;
4231
  if (end_key)
4232
  {
4233
    end_range= &save_end_range;
4234
    save_end_range= *end_key;
4235
    key_compare_result_on_equal= ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 :
4236
				  (end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0);
4237
  }
4238
  range_key_part= table->key_info[active_index].key_part;
4239
4240
  if (!start_key)			// Read first record
4241
    result= index_first(table->record[0]);
4242
  else
4243
    result= index_read_map(table->record[0],
4244
                           start_key->key,
4245
                           start_key->keypart_map,
4246
                           start_key->flag);
4247
  if (result)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4248
    return((result == HA_ERR_KEY_NOT_FOUND) 
1 by brian
clean slate
4249
		? HA_ERR_END_OF_FILE
4250
		: result);
4251
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4252
  return (compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE);
1 by brian
clean slate
4253
}
4254
4255
4256
/**
4257
  Read next row between two endpoints.
4258
4259
  @note
4260
    Record is read into table->record[0]
4261
4262
  @retval
4263
    0			Found row
4264
  @retval
4265
    HA_ERR_END_OF_FILE	No rows in range
4266
  @retval
4267
    \#			Error code
4268
*/
4269
int handler::read_range_next()
4270
{
4271
  int result;
4272
4273
  if (eq_range)
4274
  {
4275
    /* We trust that index_next_same always gives a row in range */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4276
    return(index_next_same(table->record[0],
1 by brian
clean slate
4277
                                end_range->key,
4278
                                end_range->length));
4279
  }
4280
  result= index_next(table->record[0]);
4281
  if (result)
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4282
    return(result);
4283
  return(compare_key(end_range) <= 0 ? 0 : HA_ERR_END_OF_FILE);
1 by brian
clean slate
4284
}
4285
4286
4287
/**
4288
  Compare if found key (in row) is over max-value.
4289
4290
  @param range		range to compare to row. May be 0 for no range
4291
4292
  @seealso
4293
    key.cc::key_cmp()
4294
4295
  @return
4296
    The return value is SIGN(key_in_row - range_key):
4297
4298
    - 0   : Key is equal to range or 'range' == 0 (no range)
4299
    - -1  : Key is less than range
4300
    - 1   : Key is larger than range
4301
*/
4302
int handler::compare_key(key_range *range)
4303
{
4304
  int cmp;
4305
  if (!range || in_range_check_pushed_down)
4306
    return 0;					// No max range
4307
  cmp= key_cmp(range_key_part, range->key, range->length);
4308
  if (!cmp)
4309
    cmp= key_compare_result_on_equal;
4310
  return cmp;
4311
}
4312
4313
4314
/*
4315
  Same as compare_key() but doesn't check have in_range_check_pushed_down.
4316
  This is used by index condition pushdown implementation.
4317
*/
4318
4319
int handler::compare_key2(key_range *range)
4320
{
4321
  int cmp;
4322
  if (!range)
4323
    return 0;					// no max range
4324
  cmp= key_cmp(range_key_part, range->key, range->length);
4325
  if (!cmp)
4326
    cmp= key_compare_result_on_equal;
4327
  return cmp;
4328
}
4329
482 by Brian Aker
Remove uint.
4330
int handler::index_read_idx_map(unsigned char * buf, uint32_t index, const unsigned char * key,
1 by brian
clean slate
4331
                                key_part_map keypart_map,
4332
                                enum ha_rkey_function find_flag)
4333
{
4334
  int error, error1;
4335
  error= index_init(index, 0);
4336
  if (!error)
4337
  {
4338
    error= index_read_map(buf, key, keypart_map, find_flag);
4339
    error1= index_end();
4340
  }
4341
  return error ?  error : error1;
4342
}
4343
4344
4345
/**
4346
  Returns a list of all known extensions.
4347
4348
    No mutexes, worst case race is a minor surplus memory allocation
4349
    We have to recreate the extension map if mysqld is restarted (for example
4350
    within libmysqld)
4351
4352
  @retval
4353
    pointer		pointer to TYPELIB structure
4354
*/
520.1.21 by Brian Aker
THD -> Session rename
4355
static bool exts_handlerton(Session *unused __attribute__((unused)),
149 by Brian Aker
More bool conversion.
4356
                            plugin_ref plugin,
4357
                            void *arg)
1 by brian
clean slate
4358
{
4359
  List<char> *found_exts= (List<char> *) arg;
4360
  handlerton *hton= plugin_data(plugin, handlerton *);
4361
  handler *file;
4362
  if (hton->state == SHOW_OPTION_YES && hton->create &&
520.1.22 by Brian Aker
Second pass of thd cleanup
4363
      (file= hton->create(hton, (TABLE_SHARE*) 0, current_session->mem_root)))
1 by brian
clean slate
4364
  {
4365
    List_iterator_fast<char> it(*found_exts);
4366
    const char **ext, *old_ext;
4367
4368
    for (ext= file->bas_ext(); *ext; ext++)
4369
    {
4370
      while ((old_ext= it++))
4371
      {
4372
        if (!strcmp(old_ext, *ext))
4373
	  break;
4374
      }
4375
      if (!old_ext)
4376
        found_exts->push_back((char *) *ext);
4377
4378
      it.rewind();
4379
    }
4380
    delete file;
4381
  }
56 by brian
Next pass of true/false update.
4382
  return false;
1 by brian
clean slate
4383
}
4384
4385
TYPELIB *ha_known_exts(void)
4386
{
4387
  if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
4388
  {
4389
    List<char> found_exts;
4390
    const char **ext, *old_ext;
4391
4392
    known_extensions_id= mysys_usage_id;
4393
4394
    plugin_foreach(NULL, exts_handlerton,
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
4395
                   DRIZZLE_STORAGE_ENGINE_PLUGIN, &found_exts);
1 by brian
clean slate
4396
4397
    ext= (const char **) my_once_alloc(sizeof(char *)*
4398
                                       (found_exts.elements+1),
4399
                                       MYF(MY_WME | MY_FAE));
4400
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4401
    assert(ext != 0);
1 by brian
clean slate
4402
    known_extensions.count= found_exts.elements;
4403
    known_extensions.type_names= ext;
4404
4405
    List_iterator_fast<char> it(found_exts);
4406
    while ((old_ext= it++))
4407
      *ext++= old_ext;
4408
    *ext= 0;
4409
  }
4410
  return &known_extensions;
4411
}
4412
4413
520.1.22 by Brian Aker
Second pass of thd cleanup
4414
static bool stat_print(Session *session, const char *type, uint32_t type_len,
482 by Brian Aker
Remove uint.
4415
                       const char *file, uint32_t file_len,
4416
                       const char *status, uint32_t status_len)
1 by brian
clean slate
4417
{
520.1.22 by Brian Aker
Second pass of thd cleanup
4418
  Protocol *protocol= session->protocol;
1 by brian
clean slate
4419
  protocol->prepare_for_resend();
4420
  protocol->store(type, type_len, system_charset_info);
4421
  protocol->store(file, file_len, system_charset_info);
4422
  protocol->store(status, status_len, system_charset_info);
4423
  if (protocol->write())
56 by brian
Next pass of true/false update.
4424
    return true;
4425
  return false;
1 by brian
clean slate
4426
}
4427
520.1.22 by Brian Aker
Second pass of thd cleanup
4428
bool ha_show_status(Session *session, handlerton *db_type, enum ha_stat_type stat)
1 by brian
clean slate
4429
{
4430
  List<Item> field_list;
520.1.22 by Brian Aker
Second pass of thd cleanup
4431
  Protocol *protocol= session->protocol;
1 by brian
clean slate
4432
  bool result;
4433
4434
  field_list.push_back(new Item_empty_string("Type",10));
4435
  field_list.push_back(new Item_empty_string("Name",FN_REFLEN));
4436
  field_list.push_back(new Item_empty_string("Status",10));
4437
4438
  if (protocol->send_fields(&field_list,
4439
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
56 by brian
Next pass of true/false update.
4440
    return true;
1 by brian
clean slate
4441
12.1.1 by Brian Aker
Cleaned up show status.
4442
  result= db_type->show_status &&
520.1.22 by Brian Aker
Second pass of thd cleanup
4443
    db_type->show_status(db_type, session, stat_print, stat) ? 1 : 0;
1 by brian
clean slate
4444
4445
  if (!result)
520.1.22 by Brian Aker
Second pass of thd cleanup
4446
    my_eof(session);
1 by brian
clean slate
4447
  return result;
4448
}
4449
4450
4451
/**
4452
  Check if the conditions for row-based binlogging is correct for the table.
4453
4454
  A row in the given table should be replicated if:
4455
  - Row-based replication is enabled in the current thread
4456
  - The binlog is enabled
4457
  - It is not a temporary table
4458
  - The binary log is open
4459
  - The database the table resides in shall be binlogged (binlog_*_db rules)
4460
  - table is not mysql.event
4461
*/
4462
520.1.22 by Brian Aker
Second pass of thd cleanup
4463
static bool check_table_binlog_row_based(Session *session, Table *table)
1 by brian
clean slate
4464
{
4465
  if (table->s->cached_row_logging_check == -1)
4466
  {
4467
    int const check(table->s->tmp_table == NO_TMP_TABLE &&
4468
                    binlog_filter->db_ok(table->s->db.str));
4469
    table->s->cached_row_logging_check= check;
4470
  }
4471
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4472
  assert(table->s->cached_row_logging_check == 0 ||
1 by brian
clean slate
4473
              table->s->cached_row_logging_check == 1);
4474
520.1.22 by Brian Aker
Second pass of thd cleanup
4475
  return (session->current_stmt_binlog_row_based &&
1 by brian
clean slate
4476
          table->s->cached_row_logging_check &&
520.1.22 by Brian Aker
Second pass of thd cleanup
4477
          (session->options & OPTION_BIN_LOG) &&
1 by brian
clean slate
4478
          mysql_bin_log.is_open());
4479
}
4480
4481
4482
/**
4483
   Write table maps for all (manually or automatically) locked tables
4484
   to the binary log.
4485
4486
   This function will generate and write table maps for all tables
520.1.22 by Brian Aker
Second pass of thd cleanup
4487
   that are locked by the thread 'session'.  Either manually locked
520.1.21 by Brian Aker
THD -> Session rename
4488
   (stored in Session::locked_tables) and automatically locked (stored
4489
   in Session::lock) are considered.
1 by brian
clean slate
4490
520.1.22 by Brian Aker
Second pass of thd cleanup
4491
   @param session     Pointer to Session structure
1 by brian
clean slate
4492
4493
   @retval 0   All OK
4494
   @retval 1   Failed to write all table maps
4495
4496
   @sa
520.1.21 by Brian Aker
THD -> Session rename
4497
       Session::lock
4498
       Session::locked_tables
1 by brian
clean slate
4499
*/
4500
520.1.22 by Brian Aker
Second pass of thd cleanup
4501
static int write_locked_table_maps(Session *session)
1 by brian
clean slate
4502
{
520.1.22 by Brian Aker
Second pass of thd cleanup
4503
  if (session->get_binlog_table_maps() == 0)
1 by brian
clean slate
4504
  {
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
4505
    DRIZZLE_LOCK *locks[3];
520.1.22 by Brian Aker
Second pass of thd cleanup
4506
    locks[0]= session->extra_lock;
4507
    locks[1]= session->lock;
4508
    locks[2]= session->locked_tables;
482 by Brian Aker
Remove uint.
4509
    for (uint32_t i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i )
1 by brian
clean slate
4510
    {
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
4511
      DRIZZLE_LOCK const *const lock= locks[i];
1 by brian
clean slate
4512
      if (lock == NULL)
4513
        continue;
4514
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
4515
      Table **const end_ptr= lock->table + lock->table_count;
4516
      for (Table **table_ptr= lock->table ; 
1 by brian
clean slate
4517
           table_ptr != end_ptr ;
4518
           ++table_ptr)
4519
      {
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
4520
        Table *const table= *table_ptr;
1 by brian
clean slate
4521
        if (table->current_lock == F_WRLCK &&
520.1.22 by Brian Aker
Second pass of thd cleanup
4522
            check_table_binlog_row_based(session, table))
1 by brian
clean slate
4523
        {
4524
          int const has_trans= table->file->has_transactions();
520.1.22 by Brian Aker
Second pass of thd cleanup
4525
          int const error= session->binlog_write_table_map(table, has_trans);
1 by brian
clean slate
4526
          /*
4527
            If an error occurs, it is the responsibility of the caller to
4528
            roll back the transaction.
4529
          */
4530
          if (unlikely(error))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4531
            return(1);
1 by brian
clean slate
4532
        }
4533
      }
4534
    }
4535
  }
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4536
  return(0);
1 by brian
clean slate
4537
}
4538
4539
520.1.21 by Brian Aker
THD -> Session rename
4540
typedef bool Log_func(Session*, Table*, bool, const unsigned char*, const unsigned char*);
1 by brian
clean slate
4541
327.1.5 by Brian Aker
Refactor around classes. TABLE_LIST has been factored out of table.h
4542
static int binlog_log_row(Table* table,
481 by Brian Aker
Remove all of uchar.
4543
                          const unsigned char *before_record,
4544
                          const unsigned char *after_record,
1 by brian
clean slate
4545
                          Log_func *log_func)
4546
{
4547
  if (table->no_replicate)
4548
    return 0;
4549
  bool error= 0;
520.1.22 by Brian Aker
Second pass of thd cleanup
4550
  Session *const session= table->in_use;
1 by brian
clean slate
4551
520.1.22 by Brian Aker
Second pass of thd cleanup
4552
  if (check_table_binlog_row_based(session, table))
1 by brian
clean slate
4553
  {
4554
    /*
4555
      If there are no table maps written to the binary log, this is
4556
      the first row handled in this statement. In that case, we need
4557
      to write table maps for all locked tables to the binary log.
4558
    */
520.1.22 by Brian Aker
Second pass of thd cleanup
4559
    if (likely(!(error= write_locked_table_maps(session))))
1 by brian
clean slate
4560
    {
4561
      bool const has_trans= table->file->has_transactions();
520.1.22 by Brian Aker
Second pass of thd cleanup
4562
      error= (*log_func)(session, table, has_trans, before_record, after_record);
1 by brian
clean slate
4563
    }
4564
  }
4565
  return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
4566
}
4567
520.1.22 by Brian Aker
Second pass of thd cleanup
4568
int handler::ha_external_lock(Session *session, int lock_type)
1 by brian
clean slate
4569
{
4570
  /*
4571
    Whether this is lock or unlock, this should be true, and is to verify that
4572
    if get_auto_increment() was called (thus may have reserved intervals or
4573
    taken a table lock), ha_release_auto_increment() was too.
4574
  */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4575
  assert(next_insert_id == 0);
1 by brian
clean slate
4576
4577
  /*
4578
    We cache the table flags if the locking succeeded. Otherwise, we
4579
    keep them as they were when they were fetched in ha_open().
4580
  */
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
4581
  DRIZZLE_EXTERNAL_LOCK(lock_type);
1 by brian
clean slate
4582
520.1.22 by Brian Aker
Second pass of thd cleanup
4583
  int error= external_lock(session, lock_type);
1 by brian
clean slate
4584
  if (error == 0)
4585
    cached_table_flags= table_flags();
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4586
  return(error);
1 by brian
clean slate
4587
}
4588
4589
4590
/**
4591
  Check handler usage and reset state of file to after 'open'
4592
*/
4593
int handler::ha_reset()
4594
{
4595
  /* Check that we have called all proper deallocation functions */
481 by Brian Aker
Remove all of uchar.
4596
  assert((unsigned char*) table->def_read_set.bitmap +
1 by brian
clean slate
4597
              table->s->column_bitmap_size ==
481 by Brian Aker
Remove all of uchar.
4598
              (unsigned char*) table->def_write_set.bitmap);
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4599
  assert(bitmap_is_set_all(&table->s->all_set));
4600
  assert(table->key_read == 0);
1 by brian
clean slate
4601
  /* ensure that ha_index_end / ha_rnd_end has been called */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4602
  assert(inited == NONE);
1 by brian
clean slate
4603
  /* Free cache used by filesort */
4604
  free_io_cache(table);
4605
  /* reset the bitmaps to point to defaults */
4606
  table->default_column_bitmaps();
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4607
  return(reset());
1 by brian
clean slate
4608
}
4609
4610
481 by Brian Aker
Remove all of uchar.
4611
int handler::ha_write_row(unsigned char *buf)
1 by brian
clean slate
4612
{
4613
  int error;
4614
  Log_func *log_func= Write_rows_log_event::binlog_row_logging_function;
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
4615
  DRIZZLE_INSERT_ROW_START();
1 by brian
clean slate
4616
4617
  mark_trx_read_write();
4618
4619
  if (unlikely(error= write_row(buf)))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4620
    return(error);
1 by brian
clean slate
4621
  if (unlikely(error= binlog_log_row(table, 0, buf, log_func)))
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4622
    return(error); /* purecov: inspected */
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
4623
  DRIZZLE_INSERT_ROW_END();
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4624
  return(0);
1 by brian
clean slate
4625
}
4626
4627
481 by Brian Aker
Remove all of uchar.
4628
int handler::ha_update_row(const unsigned char *old_data, unsigned char *new_data)
1 by brian
clean slate
4629
{
4630
  int error;
4631
  Log_func *log_func= Update_rows_log_event::binlog_row_logging_function;
4632
4633
  /*
4634
    Some storage engines require that the new record is in record[0]
4635
    (and the old record is in record[1]).
4636
   */
51.1.77 by Jay Pipes
Standardized TRUE/FALSE, removed/replaced DBUG symbols
4637
  assert(new_data == table->record[0]);
1 by brian
clean slate
4638
4639
  mark_trx_read_write();
4640
4641
  if (unlikely(error= update_row(old_data, new_data)))
4642
    return error;
4643
  if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func)))
4644
    return error;
4645
  return 0;
4646
}
4647
481 by Brian Aker
Remove all of uchar.
4648
int handler::ha_delete_row(const unsigned char *buf)
1 by brian
clean slate
4649
{
4650
  int error;
4651
  Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function;
4652
4653
  mark_trx_read_write();
4654
4655
  if (unlikely(error= delete_row(buf)))
4656
    return error;
4657
  if (unlikely(error= binlog_log_row(table, buf, 0, log_func)))
4658
    return error;
4659
  return 0;
4660
}
4661
4662
4663
4664
/**
4665
  @details
4666
  use_hidden_primary_key() is called in case of an update/delete when
4667
  (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
4668
  but we don't have a primary key
4669
*/
4670
void handler::use_hidden_primary_key()
4671
{
4672
  /* fallback to use all columns in the table to identify row */
4673
  table->use_all_columns();
4674
}