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

« back to all changes in this revision

Viewing changes to storage/ibmdb2i/ha_ibmdb2i.cc

  • 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
 
 
37
/**
 
38
  @file ha_ibmdb2i.cc
 
39
 
 
40
  @brief
 
41
  The ha_ibmdb2i storage engine provides an interface from MySQL to IBM DB2 for i.
 
42
 
 
43
*/
 
44
 
 
45
#ifdef USE_PRAGMA_IMPLEMENTATION
 
46
#pragma implementation        // gcc: Class implementation
 
47
#endif
 
48
 
 
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"
 
56
 
 
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;
 
62
 
 
63
static const char SAVEPOINT_PREFIX[] = {0xD4, 0xE8, 0xE2, 0xD7}; // MYSP (in EBCDIC)
 
64
 
 
65
OSVersion osVersion;
 
66
 
 
67
 
 
68
// ================================================================
 
69
// ================================================================
 
70
// System variables
 
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",
 
75
  NULL, 
 
76
  NULL,
 
77
  BlankASPName);
 
78
 
 
79
static MYSQL_THDVAR_BOOL(transaction_unsafe,
 
80
  0,
 
81
  "Disable support for commitment control",
 
82
  NULL, 
 
83
  NULL, 
 
84
  FALSE);
 
85
 
 
86
static MYSQL_THDVAR_UINT(lob_alloc_size,
 
87
  0,
 
88
  "Baseline allocation for lob read buffer",
 
89
  NULL, 
 
90
  NULL, 
 
91
  2*1024*1024,
 
92
  64*1024,
 
93
  128*1024*1024,
 
94
  1);
 
95
 
 
96
static MYSQL_THDVAR_UINT(max_read_buffer_size,
 
97
  0,
 
98
  "Maximum size of buffers used for read-ahead.",
 
99
  NULL,
 
100
  NULL,
 
101
  1*1024*1024,
 
102
  32*1024,
 
103
  16*1024*1024,
 
104
  1);
 
105
  
 
106
static MYSQL_THDVAR_UINT(max_write_buffer_size,
 
107
  0,
 
108
  "Maximum size of buffers used for bulk writes.",
 
109
  NULL,
 
110
  NULL,
 
111
  8*1024*1024,
 
112
  32*1024,
 
113
  64*1024*1024,
 
114
  1);
 
115
 
 
116
static MYSQL_THDVAR_BOOL(compat_opt_time_as_duration,
 
117
  0,
 
118
  "Control how new TIME columns should be defined in DB2. 0=time-of-day (default), 1=duration.",
 
119
  NULL, 
 
120
  NULL, 
 
121
  FALSE);
 
122
 
 
123
static MYSQL_THDVAR_UINT(compat_opt_year_as_int,
 
124
  0,
 
125
  "Control how new YEAR columns should be defined in DB2. 0=CHAR(4) (default), 1=SMALLINT.",
 
126
  NULL, 
 
127
  NULL, 
 
128
  0,
 
129
  0,
 
130
  1,
 
131
  1);
 
132
 
 
133
static MYSQL_THDVAR_UINT(compat_opt_blob_cols,
 
134
  0,
 
135
  "Control how new TEXT and BLOB columns should be defined in DB2. 0=CLOB/BLOB (default), 1=VARCHAR/VARBINARY",
 
136
  NULL, 
 
137
  NULL, 
 
138
  0,
 
139
  0,
 
140
  1,
 
141
  1);
 
142
 
 
143
static MYSQL_THDVAR_UINT(compat_opt_allow_zero_date_vals,
 
144
  0,
 
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'",
 
146
  NULL, 
 
147
  NULL, 
 
148
  0,
 
149
  0,
 
150
  1,
 
151
  1);
 
152
 
 
153
static MYSQL_THDVAR_BOOL(propagate_default_col_vals,
 
154
  0,
 
155
  "Should DEFAULT column values be propagated to the DB2 table definition.",
 
156
  NULL, 
 
157
  NULL, 
 
158
  TRUE);
 
159
 
 
160
static my_bool ibmdb2i_assume_exclusive_use;
 
161
static MYSQL_SYSVAR_BOOL(assume_exclusive_use, ibmdb2i_assume_exclusive_use,
 
162
  0,
 
163
  "Can MySQL assume that this process is the only one modifying the DB2 tables. ",
 
164
  NULL, 
 
165
  NULL, 
 
166
  FALSE);
 
167
 
 
168
static MYSQL_THDVAR_BOOL(async_enabled,
 
169
  0,
 
170
  "Should reads be done asynchronously when possible",
 
171
  NULL, 
 
172
  NULL, 
 
173
  TRUE);
 
174
 
 
175
static MYSQL_THDVAR_UINT(create_index_option,
 
176
  0,
 
177
  "Control whether additional indexes are created. 0=No (default), 1=Create additional *HEX-based index",
 
178
  NULL,
 
179
  NULL,
 
180
  0,
 
181
  0,
 
182
  1,
 
183
  1);
 
184
 
 
185
/* static MYSQL_THDVAR_UINT(discovery_mode,
 
186
  0,
 
187
  "Unsupported",
 
188
  NULL,
 
189
  NULL,
 
190
  0,
 
191
  0,
 
192
  1,
 
193
  1); */
 
194
 
 
195
static uint32 ibmdb2i_system_trace;
 
196
static MYSQL_SYSVAR_UINT(system_trace_level, ibmdb2i_system_trace,
 
197
  0,
 
198
  "Set system tracing level",
 
199
  NULL, 
 
200
  NULL, 
 
201
  0,
 
202
  0,
 
203
  63,
 
204
  1);
 
205
 
 
206
 
 
207
inline uint8 ha_ibmdb2i::getCommitLevel(THD* thd)
 
208
{
 
209
  if (!THDVAR(thd, transaction_unsafe))
 
210
  {    
 
211
    switch (thd_tx_isolation(thd))
 
212
    {
 
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;
 
221
    }
 
222
  }
 
223
 
 
224
  return QMY_NONE;
 
225
}
 
226
 
 
227
inline uint8 ha_ibmdb2i::getCommitLevel()
 
228
{
 
229
  return getCommitLevel(ha_thd());
 
230
}
 
231
 
 
232
//=====================================================================
 
233
 
 
234
static handler *ibmdb2i_create_handler(handlerton *hton,
 
235
                                       TABLE_SHARE *table, 
 
236
                                       MEM_ROOT *mem_root);
 
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);
 
242
 
 
243
handlerton *ibmdb2i_hton;
 
244
static bool was_ILE_inited;
 
245
 
 
246
/* Tracks the number of open tables */
 
247
static HASH ibmdb2i_open_tables;
 
248
 
 
249
/* Mutex used to synchronize initialization of the hash */
 
250
static pthread_mutex_t ibmdb2i_mutex;
 
251
 
 
252
 
 
253
/**
 
254
  Create hash key for tracking open tables.
 
255
*/
 
256
 
 
257
static uchar* ibmdb2i_get_key(IBMDB2I_SHARE *share,size_t *length,
 
258
                             bool not_used __attribute__((unused)))
 
259
{
 
260
  *length=share->table_name_length;
 
261
  return (uchar*) share->table_name;
 
262
}
 
263
 
 
264
 
 
265
int ibmdb2i_close_connection(handlerton* hton, THD *thd)
 
266
{
 
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);
 
270
  
 
271
  return 0;  
 
272
}
 
273
 
 
274
 
 
275
static int ibmdb2i_init_func(void *p)
 
276
{
 
277
  DBUG_ENTER("ibmdb2i_init_func");
 
278
  
 
279
  utsname tempName;
 
280
  uname(&tempName);
 
281
  osVersion.v = atoi(tempName.version);
 
282
  osVersion.r = atoi(tempName.release);
 
283
  
 
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);
 
289
 
 
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;
 
301
 
 
302
  int rc;
 
303
  
 
304
  rc = initCharsetSupport();
 
305
    
 
306
  if (!rc)
 
307
    rc = db2i_ileBridge::setup();
 
308
  
 
309
  if (!rc)
 
310
  {
 
311
    int nameLen = strlen(ibmdb2i_rdb_name);
 
312
    for (int i = 0; i < nameLen; ++i)
 
313
    {
 
314
      ibmdb2i_rdb_name[i] = my_toupper(system_charset_info, (uchar)ibmdb2i_rdb_name[i]);
 
315
    }    
 
316
    
 
317
    rc = db2i_ileBridge::initILE(ibmdb2i_rdb_name, (uint16*)(((char*)&ibmdb2i_system_trace)+2));
 
318
    if (rc == 0)
 
319
    {
 
320
      was_ILE_inited = true;
 
321
    }
 
322
  }
 
323
  
 
324
  DBUG_RETURN(rc);
 
325
}
 
326
 
 
327
 
 
328
static int ibmdb2i_done_func(void *p)
 
329
{
 
330
  int error= 0;
 
331
  DBUG_ENTER("ibmdb2i_done_func");
 
332
 
 
333
  if (ibmdb2i_open_tables.records)
 
334
    error= 1;  
 
335
  
 
336
  if (was_ILE_inited)
 
337
    db2i_ileBridge::exitILE();
 
338
 
 
339
  db2i_ileBridge::takedown();
 
340
  
 
341
  doneCharsetSupport();
 
342
 
 
343
  hash_free(&ibmdb2i_open_tables);
 
344
  pthread_mutex_destroy(&ibmdb2i_mutex);
 
345
  
 
346
  DBUG_RETURN(0);
 
347
}
 
348
 
 
349
 
 
350
IBMDB2I_SHARE *ha_ibmdb2i::get_share(const char *table_name, TABLE *table)
 
351
{
 
352
  IBMDB2I_SHARE *share;
 
353
  uint length;
 
354
  char *tmp_name;
 
355
  
 
356
  pthread_mutex_lock(&ibmdb2i_mutex);
 
357
  length=(uint) strlen(table_name);
 
358
 
 
359
  if (!(share=(IBMDB2I_SHARE*) hash_search(&ibmdb2i_open_tables,
 
360
                                           (uchar*)table_name,
 
361
                                           length)))
 
362
  {
 
363
    if (!(share=(IBMDB2I_SHARE *)
 
364
          my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
 
365
                          &share, sizeof(*share),
 
366
                          &tmp_name, length+1,
 
367
                          NullS)))
 
368
    {
 
369
      pthread_mutex_unlock(&ibmdb2i_mutex);
 
370
      return NULL;
 
371
    }
 
372
 
 
373
    share->use_count=0;
 
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))
 
378
      goto error;
 
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);
 
383
    
 
384
    share->db2Table = new db2i_table(table->s, table_name);
 
385
    int32 rc = share->db2Table->initDB2Objects(table_name);
 
386
    
 
387
    if (rc)
 
388
    {
 
389
      delete share->db2Table;
 
390
      hash_delete(&ibmdb2i_open_tables, (uchar*) share);
 
391
      thr_lock_delete(&share->lock);
 
392
      my_errno = rc;
 
393
      goto error;
 
394
    }
 
395
    
 
396
    memset(&share->cachedStats, 0, sizeof(share->cachedStats));
 
397
  }
 
398
  share->use_count++;
 
399
  pthread_mutex_unlock(&ibmdb2i_mutex);
 
400
 
 
401
  db2Table = share->db2Table;
 
402
  
 
403
  return share;
 
404
 
 
405
error:
 
406
  pthread_mutex_destroy(&share->mutex);
 
407
  my_free((uchar*) share, MYF(0));
 
408
  pthread_mutex_unlock(&ibmdb2i_mutex);
 
409
 
 
410
  return NULL;
 
411
}
 
412
 
 
413
 
 
414
 
 
415
int ha_ibmdb2i::free_share(IBMDB2I_SHARE *share)
 
416
{
 
417
  pthread_mutex_lock(&ibmdb2i_mutex);
 
418
  if (!--share->use_count)
 
419
  {
 
420
    delete share->db2Table;
 
421
    db2Table = NULL;
 
422
 
 
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);
 
428
    return 1;
 
429
  }
 
430
  pthread_mutex_unlock(&ibmdb2i_mutex);
 
431
 
 
432
  return 0;
 
433
}
 
434
 
 
435
static handler* ibmdb2i_create_handler(handlerton *hton,
 
436
                                       TABLE_SHARE *table, 
 
437
                                       MEM_ROOT *mem_root)
 
438
{
 
439
  return new (mem_root) ha_ibmdb2i(hton, table);
 
440
}
 
441
 
 
442
static void ibmdb2i_drop_database(handlerton *hton, char* path)
 
443
{
 
444
  DBUG_ENTER("ha_ibmdb2i::ibmdb2i_drop_database");
 
445
  int rc = 0;
 
446
  char queryBuffer[200];
 
447
  String query(queryBuffer, sizeof(queryBuffer), system_charset_info);
 
448
  query.length(0);
 
449
  query.append(STRING_WITH_LEN(" DROP SCHEMA \""));
 
450
  query.append(path+2, strchr(path+2, '/')-(path+2));
 
451
  query.append('"');
 
452
  
 
453
  SqlStatementStream sqlStream(query);
 
454
  
 
455
  rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
 
456
                                              sqlStream.getStatementCount(),
 
457
                                              QMY_NONE,
 
458
                                              FALSE,
 
459
                                              TRUE);
 
460
  DBUG_VOID_RETURN;
 
461
}
 
462
 
 
463
inline static void genSavepointName(const void* sv, char* out)
 
464
{
 
465
  *(uint32*)out = *(uint32*)SAVEPOINT_PREFIX;
 
466
  DBUG_ASSERT(sizeof(SAVEPOINT_PREFIX) == 4);
 
467
  out += sizeof(SAVEPOINT_PREFIX);
 
468
  
 
469
  longlong2str((longlong)sv, out, 10);
 
470
  while (*out)
 
471
  {
 
472
    out += 0xF0;
 
473
    ++out;
 
474
  }
 
475
}
 
476
 
 
477
 
 
478
/*********************************************************************
 
479
Sets a transaction savepoint. */
 
480
static int ibmdb2i_savepoint_set(handlerton* hton, THD* thd, void* sv) 
 
481
{
 
482
  DBUG_ENTER("ibmdb2i_savepoint_set");
 
483
  int rc = 0;
 
484
  if (!THDVAR(thd ,transaction_unsafe))
 
485
  {
 
486
    char name[64];
 
487
    genSavepointName(sv, name);
 
488
    DBUG_PRINT("ibmdb2i_savepoint_set",("Setting %s", name));
 
489
    rc = ha_ibmdb2i::doSavepointSet(thd, name);
 
490
  } 
 
491
  DBUG_RETURN(rc);
 
492
}
 
