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
36
/** @file ha_ibmdb2i.h
45
#ifdef USE_PRAGMA_INTERFACE
46
#pragma interface /* gcc class implementation */
49
#include "as400_types.h"
50
#include "as400_protos.h"
51
#include "db2i_global.h"
52
#include "db2i_ileBridge.h"
54
#include "db2i_misc.h"
55
#include "db2i_file.h"
56
#include "db2i_blobCollection.h"
57
#include "db2i_collationSupport.h"
58
#include "db2i_validatedPointer.h"
59
#include "db2i_ioBuffers.h"
60
#include "db2i_errors.h"
61
#include "db2i_sqlStatementStream.h"
64
IBMDB2I_SHARE is a structure that will be shared among all open handlers.
65
It is used to describe the underlying table definition, and it caches
68
struct IBMDB2I_SHARE {
70
uint table_name_length,use_count;
71
pthread_mutex_t mutex;
79
void cacheUpdateTime(time_t time)
80
{update_time = time; initFlag |= lastModTime;}
81
time_t getUpdateTime() const
83
void cacheRowCount(ha_rows rows)
84
{records = rows; initFlag |= rowCount;}
85
ha_rows getRowCount() const
87
void cacheDelRowCount(ha_rows rows)
88
{deleted = rows; initFlag |= deletedRowCount;}
89
ha_rows getDelRowCount() const
91
void cacheMeanLength(ulong len)
92
{mean_rec_length = len; initFlag |= meanRowLen;}
94
{return mean_rec_length;}
95
void cacheAugmentedDataLength(ulong len)
96
{data_file_length = len; initFlag |= ioCount;}
97
ulong getAugmentedDataLength()
98
{return data_file_length;}
99
bool isInited(uint flags)
100
{return initFlag & flags;}
101
void invalidate(uint flags)
102
{initFlag &= ~flags;}
109
ulong mean_rec_length;
110
ulong data_file_length;
115
class ha_ibmdb2i: public handler
117
THR_LOCK_DATA lock; ///< MySQL lock
118
IBMDB2I_SHARE *share; ///< Shared lock info
120
// The record we are positioned on, together with the handle used to get
123
uint32 rrnAssocHandle;
125
// Dup key values needed by info()
126
uint32 lastDupKeyRRN;
129
bool returnDupKeysImmediately;
131
// Dup key value need by update()
135
db2i_table* db2Table;
137
// The file handle of the PF or LF being accessed by the current operation.
138
FILE_HANDLE activeHandle;
140
// The file handle of the underlying PF
141
FILE_HANDLE dataHandle;
143
// Array of file handles belonging to the underlying LFs
144
FILE_HANDLE* indexHandles;
146
// Flag to indicate whether a call needs to be made to unlock a row when
147
// a read operation has ended. DB2 will handle row unlocking as we move
148
// through rows, but if an operation ends before we reach the end of a file,
149
// DB2 needs to know to unlock the last row read.
150
bool releaseRowNeeded;
152
// Pointer to a definition of the layout of the row buffer for the file
153
// described by activeHandle
154
const db2i_file::RowFormat* activeFormat;
159
IOWriteBuffer multiRowWriteBuf;
160
IOAsyncReadBuffer multiRowReadBuf;
162
IOAsyncReadBuffer* activeReadBuf;
163
IOWriteBuffer* activeWriteBuf;
165
BlobCollection* blobReadBuffers; // Dynamically allocated per query and used
166
// to manage the buffers used for reading LOBs
167
ValidatedPointer<char>* blobWriteBuffers;
169
// Return codes are not used/honored by rnd_init and start_bulk_insert
170
// so we need a way to signal the failure "downstream" to subsequent
172
int last_rnd_init_rc;
173
int last_index_init_rc;
174
int last_start_bulk_insert_rc;
176
// end_bulk_insert may get called twice for a single start_bulk_insert
177
// This is our way to do cleanup only once.
178
bool outstanding_start_bulk_insert;
180
// Auto_increment 'increment by' value needed by write_row()
181
uint32 incrementByValue;
182
bool default_identity_value;
184
// Flags and values used during write operations for auto_increment processing
185
bool autoIncLockAcquired;
186
bool got_auto_inc_values;
187
uint64 next_identity_value;
189
// The access intent indicated by the last external_locks() call.
190
// May be either QMY_READ or QMY_UPDATABLE
192
char readAccessIntent;
194
ha_rows* indexReadSizeEstimates;
196
MEM_ROOT conversionBufferMemroot;
198
bool forceSingleRowRead;
202
bool invalidDataFound;
204
db2i_ileBridge* cachedBridge;
206
ValidatedObject<volatile uint32> curConnection;
207
uint16 activeReferences;
211
ha_ibmdb2i(handlerton *hton, TABLE_SHARE *table_arg);
214
const char *table_type() const { return "IBMDB2I"; }
215
const char *index_type(uint inx) { return "RADIX"; }
216
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
217
const char **bas_ext() const;
219
ulonglong table_flags() const
221
return HA_NULL_IN_KEY | HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY |
222
HA_PARTIAL_COLUMN_READ |
223
HA_DUPLICATE_POS | HA_NO_PREFIX_CHAR_KEYS |
224
HA_HAS_RECORDS | HA_BINLOG_ROW_CAPABLE | HA_REQUIRES_KEY_COLUMNS_FOR_DELETE |
228
ulong index_flags(uint inx, uint part, bool all_parts) const;
230
// Note that we do not implement max_supported_record_length.
231
// We'll let create fail accordingly if the row is
232
// too long. This allows us to hide the fact that varchars > 32K are being
233
// implemented as DB2 LOBs.
235
uint max_supported_keys() const { return 4000; }
236
uint max_supported_key_parts() const { return MAX_DB2_KEY_PARTS; }
237
uint max_supported_key_length() const { return 32767; }
238
uint max_supported_key_part_length() const { return 32767; }
239
double read_time(uint index, uint ranges, ha_rows rows);
241
int open(const char *name, int mode, uint test_if_locked);
243
int write_row(uchar * buf);
244
int update_row(const uchar * old_data, uchar * new_data);
245
int delete_row(const uchar * buf);
246
int index_init(uint idx, bool sorted);
247
int index_read(uchar * buf, const uchar * key,
248
uint key_len, enum ha_rkey_function find_flag);
249
int index_next(uchar * buf);
250
int index_read_last(uchar * buf, const uchar * key, uint key_len);
251
int index_next_same(uchar *buf, const uchar *key, uint keylen);
252
int index_prev(uchar * buf);
253
int index_first(uchar * buf);
254
int index_last(uchar * buf);
255
int rnd_init(bool scan);
257
int rnd_next(uchar *buf);
258
int rnd_pos(uchar * buf, uchar *pos);
259
void position(const uchar *record);
262
int extra(enum ha_extra_function operation);
263
int external_lock(THD *thd, int lock_type);
264
int delete_all_rows(void);
265
ha_rows records_in_range(uint inx, key_range *min_key,
267
int delete_table(const char *from);
268
int rename_table(const char * from, const char * to);
269
int create(const char *name, TABLE *form,
270
HA_CREATE_INFO *create_info);
271
int updateFrm(TABLE *table_def, File file);
272
int openTableDef(TABLE *table_def);
273
int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
274
int prepare_drop_index(TABLE *table_arg, uint *key_num, uint num_of_keys);
275
int final_drop_index(TABLE *table_arg) {return 0;}
276
void get_auto_increment(ulonglong offset, ulonglong increment,
277
ulonglong nb_desired_values,
278
ulonglong *first_value,
279
ulonglong *nb_reserved_values);
280
int reset_auto_increment(ulonglong value);
281
void restore_auto_increment(ulonglong prev_insert_id) {return;}
282
void update_create_info(HA_CREATE_INFO *create_info);
283
int getNextIdVal(ulonglong *value);
284
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
285
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
286
bool can_switch_engines();
287
void free_foreign_key_create_info(char* str);
288
char* get_foreign_key_create_info();
289
int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
290
uint referenced_by_foreign_key();
291
bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
292
virtual bool get_error_message(int error, String *buf);
294
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
295
enum thr_lock_type lock_type);
297
bool low_byte_first() const { return 0; }
301
static int doCommit(handlerton *hton, THD *thd, bool all);
302
static int doRollback(handlerton *hton, THD *thd, bool all);
303
void start_bulk_insert(ha_rows rows);
304
int end_bulk_insert();
305
int start_stmt(THD *thd, thr_lock_type lock_type);
307
void initBridge(THD* thd = NULL)
309
if (thd == NULL) thd = ha_thd();
310
DBUG_PRINT("ha_ibmdb2i::initBridge",("Initing bridge. Conn ID=%d", thd->thread_id));
311
cachedBridge = db2i_ileBridge::getBridgeForThread(thd);
314
db2i_ileBridge* bridge() {DBUG_ASSERT(cachedBridge); return cachedBridge;}
316
static uint8 autoCommitIsOn(THD* thd)
317
{ return (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ? QMY_NO : QMY_YES); }
319
uint8 getCommitLevel();
320
uint8 getCommitLevel(THD* thd);
322
static int doSavepointSet(THD* thd, char* name)
324
return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_SET_SAVEPOINT,
328
static int doSavepointRollback(THD* thd, char* name)
330
return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_ROLLBACK_SAVEPOINT,
334
static int doSavepointRelease(THD* thd, char* name)
336
return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_RELEASE_SAVEPOINT,
340
// We can't guarantee that the rows we know about when this is called
341
// will be the same number of rows that read returns (since DB2 activity
342
// may insert additional rows). Therefore, we do as the Federated SE and
343
// return the max possible.
344
ha_rows estimate_rows_upper_bound()
358
enum enum_BlobMapping
367
SUBSTITUTE_0001_01_01
376
enum_ZeroDate cachedZeroDateOption;
378
IBMDB2I_SHARE *get_share(const char *table_name, TABLE *table);
379
int free_share(IBMDB2I_SHARE *share);
380
int32 mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs);
381
int prepareRowForWrite(char* data, char* nulls, bool honorIdentCols);
382
int prepareReadBufferForLobs();
383
int32 prepareWriteBufferForLobs();
384
uint32 adjustLobBuffersForRead();
385
bool lobFieldsRequested();
386
int convertFieldChars(enum_conversionDirection direction,
393
bool tacitErrors=FALSE,
394
size_t* substChars=NULL);
397
Fast integer log2 function
399
uint64 log_2(uint64 val)
402
while( (val >> exp) != 0)
406
DBUG_ASSERT(exp-1 == (uint64)log2(val));
410
void bumpInUseCounter(uint16 amount)
412
activeReferences += amount;
413
DBUG_PRINT("ha_ibmdb2i::bumpInUseCounter", ("activeReferences = %d", activeReferences));
414
if (activeReferences)
415
curConnection = (uint32)(ha_thd()->thread_id);
423
DBUG_ENTER("ha_ibmdb2i::useDataFile");
427
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
428
else if (activeHandle == dataHandle)
431
DBUG_ASSERT(activeHandle == 0);
435
activeHandle = dataHandle;
442
void releaseAnyLockedRows()
444
if (releaseRowNeeded)
446
DBUG_PRINT("ha_ibmdb2i::releaseAnyLockedRows", ("Releasing rows"));
447
db2i_ileBridge::getBridgeForThread()->rrlslck(activeHandle, accessIntent);
448
releaseRowNeeded = FALSE;
453
void releaseDataFile()
455
DBUG_ENTER("ha_ibmdb2i::releaseDataFile");
456
releaseAnyLockedRows();
457
bumpInUseCounter(-1);
458
DBUG_ASSERT((volatile int)activeReferences >= 0);
463
int useIndexFile(int idx);
465
void releaseIndexFile(int idx)
467
DBUG_ENTER("ha_ibmdb2i::releaseIndexFile");
468
releaseAnyLockedRows();
469
bumpInUseCounter(-1);
470
DBUG_ASSERT((volatile int)activeReferences >= 0);
475
FILE_HANDLE allocateFileHandle(char* database, char* table, int* activityReference, bool hasBlobs);
477
int updateBuffers(const db2i_file::RowFormat* format, uint rowsToRead, uint rowsToWrite);
479
int flushWrite(FILE_HANDLE fileHandle, uchar* buf = NULL);
481
int alterStartWith();
483
int buildDB2ConstraintString(LEX* lex,
485
const char* database,
487
char* fileSortSequenceType,
488
char* fileSortSequence,
489
char* fileSortSequenceLibrary);
491
void releaseWriteBuffer();
493
void setIndexReadEstimate(uint index, ha_rows rows)
495
if (!indexReadSizeEstimates)
497
indexReadSizeEstimates = (ha_rows*)my_malloc(sizeof(ha_rows) * table->s->keys, MYF(MY_WME | MY_ZEROFILL));
499
indexReadSizeEstimates[index] = rows;
502
ha_rows getIndexReadEstimate(uint index)
504
if (indexReadSizeEstimates)
505
return max(indexReadSizeEstimates[index], 1);
507
return 10000; // Assume index scan if no estimate exists.
511
void quiesceAllFileHandles()
513
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread();
516
bridge->quiesceFileInstance(dataHandle);
519
for (int idx = 0; idx < table_share->keys; ++idx)
521
if (indexHandles[idx] != 0)
523
bridge->quiesceFileInstance(indexHandles[idx]);
528
int32 buildCreateIndexStatement(SqlStatementStream& sqlStream,
531
const char* db2LibName,
532
const char* db2FileName);
534
int32 buildIndexFieldList(String& appendHere,
537
char* fileSortSequenceType,
538
char* fileSortSequence,
539
char* fileSortSequenceLibrary);
541
// Specify NULL for data when using the data pointed to by field
542
int32 convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char* db2Buf, const uchar* data = NULL);
544
int32 convertDB2toMySQL(const DB2Field& db2Field, Field* field, const char* buf);
545
int getFieldTypeMapping(Field* field,
547
enum_TimeFormat timeFormate,
548
enum_BlobMapping blobMapping,
549
enum_ZeroDate zeroDateHandling,
550
bool propagateDefaults,
551
enum_YearFormat yearFormat);
553
int getKeyFromName(const char* name, size_t len);
555
void releaseActiveHandle()
557
if (activeHandle == dataHandle)
560
releaseIndexFile(active_index);
564
int32 finishBulkInsert();
566
void doInitialRead(char orientation,
568
ILEMemHandle key = 0,
573
int32 readFromBuffer(uchar* destination, char orientation)
577
row = activeReadBuf->readNextRow(orientation, currentRRN);
581
rc = activeReadBuf->lastrc();
582
if (rc == QMY_ERR_LOB_SPACE_TOO_SMALL)
584
rc = handleLOBReadOverflow();
587
DBUG_ASSERT(activeReadBuf->rowCount() == 1);
588
row = activeReadBuf->readNextRow(orientation, currentRRN);
591
rc = activeReadBuf->lastrc();
598
rrnAssocHandle = activeHandle;
599
rc = mungeDB2row(destination, row, row+activeReadBuf->getRowNullOffset(), false);
604
int32 handleLOBReadOverflow();
606
char* getCharacterConversionBuffer(int fieldId, int length)
608
if (unlikely(!alloc_root_inited(&conversionBufferMemroot)))
609
init_alloc_root(&conversionBufferMemroot, 8192, 0);
611
return (char*)alloc_root(&conversionBufferMemroot, length);;
614
void resetCharacterConversionBuffers()
616
if (alloc_root_inited(&conversionBufferMemroot))
618
free_root(&conversionBufferMemroot, MYF(MY_MARK_BLOCKS_FREE));
625
int command = thd_sql_command(thd);
626
if ((command == SQLCOM_UPDATE ||
627
command == SQLCOM_UPDATE_MULTI) ||
628
((command == SQLCOM_DELETE ||
629
command == SQLCOM_DELETE_MULTI) &&
630
thd->options & OPTION_BIN_LOG))
631
readAllColumns = TRUE;
633
readAllColumns = FALSE;
639
int useFileByHandle(char intent,
642
DBUG_ENTER("ha_ibmdb2i::useFileByHandle");
644
const db2i_file* file;
645
if (handle == dataHandle)
646
file = db2Table->dataFile();
649
for (uint i = 0; i < table_share->keys; ++i)
651
if (indexHandles[i] == handle)
653
file = db2Table->indexFile(i);
659
int rc = file->obtainRowFormat(handle, intent, getCommitLevel(), &activeFormat);
662
activeHandle = handle;
669
const db2i_file* getFileForActiveHandle() const
671
if (activeHandle == dataHandle)
672
return db2Table->dataFile();
674
for (uint i = 0; i < table_share->keys; ++i)
675
if (indexHandles[i] == activeHandle)
676
return db2Table->indexFile(i);
681
int prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent);
682
int prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file);
684
void invalidateCachedStats()
686
share->cachedStats.invalidate(rowCount | deletedRowCount | objLength |
687
meanRowLen | ioCount);
690
void warnIfInvalidData()
692
if (unlikely(invalidDataFound))
694
warning(ha_thd(), DB2I_ERR_INVALID_DATA, table->alias);
699
Calculate the maximum value that a particular field can hold.
701
This is used to anticipate overflows in the auto_increment processing.
703
@param field The Field to be analyzed
705
@return The maximum value
707
static uint64 maxValueForField(const Field* field)
710
switch (field->type())
712
case MYSQL_TYPE_TINY:
713
if (((const Field_num*)field)->unsigned_flag)
714
maxValue = (1 << 8) - 1;
716
maxValue = (1 << 7) - 1;
718
case MYSQL_TYPE_SHORT:
719
if (((const Field_num*)field)->unsigned_flag)
720
maxValue = (1 << 16) - 1;
722
maxValue = (1 << 15) - 1;
724
case MYSQL_TYPE_INT24:
725
if (((const Field_num*)field)->unsigned_flag)
726
maxValue = (1 << 24) - 1;
728
maxValue = (1 << 23) - 1;
730
case MYSQL_TYPE_LONG:
731
if (((const Field_num*)field)->unsigned_flag)
732
maxValue = (1LL << 32) - 1;
734
maxValue = (1 << 31) - 1;
736
case MYSQL_TYPE_LONGLONG:
737
if (((const Field_num*)field)->unsigned_flag)
740
maxValue = 1 << 63 - 1;
747
void cleanupBuffers()
751
delete blobReadBuffers;
752
blobReadBuffers = NULL;
754
if (blobWriteBuffers)
756
delete[] blobWriteBuffers;
757
blobWriteBuffers = NULL;
759
if (alloc_root_inited(&conversionBufferMemroot))
761
free_root(&conversionBufferMemroot, MYF(0));
767
Generate a valid RCDFMT name based on the name of the table.
769
The RCDFMT name is devised by munging the name of the table,
770
uppercasing all ascii alpha-numeric characters and replacing all other
771
characters with underscores until up to ten characters have been generated.
773
@param tableName The name of the table, as given on the MySQL
774
CREATE TABLE statement
775
@param[out] query The string to receive the generated RCDFMT name
777
static void generateAndAppendRCDFMT(const char* tableName, String& query)
781
// The RCDFMT name must begin with an alpha character.
782
// We enforce this by skipping to the first alpha character in the table
783
// name. If no alpha character exists, we use 'X' for the RCDFMT name;
786
(!my_isascii(*tableName) ||
787
!my_isalpha(system_charset_info, *tableName)))
789
tableName += my_mbcharlen(system_charset_info, *tableName);
792
if (unlikely(!(*tableName)))
800
while ((r < sizeof(rcdfmt)-1) && *tableName)
802
if (my_isascii(*tableName) &&
803
my_isalnum(system_charset_info, *tableName))
804
rcdfmt[r] = my_toupper(system_charset_info, *tableName);
809
tableName += my_mbcharlen(system_charset_info, *tableName);
813
query.append(STRING_WITH_LEN(" RCDFMT "));
814
query.append(rcdfmt);
817
int32 generateShadowIndex(SqlStatementStream& stream,
820
const char* fileName,
821
const String& fieldDefinition);