~drizzle-trunk/drizzle/development

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