~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/ibmdb2i/ha_ibmdb2i.h

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Licensed Materials - Property of IBM
 
3
DB2 Storage Engine Enablement
 
4
Copyright IBM Corporation 2007,2008
 
5
All rights reserved
 
6
 
 
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
 
11
     list of conditions. 
 
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 
 
22
       All rights reserved
 
23
 
 
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
 
33
OF SUCH DAMAGE.
 
34
*/
 
35
 
 
36
/** @file ha_ibmdb2i.h
 
37
 
 
38
    @brief
 
39
 
 
40
    @note
 
41
 
 
42
   @see
 
43
*/
 
44
 
 
45
#ifdef USE_PRAGMA_INTERFACE
 
46
#pragma interface                        /* gcc class implementation */
 
47
#endif
 
48
 
 
49
#include "as400_types.h"
 
50
#include "as400_protos.h"
 
51
#include "db2i_global.h"
 
52
#include "db2i_ileBridge.h"
 
53
#include "builtins.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"
 
62
  
 
63
/** @brief
 
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
 
66
  table statistics.
 
67
*/
 
68
struct IBMDB2I_SHARE {
 
69
  char *table_name;
 
70
  uint table_name_length,use_count;
 
71
  pthread_mutex_t mutex;
 
72
  THR_LOCK lock;
 
73
  
 
74
  db2i_table* db2Table;
 
75
 
 
76
  class CStats
 
77
  {
 
78
    public:
 
79
      void cacheUpdateTime(time_t time) 
 
80
        {update_time = time; initFlag |= lastModTime;}
 
81
      time_t getUpdateTime() const 
 
82
        {return update_time;}
 
83
      void cacheRowCount(ha_rows rows) 
 
84
        {records = rows; initFlag |= rowCount;}
 
85
      ha_rows getRowCount() const 
 
86
        {return records;}
 
87
      void cacheDelRowCount(ha_rows rows) 
 
88
        {deleted = rows; initFlag |= deletedRowCount;}
 
89
      ha_rows getDelRowCount() const 
 
90
        {return deleted;}
 
91
      void cacheMeanLength(ulong len) 
 
92
        {mean_rec_length = len; initFlag |= meanRowLen;}
 
93
      ulong getMeanLength()
 
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;}
 
103
    
 
104
    private:
 
105
    uint initFlag;
 
106
    time_t update_time;
 
107
    ha_rows records;
 
108
    ha_rows deleted;
 
109
    ulong mean_rec_length;
 
110
    ulong data_file_length;
 
111
  } cachedStats;
 
112
  
 
113
};
 
114
 
 
115
class ha_ibmdb2i: public handler
 