493
 
 
494
 
 
495
/*********************************************************************
 
496
Rollback a savepoint. */
 
497
static int ibmdb2i_savepoint_rollback(handlerton* hton, THD* thd, void* sv) 
 
498
{
 
499
  DBUG_ENTER("ibmdb2i_savepoint_rollback");
 
500
  int rc = 0;
 
501
  if (!THDVAR(thd,transaction_unsafe))
 
502
  {
 
503
    char name[64];
 
504
    genSavepointName(sv, name);
 
505
    DBUG_PRINT("ibmdb2i_savepoint_rollback",("Rolling back %s", name));
 
506
    rc = ha_ibmdb2i::doSavepointRollback(thd, name);
 
507
  } 
 
508
  DBUG_RETURN(rc);  
 
509
}
 
510
 
 
511
 
 
512
/*********************************************************************
 
513
Release a savepoint. */
 
514
static int ibmdb2i_savepoint_release(handlerton* hton, THD* thd, void* sv) 
 
515
{
 
516
  DBUG_ENTER("ibmdb2i_savepoint_release");
 
517
  int rc = 0;
 
518
  if (!THDVAR(thd,transaction_unsafe))
 
519
  {
 
520
    char name[64];
 
521
    genSavepointName(sv, name);
 
522
    DBUG_PRINT("ibmdb2i_savepoint_release",("Releasing %s", name));
 
523
    rc = ha_ibmdb2i::doSavepointRelease(thd, name);
 
524
  } 
 
525
  DBUG_RETURN(rc);
 
526
}
 
527
 
 
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
 
531
   index(s).  */                    
 
532
static uint ibmdb2i_alter_table_flags(uint flags)
 
533
{
 
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); 
 
537
}
 
538
 
 
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),
 
547
    last_rnd_init_rc(0),
 
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),
 
553
    indexHandles(0),
 
554
    returnDupKeysImmediately(false),
 
555
    onDupUpdate(false), 
 
556
    blobWriteBuffers(NULL),
 
557
    forceSingleRowRead(false)
 
558
 {
 
559
   activeReferences = 0;
 
560
   ref_length = sizeof(currentRRN);
 
561
   if (table_share && table_share->keys > 0)
 
562
   {
 
563
     indexHandles = (FILE_HANDLE*)my_malloc(table_share->keys * sizeof(FILE_HANDLE), MYF(MY_WME | MY_ZEROFILL));
 
564
   }
 
565
   clear_alloc_root(&conversionBufferMemroot);
 
566
 }
 
567
 
 
568
 
 
569
ha_ibmdb2i::~ha_ibmdb2i()
 
570
{
 
571
  DBUG_ASSERT(activeReferences == 0 || outstanding_start_bulk_insert);
 
572
    
 
573
  if (indexHandles)
 
574
    my_free(indexHandles, MYF(0));
 
575
  if (indexReadSizeEstimates)
 
576
    my_free(indexReadSizeEstimates, MYF(0));
 
577
  
 
578
  cleanupBuffers();
 
579
}
 
580
 
 
581
 
 
582
static const char *ha_ibmdb2i_exts[] = {
 
583
  FID_EXT,
 
584
  NullS
 
585
};
 
586
 
 
587
const char **ha_ibmdb2i::bas_ext() const
 
588
{
 
589
  return ha_ibmdb2i_exts;
 
590
}
 
591
 
 
592
 
 
593
int ha_ibmdb2i::open(const char *name, int mode, uint test_if_locked)
 
594
{
 
595
  DBUG_ENTER("ha_ibmdb2i::open");
 
596
 
 
597
  initBridge();
 
598
  
 
599
  dataHandle = bridge()->findAndRemovePreservedHandle(name, &share);
 
600
  
 
601
  if (share)
 
602
    db2Table = share->db2Table;
 
603
  
 
604
  if (!share && (!(share = get_share(name, table))))
 
605
    DBUG_RETURN(my_errno);
 
606
  thr_lock_data_init(&share->lock,&lock,NULL);
 
607
 
 
608
  info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
609
 
 
610
    
 
611
  DBUG_RETURN(0);
 
612
}
 
613
 
 
614
 
 
615
 
 
616
 
 
617
int ha_ibmdb2i::close(void)
 
618
{
 
619
  DBUG_ENTER("ha_ibmdb2i::close");
 
620
  int32 rc = 0;
 
621
  bool preserveShare = false;
 
622
  
 
623
  db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread();
 
624
  
 
625
  if (dataHandle)
 
626
  {
 
627
    if (bridge->expectErrors(QMY_ERR_PEND_LOCKS)->deallocateFile(dataHandle, FALSE) == QMY_ERR_PEND_LOCKS)
 
628
    {
 
629
      bridge->preserveHandle(share->table_name, dataHandle, share);
 
630
      preserveShare = true;
 
631
    }
 
632
    dataHandle = 0;
 
633
  }
 
634
 
 
635
  for (int idx = 0; idx < table_share->keys; ++idx)
 
636
  {
 
637
    if (indexHandles[idx] != 0)
 
638
    {
 
639
      bridge->deallocateFile(indexHandles[idx], FALSE);
 
640
    }
 
641
  }
 
642
  
 
643
  cleanupBuffers();
 
644
    
 
645
  if (!preserveShare)
 
646
  {
 
647
    if (free_share(share))
 
648
      share = NULL;
 
649
  }
 
650
  
 
651
  DBUG_RETURN(rc);
 
652
}
 
653
 
 
654
 
 
655
 
 
656
int ha_ibmdb2i::write_row(uchar * buf)
 
657
{  
 
658
 
 
659
  DBUG_ENTER("ha_ibmdb2i::write_row");
 
660
  
 
661
  if (last_start_bulk_insert_rc)
 
662
    DBUG_RETURN( last_start_bulk_insert_rc );
 
663
  
 
664
  ha_statistic_increment(&SSV::ha_write_count);
 
665
  int rc = 0;
 
666
 
 
667
  bool fileHandleNeedsRelease = false;
 
668
  
 
669
  if (!activeHandle)
 
670
  {
 
671
    rc = useDataFile();
 
672
    if (rc) DBUG_RETURN(rc);
 
673
    fileHandleNeedsRelease = true;
 
674
  }
 
675
      
 
676
  if (!outstanding_start_bulk_insert)
 
677
    rc = prepWriteBuffer(1, getFileForActiveHandle());
 
678
  
 
679
  if (!rc)
 
680
  {
 
681
    if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
 
682
      table->timestamp_field->set_time();
 
683
 
 
684
    char* writeBuffer = activeWriteBuf->addRow();
 
685
    rc = prepareRowForWrite(writeBuffer, 
 
686
                            writeBuffer+activeWriteBuf->getRowNullOffset(),
 
687
                            true);
 
688
    if (rc == 0)
 
689
    {
 
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.    
 
694
 
 
695
      if ((autoIncLockAcquired) && (default_identity_value) && (got_auto_inc_values))
 
696
      { 
 
697
        if (unlikely((next_identity_value - 1) == 
 
698
                      maxValueForField(table->next_number_field)))
 
699
        {
 
700
          rc = QMY_ERR_MAXVALUE;
 
701
        }
 
702
        else
 
703
        {
 
704
          rc = table->next_number_field->store((longlong) next_identity_value, TRUE);
 
705
          next_identity_value = next_identity_value + incrementByValue;
 
706
        }
 
707
      }
 
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);
 
715
    }
 
716
    else
 
717
      activeWriteBuf->deleteRow();
 
718
  }
 
719
      
 
720
  if (fileHandleNeedsRelease)
 
721
    releaseActiveHandle();
 
722
  
 
723
  DBUG_RETURN(rc);
 
724
}
 
725
 
 
726
/**
 
727
  @brief 
 
728
  Helper function used by write_row and update_row to prepare the MySQL
 
729
  row for insertion into DB2.
 
730
*/
 
731
int ha_ibmdb2i::prepareRowForWrite(char* data, char* nulls, bool honorIdentCols)
 
732
{
 
733
  int rc = 0;
 
734
  
 
735
  // set null map all to non nulls
 
736
  memset(nulls,__NOT_NULL_VALUE_EBCDIC, table->s->fields);
 
737
  default_identity_value = FALSE;  
 
738
    
 
739
  ulong sql_mode = ha_thd()->variables.sql_mode;
 
740
  
 
741
  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
 
742
  for (Field **field = table->field; *field && !rc; ++field)
 
743
  {  
 
744
    int fieldIndex = (*field)->field_index;
 
745
    if ((*field)->Field::is_null())                        
 
746
    {                                                  
 
747
      nulls[fieldIndex] = __NULL_VALUE_EBCDIC;         
 
748
    }                                                 
 
749
    if (honorIdentCols && ((*field)->flags & AUTO_INCREMENT_FLAG) &&
 
750
        *field == table->next_number_field) 
 
751
//     && ((!autoIncLockAcquired) || (!got_auto_inc_values)))
 
752
    {
 
753
      if (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
 
754
      {
 
755
        if (!table->auto_increment_field_not_null)
 
756
        {
 
757
          nulls[fieldIndex] = __DEFAULT_VALUE_EBCDIC;
 
758
          default_identity_value = TRUE; 
 
759
        }
 
760
      }
 
761
      else if ((*field)->val_int() == 0)
 
762
      {
 
763
        nulls[fieldIndex] = __DEFAULT_VALUE_EBCDIC;
 
764
        default_identity_value = TRUE; 
 
765
      }
 
766
    }   
 
767
    
 
768
    DB2Field& db2Field = db2Table->db2Field(fieldIndex);
 
769
    if (nulls[fieldIndex] == __NOT_NULL_VALUE_EBCDIC ||
 
770
        db2Field.isBlob())
 
771
    {
 
772
      rc = convertMySQLtoDB2(*field, db2Field, data + db2Field.getBufferOffset());
 
773
    }
 
774
  }  
 
775
  
 
776
  if (!rc && db2Table->hasBlobs())
 
777
    rc = db2i_ileBridge::getBridgeForThread()->objectOverride(activeHandle,
 
778
                                                            activeWriteBuf->ptr());  
 
779
 
 
780
  dbug_tmp_restore_column_map(table->read_set, old_map);
 
781
 
 
782
  return rc; 
 
783
}
 
784
 
 
785
 
 
786
 
 
787
int ha_ibmdb2i::update_row(const uchar * old_data, uchar * new_data)
 
788
{
 
789
  DBUG_ENTER("ha_ibmdb2i::update_row");
 
790
  ha_statistic_increment(&SSV::ha_update_count);
 
791
  int rc;
 
792
  
 
793
  bool fileHandleNeedsRelease = false;
 
794
  
 
795
  if (!activeHandle)
 
796
  {
 
797
    rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);
 
798
    if (rc) DBUG_RETURN(rc);
 
799
    fileHandleNeedsRelease = true;
 
800
  }
 
801
    
 
802
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
803
    table->timestamp_field->set_time();
 
804
  
 
805
  char* writeBuf = activeWriteBuf->addRow();
 
806
  rc = prepareRowForWrite(writeBuf, 
 
807
                          writeBuf+activeWriteBuf->getRowNullOffset(),
 
808
                          onDupUpdate);
 
809
 
 
810
  char* lastDupKeyNamePtr = NULL;
 
811
  uint32 lastDupKeyNameLen = 0;
 
812
  
 
813
  if (!rc)
 
814
  {
 
815
    rc = db2i_ileBridge::getBridgeForThread()->updateRow(activeHandle,
 
816
                                                       currentRRN,
 
817
                                                       activeWriteBuf->ptr(),
 
818
                                                       &lastDupKeyRRN,
 
819
                                                       &lastDupKeyNamePtr,
 
820
                                                       &lastDupKeyNameLen);
 
821
  }
 
822
  
 
823
  if (lastDupKeyNameLen)
 
824
  {
 
825
    lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen);
 
826
    rrnAssocHandle = activeHandle;
 
827
  }
 
828
 
 
829
  if (fileHandleNeedsRelease)
 
830
    releaseActiveHandle();
 
831
  
 
832
  activeWriteBuf->resetAfterWrite();
 
833
    
 
834
  DBUG_RETURN(rc);
 
835
}
 
836
 
 
837
 
 
838
int ha_ibmdb2i::delete_row(const uchar * buf)
 
839
{
 
840
  DBUG_ENTER("ha_ibmdb2i::delete_row");
 
841
  ha_statistic_increment(&SSV::ha_delete_count);
 
842
  
 
843
  bool needReleaseFile = false;
 
844
  int rc = 0;
 
845
  
 
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;
 
850
  }
 
851
      
 
852
  if (likely(!rc))
 
853
  {
 
854
    rc = db2i_ileBridge::getBridgeForThread()->deleteRow(activeHandle,
 
855
                                                       currentRRN);  
 
856
    invalidateCachedStats();
 
857
    if (needReleaseFile)
 
858
      releaseActiveHandle();
 
859
  }
 
860
 
 
861
  DBUG_RETURN(rc);
 
862
}
 
863
 
 
864
 
 
865
 
 
866
int ha_ibmdb2i::index_init(uint idx, bool sorted)
 
867
{
 
868
  DBUG_ENTER("ha_ibmdb2i::index_init");
 
869
  
 
870
  int& rc = last_index_init_rc;
 
871
  rc = 0;
 
872
  
 
873
  invalidDataFound=false;
 
874
  tweakReadSet();
 
875
    
 
876
  active_index=idx;
 
877
 
 
878
  rc = useIndexFile(idx);
 
879
  
 
880
  if (!rc)
 
881
  {
 
882
//     THD* thd = ha_thd();
 
883
//     if (accessIntent == QMY_UPDATABLE &&
 
884
//         thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
 
885
//         !THDVAR(thd, transaction_unsafe))
 
886
//     {
 
887
//       readAccessIntent = QMY_READ_ONLY;
 
888
//     }
 
889
//     else
 
890
//     {
 
891
      readAccessIntent = accessIntent;
 
892
//     }
 
893
    
 
894
    if (!rc && accessIntent != QMY_READ_ONLY)
 
895
      rc = prepWriteBuffer(1, db2Table->indexFile(idx));
 
896
    
 
897
    if (rc)
 
898
      releaseIndexFile(idx);
 
899
  }
 
900
  
 
901
  rrnAssocHandle= 0;
 
902
 
 
903
  DBUG_RETURN(rc); 
 
904
}
 
