~drizzle-trunk/drizzle/development

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