2
Licensed Materials - Property of IBM
3
DB2 Storage Engine Enablement
4
Copyright IBM Corporation 2007,2008
7
Redistribution and use in source and binary forms, with or without modification,
8
are permitted provided that the following conditions are met:
9
(a) Redistributions of source code must retain this list of conditions, the
10
copyright notice in section {d} below, and the disclaimer following this
12
(b) Redistributions in binary form must reproduce this list of conditions, the
13
copyright notice in section (d) below, and the disclaimer following this
14
list of conditions, in the documentation and/or other materials provided
15
with the distribution.
16
(c) The name of IBM may not be used to endorse or promote products derived from
17
this software without specific prior written permission.
18
(d) The text of the required copyright notice is:
19
Licensed Materials - Property of IBM
20
DB2 Storage Engine Enablement
21
Copyright IBM Corporation 2007,2008
24
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
25
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41
The ha_ibmdb2i storage engine provides an interface from MySQL to IBM DB2 for i.
45
#ifdef USE_PRAGMA_IMPLEMENTATION
46
#pragma implementation // gcc: Class implementation
49
#include "ha_ibmdb2i.h"
50
#include "mysql_priv.h"
51
#include <mysql/plugin.h>
52
#include "db2i_ileBridge.h"
53
#include "db2i_charsetSupport.h"
54
#include <sys/utsname.h>
55
#include "db2i_safeString.h"
57
static const char __NOT_NULL_VALUE_EBCDIC = 0xF0; // '0'
58
static const char __NULL_VALUE_EBCDIC = 0xF1; // '1'
59
static const char __DEFAULT_VALUE_EBCDIC = 0xC4; // 'D'
60
static const char BlankASPName[19] = " ";
61
static const int DEFAULT_MAX_ROWS_TO_BUFFER = 4096;
63
static const char SAVEPOINT_PREFIX[] = {0xD4, 0xE8, 0xE2, 0xD7}; // MYSP (in EBCDIC)
68
// ================================================================
69
// ================================================================
71
static char* ibmdb2i_rdb_name;
72
static MYSQL_SYSVAR_STR(rdb_name, ibmdb2i_rdb_name,
73
PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY,
74
"The name of the RDB to use",
79
static MYSQL_THDVAR_BOOL(transaction_unsafe,
81
"Disable support for commitment control",
86
static MYSQL_THDVAR_UINT(lob_alloc_size,
88
"Baseline allocation for lob read buffer",
96
static MYSQL_THDVAR_UINT(max_read_buffer_size,
98
"Maximum size of buffers used for read-ahead.",
106
static MYSQL_THDVAR_UINT(max_write_buffer_size,
108
"Maximum size of buffers used for bulk writes.",
116
static MYSQL_THDVAR_BOOL(compat_opt_time_as_duration,
118
"Control how new TIME columns should be defined in DB2. 0=time-of-day (default), 1=duration.",
123
static MYSQL_THDVAR_UINT(compat_opt_year_as_int,
125
"Control how new YEAR columns should be defined in DB2. 0=CHAR(4) (default), 1=SMALLINT.",
133
static MYSQL_THDVAR_UINT(compat_opt_blob_cols,
135
"Control how new TEXT and BLOB columns should be defined in DB2. 0=CLOB/BLOB (default), 1=VARCHAR/VARBINARY",
143
static MYSQL_THDVAR_UINT(compat_opt_allow_zero_date_vals,
145
"Allow substitute values to be used when storing a column with a 0000-00-00 date component. 0=No substitution (default), 1=Substitute '0001-01-01'",
153
static MYSQL_THDVAR_BOOL(propagate_default_col_vals,
155
"Should DEFAULT column values be propagated to the DB2 table definition.",
160
static my_bool ibmdb2i_assume_exclusive_use;
161
static MYSQL_SYSVAR_BOOL(assume_exclusive_use, ibmdb2i_assume_exclusive_use,
163
"Can MySQL assume that this process is the only one modifying the DB2 tables. ",
168
static MYSQL_THDVAR_BOOL(async_enabled,
170
"Should reads be done asynchronously when possible",
175
static MYSQL_THDVAR_UINT(create_index_option,
177
"Control whether additional indexes are created. 0=No (default), 1=Create additional *HEX-based index",
185
/* static MYSQL_THDVAR_UINT(discovery_mode,
195
static uint32 ibmdb2i_system_trace;
196
static MYSQL_SYSVAR_UINT(system_trace_level, ibmdb2i_system_trace,
198
"Set system tracing level",
207
inline uint8 ha_ibmdb2i::getCommitLevel(THD* thd)
209
if (!THDVAR(thd, transaction_unsafe))
211
switch (thd_tx_isolation(thd))
213
case ISO_READ_UNCOMMITTED:
214
return (accessIntent == QMY_READ_ONLY ? QMY_READ_UNCOMMITTED : QMY_REPEATABLE_READ);
215
case ISO_READ_COMMITTED:
216
return (accessIntent == QMY_READ_ONLY ? QMY_READ_COMMITTED : QMY_REPEATABLE_READ);
217
case ISO_REPEATABLE_READ:
218
return QMY_REPEATABLE_READ;
219
case ISO_SERIALIZABLE:
220
return QMY_SERIALIZABLE;
227
inline uint8 ha_ibmdb2i::getCommitLevel()
229
return getCommitLevel(ha_thd());
232
//=====================================================================
234
static handler *ibmdb2i_create_handler(handlerton *hton,
237
static void ibmdb2i_drop_database(handlerton *hton, char* path);
238
static int ibmdb2i_savepoint_set(handlerton *hton, THD* thd, void *sv);
239
static int ibmdb2i_savepoint_rollback(handlerton *hton, THD* thd, void *sv);
240
static int ibmdb2i_savepoint_release(handlerton *hton, THD* thd, void *sv);
241
static uint ibmdb2i_alter_table_flags(uint flags);
243
handlerton *ibmdb2i_hton;
244
static bool was_ILE_inited;
246
/* Tracks the number of open tables */
247
static HASH ibmdb2i_open_tables;
249
/* Mutex used to synchronize initialization of the hash */
250
static pthread_mutex_t ibmdb2i_mutex;
254
Create hash key for tracking open tables.
257
static uchar* ibmdb2i_get_key(IBMDB2I_SHARE *share,size_t *length,
258
bool not_used __attribute__((unused)))
260
*length=share->table_name_length;
261
return (uchar*) share->table_name;
265
int ibmdb2i_close_connection(handlerton* hton, THD *thd)
267
DBUG_PRINT("ha_ibmdb2i::close_connection", ("Closing %d", thd->thread_id));
268
db2i_ileBridge::getBridgeForThread(thd)->closeConnection(thd->thread_id);
269
db2i_ileBridge::destroyBridgeForThread(thd);
275
static int ibmdb2i_init_func(void *p)
277
DBUG_ENTER("ibmdb2i_init_func");
281
osVersion.v = atoi(tempName.version);
282
osVersion.r = atoi(tempName.release);
284
was_ILE_inited = false;
285
ibmdb2i_hton= (handlerton *)p;
286
VOID(pthread_mutex_init(&ibmdb2i_mutex,MY_MUTEX_INIT_FAST));
287
(void) hash_init(&ibmdb2i_open_tables,system_charset_info,32,0,0,
288
(hash_get_key) ibmdb2i_get_key,0,0);
290
ibmdb2i_hton->state= SHOW_OPTION_YES;
291
ibmdb2i_hton->create= ibmdb2i_create_handler;
292
ibmdb2i_hton->drop_database= ibmdb2i_drop_database;
293
ibmdb2i_hton->commit= ha_ibmdb2i::doCommit;
294
ibmdb2i_hton->rollback= ha_ibmdb2i::doRollback;
295
ibmdb2i_hton->savepoint_offset= 0;
296
ibmdb2i_hton->savepoint_set= ibmdb2i_savepoint_set;
297
ibmdb2i_hton->savepoint_rollback= ibmdb2i_savepoint_rollback;
298
ibmdb2i_hton->savepoint_release= ibmdb2i_savepoint_release;
299
ibmdb2i_hton->alter_table_flags=ibmdb2i_alter_table_flags;
300
ibmdb2i_hton->close_connection=ibmdb2i_close_connection;
304
rc = initCharsetSupport();
307
rc = db2i_ileBridge::setup();
311
int nameLen = strlen(ibmdb2i_rdb_name);
312
for (int i = 0; i < nameLen; ++i)
314
ibmdb2i_rdb_name[i] = my_toupper(system_charset_info, (uchar)ibmdb2i_rdb_name[i]);
317
rc = db2i_ileBridge::initILE(ibmdb2i_rdb_name, (uint16*)(((char*)&ibmdb2i_system_trace)+2));
320
was_ILE_inited = true;
328
static int ibmdb2i_done_func(void *p)
331
DBUG_ENTER("ibmdb2i_done_func");
333
if (ibmdb2i_open_tables.records)
337
db2i_ileBridge::exitILE();
339
db2i_ileBridge::takedown();
341
doneCharsetSupport();
343
hash_free(&ibmdb2i_open_tables);
344
pthread_mutex_destroy(&ibmdb2i_mutex);
350
IBMDB2I_SHARE *ha_ibmdb2i::get_share(const char *table_name, TABLE *table)
352
IBMDB2I_SHARE *share;
356
pthread_mutex_lock(&ibmdb2i_mutex);
357
length=(uint) strlen(table_name);
359
if (!(share=(IBMDB2I_SHARE*) hash_search(&ibmdb2i_open_tables,
363
if (!(share=(IBMDB2I_SHARE *)
364
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
365
&share, sizeof(*share),
369
pthread_mutex_unlock(&ibmdb2i_mutex);
374
share->table_name_length=length;
375
share->table_name=tmp_name;
376
strmov(share->table_name,table_name);
377
if (my_hash_insert(&ibmdb2i_open_tables, (uchar*) share))
379
thr_lock_init(&share->lock);
380
pthread_mutexattr_t mutexattr = MY_MUTEX_INIT_FAST;
381
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
382
pthread_mutex_init(&share->mutex, &mutexattr);
384
share->db2Table = new db2i_table(table->s, table_name);
385
int32 rc = share->db2Table->initDB2Objects(table_name);
389
delete share->db2Table;
390
hash_delete(&ibmdb2i_open_tables, (uchar*) share);
391
thr_lock_delete(&share->lock);
396
memset(&share->cachedStats, 0, sizeof(share->cachedStats));
399
pthread_mutex_unlock(&ibmdb2i_mutex);
401
db2Table = share->db2Table;
406
pthread_mutex_destroy(&share->mutex);
407
my_free((uchar*) share, MYF(0));
408
pthread_mutex_unlock(&ibmdb2i_mutex);
415
int ha_ibmdb2i::free_share(IBMDB2I_SHARE *share)
417
pthread_mutex_lock(&ibmdb2i_mutex);
418
if (!--share->use_count)
420
delete share->db2Table;
423
hash_delete(&ibmdb2i_open_tables, (uchar*) share);
424
thr_lock_delete(&share->lock);
425
pthread_mutex_destroy(&share->mutex);
426
my_free(share, MYF(0));
427
pthread_mutex_unlock(&ibmdb2i_mutex);
430
pthread_mutex_unlock(&ibmdb2i_mutex);
435
static handler* ibmdb2i_create_handler(handlerton *hton,
439
return new (mem_root) ha_ibmdb2i(hton, table);
442
static void ibmdb2i_drop_database(handlerton *hton, char* path)
444
DBUG_ENTER("ha_ibmdb2i::ibmdb2i_drop_database");
446
char queryBuffer[200];
447
String query(queryBuffer, sizeof(queryBuffer), system_charset_info);
449
query.append(STRING_WITH_LEN(" DROP SCHEMA \""));
450
query.append(path+2, strchr(path+2, '/')-(path+2));
453
SqlStatementStream sqlStream(query);
455
rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
456
sqlStream.getStatementCount(),
463
inline static void genSavepointName(const void* sv, char* out)
465
*(uint32*)out = *(uint32*)SAVEPOINT_PREFIX;
466
DBUG_ASSERT(sizeof(SAVEPOINT_PREFIX) == 4);
467
out += sizeof(SAVEPOINT_PREFIX);
469
longlong2str((longlong)sv, out, 10);
478
/*********************************************************************
479
Sets a transaction savepoint. */
480
static int ibmdb2i_savepoint_set(handlerton* hton, THD* thd, void* sv)
482
DBUG_ENTER("ibmdb2i_savepoint_set");
484
if (!THDVAR(thd ,transaction_unsafe))
487
genSavepointName(sv, name);
488
DBUG_PRINT("ibmdb2i_savepoint_set",("Setting %s", name));
489
rc = ha_ibmdb2i::doSavepointSet(thd, name);
495
/*********************************************************************
496
Rollback a savepoint. */
497
static int ibmdb2i_savepoint_rollback(handlerton* hton, THD* thd, void* sv)
499
DBUG_ENTER("ibmdb2i_savepoint_rollback");
501
if (!THDVAR(thd,transaction_unsafe))
504
genSavepointName(sv, name);
505
DBUG_PRINT("ibmdb2i_savepoint_rollback",("Rolling back %s", name));
506
rc = ha_ibmdb2i::doSavepointRollback(thd, name);
512
/*********************************************************************
513
Release a savepoint. */
514
static int ibmdb2i_savepoint_release(handlerton* hton, THD* thd, void* sv)
516
DBUG_ENTER("ibmdb2i_savepoint_release");
518
if (!THDVAR(thd,transaction_unsafe))
521
genSavepointName(sv, name);
522
DBUG_PRINT("ibmdb2i_savepoint_release",("Releasing %s", name));
523
rc = ha_ibmdb2i::doSavepointRelease(thd, name);
528
/* Thse flags allow for the online add and drop of an index via the CREATE INDEX,
529
DROP INDEX, and ALTER TABLE statements. These flags indicate that MySQL is not
530
required to lock the table before calling the storage engine to add or drop the
532
static uint ibmdb2i_alter_table_flags(uint flags)
534
return (HA_ONLINE_ADD_INDEX | HA_ONLINE_DROP_INDEX |
535
HA_ONLINE_ADD_UNIQUE_INDEX | HA_ONLINE_DROP_UNIQUE_INDEX |
536
HA_ONLINE_ADD_PK_INDEX | HA_ONLINE_DROP_PK_INDEX);
539
ha_ibmdb2i::ha_ibmdb2i(handlerton *hton, TABLE_SHARE *table_arg)
540
:share(NULL), handler(hton, table_arg),
541
activeHandle(0), dataHandle(0),
542
activeReadBuf(NULL), activeWriteBuf(NULL),
543
blobReadBuffers(NULL), accessIntent(QMY_UPDATABLE), currentRRN(0),
544
releaseRowNeeded(FALSE),
545
indexReadSizeEstimates(NULL),
546
outstanding_start_bulk_insert(false),
548
last_index_init_rc(0),
549
last_start_bulk_insert_rc(0),
550
autoIncLockAcquired(false),
551
got_auto_inc_values(false),
552
next_identity_value(0),
554
returnDupKeysImmediately(false),
556
blobWriteBuffers(NULL),
557
forceSingleRowRead(false)
559
activeReferences = 0;
560
ref_length = sizeof(currentRRN);
561
if (table_share && table_share->keys > 0)
563
indexHandles = (FILE_HANDLE*)my_malloc(table_share->keys * sizeof(FILE_HANDLE), MYF(MY_WME | MY_ZEROFILL));
565
clear_alloc_root(&conversionBufferMemroot);
569
ha_ibmdb2i::~ha_ibmdb2i()
571
DBUG_ASSERT(activeReferences == 0 || outstanding_start_bulk_insert);
574
my_free(indexHandles, MYF(0));
575
if (indexReadSizeEstimates)
576
my_free(indexReadSizeEstimates, MYF(0));
582
static const char *ha_ibmdb2i_exts[] = {
587
const char **ha_ibmdb2i::bas_ext() const
589
return ha_ibmdb2i_exts;
593
int ha_ibmdb2i::open(const char *name, int mode, uint test_if_locked)
595
DBUG_ENTER("ha_ibmdb2i::open");
599
dataHandle = bridge()->findAndRemovePreservedHandle(name, &share);
602
db2Table = share->db2Table;
604
if (!share && (!(share = get_share(name, table))))
605
DBUG_RETURN(my_errno);
606
thr_lock_data_init(&share->lock,&lock,NULL);
608
info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
617
int ha_ibmdb2i::close(void)
619
DBUG_ENTER("ha_ibmdb2i::close");
621
bool preserveShare = false;
623
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread();
627
if (bridge->expectErrors(QMY_ERR_PEND_LOCKS)->deallocateFile(dataHandle, FALSE) == QMY_ERR_PEND_LOCKS)
629
bridge->preserveHandle(share->table_name, dataHandle, share);
630
preserveShare = true;
635
for (int idx = 0; idx < table_share->keys; ++idx)
637
if (indexHandles[idx] != 0)
639
bridge->deallocateFile(indexHandles[idx], FALSE);
647
if (free_share(share))
656
int ha_ibmdb2i::write_row(uchar * buf)
659
DBUG_ENTER("ha_ibmdb2i::write_row");
661
if (last_start_bulk_insert_rc)
662
DBUG_RETURN( last_start_bulk_insert_rc );
664
ha_statistic_increment(&SSV::ha_write_count);
667
bool fileHandleNeedsRelease = false;
672
if (rc) DBUG_RETURN(rc);
673
fileHandleNeedsRelease = true;
676
if (!outstanding_start_bulk_insert)
677
rc = prepWriteBuffer(1, getFileForActiveHandle());
681
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
682
table->timestamp_field->set_time();
684
char* writeBuffer = activeWriteBuf->addRow();
685
rc = prepareRowForWrite(writeBuffer,
686
writeBuffer+activeWriteBuf->getRowNullOffset(),
690
// If we are doing block inserts, if the MI is supposed to generate an auto_increment
691
// (i.e. identity column) value for this record, and if this is not the first record in
692
// the block, then store the value (that the MI will generate for the identity column)
693
// into the MySQL write buffer. We can predetermine the value because the file is locked.
695
if ((autoIncLockAcquired) && (default_identity_value) && (got_auto_inc_values))
697
if (unlikely((next_identity_value - 1) ==
698
maxValueForField(table->next_number_field)))
700
rc = QMY_ERR_MAXVALUE;
704
rc = table->next_number_field->store((longlong) next_identity_value, TRUE);
705
next_identity_value = next_identity_value + incrementByValue;
708
// If the buffer is full, or if we locked the file and this is the first or last row
709
// of a blocked insert, then flush the buffer.
710
if (!rc && (activeWriteBuf->endOfBuffer()) ||
711
((autoIncLockAcquired) &&
712
((!got_auto_inc_values))) ||
713
(returnDupKeysImmediately))
714
rc = flushWrite(activeHandle, buf);
717
activeWriteBuf->deleteRow();
720
if (fileHandleNeedsRelease)
721
releaseActiveHandle();
728
Helper function used by write_row and update_row to prepare the MySQL
729
row for insertion into DB2.
731
int ha_ibmdb2i::prepareRowForWrite(char* data, char* nulls, bool honorIdentCols)
735
// set null map all to non nulls
736
memset(nulls,__NOT_NULL_VALUE_EBCDIC, table->s->fields);
737
default_identity_value = FALSE;
739
ulong sql_mode = ha_thd()->variables.sql_mode;
741
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
742
for (Field **field = table->field; *field && !rc; ++field)
744
int fieldIndex = (*field)->field_index;
745
if ((*field)->Field::is_null())
747
nulls[fieldIndex] = __NULL_VALUE_EBCDIC;
749
if (honorIdentCols && ((*field)->flags & AUTO_INCREMENT_FLAG) &&
750
*field == table->next_number_field)
751
// && ((!autoIncLockAcquired) || (!got_auto_inc_values)))
753
if (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
755
if (!table->auto_increment_field_not_null)
757
nulls[fieldIndex] = __DEFAULT_VALUE_EBCDIC;
758
default_identity_value = TRUE;
761
else if ((*field)->val_int() == 0)
763
nulls[fieldIndex] = __DEFAULT_VALUE_EBCDIC;
764
default_identity_value = TRUE;
768
DB2Field& db2Field = db2Table->db2Field(fieldIndex);
769
if (nulls[fieldIndex] == __NOT_NULL_VALUE_EBCDIC ||
772
rc = convertMySQLtoDB2(*field, db2Field, data + db2Field.getBufferOffset());
776
if (!rc && db2Table->hasBlobs())
777
rc = db2i_ileBridge::getBridgeForThread()->objectOverride(activeHandle,
778
activeWriteBuf->ptr());
780
dbug_tmp_restore_column_map(table->read_set, old_map);
787
int ha_ibmdb2i::update_row(const uchar * old_data, uchar * new_data)
789
DBUG_ENTER("ha_ibmdb2i::update_row");
790
ha_statistic_increment(&SSV::ha_update_count);
793
bool fileHandleNeedsRelease = false;
797
rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);
798
if (rc) DBUG_RETURN(rc);
799
fileHandleNeedsRelease = true;
802
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
803
table->timestamp_field->set_time();
805
char* writeBuf = activeWriteBuf->addRow();
806
rc = prepareRowForWrite(writeBuf,
807
writeBuf+activeWriteBuf->getRowNullOffset(),
810
char* lastDupKeyNamePtr = NULL;
811
uint32 lastDupKeyNameLen = 0;
815
rc = db2i_ileBridge::getBridgeForThread()->updateRow(activeHandle,
817
activeWriteBuf->ptr(),
823
if (lastDupKeyNameLen)
825
lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen);
826
rrnAssocHandle = activeHandle;
829
if (fileHandleNeedsRelease)
830
releaseActiveHandle();
832
activeWriteBuf->resetAfterWrite();
838
int ha_ibmdb2i::delete_row(const uchar * buf)
840
DBUG_ENTER("ha_ibmdb2i::delete_row");
841
ha_statistic_increment(&SSV::ha_delete_count);
843
bool needReleaseFile = false;
846
if (!activeHandle) // In some circumstances, MySQL comes here after
847
{ // closing the active handle. We need to re-open.
848
rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);
849
needReleaseFile = true;
854
rc = db2i_ileBridge::getBridgeForThread()->deleteRow(activeHandle,
856
invalidateCachedStats();
858
releaseActiveHandle();
866
int ha_ibmdb2i::index_init(uint idx, bool sorted)
868
DBUG_ENTER("ha_ibmdb2i::index_init");
870
int& rc = last_index_init_rc;
873
invalidDataFound=false;
878
rc = useIndexFile(idx);
882
// THD* thd = ha_thd();
883
// if (accessIntent == QMY_UPDATABLE &&
884
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
885
// !THDVAR(thd, transaction_unsafe))
887
// readAccessIntent = QMY_READ_ONLY;
891
readAccessIntent = accessIntent;
894
if (!rc && accessIntent != QMY_READ_ONLY)
895
rc = prepWriteBuffer(1, db2Table->indexFile(idx));
898
releaseIndexFile(idx);
906
int ha_ibmdb2i::index_read(uchar * buf, const uchar * key,
908
enum ha_rkey_function find_flag)
910
DBUG_ENTER("ha_ibmdb2i::index_read");
912
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
916
ha_rows estimatedRows = getIndexReadEstimate(active_index);
917
rc = prepReadBuffer(estimatedRows, db2Table->indexFile(active_index), readAccessIntent);
918
if (unlikely(rc)) DBUG_RETURN(rc);
920
DBUG_ASSERT(activeReadBuf);
922
keyBuf.allocBuf(activeReadBuf->getRowLength(),
923
activeReadBuf->getRowNullOffset(),
924
activeReadBuf->getRowLength());
927
char* db2KeyBufPtr = keyBuf.ptr();
928
char* nullKeyMap = db2KeyBufPtr + activeReadBuf->getRowNullOffset();
930
const uchar* keyBegin = key;
933
KEY& curKey = table->key_info[active_index];
935
for (partsInUse = 0; partsInUse < curKey.key_parts, key - keyBegin < key_len; ++partsInUse)
937
Field* field = curKey.key_part[partsInUse].field;
938
if ((curKey.key_part[partsInUse].null_bit) &&
941
if (field->flags & AUTO_INCREMENT_FLAG)
943
table->status = STATUS_NOT_FOUND;
944
DBUG_RETURN(HA_ERR_END_OF_FILE);
948
nullKeyMap[partsInUse] = __NULL_VALUE_EBCDIC;
953
nullKeyMap[partsInUse] = __NOT_NULL_VALUE_EBCDIC;
954
convertMySQLtoDB2(field,
955
db2Table->db2Field(field->field_index),
957
(uchar*)key+((curKey.key_part[partsInUse].null_bit)? 1 : 0) ); // + (curKey.key_parts+7) / 8);
960
db2KeyBufPtr += db2Table->db2Field(field->field_index).getByteLengthInRecord();
961
key += curKey.key_part[partsInUse].store_length;
964
keyLen = db2KeyBufPtr - (char*)keyBuf.ptr();
966
DBUG_PRINT("ha_ibmdb2i::index_read", ("find_flag: %d", find_flag));
968
char readDirection = QMY_NEXT;
972
case HA_READ_AFTER_KEY:
973
doInitialRead(QMY_AFTER_EQUAL, estimatedRows,
974
keyBuf.ptr(), keyLen, partsInUse);
976
case HA_READ_BEFORE_KEY:
977
doInitialRead(QMY_BEFORE_EQUAL, estimatedRows,
978
keyBuf.ptr(), keyLen, partsInUse);
980
case HA_READ_KEY_OR_NEXT:
981
doInitialRead(QMY_AFTER_OR_EQUAL, estimatedRows,
982
keyBuf.ptr(), keyLen, partsInUse);
984
case HA_READ_KEY_OR_PREV:
985
DBUG_ASSERT(0); // This function is unused
986
doInitialRead(QMY_BEFORE_OR_EQUAL, estimatedRows,
987
keyBuf.ptr(), keyLen, partsInUse);
989
case HA_READ_PREFIX_LAST_OR_PREV:
990
doInitialRead(QMY_LAST_PREVIOUS, estimatedRows,
991
keyBuf.ptr(), keyLen, partsInUse);
992
readDirection = QMY_PREVIOUS;
994
case HA_READ_PREFIX_LAST:
995
doInitialRead(QMY_PREFIX_LAST, estimatedRows,
996
keyBuf.ptr(), keyLen, partsInUse);
997
readDirection = QMY_PREVIOUS;
999
case HA_READ_KEY_EXACT:
1000
doInitialRead(QMY_EQUAL, estimatedRows, keyBuf.ptr(), keyLen, partsInUse);
1004
return HA_ERR_GENERIC;
1008
ha_statistic_increment(&SSV::ha_read_key_count);
1009
rc = readFromBuffer(buf, readDirection);
1011
table->status= (rc ? STATUS_NOT_FOUND: 0);
1016
int ha_ibmdb2i::index_next(uchar * buf)
1018
DBUG_ENTER("ha_ibmdb2i::index_next");
1019
ha_statistic_increment(&SSV::ha_read_next_count);
1021
int rc = readFromBuffer(buf, QMY_NEXT);
1023
table->status= (rc ? STATUS_NOT_FOUND: 0);
1028
int ha_ibmdb2i::index_next_same(uchar *buf, const uchar *key, uint keylen)
1030
DBUG_ENTER("ha_ibmdb2i::index_next_same");
1031
ha_statistic_increment(&SSV::ha_read_next_count);
1033
int rc = readFromBuffer(buf, QMY_NEXT_EQUAL);
1035
if (rc == HA_ERR_KEY_NOT_FOUND)
1037
rc = HA_ERR_END_OF_FILE;
1040
table->status= (rc ? STATUS_NOT_FOUND: 0);
1044
int ha_ibmdb2i::index_read_last(uchar * buf, const uchar * key, uint key_len)
1046
DBUG_ENTER("ha_ibmdb2i::index_read_last");
1047
DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));
1052
int ha_ibmdb2i::index_prev(uchar * buf)
1054
DBUG_ENTER("ha_ibmdb2i::index_prev");
1055
ha_statistic_increment(&SSV::ha_read_prev_count);
1057
int rc = readFromBuffer(buf, QMY_PREVIOUS);
1059
table->status= (rc ? STATUS_NOT_FOUND: 0);
1064
int ha_ibmdb2i::index_first(uchar * buf)
1066
DBUG_ENTER("ha_ibmdb2i::index_first");
1068
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
1070
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER,
1071
db2Table->indexFile(active_index),
1076
doInitialRead(QMY_FIRST, DEFAULT_MAX_ROWS_TO_BUFFER);
1077
ha_statistic_increment(&SSV::ha_read_first_count);
1078
rc = readFromBuffer(buf, QMY_NEXT);
1081
table->status= (rc ? STATUS_NOT_FOUND: 0);
1086
int ha_ibmdb2i::index_last(uchar * buf)
1088
DBUG_ENTER("ha_ibmdb2i::index_last");
1090
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
1092
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER,
1093
db2Table->indexFile(active_index),
1098
doInitialRead(QMY_LAST, DEFAULT_MAX_ROWS_TO_BUFFER);
1099
ha_statistic_increment(&SSV::ha_read_last_count);
1100
rc = readFromBuffer(buf, QMY_PREVIOUS);
1103
table->status= (rc ? STATUS_NOT_FOUND: 0);
1108
int ha_ibmdb2i::rnd_init(bool scan)
1110
DBUG_ENTER("ha_ibmdb2i::rnd_init");
1112
int& rc = last_rnd_init_rc;
1116
invalidDataFound=false;
1118
uint32 rowsToBlockOnRead;
1122
rowsToBlockOnRead = 1;
1126
rowsToBlockOnRead = DEFAULT_MAX_ROWS_TO_BUFFER;
1133
// THD* thd = ha_thd();
1134
// if (accessIntent == QMY_UPDATABLE &&
1135
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
1136
// !THDVAR(thd, transaction_unsafe))
1138
// readAccessIntent = QMY_READ_ONLY;
1142
readAccessIntent = accessIntent;
1145
rc = prepReadBuffer(rowsToBlockOnRead, db2Table->dataFile(), readAccessIntent);
1147
if (!rc && accessIntent != QMY_READ_ONLY)
1148
rc = prepWriteBuffer(1, db2Table->dataFile());
1151
doInitialRead(QMY_FIRST, rowsToBlockOnRead);
1157
DBUG_RETURN(0); // MySQL sometimes does not check the return code, causing
1158
// an assert in ha_rnd_end later on if we return a non-zero
1162
int ha_ibmdb2i::rnd_end()
1164
DBUG_ENTER("ha_ibmdb2i::rnd_end");
1166
warnIfInvalidData();
1167
if (likely(activeReadBuf))
1168
activeReadBuf->endRead();
1169
if (last_rnd_init_rc == 0)
1170
releaseActiveHandle();
1171
last_rnd_init_rc = 0;
1176
int32 ha_ibmdb2i::mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs)
1178
DBUG_ASSERT(dataPtr);
1180
my_bitmap_map *old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
1181
my_bitmap_map *old_read_map;
1183
if (unlikely(readAllColumns))
1184
old_read_map = tmp_use_all_columns(table, table->read_set);
1186
resetCharacterConversionBuffers();
1188
my_ptrdiff_t old_ptr= (my_ptrdiff_t) (record - table->record[0]);
1190
for (Field **field = table->field; *field; ++field, ++fieldIndex)
1192
if (unlikely(old_ptr))
1193
(*field)->move_field_offset(old_ptr);
1194
if (nullMapPtr[fieldIndex] == __NULL_VALUE_EBCDIC ||
1195
(!bitmap_is_set(table->read_set, fieldIndex)) ||
1196
(skipLOBs && db2Table->db2Field(fieldIndex).isBlob()))
1198
(*field)->set_null();
1202
(*field)->set_notnull();
1203
convertDB2toMySQL(db2Table->db2Field(fieldIndex), *field, dataPtr);
1205
if (unlikely(old_ptr))
1206
(*field)->move_field_offset(-old_ptr);
1210
if (unlikely(readAllColumns))
1211
tmp_restore_column_map(table->read_set, old_read_map);
1212
dbug_tmp_restore_column_map(table->write_set, old_write_map);
1218
int ha_ibmdb2i::rnd_next(uchar *buf)
1220
DBUG_ENTER("ha_ibmdb2i::rnd_next");
1222
if (unlikely(last_rnd_init_rc)) DBUG_RETURN(last_rnd_init_rc);
1223
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1227
rc = readFromBuffer(buf, QMY_NEXT);
1229
table->status= (rc ? STATUS_NOT_FOUND: 0);
1234
void ha_ibmdb2i::position(const uchar *record)
1236
DBUG_ENTER("ha_ibmdb2i::position");
1237
my_store_ptr(ref, ref_length, currentRRN);
1242
int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos)
1244
DBUG_ENTER("ha_ibmdb2i::rnd_pos");
1245
if (unlikely(last_rnd_init_rc)) DBUG_RETURN( last_rnd_init_rc);
1246
ha_statistic_increment(&SSV::ha_read_rnd_count);
1248
currentRRN = my_get_ptr(pos, ref_length);
1254
if (activeHandle != rrnAssocHandle)
1256
if (activeHandle) releaseActiveHandle();
1257
rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);
1260
if (likely(rc == 0))
1262
rc = prepReadBuffer(1, getFileForActiveHandle(), accessIntent);
1264
if (likely(rc == 0) && accessIntent == QMY_UPDATABLE)
1265
rc = prepWriteBuffer(1, getFileForActiveHandle());
1267
if (likely(rc == 0))
1269
rc = db2i_ileBridge::getBridgeForThread()->readByRRN(activeHandle,
1270
activeReadBuf->ptr(),
1275
if (likely(rc == 0))
1277
rrnAssocHandle = activeHandle;
1278
const char* readBuf = activeReadBuf->getRowN(0);
1279
rc = mungeDB2row(buf, readBuf, readBuf + activeReadBuf->getRowNullOffset(), false);
1280
releaseRowNeeded = TRUE;
1289
int ha_ibmdb2i::info(uint flag)
1291
DBUG_ENTER("ha_ibmdb2i::info");
1293
uint16 infoRequested = 0;
1294
ValidatedPointer<char> rowKeySpcPtr; // Space pointer passed to DB2
1295
uint32 rowKeySpcLen; // Length of space passed to DB2
1296
THD* thd = ha_thd();
1297
int command = thd_sql_command(thd);
1299
if (flag & HA_STATUS_AUTO)
1300
stats.auto_increment_value = (ulonglong) 0;
1302
if (flag & HA_STATUS_ERRKEY)
1304
errkey = lastDupKeyID;
1305
my_store_ptr(dup_ref, ref_length, lastDupKeyRRN);
1308
if (flag & HA_STATUS_TIME)
1310
if ((flag & HA_STATUS_NO_LOCK) &&
1311
ibmdb2i_assume_exclusive_use &&
1313
(share->cachedStats.isInited(lastModTime)))
1314
stats.update_time = share->cachedStats.getUpdateTime();
1316
infoRequested |= lastModTime;
1319
if (flag & HA_STATUS_CONST)
1321
stats.block_size=4096;
1322
infoRequested |= createTime;
1326
infoRequested |= rowsPerKey;
1327
rowKeySpcLen = (table->s->keys) * MAX_DB2_KEY_PARTS * sizeof(uint64);
1328
rowKeySpcPtr.alloc(rowKeySpcLen);
1329
memset(rowKeySpcPtr, 0, rowKeySpcLen); // Clear the allocated space
1333
if (flag & HA_STATUS_VARIABLE)
1335
if ((flag & HA_STATUS_NO_LOCK) &&
1336
(command != SQLCOM_SHOW_TABLE_STATUS) &&
1337
ibmdb2i_assume_exclusive_use &&
1339
(share->cachedStats.isInited(rowCount | deletedRowCount | meanRowLen | ioCount)) &&
1340
(share->cachedStats.getRowCount() >= 2))
1342
stats.records = share->cachedStats.getRowCount();
1343
stats.deleted = share->cachedStats.getDelRowCount();
1344
stats.mean_rec_length = share->cachedStats.getMeanLength();
1345
stats.data_file_length = share->cachedStats.getAugmentedDataLength();
1349
infoRequested |= rowCount | deletedRowCount | meanRowLen;
1350
if (command == SQLCOM_SHOW_TABLE_STATUS)
1351
infoRequested |= objLength;
1353
infoRequested |= ioCount;
1361
DBUG_PRINT("ha_ibmdb2i::info",("Retrieving fresh stats %d", flag));
1364
rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
1371
if ((flag & HA_STATUS_VARIABLE) &&
1372
(command != SQLCOM_SHOW_TABLE_STATUS))
1373
stats.data_file_length = stats.data_file_length * IO_SIZE;
1375
if ((ibmdb2i_assume_exclusive_use) &&
1377
(command != SQLCOM_SHOW_TABLE_STATUS))
1379
if (flag & HA_STATUS_VARIABLE)
1381
share->cachedStats.cacheRowCount(stats.records);
1382
share->cachedStats.cacheDelRowCount(stats.deleted);
1383
share->cachedStats.cacheMeanLength(stats.mean_rec_length);
1384
share->cachedStats.cacheAugmentedDataLength(stats.data_file_length);
1387
if (flag & HA_STATUS_TIME)
1389
share->cachedStats.cacheUpdateTime(stats.update_time);
1393
if (flag & HA_STATUS_CONST)
1395
ulong i; // Loop counter for indexes
1396
ulong j; // Loop counter for key parts
1397
RowKey* rowKeyPtr; // Pointer to 'number of unique rows' array for this index
1399
rowKeyPtr = (RowKey_t*)(void*)rowKeySpcPtr; // Address first array of DB2 row counts
1400
for (i = 0; i < table->s->keys; i++) // Do for each index, including primary
1402
for (j = 0; j < table->key_info[i].key_parts; j++)
1404
table->key_info[i].rec_per_key[j]= rowKeyPtr->RowKeyArray[j];
1406
rowKeyPtr = rowKeyPtr + 1; // Address next array of DB2 row counts
1410
else if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && share)
1412
// If we couldn't retrieve the info because the object was locked,
1413
// we'll do our best by returning the most recently cached data.
1414
if ((infoRequested & rowCount) &&
1415
share->cachedStats.isInited(rowCount))
1416
stats.records = share->cachedStats.getRowCount();
1417
if ((infoRequested & deletedRowCount) &&
1418
share->cachedStats.isInited(deletedRowCount))
1419
stats.deleted = share->cachedStats.getDelRowCount();
1420
if ((infoRequested & meanRowLen) &&
1421
share->cachedStats.isInited(meanRowLen))
1422
stats.mean_rec_length = share->cachedStats.getMeanLength();
1423
if ((infoRequested & lastModTime) &&
1424
share->cachedStats.isInited(lastModTime))
1425
stats.update_time = share->cachedStats.getUpdateTime();
1435
ha_rows ha_ibmdb2i::records()
1437
DBUG_ENTER("ha_ibmdb2i::records");
1439
rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
1445
if (rc == HA_ERR_LOCK_WAIT_TIMEOUT &&
1447
(share->cachedStats.isInited(rowCount)))
1448
DBUG_RETURN(share->cachedStats.getRowCount());
1450
DBUG_RETURN(HA_POS_ERROR);
1454
share->cachedStats.cacheRowCount(stats.records);
1457
DBUG_RETURN(stats.records);
1461
int ha_ibmdb2i::extra(enum ha_extra_function operation)
1463
DBUG_ENTER("ha_ibmdb2i::extra");
1467
// Can these first five flags be replaced by attending to HA_EXTRA_WRITE_CACHE?
1468
case HA_EXTRA_NO_IGNORE_DUP_KEY:
1469
case HA_EXTRA_WRITE_CANNOT_REPLACE:
1471
returnDupKeysImmediately = false;
1472
onDupUpdate = false;
1475
case HA_EXTRA_INSERT_WITH_UPDATE:
1477
returnDupKeysImmediately = true;
1481
case HA_EXTRA_IGNORE_DUP_KEY:
1482
case HA_EXTRA_WRITE_CAN_REPLACE:
1483
returnDupKeysImmediately = true;
1485
case HA_EXTRA_FLUSH_CACHE:
1486
if (outstanding_start_bulk_insert)
1497
The DB2 storage engine will ignore a MySQL generated value and will generate
1498
a new value in SLIC. We arbitrarily set first_value to 1, and set the
1499
interval to infinity for better performance on multi-row inserts.
1501
void ha_ibmdb2i::get_auto_increment(ulonglong offset, ulonglong increment,
1502
ulonglong nb_desired_values,
1503
ulonglong *first_value,
1504
ulonglong *nb_reserved_values)
1506
DBUG_ENTER("ha_ibmdb2i::get_auto_increment");
1508
*nb_reserved_values= ULONGLONG_MAX;
1513
void ha_ibmdb2i::update_create_info(HA_CREATE_INFO *create_info)
1515
DBUG_ENTER("ha_ibmdb2i::update_create_info");
1517
if ((!(create_info->used_fields & HA_CREATE_USED_AUTO)) &&
1518
(table->found_next_number_field != NULL))
1522
create_info->auto_increment_value= 1;
1524
ha_rows rowCount = records();
1528
create_info->auto_increment_value = db2Table->getStartId();
1531
else if (rowCount == HA_POS_ERROR)
1536
getNextIdVal(&create_info->auto_increment_value);
1542
int ha_ibmdb2i::getNextIdVal(ulonglong *value)
1544
DBUG_ENTER("ha_ibmdb2i::getNextIdVal");
1546
char queryBuffer[MAX_DB2_COLNAME_LENGTH + MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
1547
strcpy(queryBuffer, " SELECT CAST(MAX( ");
1548
convertMySQLNameToDB2Name(table->found_next_number_field->field_name,
1549
strend(queryBuffer),
1550
MAX_DB2_COLNAME_LENGTH+1);
1551
strcat(queryBuffer, ") AS BIGINT) FROM ");
1552
db2Table->getDB2QualifiedName(strend(queryBuffer));
1553
DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
1555
SqlStatementStream sqlStream(queryBuffer);
1556
DBUG_PRINT("ha_ibmdb2i::getNextIdVal", ("Sent to DB2: %s",queryBuffer));
1559
FILE_HANDLE fileHandle2;
1560
uint32 db2RowDataLen2;
1561
rc = bridge()->prepOpen(sqlStream.getPtrToData(),
1564
if (likely(rc == 0))
1566
IOReadBuffer rowBuffer(1, db2RowDataLen2);
1567
rc = bridge()->read(fileHandle2,
1573
if (likely(rc == 0))
1575
/* This check is here for the case where the table is not empty,
1576
but the auto_increment starting value has been changed since
1577
the last record was written. */
1579
longlong maxIdVal = *(longlong*)(rowBuffer.getRowN(0));
1580
if ((maxIdVal + 1) > db2Table->getStartId())
1581
*value = maxIdVal + 1;
1583
*value = db2Table->getStartId();
1586
bridge()->deallocateFile(fileHandle2);
1593
Updates index cardinalities.
1595
int ha_ibmdb2i::analyze(THD* thd, HA_CHECK_OPT *check_opt)
1597
DBUG_ENTER("ha_ibmdb2i::analyze");
1598
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
1602
int ha_ibmdb2i::optimize(THD* thd, HA_CHECK_OPT *check_opt)
1604
DBUG_ENTER("ha_ibmdb2i::optimize");
1608
if (unlikely(records() == 0))
1609
DBUG_RETURN(0); // DB2 doesn't like to reorganize a table with no data.
1611
quiesceAllFileHandles();
1613
int32 rc = bridge()->optimizeTable(db2Table->dataFile()->getMasterDefnHandle());
1614
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
1622
Determines if an ALTER TABLE is allowed to switch the storage engine
1623
for this table. If the table has a foreign key or is referenced by a
1624
foreign key, then it cannot be switched.
1626
bool ha_ibmdb2i::can_switch_engines(void)
1627
/*=================================*/
1629
DBUG_ENTER("ha_ibmdb2i::can_switch_engines");
1632
FILE_HANDLE queryFile = 0;
1633
uint32 resultRowLen;
1635
bool can_switch = FALSE; // 1 if changing storage engine is allowed
1637
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
1638
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
1641
query.append(STRING_WITH_LEN(" SELECT COUNT(*) FROM SYSIBM.SQLFOREIGNKEYS WHERE ((PKTABLE_SCHEM = '"));
1642
query.append(libName+1, strlen(libName)-2); // Remove quotes from parent schema name
1643
query.append(STRING_WITH_LEN("' AND PKTABLE_NAME = '"));
1644
query.append(fileName+1,strlen(fileName)-2); // Remove quotes from file name
1645
query.append(STRING_WITH_LEN("') OR (FKTABLE_SCHEM = '"));
1646
query.append(libName+1,strlen(libName)-2); // Remove quotes from child schema
1647
query.append(STRING_WITH_LEN("' AND FKTABLE_NAME = '"));
1648
query.append(fileName+1,strlen(fileName)-2); // Remove quotes from child name
1649
query.append(STRING_WITH_LEN("'))"));
1651
SqlStatementStream sqlStream(query);
1653
rc = bridge()->prepOpen(sqlStream.getPtrToData(),
1658
IOReadBuffer rowBuffer(1, resultRowLen);
1660
rc = bridge()->read(queryFile,
1667
count = *(uint*)(rowBuffer.getRowN(0));
1672
bridge()->deallocateFile(queryFile);
1674
DBUG_RETURN(can_switch);
1679
bool ha_ibmdb2i::check_if_incompatible_data(HA_CREATE_INFO *info,
1682
DBUG_ENTER("ha_ibmdb2i::check_if_incompatible_data");
1684
/* Check that auto_increment value and field definitions were
1686
if ((info->used_fields & HA_CREATE_USED_AUTO &&
1687
info->auto_increment_value != 0) ||
1688
table_changes != IS_EQUAL_YES)
1689
DBUG_RETURN(COMPATIBLE_DATA_NO);
1690
/* Check if any fields were renamed. */
1691
for (i= 0; i < table->s->fields; i++)
1693
Field *field= table->field[i];
1694
if (field->flags & FIELD_IS_RENAMED)
1696
DBUG_PRINT("info", ("Field has been renamed, copy table"));
1697
DBUG_RETURN(COMPATIBLE_DATA_NO);
1700
DBUG_RETURN(COMPATIBLE_DATA_YES);
1703
int ha_ibmdb2i::reset_auto_increment(ulonglong value)
1705
DBUG_ENTER("ha_ibmdb2i::reset_auto_increment");
1709
quiesceAllFileHandles();
1711
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
1712
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
1715
query.append(STRING_WITH_LEN(" ALTER TABLE "));
1716
query.append(libName);
1718
query.append(fileName);
1719
query.append(STRING_WITH_LEN(" ALTER COLUMN "));
1720
char colName[MAX_DB2_COLNAME_LENGTH+1];
1721
convertMySQLNameToDB2Name(table->found_next_number_field->field_name,
1724
query.append(colName);
1726
char restart_value[22];
1727
CHARSET_INFO *cs= &my_charset_bin;
1728
uint len = (uint)(cs->cset->longlong10_to_str)(cs,restart_value,sizeof(restart_value), 10, value);
1729
restart_value[len] = 0;
1731
query.append(STRING_WITH_LEN(" RESTART WITH "));
1732
query.append(restart_value);
1734
SqlStatementStream sqlStream(query);
1735
DBUG_PRINT("ha_ibmdb2i::reset_auto_increment", ("Sent to DB2: %s",query.c_ptr()));
1737
rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
1738
sqlStream.getStatementCount(),
1739
QMY_NONE, //getCommitLevel(),
1745
db2Table->updateStartId(value);
1753
This function receives an error code that was previously set by the handler.
1754
It returns to MySQL the error string associated with that error.
1756
bool ha_ibmdb2i::get_error_message(int error, String *buf)
1758
DBUG_ENTER("ha_ibmdb2i::get_error_message");
1759
if ((error >= DB2I_FIRST_ERR && error <= DB2I_LAST_ERR) ||
1760
(error >= QMY_ERR_MIN && error <= QMY_ERR_MAX))
1762
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(ha_thd());
1763
char* errMsg = bridge->getErrorStorage();
1764
buf->copy(errMsg, strlen(errMsg),system_charset_info);
1765
bridge->freeErrorStorage();
1771
int ha_ibmdb2i::delete_all_rows()
1773
DBUG_ENTER("ha_ibmdb2i::delete_all_rows");
1775
char queryBuffer[MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
1776
strcpy(queryBuffer, " DELETE FROM ");
1777
db2Table->getDB2QualifiedName(strend(queryBuffer));
1778
DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
1780
SqlStatementStream sqlStream(queryBuffer);
1781
DBUG_PRINT("ha_ibmdb2i::delete_all_rows", ("Sent to DB2: %s",queryBuffer));
1782
rc = bridge()->execSQL(sqlStream.getPtrToData(),
1783
sqlStream.getStatementCount(),
1790
/* If this method was called on behalf of a TRUNCATE TABLE statement, and if */
1791
/* the table has an auto_increment field, then reset the starting value for */
1792
/* the auto_increment field to 1.
1794
if (rc == 0 && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE &&
1795
table->found_next_number_field )
1796
rc = reset_auto_increment(1);
1798
invalidateCachedStats();
1804
int ha_ibmdb2i::external_lock(THD *thd, int lock_type)
1808
DBUG_ENTER("ha_ibmdb2i::external_lock");
1809
DBUG_PRINT("ha_ibmdb2i::external_lock",("Lock type: %d", lock_type));
1811
if (lock_type == F_RDLCK)
1812
accessIntent = QMY_READ_ONLY;
1813
else if (lock_type == F_WRLCK)
1814
accessIntent = QMY_UPDATABLE;
1817
int command = thd_sql_command(thd);
1819
if (!THDVAR(thd,transaction_unsafe))
1821
if (lock_type != F_UNLCK)
1823
if (autoCommitIsOn(thd) == QMY_YES)
1825
trans_register_ha(thd, FALSE, ibmdb2i_hton);
1829
trans_register_ha(thd, TRUE, ibmdb2i_hton);
1830
if (likely(command != SQLCOM_CREATE_TABLE))
1832
trans_register_ha(thd, FALSE, ibmdb2i_hton);
1833
bridge()->beginStmtTx();
1839
if (command == SQLCOM_LOCK_TABLES ||
1840
command == SQLCOM_ALTER_TABLE ||
1841
command == SQLCOM_UNLOCK_TABLES ||
1842
(accessIntent == QMY_UPDATABLE &&
1843
(command == SQLCOM_UPDATE ||
1844
command == SQLCOM_UPDATE_MULTI ||
1845
command == SQLCOM_DELETE ||
1846
command == SQLCOM_DELETE_MULTI ||
1847
command == SQLCOM_REPLACE ||
1848
command == SQLCOM_REPLACE_SELECT) &&
1849
getCommitLevel(thd) == QMY_NONE))
1853
if (lock_type == F_UNLCK)
1855
action = QMY_UNLOCK;
1856
type = accessIntent == QMY_READ_ONLY ? QMY_LSRD : QMY_LENR;
1861
type = lock_type == F_RDLCK ? QMY_LSRD : QMY_LENR;
1864
DBUG_PRINT("ha_ibmdb2i::external_lock",("%socking table", action==QMY_LOCK ? "L" : "Unl"));
1867
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
1869
rc = bridge()->lockObj(dataHandle,
1873
(command == SQLCOM_LOCK_TABLES ? QMY_NO : QMY_YES));
1877
// Cache this away so we don't have to access it on each row operation
1878
cachedZeroDateOption = (enum_ZeroDate)THDVAR(thd, compat_opt_allow_zero_date_vals);
1884
THR_LOCK_DATA **ha_ibmdb2i::store_lock(THD *thd,
1886
enum thr_lock_type lock_type)
1888
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
1890
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
1891
lock_type <= TL_WRITE) && !(thd->in_lock_tables && thd_sql_command(thd) == SQLCOM_LOCK_TABLES))
1892
lock_type= TL_WRITE_ALLOW_WRITE;
1893
lock.type=lock_type;
1900
int ha_ibmdb2i::delete_table(const char *name)
1902
DBUG_ENTER("ha_ibmdb2i::delete_table");
1903
THD* thd = ha_thd();
1904
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(thd);
1906
char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
1907
db2i_table::getDB2QualifiedNameFromPath(name, db2Name);
1910
query.append(STRING_WITH_LEN(" DROP TABLE "));
1911
query.append(db2Name);
1913
if (thd_sql_command(thd) == SQLCOM_DROP_TABLE &&
1914
thd->lex->drop_mode == DROP_RESTRICT)
1915
query.append(STRING_WITH_LEN(" RESTRICT "));
1916
DBUG_PRINT("ha_ibmdb2i::delete_table", ("Sent to DB2: %s",query.c_ptr()));
1918
SqlStatementStream sqlStream(query);
1920
db2i_table::getDB2LibNameFromPath(name, db2Name);
1921
bool isTemporary = (strcmp(db2Name, DB2I_TEMP_TABLE_SCHEMA) == 0 ? TRUE : FALSE);
1923
int rc = bridge->execSQL(sqlStream.getPtrToData(),
1924
sqlStream.getStatementCount(),
1925
(isTemporary ? QMY_NONE : getCommitLevel(thd)),
1930
if (rc == HA_ERR_NO_SUCH_TABLE)
1932
warning(thd, DB2I_ERR_TABLE_NOT_FOUND, name);
1938
db2i_table::deleteAssocFiles(name);
1941
FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
1944
bridge->deallocateFile(savedHandle, TRUE);
1946
if (free_share(share))
1948
savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
1956
int ha_ibmdb2i::rename_table(const char * from, const char * to)
1958
DBUG_ENTER("ha_ibmdb2i::rename_table ");
1960
char db2FromFileName[MAX_DB2_FILENAME_LENGTH + 1];
1961
char db2ToFileName[MAX_DB2_FILENAME_LENGTH+1];
1962
char db2FromLibName[MAX_DB2_SCHEMANAME_LENGTH+1];
1963
char db2ToLibName[MAX_DB2_SCHEMANAME_LENGTH+1];
1965
db2i_table::getDB2LibNameFromPath(from, db2FromLibName);
1966
db2i_table::getDB2LibNameFromPath(to, db2ToLibName);
1968
if (strcmp(db2FromLibName, db2ToLibName) != 0 )
1970
getErrTxt(DB2I_ERR_RENAME_MOVE,from,to);
1971
DBUG_RETURN(DB2I_ERR_RENAME_MOVE);
1974
db2i_table::getDB2FileNameFromPath(from, db2FromFileName, db2i_table::ASCII_NATIVE);
1975
db2i_table::getDB2FileNameFromPath(to, db2ToFileName);
1977
char escapedFromFileName[2 * MAX_DB2_FILENAME_LENGTH + 1];
1983
escapedFromFileName[o++] = db2FromFileName[i];
1984
if (db2FromFileName[i] == '+')
1985
escapedFromFileName[o++] = '+';
1986
} while (db2FromFileName[++i]);
1987
escapedFromFileName[o-1] = 0;
1992
char queryBuffer[sizeof(db2FromLibName) + 2 * sizeof(db2FromFileName) + 256];
1993
SafeString selectQuery(queryBuffer, sizeof(queryBuffer));
1994
selectQuery.strncat(STRING_WITH_LEN("SELECT CAST(INDEX_NAME AS VARCHAR(128) CCSID 1208) FROM QSYS2.SYSINDEXES WHERE INDEX_NAME LIKE '%+_+_+_%"));
1995
selectQuery.strcat(escapedFromFileName);
1996
selectQuery.strncat(STRING_WITH_LEN("' ESCAPE '+' AND TABLE_NAME='"));
1997
selectQuery.strncat(db2FromFileName+1, strlen(db2FromFileName)-2);
1998
selectQuery.strncat(STRING_WITH_LEN("' AND TABLE_SCHEMA='"));
1999
selectQuery.strncat(db2FromLibName+1, strlen(db2FromLibName)-2);
2000
selectQuery.strcat('\'');
2001
DBUG_ASSERT(!selectQuery.overflowed());
2003
SqlStatementStream indexQuery(selectQuery.ptr());
2005
FILE_HANDLE queryFile = 0;
2006
uint32 resultRowLen;
2009
rc = bridge()->prepOpen(indexQuery.getPtrToData(),
2016
IOReadBuffer rowBuffer(1, resultRowLen);
2018
int tableNameLen = strlen(db2FromFileName) - 2;
2020
SqlStatementStream renameQuery(64);
2026
rc = bridge()->read(queryFile,
2034
const char* rowData = rowBuffer.getRowN(0);
2035
char indexFileName[MAX_DB2_FILENAME_LENGTH];
2036
memset(indexFileName, 0, sizeof(indexFileName));
2038
uint16 fileNameLen = *(uint16*)(rowData);
2039
strncpy(indexFileName, rowData + sizeof(uint16), fileNameLen);
2041
int bytesToRetain = fileNameLen - tableNameLen;
2042
if (bytesToRetain <= 0)
2043
/* We can't handle index names in which the MySQL index name and
2044
the table name together are longer than the max index name. */
2046
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
2047
DBUG_RETURN(DB2I_ERR_INVALID_NAME);
2049
char indexName[MAX_DB2_FILENAME_LENGTH];
2050
memset(indexName, 0, sizeof(indexName));
2056
char db2IndexName[MAX_DB2_FILENAME_LENGTH+1];
2058
convertMySQLNameToDB2Name(indexFileName, db2IndexName, sizeof(db2IndexName));
2060
query.append(STRING_WITH_LEN("RENAME INDEX "));
2061
query.append(db2FromLibName);
2063
query.append(db2IndexName);
2064
query.append(STRING_WITH_LEN(" TO "));
2065
if (db2i_table::appendQualifiedIndexFileName(indexName, db2ToFileName, query, db2i_table::ASCII_SQL, typeNone) == -1)
2067
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
2068
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
2070
renameQuery.addStatement(query);
2071
DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
2077
bridge()->deallocateFile(queryFile);
2079
if (rc != HA_ERR_END_OF_FILE)
2082
char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
2084
/* Rename the table */
2086
query.append(STRING_WITH_LEN(" RENAME TABLE "));
2087
db2i_table::getDB2QualifiedNameFromPath(from, db2Name);
2088
query.append(db2Name);
2089
query.append(STRING_WITH_LEN(" TO "));
2090
query.append(db2ToFileName);
2091
DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
2092
renameQuery.addStatement(query);
2093
rc = bridge()->execSQL(renameQuery.getPtrToData(),
2094
renameQuery.getStatementCount(),
2098
db2i_table::renameAssocFiles(from, to);
2104
int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
2105
HA_CREATE_INFO *create_info)
2107
DBUG_ENTER("ha_ibmdb2i::create");
2110
char fileSortSequence[11] = "*HEX";
2111
char fileSortSequenceLibrary[11] = "";
2112
char fileSortSequenceType = ' ';
2113
char libName[MAX_DB2_SCHEMANAME_LENGTH+1];
2114
char fileName[MAX_DB2_FILENAME_LENGTH+1];
2115
char colName[MAX_DB2_COLNAME_LENGTH+1];
2117
ulong auto_inc_value;
2119
db2i_table::getDB2LibNameFromPath(name, libName);
2120
db2i_table::getDB2FileNameFromPath(name, fileName);
2122
if (osVersion.v < 6)
2124
if (strlen(libName) >
2125
MAX_DB2_V5R4_LIBNAME_LENGTH + (isUpperOrQuote(system_charset_info, libName) ? 2 : 0))
2127
getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V5R4_LIBNAME_LENGTH);
2128
DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
2131
else if (strlen(libName) > MAX_DB2_V6R1_LIBNAME_LENGTH)
2133
getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V6R1_LIBNAME_LENGTH);
2134
DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
2139
if (strcmp(libName, DB2I_TEMP_TABLE_SCHEMA))
2141
query.append(STRING_WITH_LEN("CREATE TABLE "));
2142
query.append(libName);
2144
query.append(fileName);
2145
isTemporary = FALSE;
2149
query.append(STRING_WITH_LEN("DECLARE GLOBAL TEMPORARY TABLE "));
2150
query.append(fileName);
2153
query.append(STRING_WITH_LEN(" ("));
2155
THD* thd = ha_thd();
2156
enum_TimeFormat timeFormat = (enum_TimeFormat)(THDVAR(thd, compat_opt_time_as_duration));
2157
enum_YearFormat yearFormat = (enum_YearFormat)(THDVAR(thd, compat_opt_year_as_int));
2158
enum_BlobMapping blobMapping = (enum_BlobMapping)(THDVAR(thd, compat_opt_blob_cols));
2159
enum_ZeroDate zeroDate = (enum_ZeroDate)(THDVAR(thd, compat_opt_allow_zero_date_vals));
2160
bool propagateDefaults = THDVAR(thd, propagate_default_col_vals);
2163
for (field= table_arg->field; *field; field++)
2165
if ( field != table_arg->field ) // Not the first one
2166
query.append(STRING_WITH_LEN(" , "));
2168
if (!convertMySQLNameToDB2Name((*field)->field_name, colName, sizeof(colName)))
2170
getErrTxt(DB2I_ERR_INVALID_NAME,"field",(*field)->field_name);
2171
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
2174
query.append(colName);
2177
if (rc = getFieldTypeMapping(*field,
2186
if ( (*field)->flags & NOT_NULL_FLAG )
2188
query.append(STRING_WITH_LEN(" NOT NULL "));
2190
if ( (*field)->flags & AUTO_INCREMENT_FLAG )
2192
#ifdef WITH_PARTITION_STORAGE_ENGINE
2193
if (table_arg->part_info)
2195
getErrTxt(DB2I_ERR_PART_AUTOINC);
2196
DBUG_RETURN(DB2I_ERR_PART_AUTOINC);
2199
query.append(STRING_WITH_LEN(" GENERATED BY DEFAULT AS IDENTITY ") );
2200
if (create_info->auto_increment_value != 0)
2202
/* Query was ALTER TABLE...AUTO_INCREMENT = x; or
2203
CREATE TABLE ...AUTO_INCREMENT = x; Set the starting
2204
value for the auto_increment column. */
2205
char stringValue[22];
2206
CHARSET_INFO *cs= &my_charset_bin;
2207
uint len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, create_info->auto_increment_value);
2208
stringValue[len] = 0;
2209
query.append(STRING_WITH_LEN(" (START WITH "));
2210
query.append(stringValue);
2212
uint64 maxValue=maxValueForField(*field);
2216
len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, maxValue);
2217
stringValue[len] = 0;
2218
query.append(STRING_WITH_LEN(" MAXVALUE "));
2219
query.append(stringValue);
2222
query.append(STRING_WITH_LEN(") "));
2228
bool primaryHasStringField = false;
2230
if (table_arg->s->primary_key != MAX_KEY && !isTemporary)
2232
KEY& curKey = table_arg->key_info[table_arg->s->primary_key];
2233
query.append(STRING_WITH_LEN(", PRIMARY KEY( "));
2234
for (int j = 0; j < curKey.key_parts; ++j)
2238
query.append( STRING_WITH_LEN(" , ") );
2240
Field* field = curKey.key_part[j].field;
2241
convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
2242
query.append(colName);
2243
enum_field_types type = field->real_type();
2244
if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_BLOB ||
2245
type == MYSQL_TYPE_STRING)
2247
rc = updateAssociatedSortSequence(field->charset(),
2248
&fileSortSequenceType,
2250
fileSortSequenceLibrary);
2251
if (rc) DBUG_RETURN (rc);
2252
primaryHasStringField = true;
2255
query.append(STRING_WITH_LEN(" ) "));
2258
rc = buildDB2ConstraintString(thd->lex,
2262
&fileSortSequenceType,
2264
fileSortSequenceLibrary);
2265
if (rc) DBUG_RETURN (rc);
2267
query.append(STRING_WITH_LEN(" ) "));
2270
query.append(STRING_WITH_LEN(" ON COMMIT PRESERVE ROWS "));
2272
DBUG_PRINT("ha_ibmdb2i::create", ("Sent to DB2: %s",query.c_ptr()));
2273
SqlStatementStream sqlStream(query.length());
2274
sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
2276
for (uint i = 0; i < table_arg->s->keys; ++i)
2278
if (i != table_arg->s->primary_key || isTemporary)
2280
rc = buildCreateIndexStatement(sqlStream,
2281
table_arg->key_info[i],
2285
if (rc) DBUG_RETURN (rc);
2289
bool noCommit = isTemporary || ((!autoCommitIsOn(thd)) && (thd_sql_command(thd) == SQLCOM_ALTER_TABLE));
2293
// if (THDVAR(thd, discovery_mode) == 1)
2294
// bridge()->expectErrors(QMY_ERR_TABLE_EXISTS);
2296
rc = bridge()->execSQL(sqlStream.getPtrToData(),
2297
sqlStream.getStatementCount(),
2298
(isTemporary ? QMY_NONE : getCommitLevel(thd)),
2303
if (unlikely(rc == QMY_ERR_MSGID) &&
2304
memcmp(bridge()->getErrorMsgID(), DB2I_SQL0350, 7) == 0)
2306
my_error(ER_BLOB_USED_AS_KEY, MYF(0), "*unknown*");
2307
rc = ER_BLOB_USED_AS_KEY;
2309
/* else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) &&
2310
THDVAR(thd, discovery_mode) == 1)
2312
db2i_table* temp = new db2i_table(table_arg->s, name);
2313
int32 rc = temp->fastInitForCreate(name);
2317
warning(thd, DB2I_ERR_WARN_CREATE_DISCOVER);
2323
if (!rc && !isTemporary)
2325
db2i_table* temp = new db2i_table(table_arg->s, name);
2326
int32 rc = temp->fastInitForCreate(name);
2338
Add an index on-line to a table. This method is called on behalf of
2339
a CREATE INDEX or ALTER TABLE statement.
2340
It is implemented via a composed DDL statement passed to DB2.
2342
int ha_ibmdb2i::add_index(TABLE *table_arg,
2346
DBUG_ENTER("ha_ibmdb2i::add_index");
2349
SqlStatementStream sqlStream(256);
2350
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
2351
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
2353
quiesceAllFileHandles();
2355
uint primaryKey = MAX_KEY;
2356
if (table_arg->s->primary_key >= MAX_KEY && !db2Table->isTemporary())
2358
for (int i = 0; i < num_of_keys; ++i)
2360
if (strcmp(key_info[i].name, "PRIMARY") == 0)
2365
else if (primaryKey == MAX_KEY &&
2366
key_info[i].flags & HA_NOSAME)
2369
for (int j=0 ; j < key_info[i].key_parts ;j++)
2371
uint fieldnr= key_info[i].key_part[j].fieldnr;
2372
if (table_arg->s->field[fieldnr]->null_ptr ||
2373
table_arg->s->field[fieldnr]->key_length() !=
2374
key_info[i].key_part[j].length)
2376
primaryKey = MAX_KEY;
2385
for (int i = 0; i < num_of_keys; ++i)
2387
KEY& curKey= key_info[i];
2388
rc = buildCreateIndexStatement(sqlStream,
2393
if (rc) DBUG_RETURN (rc);
2396
rc = bridge()->execSQL(sqlStream.getPtrToData(),
2397
sqlStream.getStatementCount(),
2404
/* Handle the case where a unique index is being created but an error occurs
2405
because the file contains duplicate key values. */
2406
if (rc == ER_DUP_ENTRY)
2407
print_keydup_error(MAX_KEY,ER(ER_DUP_ENTRY_WITH_KEY_NAME));
2414
Drop an index on-line from a table. This method is called on behalf of
2415
a DROP INDEX or ALTER TABLE statement.
2416
It is implemented via a composed DDL statement passed to DB2.
2418
int ha_ibmdb2i::prepare_drop_index(TABLE *table_arg,
2419
uint *key_num, uint num_of_keys)
2421
DBUG_ENTER("ha_ibmdb2i::prepare_drop_index");
2425
SqlStatementStream sqlStream(64 * num_of_keys);
2426
SqlStatementStream shadowStream(64 * num_of_keys);
2428
quiesceAllFileHandles();
2430
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
2431
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
2433
while (i < num_of_keys)
2436
DBUG_PRINT("info", ("ha_ibmdb2i::prepare_drop_index %u", key_num[i]));
2437
KEY& curKey= table_arg->key_info[key_num[i]];
2438
if (key_num[i] == table->s->primary_key && !db2Table->isTemporary())
2440
query.append(STRING_WITH_LEN("ALTER TABLE "));
2441
query.append(libName);
2442
query.append(STRING_WITH_LEN("."));
2443
query.append(fileName);
2444
query.append(STRING_WITH_LEN(" DROP PRIMARY KEY"));
2448
query.append(STRING_WITH_LEN("DROP INDEX "));
2449
query.append(libName);
2450
query.append(STRING_WITH_LEN("."));
2451
db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query);
2453
DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
2454
sqlStream.addStatement(query);
2457
query.append(STRING_WITH_LEN("DROP INDEX "));
2458
query.append(libName);
2459
query.append(STRING_WITH_LEN("."));
2460
db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query, db2i_table::ASCII_SQL, typeHex);
2462
DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
2463
shadowStream.addStatement(query);
2468
rc = bridge()->execSQL(sqlStream.getPtrToData(),
2469
sqlStream.getStatementCount(),
2477
bridge()->execSQL(shadowStream.getPtrToData(),
2478
shadowStream.getStatementCount(),
2486
ha_ibmdb2i::unlock_row()
2488
DBUG_ENTER("ha_ibmdb2i::unlock_row");
2493
ha_ibmdb2i::index_end()
2495
DBUG_ENTER("ha_ibmdb2i::index_end");
2496
warnIfInvalidData();
2497
last_index_init_rc = 0;
2498
if (likely(activeReadBuf))
2499
activeReadBuf->endRead();
2500
if (likely(!last_index_init_rc))
2501
releaseIndexFile(active_index);
2502
active_index= MAX_KEY;
2506
int ha_ibmdb2i::doCommit(handlerton *hton, THD *thd, bool all)
2508
if (!THDVAR(thd, transaction_unsafe))
2510
if (all || autoCommitIsOn(thd))
2512
DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing all"));
2513
return (db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_COMMIT));
2517
DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing stmt"));
2518
return (db2i_ileBridge::getBridgeForThread(thd)->commitStmtTx());
2526
int ha_ibmdb2i::doRollback(handlerton *hton, THD *thd, bool all)
2528
if (!THDVAR(thd,transaction_unsafe))
2530
if (all || autoCommitIsOn(thd))
2532
DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back all"));
2533
return ( db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_ROLLBACK));
2537
DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back stmt"));
2538
return (db2i_ileBridge::getBridgeForThread(thd)->rollbackStmtTx());
2545
void ha_ibmdb2i::start_bulk_insert(ha_rows rows)
2547
DBUG_ENTER("ha_ibmdb2i::start_bulk_insert");
2548
DBUG_PRINT("ha_ibmdb2i::start_bulk_insert",("Rows hinted %d", rows));
2550
THD* thd = ha_thd();
2551
int command = thd_sql_command(thd);
2553
if (db2Table->hasBlobs() ||
2554
(command == SQLCOM_REPLACE || command == SQLCOM_REPLACE_SELECT))
2557
rows = DEFAULT_MAX_ROWS_TO_BUFFER; // Shoot the moon
2559
// If we're doing a multi-row insert, binlogging is active, and the table has an
2560
// auto_increment column, then we'll attempt to lock the file while we perform a 'fast path' blocked
2561
// insert. If we can't get the lock, then we'll do a row-by-row 'slow path' insert instead. The reason is
2562
// because the MI generates the auto_increment (identity value), and if we can't lock the file,
2563
// then we can't predetermine what that value will be for insertion into the MySQL write buffer.
2565
if ((rows > 1) && // Multi-row insert
2566
(thd->options & OPTION_BIN_LOG) && // Binlogging is on
2567
(table->found_next_number_field)) // Table has an auto_increment column
2570
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
2572
rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LEAR, QMY_YES);
2573
if (rc==0) // Got the lock
2575
autoIncLockAcquired = TRUE;
2576
got_auto_inc_values = FALSE;
2578
else // Didn't get the lock
2579
rows = 1; // No problem, but don't block inserts
2582
if (activeHandle == 0)
2584
last_start_bulk_insert_rc = useDataFile();
2585
if (last_start_bulk_insert_rc == 0)
2586
last_start_bulk_insert_rc = prepWriteBuffer(rows, db2Table->dataFile());
2589
if (last_start_bulk_insert_rc == 0)
2590
outstanding_start_bulk_insert = true;
2593
if (autoIncLockAcquired == TRUE)
2595
bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
2596
autoIncLockAcquired = FALSE;
2604
int ha_ibmdb2i::end_bulk_insert()
2606
DBUG_ENTER("ha_ibmdb2i::end_bulk_insert");
2609
if (outstanding_start_bulk_insert)
2611
rc = finishBulkInsert();
2620
int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent)
2622
DBUG_ENTER("ha_ibmdb2i::prepReadBuffer");
2623
DBUG_ASSERT(rowsToRead > 0);
2625
THD* thd = ha_thd();
2626
char cmtLvl = getCommitLevel(thd);
2628
const db2i_file::RowFormat* format;
2629
int rc = file->obtainRowFormat(activeHandle, intent, cmtLvl, &format);
2631
if (unlikely(rc)) DBUG_RETURN(rc);
2633
if (lobFieldsRequested())
2635
forceSingleRowRead = true;
2639
rowsToRead = min(stats.records+1,min(rowsToRead, DEFAULT_MAX_ROWS_TO_BUFFER));
2641
uint bufSize = min((format->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size));
2642
multiRowReadBuf.allocBuf(format->readRowLen, format->readRowNullOffset, bufSize);
2643
activeReadBuf = &multiRowReadBuf;
2645
if (db2Table->hasBlobs())
2647
if (!blobReadBuffers)
2648
blobReadBuffers = new BlobCollection(db2Table, THDVAR(thd, lob_alloc_size));
2649
rc = prepareReadBufferForLobs();
2650
if (rc) DBUG_RETURN(rc);
2653
// if (accessIntent == QMY_UPDATABLE &&
2654
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
2655
// !THDVAR(thd, transaction_unsafe))
2656
// activeReadBuf->update(QMY_READ_ONLY, &releaseRowNeeded, QMY_REPEATABLE_READ);
2658
activeReadBuf->update(intent, &releaseRowNeeded, cmtLvl);
2664
int ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file)
2666
DBUG_ENTER("ha_ibmdb2i::prepWriteBuffer");
2667
DBUG_ASSERT(accessIntent == QMY_UPDATABLE && rowsToWrite > 0);
2669
const db2i_file::RowFormat* format;
2670
int rc = file->obtainRowFormat(activeHandle,
2672
getCommitLevel(ha_thd()),
2675
if (unlikely(rc)) DBUG_RETURN(rc);
2677
rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER);
2679
uint bufSize = min((format->writeRowLen * rowsToWrite), THDVAR(ha_thd(), max_write_buffer_size));
2680
multiRowWriteBuf.allocBuf(format->writeRowLen, format->writeRowNullOffset, bufSize);
2681
activeWriteBuf = &multiRowWriteBuf;
2683
if (!blobWriteBuffers && db2Table->hasBlobs())
2685
blobWriteBuffers = new ValidatedPointer<char>[db2Table->getBlobCount()];
2691
int ha_ibmdb2i::flushWrite(FILE_HANDLE fileHandle, uchar* buf )
2693
DBUG_ENTER("ha_ibmdb2i::flushWrite");
2695
int64 generatedIdValue = 0;
2696
bool IdValueWasGenerated = FALSE;
2697
char* lastDupKeyNamePtr = NULL;
2698
uint32 lastDupKeyNameLen = 0;
2700
bool retry_dup = FALSE;
2702
while (loopCnt == 0 || retry_dup == TRUE)
2704
rc = bridge()->writeRows(fileHandle,
2705
activeWriteBuf->ptr(),
2708
&IdValueWasGenerated,
2715
invalidateCachedStats();
2716
if (lastDupKeyNameLen)
2718
rrnAssocHandle = fileHandle;
2720
int command = thd_sql_command(ha_thd());
2722
if (command == SQLCOM_REPLACE ||
2723
command == SQLCOM_REPLACE_SELECT)
2727
lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen);
2729
if (likely(lastDupKeyID != MAX_KEY))
2731
uint16 failedRow = activeWriteBuf->rowsWritten()+1;
2733
if (buf && (failedRow != activeWriteBuf->rowCount()))
2735
const char* badRow = activeWriteBuf->getRowN(failedRow-1);
2736
bool savedReadAllColumns = readAllColumns;
2737
readAllColumns = true;
2740
badRow + activeWriteBuf->getRowNullOffset(),
2742
readAllColumns = savedReadAllColumns;
2744
if (table->found_next_number_field)
2746
table->next_number_field->store(next_identity_value - (incrementByValue * (activeWriteBuf->rowCount() - (failedRow - 1))));
2750
if (default_identity_value && // Table has ID colm and generating a value
2751
(!autoIncLockAcquired || !got_auto_inc_values) &&
2752
// Writing first or only row in block
2753
loopCnt == 1 && // Didn't already retry
2754
lastDupKeyID == table->s->next_number_index) // Autoinc column is in failed index
2756
if (alterStartWith() == 0) // Reset next Identity value to max+1
2757
retry_dup = TRUE; // Rtry the write operation
2762
char unknownIndex[MAX_DB2_FILENAME_LENGTH+1];
2763
convFromEbcdic(lastDupKeyNamePtr, unknownIndex, min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH));
2764
unknownIndex[min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH)] = 0;
2765
getErrTxt(DB2I_ERR_UNKNOWN_IDX, unknownIndex);
2771
if ((rc == 0 || rc == HA_ERR_FOUND_DUPP_KEY)
2772
&& default_identity_value && IdValueWasGenerated &&
2773
(!autoIncLockAcquired || !got_auto_inc_values))
2775
/* Save the generated identity value for the MySQL last_insert_id() function. */
2776
insert_id_for_cur_row = generatedIdValue;
2778
/* Store the value into MySQL's buf for row-based replication
2779
or for an 'on duplicate key update' clause. */
2780
table->next_number_field->store((longlong) generatedIdValue, TRUE);
2781
if (autoIncLockAcquired)
2783
got_auto_inc_values = TRUE;
2784
next_identity_value = generatedIdValue + incrementByValue;
2789
if (!autoIncLockAcquired) // Don't overlay value for first row of a block
2790
insert_id_for_cur_row = 0;
2794
activeWriteBuf->resetAfterWrite();
2798
int ha_ibmdb2i::alterStartWith()
2800
DBUG_ENTER("ha_ibmdb2i::alterStartWith");
2802
ulonglong nextIdVal;
2804
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
2805
if (!rc) {rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LENR, QMY_YES);}
2808
rc = getNextIdVal(&nextIdVal);
2809
if (!rc) {rc = reset_auto_increment(nextIdVal);}
2810
bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LENR, QMY_YES);
2815
bool ha_ibmdb2i::lobFieldsRequested()
2817
if (!db2Table->hasBlobs())
2819
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs"));
2825
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("All cols requested"));
2829
for (int i = 0; i < db2Table->getBlobCount(); ++i)
2831
if (bitmap_is_set(table->read_set, db2Table->blobFields[i]))
2833
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("LOB requested"));
2838
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs requested"));
2843
int ha_ibmdb2i::prepareReadBufferForLobs()
2845
DBUG_ENTER("ha_ibmdb2i::prepareReadBufferForLobs");
2846
DBUG_ASSERT(db2Table->hasBlobs());
2848
uint32 activeLobFields = 0;
2849
DB2LobField* lobField;
2850
uint16 blobCount = db2Table->getBlobCount();
2852
char* readBuf = activeReadBuf->getRowN(0);
2854
for (int i = 0; i < blobCount; ++i)
2856
int fieldID = db2Table->blobFields[i];
2857
DB2Field& db2Field = db2Table->db2Field(fieldID);
2858
lobField = db2Field.asBlobField(readBuf);
2859
if (readAllColumns ||
2860
bitmap_is_set(table->read_set, fieldID))
2862
lobField->dataHandle = (ILEMemHandle)blobReadBuffers->getBufferPtr(fieldID);
2867
lobField->dataHandle = NULL;
2871
if (activeLobFields == 0)
2873
for (int i = 0; i < blobCount; ++i)
2875
DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
2876
uint16 offset = db2Field.getBufferOffset() + db2Field.calcBlobPad();
2878
for (int r = 1; r < activeReadBuf->getRowCapacity(); ++r)
2880
lobField = (DB2LobField*)(activeReadBuf->getRowN(r) + offset);
2881
lobField->dataHandle = NULL;
2886
activeReadBuf->setRowsToProcess((activeLobFields ? 1 : activeReadBuf->getRowCapacity()));
2887
int rc = bridge()->objectOverride(activeHandle,
2888
activeReadBuf->ptr(),
2889
activeReadBuf->getRowLength());
2894
uint32 ha_ibmdb2i::adjustLobBuffersForRead()
2896
DBUG_ENTER("ha_ibmdb2i::adjustLobBuffersForRead");
2898
char* readBuf = activeReadBuf->getRowN(0);
2900
for (int i = 0; i < db2Table->getBlobCount(); ++i)
2902
DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
2903
DB2LobField* lobField = db2Field.asBlobField(readBuf);
2904
if (readAllColumns ||
2905
bitmap_is_set(table->read_set, db2Table->blobFields[i]))
2907
lobField->dataHandle = (ILEMemHandle)blobReadBuffers->reallocBuffer(db2Table->blobFields[i], lobField->length);
2909
if (lobField->dataHandle == NULL)
2910
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
2914
lobField->dataHandle = 0;
2918
int32 rc = bridge()->objectOverride(activeHandle,
2919
activeReadBuf->ptr());
2925
int ha_ibmdb2i::reset()
2927
DBUG_ENTER("ha_ibmdb2i::reset");
2929
if (outstanding_start_bulk_insert)
2934
if (activeHandle != 0)
2936
releaseActiveHandle();
2941
db2i_ileBridge::getBridgeForThread(ha_thd())->freeErrorStorage();
2943
last_rnd_init_rc = last_index_init_rc = last_start_bulk_insert_rc = 0;
2945
returnDupKeysImmediately = false;
2946
onDupUpdate = false;
2947
forceSingleRowRead = false;
2957
int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream,
2960
const char* db2LibName,
2961
const char* db2FileName)
2963
DBUG_ENTER("ha_ibmdb2i::buildCreateIndexStatement");
2965
char fileSortSequence[11] = "*HEX";
2966
char fileSortSequenceLibrary[11] = "";
2967
char fileSortSequenceType = ' ';
2974
query.append(STRING_WITH_LEN("ALTER TABLE "));
2975
query.append(db2LibName);
2977
query.append(db2FileName);
2978
query.append(STRING_WITH_LEN(" ADD PRIMARY KEY "));
2982
query.append(STRING_WITH_LEN("CREATE"));
2984
if (key.flags & HA_NOSAME)
2985
query.append(STRING_WITH_LEN(" UNIQUE WHERE NOT NULL"));
2987
query.append(STRING_WITH_LEN(" INDEX "));
2989
query.append(db2LibName);
2991
if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, query))
2993
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
2994
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
2997
query.append(STRING_WITH_LEN(" ON "));
2999
query.append(db2LibName);
3001
query.append(db2FileName);
3004
String fieldDefinition(128);
3005
fieldDefinition.length(0);
3006
fieldDefinition.append(STRING_WITH_LEN(" ( "));
3007
for (int j = 0; j < key.key_parts; ++j)
3009
char colName[MAX_DB2_COLNAME_LENGTH+1];
3012
fieldDefinition.append(STRING_WITH_LEN(" , "));
3014
Field* field = key.key_part[j].field;
3015
convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
3016
fieldDefinition.append(colName);
3017
rc = updateAssociatedSortSequence(field->charset(),
3018
&fileSortSequenceType,
3020
fileSortSequenceLibrary);
3021
if (rc) DBUG_RETURN (rc);
3023
fieldDefinition.append(STRING_WITH_LEN(" ) "));
3025
query.append(fieldDefinition);
3027
if ((THDVAR(ha_thd(), create_index_option)==1) &&
3028
(fileSortSequenceType != 'B'))
3030
String shadowQuery(256);
3031
shadowQuery.length(0);
3033
shadowQuery.append(STRING_WITH_LEN("CREATE INDEX "));
3035
shadowQuery.append(db2LibName);
3036
shadowQuery.append('.');
3037
if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, shadowQuery, db2i_table::ASCII_SQL, typeHex))
3039
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
3040
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
3043
shadowQuery.append(STRING_WITH_LEN(" ON "));
3045
shadowQuery.append(db2LibName);
3046
shadowQuery.append('.');
3047
shadowQuery.append(db2FileName);
3048
shadowQuery.append(fieldDefinition);
3049
DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",shadowQuery.c_ptr_safe()));
3050
sqlStream.addStatement(shadowQuery,"*HEX","QSYS");
3053
DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",query.c_ptr_safe()));
3054
sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
3060
void ha_ibmdb2i::doInitialRead(char orientation,
3061
uint32 rowsToBuffer,
3066
DBUG_ENTER("ha_ibmdb2i::doInitialRead");
3068
if (forceSingleRowRead)
3071
rowsToBuffer = min(rowsToBuffer, activeReadBuf->getRowCapacity());
3073
activeReadBuf->newReadRequest(activeHandle,
3076
THDVAR(ha_thd(), async_enabled),
3084
int ha_ibmdb2i::start_stmt(THD *thd, thr_lock_type lock_type)
3086
DBUG_ENTER("ha_ibmdb2i::start_stmt");
3088
if (!THDVAR(thd, transaction_unsafe))
3090
trans_register_ha(thd, FALSE, ibmdb2i_hton);
3092
if (!autoCommitIsOn(thd))
3094
bridge()->beginStmtTx();
3101
int32 ha_ibmdb2i::handleLOBReadOverflow()
3103
DBUG_ENTER("ha_ibmdb2i::handleLOBReadOverflow");
3104
DBUG_ASSERT(db2Table->hasBlobs() && (activeReadBuf->getRowCapacity() == 1));
3106
int32 rc = adjustLobBuffersForRead();
3110
activeReadBuf->rewind();
3111
rc = bridge()->expectErrors(QMY_ERR_END_OF_BLOCK)
3112
->read(activeHandle,
3113
activeReadBuf->ptr(),
3117
releaseRowNeeded = TRUE;
3124
int32 ha_ibmdb2i::finishBulkInsert()
3128
if (activeWriteBuf->rowCount() && activeHandle)
3129
rc = flushWrite(activeHandle, table->record[0]);
3132
releaseActiveHandle();
3134
if (autoIncLockAcquired == TRUE)
3136
// We could check the return code on the unlock, but beware not
3137
// to overlay the return code from the flushwrite or we will mask
3138
// duplicate key errors..
3139
bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
3140
autoIncLockAcquired = FALSE;
3142
outstanding_start_bulk_insert = false;
3143
multiRowWriteBuf.freeBuf();
3144
last_start_bulk_insert_rc = 0;
3146
resetCharacterConversionBuffers();
3151
int ha_ibmdb2i::getKeyFromName(const char* name, size_t len)
3153
for (int i = 0; i < table_share->keys; ++i)
3155
const char* indexName = db2Table->indexFile(i)->getDB2FileName();
3156
if ((strncmp(name, indexName, len) == 0) &&
3157
(strlen(indexName) == len))
3166
Determine the number of I/O's it takes to read through the table.
3168
double ha_ibmdb2i::scan_time()
3170
DBUG_ENTER("ha_ibmdb2i::scan_time");
3171
DBUG_RETURN(ulonglong2double((stats.data_file_length)/IO_SIZE));
3176
Estimate the number of I/O's it takes to read a set of ranges through
3183
@return The estimate number of I/Os
3186
double ha_ibmdb2i::read_time(uint index, uint ranges, ha_rows rows)
3188
DBUG_ENTER("ha_ibmdb2i::read_time");
3190
uint64 idxPageCnt = 0;
3193
if (unlikely(rows == HA_POS_ERROR))
3194
DBUG_RETURN(double(rows) + ranges);
3196
rc = bridge()->retrieveIndexInfo(db2Table->indexFile(index)->getMasterDefnHandle(),
3200
if ((idxPageCnt == 1) || // Retrieving rows in requested order or
3201
(ranges == rows)) // 'Sweep' full records retrieval
3202
cost = idxPageCnt/4;
3205
uint64 totalRecords = stats.records + 1;
3206
double dataPageCount = stats.data_file_length/IO_SIZE;
3208
cost = (rows * dataPageCount / totalRecords) +
3209
min(idxPageCnt, (log_2(idxPageCnt) * ranges +
3210
rows * (log_2(idxPageCnt) + log_2(rows) - log_2(totalRecords))));
3215
cost = rows2double(ranges+rows); // Use default costing
3220
int ha_ibmdb2i::useIndexFile(int idx)
3222
DBUG_ENTER("ha_ibmdb2i::useIndexFile");
3225
releaseActiveHandle();
3229
if (!indexHandles[idx])
3230
rc = db2Table->indexFile(idx)->allocateNewInstance(&indexHandles[idx], curConnection);
3234
activeHandle = indexHandles[idx];
3235
bumpInUseCounter(1);
3242
ulong ha_ibmdb2i::index_flags(uint inx, uint part, bool all_parts) const
3244
return HA_READ_NEXT | HA_READ_PREV | HA_KEYREAD_ONLY | HA_READ_ORDER | HA_READ_RANGE;
3248
static struct st_mysql_sys_var* ibmdb2i_system_variables[] = {
3249
MYSQL_SYSVAR(rdb_name),
3250
MYSQL_SYSVAR(transaction_unsafe),
3251
MYSQL_SYSVAR(lob_alloc_size),
3252
MYSQL_SYSVAR(max_read_buffer_size),
3253
MYSQL_SYSVAR(max_write_buffer_size),
3254
MYSQL_SYSVAR(async_enabled),
3255
MYSQL_SYSVAR(assume_exclusive_use),
3256
MYSQL_SYSVAR(compat_opt_blob_cols),
3257
MYSQL_SYSVAR(compat_opt_time_as_duration),
3258
MYSQL_SYSVAR(compat_opt_allow_zero_date_vals),
3259
MYSQL_SYSVAR(compat_opt_year_as_int),
3260
MYSQL_SYSVAR(propagate_default_col_vals),
3261
MYSQL_SYSVAR(create_index_option),
3262
// MYSQL_SYSVAR(discovery_mode),
3263
MYSQL_SYSVAR(system_trace_level),
3268
struct st_mysql_storage_engine ibmdb2i_storage_engine=
3269
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
3271
mysql_declare_plugin(ibmdb2i)
3273
MYSQL_STORAGE_ENGINE_PLUGIN,
3274
&ibmdb2i_storage_engine,
3276
"The IBM development team in Rochester, Minnesota",
3277
"IBM DB2 for i Storage Engine",
3279
ibmdb2i_init_func, /* Plugin Init */
3280
ibmdb2i_done_func, /* Plugin Deinit */
3282
NULL, /* status variables */
3283
ibmdb2i_system_variables, /* system variables */
3284
NULL /* config options */
3286
mysql_declare_plugin_end;