905
 
 
906
 
 
907
 
 
908
int ha_ibmdb2i::index_read(uchar * buf, const uchar * key,
 
909
                           uint key_len,
 
910
                           enum ha_rkey_function find_flag)
 
911
{
 
912
  DBUG_ENTER("ha_ibmdb2i::index_read");
 
913
 
 
914
  if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
 
915
 
 
916
  int rc;
 
917
  
 
918
  ha_rows estimatedRows = getIndexReadEstimate(active_index);
 
919
  rc = prepReadBuffer(estimatedRows, db2Table->indexFile(active_index), readAccessIntent);  
 
920
  if (unlikely(rc)) DBUG_RETURN(rc);
 
921
  
 
922
  DBUG_ASSERT(activeReadBuf);
 
923
  
 
924
  keyBuf.allocBuf(activeReadBuf->getRowLength(), 
 
925
                  activeReadBuf->getRowNullOffset(), 
 
926
                  activeReadBuf->getRowLength());
 
927
  keyBuf.zeroBuf();
 
928
  
 
929
  char* db2KeyBufPtr = keyBuf.ptr();
 
930
  char* nullKeyMap = db2KeyBufPtr + activeReadBuf->getRowNullOffset();
 
931
  
 
932
  const uchar* keyBegin = key;
 
933
  int partsInUse;
 
934
  
 
935
  KEY& curKey = table->key_info[active_index];
 
936
  
 
937
  for (partsInUse = 0; partsInUse < curKey.key_parts, key - keyBegin < key_len; ++partsInUse)
 
938
  {
 
939
    Field* field = curKey.key_part[partsInUse].field;     
 
940
    if ((curKey.key_part[partsInUse].null_bit) &&
 
941
        (char*)key[0])
 
942
    {
 
943
      if (field->flags & AUTO_INCREMENT_FLAG)
 
944
      {
 
945
        table->status = STATUS_NOT_FOUND; 
 
946
        DBUG_RETURN(HA_ERR_END_OF_FILE);
 
947
      }
 
948
      else
 
949
      {
 
950
        nullKeyMap[partsInUse] = __NULL_VALUE_EBCDIC;
 
951
      }
 
952
    }
 
953
    else
 
954
    {
 
955
      nullKeyMap[partsInUse] = __NOT_NULL_VALUE_EBCDIC;
 
956
      convertMySQLtoDB2(field, 
 
957
                        db2Table->db2Field(field->field_index),
 
958
                        db2KeyBufPtr, 
 
959
                        (uchar*)key+((curKey.key_part[partsInUse].null_bit)? 1 : 0) ); // + (curKey.key_parts+7) / 8);
 
960
    }
 
961
   
 
962
    db2KeyBufPtr += db2Table->db2Field(field->field_index).getByteLengthInRecord();
 
963
    key += curKey.key_part[partsInUse].store_length;
 
964
  }
 
965
  
 
966
  keyLen = db2KeyBufPtr - (char*)keyBuf.ptr();
 
967
  
 
968
  DBUG_PRINT("ha_ibmdb2i::index_read", ("find_flag: %d", find_flag));
 
969
 
 
970
  char readDirection = QMY_NEXT;
 
971
    
 
972
  switch (find_flag)
 
973
  {
 
974
    case HA_READ_AFTER_KEY:
 
975
      doInitialRead(QMY_AFTER_EQUAL, estimatedRows,
 
976
                    keyBuf.ptr(), keyLen, partsInUse);
 
977
      break;
 
978
    case HA_READ_BEFORE_KEY:
 
979
      doInitialRead(QMY_BEFORE_EQUAL, estimatedRows,
 
980
                    keyBuf.ptr(), keyLen, partsInUse);
 
981
      break;
 
982
    case HA_READ_KEY_OR_NEXT:
 
983
      doInitialRead(QMY_AFTER_OR_EQUAL, estimatedRows,
 
984
                    keyBuf.ptr(), keyLen, partsInUse);
 
985
      break;
 
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);
 
990
      break;
 
991
    case HA_READ_PREFIX_LAST_OR_PREV:
 
992
      doInitialRead(QMY_LAST_PREVIOUS, estimatedRows,
 
993
                    keyBuf.ptr(), keyLen, partsInUse);
 
994
      readDirection = QMY_PREVIOUS;
 
995
      break; 
 
996
    case HA_READ_PREFIX_LAST:
 
997
      doInitialRead(QMY_PREFIX_LAST, estimatedRows,
 
998
                    keyBuf.ptr(), keyLen, partsInUse);
 
999
      readDirection = QMY_PREVIOUS;
 
1000
      break; 
 
1001
    case HA_READ_KEY_EXACT:
 
1002
      doInitialRead(QMY_EQUAL, estimatedRows, keyBuf.ptr(), keyLen, partsInUse);
 
1003
      break;
 
1004
    default: 
 
1005
        DBUG_ASSERT(0);
 
1006
        return HA_ERR_GENERIC;
 
1007
      break;
 
1008
  }
 
1009
  
 
1010
  ha_statistic_increment(&SSV::ha_read_key_count);
 
1011
  rc = readFromBuffer(buf, readDirection);
 
1012
  
 
1013
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1014
  DBUG_RETURN(rc);
 
1015
}
 
1016
 
 
1017
 
 
1018
int ha_ibmdb2i::index_next(uchar * buf)
 
1019
{
 
1020
  DBUG_ENTER("ha_ibmdb2i::index_next");
 
1021
  ha_statistic_increment(&SSV::ha_read_next_count);
 
1022
  
 
1023
  int rc = readFromBuffer(buf, QMY_NEXT);
 
1024
  
 
1025
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1026
  DBUG_RETURN(rc);
 
1027
}
 
1028
 
 
1029
 
 
1030
int ha_ibmdb2i::index_next_same(uchar *buf, const uchar *key, uint keylen)
 
1031
{
 
1032
  DBUG_ENTER("ha_ibmdb2i::index_next_same");
 
1033
  ha_statistic_increment(&SSV::ha_read_next_count);
 
1034
  
 
1035
  int rc = readFromBuffer(buf, QMY_NEXT_EQUAL);
 
1036
  
 
1037
  if (rc == HA_ERR_KEY_NOT_FOUND)
 
1038
  {
 
1039
    rc = HA_ERR_END_OF_FILE;
 
1040
  }
 
1041
 
 
1042
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1043
  DBUG_RETURN(rc);
 
1044
}
 
1045
 
 
1046
int ha_ibmdb2i::index_read_last(uchar * buf, const uchar * key, uint key_len)
 
1047
{
 
1048
  DBUG_ENTER("ha_ibmdb2i::index_read_last");
 
1049
  DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));  
 
1050
}
 
1051
 
 
1052
 
 
1053
 
 
1054
int ha_ibmdb2i::index_prev(uchar * buf)
 
1055
{
 
1056
  DBUG_ENTER("ha_ibmdb2i::index_prev");
 
1057
  ha_statistic_increment(&SSV::ha_read_prev_count);
 
1058
  
 
1059
  int rc = readFromBuffer(buf, QMY_PREVIOUS);
 
1060
 
 
1061
  table->status= (rc ? STATUS_NOT_FOUND: 0);  
 
1062
  DBUG_RETURN(rc);
 
1063
}
 
1064
 
 
1065
 
 
1066
int ha_ibmdb2i::index_first(uchar * buf)
 
1067
{
 
1068
  DBUG_ENTER("ha_ibmdb2i::index_first");
 
1069
 
 
1070
  if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
 
1071
    
 
1072
  int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER, 
 
1073
                          db2Table->indexFile(active_index), 
 
1074
                          readAccessIntent);
 
1075
  
 
1076
  if (rc == 0)
 
1077
  {
 
1078
    doInitialRead(QMY_FIRST, DEFAULT_MAX_ROWS_TO_BUFFER);
 
1079
    ha_statistic_increment(&SSV::ha_read_first_count);
 
1080
    rc = readFromBuffer(buf, QMY_NEXT);
 
1081
  }
 
1082
  
 
1083
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1084
  DBUG_RETURN(rc);
 
1085
}
 
1086
 
 
1087
 
 
1088
int ha_ibmdb2i::index_last(uchar * buf)
 
1089
{
 
1090
  DBUG_ENTER("ha_ibmdb2i::index_last");
 
1091
  
 
1092
  if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
 
1093
  
 
1094
  int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER, 
 
1095
                          db2Table->indexFile(active_index), 
 
1096
                          readAccessIntent);
 
1097
  
 
1098
  if (rc == 0)
 
1099
  {
 
1100
    doInitialRead(QMY_LAST, DEFAULT_MAX_ROWS_TO_BUFFER);
 
1101
    ha_statistic_increment(&SSV::ha_read_last_count);
 
1102
    rc = readFromBuffer(buf, QMY_PREVIOUS);
 
1103
  }
 
1104
  
 
1105
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1106
  DBUG_RETURN(rc);
 
1107
}
 
1108
 
 
1109
 
 
1110
int ha_ibmdb2i::rnd_init(bool scan)
 
1111
{
 
1112
  DBUG_ENTER("ha_ibmdb2i::rnd_init");
 
1113
 
 
1114
  int& rc = last_rnd_init_rc;
 
1115
  rc = 0;
 
1116
      
 
1117
  tweakReadSet();
 
1118
  invalidDataFound=false;
 
1119
  
 
1120
  uint32 rowsToBlockOnRead;
 
1121
 
 
1122
  if (!scan)
 
1123
  { 
 
1124
    rowsToBlockOnRead = 1;
 
1125
  }
 
1126
  else
 
1127
  {
 
1128
    rowsToBlockOnRead = DEFAULT_MAX_ROWS_TO_BUFFER;
 
1129
  }
 
1130
  
 
1131
  rc = useDataFile(); 
 
1132
  
 
1133
  if (!rc)
 
1134
  {
 
1135
//     THD* thd = ha_thd();
 
1136
//     if (accessIntent == QMY_UPDATABLE &&
 
1137
//         thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
 
1138
//         !THDVAR(thd, transaction_unsafe))
 
1139
//     {
 
1140
//       readAccessIntent = QMY_READ_ONLY;
 
1141
//     }
 
1142
//     else
 
1143
//     {
 
1144
      readAccessIntent = accessIntent;
 
1145
//     }
 
1146
 
 
1147
    rc = prepReadBuffer(rowsToBlockOnRead, db2Table->dataFile(), readAccessIntent);
 
1148
 
 
1149
    if (!rc && accessIntent != QMY_READ_ONLY)
 
1150
      rc = prepWriteBuffer(1, db2Table->dataFile());
 
1151
 
 
1152
    if (!rc && scan)
 
1153
      doInitialRead(QMY_FIRST, rowsToBlockOnRead);
 
1154
    
 
1155
    if (rc)
 
1156
      releaseDataFile();
 
1157
  }
 
1158
  
 
1159
  rrnAssocHandle= 0;
 
1160
 
 
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
 
1163
                  // value here. 
 
1164
}
 
1165
 
 
1166
int ha_ibmdb2i::rnd_end()
 
1167
{
 
1168
  DBUG_ENTER("ha_ibmdb2i::rnd_end");
 
1169
  
 
1170
  warnIfInvalidData();
 
1171
  if (likely(activeReadBuf))
 
1172
    activeReadBuf->endRead();
 
1173
  if (last_rnd_init_rc == 0)
 
1174
    releaseActiveHandle();
 
1175
  last_rnd_init_rc = 0;
 
1176
  DBUG_RETURN(0);
 
1177
}
 
1178
 
 
1179
 
 
1180
int32 ha_ibmdb2i::mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs)
 
1181
{
 
1182
  DBUG_ASSERT(dataPtr);
 
1183
  
 
1184
  my_bitmap_map *old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
 
1185
  my_bitmap_map *old_read_map;
 
1186
  
 
1187
  if (unlikely(readAllColumns))
 
1188
    old_read_map = tmp_use_all_columns(table, table->read_set);
 
1189
 
 
1190
  resetCharacterConversionBuffers();
 
1191
  
 
1192
  my_ptrdiff_t old_ptr= (my_ptrdiff_t) (record - table->record[0]); 
 
1193
  int fieldIndex = 0;
 
1194
  for (Field **field = table->field; *field; ++field, ++fieldIndex)
 
1195
  {  
 
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()))
 
1201
    {
 
1202
      (*field)->set_null();
 
1203
    }
 
1204
    else
 
1205
    {
 
1206
      (*field)->set_notnull();
 
1207
      convertDB2toMySQL(db2Table->db2Field(fieldIndex), *field, dataPtr);
 
1208
    }
 
1209
    if (unlikely(old_ptr))
 
1210
      (*field)->move_field_offset(-old_ptr);
 
1211
    
 
1212
  }
 
1213
    
 
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);
 
1217
  
 
1218
  return 0;
 
1219
}
 
1220
 
 
1221
 
 
1222
int ha_ibmdb2i::rnd_next(uchar *buf)
 
1223
{
 
1224
  DBUG_ENTER("ha_ibmdb2i::rnd_next");
 
1225
 
 
1226
  if (unlikely(last_rnd_init_rc)) DBUG_RETURN(last_rnd_init_rc);
 
1227
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
1228
  
 
1229
  int rc;      
 
1230
  
 
1231
  rc = readFromBuffer(buf, QMY_NEXT);
 
1232
    
 
1233
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1234
  DBUG_RETURN(rc);
 
1235
}
 
1236
 
 
1237
 
 
1238
void ha_ibmdb2i::position(const uchar *record)
 
1239
{
 
1240
  DBUG_ENTER("ha_ibmdb2i::position");
 
1241
  my_store_ptr(ref, ref_length, currentRRN);
 
1242
  DBUG_VOID_RETURN;
 
1243
}
 
1244
 
 
1245
 
 
1246
int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos)
 
1247
{
 
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);
 
1251
 
 
1252
  currentRRN = my_get_ptr(pos, ref_length);
 
1253
 
 
1254
  tweakReadSet();  
 
1255
  
 
1256
  int rc = 0;
 
1257
 
 
1258
  if (rrnAssocHandle &&
 
1259
      (activeHandle != rrnAssocHandle))
 
1260
  {
 
1261
    if (activeHandle) releaseActiveHandle();
 
1262
    rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);    
 
1263
  }
 
1264
  
 
1265
  if (likely(rc == 0))
 