116
{
 
117
  THR_LOCK_DATA lock;      ///< MySQL lock
 
118
  IBMDB2I_SHARE *share;    ///< Shared lock info
 
119
 
 
120
  // The record we are positioned on, together with the handle used to get
 
121
  // i.
 
122
  uint32 currentRRN;
 
123
  uint32 rrnAssocHandle;  
 
124
  
 
125
  // Dup key values needed by info()
 
126
  uint32 lastDupKeyRRN;
 
127
  uint32 lastDupKeyID;
 
128
  
 
129
  bool returnDupKeysImmediately;
 
130
 
 
131
  // Dup key value need by update()
 
132
  bool onDupUpdate; 
 
133
 
 
134
  
 
135
  db2i_table* db2Table;
 
136
 
 
137
  // The file handle of the PF or LF being accessed by the current operation.
 
138
  FILE_HANDLE activeHandle;
 
139
  
 
140
  // The file handle of the underlying PF
 
141
  FILE_HANDLE dataHandle;
 
142
  
 
143
  // Array of file handles belonging to the underlying LFs
 
144
  FILE_HANDLE* indexHandles;
 
145
 
 
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;
 
151
  
 
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;
 
155
   
 
156
  IORowBuffer keyBuf;
 
157
  uint32 keyLen;
 
158
  
 
159
  IOWriteBuffer multiRowWriteBuf;
 
160
  IOAsyncReadBuffer multiRowReadBuf;
 
161
  
 
162
  IOAsyncReadBuffer* activeReadBuf;
 
163
  IOWriteBuffer* activeWriteBuf;
 
164
      
 
165
  BlobCollection* blobReadBuffers; // Dynamically allocated per query and used
 
166
                               // to manage the buffers used for reading LOBs
 
167
  ValidatedPointer<char>* blobWriteBuffers;
 
168
  
 
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
 
171
  // functions. 
 
172
  int last_rnd_init_rc;
 
173
  int last_index_init_rc;
 
174
  int last_start_bulk_insert_rc;
 
175
 
 
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;
 
179
 
 
180
  // Auto_increment 'increment by' value needed by write_row()
 
181
  uint32 incrementByValue;
 
182
  bool default_identity_value;
 
183
 
 
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;
 
188
  
 
189
  // The access intent indicated by the last external_locks() call.
 
190
  // May be either QMY_READ or QMY_UPDATABLE
 
191
  char accessIntent;
 
192
  char readAccessIntent;
 
193
 
 
194
  ha_rows* indexReadSizeEstimates;
 
195
 
 
196
  MEM_ROOT conversionBufferMemroot;
 
197
  
 
198
  bool forceSingleRowRead;
 
199
 
 
200
  bool readAllColumns;
 
201
  
 
202
  bool invalidDataFound;
 
203
 
 
204
  db2i_ileBridge* cachedBridge;
 
205
  
 
206
  ValidatedObject<volatile uint32> curConnection;
 
207
  uint16 activeReferences;
 
208
  
 
209
public:
 
210
  
 
211
  ha_ibmdb2i(handlerton *hton, TABLE_SHARE *table_arg);
 
212
  ~ha_ibmdb2i();
 
213
 
 
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;
 
218
 
 
219
  ulonglong table_flags() const
 
220
  {
 
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 |
 
225
           HA_CAN_INDEX_BLOBS;
 
226
  }
 
227
 
 
228
  ulong index_flags(uint inx, uint part, bool all_parts) const;
 
229
 
 
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.
 
234
 
 
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);
 
240
  double scan_time();
 
241
  int open(const char *name, int mode, uint test_if_locked);
 
242
  int close(void);
 
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);                        
 
256
  int rnd_end();
 
257
  int rnd_next(uchar *buf);                       
 
258
  int rnd_pos(uchar * buf, uchar *pos);           
 
259
  void position(const uchar *record);             
 
260
  int info(uint);
 
261
  ha_rows records();                              
 
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,
 
266
                           key_range *max_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);
 
293
 
 
294
  THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
 
295
                             enum thr_lock_type lock_type);   
 
296
                                                              
 
297
  bool low_byte_first() const { return 0; }
 
298
  void unlock_row();
 
299
  int index_end();
 
300
  int reset();
 
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);
 
306
 
 
307
  void initBridge(THD* thd = NULL)
 
308
  {
 
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);
 
312
  }
 
313
  
 
314
  db2i_ileBridge* bridge() {DBUG_ASSERT(cachedBridge); return cachedBridge;}
 
315
  
 
316
  static uint8 autoCommitIsOn(THD* thd)
 
317
  { return (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ? QMY_NO : QMY_YES); }
 
318
  
 
319
  uint8 getCommitLevel();
 
320
  uint8 getCommitLevel(THD* thd);
 
321
 
 
322
  static int doSavepointSet(THD* thd, char* name)
 
323
  {
 
324
    return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_SET_SAVEPOINT,
 
325
                                                  name);
 
326
  }
 
327
  
 
328
  static int doSavepointRollback(THD* thd, char* name)
 
329
  {
 
330
    return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_ROLLBACK_SAVEPOINT,
 
331
                                                  name);
 
332
  }
 
333
  
 
334
  static int doSavepointRelease(THD* thd, char* name)
 
335
  {
 
336
    return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_RELEASE_SAVEPOINT,
 
337
                                                  name);
 
338
  }
 
339
  
 
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()
 
345
  {
 
346
    return HA_POS_ERROR;
 
347
  }
 
348
     
 
349
  
 
350
private:
 
351
 
 
352
  enum enum_TimeFormat
 
353
  {
 
354
    TIME_OF_DAY,
 
355
    DURATION
 
356
  };
 
