~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/handler.cc

Moved the last of the libdrizzleclient calls into Protocol.

Show diffs side-by-side

added added

removed removed

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