1266
  {
 
1267
    rc = prepReadBuffer(1, getFileForActiveHandle(), accessIntent);
 
1268
 
 
1269
    if (likely(rc == 0) && accessIntent == QMY_UPDATABLE)
 
1270
      rc = prepWriteBuffer(1, getFileForActiveHandle());
 
1271
 
 
1272
    if (likely(rc == 0))
 
1273
    {
 
1274
      rc = db2i_ileBridge::getBridgeForThread()->readByRRN(activeHandle, 
 
1275
                                                         activeReadBuf->ptr(),
 
1276
                                                         currentRRN,
 
1277
                                                         accessIntent,
 
1278
                                                         getCommitLevel());
 
1279
 
 
1280
      if (likely(rc == 0))
 
1281
      {
 
1282
        rrnAssocHandle = activeHandle;
 
1283
        const char* readBuf = activeReadBuf->getRowN(0);
 
1284
        rc = mungeDB2row(buf, readBuf, readBuf + activeReadBuf->getRowNullOffset(), false);
 
1285
        releaseRowNeeded = TRUE;
 
1286
      }
 
1287
    }    
 
1288
  }
 
1289
  
 
1290
  DBUG_RETURN(rc);
 
1291
}
 
1292
 
 
1293
 
 
1294
int ha_ibmdb2i::info(uint flag)
 
1295
{
 
1296
  DBUG_ENTER("ha_ibmdb2i::info");
 
1297
 
 
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);
 
1303
  
 
1304
  if (flag & HA_STATUS_AUTO)
 
1305
    stats.auto_increment_value = (ulonglong) 0;
 
1306
 
 
1307
  if (flag & HA_STATUS_ERRKEY)
 
1308
  {
 
1309
    errkey = lastDupKeyID;
 
1310
    my_store_ptr(dup_ref, ref_length, lastDupKeyRRN);
 
1311
  }
 
1312
  
 
1313
  if (flag & HA_STATUS_TIME)
 
1314
  {
 
1315
    if ((flag & HA_STATUS_NO_LOCK) && 
 
1316
        ibmdb2i_assume_exclusive_use &&
 
1317
        share &&
 
1318
        (share->cachedStats.isInited(lastModTime)))
 
1319
      stats.update_time = share->cachedStats.getUpdateTime();
 
1320
    else
 
1321
      infoRequested |= lastModTime;
 
1322
  }
 
1323
  
 
1324
  if (flag & HA_STATUS_CONST)
 
1325
  {
 
1326
    stats.block_size=4096;
 
1327
    infoRequested |= createTime;
 
1328
    
 
1329
    if (table->s->keys)
 
1330
    {
 
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
 
1335
    }
 
1336
  }
 
1337
  
 
1338
  if (flag & HA_STATUS_VARIABLE)
 
1339
  {
 
1340
    if ((flag & HA_STATUS_NO_LOCK) &&
 
1341
        (command != SQLCOM_SHOW_TABLE_STATUS) &&
 
1342
        ibmdb2i_assume_exclusive_use &&
 
1343
        share &&
 
1344
        (share->cachedStats.isInited(rowCount | deletedRowCount | meanRowLen | ioCount)) &&
 
1345
        (share->cachedStats.getRowCount() >= 2))
 
1346
    {
 
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();
 
1351
    }
 
1352
    else
 
1353
    {
 
1354
      infoRequested |= rowCount | deletedRowCount | meanRowLen;            
 
1355
      if (command == SQLCOM_SHOW_TABLE_STATUS)
 
1356
        infoRequested |= objLength;
 
1357
      else
 
1358
        infoRequested |= ioCount;
 
1359
    }
 
1360
  }
 
1361
 
 
1362
  int rc = 0;
 
1363
          
 
1364
  if (infoRequested)
 
1365
  {
 
1366
    DBUG_PRINT("ha_ibmdb2i::info",("Retrieving fresh stats %d", flag));
 
1367
 
 
1368
    initBridge(thd);
 
1369
    rc = bridge()->retrieveTableInfo((dataHandle  ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
 
1370
                                     infoRequested,
 
1371
                                     stats,
 
1372
                                     rowKeySpcPtr);
 
1373
    
 
1374
    if (!rc)
 
1375
    {
 
1376
      if ((flag & HA_STATUS_VARIABLE) &&
 
1377
          (command != SQLCOM_SHOW_TABLE_STATUS))
 
1378
        stats.data_file_length = stats.data_file_length * IO_SIZE;
 
1379
 
 
1380
      if ((ibmdb2i_assume_exclusive_use) &&
 
1381
          (share) && 
 
1382
          (command != SQLCOM_SHOW_TABLE_STATUS))
 
1383
      {
 
1384
        if (flag & HA_STATUS_VARIABLE) 
 
1385
        {
 
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);
 
1390
        }
 
1391
 
 
1392
        if (flag & HA_STATUS_TIME)
 
1393
        {
 
1394
          share->cachedStats.cacheUpdateTime(stats.update_time);
 
1395
        }
 
1396
      }
 
1397
 
 
1398
      if (flag & HA_STATUS_CONST)
 
1399
      {
 
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
 
1403
 
 
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
 
1406
        {
 
1407
          for (j = 0; j < table->key_info[i].key_parts; j++)   
 
1408
          {
 
1409
            table->key_info[i].rec_per_key[j]= rowKeyPtr->RowKeyArray[j];
 
1410
          }
 
1411
          rowKeyPtr = rowKeyPtr + 1;                   // Address next array of DB2 row counts 
 
1412
        }
 
1413
      }
 
1414
    }
 
1415
    else if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && share)
 
1416
    {
 
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();
 
1431
      
 
1432
      rc = 0;
 
1433
    }
 
1434
  }
 
1435
 
 
1436
  DBUG_RETURN(rc);
 
1437
}
 
1438
 
 
1439
 
 
1440
ha_rows ha_ibmdb2i::records()
 
1441
{
 
1442
  DBUG_ENTER("ha_ibmdb2i::records");
 
1443
  int rc;
 
1444
  rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
 
1445
                                                             rowCount,
 
1446
                                                             stats);
 
1447
 
 
1448
  if (unlikely(rc))
 
1449
  {
 
1450
    if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && 
 
1451
        share && 
 
1452
        (share->cachedStats.isInited(rowCount)))
 
1453
      DBUG_RETURN(share->cachedStats.getRowCount());
 
1454
    else
 
1455
      DBUG_RETURN(HA_POS_ERROR);
 
1456
  }
 
1457
  else if (share)
 
1458
  {
 
1459
    share->cachedStats.cacheRowCount(stats.records);
 
1460
  }
 
1461
 
 
1462
 DBUG_RETURN(stats.records); 
 
1463
}
 
1464
 
 
1465
 
 
1466
int ha_ibmdb2i::extra(enum ha_extra_function operation)
 
1467
{
 
1468
  DBUG_ENTER("ha_ibmdb2i::extra");
 
1469
  
 
1470
  switch(operation)
 
1471
  {
 
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: 
 
1475
      {                                                
 
1476
        returnDupKeysImmediately = false;
 
1477
        onDupUpdate = false;                         
 
1478
      }                                              
 
1479
      break;
 
1480
    case HA_EXTRA_INSERT_WITH_UPDATE:                
 
1481
      {                                              
 
1482
        returnDupKeysImmediately = true;             
 
1483
        onDupUpdate = true;                          
 
1484
      }                                               
 
1485
      break;                            
 
1486
    case HA_EXTRA_IGNORE_DUP_KEY:  
 
1487
    case HA_EXTRA_WRITE_CAN_REPLACE: 
 
1488
      returnDupKeysImmediately = true;
 
1489
      break;
 
1490
    case HA_EXTRA_FLUSH_CACHE:
 
1491
      if (outstanding_start_bulk_insert)
 
1492
        finishBulkInsert();
 
1493
      break;
 
1494
  }
 
1495
 
 
1496
  
 
1497
  DBUG_RETURN(0);
 
1498
}
 
1499
 
 
1500
/** 
 
1501
  @brief  
 
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.
 
1505
*/
 
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)
 
1510
{
 
1511
  DBUG_ENTER("ha_ibmdb2i::get_auto_increment");
 
1512
  *first_value= 1;
 
1513
  *nb_reserved_values= ULONGLONG_MAX;
 
1514
 
1515
 
 
1516
 
 
1517
 
 
1518
void ha_ibmdb2i::update_create_info(HA_CREATE_INFO *create_info)
 
1519
{
 
1520
  DBUG_ENTER("ha_ibmdb2i::update_create_info");
 
1521
 
 
1522
  if ((!(create_info->used_fields & HA_CREATE_USED_AUTO)) &&
 
1523
      (table->found_next_number_field != NULL))
 
1524
  {
 
1525
    initBridge();
 
1526
    
 
1527
    create_info->auto_increment_value= 1; 
 
1528
 
 
1529
    ha_rows rowCount = records();
 
1530
    
 
1531
    if (rowCount == 0)
 
1532
    { 
 
1533
      create_info->auto_increment_value = db2Table->getStartId();
 
1534
      DBUG_VOID_RETURN;
 
1535
    }
 
1536
    else if (rowCount == HA_POS_ERROR)
 
1537
    { 
 
1538
      DBUG_VOID_RETURN;
 
1539
    }
 
1540
 
 
1541
    getNextIdVal(&create_info->auto_increment_value); 
 
1542
  }
 
1543
  DBUG_VOID_RETURN;
 
1544
}
 
1545
 
 
1546
 
 
1547
int ha_ibmdb2i::getNextIdVal(ulonglong *value)
 
1548
{
 
1549
  DBUG_ENTER("ha_ibmdb2i::getNextIdVal");
 
1550
  
 
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));
 
1559
  
 
1560
  SqlStatementStream sqlStream(queryBuffer);
 
1561
  DBUG_PRINT("ha_ibmdb2i::getNextIdVal", ("Sent to DB2: %s",queryBuffer));
 
1562
 
 
1563
  int rc = 0;
 
1564
  FILE_HANDLE fileHandle2;
 
1565
  uint32 db2RowDataLen2;
 
1566
  rc = bridge()->prepOpen(sqlStream.getPtrToData(),
 
1567
                          &fileHandle2,
 
1568
                          &db2RowDataLen2);
 
1569
  if (likely(rc == 0))
 
1570
  {
 
1571
    IOReadBuffer rowBuffer(1, db2RowDataLen2);
 
1572
    rc = bridge()->read(fileHandle2, 
 
1573
                        rowBuffer.ptr(),
 
1574
                        QMY_READ_ONLY,
 
1575
                        QMY_NONE,
 
1576
                        QMY_FIRST);
 
1577
    
 
1578
    if (likely(rc == 0))
 
1579
    {
 
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.                                */
 
1583
 
 
1584
      longlong maxIdVal = *(longlong*)(rowBuffer.getRowN(0));
 
1585
      if ((maxIdVal + 1) > db2Table->getStartId())
 
1586
        *value = maxIdVal + 1; 
 
1587
      else
 
1588
        *value = db2Table->getStartId();
 
1589
    }
 
1590
    
 
1591
    bridge()->deallocateFile(fileHandle2);
 
1592
  }
 
1593
  DBUG_RETURN(rc);
 
1594
}
 
1595
 
 
1596
 
 
1597
/*
 
1598
  Updates index cardinalities.                                             
 
1599
*/
 
1600
int ha_ibmdb2i::analyze(THD* thd, HA_CHECK_OPT *check_opt)
 
1601
{
 
1602
  DBUG_ENTER("ha_ibmdb2i::analyze");
 
1603
  info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
1604
  DBUG_RETURN(0);
 
1605
}
 
1606
 
 
1607
int ha_ibmdb2i::optimize(THD* thd, HA_CHECK_OPT *check_opt)
 
1608
{
 
1609
  DBUG_ENTER("ha_ibmdb2i::optimize");
 
1610
 
 
1611
  initBridge(thd);
 
1612
  
 
1613
  if (unlikely(records() == 0))
 
1614
    DBUG_RETURN(0); // DB2 doesn't like to reorganize a table with no data.
 
1615
  
 
1616
  quiesceAllFileHandles();
 
1617
  
 
1618
  int32 rc = bridge()->optimizeTable(db2Table->dataFile()->getMasterDefnHandle());
 
1619
  info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
1620
  
 
1621
  DBUG_RETURN(rc);
 
1622
}
 
1623
 
 
1624
 
 
1625
/**
 
1626
  @brief
 
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. 
 
1630
*/
 
1631
bool ha_ibmdb2i::can_switch_engines(void)
 
1632
/*=================================*/
 
1633
{
 
1634
  DBUG_ENTER("ha_ibmdb2i::can_switch_engines");
 
1635
 
 
1636
  int rc = 0;
 
1637
  FILE_HANDLE queryFile = 0;
 
1638
  uint32 resultRowLen;  
 
1639
  uint count = 0; 
 
1640
  bool can_switch = FALSE;   // 1 if changing storage engine is allowed
 
1641
  
 
1642
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
1643
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
1644
  
 
1645
  String query(256);
 
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("'))"));
 
1655
                                               
 
1656
  SqlStatementStream sqlStream(query);
 
1657
  
 
1658
  rc = bridge()->prepOpen(sqlStream.getPtrToData(),
 
1659
                        &queryFile,
 
1660
                        &resultRowLen);
 
1661
  if (rc == 0)
 
1662
  {
 
1663
    IOReadBuffer rowBuffer(1, resultRowLen);
 
1664
 
 
1665
    rc =   bridge()->read(queryFile, 
 
1666
                        rowBuffer.ptr(),
 
1667
                        QMY_READ_ONLY, 
 
1668
                        QMY_NONE,
 
1669
                        QMY_FIRST);
 
1670
    if (!rc)
 
1671
    {
 
1672
       count = *(uint*)(rowBuffer.getRowN(0));
 
1673
       if (count == 0)
 
1674
         can_switch = TRUE;
 
1675
    }
 
1676
 
 
1677
    bridge()->deallocateFile(queryFile);
 
1678
  }
 
1679
  DBUG_RETURN(can_switch);
 
1680
}
 
1681
 
 
1682
 
 
1683
 
 
1684
bool ha_ibmdb2i::check_if_incompatible_data(HA_CREATE_INFO *info,
 
1685
                                         uint table_changes)
 
1686
{
 
1687
  DBUG_ENTER("ha_ibmdb2i::check_if_incompatible_data");
 
1688
  uint i;
 
1689
  /* Check that auto_increment value and field definitions were
 
1690
     not changed. */
 
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++)
 
1697
  {
 
1698
   Field *field= table->field[i];
 
1699
   if (field->flags & FIELD_IS_RENAMED)
 
1700
    {
 
1701
      DBUG_PRINT("info", ("Field has been renamed, copy table"));
 
1702
      DBUG_RETURN(COMPATIBLE_DATA_NO);
 
1703
    }
 
1704
  }
 