357
    
 
358
  enum enum_BlobMapping
 
359
  {
 
360
    AS_BLOB,
 
361
    AS_VARCHAR
 
362
  };
 
363
    
 
364
  enum enum_ZeroDate
 
365
  {
 
366
    NO_SUBSTITUTE,
 
367
    SUBSTITUTE_0001_01_01
 
368
  };
 
369
  
 
370
  enum enum_YearFormat
 
371
  {
 
372
    CHAR4,
 
373
    SMALLINT
 
374
  };
 
375
  
 
376
  enum_ZeroDate cachedZeroDateOption;
 
377
    
 
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, 
 
387
                        uint16 fieldID, 
 
388
                        const char* input, 
 
389
                        char* output, 
 
390
                        size_t ilen, 
 
391
                        size_t olen, 
 
392
                        size_t* outDataLen,
 
393
                        bool tacitErrors=FALSE,
 
394
                        size_t* substChars=NULL);
 
395
 
 
396
  /**
 
397
    Fast integer log2 function
 
398
  */
 
399
  uint64 log_2(uint64 val)
 
400
  {
 
401
    uint64 exp = 0;
 
402
    while( (val >> exp) != 0)
 
403
    {
 
404
      exp++;
 
405
    }
 
406
    DBUG_ASSERT(exp-1 == (uint64)log2(val));
 
407
    return exp-1;
 
408
  }
 
409
 
 
410
  void bumpInUseCounter(uint16 amount)
 
411
  {
 
412
    activeReferences += amount;
 
413
    DBUG_PRINT("ha_ibmdb2i::bumpInUseCounter", ("activeReferences = %d", activeReferences));
 
414
    if (activeReferences)
 
415
      curConnection = (uint32)(ha_thd()->thread_id);
 
416
    else
 
417
      curConnection = 0;
 
418
  }
 
419
  
 
420
        
 
421
  int useDataFile()
 
422
  {
 
423
    DBUG_ENTER("ha_ibmdb2i::useDataFile");    
 
424
    
 
425
    int rc = 0;
 
426
    if (!dataHandle)
 
427
      rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
 
428
    else if (activeHandle == dataHandle)
 
429
      DBUG_RETURN(0);
 
430
    
 
431
    DBUG_ASSERT(activeHandle == 0);
 
432
    
 
433
    if (likely(rc == 0))
 
434
    {
 
435
      activeHandle = dataHandle;
 
436
      bumpInUseCounter(1);
 
437
    }
 
438
 
 
439
    DBUG_RETURN(rc);
 
440
  }
 
441
  
 
442
  void releaseAnyLockedRows()
 
443
  {
 
444
    if (releaseRowNeeded)
 
445
    {
 
446
      DBUG_PRINT("ha_ibmdb2i::releaseAnyLockedRows", ("Releasing rows"));
 
447
      db2i_ileBridge::getBridgeForThread()->rrlslck(activeHandle, accessIntent);
 
448
      releaseRowNeeded = FALSE;
 
449
    }
 
450
  }
 
451
 
 
452
  
 
453
  void releaseDataFile()
 
454
  {
 
455
    DBUG_ENTER("ha_ibmdb2i::releaseDataFile");
 
456
    releaseAnyLockedRows();
 
457
    bumpInUseCounter(-1);
 
458
    DBUG_ASSERT((volatile int)activeReferences >= 0);
 
459
    activeHandle = 0;
 
460
    DBUG_VOID_RETURN;
 
461
  }
 
462
 
 
463
  int useIndexFile(int idx);
 
464
  
 
465
  void releaseIndexFile(int idx)
 
466
  {
 
467
    DBUG_ENTER("ha_ibmdb2i::releaseIndexFile");
 
468
    releaseAnyLockedRows();
 
469
    bumpInUseCounter(-1);
 
470
    DBUG_ASSERT((volatile int)activeReferences >= 0);
 
471
    activeHandle = 0;    
 
472
    DBUG_VOID_RETURN;
 
473
  }
 
474
  
 
475
  FILE_HANDLE allocateFileHandle(char* database, char* table, int* activityReference, bool hasBlobs);
 
476
  
 
477
  int updateBuffers(const db2i_file::RowFormat* format, uint rowsToRead, uint rowsToWrite);
 
