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,table_alias_charset,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);
908
int ha_ibmdb2i::index_read(uchar * buf, const uchar * key,
910
enum ha_rkey_function find_flag)
912
DBUG_ENTER("ha_ibmdb2i::index_read");
914
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
918
ha_rows estimatedRows = getIndexReadEstimate(active_index);
919
rc = prepReadBuffer(estimatedRows, db2Table->indexFile(active_index), readAccessIntent);
920
if (unlikely(rc)) DBUG_RETURN(rc);
922
DBUG_ASSERT(activeReadBuf);
924
keyBuf.allocBuf(activeReadBuf->getRowLength(),
925
activeReadBuf->getRowNullOffset(),
926
activeReadBuf->getRowLength());
929
char* db2KeyBufPtr = keyBuf.ptr();
930
char* nullKeyMap = db2KeyBufPtr + activeReadBuf->getRowNullOffset();
932
const uchar* keyBegin = key;
935
KEY& curKey = table->key_info[active_index];
937
for (partsInUse = 0; partsInUse < curKey.key_parts, key - keyBegin < key_len; ++partsInUse)
939
Field* field = curKey.key_part[partsInUse].field;
940
if ((curKey.key_part[partsInUse].null_bit) &&
943
if (field->flags & AUTO_INCREMENT_FLAG)
945
table->status = STATUS_NOT_FOUND;
946
DBUG_RETURN(HA_ERR_END_OF_FILE);
950
nullKeyMap[partsInUse] = __NULL_VALUE_EBCDIC;
955
nullKeyMap[partsInUse] = __NOT_NULL_VALUE_EBCDIC;
956
convertMySQLtoDB2(field,
957
db2Table->db2Field(field->field_index),
959
(uchar*)key+((curKey.key_part[partsInUse].null_bit)? 1 : 0) ); // + (curKey.key_parts+7) / 8);
962
db2KeyBufPtr += db2Table->db2Field(field->field_index).getByteLengthInRecord();
963
key += curKey.key_part[partsInUse].store_length;
966
keyLen = db2KeyBufPtr - (char*)keyBuf.ptr();
968
DBUG_PRINT("ha_ibmdb2i::index_read", ("find_flag: %d", find_flag));
970
char readDirection = QMY_NEXT;
974
case HA_READ_AFTER_KEY:
975
doInitialRead(QMY_AFTER_EQUAL, estimatedRows,
976
keyBuf.ptr(), keyLen, partsInUse);
978
case HA_READ_BEFORE_KEY:
979
doInitialRead(QMY_BEFORE_EQUAL, estimatedRows,
980
keyBuf.ptr(), keyLen, partsInUse);
982
case HA_READ_KEY_OR_NEXT:
983
doInitialRead(QMY_AFTER_OR_EQUAL, estimatedRows,
984
keyBuf.ptr(), keyLen, partsInUse);
986
case HA_READ_KEY_OR_PREV:
987
DBUG_ASSERT(0); // This function is unused
988
doInitialRead(QMY_BEFORE_OR_EQUAL, estimatedRows,
989
keyBuf.ptr(), keyLen, partsInUse);
991
case HA_READ_PREFIX_LAST_OR_PREV:
992
doInitialRead(QMY_LAST_PREVIOUS, estimatedRows,
993
keyBuf.ptr(), keyLen, partsInUse);
994
readDirection = QMY_PREVIOUS;
996
case HA_READ_PREFIX_LAST:
997
doInitialRead(QMY_PREFIX_LAST, estimatedRows,
998
keyBuf.ptr(), keyLen, partsInUse);
999
readDirection = QMY_PREVIOUS;
1001
case HA_READ_KEY_EXACT:
1002
doInitialRead(QMY_EQUAL, estimatedRows, keyBuf.ptr(), keyLen, partsInUse);
1006
return HA_ERR_GENERIC;
1010
ha_statistic_increment(&SSV::ha_read_key_count);
1011
rc = readFromBuffer(buf, readDirection);
1013
table->status= (rc ? STATUS_NOT_FOUND: 0);
1018
int ha_ibmdb2i::index_next(uchar * buf)
1020
DBUG_ENTER("ha_ibmdb2i::index_next");
1021
ha_statistic_increment(&SSV::ha_read_next_count);
1023
int rc = readFromBuffer(buf, QMY_NEXT);
1025
table->status= (rc ? STATUS_NOT_FOUND: 0);
1030
int ha_ibmdb2i::index_next_same(uchar *buf, const uchar *key, uint keylen)
1032
DBUG_ENTER("ha_ibmdb2i::index_next_same");
1033
ha_statistic_increment(&SSV::ha_read_next_count);
1035
int rc = readFromBuffer(buf, QMY_NEXT_EQUAL);
1037
if (rc == HA_ERR_KEY_NOT_FOUND)
1039
rc = HA_ERR_END_OF_FILE;
1042
table->status= (rc ? STATUS_NOT_FOUND: 0);
1046
int ha_ibmdb2i::index_read_last(uchar * buf, const uchar * key, uint key_len)
1048
DBUG_ENTER("ha_ibmdb2i::index_read_last");
1049
DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));
1054
int ha_ibmdb2i::index_prev(uchar * buf)
1056
DBUG_ENTER("ha_ibmdb2i::index_prev");
1057
ha_statistic_increment(&SSV::ha_read_prev_count);
1059
int rc = readFromBuffer(buf, QMY_PREVIOUS);
1061
table->status= (rc ? STATUS_NOT_FOUND: 0);
1066
int ha_ibmdb2i::index_first(uchar * buf)
1068
DBUG_ENTER("ha_ibmdb2i::index_first");
1070
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
1072
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER,
1073
db2Table->indexFile(active_index),
1078
doInitialRead(QMY_FIRST, DEFAULT_MAX_ROWS_TO_BUFFER);
1079
ha_statistic_increment(&SSV::ha_read_first_count);
1080
rc = readFromBuffer(buf, QMY_NEXT);
1083
table->status= (rc ? STATUS_NOT_FOUND: 0);
1088
int ha_ibmdb2i::index_last(uchar * buf)
1090
DBUG_ENTER("ha_ibmdb2i::index_last");
1092
if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
1094
int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER,
1095
db2Table->indexFile(active_index),
1100
doInitialRead(QMY_LAST, DEFAULT_MAX_ROWS_TO_BUFFER);
1101
ha_statistic_increment(&SSV::ha_read_last_count);
1102
rc = readFromBuffer(buf, QMY_PREVIOUS);
1105
table->status= (rc ? STATUS_NOT_FOUND: 0);
1110
int ha_ibmdb2i::rnd_init(bool scan)
1112
DBUG_ENTER("ha_ibmdb2i::rnd_init");
1114
int& rc = last_rnd_init_rc;
1118
invalidDataFound=false;
1120
uint32 rowsToBlockOnRead;
1124
rowsToBlockOnRead = 1;
1128
rowsToBlockOnRead = DEFAULT_MAX_ROWS_TO_BUFFER;
1135
// THD* thd = ha_thd();
1136
// if (accessIntent == QMY_UPDATABLE &&
1137
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
1138
// !THDVAR(thd, transaction_unsafe))
1140
// readAccessIntent = QMY_READ_ONLY;
1144
readAccessIntent = accessIntent;
1147
rc = prepReadBuffer(rowsToBlockOnRead, db2Table->dataFile(), readAccessIntent);
1149
if (!rc && accessIntent != QMY_READ_ONLY)
1150
rc = prepWriteBuffer(1, db2Table->dataFile());
1153
doInitialRead(QMY_FIRST, rowsToBlockOnRead);
1161
DBUG_RETURN(0); // MySQL sometimes does not check the return code, causing
1162
// an assert in ha_rnd_end later on if we return a non-zero
1166
int ha_ibmdb2i::rnd_end()
1168
DBUG_ENTER("ha_ibmdb2i::rnd_end");
1170
warnIfInvalidData();
1171
if (likely(activeReadBuf))
1172
activeReadBuf->endRead();
1173
if (last_rnd_init_rc == 0)
1174
releaseActiveHandle();
1175
last_rnd_init_rc = 0;
1180
int32 ha_ibmdb2i::mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs)
1182
DBUG_ASSERT(dataPtr);
1184
my_bitmap_map *old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
1185
my_bitmap_map *old_read_map;
1187
if (unlikely(readAllColumns))
1188
old_read_map = tmp_use_all_columns(table, table->read_set);
1190
resetCharacterConversionBuffers();
1192
my_ptrdiff_t old_ptr= (my_ptrdiff_t) (record - table->record[0]);
1194
for (Field **field = table->field; *field; ++field, ++fieldIndex)
1196
if (unlikely(old_ptr))
1197
(*field)->move_field_offset(old_ptr);
1198
if (nullMapPtr[fieldIndex] == __NULL_VALUE_EBCDIC ||
1199
(!bitmap_is_set(table->read_set, fieldIndex)) ||
1200
(skipLOBs && db2Table->db2Field(fieldIndex).isBlob()))
1202
(*field)->set_null();
1206
(*field)->set_notnull();
1207
convertDB2toMySQL(db2Table->db2Field(fieldIndex), *field, dataPtr);
1209
if (unlikely(old_ptr))
1210
(*field)->move_field_offset(-old_ptr);
1214
if (unlikely(readAllColumns))
1215
tmp_restore_column_map(table->read_set, old_read_map);
1216
dbug_tmp_restore_column_map(table->write_set, old_write_map);
1222
int ha_ibmdb2i::rnd_next(uchar *buf)
1224
DBUG_ENTER("ha_ibmdb2i::rnd_next");
1226
if (unlikely(last_rnd_init_rc)) DBUG_RETURN(last_rnd_init_rc);
1227
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1231
rc = readFromBuffer(buf, QMY_NEXT);
1233
table->status= (rc ? STATUS_NOT_FOUND: 0);
1238
void ha_ibmdb2i::position(const uchar *record)
1240
DBUG_ENTER("ha_ibmdb2i::position");
1241
my_store_ptr(ref, ref_length, currentRRN);
1246
int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos)
1248
DBUG_ENTER("ha_ibmdb2i::rnd_pos");
1249
if (unlikely(last_rnd_init_rc)) DBUG_RETURN( last_rnd_init_rc);
1250
ha_statistic_increment(&SSV::ha_read_rnd_count);
1252
currentRRN = my_get_ptr(pos, ref_length);
1258
if (rrnAssocHandle &&
1259
(activeHandle != rrnAssocHandle))
1261
if (activeHandle) releaseActiveHandle();
1262
rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);
1265
if (likely(rc == 0))
1267
rc = prepReadBuffer(1, getFileForActiveHandle(), accessIntent);
1269
if (likely(rc == 0) && accessIntent == QMY_UPDATABLE)
1270
rc = prepWriteBuffer(1, getFileForActiveHandle());
1272
if (likely(rc == 0))
1274
rc = db2i_ileBridge::getBridgeForThread()->readByRRN(activeHandle,
1275
activeReadBuf->ptr(),
1280
if (likely(rc == 0))
1282
rrnAssocHandle = activeHandle;
1283
const char* readBuf = activeReadBuf->getRowN(0);
1284
rc = mungeDB2row(buf, readBuf, readBuf + activeReadBuf->getRowNullOffset(), false);
1285
releaseRowNeeded = TRUE;
1294
int ha_ibmdb2i::info(uint flag)
1296
DBUG_ENTER("ha_ibmdb2i::info");
1298
uint16 infoRequested = 0;
1299
ValidatedPointer<char> rowKeySpcPtr; // Space pointer passed to DB2
1300
uint32 rowKeySpcLen; // Length of space passed to DB2
1301
THD* thd = ha_thd();
1302
int command = thd_sql_command(thd);
1304
if (flag & HA_STATUS_AUTO)
1305
stats.auto_increment_value = (ulonglong) 0;
1307
if (flag & HA_STATUS_ERRKEY)
1309
errkey = lastDupKeyID;
1310
my_store_ptr(dup_ref, ref_length, lastDupKeyRRN);
1313
if (flag & HA_STATUS_TIME)
1315
if ((flag & HA_STATUS_NO_LOCK) &&
1316
ibmdb2i_assume_exclusive_use &&
1318
(share->cachedStats.isInited(lastModTime)))
1319
stats.update_time = share->cachedStats.getUpdateTime();
1321
infoRequested |= lastModTime;
1324
if (flag & HA_STATUS_CONST)
1326
stats.block_size=4096;
1327
infoRequested |= createTime;
1331
infoRequested |= rowsPerKey;
1332
rowKeySpcLen = (table->s->keys) * MAX_DB2_KEY_PARTS * sizeof(uint64);
1333
rowKeySpcPtr.alloc(rowKeySpcLen);
1334
memset(rowKeySpcPtr, 0, rowKeySpcLen); // Clear the allocated space
1338
if (flag & HA_STATUS_VARIABLE)
1340
if ((flag & HA_STATUS_NO_LOCK) &&
1341
(command != SQLCOM_SHOW_TABLE_STATUS) &&
1342
ibmdb2i_assume_exclusive_use &&
1344
(share->cachedStats.isInited(rowCount | deletedRowCount | meanRowLen | ioCount)) &&
1345
(share->cachedStats.getRowCount() >= 2))
1347
stats.records = share->cachedStats.getRowCount();
1348
stats.deleted = share->cachedStats.getDelRowCount();
1349
stats.mean_rec_length = share->cachedStats.getMeanLength();
1350
stats.data_file_length = share->cachedStats.getAugmentedDataLength();
1354
infoRequested |= rowCount | deletedRowCount | meanRowLen;
1355
if (command == SQLCOM_SHOW_TABLE_STATUS)
1356
infoRequested |= objLength;
1358
infoRequested |= ioCount;
1366
DBUG_PRINT("ha_ibmdb2i::info",("Retrieving fresh stats %d", flag));
1369
rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
1376
if ((flag & HA_STATUS_VARIABLE) &&
1377
(command != SQLCOM_SHOW_TABLE_STATUS))
1378
stats.data_file_length = stats.data_file_length * IO_SIZE;
1380
if ((ibmdb2i_assume_exclusive_use) &&
1382
(command != SQLCOM_SHOW_TABLE_STATUS))
1384
if (flag & HA_STATUS_VARIABLE)
1386
share->cachedStats.cacheRowCount(stats.records);
1387
share->cachedStats.cacheDelRowCount(stats.deleted);
1388
share->cachedStats.cacheMeanLength(stats.mean_rec_length);
1389
share->cachedStats.cacheAugmentedDataLength(stats.data_file_length);
1392
if (flag & HA_STATUS_TIME)
1394
share->cachedStats.cacheUpdateTime(stats.update_time);
1398
if (flag & HA_STATUS_CONST)
1400
ulong i; // Loop counter for indexes
1401
ulong j; // Loop counter for key parts
1402
RowKey* rowKeyPtr; // Pointer to 'number of unique rows' array for this index
1404
rowKeyPtr = (RowKey_t*)(void*)rowKeySpcPtr; // Address first array of DB2 row counts
1405
for (i = 0; i < table->s->keys; i++) // Do for each index, including primary
1407
for (j = 0; j < table->key_info[i].key_parts; j++)
1409
table->key_info[i].rec_per_key[j]= rowKeyPtr->RowKeyArray[j];
1411
rowKeyPtr = rowKeyPtr + 1; // Address next array of DB2 row counts
1415
else if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && share)
1417
// If we couldn't retrieve the info because the object was locked,
1418
// we'll do our best by returning the most recently cached data.
1419
if ((infoRequested & rowCount) &&
1420
share->cachedStats.isInited(rowCount))
1421
stats.records = share->cachedStats.getRowCount();
1422
if ((infoRequested & deletedRowCount) &&
1423
share->cachedStats.isInited(deletedRowCount))
1424
stats.deleted = share->cachedStats.getDelRowCount();
1425
if ((infoRequested & meanRowLen) &&
1426
share->cachedStats.isInited(meanRowLen))
1427
stats.mean_rec_length = share->cachedStats.getMeanLength();
1428
if ((infoRequested & lastModTime) &&
1429
share->cachedStats.isInited(lastModTime))
1430
stats.update_time = share->cachedStats.getUpdateTime();
1440
ha_rows ha_ibmdb2i::records()
1442
DBUG_ENTER("ha_ibmdb2i::records");
1444
rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
1450
if (rc == HA_ERR_LOCK_WAIT_TIMEOUT &&
1452
(share->cachedStats.isInited(rowCount)))
1453
DBUG_RETURN(share->cachedStats.getRowCount());
1455
DBUG_RETURN(HA_POS_ERROR);
1459
share->cachedStats.cacheRowCount(stats.records);
1462
DBUG_RETURN(stats.records);
1466
int ha_ibmdb2i::extra(enum ha_extra_function operation)
1468
DBUG_ENTER("ha_ibmdb2i::extra");
1472
// Can these first five flags be replaced by attending to HA_EXTRA_WRITE_CACHE?
1473
case HA_EXTRA_NO_IGNORE_DUP_KEY:
1474
case HA_EXTRA_WRITE_CANNOT_REPLACE:
1476
returnDupKeysImmediately = false;
1477
onDupUpdate = false;
1480
case HA_EXTRA_INSERT_WITH_UPDATE:
1482
returnDupKeysImmediately = true;
1486
case HA_EXTRA_IGNORE_DUP_KEY:
1487
case HA_EXTRA_WRITE_CAN_REPLACE:
1488
returnDupKeysImmediately = true;
1490
case HA_EXTRA_FLUSH_CACHE:
1491
if (outstanding_start_bulk_insert)
1502
The DB2 storage engine will ignore a MySQL generated value and will generate
1503
a new value in SLIC. We arbitrarily set first_value to 1, and set the
1504
interval to infinity for better performance on multi-row inserts.
1506
void ha_ibmdb2i::get_auto_increment(ulonglong offset, ulonglong increment,
1507
ulonglong nb_desired_values,
1508
ulonglong *first_value,
1509
ulonglong *nb_reserved_values)
1511
DBUG_ENTER("ha_ibmdb2i::get_auto_increment");
1513
*nb_reserved_values= ULONGLONG_MAX;
1518
void ha_ibmdb2i::update_create_info(HA_CREATE_INFO *create_info)
1520
DBUG_ENTER("ha_ibmdb2i::update_create_info");
1522
if ((!(create_info->used_fields & HA_CREATE_USED_AUTO)) &&
1523
(table->found_next_number_field != NULL))
1527
create_info->auto_increment_value= 1;
1529
ha_rows rowCount = records();
1533
create_info->auto_increment_value = db2Table->getStartId();
1536
else if (rowCount == HA_POS_ERROR)
1541
getNextIdVal(&create_info->auto_increment_value);
1547
int ha_ibmdb2i::getNextIdVal(ulonglong *value)
1549
DBUG_ENTER("ha_ibmdb2i::getNextIdVal");
1551
char queryBuffer[MAX_DB2_COLNAME_LENGTH + MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
1552
strcpy(queryBuffer, " SELECT CAST(MAX( ");
1553
convertMySQLNameToDB2Name(table->found_next_number_field->field_name,
1554
strend(queryBuffer),
1555
MAX_DB2_COLNAME_LENGTH+1);
1556
strcat(queryBuffer, ") AS BIGINT) FROM ");
1557
db2Table->getDB2QualifiedName(strend(queryBuffer));
1558
DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
1560
SqlStatementStream sqlStream(queryBuffer);
1561
DBUG_PRINT("ha_ibmdb2i::getNextIdVal", ("Sent to DB2: %s",queryBuffer));
1564
FILE_HANDLE fileHandle2;
1565
uint32 db2RowDataLen2;
1566
rc = bridge()->prepOpen(sqlStream.getPtrToData(),
1569
if (likely(rc == 0))
1571
IOReadBuffer rowBuffer(1, db2RowDataLen2);
1572
rc = bridge()->read(fileHandle2,
1578
if (likely(rc == 0))
1580
/* This check is here for the case where the table is not empty,
1581
but the auto_increment starting value has been changed since
1582
the last record was written. */
1584
longlong maxIdVal = *(longlong*)(rowBuffer.getRowN(0));
1585
if ((maxIdVal + 1) > db2Table->getStartId())
1586
*value = maxIdVal + 1;
1588
*value = db2Table->getStartId();
1591
bridge()->deallocateFile(fileHandle2);
1598
Updates index cardinalities.
1600
int ha_ibmdb2i::analyze(THD* thd, HA_CHECK_OPT *check_opt)
1602
DBUG_ENTER("ha_ibmdb2i::analyze");
1603
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
1607
int ha_ibmdb2i::optimize(THD* thd, HA_CHECK_OPT *check_opt)
1609
DBUG_ENTER("ha_ibmdb2i::optimize");
1613
if (unlikely(records() == 0))
1614
DBUG_RETURN(0); // DB2 doesn't like to reorganize a table with no data.
1616
quiesceAllFileHandles();
1618
int32 rc = bridge()->optimizeTable(db2Table->dataFile()->getMasterDefnHandle());
1619
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
1627
Determines if an ALTER TABLE is allowed to switch the storage engine
1628
for this table. If the table has a foreign key or is referenced by a
1629
foreign key, then it cannot be switched.
1631
bool ha_ibmdb2i::can_switch_engines(void)
1632
/*=================================*/
1634
DBUG_ENTER("ha_ibmdb2i::can_switch_engines");
1637
FILE_HANDLE queryFile = 0;
1638
uint32 resultRowLen;
1640
bool can_switch = FALSE; // 1 if changing storage engine is allowed
1642
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
1643
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
1646
query.append(STRING_WITH_LEN(" SELECT COUNT(*) FROM SYSIBM.SQLFOREIGNKEYS WHERE ((PKTABLE_SCHEM = '"));
1647
query.append(libName+1, strlen(libName)-2); // Remove quotes from parent schema name
1648
query.append(STRING_WITH_LEN("' AND PKTABLE_NAME = '"));
1649
query.append(fileName+1,strlen(fileName)-2); // Remove quotes from file name
1650
query.append(STRING_WITH_LEN("') OR (FKTABLE_SCHEM = '"));
1651
query.append(libName+1,strlen(libName)-2); // Remove quotes from child schema
1652
query.append(STRING_WITH_LEN("' AND FKTABLE_NAME = '"));
1653
query.append(fileName+1,strlen(fileName)-2); // Remove quotes from child name
1654
query.append(STRING_WITH_LEN("'))"));
1656
SqlStatementStream sqlStream(query);
1658
rc = bridge()->prepOpen(sqlStream.getPtrToData(),
1663
IOReadBuffer rowBuffer(1, resultRowLen);
1665
rc = bridge()->read(queryFile,
1672
count = *(uint*)(rowBuffer.getRowN(0));
1677
bridge()->deallocateFile(queryFile);
1679
DBUG_RETURN(can_switch);
1684
bool ha_ibmdb2i::check_if_incompatible_data(HA_CREATE_INFO *info,
1687
DBUG_ENTER("ha_ibmdb2i::check_if_incompatible_data");
1689
/* Check that auto_increment value and field definitions were
1691
if ((info->used_fields & HA_CREATE_USED_AUTO &&
1692
info->auto_increment_value != 0) ||
1693
table_changes != IS_EQUAL_YES)
1694
DBUG_RETURN(COMPATIBLE_DATA_NO);
1695
/* Check if any fields were renamed. */
1696
for (i= 0; i < table->s->fields; i++)
1698
Field *field= table->field[i];
1699
if (field->flags & FIELD_IS_RENAMED)
1701
DBUG_PRINT("info", ("Field has been renamed, copy table"));
1702
DBUG_RETURN(COMPATIBLE_DATA_NO);
1705
DBUG_RETURN(COMPATIBLE_DATA_YES);
1708
int ha_ibmdb2i::reset_auto_increment(ulonglong value)
1710
DBUG_ENTER("ha_ibmdb2i::reset_auto_increment");
1714
quiesceAllFileHandles();
1716
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
1717
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
1720
query.append(STRING_WITH_LEN(" ALTER TABLE "));
1721
query.append(libName);
1723
query.append(fileName);
1724
query.append(STRING_WITH_LEN(" ALTER COLUMN "));
1725
char colName[MAX_DB2_COLNAME_LENGTH+1];
1726
convertMySQLNameToDB2Name(table->found_next_number_field->field_name,
1729
query.append(colName);
1731
char restart_value[22];
1732
CHARSET_INFO *cs= &my_charset_bin;
1733
uint len = (uint)(cs->cset->longlong10_to_str)(cs,restart_value,sizeof(restart_value), 10, value);
1734
restart_value[len] = 0;
1736
query.append(STRING_WITH_LEN(" RESTART WITH "));
1737
query.append(restart_value);
1739
SqlStatementStream sqlStream(query);
1740
DBUG_PRINT("ha_ibmdb2i::reset_auto_increment", ("Sent to DB2: %s",query.c_ptr()));
1742
rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
1743
sqlStream.getStatementCount(),
1744
QMY_NONE, //getCommitLevel(),
1750
db2Table->updateStartId(value);
1758
This function receives an error code that was previously set by the handler.
1759
It returns to MySQL the error string associated with that error.
1761
bool ha_ibmdb2i::get_error_message(int error, String *buf)
1763
DBUG_ENTER("ha_ibmdb2i::get_error_message");
1764
if ((error >= DB2I_FIRST_ERR && error <= DB2I_LAST_ERR) ||
1765
(error >= QMY_ERR_MIN && error <= QMY_ERR_MAX))
1767
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(ha_thd());
1768
char* errMsg = bridge->getErrorStorage();
1769
buf->copy(errMsg, strlen(errMsg),system_charset_info);
1770
bridge->freeErrorStorage();
1776
int ha_ibmdb2i::delete_all_rows()
1778
DBUG_ENTER("ha_ibmdb2i::delete_all_rows");
1780
char queryBuffer[MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
1781
strcpy(queryBuffer, " DELETE FROM ");
1782
db2Table->getDB2QualifiedName(strend(queryBuffer));
1783
DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
1785
SqlStatementStream sqlStream(queryBuffer);
1786
DBUG_PRINT("ha_ibmdb2i::delete_all_rows", ("Sent to DB2: %s",queryBuffer));
1787
rc = bridge()->execSQL(sqlStream.getPtrToData(),
1788
sqlStream.getStatementCount(),
1795
/* If this method was called on behalf of a TRUNCATE TABLE statement, and if */
1796
/* the table has an auto_increment field, then reset the starting value for */
1797
/* the auto_increment field to 1.
1799
if (rc == 0 && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE &&
1800
table->found_next_number_field )
1801
rc = reset_auto_increment(1);
1803
invalidateCachedStats();
1809
int ha_ibmdb2i::external_lock(THD *thd, int lock_type)
1813
DBUG_ENTER("ha_ibmdb2i::external_lock");
1814
DBUG_PRINT("ha_ibmdb2i::external_lock",("Lock type: %d", lock_type));
1816
if (lock_type == F_RDLCK)
1817
accessIntent = QMY_READ_ONLY;
1818
else if (lock_type == F_WRLCK)
1819
accessIntent = QMY_UPDATABLE;
1822
int command = thd_sql_command(thd);
1824
if (!THDVAR(thd,transaction_unsafe))
1826
if (lock_type != F_UNLCK)
1828
if (autoCommitIsOn(thd) == QMY_YES)
1830
trans_register_ha(thd, FALSE, ibmdb2i_hton);
1834
trans_register_ha(thd, TRUE, ibmdb2i_hton);
1835
if (likely(command != SQLCOM_CREATE_TABLE))
1837
trans_register_ha(thd, FALSE, ibmdb2i_hton);
1838
bridge()->beginStmtTx();
1844
if (command == SQLCOM_LOCK_TABLES ||
1845
command == SQLCOM_ALTER_TABLE ||
1846
command == SQLCOM_UNLOCK_TABLES ||
1847
(accessIntent == QMY_UPDATABLE &&
1848
(command == SQLCOM_UPDATE ||
1849
command == SQLCOM_UPDATE_MULTI ||
1850
command == SQLCOM_DELETE ||
1851
command == SQLCOM_DELETE_MULTI ||
1852
command == SQLCOM_REPLACE ||
1853
command == SQLCOM_REPLACE_SELECT) &&
1854
getCommitLevel(thd) == QMY_NONE))
1858
if (lock_type == F_UNLCK)
1860
action = QMY_UNLOCK;
1861
type = accessIntent == QMY_READ_ONLY ? QMY_LSRD : QMY_LENR;
1866
type = lock_type == F_RDLCK ? QMY_LSRD : QMY_LENR;
1869
DBUG_PRINT("ha_ibmdb2i::external_lock",("%socking table", action==QMY_LOCK ? "L" : "Unl"));
1872
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
1874
rc = bridge()->lockObj(dataHandle,
1878
(command == SQLCOM_LOCK_TABLES ? QMY_NO : QMY_YES));
1882
// Cache this away so we don't have to access it on each row operation
1883
cachedZeroDateOption = (enum_ZeroDate)THDVAR(thd, compat_opt_allow_zero_date_vals);
1889
THR_LOCK_DATA **ha_ibmdb2i::store_lock(THD *thd,
1891
enum thr_lock_type lock_type)
1893
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
1895
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
1896
lock_type <= TL_WRITE) && !(thd->in_lock_tables && thd_sql_command(thd) == SQLCOM_LOCK_TABLES))
1897
lock_type= TL_WRITE_ALLOW_WRITE;
1898
lock.type=lock_type;
1905
int ha_ibmdb2i::delete_table(const char *name)
1907
DBUG_ENTER("ha_ibmdb2i::delete_table");
1908
THD* thd = ha_thd();
1909
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(thd);
1911
char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
1912
db2i_table::getDB2QualifiedNameFromPath(name, db2Name);
1915
query.append(STRING_WITH_LEN(" DROP TABLE "));
1916
query.append(db2Name);
1918
if (thd_sql_command(thd) == SQLCOM_DROP_TABLE &&
1919
thd->lex->drop_mode == DROP_RESTRICT)
1920
query.append(STRING_WITH_LEN(" RESTRICT "));
1921
DBUG_PRINT("ha_ibmdb2i::delete_table", ("Sent to DB2: %s",query.c_ptr()));
1923
SqlStatementStream sqlStream(query);
1925
db2i_table::getDB2LibNameFromPath(name, db2Name);
1926
bool isTemporary = (strcmp(db2Name, DB2I_TEMP_TABLE_SCHEMA) == 0 ? TRUE : FALSE);
1928
int rc = bridge->execSQL(sqlStream.getPtrToData(),
1929
sqlStream.getStatementCount(),
1930
(isTemporary ? QMY_NONE : getCommitLevel(thd)),
1935
if (rc == HA_ERR_NO_SUCH_TABLE)
1937
warning(thd, DB2I_ERR_TABLE_NOT_FOUND, name);
1943
db2i_table::deleteAssocFiles(name);
1946
FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
1949
bridge->deallocateFile(savedHandle, TRUE);
1951
if (free_share(share))
1953
savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
1961
int ha_ibmdb2i::rename_table(const char * from, const char * to)
1963
DBUG_ENTER("ha_ibmdb2i::rename_table ");
1965
char db2FromFileName[MAX_DB2_FILENAME_LENGTH + 1];
1966
char db2ToFileName[MAX_DB2_FILENAME_LENGTH+1];
1967
char db2FromLibName[MAX_DB2_SCHEMANAME_LENGTH+1];
1968
char db2ToLibName[MAX_DB2_SCHEMANAME_LENGTH+1];
1970
db2i_table::getDB2LibNameFromPath(from, db2FromLibName);
1971
db2i_table::getDB2LibNameFromPath(to, db2ToLibName);
1973
if (strcmp(db2FromLibName, db2ToLibName) != 0 )
1975
getErrTxt(DB2I_ERR_RENAME_MOVE,from,to);
1976
DBUG_RETURN(DB2I_ERR_RENAME_MOVE);
1979
db2i_table::getDB2FileNameFromPath(from, db2FromFileName, db2i_table::ASCII_NATIVE);
1980
db2i_table::getDB2FileNameFromPath(to, db2ToFileName);
1982
char escapedFromFileName[2 * MAX_DB2_FILENAME_LENGTH + 1];
1988
escapedFromFileName[o++] = db2FromFileName[i];
1989
if (db2FromFileName[i] == '+')
1990
escapedFromFileName[o++] = '+';
1991
} while (db2FromFileName[++i]);
1992
escapedFromFileName[o-1] = 0;
1997
char queryBuffer[sizeof(db2FromLibName) + 2 * sizeof(db2FromFileName) + 256];
1998
SafeString selectQuery(queryBuffer, sizeof(queryBuffer));
1999
selectQuery.strncat(STRING_WITH_LEN("SELECT CAST(INDEX_NAME AS VARCHAR(128) CCSID 1208) FROM QSYS2.SYSINDEXES WHERE INDEX_NAME LIKE '%+_+_+_%"));
2000
selectQuery.strcat(escapedFromFileName);
2001
selectQuery.strncat(STRING_WITH_LEN("' ESCAPE '+' AND TABLE_NAME='"));
2002
selectQuery.strncat(db2FromFileName+1, strlen(db2FromFileName)-2);
2003
selectQuery.strncat(STRING_WITH_LEN("' AND TABLE_SCHEMA='"));
2004
selectQuery.strncat(db2FromLibName+1, strlen(db2FromLibName)-2);
2005
selectQuery.strcat('\'');
2006
DBUG_ASSERT(!selectQuery.overflowed());
2008
SqlStatementStream indexQuery(selectQuery.ptr());
2010
FILE_HANDLE queryFile = 0;
2011
uint32 resultRowLen;
2014
rc = bridge()->prepOpen(indexQuery.getPtrToData(),
2021
IOReadBuffer rowBuffer(1, resultRowLen);
2023
int tableNameLen = strlen(db2FromFileName) - 2;
2025
SqlStatementStream renameQuery(64);
2031
rc = bridge()->read(queryFile,
2039
const char* rowData = rowBuffer.getRowN(0);
2040
char indexFileName[MAX_DB2_FILENAME_LENGTH];
2041
memset(indexFileName, 0, sizeof(indexFileName));
2043
uint16 fileNameLen = *(uint16*)(rowData);
2044
strncpy(indexFileName, rowData + sizeof(uint16), fileNameLen);
2046
int bytesToRetain = fileNameLen - tableNameLen;
2047
if (bytesToRetain <= 0)
2048
/* We can't handle index names in which the MySQL index name and
2049
the table name together are longer than the max index name. */
2051
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
2052
DBUG_RETURN(DB2I_ERR_INVALID_NAME);
2054
char indexName[MAX_DB2_FILENAME_LENGTH];
2055
memset(indexName, 0, sizeof(indexName));
2061
char db2IndexName[MAX_DB2_FILENAME_LENGTH+1];
2063
convertMySQLNameToDB2Name(indexFileName, db2IndexName, sizeof(db2IndexName));
2065
query.append(STRING_WITH_LEN("RENAME INDEX "));
2066
query.append(db2FromLibName);
2068
query.append(db2IndexName);
2069
query.append(STRING_WITH_LEN(" TO "));
2070
if (db2i_table::appendQualifiedIndexFileName(indexName, db2ToFileName, query, db2i_table::ASCII_SQL, typeNone) == -1)
2072
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
2073
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
2075
renameQuery.addStatement(query);
2076
DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
2082
bridge()->deallocateFile(queryFile);
2084
if (rc != HA_ERR_END_OF_FILE)
2087
char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
2089
/* Rename the table */
2091
query.append(STRING_WITH_LEN(" RENAME TABLE "));
2092
db2i_table::getDB2QualifiedNameFromPath(from, db2Name);
2093
query.append(db2Name);
2094
query.append(STRING_WITH_LEN(" TO "));
2095
query.append(db2ToFileName);
2096
DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
2097
renameQuery.addStatement(query);
2098
rc = bridge()->execSQL(renameQuery.getPtrToData(),
2099
renameQuery.getStatementCount(),
2103
db2i_table::renameAssocFiles(from, to);
2109
int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
2110
HA_CREATE_INFO *create_info)
2112
DBUG_ENTER("ha_ibmdb2i::create");
2115
char fileSortSequence[11] = "*HEX";
2116
char fileSortSequenceLibrary[11] = "";
2117
char fileSortSequenceType = ' ';
2118
char libName[MAX_DB2_SCHEMANAME_LENGTH+1];
2119
char fileName[MAX_DB2_FILENAME_LENGTH+1];
2120
char colName[MAX_DB2_COLNAME_LENGTH+1];
2122
ulong auto_inc_value;
2124
db2i_table::getDB2LibNameFromPath(name, libName);
2125
db2i_table::getDB2FileNameFromPath(name, fileName);
2127
if (osVersion.v < 6)
2129
if (strlen(libName) >
2130
MAX_DB2_V5R4_LIBNAME_LENGTH + (isOrdinaryIdentifier(libName) ? 2 : 0))
2132
getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V5R4_LIBNAME_LENGTH);
2133
DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
2136
else if (strlen(libName) > MAX_DB2_V6R1_LIBNAME_LENGTH)
2138
getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V6R1_LIBNAME_LENGTH);
2139
DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
2144
if (strcmp(libName, DB2I_TEMP_TABLE_SCHEMA))
2146
query.append(STRING_WITH_LEN("CREATE TABLE "));
2147
query.append(libName);
2149
query.append(fileName);
2150
isTemporary = FALSE;
2154
query.append(STRING_WITH_LEN("DECLARE GLOBAL TEMPORARY TABLE "));
2155
query.append(fileName);
2158
query.append(STRING_WITH_LEN(" ("));
2160
THD* thd = ha_thd();
2161
enum_TimeFormat timeFormat = (enum_TimeFormat)(THDVAR(thd, compat_opt_time_as_duration));
2162
enum_YearFormat yearFormat = (enum_YearFormat)(THDVAR(thd, compat_opt_year_as_int));
2163
enum_BlobMapping blobMapping = (enum_BlobMapping)(THDVAR(thd, compat_opt_blob_cols));
2164
enum_ZeroDate zeroDate = (enum_ZeroDate)(THDVAR(thd, compat_opt_allow_zero_date_vals));
2165
bool propagateDefaults = THDVAR(thd, propagate_default_col_vals);
2168
for (field= table_arg->field; *field; field++)
2170
if ( field != table_arg->field ) // Not the first one
2171
query.append(STRING_WITH_LEN(" , "));
2173
if (!convertMySQLNameToDB2Name((*field)->field_name, colName, sizeof(colName)))
2175
getErrTxt(DB2I_ERR_INVALID_NAME,"field",(*field)->field_name);
2176
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
2179
query.append(colName);
2182
if (rc = getFieldTypeMapping(*field,
2191
if ( (*field)->flags & NOT_NULL_FLAG )
2193
query.append(STRING_WITH_LEN(" NOT NULL "));
2195
if ( (*field)->flags & AUTO_INCREMENT_FLAG )
2197
#ifdef WITH_PARTITION_STORAGE_ENGINE
2198
if (table_arg->part_info)
2200
getErrTxt(DB2I_ERR_PART_AUTOINC);
2201
DBUG_RETURN(DB2I_ERR_PART_AUTOINC);
2204
query.append(STRING_WITH_LEN(" GENERATED BY DEFAULT AS IDENTITY ") );
2205
if (create_info->auto_increment_value != 0)
2207
/* Query was ALTER TABLE...AUTO_INCREMENT = x; or
2208
CREATE TABLE ...AUTO_INCREMENT = x; Set the starting
2209
value for the auto_increment column. */
2210
char stringValue[22];
2211
CHARSET_INFO *cs= &my_charset_bin;
2212
uint len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, create_info->auto_increment_value);
2213
stringValue[len] = 0;
2214
query.append(STRING_WITH_LEN(" (START WITH "));
2215
query.append(stringValue);
2217
uint64 maxValue=maxValueForField(*field);
2221
len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, maxValue);
2222
stringValue[len] = 0;
2223
query.append(STRING_WITH_LEN(" MAXVALUE "));
2224
query.append(stringValue);
2227
query.append(STRING_WITH_LEN(") "));
2233
String fieldDefinition(128);
2235
if (table_arg->s->primary_key != MAX_KEY && !isTemporary)
2237
query.append(STRING_WITH_LEN(", PRIMARY KEY "));
2238
rc = buildIndexFieldList(fieldDefinition,
2239
table_arg->key_info[table_arg->s->primary_key],
2241
&fileSortSequenceType,
2243
fileSortSequenceLibrary);
2244
if (rc) DBUG_RETURN(rc);
2245
query.append(fieldDefinition);
2248
rc = buildDB2ConstraintString(thd->lex,
2252
&fileSortSequenceType,
2254
fileSortSequenceLibrary);
2255
if (rc) DBUG_RETURN (rc);
2257
query.append(STRING_WITH_LEN(" ) "));
2260
query.append(STRING_WITH_LEN(" ON COMMIT PRESERVE ROWS "));
2262
if (create_info->alias)
2263
generateAndAppendRCDFMT(create_info->alias, query);
2264
else if (((TABLE_LIST*)(thd->lex->select_lex.table_list.first))->table_name)
2265
generateAndAppendRCDFMT((char*)((TABLE_LIST*)(thd->lex->select_lex.table_list.first))->table_name, query);
2267
DBUG_PRINT("ha_ibmdb2i::create", ("Sent to DB2: %s",query.c_ptr()));
2268
SqlStatementStream sqlStream(query.length());
2269
sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
2271
if (table_arg->s->primary_key != MAX_KEY &&
2273
(THDVAR(thd, create_index_option)==1) &&
2274
(fileSortSequenceType != 'B') &&
2275
(fileSortSequenceType != ' '))
2277
rc = generateShadowIndex(sqlStream,
2278
table_arg->key_info[table_arg->s->primary_key],
2282
if (rc) DBUG_RETURN(rc);
2284
for (uint i = 0; i < table_arg->s->keys; ++i)
2286
if (i != table_arg->s->primary_key || isTemporary)
2288
rc = buildCreateIndexStatement(sqlStream,
2289
table_arg->key_info[i],
2293
if (rc) DBUG_RETURN (rc);
2297
bool noCommit = isTemporary || ((!autoCommitIsOn(thd)) && (thd_sql_command(thd) == SQLCOM_ALTER_TABLE));
2301
// if (THDVAR(thd, discovery_mode) == 1)
2302
// bridge()->expectErrors(QMY_ERR_TABLE_EXISTS);
2304
rc = bridge()->execSQL(sqlStream.getPtrToData(),
2305
sqlStream.getStatementCount(),
2306
(isTemporary ? QMY_NONE : getCommitLevel(thd)),
2311
if (unlikely(rc == QMY_ERR_MSGID) &&
2312
memcmp(bridge()->getErrorMsgID(), DB2I_SQL0350, 7) == 0)
2314
my_error(ER_BLOB_USED_AS_KEY, MYF(0), "*unknown*");
2315
rc = ER_BLOB_USED_AS_KEY;
2317
/* else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) &&
2318
THDVAR(thd, discovery_mode) == 1)
2320
db2i_table* temp = new db2i_table(table_arg->s, name);
2321
int32 rc = temp->fastInitForCreate(name);
2325
warning(thd, DB2I_ERR_WARN_CREATE_DISCOVER);
2331
if (!rc && !isTemporary)
2333
db2i_table* temp = new db2i_table(table_arg->s, name);
2334
rc = temp->fastInitForCreate(name);
2346
Add an index on-line to a table. This method is called on behalf of
2347
a CREATE INDEX or ALTER TABLE statement.
2348
It is implemented via a composed DDL statement passed to DB2.
2350
int ha_ibmdb2i::add_index(TABLE *table_arg,
2354
DBUG_ENTER("ha_ibmdb2i::add_index");
2357
SqlStatementStream sqlStream(256);
2358
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
2359
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
2361
quiesceAllFileHandles();
2363
uint primaryKey = MAX_KEY;
2364
if (table_arg->s->primary_key >= MAX_KEY && !db2Table->isTemporary())
2366
for (int i = 0; i < num_of_keys; ++i)
2368
if (strcmp(key_info[i].name, "PRIMARY") == 0)
2373
else if (primaryKey == MAX_KEY &&
2374
key_info[i].flags & HA_NOSAME)
2377
for (int j=0 ; j < key_info[i].key_parts ;j++)
2379
uint fieldnr= key_info[i].key_part[j].fieldnr;
2380
if (table_arg->s->field[fieldnr]->null_ptr ||
2381
table_arg->s->field[fieldnr]->key_length() !=
2382
key_info[i].key_part[j].length)
2384
primaryKey = MAX_KEY;
2393
for (int i = 0; i < num_of_keys; ++i)
2395
KEY& curKey= key_info[i];
2396
rc = buildCreateIndexStatement(sqlStream,
2401
if (rc) DBUG_RETURN (rc);
2404
rc = bridge()->execSQL(sqlStream.getPtrToData(),
2405
sqlStream.getStatementCount(),
2412
/* Handle the case where a unique index is being created but an error occurs
2413
because the file contains duplicate key values. */
2414
if (rc == ER_DUP_ENTRY)
2415
print_keydup_error(MAX_KEY,ER(ER_DUP_ENTRY_WITH_KEY_NAME));
2422
Drop an index on-line from a table. This method is called on behalf of
2423
a DROP INDEX or ALTER TABLE statement.
2424
It is implemented via a composed DDL statement passed to DB2.
2426
int ha_ibmdb2i::prepare_drop_index(TABLE *table_arg,
2427
uint *key_num, uint num_of_keys)
2429
DBUG_ENTER("ha_ibmdb2i::prepare_drop_index");
2433
SqlStatementStream sqlStream(64 * num_of_keys);
2434
SqlStatementStream shadowStream(64 * num_of_keys);
2436
quiesceAllFileHandles();
2438
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
2439
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
2441
while (i < num_of_keys)
2444
DBUG_PRINT("info", ("ha_ibmdb2i::prepare_drop_index %u", key_num[i]));
2445
KEY& curKey= table_arg->key_info[key_num[i]];
2446
if (key_num[i] == table->s->primary_key && !db2Table->isTemporary())
2448
query.append(STRING_WITH_LEN("ALTER TABLE "));
2449
query.append(libName);
2450
query.append(STRING_WITH_LEN("."));
2451
query.append(fileName);
2452
query.append(STRING_WITH_LEN(" DROP PRIMARY KEY"));
2456
query.append(STRING_WITH_LEN("DROP INDEX "));
2457
query.append(libName);
2458
query.append(STRING_WITH_LEN("."));
2459
db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query);
2461
DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
2462
sqlStream.addStatement(query);
2465
query.append(STRING_WITH_LEN("DROP INDEX "));
2466
query.append(libName);
2467
query.append(STRING_WITH_LEN("."));
2468
db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query, db2i_table::ASCII_SQL, typeHex);
2470
DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
2471
shadowStream.addStatement(query);
2476
rc = bridge()->execSQL(sqlStream.getPtrToData(),
2477
sqlStream.getStatementCount(),
2485
bridge()->execSQL(shadowStream.getPtrToData(),
2486
shadowStream.getStatementCount(),
2494
ha_ibmdb2i::unlock_row()
2496
DBUG_ENTER("ha_ibmdb2i::unlock_row");
2501
ha_ibmdb2i::index_end()
2503
DBUG_ENTER("ha_ibmdb2i::index_end");
2504
warnIfInvalidData();
2505
last_index_init_rc = 0;
2506
if (likely(activeReadBuf))
2507
activeReadBuf->endRead();
2508
if (likely(!last_index_init_rc))
2509
releaseIndexFile(active_index);
2510
active_index= MAX_KEY;
2514
int ha_ibmdb2i::doCommit(handlerton *hton, THD *thd, bool all)
2516
if (!THDVAR(thd, transaction_unsafe))
2518
if (all || autoCommitIsOn(thd))
2520
DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing all"));
2521
return (db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_COMMIT));
2525
DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing stmt"));
2526
return (db2i_ileBridge::getBridgeForThread(thd)->commitStmtTx());
2534
int ha_ibmdb2i::doRollback(handlerton *hton, THD *thd, bool all)
2536
if (!THDVAR(thd,transaction_unsafe))
2538
if (all || autoCommitIsOn(thd))
2540
DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back all"));
2541
return ( db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_ROLLBACK));
2545
DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back stmt"));
2546
return (db2i_ileBridge::getBridgeForThread(thd)->rollbackStmtTx());
2553
void ha_ibmdb2i::start_bulk_insert(ha_rows rows)
2555
DBUG_ENTER("ha_ibmdb2i::start_bulk_insert");
2556
DBUG_PRINT("ha_ibmdb2i::start_bulk_insert",("Rows hinted %d", rows));
2558
THD* thd = ha_thd();
2559
int command = thd_sql_command(thd);
2561
if (db2Table->hasBlobs() ||
2562
(command == SQLCOM_REPLACE || command == SQLCOM_REPLACE_SELECT))
2565
rows = DEFAULT_MAX_ROWS_TO_BUFFER; // Shoot the moon
2567
// If we're doing a multi-row insert, binlogging is active, and the table has an
2568
// auto_increment column, then we'll attempt to lock the file while we perform a 'fast path' blocked
2569
// insert. If we can't get the lock, then we'll do a row-by-row 'slow path' insert instead. The reason is
2570
// because the MI generates the auto_increment (identity value), and if we can't lock the file,
2571
// then we can't predetermine what that value will be for insertion into the MySQL write buffer.
2573
if ((rows > 1) && // Multi-row insert
2574
(thd->options & OPTION_BIN_LOG) && // Binlogging is on
2575
(table->found_next_number_field)) // Table has an auto_increment column
2578
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
2580
rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LEAR, QMY_YES);
2581
if (rc==0) // Got the lock
2583
autoIncLockAcquired = TRUE;
2584
got_auto_inc_values = FALSE;
2586
else // Didn't get the lock
2587
rows = 1; // No problem, but don't block inserts
2590
if (activeHandle == 0)
2592
last_start_bulk_insert_rc = useDataFile();
2593
if (last_start_bulk_insert_rc == 0)
2594
last_start_bulk_insert_rc = prepWriteBuffer(rows, db2Table->dataFile());
2597
if (last_start_bulk_insert_rc == 0)
2598
outstanding_start_bulk_insert = true;
2601
if (autoIncLockAcquired == TRUE)
2603
bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
2604
autoIncLockAcquired = FALSE;
2612
int ha_ibmdb2i::end_bulk_insert()
2614
DBUG_ENTER("ha_ibmdb2i::end_bulk_insert");
2617
if (outstanding_start_bulk_insert)
2619
rc = finishBulkInsert();
2628
int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent)
2630
DBUG_ENTER("ha_ibmdb2i::prepReadBuffer");
2631
DBUG_ASSERT(rowsToRead > 0);
2633
THD* thd = ha_thd();
2634
char cmtLvl = getCommitLevel(thd);
2636
const db2i_file::RowFormat* format;
2637
int rc = file->obtainRowFormat(activeHandle, intent, cmtLvl, &format);
2639
if (unlikely(rc)) DBUG_RETURN(rc);
2641
if (lobFieldsRequested())
2643
forceSingleRowRead = true;
2647
rowsToRead = min(stats.records+1,min(rowsToRead, DEFAULT_MAX_ROWS_TO_BUFFER));
2649
uint bufSize = min((format->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size));
2650
multiRowReadBuf.allocBuf(format->readRowLen, format->readRowNullOffset, bufSize);
2651
activeReadBuf = &multiRowReadBuf;
2653
if (db2Table->hasBlobs())
2655
if (!blobReadBuffers)
2656
blobReadBuffers = new BlobCollection(db2Table, THDVAR(thd, lob_alloc_size));
2657
rc = prepareReadBufferForLobs();
2658
if (rc) DBUG_RETURN(rc);
2661
// if (accessIntent == QMY_UPDATABLE &&
2662
// thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
2663
// !THDVAR(thd, transaction_unsafe))
2664
// activeReadBuf->update(QMY_READ_ONLY, &releaseRowNeeded, QMY_REPEATABLE_READ);
2666
activeReadBuf->update(intent, &releaseRowNeeded, cmtLvl);
2672
int ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file)
2674
DBUG_ENTER("ha_ibmdb2i::prepWriteBuffer");
2675
DBUG_ASSERT(accessIntent == QMY_UPDATABLE && rowsToWrite > 0);
2677
const db2i_file::RowFormat* format;
2678
int rc = file->obtainRowFormat(activeHandle,
2680
getCommitLevel(ha_thd()),
2683
if (unlikely(rc)) DBUG_RETURN(rc);
2685
rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER);
2687
uint bufSize = min((format->writeRowLen * rowsToWrite), THDVAR(ha_thd(), max_write_buffer_size));
2688
multiRowWriteBuf.allocBuf(format->writeRowLen, format->writeRowNullOffset, bufSize);
2689
activeWriteBuf = &multiRowWriteBuf;
2691
if (!blobWriteBuffers && db2Table->hasBlobs())
2693
blobWriteBuffers = new ValidatedPointer<char>[db2Table->getBlobCount()];
2699
int ha_ibmdb2i::flushWrite(FILE_HANDLE fileHandle, uchar* buf )
2701
DBUG_ENTER("ha_ibmdb2i::flushWrite");
2703
int64 generatedIdValue = 0;
2704
bool IdValueWasGenerated = FALSE;
2705
char* lastDupKeyNamePtr = NULL;
2706
uint32 lastDupKeyNameLen = 0;
2708
bool retry_dup = FALSE;
2710
while (loopCnt == 0 || retry_dup == TRUE)
2712
rc = bridge()->writeRows(fileHandle,
2713
activeWriteBuf->ptr(),
2716
&IdValueWasGenerated,
2723
invalidateCachedStats();
2724
if (lastDupKeyNameLen)
2726
rrnAssocHandle = fileHandle;
2728
int command = thd_sql_command(ha_thd());
2730
if (command == SQLCOM_REPLACE ||
2731
command == SQLCOM_REPLACE_SELECT)
2735
lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen);
2737
if (likely(lastDupKeyID != MAX_KEY))
2739
uint16 failedRow = activeWriteBuf->rowsWritten()+1;
2741
if (buf && (failedRow != activeWriteBuf->rowCount()))
2743
const char* badRow = activeWriteBuf->getRowN(failedRow-1);
2744
bool savedReadAllColumns = readAllColumns;
2745
readAllColumns = true;
2748
badRow + activeWriteBuf->getRowNullOffset(),
2750
readAllColumns = savedReadAllColumns;
2752
if (table->found_next_number_field)
2754
table->next_number_field->store(next_identity_value - (incrementByValue * (activeWriteBuf->rowCount() - (failedRow - 1))));
2758
if (default_identity_value && // Table has ID colm and generating a value
2759
(!autoIncLockAcquired || !got_auto_inc_values) &&
2760
// Writing first or only row in block
2761
loopCnt == 1 && // Didn't already retry
2762
lastDupKeyID == table->s->next_number_index) // Autoinc column is in failed index
2764
if (alterStartWith() == 0) // Reset next Identity value to max+1
2765
retry_dup = TRUE; // Rtry the write operation
2770
char unknownIndex[MAX_DB2_FILENAME_LENGTH+1];
2771
convFromEbcdic(lastDupKeyNamePtr, unknownIndex, min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH));
2772
unknownIndex[min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH)] = 0;
2773
getErrTxt(DB2I_ERR_UNKNOWN_IDX, unknownIndex);
2779
if ((rc == 0 || rc == HA_ERR_FOUND_DUPP_KEY)
2780
&& default_identity_value && IdValueWasGenerated &&
2781
(!autoIncLockAcquired || !got_auto_inc_values))
2783
/* Save the generated identity value for the MySQL last_insert_id() function. */
2784
insert_id_for_cur_row = generatedIdValue;
2786
/* Store the value into MySQL's buf for row-based replication
2787
or for an 'on duplicate key update' clause. */
2788
table->next_number_field->store((longlong) generatedIdValue, TRUE);
2789
if (autoIncLockAcquired)
2791
got_auto_inc_values = TRUE;
2792
next_identity_value = generatedIdValue + incrementByValue;
2797
if (!autoIncLockAcquired) // Don't overlay value for first row of a block
2798
insert_id_for_cur_row = 0;
2802
activeWriteBuf->resetAfterWrite();
2806
int ha_ibmdb2i::alterStartWith()
2808
DBUG_ENTER("ha_ibmdb2i::alterStartWith");
2810
ulonglong nextIdVal;
2812
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
2813
if (!rc) {rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LENR, QMY_YES);}
2816
rc = getNextIdVal(&nextIdVal);
2817
if (!rc) {rc = reset_auto_increment(nextIdVal);}
2818
bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LENR, QMY_YES);
2823
bool ha_ibmdb2i::lobFieldsRequested()
2825
if (!db2Table->hasBlobs())
2827
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs"));
2833
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("All cols requested"));
2837
for (int i = 0; i < db2Table->getBlobCount(); ++i)
2839
if (bitmap_is_set(table->read_set, db2Table->blobFields[i]))
2841
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("LOB requested"));
2846
DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs requested"));
2851
int ha_ibmdb2i::prepareReadBufferForLobs()
2853
DBUG_ENTER("ha_ibmdb2i::prepareReadBufferForLobs");
2854
DBUG_ASSERT(db2Table->hasBlobs());
2856
uint32 activeLobFields = 0;
2857
DB2LobField* lobField;
2858
uint16 blobCount = db2Table->getBlobCount();
2860
char* readBuf = activeReadBuf->getRowN(0);
2862
for (int i = 0; i < blobCount; ++i)
2864
int fieldID = db2Table->blobFields[i];
2865
DB2Field& db2Field = db2Table->db2Field(fieldID);
2866
lobField = db2Field.asBlobField(readBuf);
2867
if (readAllColumns ||
2868
bitmap_is_set(table->read_set, fieldID))
2870
lobField->dataHandle = (ILEMemHandle)blobReadBuffers->getBufferPtr(fieldID);
2875
lobField->dataHandle = NULL;
2879
if (activeLobFields == 0)
2881
for (int i = 0; i < blobCount; ++i)
2883
DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
2884
uint16 offset = db2Field.getBufferOffset() + db2Field.calcBlobPad();
2886
for (int r = 1; r < activeReadBuf->getRowCapacity(); ++r)
2888
lobField = (DB2LobField*)(activeReadBuf->getRowN(r) + offset);
2889
lobField->dataHandle = NULL;
2894
activeReadBuf->setRowsToProcess((activeLobFields ? 1 : activeReadBuf->getRowCapacity()));
2895
int rc = bridge()->objectOverride(activeHandle,
2896
activeReadBuf->ptr(),
2897
activeReadBuf->getRowLength());
2902
uint32 ha_ibmdb2i::adjustLobBuffersForRead()
2904
DBUG_ENTER("ha_ibmdb2i::adjustLobBuffersForRead");
2906
char* readBuf = activeReadBuf->getRowN(0);
2908
for (int i = 0; i < db2Table->getBlobCount(); ++i)
2910
DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
2911
DB2LobField* lobField = db2Field.asBlobField(readBuf);
2912
if (readAllColumns ||
2913
bitmap_is_set(table->read_set, db2Table->blobFields[i]))
2915
lobField->dataHandle = (ILEMemHandle)blobReadBuffers->reallocBuffer(db2Table->blobFields[i], lobField->length);
2917
if (lobField->dataHandle == NULL)
2918
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
2922
lobField->dataHandle = 0;
2926
int32 rc = bridge()->objectOverride(activeHandle,
2927
activeReadBuf->ptr());
2933
int ha_ibmdb2i::reset()
2935
DBUG_ENTER("ha_ibmdb2i::reset");
2937
if (outstanding_start_bulk_insert)
2942
if (activeHandle != 0)
2944
releaseActiveHandle();
2949
db2i_ileBridge::getBridgeForThread(ha_thd())->freeErrorStorage();
2951
last_rnd_init_rc = last_index_init_rc = last_start_bulk_insert_rc = 0;
2953
returnDupKeysImmediately = false;
2954
onDupUpdate = false;
2955
forceSingleRowRead = false;
2965
int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream,
2968
const char* db2LibName,
2969
const char* db2FileName)
2971
DBUG_ENTER("ha_ibmdb2i::buildCreateIndexStatement");
2973
char fileSortSequence[11] = "*HEX";
2974
char fileSortSequenceLibrary[11] = "";
2975
char fileSortSequenceType = ' ';
2982
query.append(STRING_WITH_LEN("ALTER TABLE "));
2983
query.append(db2LibName);
2985
query.append(db2FileName);
2986
query.append(STRING_WITH_LEN(" ADD PRIMARY KEY "));
2990
query.append(STRING_WITH_LEN("CREATE"));
2992
if (key.flags & HA_NOSAME)
2993
query.append(STRING_WITH_LEN(" UNIQUE WHERE NOT NULL"));
2995
query.append(STRING_WITH_LEN(" INDEX "));
2997
query.append(db2LibName);
2999
if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, query))
3001
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
3002
DBUG_RETURN(DB2I_ERR_INVALID_NAME );
3005
query.append(STRING_WITH_LEN(" ON "));
3007
query.append(db2LibName);
3009
query.append(db2FileName);
3012
String fieldDefinition(128);
3013
rc = buildIndexFieldList(fieldDefinition,
3016
&fileSortSequenceType,
3018
fileSortSequenceLibrary);
3020
if (rc) DBUG_RETURN(rc);
3022
query.append(fieldDefinition);
3024
if ((THDVAR(ha_thd(), create_index_option)==1) &&
3025
(fileSortSequenceType != 'B') &&
3026
(fileSortSequenceType != ' '))
3028
rc = generateShadowIndex(sqlStream,
3033
if (rc) DBUG_RETURN(rc);
3036
DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",query.c_ptr_safe()));
3037
sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
3043
Generate the SQL syntax for the list of fields to be assigned to the
3044
specified key. The corresponding sort sequence is also calculated.
3046
@param[out] appendHere The string to receive the generated SQL
3047
@param key The key to evaluate
3048
@param isPrimary True if this is being generated on behalf of the primary key
3049
@param[out] fileSortSequenceType The type of the associated sort sequence
3050
@param[out] fileSortSequence The name of the associated sort sequence
3051
@param[out] fileSortSequenceLibrary The library of the associated sort sequence
3053
@return 0 if successful; error value otherwise
3055
int32 ha_ibmdb2i::buildIndexFieldList(String& appendHere,
3058
char* fileSortSequenceType,
3059
char* fileSortSequence,
3060
char* fileSortSequenceLibrary)
3062
DBUG_ENTER("ha_ibmdb2i::buildIndexFieldList");
3063
appendHere.append(STRING_WITH_LEN(" ( "));
3064
for (int j = 0; j < key.key_parts; ++j)
3066
char colName[MAX_DB2_COLNAME_LENGTH+1];
3069
appendHere.append(STRING_WITH_LEN(" , "));
3072
KEY_PART_INFO& kpi = key.key_part[j];
3073
Field* field = kpi.field;
3075
convertMySQLNameToDB2Name(field->field_name,
3078
appendHere.append(colName);
3081
rc = updateAssociatedSortSequence(field->charset(),
3082
fileSortSequenceType,
3084
fileSortSequenceLibrary);
3085
if (rc) DBUG_RETURN (rc);
3088
appendHere.append(STRING_WITH_LEN(" ) "));
3095
Generate an SQL statement that defines a *HEX sorted index to implement
3096
the ibmdb2i_create_index.
3098
@param[out] stream The stream to append the generated statement to
3099
@param key The key to evaluate
3100
@param[out] libName The library containg the table
3101
@param[out] fileName The DB2-compatible name of the table
3102
@param[out] fieldDefinition The list of the fields in the index, in SQL syntax
3104
@return 0 if successful; error value otherwise
3106
int32 ha_ibmdb2i::generateShadowIndex(SqlStatementStream& stream,
3108
const char* libName,
3109
const char* fileName,
3110
const String& fieldDefinition)
3112
String shadowQuery(256);
3113
shadowQuery.length(0);
3114
shadowQuery.append(STRING_WITH_LEN("CREATE INDEX "));
3115
shadowQuery.append(libName);
3116
shadowQuery.append('.');
3117
if (db2i_table::appendQualifiedIndexFileName(key.name, fileName, shadowQuery, db2i_table::ASCII_SQL, typeHex))
3119
getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
3120
return DB2I_ERR_INVALID_NAME;
3122
shadowQuery.append(STRING_WITH_LEN(" ON "));
3123
shadowQuery.append(libName);
3124
shadowQuery.append('.');
3125
shadowQuery.append(fileName);
3126
shadowQuery.append(fieldDefinition);
3127
DBUG_PRINT("ha_ibmdb2i::generateShadowIndex", ("Sent to DB2: %s",shadowQuery.c_ptr_safe()));
3128
stream.addStatement(shadowQuery,"*HEX","QSYS");
3133
void ha_ibmdb2i::doInitialRead(char orientation,
3134
uint32 rowsToBuffer,
3139
DBUG_ENTER("ha_ibmdb2i::doInitialRead");
3141
if (forceSingleRowRead)
3144
rowsToBuffer = min(rowsToBuffer, activeReadBuf->getRowCapacity());
3146
activeReadBuf->newReadRequest(activeHandle,
3149
THDVAR(ha_thd(), async_enabled),
3157
int ha_ibmdb2i::start_stmt(THD *thd, thr_lock_type lock_type)
3159
DBUG_ENTER("ha_ibmdb2i::start_stmt");
3161
if (!THDVAR(thd, transaction_unsafe))
3163
trans_register_ha(thd, FALSE, ibmdb2i_hton);
3165
if (!autoCommitIsOn(thd))
3167
bridge()->beginStmtTx();
3174
int32 ha_ibmdb2i::handleLOBReadOverflow()
3176
DBUG_ENTER("ha_ibmdb2i::handleLOBReadOverflow");
3177
DBUG_ASSERT(db2Table->hasBlobs() && (activeReadBuf->getRowCapacity() == 1));
3179
int32 rc = adjustLobBuffersForRead();
3183
activeReadBuf->rewind();
3184
rc = bridge()->expectErrors(QMY_ERR_END_OF_BLOCK)
3185
->read(activeHandle,
3186
activeReadBuf->ptr(),
3190
releaseRowNeeded = TRUE;
3197
int32 ha_ibmdb2i::finishBulkInsert()
3201
if (activeWriteBuf->rowCount() && activeHandle)
3202
rc = flushWrite(activeHandle, table->record[0]);
3205
releaseActiveHandle();
3207
if (autoIncLockAcquired == TRUE)
3209
// We could check the return code on the unlock, but beware not
3210
// to overlay the return code from the flushwrite or we will mask
3211
// duplicate key errors..
3212
bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
3213
autoIncLockAcquired = FALSE;
3215
outstanding_start_bulk_insert = false;
3216
multiRowWriteBuf.freeBuf();
3217
last_start_bulk_insert_rc = 0;
3219
resetCharacterConversionBuffers();
3224
int ha_ibmdb2i::getKeyFromName(const char* name, size_t len)
3226
for (int i = 0; i < table_share->keys; ++i)
3228
const char* indexName = db2Table->indexFile(i)->getDB2FileName();
3229
if ((strncmp(name, indexName, len) == 0) &&
3230
(strlen(indexName) == len))
3239
Determine the number of I/O's it takes to read through the table.
3241
double ha_ibmdb2i::scan_time()
3243
DBUG_ENTER("ha_ibmdb2i::scan_time");
3244
DBUG_RETURN(ulonglong2double((stats.data_file_length)/IO_SIZE));
3249
Estimate the number of I/O's it takes to read a set of ranges through
3256
@return The estimate number of I/Os
3259
double ha_ibmdb2i::read_time(uint index, uint ranges, ha_rows rows)
3261
DBUG_ENTER("ha_ibmdb2i::read_time");
3263
uint64 idxPageCnt = 0;
3266
if (unlikely(rows == HA_POS_ERROR))
3267
DBUG_RETURN(double(rows) + ranges);
3269
rc = bridge()->retrieveIndexInfo(db2Table->indexFile(index)->getMasterDefnHandle(),
3273
if ((idxPageCnt == 1) || // Retrieving rows in requested order or
3274
(ranges == rows)) // 'Sweep' full records retrieval
3275
cost = idxPageCnt/4;
3278
uint64 totalRecords = stats.records + 1;
3279
double dataPageCount = stats.data_file_length/IO_SIZE;
3281
cost = (rows * dataPageCount / totalRecords) +
3282
min(idxPageCnt, (log_2(idxPageCnt) * ranges +
3283
rows * (log_2(idxPageCnt) + log_2(rows) - log_2(totalRecords))));
3288
cost = rows2double(ranges+rows); // Use default costing
3293
int ha_ibmdb2i::useIndexFile(int idx)
3295
DBUG_ENTER("ha_ibmdb2i::useIndexFile");
3298
releaseActiveHandle();
3302
if (!indexHandles[idx])
3303
rc = db2Table->indexFile(idx)->allocateNewInstance(&indexHandles[idx], curConnection);
3307
activeHandle = indexHandles[idx];
3308
bumpInUseCounter(1);
3315
ulong ha_ibmdb2i::index_flags(uint inx, uint part, bool all_parts) const
3317
return HA_READ_NEXT | HA_READ_PREV | HA_KEYREAD_ONLY | HA_READ_ORDER | HA_READ_RANGE;
3321
static struct st_mysql_sys_var* ibmdb2i_system_variables[] = {
3322
MYSQL_SYSVAR(rdb_name),
3323
MYSQL_SYSVAR(transaction_unsafe),
3324
MYSQL_SYSVAR(lob_alloc_size),
3325
MYSQL_SYSVAR(max_read_buffer_size),
3326
MYSQL_SYSVAR(max_write_buffer_size),
3327
MYSQL_SYSVAR(async_enabled),
3328
MYSQL_SYSVAR(assume_exclusive_use),
3329
MYSQL_SYSVAR(compat_opt_blob_cols),
3330
MYSQL_SYSVAR(compat_opt_time_as_duration),
3331
MYSQL_SYSVAR(compat_opt_allow_zero_date_vals),
3332
MYSQL_SYSVAR(compat_opt_year_as_int),
3333
MYSQL_SYSVAR(propagate_default_col_vals),
3334
MYSQL_SYSVAR(create_index_option),
3335
// MYSQL_SYSVAR(discovery_mode),
3336
MYSQL_SYSVAR(system_trace_level),
3341
struct st_mysql_storage_engine ibmdb2i_storage_engine=
3342
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
3344
mysql_declare_plugin(ibmdb2i)
3346
MYSQL_STORAGE_ENGINE_PLUGIN,
3347
&ibmdb2i_storage_engine,
3349
"The IBM development team in Rochester, Minnesota",
3350
"IBM DB2 for i Storage Engine",
3352
ibmdb2i_init_func, /* Plugin Init */
3353
ibmdb2i_done_func, /* Plugin Deinit */
3355
NULL, /* status variables */
3356
ibmdb2i_system_variables, /* system variables */
3357
NULL /* config options */
3359
mysql_declare_plugin_end;