1705
  DBUG_RETURN(COMPATIBLE_DATA_YES);
 
1706
}
 
1707
 
 
1708
int ha_ibmdb2i::reset_auto_increment(ulonglong value)
 
1709
 {
 
1710
  DBUG_ENTER("ha_ibmdb2i::reset_auto_increment");
 
1711
  
 
1712
  int rc = 0;
 
1713
 
 
1714
  quiesceAllFileHandles();
 
1715
 
 
1716
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
1717
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
1718
 
 
1719
  String query(512);
 
1720
  query.append(STRING_WITH_LEN(" ALTER TABLE "));
 
1721
  query.append(libName);
 
1722
  query.append('.');
 
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, 
 
1727
                            colName, 
 
1728
                            sizeof(colName));
 
1729
  query.append(colName);
 
1730
  
 
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;
 
1735
  
 
1736
  query.append(STRING_WITH_LEN(" RESTART WITH "));
 
1737
  query.append(restart_value);
 
1738
  
 
1739
  SqlStatementStream sqlStream(query);
 
1740
  DBUG_PRINT("ha_ibmdb2i::reset_auto_increment", ("Sent to DB2: %s",query.c_ptr()));
 
1741
 
 
1742
  rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
 
1743
                                                     sqlStream.getStatementCount(),
 
1744
                                                     QMY_NONE, //getCommitLevel(),
 
1745
                                                     FALSE,
 
1746
                                                     FALSE,
 
1747
                                                     TRUE, //FALSE,
 
1748
                                                     dataHandle);
 
1749
  if (rc == 0)
 
1750
    db2Table->updateStartId(value); 
 
1751
 
 
1752
  DBUG_RETURN(rc);
 
1753
}
 
1754
 
 
1755
 
 
1756
/**
 
1757
  @brief
 
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.   
 
1760
*/
 
1761
bool ha_ibmdb2i::get_error_message(int error, String *buf)
 
1762
{
 
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))
 
1766
  {
 
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();
 
1771
  }
 
1772
  DBUG_RETURN(FALSE);                          
 
1773
}
 
1774
 
 
1775
 
 
1776
int ha_ibmdb2i::delete_all_rows()
 
1777
{
 
1778
  DBUG_ENTER("ha_ibmdb2i::delete_all_rows");
 
1779
  int rc = 0;
 
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));
 
1784
  
 
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(),
 
1789
                         getCommitLevel(),
 
1790
                         false,
 
1791
                         false,
 
1792
                         true,
 
1793
                         dataHandle);
 
1794
  
 
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.
 
1798
                                            */
 
1799
  if (rc == 0 && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE &&
 
1800
      table->found_next_number_field )
 
1801
    rc = reset_auto_increment(1);
 
1802
 
 
1803
  invalidateCachedStats();
 
1804
  
 
1805
  DBUG_RETURN(rc);
 
1806
}
 
1807
 
 
1808
 
 
1809
int ha_ibmdb2i::external_lock(THD *thd, int lock_type)
 
1810
{
 
1811
  int rc = 0;
 
1812
 
 
1813
  DBUG_ENTER("ha_ibmdb2i::external_lock");
 
1814
  DBUG_PRINT("ha_ibmdb2i::external_lock",("Lock type: %d", lock_type));
 
1815
  
 
1816
  if (lock_type == F_RDLCK)
 
1817
    accessIntent = QMY_READ_ONLY;
 
1818
  else if (lock_type == F_WRLCK)
 
1819
    accessIntent = QMY_UPDATABLE;
 
1820
  
 
1821
  initBridge(thd);
 
1822
  int command = thd_sql_command(thd);
 
1823
  
 
1824
  if (!THDVAR(thd,transaction_unsafe))
 
1825
  {
 
1826
    if (lock_type != F_UNLCK)
 
1827
    {
 
1828
      if (autoCommitIsOn(thd) == QMY_YES)
 
1829
      {
 
1830
        trans_register_ha(thd, FALSE, ibmdb2i_hton);
 
1831
      }
 
1832
      else 
 
1833
      { 
 
1834
        trans_register_ha(thd, TRUE, ibmdb2i_hton);
 
1835
        if (likely(command != SQLCOM_CREATE_TABLE))
 
1836
        {
 
1837
          trans_register_ha(thd, FALSE, ibmdb2i_hton);
 
1838
          bridge()->beginStmtTx();
 
1839
        }
 
1840
      }
 
1841
    }    
 
1842
  }
 
1843
 
 
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))
 
1855
  {
 
1856
    char action;
 
1857
    char type;
 
1858
    if (lock_type == F_UNLCK)
 
1859
    { 
 
1860
      action = QMY_UNLOCK;
 
1861
      type = accessIntent == QMY_READ_ONLY ? QMY_LSRD : QMY_LENR;
 
1862
    }
 
1863
    else
 
1864
    {
 
1865
      action = QMY_LOCK;
 
1866
      type = lock_type == F_RDLCK ? QMY_LSRD : QMY_LENR;
 
1867
    }
 
1868
 
 
1869
    DBUG_PRINT("ha_ibmdb2i::external_lock",("%socking table", action==QMY_LOCK ? "L" : "Unl"));
 
1870
 
 
1871
    if (!dataHandle)
 
1872
      rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);  
 
1873
 
 
1874
    rc = bridge()->lockObj(dataHandle, 
 
1875
                           0,
 
1876
                           action,               
 
1877
                           type,
 
1878
                           (command == SQLCOM_LOCK_TABLES ? QMY_NO : QMY_YES)); 
 
1879
    
 
1880
  } 
 
1881
  
 
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);
 
1884
  
 
1885
  DBUG_RETURN(rc);
 
1886
}
 
1887
 
 
1888
 
 
1889
THR_LOCK_DATA **ha_ibmdb2i::store_lock(THD *thd,
 
1890
                                       THR_LOCK_DATA **to,
 
1891
                                       enum thr_lock_type lock_type)
 
1892
{
 
1893
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
 
1894
  {
 
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;
 
1899
  }
 
1900
  *to++= &lock;
 
1901
  return to;
 
1902
}
 
1903
 
 
1904
 
 
1905
int ha_ibmdb2i::delete_table(const char *name)
 
1906
{
 
1907
  DBUG_ENTER("ha_ibmdb2i::delete_table");
 
1908
  THD* thd = ha_thd();
 
1909
  db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(thd);  
 
1910
  
 
1911
  char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
 
1912
  db2i_table::getDB2QualifiedNameFromPath(name, db2Name);
 
1913
 
 
1914
  String query(128);
 
1915
  query.append(STRING_WITH_LEN(" DROP TABLE "));
 
1916
  query.append(db2Name);
 
1917
 
 
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()));
 
1922
 
 
1923
  SqlStatementStream sqlStream(query);
 
1924
 
 
1925
  db2i_table::getDB2LibNameFromPath(name, db2Name);  
 
1926
  bool isTemporary = (strcmp(db2Name, DB2I_TEMP_TABLE_SCHEMA) == 0 ? TRUE : FALSE);
 
1927
 
 
1928
  int rc = bridge->execSQL(sqlStream.getPtrToData(),
 
1929
                       sqlStream.getStatementCount(),
 
1930
                       (isTemporary ? QMY_NONE : getCommitLevel(thd)),
 
1931
                       FALSE,
 
1932
                       FALSE,
 
1933
                       isTemporary);
 
1934
 
 
1935
  if (rc == HA_ERR_NO_SUCH_TABLE)
 
1936
  {
 
1937
     warning(thd, DB2I_ERR_TABLE_NOT_FOUND, name);
 
1938
     rc = 0;
 
1939
  }
 
1940
  
 
1941
  if (rc == 0)
 
1942
  {
 
1943
    db2i_table::deleteAssocFiles(name);
 
1944
  }
 
1945
  
 
1946
  FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
 
1947
  while (savedHandle)
 
1948
  {
 
1949
    bridge->deallocateFile(savedHandle, TRUE);
 
1950
    DBUG_ASSERT(share);
 
1951
    if (free_share(share))
 
1952
      share = NULL;   
 
1953
    savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
 
1954
  }
 
1955
    
 
1956
  my_errno = rc;
 
1957
  DBUG_RETURN(rc);
 
1958
}
 
1959
 
 
1960
 
 
1961
int ha_ibmdb2i::rename_table(const char * from, const char * to)
 
1962
{
 
1963
  DBUG_ENTER("ha_ibmdb2i::rename_table ");
 
1964
    
 
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];
 
1969
 
 
1970
  db2i_table::getDB2LibNameFromPath(from, db2FromLibName);
 
1971
  db2i_table::getDB2LibNameFromPath(to, db2ToLibName);
 
1972
 
 
1973
  if (strcmp(db2FromLibName, db2ToLibName) != 0 )
 
1974
  {
 
1975
    getErrTxt(DB2I_ERR_RENAME_MOVE,from,to);
 
1976
    DBUG_RETURN(DB2I_ERR_RENAME_MOVE);
 
1977
  }
 
1978
 
 
1979
  db2i_table::getDB2FileNameFromPath(from, db2FromFileName, db2i_table::ASCII_NATIVE);
 
1980
  db2i_table::getDB2FileNameFromPath(to, db2ToFileName);
 
1981
 
 
1982
  char escapedFromFileName[2 * MAX_DB2_FILENAME_LENGTH + 1];
 
1983
    
 
1984
  uint o = 0;
 
1985
  uint i = 1;
 
1986
  do
 
1987
  {
 
1988
    escapedFromFileName[o++] = db2FromFileName[i];
 
1989
    if (db2FromFileName[i] == '+')
 
1990
      escapedFromFileName[o++] = '+';
 
1991
  } while (db2FromFileName[++i]);
 
1992
  escapedFromFileName[o-1] = 0;
 
1993
 
 
1994
  
 
1995
  int rc = 0;
 
1996
  
 
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());
 
2007
  
 
2008
  SqlStatementStream indexQuery(selectQuery.ptr());
 
2009
 
 
2010
  FILE_HANDLE queryFile = 0;
 
2011
  uint32 resultRowLen;
 
2012
    
 
2013
  initBridge();
 
2014
  rc = bridge()->prepOpen(indexQuery.getPtrToData(),
 
2015
                        &queryFile,
 
2016
                        &resultRowLen);
 
2017
 
 
2018
  if (unlikely(rc))
 
2019
    DBUG_RETURN(rc);
 
2020
    
 
2021
  IOReadBuffer rowBuffer(1, resultRowLen);  
 
2022
     
 
2023
  int tableNameLen = strlen(db2FromFileName) - 2;
 
2024
  
 
2025
  SqlStatementStream renameQuery(64);
 
2026
  String query;
 
2027
  while (rc == 0)
 
2028
  {
 
2029
    query.length(0);
 
2030
 
 
2031
    rc = bridge()->read(queryFile,
 
2032
                      rowBuffer.ptr(),
 
2033
                      QMY_READ_ONLY,
 
2034
                      QMY_NONE,
 
2035
                      QMY_NEXT);
 
2036
 
 
2037
    if (!rc)
 
2038
    {
 
2039
      const char* rowData = rowBuffer.getRowN(0);
 
2040
      char indexFileName[MAX_DB2_FILENAME_LENGTH];
 
2041
      memset(indexFileName, 0, sizeof(indexFileName));
 
2042
      
 
2043
      uint16 fileNameLen = *(uint16*)(rowData);
 
2044
      strncpy(indexFileName, rowData + sizeof(uint16), fileNameLen);
 
2045
            
 
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.      */
 
2050
      {
 
2051
        getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
2052
        DBUG_RETURN(DB2I_ERR_INVALID_NAME);     
 
2053
      }
 
2054
      char indexName[MAX_DB2_FILENAME_LENGTH];
 
2055
      memset(indexName, 0, sizeof(indexName));
 
2056
 
 
2057
      strncpy(indexName, 
 
2058
              indexFileName, 
 
2059
              bytesToRetain);
 
2060
      
 
2061
      char db2IndexName[MAX_DB2_FILENAME_LENGTH+1];
 
2062
      
 
2063
      convertMySQLNameToDB2Name(indexFileName, db2IndexName, sizeof(db2IndexName));
 
2064
 
 
2065
      query.append(STRING_WITH_LEN("RENAME INDEX "));
 
2066
      query.append(db2FromLibName);
 
2067
      query.append('.');
 
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)
 
2071
      {
 
2072
        getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
2073
        DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
2074
      }
 
2075
      renameQuery.addStatement(query);      
 
2076
      DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2077
    }    
 
2078
  }
 
2079
 
 
2080
    
 
2081
  if (queryFile)
 
2082
    bridge()->deallocateFile(queryFile);
 
2083
  
 
2084
  if (rc != HA_ERR_END_OF_FILE)
 
2085
    DBUG_RETURN(rc);
 
2086
  
 
2087
  char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
 
2088
          
 
2089
  /* Rename the table */
 
2090
  query.length(0);
 
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(),
 
2100
                       getCommitLevel());
 
2101
  
 
2102
  if (!rc)
 
2103
    db2i_table::renameAssocFiles(from, to);
 
2104
  
 
2105
  DBUG_RETURN(rc);
 
2106
}
 
2107
 
 
2108
 
 
2109
int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
 
2110
                       HA_CREATE_INFO *create_info)
 
2111
{
 
2112
  DBUG_ENTER("ha_ibmdb2i::create");
 
2113
 
 
2114
  int rc;
 
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];
 
2121
  bool isTemporary;
 
2122
  ulong auto_inc_value;
 
2123
 
 
2124
  db2i_table::getDB2LibNameFromPath(name, libName);
 
2125
  db2i_table::getDB2FileNameFromPath(name, fileName);
 
2126
 
 
2127
  if (osVersion.v < 6)
 
2128
  {
 
2129
    if (strlen(libName) > 
 
2130
         MAX_DB2_V5R4_LIBNAME_LENGTH + (isOrdinaryIdentifier(libName) ? 2 : 0))
 
2131
    {
 
2132
      getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V5R4_LIBNAME_LENGTH);
 
2133
      DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
 
2134
    }
 
2135
  }
 
2136
  else if (strlen(libName) > MAX_DB2_V6R1_LIBNAME_LENGTH)
 
2137
  {
 
2138
    getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V6R1_LIBNAME_LENGTH);
 
2139
    DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
 
2140
  }
 
2141
  
 
2142
  String query(256);
 
2143
  
 
2144
  if (strcmp(libName, DB2I_TEMP_TABLE_SCHEMA))
 