478
 
 
479
  int flushWrite(FILE_HANDLE fileHandle, uchar* buf = NULL);
 
480
 
 
481
  int alterStartWith(); 
 
482
      
 
483
  int buildDB2ConstraintString(LEX* lex, 
 
484
                               String& appendHere, 
 
485
                               const char* database,
 
486
                               Field** fields,
 
487
                               char* fileSortSequenceType, 
 
488
                               char* fileSortSequence, 
 
489
                               char* fileSortSequenceLibrary);
 
490
  
 
491
  void releaseWriteBuffer();
 
492
 
 
493
  void setIndexReadEstimate(uint index, ha_rows rows)
 
494
  {
 
495
    if (!indexReadSizeEstimates)
 
496
    {
 
497
      indexReadSizeEstimates = (ha_rows*)my_malloc(sizeof(ha_rows) * table->s->keys, MYF(MY_WME | MY_ZEROFILL));
 
498
    }
 
499
    indexReadSizeEstimates[index] = rows;
 
500
  }
 
501
  
 
502
  ha_rows getIndexReadEstimate(uint index)
 
503
  {
 
504
    if (indexReadSizeEstimates)
 
505
      return max(indexReadSizeEstimates[index], 1);
 
506
    
 
507
    return 10000; // Assume index scan if no estimate exists.
 
508
  }
 
509
  
 
510
  
 
511
  void quiesceAllFileHandles()
 
512
  {
 
513
    db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread();
 
514
    if (dataHandle)
 
515
    {
 
516
      bridge->quiesceFileInstance(dataHandle);
 
517
    }
 
518
 
 
519
    for (int idx = 0; idx < table_share->keys; ++idx)
 
520
    {
 
521
      if (indexHandles[idx] != 0)
 
522
      {
 
523
        bridge->quiesceFileInstance(indexHandles[idx]);
 
524
      }
 
525
    }
 
526
  }
 
527
    
 
528
  int32 buildCreateIndexStatement(SqlStatementStream& sqlStream, 
 
529
                                 KEY& key,
 
530
                                 bool isPrimary,
 
531
                                 const char* db2LibName,    
 
532
                                 const char* db2FileName);
 
533
  
 
534
  int32 buildIndexFieldList(String& appendHere,
 
535
                            const KEY& key,
 
536
                            bool isPrimary,
 
537
                            char* fileSortSequenceType, 
 
538
                            char* fileSortSequence, 
 
539
                            char* fileSortSequenceLibrary);
 
540
 
 
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); 
 
543
 
 
544
  int32 convertDB2toMySQL(const DB2Field& db2Field, Field* field, const char* buf);
 
545
  int getFieldTypeMapping(Field* field, 
 
546
                          String& mapping, 
 
547
                          enum_TimeFormat timeFormate,
 
548
                          enum_BlobMapping blobMapping,
 
549
                          enum_ZeroDate zeroDateHandling,
 
550
                          bool propagateDefaults,
 
551
                          enum_YearFormat yearFormat);
 
552
 
 
553
  int getKeyFromName(const char* name, size_t len);
 
554
 
 
555
  void releaseActiveHandle()
 
556
  {
 
557
    if (activeHandle == dataHandle)
 
558
      releaseDataFile();
 
559
    else
 
560
      releaseIndexFile(active_index);
 
561
  }
 
562
 
 
563
      
 
564
  int32 finishBulkInsert();
 
565
  
 
566
  void doInitialRead(char orientation,
 
567
                       uint32 rowsToBuffer,
 
568
                       ILEMemHandle key = 0,
 
569
                       int keyLength = 0,
 
570
                       int keyParts = 0);
 
571
  
 
572
  
 
573
  int32 readFromBuffer(uchar* destination, char orientation)
 
