~ubuntu-branches/ubuntu/maverick/mysql-5.1/maverick-proposed

« back to all changes in this revision

Viewing changes to storage/ibmdb2i/ha_ibmdb2i.cc

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-22 14:16:05 UTC
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: package-import@ubuntu.com-20120222141605-nxlu9yzc6attylc2
Tags: upstream-5.1.61
ImportĀ upstreamĀ versionĀ 5.1.61

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;