2145
  {
 
2146
    query.append(STRING_WITH_LEN("CREATE TABLE "));
 
2147
    query.append(libName);
 
2148
    query.append('.');
 
2149
    query.append(fileName);
 
2150
    isTemporary = FALSE;
 
2151
  }
 
2152
  else
 
2153
  {
 
2154
    query.append(STRING_WITH_LEN("DECLARE GLOBAL TEMPORARY TABLE "));
 
2155
    query.append(fileName);
 
2156
    isTemporary = TRUE;
 
2157
  }
 
2158
  query.append(STRING_WITH_LEN(" ("));
 
2159
  
 
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);
 
2166
  
 
2167
  Field **field;
 
2168
  for (field= table_arg->field; *field; field++)
 
2169
  {  
 
2170
    if ( field != table_arg->field ) // Not the first one
 
2171
      query.append(STRING_WITH_LEN(" , "));
 
2172
 
 
2173
    if (!convertMySQLNameToDB2Name((*field)->field_name, colName, sizeof(colName)))
 
2174
    {
 
2175
      getErrTxt(DB2I_ERR_INVALID_NAME,"field",(*field)->field_name);
 
2176
      DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
2177
    }
 
2178
 
 
2179
    query.append(colName);    
 
2180
    query.append(' ');
 
2181
 
 
2182
    if (rc = getFieldTypeMapping(*field, 
 
2183
                                 query, 
 
2184
                                 timeFormat, 
 
2185
                                 blobMapping,
 
2186
                                 zeroDate,
 
2187
                                 propagateDefaults,
 
2188
                                 yearFormat))
 
2189
      DBUG_RETURN(rc);
 
2190
 
 
2191
    if ( (*field)->flags & NOT_NULL_FLAG )
 
2192
    {
 
2193
      query.append(STRING_WITH_LEN(" NOT NULL "));
 
2194
    }
 
2195
    if ( (*field)->flags & AUTO_INCREMENT_FLAG )     
 
2196
    {
 
2197
#ifdef WITH_PARTITION_STORAGE_ENGINE      
 
2198
      if (table_arg->part_info)
 
2199
      {
 
2200
        getErrTxt(DB2I_ERR_PART_AUTOINC);
 
2201
        DBUG_RETURN(DB2I_ERR_PART_AUTOINC);
 
2202
      }
 
2203
#endif
 
2204
      query.append(STRING_WITH_LEN(" GENERATED BY DEFAULT AS IDENTITY ") );
 
2205
      if (create_info->auto_increment_value != 0) 
 
2206
      {
 
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);
 
2216
 
 
2217
        uint64 maxValue=maxValueForField(*field);
 
2218
        
 
2219
        if (maxValue)
 
2220
        {
 
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);
 
2225
        }
 
2226
        
 
2227
        query.append(STRING_WITH_LEN(") "));
 
2228
      }
 
2229
 
 
2230
    } 
 
2231
  }
 
2232
  
 
2233
  String fieldDefinition(128);
 
2234
  
 
2235
  if (table_arg->s->primary_key != MAX_KEY && !isTemporary)
 
2236
  {
 
2237
    query.append(STRING_WITH_LEN(", PRIMARY KEY "));
 
2238
    rc = buildIndexFieldList(fieldDefinition, 
 
2239
                             table_arg->key_info[table_arg->s->primary_key],
 
2240
                             true,
 
2241
                             &fileSortSequenceType,
 
2242
                             fileSortSequence,
 
2243
                             fileSortSequenceLibrary);
 
2244
    if (rc) DBUG_RETURN(rc);
 
2245
    query.append(fieldDefinition);
 
2246
  }
 
2247
 
 
2248
  rc = buildDB2ConstraintString(thd->lex, 
 
2249
                                query, 
 
2250
                                name,
 
2251
                                table_arg->field,
 
2252
                                &fileSortSequenceType,
 
2253
                                fileSortSequence,
 
2254
                                fileSortSequenceLibrary);  
 
2255
  if (rc) DBUG_RETURN (rc);
 
2256
  
 
2257
  query.append(STRING_WITH_LEN(" ) "));
 
2258
  
 
2259
  if (isTemporary)
 
2260
    query.append(STRING_WITH_LEN(" ON COMMIT PRESERVE ROWS "));
 
2261
  
 
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);
 
2266
        
 
2267
  DBUG_PRINT("ha_ibmdb2i::create", ("Sent to DB2: %s",query.c_ptr()));
 
2268
  SqlStatementStream sqlStream(query.length());
 
2269
  sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
 
2270
  
 
2271
  if (table_arg->s->primary_key != MAX_KEY && 
 
2272
      !isTemporary &&
 
2273
      (THDVAR(thd, create_index_option)==1) &&
 
2274
      (fileSortSequenceType != 'B') &&
 
2275
      (fileSortSequenceType != ' '))
 
2276
  {
 
2277
    rc = generateShadowIndex(sqlStream, 
 
2278
                             table_arg->key_info[table_arg->s->primary_key], 
 
2279
                             libName, 
 
2280
                             fileName, 
 
2281
                             fieldDefinition);
 
2282
    if (rc) DBUG_RETURN(rc);
 
2283
  }
 
2284
  for (uint i = 0; i < table_arg->s->keys; ++i)
 
2285
  {
 
2286
    if (i != table_arg->s->primary_key || isTemporary)
 
2287
    {
 
2288
      rc = buildCreateIndexStatement(sqlStream, 
 
2289
                                table_arg->key_info[i], 
 
2290
                                false,
 
2291
                                libName,
 
2292
                                fileName);
 
2293
      if (rc) DBUG_RETURN (rc);
 
2294
    }
 
2295
  }
 
2296
  
 
2297
  bool noCommit = isTemporary || ((!autoCommitIsOn(thd)) && (thd_sql_command(thd) == SQLCOM_ALTER_TABLE));
 
2298
  
 
2299
  initBridge();
 
2300
  
 
2301
//   if (THDVAR(thd, discovery_mode) == 1)
 
2302
//     bridge()->expectErrors(QMY_ERR_TABLE_EXISTS);
 
2303
  
 
2304
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
2305
                         sqlStream.getStatementCount(),
 
2306
                         (isTemporary ? QMY_NONE : getCommitLevel(thd)),
 
2307
                         TRUE,
 
2308
                         FALSE,
 
2309
                         noCommit );
 
2310
  
 
2311
  if (unlikely(rc == QMY_ERR_MSGID) &&
 
2312
      memcmp(bridge()->getErrorMsgID(), DB2I_SQL0350, 7) == 0)
 
2313
  {
 
2314
    my_error(ER_BLOB_USED_AS_KEY, MYF(0), "*unknown*");
 
2315
    rc = ER_BLOB_USED_AS_KEY;
 
2316
  }
 
2317
/*   else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) &&
 
2318
            THDVAR(thd, discovery_mode) == 1)
 
2319
  {
 
2320
    db2i_table* temp = new db2i_table(table_arg->s, name);
 
2321
    int32 rc = temp->fastInitForCreate(name);
 
2322
    delete temp;
 
2323
    
 
2324
    if (!rc)
 
2325
      warning(thd, DB2I_ERR_WARN_CREATE_DISCOVER);
 
2326
    
 
2327
    DBUG_RETURN(rc);
 
2328
  }   
 
2329
*/
 
2330
  
 
2331
  if (!rc && !isTemporary)
 
2332
  {
 
2333
    db2i_table* temp = new db2i_table(table_arg->s, name);
 
2334
    rc = temp->fastInitForCreate(name);
 
2335
    delete temp;
 
2336
    if (rc) 
 
2337
      delete_table(name);
 
2338
  }
 
2339
  
 
2340
  DBUG_RETURN(rc);
 
2341
}
 
2342
 
 
2343
 
 
2344
/**
 
2345
  @brief
 
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.
 
2349
*/
 
2350
int ha_ibmdb2i::add_index(TABLE *table_arg, 
 
2351
                          KEY *key_info,
 
2352
                          uint num_of_keys)
 
2353
{
 
2354
  DBUG_ENTER("ha_ibmdb2i::add_index");
 
2355
 
 
2356
  int rc;
 
2357
  SqlStatementStream sqlStream(256);
 
2358
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
2359
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
2360
  
 
2361
  quiesceAllFileHandles();
 
2362
  
 
2363
  uint primaryKey = MAX_KEY;
 
2364
  if (table_arg->s->primary_key >= MAX_KEY && !db2Table->isTemporary())
 
2365
  {  
 
2366
    for (int i = 0; i < num_of_keys; ++i)
 
2367
    {
 
2368
      if (strcmp(key_info[i].name, "PRIMARY") == 0)
 
2369
      {
 
2370
        primaryKey = i;
 
2371
        break;
 
2372
      }
 
2373
      else if (primaryKey == MAX_KEY &&
 
2374
               key_info[i].flags & HA_NOSAME)
 
2375
      {
 
2376
        primaryKey = i;
 
2377
        for (int j=0 ; j < key_info[i].key_parts ;j++)
 
2378
        {
 
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)
 
2383
          {
 
2384
            primaryKey = MAX_KEY;
 
2385
            break;
 
2386
          }
 
2387
        }
 
2388
      }
 
2389
    }
 
2390
  }
 
2391
        
 
2392
        
 
2393
  for (int i = 0; i < num_of_keys; ++i)
 
2394
  {
 
2395
    KEY& curKey= key_info[i];
 
2396
    rc = buildCreateIndexStatement(sqlStream, 
 
2397
                              curKey, 
 
2398
                              (i == primaryKey),
 
2399
                              libName,
 
2400
                              fileName);
 
2401
    if (rc) DBUG_RETURN (rc);
 
2402
  }
 
2403
  
 
2404
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
2405
                         sqlStream.getStatementCount(),
 
2406
                         getCommitLevel(),
 
2407
                         FALSE,
 
2408
                         FALSE,
 
2409
                         FALSE,
 
2410
                         dataHandle);
 
2411
 
 
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));
 
2416
 
 
2417
  DBUG_RETURN(rc);
 
2418
}
 
2419
 
 
2420
/**
 
2421
  @brief
 
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.
 
2425
*/
 
2426
int ha_ibmdb2i::prepare_drop_index(TABLE *table_arg, 
 
2427
                                   uint *key_num, uint num_of_keys)
 
2428
{
 
2429
  DBUG_ENTER("ha_ibmdb2i::prepare_drop_index");
 
2430
  int rc;
 
2431
  int i = 0;
 
2432
  String query(64);
 
2433
  SqlStatementStream sqlStream(64 * num_of_keys);
 
2434
  SqlStatementStream shadowStream(64 * num_of_keys);
 
2435
 
 
2436
  quiesceAllFileHandles();
 
2437
  
 
2438
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
2439
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
2440
 
 
2441
  while (i < num_of_keys)
 
2442
  {
 
2443
    query.length(0);
 
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())
 
2447
    {
 
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"));
 
2453
    }
 
2454
    else
 
2455
    {
 
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);
 
2460
    }
 
2461
    DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2462
    sqlStream.addStatement(query);
 
2463
    
 
2464
    query.length(0);
 
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);
 
2469
    
 
2470
    DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2471
    shadowStream.addStatement(query);
 
2472
    
 
2473
    ++i;
 
2474
   }
 
2475
  
 
2476
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
2477
                         sqlStream.getStatementCount(),
 
2478
                         getCommitLevel(),
 
2479
                         FALSE,
 
2480
                         FALSE,
 
2481
                         FALSE,
 
2482
                         dataHandle);
 
2483
  
 
2484
  if (rc == 0)
 
2485
    bridge()->execSQL(shadowStream.getPtrToData(),
 
2486
                         shadowStream.getStatementCount(),
 
2487
                         getCommitLevel());
 
2488
  
 
2489
  DBUG_RETURN(rc);
 
2490
}
 
2491
 
 
2492
 
 
2493
void
 
2494
ha_ibmdb2i::unlock_row()
 
2495
{
 
2496
  DBUG_ENTER("ha_ibmdb2i::unlock_row");
 
2497
  DBUG_VOID_RETURN;
 
2498
}    
 
2499
 
 
2500
int
 
2501
ha_ibmdb2i::index_end()
 
2502
{
 
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;
 
2511
  DBUG_RETURN (0);
 
2512
}
 
2513
 
 
2514
int ha_ibmdb2i::doCommit(handlerton *hton, THD *thd, bool all)
 
2515
{
 
2516
  if (!THDVAR(thd, transaction_unsafe))
 
2517
  {
 
2518
    if (all || autoCommitIsOn(thd))
 
2519
    {
 
2520
      DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing all"));
 
2521
      return (db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_COMMIT));
 
2522
    }
 
2523
    else
 
2524
    {
 
2525
      DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing stmt"));
 
2526
      return (db2i_ileBridge::getBridgeForThread(thd)->commitStmtTx());
 
2527
    }
 
2528
  }
 
2529
  
 
2530
  return (0);
 
2531
 
2532
 
 
2533
 
 
2534
int ha_ibmdb2i::doRollback(handlerton *hton, THD *thd, bool all)
 
2535
{
 
2536
  if (!THDVAR(thd,transaction_unsafe))
 
2537
  {
 
2538
    if (all || autoCommitIsOn(thd))
 
2539
    {
 
2540
      DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back all"));
 
2541
      return ( db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_ROLLBACK));
 
2542
    }
 
2543
    else
 
2544
    {
 
2545
      DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back stmt"));
 
2546
      return (db2i_ileBridge::getBridgeForThread(thd)->rollbackStmtTx());
 
2547
    }
 
2548
  }
 
2549
  return (0);
 
2550
}
 
2551
 
 
2552
 
 
2553
void ha_ibmdb2i::start_bulk_insert(ha_rows rows)
 
2554
{
 
2555
  DBUG_ENTER("ha_ibmdb2i::start_bulk_insert");
 
2556
  DBUG_PRINT("ha_ibmdb2i::start_bulk_insert",("Rows hinted %d", rows));
 
2557
  int rc;
 
2558
  THD* thd = ha_thd();
 
2559
  int command = thd_sql_command(thd);
 
2560
  
 
2561
  if (db2Table->hasBlobs() || 
 
2562
      (command == SQLCOM_REPLACE || command == SQLCOM_REPLACE_SELECT))
 
2563
    rows = 1;
 
2564
  else if (rows == 0)
 
2565
    rows = DEFAULT_MAX_ROWS_TO_BUFFER; // Shoot the moon
 
2566
  
 
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.
 
2572
 
 
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
 
2576
  {
 
2577
    if (!dataHandle)
 
2578
      rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);  
 
2579
 
 
2580
    rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LEAR, QMY_YES);
 