574
  {
 
575
    char* row;
 
576
    int32 rc = 0;
 
577
    row = activeReadBuf->readNextRow(orientation, currentRRN);
 
578
    
 
579
    if (unlikely(!row))
 
580
    {
 
581
      rc = activeReadBuf->lastrc();
 
582
      if (rc == QMY_ERR_LOB_SPACE_TOO_SMALL)
 
583
      {
 
584
        rc = handleLOBReadOverflow();
 
585
        if (rc == 0)        
 
586
        {
 
587
          DBUG_ASSERT(activeReadBuf->rowCount() == 1);
 
588
          row = activeReadBuf->readNextRow(orientation, currentRRN);
 
589
          
 
590
          if (unlikely(!row))
 
591
            rc = activeReadBuf->lastrc();
 
592
        }
 
593
      }
 
594
    }
 
595
 
 
596
    if (likely(rc == 0))
 
597
    {
 
598
      rrnAssocHandle = activeHandle;
 
599
      rc = mungeDB2row(destination, row, row+activeReadBuf->getRowNullOffset(), false);
 
600
    }   
 
601
    return rc;
 
602
  }
 
603
  
 
604
  int32 handleLOBReadOverflow();
 
605
 
 
606
  char* getCharacterConversionBuffer(int fieldId, int length)
 
607
  {
 
608
    if (unlikely(!alloc_root_inited(&conversionBufferMemroot)))
 
609
        init_alloc_root(&conversionBufferMemroot, 8192, 0);
 
610
    
 
611
    return (char*)alloc_root(&conversionBufferMemroot, length);;
 
612
  }      
 
613
      
 
614
  void resetCharacterConversionBuffers()
 
615
  {
 
616
    if (alloc_root_inited(&conversionBufferMemroot))
 
617
    {
 
618
      free_root(&conversionBufferMemroot, MYF(MY_MARK_BLOCKS_FREE));
 
619
    }    
 
620
  }
 
621
  
 
622
  void tweakReadSet()
 
623
  {
 
624
    THD* thd = ha_thd();
 
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;
 
632
    else
 
633
      readAllColumns = FALSE;
 
634
  }
 
635
   
 
636
  /**
 
637
    
 
638
  */
 
639
  int useFileByHandle(char intent, 
 
640
                      FILE_HANDLE handle)
 
641
  {
 
642
    DBUG_ENTER("ha_ibmdb2i::useFileByHandle");
 
643
    
 
644
    const db2i_file* file;
 
645
    if (handle == dataHandle)
 
646
      file = db2Table->dataFile();
 
647
    else
 
648
    {
 
649
      for (uint i = 0; i < table_share->keys; ++i)
 
650
      {
 
651
        if (indexHandles[i] == handle)
 
652
        {
 
653
          file = db2Table->indexFile(i);
 
654
          active_index = i;
 
655
        }
 
656
      }
 
657
    }
 
658
    
 
659
    int rc = file->obtainRowFormat(handle, intent, getCommitLevel(), &activeFormat);
 
660
    if (likely(rc == 0))
 
661
    {
 
662
      activeHandle = handle;
 
663
      bumpInUseCounter(1);
 
664
    }
 
665
    
 
666
    DBUG_RETURN(rc);   
 
667
  }
 
668
  
 
669
  const db2i_file* getFileForActiveHandle() const
 
670
  {
 
671
    if (activeHandle == dataHandle)
 
672
      return db2Table->dataFile();
 
673
    else
 
674
      for (uint i = 0; i < table_share->keys; ++i)
 
675
        if (indexHandles[i] == activeHandle)
 
676
          return db2Table->indexFile(i);
 
677
    DBUG_ASSERT(0);
 
678
    return NULL;
 
679
  }
 
680
  
 
681
  int prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent);
 
682
  int prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file);
 
683
  
 
684
  void invalidateCachedStats()
 
685
  {
 
686
    share->cachedStats.invalidate(rowCount | deletedRowCount | objLength | 
 
687
                                  meanRowLen | ioCount);
 
688
  }
 
689
    
 
690
  void warnIfInvalidData()
 
691
  {
 
692
    if (unlikely(invalidDataFound))
 
693
    {
 
694
      warning(ha_thd(), DB2I_ERR_INVALID_DATA, table->alias);
 
695
    }
 
696
  }
 
697
  
 
698
  /**
 
699
    Calculate the maximum value that a particular field can hold.
 
700
    
 
701
    This is used to anticipate overflows in the auto_increment processing.
 
702
  
 
703
    @param field  The Field to be analyzed
 
704
    
 
705
    @return  The maximum value
 
706
  */
 