2581
    if (rc==0)                                     // Got the lock
 
2582
    {
 
2583
      autoIncLockAcquired = TRUE;               
 
2584
      got_auto_inc_values = FALSE;                    
 
2585
    }
 
2586
    else                                          // Didn't get the lock
 
2587
      rows = 1;                                   // No problem, but don't block inserts
 
2588
  }
 
2589
  
 
2590
  if (activeHandle == 0)
 
2591
  {
 
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());
 
2595
  }
 
2596
 
 
2597
  if (last_start_bulk_insert_rc == 0)
 
2598
    outstanding_start_bulk_insert = true;
 
2599
  else
 
2600
  {
 
2601
    if (autoIncLockAcquired == TRUE)
 
2602
    {
 
2603
      bridge()->lockObj(dataHandle,  0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
 
2604
      autoIncLockAcquired = FALSE;
 
2605
    }
 
2606
  }
 
2607
 
 
2608
  DBUG_VOID_RETURN;
 
2609
}
 
2610
 
 
2611
 
 
2612
int ha_ibmdb2i::end_bulk_insert()
 
2613
{
 
2614
  DBUG_ENTER("ha_ibmdb2i::end_bulk_insert");
 
2615
  int rc = 0;
 
2616
  
 
2617
  if (outstanding_start_bulk_insert)
 
2618
  {
 
2619
    rc = finishBulkInsert();
 
2620
  }
 
2621
 
 
2622
  my_errno = rc;
 
2623
    
 
2624
  DBUG_RETURN(rc);
 
2625
}
 
2626
 
 
2627
  
 
2628
int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent)    
 
2629
{
 
2630
  DBUG_ENTER("ha_ibmdb2i::prepReadBuffer");
 
2631
  DBUG_ASSERT(rowsToRead > 0);
 
2632
 
 
2633
  THD* thd = ha_thd();
 
2634
  char cmtLvl = getCommitLevel(thd);
 
2635
  
 
2636
  const db2i_file::RowFormat* format;
 
2637
  int rc = file->obtainRowFormat(activeHandle, intent, cmtLvl, &format);
 
2638
  
 
2639
  if (unlikely(rc)) DBUG_RETURN(rc);
 
2640
  
 
2641
  if (lobFieldsRequested())
 
2642
  {
 
2643
    forceSingleRowRead = true;
 
2644
    rowsToRead = 1;
 
2645
  }
 
2646
  
 
2647
  rowsToRead = min(stats.records+1,min(rowsToRead, DEFAULT_MAX_ROWS_TO_BUFFER));
 
2648
  
 
2649
  uint bufSize = min((format->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size));
 
2650
  multiRowReadBuf.allocBuf(format->readRowLen, format->readRowNullOffset, bufSize);
 
2651
  activeReadBuf = &multiRowReadBuf;
 
2652
    
 
2653
  if (db2Table->hasBlobs())
 
2654
  {
 
2655
    if (!blobReadBuffers)
 
2656
      blobReadBuffers = new BlobCollection(db2Table, THDVAR(thd, lob_alloc_size));  
 
2657
    rc = prepareReadBufferForLobs();
 
2658
    if (rc) DBUG_RETURN(rc);
 
2659
  }
 
2660
  
 
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);
 
2665
//   else
 
2666
    activeReadBuf->update(intent, &releaseRowNeeded, cmtLvl);
 
2667
 
 
2668
  DBUG_RETURN(rc);
 
2669
}
 
2670
 
 
2671
 
 
2672
int ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file)
 
2673
{
 
2674
  DBUG_ENTER("ha_ibmdb2i::prepWriteBuffer");
 
2675
  DBUG_ASSERT(accessIntent == QMY_UPDATABLE && rowsToWrite > 0);
 
2676
  
 
2677
  const db2i_file::RowFormat* format;
 
2678
  int rc = file->obtainRowFormat(activeHandle,
 
2679
                                 QMY_UPDATABLE,
 
2680
                                 getCommitLevel(ha_thd()),
 
2681
                                 &format);
 
2682
 
 
2683
  if (unlikely(rc)) DBUG_RETURN(rc);
 
2684
  
 
2685
  rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER);
 
2686
  
 
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;
 
2690
 
 
2691
  if (!blobWriteBuffers && db2Table->hasBlobs())
 
2692
  {
 
2693
    blobWriteBuffers = new ValidatedPointer<char>[db2Table->getBlobCount()];
 
2694
  }    
 
2695
  DBUG_RETURN(rc);
 
2696
}
 
2697
 
 
2698
 
 
2699
int ha_ibmdb2i::flushWrite(FILE_HANDLE fileHandle, uchar* buf )
 
2700
{
 
2701
  DBUG_ENTER("ha_ibmdb2i::flushWrite");
 
2702
  int rc;
 
2703
  int64 generatedIdValue = 0;
 
2704
  bool IdValueWasGenerated = FALSE;
 
2705
  char* lastDupKeyNamePtr = NULL;
 
2706
  uint32 lastDupKeyNameLen = 0;
 
2707
  int loopCnt = 0; 
 
2708
  bool retry_dup = FALSE; 
 
2709
 
 
2710
 while (loopCnt == 0 || retry_dup == TRUE) 
 
2711
 {
 
2712
  rc = bridge()->writeRows(fileHandle,
 
2713
                           activeWriteBuf->ptr(),
 
2714
                           getCommitLevel(),  
 
2715
                           &generatedIdValue,
 
2716
                           &IdValueWasGenerated,
 
2717
                           &lastDupKeyRRN,
 
2718
                           &lastDupKeyNamePtr,
 
2719
                           &lastDupKeyNameLen,
 
2720
                           &incrementByValue);
 
2721
  loopCnt++;  
 
2722
  retry_dup = FALSE;
 
2723
  invalidateCachedStats();
 
2724
  if (lastDupKeyNameLen)
 
2725
  {
 
2726
    rrnAssocHandle = fileHandle;
 
2727
    
 
2728
    int command = thd_sql_command(ha_thd());
 
2729
 
 
2730
    if (command == SQLCOM_REPLACE ||
 
2731
        command == SQLCOM_REPLACE_SELECT)
 
2732
      lastDupKeyID = 0;
 
2733
    else
 
2734
    {
 
2735
      lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen);
 
2736
      
 
2737
      if (likely(lastDupKeyID != MAX_KEY))
 
2738
      {
 
2739
        uint16 failedRow = activeWriteBuf->rowsWritten()+1; 
 
2740
 
 
2741
        if (buf && (failedRow != activeWriteBuf->rowCount()))
 
2742
        {
 
2743
          const char* badRow = activeWriteBuf->getRowN(failedRow-1);
 
2744
          bool savedReadAllColumns = readAllColumns;
 
2745
          readAllColumns = true;
 
2746
          mungeDB2row(buf, 
 
2747
                      badRow, 
 
2748
                      badRow + activeWriteBuf->getRowNullOffset(),
 
2749
                      true);
 
2750
          readAllColumns = savedReadAllColumns;
 
2751
 
 
2752
          if (table->found_next_number_field)
 
2753
          {
 
2754
            table->next_number_field->store(next_identity_value - (incrementByValue * (activeWriteBuf->rowCount() - (failedRow - 1))));
 
2755
          }
 
2756
        }
 
2757
 
 
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
 
2763
        {  
 
2764
          if (alterStartWith() == 0)                  // Reset next Identity value to max+1
 
2765
            retry_dup = TRUE;                         // Rtry the write operation
 
2766
        } 
 
2767
      }
 
2768
      else
 
2769
      {
 
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);
 
2774
      }
 
2775
    }
 
2776
  }
 
2777
 } 
 
2778
 
 
2779
  if ((rc == 0 || rc == HA_ERR_FOUND_DUPP_KEY)
 
2780
         && default_identity_value && IdValueWasGenerated &&
 
2781
     (!autoIncLockAcquired || !got_auto_inc_values))
 
2782
  {
 
2783
    /* Save the generated identity value for the MySQL last_insert_id() function. */
 
2784
    insert_id_for_cur_row = generatedIdValue;
 
2785
 
 
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)
 
2790
    {
 
2791
      got_auto_inc_values = TRUE;
 
2792
      next_identity_value = generatedIdValue + incrementByValue;
 
2793
    }
 
2794
  } 
 
2795
  else
 
2796
  {
 
2797
    if (!autoIncLockAcquired)      // Don't overlay value for first row of a block  
 
2798
      insert_id_for_cur_row = 0;                                        
 
2799
  }
 
2800
  
 
2801
 
 
2802
  activeWriteBuf->resetAfterWrite();
 
2803
  DBUG_RETURN(rc);
 
2804
}
 
2805
 
 
2806
int ha_ibmdb2i::alterStartWith() 
 
2807
 
2808
  DBUG_ENTER("ha_ibmdb2i::alterStartWith");  
 
2809
  int rc = 0; 
 
2810
  ulonglong nextIdVal; 
 
2811
  if (!dataHandle) 
 
2812
     rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
 
2813
  if (!rc) {rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LENR, QMY_YES);}
 
2814
  if (!rc) 
 
2815
  {  
 
2816
    rc = getNextIdVal(&nextIdVal); 
 
2817
    if (!rc) {rc = reset_auto_increment(nextIdVal);} 
 
2818
    bridge()->lockObj(dataHandle,  0, QMY_UNLOCK, QMY_LENR, QMY_YES); 
 
2819
  } 
 
2820
  DBUG_RETURN(rc); 
 
2821
}
 
2822
 
 
2823
bool ha_ibmdb2i::lobFieldsRequested()
 
2824
{
 
2825
  if (!db2Table->hasBlobs())
 
2826
  {
 
2827
    DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs"));
 
2828
    return (false);
 
2829
  }
 
2830
 
 
2831
  if (readAllColumns)
 
2832
  {
 
2833
    DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("All cols requested"));
 
2834
    return (true);
 
2835
  }
 
2836
    
 
2837
  for (int i = 0; i < db2Table->getBlobCount(); ++i)
 
2838
  {
 
2839
    if (bitmap_is_set(table->read_set, db2Table->blobFields[i]))
 
2840
    {
 
2841
      DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("LOB requested"));
 
2842
      return (true);
 
2843
    }
 
2844
  }
 
2845
  
 
2846
  DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs requested"));
 
2847
  return (false);
 
2848
}
 
2849
 
 
2850
 
 
2851
int ha_ibmdb2i::prepareReadBufferForLobs()
 
2852
{
 
2853
  DBUG_ENTER("ha_ibmdb2i::prepareReadBufferForLobs");
 
2854
  DBUG_ASSERT(db2Table->hasBlobs());
 
2855
  
 
2856
  uint32 activeLobFields = 0;
 
2857
  DB2LobField* lobField;
 
2858
  uint16 blobCount = db2Table->getBlobCount();
 
2859
    
 
2860
  char* readBuf = activeReadBuf->getRowN(0);
 
2861
  
 
2862
  for (int i = 0; i < blobCount; ++i)
 
2863
  {
 
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))
 
2869
    {
 
2870
      lobField->dataHandle = (ILEMemHandle)blobReadBuffers->getBufferPtr(fieldID);
 
2871
      activeLobFields++;
 
2872
    }
 
2873
    else
 
2874
    {
 
2875
      lobField->dataHandle = NULL;
 
2876
    }
 
2877
  }
 
2878
  
 
2879
  if (activeLobFields == 0)
 
2880
  {
 
2881
    for (int i = 0; i < blobCount; ++i)
 
2882
    {
 
2883
      DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
 
2884
      uint16 offset = db2Field.getBufferOffset() + db2Field.calcBlobPad();
 
2885
 
 
2886
      for (int r = 1; r < activeReadBuf->getRowCapacity(); ++r)
 
2887
      { 
 
2888
        lobField = (DB2LobField*)(activeReadBuf->getRowN(r) + offset);
 
2889
        lobField->dataHandle = NULL;
 
2890
      }      
 
2891
    }
 
2892
  }
 
2893
 
 
2894
  activeReadBuf->setRowsToProcess((activeLobFields ? 1 : activeReadBuf->getRowCapacity()));
 
2895
  int rc = bridge()->objectOverride(activeHandle,
 
2896
                                    activeReadBuf->ptr(),
 
2897
                                    activeReadBuf->getRowLength());
 
2898
  DBUG_RETURN(rc);
 
2899
}
 
2900
 
 
2901
 
 
2902
uint32 ha_ibmdb2i::adjustLobBuffersForRead()
 
2903
{
 
2904
  DBUG_ENTER("ha_ibmdb2i::adjustLobBuffersForRead");
 
2905
 
 
2906
  char* readBuf = activeReadBuf->getRowN(0);
 
2907
   
 
2908
  for (int i = 0; i < db2Table->getBlobCount(); ++i)
 
2909
  {
 
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]))
 
2914
    {
 
2915
      lobField->dataHandle = (ILEMemHandle)blobReadBuffers->reallocBuffer(db2Table->blobFields[i], lobField->length);
 
2916
 
 
2917
      if (lobField->dataHandle == NULL)
 
2918
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
2919
    }      
 
2920
    else
 
2921
    {
 
2922
      lobField->dataHandle = 0;
 
2923
    }
 
2924
  }
 
2925
  
 
2926
  int32 rc = bridge()->objectOverride(activeHandle,
 
2927
                                      activeReadBuf->ptr());
 
2928
  DBUG_RETURN(rc);
 
2929
}
 
2930
 
 
2931
 
 
2932
 
 
2933
int ha_ibmdb2i::reset()
 
2934
{
 
2935
  DBUG_ENTER("ha_ibmdb2i::reset");
 
2936
 
 
2937
  if (outstanding_start_bulk_insert)
 
2938
  {
 
2939
    finishBulkInsert();
 
2940
  }  
 
2941
  
 
2942
  if (activeHandle != 0)
 
2943
  {
 
2944
    releaseActiveHandle();
 
2945
  }
 
2946
  
 
2947
  cleanupBuffers();
 
2948
  
 
2949
  db2i_ileBridge::getBridgeForThread(ha_thd())->freeErrorStorage();
 
2950
    
 
2951
  last_rnd_init_rc = last_index_init_rc = last_start_bulk_insert_rc = 0;
 
2952
 
 
2953
  returnDupKeysImmediately = false;
 
2954
  onDupUpdate = false;
 
2955
  forceSingleRowRead = false; 
 
2956
 
 
2957
#ifndef DBUG_OFF
 
2958
  cachedBridge=NULL;
 
2959
#endif      
 
2960
      
 
2961
  DBUG_RETURN(0);
 
2962
}
 
2963
 
 
2964
 
 
2965
int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream, 
 
2966
                                           KEY& key,
 
2967
                                           bool isPrimary,
 
2968
                                           const char* db2LibName,    
 
2969
                                           const char* db2FileName)
 
2970
{
 
2971
  DBUG_ENTER("ha_ibmdb2i::buildCreateIndexStatement");
 
2972
 
 
2973
  char fileSortSequence[11] = "*HEX";
 
2974
  char fileSortSequenceLibrary[11] = "";
 
2975
  char fileSortSequenceType = ' ';
 
2976
  String query(256);
 
2977
  query.length(0);
 
2978
  int rc = 0;
 
2979
  
 
2980
  if (isPrimary)
 
2981
  {
 
2982
    query.append(STRING_WITH_LEN("ALTER TABLE "));
 
2983
    query.append(db2LibName);
 
2984
    query.append('.');
 
2985
    query.append(db2FileName);
 
2986
    query.append(STRING_WITH_LEN(" ADD PRIMARY KEY "));    
 
2987
  }
 
2988
  else
 
2989
  {
 
2990
    query.append(STRING_WITH_LEN("CREATE"));
 
2991
 
 
2992
    if (key.flags & HA_NOSAME)
 
2993
      query.append(STRING_WITH_LEN(" UNIQUE WHERE NOT NULL"));
 
2994
 
 
2995
    query.append(STRING_WITH_LEN(" INDEX "));
 
2996
 
 
2997
    query.append(db2LibName);
 
2998
    query.append('.');
 
2999
    if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, query))
 
3000
    {
 
3001
      getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
3002
      DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
3003
    }
 
3004
 
 
3005
    query.append(STRING_WITH_LEN(" ON "));
 
3006
 
 
3007
    query.append(db2LibName);
 
3008
    query.append('.');
 
3009
    query.append(db2FileName);
 
3010
  }
 
3011
  
 
3012
  String fieldDefinition(128);
 
3013
  rc = buildIndexFieldList(fieldDefinition,
 
3014
                           key,
 
3015
                           isPrimary,
 
3016
                           &fileSortSequenceType, 
 
3017
                           fileSortSequence,
 
3018
                           fileSortSequenceLibrary);
 
3019
  
 
3020
  if (rc) DBUG_RETURN(rc);
 
3021
   
 
3022
  query.append(fieldDefinition);
 
3023
  
 
3024
  if ((THDVAR(ha_thd(), create_index_option)==1) &&
 
3025
      (fileSortSequenceType != 'B') &&
 
3026
      (fileSortSequenceType != ' '))
 
3027
  {
 
3028
    rc = generateShadowIndex(sqlStream, 
 
3029
                             key, 
 
3030
                             db2LibName, 
 
3031
                             db2FileName, 
 
3032
                             fieldDefinition);
 
3033
    if (rc) DBUG_RETURN(rc);
 
3034
  }
 
3035
    
 
3036
  DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",query.c_ptr_safe()));
 
3037
  sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
 
3038
 
 
3039
  DBUG_RETURN(0);
 
3040
}
 
3041
 
 
3042
/**
 
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.
 
3045
      
 
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
 
3052
  
 
3053
  @return  0 if successful; error value otherwise
 
3054
*/
 
3055
int32 ha_ibmdb2i::buildIndexFieldList(String& appendHere,
 
3056
                                      const KEY& key,
 
3057
                                      bool isPrimary,
 
3058
                                      char* fileSortSequenceType, 
 
3059
                                      char* fileSortSequence, 
 
3060
                                      char* fileSortSequenceLibrary)
 
3061
{
 
3062
  DBUG_ENTER("ha_ibmdb2i::buildIndexFieldList");
 
3063
  appendHere.append(STRING_WITH_LEN(" ( "));
 
3064
  for (int j = 0; j < key.key_parts; ++j)
 
3065
  {
 
3066
    char colName[MAX_DB2_COLNAME_LENGTH+1];
 
3067
    if (j != 0)
 
3068
    {
 
3069
      appendHere.append(STRING_WITH_LEN(" , "));
 
3070
    }
 
3071
    
 
3072
    KEY_PART_INFO& kpi = key.key_part[j];
 
3073
    Field* field = kpi.field;
 
3074
    
 
3075
    convertMySQLNameToDB2Name(field->field_name, 
 
3076
                              colName, 
 
3077
                              sizeof(colName));
 
3078
    appendHere.append(colName);
 
3079
    
 
3080
    int32 rc;
 
3081
    rc = updateAssociatedSortSequence(field->charset(),
 
3082
                                      fileSortSequenceType,
 
3083
                                      fileSortSequence,
 
3084
                                      fileSortSequenceLibrary);
 
3085
    if (rc) DBUG_RETURN (rc);
 
3086
  }
 
3087
    
 
3088
  appendHere.append(STRING_WITH_LEN(" ) "));
 
3089
  
 
3090
  DBUG_RETURN(0);
 
3091
}
 
3092
 
 
3093
 
 
3094
/**
 
3095
  Generate an SQL statement that defines a *HEX sorted index to implement 
 
3096
  the ibmdb2i_create_index.
 
3097
      
 
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
 
3103
  
 
3104
  @return  0 if successful; error value otherwise
 
3105
*/
 
3106
int32 ha_ibmdb2i::generateShadowIndex(SqlStatementStream& stream, 
 
3107
                                      const KEY& key,
 
3108
                                      const char* libName,
 
3109
                                      const char* fileName,
 
3110
                                      const String& fieldDefinition)
 
3111
{
 
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))
 
3118
  {
 
3119
    getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
3120
    return DB2I_ERR_INVALID_NAME;
 
3121
  }
 
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");
 
3129
  return 0;
 
3130
}
 
3131
  
 
3132
  
 
3133
void ha_ibmdb2i::doInitialRead(char orientation,
 
3134
                                uint32 rowsToBuffer,
 
3135
                                ILEMemHandle key,
 
3136
                                int keyLength,
 
3137
                                int keyParts)
 
3138
{
 
3139
  DBUG_ENTER("ha_ibmdb2i::doInitialRead");
 
3140
  
 
3141
  if (forceSingleRowRead)
 
3142
    rowsToBuffer = 1;
 
3143
  else
 
3144
    rowsToBuffer = min(rowsToBuffer, activeReadBuf->getRowCapacity());
 
3145
        
 
3146
  activeReadBuf->newReadRequest(activeHandle,
 
3147
                                    orientation,
 
3148
                                    rowsToBuffer,
 
3149
                                    THDVAR(ha_thd(), async_enabled),
 
3150
                                    key, 
 
3151
                                    keyLength,
 
3152
                                    keyParts);
 
3153
  DBUG_VOID_RETURN;
 
3154
}
 
3155
 
 
3156
 
 
3157
int ha_ibmdb2i::start_stmt(THD *thd, thr_lock_type lock_type)
 
3158
{
 
3159
  DBUG_ENTER("ha_ibmdb2i::start_stmt");
 
3160
  initBridge(thd);
 
3161
  if (!THDVAR(thd, transaction_unsafe))
 
3162
  {
 
3163
    trans_register_ha(thd, FALSE, ibmdb2i_hton);
 
3164
    
 
3165
    if (!autoCommitIsOn(thd))
 
3166
    {
 
3167
      bridge()->beginStmtTx();
 
3168
    }
 
3169
  }
 
3170
 
 
3171
  DBUG_RETURN(0);
 
3172
}
 
3173
 
 
3174
int32 ha_ibmdb2i::handleLOBReadOverflow()
 
3175
{
 
3176
  DBUG_ENTER("ha_ibmdb2i::handleLOBReadOverflow");
 
3177
  DBUG_ASSERT(db2Table->hasBlobs() && (activeReadBuf->getRowCapacity() == 1));
 
3178
 
 
3179
  int32 rc = adjustLobBuffersForRead();
 
3180
 
 
3181
  if (!rc)
 
3182
  {
 
3183
    activeReadBuf->rewind();
 
3184
    rc = bridge()->expectErrors(QMY_ERR_END_OF_BLOCK)
 
3185
                 ->read(activeHandle, 
 
3186
                        activeReadBuf->ptr(),
 
3187
                        accessIntent,
 
3188
                        getCommitLevel(),
 
3189
                        QMY_SAME);
 
3190
    releaseRowNeeded = TRUE;
 
3191
 
 
3192
  }
 
3193
  DBUG_RETURN(rc);
 
3194
}
 
3195
 
 
3196
 
 
3197
int32 ha_ibmdb2i::finishBulkInsert()
 
3198
{
 
3199
  int32 rc = 0;
 
3200
 
 
3201
  if (activeWriteBuf->rowCount() && activeHandle)
 
3202
    rc = flushWrite(activeHandle, table->record[0]);
 
3203
 
 
3204
  if (activeHandle)
 
3205
    releaseActiveHandle();
 
3206
 
 
3207
  if (autoIncLockAcquired == TRUE)
 
3208
  {
 
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;
 
3214
  } 
 
3215
  outstanding_start_bulk_insert = false;
 
3216
  multiRowWriteBuf.freeBuf();    
 
3217
  last_start_bulk_insert_rc = 0;
 
3218
 
 
3219
  resetCharacterConversionBuffers();
 
3220
 
 
3221
  return rc;
 
3222
}
 
3223
 
 
3224
int ha_ibmdb2i::getKeyFromName(const char* name, size_t len)  
 
3225
{
 
3226
  for (int i = 0; i < table_share->keys; ++i)
 
3227
  {
 
3228
    const char* indexName = db2Table->indexFile(i)->getDB2FileName();
 
3229
    if ((strncmp(name, indexName, len) == 0) &&
 
3230
        (strlen(indexName) == len))
 
3231
    {
 
3232
      return i;        
 
3233
    }
 
3234
  }
 
3235
  return MAX_KEY;
 
3236
}
 
3237
 
 
3238
/*                                                                       
 
3239
Determine the number of I/O's it takes to read through the table.        
 
3240
                                                                      */
 
3241
double ha_ibmdb2i::scan_time()
 
3242
  {
 
3243
    DBUG_ENTER("ha_ibmdb2i::scan_time");
 
3244
    DBUG_RETURN(ulonglong2double((stats.data_file_length)/IO_SIZE));
 
3245
  }
 
3246
 
 
3247
 
 
3248
/**
 
3249
  Estimate the number of I/O's it takes to read a set of ranges through
 
3250
  an index.                                                            
 
3251
  
 
3252
  @param index  
 
3253
  @param ranges  
 
3254
  @param rows  
 
3255
  
 
3256
  @return The estimate number of I/Os
 
3257
*/
 
3258
 
 
3259
double ha_ibmdb2i::read_time(uint index, uint ranges, ha_rows rows)
 
3260
{
 
3261
  DBUG_ENTER("ha_ibmdb2i::read_time");
 
3262
  int rc;
 
3263
  uint64 idxPageCnt = 0;
 
3264
  double cost;
 
3265
  
 
3266
  if (unlikely(rows == HA_POS_ERROR))
 
3267
    DBUG_RETURN(double(rows) + ranges);
 
3268
 
 
3269
  rc = bridge()->retrieveIndexInfo(db2Table->indexFile(index)->getMasterDefnHandle(),
 
3270
                                                        &idxPageCnt);                     
 
3271
  if (!rc)
 
3272
  {
 
3273
     if ((idxPageCnt == 1) ||            // Retrieving rows in requested order or
 
3274
         (ranges == rows))               // 'Sweep' full records retrieval           
 
3275
       cost = idxPageCnt/4;
 
3276
     else
 
3277
     {  
 
3278
       uint64 totalRecords = stats.records + 1;
 
3279
       double dataPageCount = stats.data_file_length/IO_SIZE;
 
3280
                  
 
3281
       cost = (rows * dataPageCount / totalRecords) + 
 
3282
               min(idxPageCnt, (log_2(idxPageCnt) * ranges + 
 
3283
                                rows * (log_2(idxPageCnt) + log_2(rows) - log_2(totalRecords))));
 
3284
     } 
 
3285
  }
 
3286
  else
 
3287
  {
 
3288
     cost = rows2double(ranges+rows);    // Use default costing
 
3289
  }
 
3290
  DBUG_RETURN(cost);
 
3291
}
 
3292
 
 
3293
int ha_ibmdb2i::useIndexFile(int idx)
 
3294
{
 
3295
  DBUG_ENTER("ha_ibmdb2i::useIndexFile");
 
3296
 
 
3297
  if (activeHandle)
 
3298
    releaseActiveHandle();
 
3299
 
 
3300
  int rc = 0;
 
3301
 
 
3302
  if (!indexHandles[idx])
 
3303
    rc = db2Table->indexFile(idx)->allocateNewInstance(&indexHandles[idx], curConnection);
 
3304
 
 
3305
  if (rc == 0)
 
3306
  {
 
3307
      activeHandle = indexHandles[idx];
 
3308
      bumpInUseCounter(1);
 
3309
  }
 
3310
 
 
3311
   DBUG_RETURN(rc);
 
3312
}
 
3313
 
 
3314
 
 
3315
ulong ha_ibmdb2i::index_flags(uint inx, uint part, bool all_parts) const
 
3316
{
 
3317
  return  HA_READ_NEXT | HA_READ_PREV | HA_KEYREAD_ONLY | HA_READ_ORDER | HA_READ_RANGE;
 
3318
}
 
3319
 
 
3320
 
 
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),
 
3337
  NULL
 
3338
};
 
3339
 
 
3340
 
 
3341
struct st_mysql_storage_engine ibmdb2i_storage_engine=
 
3342
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
 
3343
 
 
3344
mysql_declare_plugin(ibmdb2i)
 
3345
{
 
3346
  MYSQL_STORAGE_ENGINE_PLUGIN,
 
3347
  &ibmdb2i_storage_engine,
 
3348
  "IBMDB2I",
 
3349
  "The IBM development team in Rochester, Minnesota",
 
3350
  "IBM DB2 for i Storage Engine",
 
3351
  PLUGIN_LICENSE_GPL,
 
3352
  ibmdb2i_init_func,                            /* Plugin Init */
 
3353
  ibmdb2i_done_func,                            /* Plugin Deinit */
 
3354
  0x0100 /* 1.0 */,
 
3355
  NULL,                                         /* status variables */
 
3356
  ibmdb2i_system_variables,                       /* system variables */
 
3357
  NULL                                          /* config options */
 
3358
}
 
3359
mysql_declare_plugin_end;