707
  static uint64 maxValueForField(const Field* field)
 
708
  {
 
709
    uint64 maxValue=0;
 
710
    switch (field->type())
 
711
    {
 
712
      case MYSQL_TYPE_TINY: 
 
713
        if (((const Field_num*)field)->unsigned_flag)
 
714
          maxValue = (1 << 8) - 1;
 
715
        else
 
716
          maxValue = (1 << 7) - 1;
 
717
        break;
 
718
      case MYSQL_TYPE_SHORT: 
 
719
        if (((const Field_num*)field)->unsigned_flag)
 
720
          maxValue = (1 << 16) - 1;
 
721
        else
 
722
          maxValue = (1 << 15) - 1;
 
723
        break;
 
724
      case MYSQL_TYPE_INT24: 
 
725
        if (((const Field_num*)field)->unsigned_flag)
 
726
          maxValue = (1 << 24) - 1;
 
727
        else
 
728
          maxValue = (1 << 23) - 1;
 
729
        break;
 
730
      case MYSQL_TYPE_LONG: 
 
731
        if (((const Field_num*)field)->unsigned_flag)
 
732
          maxValue = (1LL << 32) - 1;
 
733
        else
 
734
          maxValue = (1 << 31) - 1;
 
735
        break;
 
736
      case MYSQL_TYPE_LONGLONG: 
 
737
        if (((const Field_num*)field)->unsigned_flag)
 
738
          maxValue = ~(0LL);
 
739
        else
 
740
          maxValue = 1 << 63 - 1;
 
741
        break;
 
742
    }
 
743
    
 
744
    return maxValue;
 
745
  }
 
746
  
 
747
  void cleanupBuffers()
 
748
  {
 
749
    if (blobReadBuffers)
 
750
    {
 
751
      delete blobReadBuffers;
 
752
      blobReadBuffers = NULL;
 
753
    }
 
754
    if (blobWriteBuffers)
 
755
    {
 
756
      delete[] blobWriteBuffers;
 
757
      blobWriteBuffers = NULL;
 
758
    }
 
759
    if (alloc_root_inited(&conversionBufferMemroot))
 
760
    {
 
761
      free_root(&conversionBufferMemroot, MYF(0));
 
762
    }    
 
763
  }
 
764
  
 
765
  
 
766
/**
 
767
  Generate a valid RCDFMT name based on the name of the table.
 
768
  
 
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.
 
772
    
 
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
 
776
*/
 
777
  static void generateAndAppendRCDFMT(const char* tableName, String& query)
 
778
  {
 
779
    char rcdfmt[11];
 
780
    
 
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;
 
784
    
 
785
    while (*tableName &&
 
786
           (!my_isascii(*tableName) ||
 
787
            !my_isalpha(system_charset_info, *tableName)))
 
788
    {
 
789
      tableName += my_mbcharlen(system_charset_info, *tableName);
 
790
    }
 
791
    
 
792
    if (unlikely(!(*tableName)))
 
793
    { 
 
794
      rcdfmt[0]= 'X';
 
795
      rcdfmt[1]= 0;
 
796
    }
 
797
    else
 
798
    {
 
799
      int r= 0;
 
800
      while ((r < sizeof(rcdfmt)-1) && *tableName)
 
801
      {
 
802
        if (my_isascii(*tableName) &&
 
803
            my_isalnum(system_charset_info, *tableName))
 
804
          rcdfmt[r] = my_toupper(system_charset_info, *tableName);
 
805
        else
 
806
          rcdfmt[r] = '_';
 
807
        
 
808
        ++r;
 
809
        tableName += my_mbcharlen(system_charset_info, *tableName);
 
810
      }
 
811
      rcdfmt[r]= 0;
 
812
    }
 
813
    query.append(STRING_WITH_LEN(" RCDFMT "));
 
814
    query.append(rcdfmt);
 
815
  }
 
816
  
 
817
  int32 generateShadowIndex(SqlStatementStream& stream, 
 
818
                           const KEY& key,
 
819
                           const char* libName,
 
820
                           const char* fileName,
 
821
                           const String& fieldDefinition);
 
822
};