~mathiaz/ubuntu/lucid/mysql-dfsg-5.1/zap-bug-552053

« back to all changes in this revision

Viewing changes to storage/ibmdb2i/ha_ibmdb2i.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2009-06-25 12:55:45 UTC
  • mfrom: (1.1.2 upstream) (0.1.3 experimental)
  • Revision ID: james.westby@ubuntu.com-20090625125545-m8ogs96zzsri74xe
Tags: 5.1.34-1ubuntu1
* Merge from debian experimental (and 5.0 from main), remaining changes:
  - debian/mysql-server-5.1.config:
    + ask for MySQL root password at priority high instead of medium so
      that the password prompt is seen on a default install. (LP: #319843)
    + don't ask for root password when upgrading from a 5.0 install.
  - debian/control:
    + Make libmysqlclient16-dev a transitional package depending on
      libmysqlclient-dev.
    + Make libmysqlclient-dev conflict with libmysqlclient15-dev.
    + Don't build mysql-server, mysql-client, mysql-common and
      libmysqlclient15-dev binary packages since they're still provided
      by mysql-dfsg-5.0.
    + Make mysql-{client,server}-5.1 packages conflict and
      replace mysql-{client,server}-5.0, but not provide
      mysql-{client,server}.
    + Depend on a specific version of mysql-common rather than the src
      version of mysql-dfsg-5.1 since mysql-common is currently part of
      mysql-dfsg-5.0.
    + Lower mailx from a Recommends to a Suggests to avoid pulling in
      a full MTA on all installs of mysql-server. (LP: #259477)
  - debian/rules:
    + added -fno-strict-aliasing to CFLAGS to get around mysql testsuite
      build failures.
    + install mysql-test and sql-bench to /usr/share/mysql/ rather than
      /usr/.
  - debian/additions/debian-start.inc.sh: support ANSI mode (LP: #310211)
  - Add AppArmor profile:
    - debian/apparmor-profile: apparmor profile.
    - debian/rules, debian/mysql-server-5.0.files: install apparmor profile.
    - debian/mysql-server-5.0.dirs: add etc/apparmor.d/force-complain
    - debian/mysql-server-5.0.postrm: remove symlink in force-complain/ on
      purge.
    - debian/mysql-server-5.1.README.Debian: add apparmor documentation.
    - debian/additions/my.cnf: Add warning about apparmor. (LP: #201799)
    - debian/mysql-server-5.1.postinst: reload apparmor profiles.
  - debian/additions/my.cnf: remove language option. Error message files are
    located in a different directory in MySQL 5.0. Setting the language
    option to use /usr/share/mysql/english breaks 5.0. Both 5.0 and 5.1
    use a default value that works. (LP: #316974)
  - debian/mysql-server-5.1.mysql.init:
    + Clearly indicate that we do not support running multiple instances
      of mysqld by duplicating the init script.
      (closes: #314785, #324834, #435165, #444216)
    + Properly parameterize all existing references to the mysql config
      file (/etc/mysql/my.cnf).
  - debian/mysql-server-5.0.postinst: Clear out the second password
    when setting up mysql. (LP: #344816)
  - mysql-server-core-5.1 package for files needed by Akonadi:
    + debian/control: create mysql-server-core-5.1 package.
    + debian/mysql-server-core-5.1.files, debian/mysql-server-5.1.files:
      move core mysqld files to mysql-server-core-5.1 package.
  - Don't package sql-bench and mysql-test file.
* Dropped changes:
  - debian/patches/92_ssl_test_cert.dpatch: certificate expiration in
    test suite (LP: #323755). Included upstream.
* Dropped from 5.0:
  - apparmor profile:
    - debian/control: Recommends apparmor >= 2.1+1075-0ubuntu6. All version
      of apparmor-profile (>hardy) are higher than this version.
    - debian/mysql-server-5.0.preinst: create symlink for force-complain/
      on pre-feisty upgrades, upgrades where apparmor-profiles profile is
      unchanged (ie non-enforcing) and upgrades where the profile
      doesn't exist. Support for pre-hardy upgrades is no longer needed.
* debian/mysql-server-5.1.postinst: fix debian-sys-maint user creation.

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,system_charset_info,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
  DBUG_RETURN(rc); 
 
902
}
 
903
 
 
904
 
 
905
 
 
906
int ha_ibmdb2i::index_read(uchar * buf, const uchar * key,
 
907
                           uint key_len,
 
908
                           enum ha_rkey_function find_flag)
 
909
{
 
910
  DBUG_ENTER("ha_ibmdb2i::index_read");
 
911
 
 
912
  if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
 
913
 
 
914
  int rc;
 
915
  
 
916
  ha_rows estimatedRows = getIndexReadEstimate(active_index);
 
917
  rc = prepReadBuffer(estimatedRows, db2Table->indexFile(active_index), readAccessIntent);  
 
918
  if (unlikely(rc)) DBUG_RETURN(rc);
 
919
  
 
920
  DBUG_ASSERT(activeReadBuf);
 
921
  
 
922
  keyBuf.allocBuf(activeReadBuf->getRowLength(), 
 
923
                  activeReadBuf->getRowNullOffset(), 
 
924
                  activeReadBuf->getRowLength());
 
925
  keyBuf.zeroBuf();
 
926
  
 
927
  char* db2KeyBufPtr = keyBuf.ptr();
 
928
  char* nullKeyMap = db2KeyBufPtr + activeReadBuf->getRowNullOffset();
 
929
  
 
930
  const uchar* keyBegin = key;
 
931
  int partsInUse;
 
932
  
 
933
  KEY& curKey = table->key_info[active_index];
 
934
  
 
935
  for (partsInUse = 0; partsInUse < curKey.key_parts, key - keyBegin < key_len; ++partsInUse)
 
936
  {
 
937
    Field* field = curKey.key_part[partsInUse].field;     
 
938
    if ((curKey.key_part[partsInUse].null_bit) &&
 
939
        (char*)key[0])
 
940
    {
 
941
      if (field->flags & AUTO_INCREMENT_FLAG)
 
942
      {
 
943
        table->status = STATUS_NOT_FOUND; 
 
944
        DBUG_RETURN(HA_ERR_END_OF_FILE);
 
945
      }
 
946
      else
 
947
      {
 
948
        nullKeyMap[partsInUse] = __NULL_VALUE_EBCDIC;
 
949
      }
 
950
    }
 
951
    else
 
952
    {
 
953
      nullKeyMap[partsInUse] = __NOT_NULL_VALUE_EBCDIC;
 
954
      convertMySQLtoDB2(field, 
 
955
                        db2Table->db2Field(field->field_index),
 
956
                        db2KeyBufPtr, 
 
957
                        (uchar*)key+((curKey.key_part[partsInUse].null_bit)? 1 : 0) ); // + (curKey.key_parts+7) / 8);
 
958
    }
 
959
   
 
960
    db2KeyBufPtr += db2Table->db2Field(field->field_index).getByteLengthInRecord();
 
961
    key += curKey.key_part[partsInUse].store_length;
 
962
  }
 
963
  
 
964
  keyLen = db2KeyBufPtr - (char*)keyBuf.ptr();
 
965
  
 
966
  DBUG_PRINT("ha_ibmdb2i::index_read", ("find_flag: %d", find_flag));
 
967
 
 
968
  char readDirection = QMY_NEXT;
 
969
    
 
970
  switch (find_flag)
 
971
  {
 
972
    case HA_READ_AFTER_KEY:
 
973
      doInitialRead(QMY_AFTER_EQUAL, estimatedRows,
 
974
                    keyBuf.ptr(), keyLen, partsInUse);
 
975
      break;
 
976
    case HA_READ_BEFORE_KEY:
 
977
      doInitialRead(QMY_BEFORE_EQUAL, estimatedRows,
 
978
                    keyBuf.ptr(), keyLen, partsInUse);
 
979
      break;
 
980
    case HA_READ_KEY_OR_NEXT:
 
981
      doInitialRead(QMY_AFTER_OR_EQUAL, estimatedRows,
 
982
                    keyBuf.ptr(), keyLen, partsInUse);
 
983
      break;
 
984
    case HA_READ_KEY_OR_PREV:
 
985
      DBUG_ASSERT(0); // This function is unused      
 
986
      doInitialRead(QMY_BEFORE_OR_EQUAL, estimatedRows,
 
987
                    keyBuf.ptr(), keyLen, partsInUse);
 
988
      break;
 
989
    case HA_READ_PREFIX_LAST_OR_PREV:
 
990
      doInitialRead(QMY_LAST_PREVIOUS, estimatedRows,
 
991
                    keyBuf.ptr(), keyLen, partsInUse);
 
992
      readDirection = QMY_PREVIOUS;
 
993
      break; 
 
994
    case HA_READ_PREFIX_LAST:
 
995
      doInitialRead(QMY_PREFIX_LAST, estimatedRows,
 
996
                    keyBuf.ptr(), keyLen, partsInUse);
 
997
      readDirection = QMY_PREVIOUS;
 
998
      break; 
 
999
    case HA_READ_KEY_EXACT:
 
1000
      doInitialRead(QMY_EQUAL, estimatedRows, keyBuf.ptr(), keyLen, partsInUse);
 
1001
      break;
 
1002
    default: 
 
1003
        DBUG_ASSERT(0);
 
1004
        return HA_ERR_GENERIC;
 
1005
      break;
 
1006
  }
 
1007
  
 
1008
  ha_statistic_increment(&SSV::ha_read_key_count);
 
1009
  rc = readFromBuffer(buf, readDirection);
 
1010
  
 
1011
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1012
  DBUG_RETURN(rc);
 
1013
}
 
1014
 
 
1015
 
 
1016
int ha_ibmdb2i::index_next(uchar * buf)
 
1017
{
 
1018
  DBUG_ENTER("ha_ibmdb2i::index_next");
 
1019
  ha_statistic_increment(&SSV::ha_read_next_count);
 
1020
  
 
1021
  int rc = readFromBuffer(buf, QMY_NEXT);
 
1022
  
 
1023
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1024
  DBUG_RETURN(rc);
 
1025
}
 
1026
 
 
1027
 
 
1028
int ha_ibmdb2i::index_next_same(uchar *buf, const uchar *key, uint keylen)
 
1029
{
 
1030
  DBUG_ENTER("ha_ibmdb2i::index_next_same");
 
1031
  ha_statistic_increment(&SSV::ha_read_next_count);
 
1032
  
 
1033
  int rc = readFromBuffer(buf, QMY_NEXT_EQUAL);
 
1034
  
 
1035
  if (rc == HA_ERR_KEY_NOT_FOUND)
 
1036
  {
 
1037
    rc = HA_ERR_END_OF_FILE;
 
1038
  }
 
1039
 
 
1040
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1041
  DBUG_RETURN(rc);
 
1042
}
 
1043
 
 
1044
int ha_ibmdb2i::index_read_last(uchar * buf, const uchar * key, uint key_len)
 
1045
{
 
1046
  DBUG_ENTER("ha_ibmdb2i::index_read_last");
 
1047
  DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));  
 
1048
}
 
1049
 
 
1050
 
 
1051
 
 
1052
int ha_ibmdb2i::index_prev(uchar * buf)
 
1053
{
 
1054
  DBUG_ENTER("ha_ibmdb2i::index_prev");
 
1055
  ha_statistic_increment(&SSV::ha_read_prev_count);
 
1056
  
 
1057
  int rc = readFromBuffer(buf, QMY_PREVIOUS);
 
1058
 
 
1059
  table->status= (rc ? STATUS_NOT_FOUND: 0);  
 
1060
  DBUG_RETURN(rc);
 
1061
}
 
1062
 
 
1063
 
 
1064
int ha_ibmdb2i::index_first(uchar * buf)
 
1065
{
 
1066
  DBUG_ENTER("ha_ibmdb2i::index_first");
 
1067
 
 
1068
  if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
 
1069
    
 
1070
  int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER, 
 
1071
                          db2Table->indexFile(active_index), 
 
1072
                          readAccessIntent);
 
1073
  
 
1074
  if (rc == 0)
 
1075
  {
 
1076
    doInitialRead(QMY_FIRST, DEFAULT_MAX_ROWS_TO_BUFFER);
 
1077
    ha_statistic_increment(&SSV::ha_read_first_count);
 
1078
    rc = readFromBuffer(buf, QMY_NEXT);
 
1079
  }
 
1080
  
 
1081
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1082
  DBUG_RETURN(rc);
 
1083
}
 
1084
 
 
1085
 
 
1086
int ha_ibmdb2i::index_last(uchar * buf)
 
1087
{
 
1088
  DBUG_ENTER("ha_ibmdb2i::index_last");
 
1089
  
 
1090
  if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc);
 
1091
  
 
1092
  int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER, 
 
1093
                          db2Table->indexFile(active_index), 
 
1094
                          readAccessIntent);
 
1095
  
 
1096
  if (rc == 0)
 
1097
  {
 
1098
    doInitialRead(QMY_LAST, DEFAULT_MAX_ROWS_TO_BUFFER);
 
1099
    ha_statistic_increment(&SSV::ha_read_last_count);
 
1100
    rc = readFromBuffer(buf, QMY_PREVIOUS);
 
1101
  }
 
1102
  
 
1103
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1104
  DBUG_RETURN(rc);
 
1105
}
 
1106
 
 
1107
 
 
1108
int ha_ibmdb2i::rnd_init(bool scan)
 
1109
{
 
1110
  DBUG_ENTER("ha_ibmdb2i::rnd_init");
 
1111
 
 
1112
  int& rc = last_rnd_init_rc;
 
1113
  rc = 0;
 
1114
      
 
1115
  tweakReadSet();
 
1116
  invalidDataFound=false;
 
1117
  
 
1118
  uint32 rowsToBlockOnRead;
 
1119
 
 
1120
  if (!scan)
 
1121
  { 
 
1122
    rowsToBlockOnRead = 1;
 
1123
  }
 
1124
  else
 
1125
  {
 
1126
    rowsToBlockOnRead = DEFAULT_MAX_ROWS_TO_BUFFER;
 
1127
  }
 
1128
  
 
1129
  rc = useDataFile(); 
 
1130
  
 
1131
  if (!rc)
 
1132
  {
 
1133
//     THD* thd = ha_thd();
 
1134
//     if (accessIntent == QMY_UPDATABLE &&
 
1135
//         thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
 
1136
//         !THDVAR(thd, transaction_unsafe))
 
1137
//     {
 
1138
//       readAccessIntent = QMY_READ_ONLY;
 
1139
//     }
 
1140
//     else
 
1141
//     {
 
1142
      readAccessIntent = accessIntent;
 
1143
//     }
 
1144
 
 
1145
    rc = prepReadBuffer(rowsToBlockOnRead, db2Table->dataFile(), readAccessIntent);
 
1146
 
 
1147
    if (!rc && accessIntent != QMY_READ_ONLY)
 
1148
      rc = prepWriteBuffer(1, db2Table->dataFile());
 
1149
 
 
1150
    if (!rc && scan)
 
1151
      doInitialRead(QMY_FIRST, rowsToBlockOnRead);
 
1152
    
 
1153
    if (rc)
 
1154
      releaseDataFile();
 
1155
  }
 
1156
  
 
1157
  DBUG_RETURN(0); // MySQL sometimes does not check the return code, causing 
 
1158
                  // an assert in ha_rnd_end later on if we return a non-zero
 
1159
                  // value here. 
 
1160
}
 
1161
 
 
1162
int ha_ibmdb2i::rnd_end()
 
1163
{
 
1164
  DBUG_ENTER("ha_ibmdb2i::rnd_end");
 
1165
  
 
1166
  warnIfInvalidData();
 
1167
  if (likely(activeReadBuf))
 
1168
    activeReadBuf->endRead();
 
1169
  if (last_rnd_init_rc == 0)
 
1170
    releaseActiveHandle();
 
1171
  last_rnd_init_rc = 0;
 
1172
  DBUG_RETURN(0);
 
1173
}
 
1174
 
 
1175
 
 
1176
int32 ha_ibmdb2i::mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs)
 
1177
{
 
1178
  DBUG_ASSERT(dataPtr);
 
1179
  
 
1180
  my_bitmap_map *old_write_map= dbug_tmp_use_all_columns(table, table->write_set);
 
1181
  my_bitmap_map *old_read_map;
 
1182
  
 
1183
  if (unlikely(readAllColumns))
 
1184
    old_read_map = tmp_use_all_columns(table, table->read_set);
 
1185
 
 
1186
  resetCharacterConversionBuffers();
 
1187
  
 
1188
  my_ptrdiff_t old_ptr= (my_ptrdiff_t) (record - table->record[0]); 
 
1189
  int fieldIndex = 0;
 
1190
  for (Field **field = table->field; *field; ++field, ++fieldIndex)
 
1191
  {  
 
1192
    if (unlikely(old_ptr))   
 
1193
      (*field)->move_field_offset(old_ptr);
 
1194
    if (nullMapPtr[fieldIndex] == __NULL_VALUE_EBCDIC ||
 
1195
        (!bitmap_is_set(table->read_set, fieldIndex)) ||
 
1196
        (skipLOBs && db2Table->db2Field(fieldIndex).isBlob()))
 
1197
    {
 
1198
      (*field)->set_null();
 
1199
    }
 
1200
    else
 
1201
    {
 
1202
      (*field)->set_notnull();
 
1203
      convertDB2toMySQL(db2Table->db2Field(fieldIndex), *field, dataPtr);
 
1204
    }
 
1205
    if (unlikely(old_ptr))
 
1206
      (*field)->move_field_offset(-old_ptr);
 
1207
    
 
1208
  }
 
1209
    
 
1210
  if (unlikely(readAllColumns))
 
1211
    tmp_restore_column_map(table->read_set, old_read_map);
 
1212
  dbug_tmp_restore_column_map(table->write_set, old_write_map);
 
1213
  
 
1214
  return 0;
 
1215
}
 
1216
 
 
1217
 
 
1218
int ha_ibmdb2i::rnd_next(uchar *buf)
 
1219
{
 
1220
  DBUG_ENTER("ha_ibmdb2i::rnd_next");
 
1221
 
 
1222
  if (unlikely(last_rnd_init_rc)) DBUG_RETURN(last_rnd_init_rc);
 
1223
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
1224
  
 
1225
  int rc;      
 
1226
  
 
1227
  rc = readFromBuffer(buf, QMY_NEXT);
 
1228
    
 
1229
  table->status= (rc ? STATUS_NOT_FOUND: 0);
 
1230
  DBUG_RETURN(rc);
 
1231
}
 
1232
 
 
1233
 
 
1234
void ha_ibmdb2i::position(const uchar *record)
 
1235
{
 
1236
  DBUG_ENTER("ha_ibmdb2i::position");
 
1237
  my_store_ptr(ref, ref_length, currentRRN);
 
1238
  DBUG_VOID_RETURN;
 
1239
}
 
1240
 
 
1241
 
 
1242
int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos)
 
1243
{
 
1244
  DBUG_ENTER("ha_ibmdb2i::rnd_pos");
 
1245
  if (unlikely(last_rnd_init_rc)) DBUG_RETURN( last_rnd_init_rc);
 
1246
  ha_statistic_increment(&SSV::ha_read_rnd_count);
 
1247
 
 
1248
  currentRRN = my_get_ptr(pos, ref_length);
 
1249
 
 
1250
  tweakReadSet();  
 
1251
  
 
1252
  int rc = 0;
 
1253
 
 
1254
  if (activeHandle != rrnAssocHandle) 
 
1255
  {
 
1256
    if (activeHandle) releaseActiveHandle();
 
1257
    rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle);    
 
1258
  }
 
1259
  
 
1260
  if (likely(rc == 0))
 
1261
  {
 
1262
    rc = prepReadBuffer(1, getFileForActiveHandle(), accessIntent);
 
1263
 
 
1264
    if (likely(rc == 0) && accessIntent == QMY_UPDATABLE)
 
1265
      rc = prepWriteBuffer(1, getFileForActiveHandle());
 
1266
 
 
1267
    if (likely(rc == 0))
 
1268
    {
 
1269
      rc = db2i_ileBridge::getBridgeForThread()->readByRRN(activeHandle, 
 
1270
                                                         activeReadBuf->ptr(),
 
1271
                                                         currentRRN,
 
1272
                                                         accessIntent,
 
1273
                                                         getCommitLevel());
 
1274
 
 
1275
      if (likely(rc == 0))
 
1276
      {
 
1277
        rrnAssocHandle = activeHandle;
 
1278
        const char* readBuf = activeReadBuf->getRowN(0);
 
1279
        rc = mungeDB2row(buf, readBuf, readBuf + activeReadBuf->getRowNullOffset(), false);
 
1280
        releaseRowNeeded = TRUE;
 
1281
      }
 
1282
    }    
 
1283
  }
 
1284
  
 
1285
  DBUG_RETURN(rc);
 
1286
}
 
1287
 
 
1288
 
 
1289
int ha_ibmdb2i::info(uint flag)
 
1290
{
 
1291
  DBUG_ENTER("ha_ibmdb2i::info");
 
1292
 
 
1293
  uint16 infoRequested = 0;
 
1294
  ValidatedPointer<char> rowKeySpcPtr;  // Space pointer passed to DB2
 
1295
  uint32 rowKeySpcLen;                  // Length of space passed to DB2
 
1296
  THD* thd = ha_thd();
 
1297
  int command = thd_sql_command(thd);
 
1298
  
 
1299
  if (flag & HA_STATUS_AUTO)
 
1300
    stats.auto_increment_value = (ulonglong) 0;
 
1301
 
 
1302
  if (flag & HA_STATUS_ERRKEY)
 
1303
  {
 
1304
    errkey = lastDupKeyID;
 
1305
    my_store_ptr(dup_ref, ref_length, lastDupKeyRRN);
 
1306
  }
 
1307
  
 
1308
  if (flag & HA_STATUS_TIME)
 
1309
  {
 
1310
    if ((flag & HA_STATUS_NO_LOCK) && 
 
1311
        ibmdb2i_assume_exclusive_use &&
 
1312
        share &&
 
1313
        (share->cachedStats.isInited(lastModTime)))
 
1314
      stats.update_time = share->cachedStats.getUpdateTime();
 
1315
    else
 
1316
      infoRequested |= lastModTime;
 
1317
  }
 
1318
  
 
1319
  if (flag & HA_STATUS_CONST)
 
1320
  {
 
1321
    stats.block_size=4096;
 
1322
    infoRequested |= createTime;
 
1323
    
 
1324
    if (table->s->keys)
 
1325
    {
 
1326
      infoRequested |= rowsPerKey;
 
1327
      rowKeySpcLen = (table->s->keys) * MAX_DB2_KEY_PARTS * sizeof(uint64);
 
1328
      rowKeySpcPtr.alloc(rowKeySpcLen);
 
1329
      memset(rowKeySpcPtr, 0, rowKeySpcLen);               // Clear the allocated space
 
1330
    }
 
1331
  }
 
1332
  
 
1333
  if (flag & HA_STATUS_VARIABLE)
 
1334
  {
 
1335
    if ((flag & HA_STATUS_NO_LOCK) &&
 
1336
        (command != SQLCOM_SHOW_TABLE_STATUS) &&
 
1337
        ibmdb2i_assume_exclusive_use &&
 
1338
        share &&
 
1339
        (share->cachedStats.isInited(rowCount | deletedRowCount | meanRowLen | ioCount)) &&
 
1340
        (share->cachedStats.getRowCount() >= 2))
 
1341
    {
 
1342
      stats.records = share->cachedStats.getRowCount();
 
1343
      stats.deleted = share->cachedStats.getDelRowCount();
 
1344
      stats.mean_rec_length = share->cachedStats.getMeanLength();
 
1345
      stats.data_file_length = share->cachedStats.getAugmentedDataLength();
 
1346
    }
 
1347
    else
 
1348
    {
 
1349
      infoRequested |= rowCount | deletedRowCount | meanRowLen;            
 
1350
      if (command == SQLCOM_SHOW_TABLE_STATUS)
 
1351
        infoRequested |= objLength;
 
1352
      else
 
1353
        infoRequested |= ioCount;
 
1354
    }
 
1355
  }
 
1356
 
 
1357
  int rc = 0;
 
1358
          
 
1359
  if (infoRequested)
 
1360
  {
 
1361
    DBUG_PRINT("ha_ibmdb2i::info",("Retrieving fresh stats %d", flag));
 
1362
 
 
1363
    initBridge(thd);
 
1364
    rc = bridge()->retrieveTableInfo((dataHandle  ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
 
1365
                                     infoRequested,
 
1366
                                     stats,
 
1367
                                     rowKeySpcPtr);
 
1368
    
 
1369
    if (!rc)
 
1370
    {
 
1371
      if ((flag & HA_STATUS_VARIABLE) &&
 
1372
          (command != SQLCOM_SHOW_TABLE_STATUS))
 
1373
        stats.data_file_length = stats.data_file_length * IO_SIZE;
 
1374
 
 
1375
      if ((ibmdb2i_assume_exclusive_use) &&
 
1376
          (share) && 
 
1377
          (command != SQLCOM_SHOW_TABLE_STATUS))
 
1378
      {
 
1379
        if (flag & HA_STATUS_VARIABLE) 
 
1380
        {
 
1381
          share->cachedStats.cacheRowCount(stats.records);
 
1382
          share->cachedStats.cacheDelRowCount(stats.deleted);
 
1383
          share->cachedStats.cacheMeanLength(stats.mean_rec_length);
 
1384
          share->cachedStats.cacheAugmentedDataLength(stats.data_file_length);
 
1385
        }
 
1386
 
 
1387
        if (flag & HA_STATUS_TIME)
 
1388
        {
 
1389
          share->cachedStats.cacheUpdateTime(stats.update_time);
 
1390
        }
 
1391
      }
 
1392
 
 
1393
      if (flag & HA_STATUS_CONST)
 
1394
      {
 
1395
        ulong i;                 // Loop counter for indexes
 
1396
        ulong j;                 // Loop counter for key parts
 
1397
        RowKey* rowKeyPtr;       // Pointer to 'number of unique rows' array for this index
 
1398
 
 
1399
        rowKeyPtr = (RowKey_t*)(void*)rowKeySpcPtr;    // Address first array of DB2 row counts
 
1400
        for (i = 0; i < table->s->keys; i++)           // Do for each index, including primary
 
1401
        {
 
1402
          for (j = 0; j < table->key_info[i].key_parts; j++)   
 
1403
          {
 
1404
            table->key_info[i].rec_per_key[j]= rowKeyPtr->RowKeyArray[j];
 
1405
          }
 
1406
          rowKeyPtr = rowKeyPtr + 1;                   // Address next array of DB2 row counts 
 
1407
        }
 
1408
      }
 
1409
    }
 
1410
    else if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && share)
 
1411
    {
 
1412
      // If we couldn't retrieve the info because the object was locked,
 
1413
      // we'll do our best by returning the most recently cached data.
 
1414
      if ((infoRequested & rowCount) &&
 
1415
          share->cachedStats.isInited(rowCount))
 
1416
        stats.records = share->cachedStats.getRowCount();
 
1417
      if ((infoRequested & deletedRowCount) &&
 
1418
          share->cachedStats.isInited(deletedRowCount))
 
1419
        stats.deleted = share->cachedStats.getDelRowCount();
 
1420
      if ((infoRequested & meanRowLen) &&
 
1421
          share->cachedStats.isInited(meanRowLen))
 
1422
        stats.mean_rec_length = share->cachedStats.getMeanLength();
 
1423
      if ((infoRequested & lastModTime) &&
 
1424
          share->cachedStats.isInited(lastModTime))
 
1425
        stats.update_time = share->cachedStats.getUpdateTime();
 
1426
      
 
1427
      rc = 0;
 
1428
    }
 
1429
  }
 
1430
 
 
1431
  DBUG_RETURN(rc);
 
1432
}
 
1433
 
 
1434
 
 
1435
ha_rows ha_ibmdb2i::records()
 
1436
{
 
1437
  DBUG_ENTER("ha_ibmdb2i::records");
 
1438
  int rc;
 
1439
  rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()),
 
1440
                                                             rowCount,
 
1441
                                                             stats);
 
1442
 
 
1443
  if (unlikely(rc))
 
1444
  {
 
1445
    if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && 
 
1446
        share && 
 
1447
        (share->cachedStats.isInited(rowCount)))
 
1448
      DBUG_RETURN(share->cachedStats.getRowCount());
 
1449
    else
 
1450
      DBUG_RETURN(HA_POS_ERROR);
 
1451
  }
 
1452
  else if (share)
 
1453
  {
 
1454
    share->cachedStats.cacheRowCount(stats.records);
 
1455
  }
 
1456
 
 
1457
 DBUG_RETURN(stats.records); 
 
1458
}
 
1459
 
 
1460
 
 
1461
int ha_ibmdb2i::extra(enum ha_extra_function operation)
 
1462
{
 
1463
  DBUG_ENTER("ha_ibmdb2i::extra");
 
1464
  
 
1465
  switch(operation)
 
1466
  {
 
1467
    // Can these first five flags be replaced by attending to HA_EXTRA_WRITE_CACHE?
 
1468
    case HA_EXTRA_NO_IGNORE_DUP_KEY: 
 
1469
    case HA_EXTRA_WRITE_CANNOT_REPLACE: 
 
1470
      {                                                
 
1471
        returnDupKeysImmediately = false;
 
1472
        onDupUpdate = false;                         
 
1473
      }                                              
 
1474
      break;
 
1475
    case HA_EXTRA_INSERT_WITH_UPDATE:                
 
1476
      {                                              
 
1477
        returnDupKeysImmediately = true;             
 
1478
        onDupUpdate = true;                          
 
1479
      }                                               
 
1480
      break;                            
 
1481
    case HA_EXTRA_IGNORE_DUP_KEY:  
 
1482
    case HA_EXTRA_WRITE_CAN_REPLACE: 
 
1483
      returnDupKeysImmediately = true;
 
1484
      break;
 
1485
    case HA_EXTRA_FLUSH_CACHE:
 
1486
      if (outstanding_start_bulk_insert)
 
1487
        finishBulkInsert();
 
1488
      break;
 
1489
  }
 
1490
 
 
1491
  
 
1492
  DBUG_RETURN(0);
 
1493
}
 
1494
 
 
1495
/** 
 
1496
  @brief  
 
1497
  The DB2 storage engine will ignore a MySQL generated value and will generate 
 
1498
  a new value in SLIC. We arbitrarily set first_value to 1, and set the
 
1499
  interval to infinity for better performance on multi-row inserts.
 
1500
*/
 
1501
void ha_ibmdb2i::get_auto_increment(ulonglong offset, ulonglong increment,
 
1502
                                  ulonglong nb_desired_values,
 
1503
                                  ulonglong *first_value,
 
1504
                                  ulonglong *nb_reserved_values)
 
1505
{
 
1506
  DBUG_ENTER("ha_ibmdb2i::get_auto_increment");
 
1507
  *first_value= 1;
 
1508
  *nb_reserved_values= ULONGLONG_MAX;
 
1509
 
1510
 
 
1511
 
 
1512
 
 
1513
void ha_ibmdb2i::update_create_info(HA_CREATE_INFO *create_info)
 
1514
{
 
1515
  DBUG_ENTER("ha_ibmdb2i::update_create_info");
 
1516
 
 
1517
  if ((!(create_info->used_fields & HA_CREATE_USED_AUTO)) &&
 
1518
      (table->found_next_number_field != NULL))
 
1519
  {
 
1520
    initBridge();
 
1521
    
 
1522
    create_info->auto_increment_value= 1; 
 
1523
 
 
1524
    ha_rows rowCount = records();
 
1525
    
 
1526
    if (rowCount == 0)
 
1527
    { 
 
1528
      create_info->auto_increment_value = db2Table->getStartId();
 
1529
      DBUG_VOID_RETURN;
 
1530
    }
 
1531
    else if (rowCount == HA_POS_ERROR)
 
1532
    { 
 
1533
      DBUG_VOID_RETURN;
 
1534
    }
 
1535
 
 
1536
    getNextIdVal(&create_info->auto_increment_value); 
 
1537
  }
 
1538
  DBUG_VOID_RETURN;
 
1539
}
 
1540
 
 
1541
 
 
1542
int ha_ibmdb2i::getNextIdVal(ulonglong *value)
 
1543
{
 
1544
  DBUG_ENTER("ha_ibmdb2i::getNextIdVal");
 
1545
  
 
1546
  char queryBuffer[MAX_DB2_COLNAME_LENGTH + MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
 
1547
  strcpy(queryBuffer, " SELECT CAST(MAX( ");
 
1548
  convertMySQLNameToDB2Name(table->found_next_number_field->field_name, 
 
1549
                            strend(queryBuffer), 
 
1550
                            MAX_DB2_COLNAME_LENGTH+1);
 
1551
  strcat(queryBuffer, ") AS BIGINT) FROM ");    
 
1552
  db2Table->getDB2QualifiedName(strend(queryBuffer));
 
1553
  DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
 
1554
  
 
1555
  SqlStatementStream sqlStream(queryBuffer);
 
1556
  DBUG_PRINT("ha_ibmdb2i::getNextIdVal", ("Sent to DB2: %s",queryBuffer));
 
1557
 
 
1558
  int rc = 0;
 
1559
  FILE_HANDLE fileHandle2;
 
1560
  uint32 db2RowDataLen2;
 
1561
  rc = bridge()->prepOpen(sqlStream.getPtrToData(),
 
1562
                          &fileHandle2,
 
1563
                          &db2RowDataLen2);
 
1564
  if (likely(rc == 0))
 
1565
  {
 
1566
    IOReadBuffer rowBuffer(1, db2RowDataLen2);
 
1567
    rc = bridge()->read(fileHandle2, 
 
1568
                        rowBuffer.ptr(),
 
1569
                        QMY_READ_ONLY,
 
1570
                        QMY_NONE,
 
1571
                        QMY_FIRST);
 
1572
    
 
1573
    if (likely(rc == 0))
 
1574
    {
 
1575
      /* This check is here for the case where the table is not empty,
 
1576
         but the auto_increment starting value has been changed since     
 
1577
         the last record was written.                                */
 
1578
 
 
1579
      longlong maxIdVal = *(longlong*)(rowBuffer.getRowN(0));
 
1580
      if ((maxIdVal + 1) > db2Table->getStartId())
 
1581
        *value = maxIdVal + 1; 
 
1582
      else
 
1583
        *value = db2Table->getStartId();
 
1584
    }
 
1585
    
 
1586
    bridge()->deallocateFile(fileHandle2);
 
1587
  }
 
1588
  DBUG_RETURN(rc);
 
1589
}
 
1590
 
 
1591
 
 
1592
/*
 
1593
  Updates index cardinalities.                                             
 
1594
*/
 
1595
int ha_ibmdb2i::analyze(THD* thd, HA_CHECK_OPT *check_opt)
 
1596
{
 
1597
  DBUG_ENTER("ha_ibmdb2i::analyze");
 
1598
  info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
1599
  DBUG_RETURN(0);
 
1600
}
 
1601
 
 
1602
int ha_ibmdb2i::optimize(THD* thd, HA_CHECK_OPT *check_opt)
 
1603
{
 
1604
  DBUG_ENTER("ha_ibmdb2i::optimize");
 
1605
 
 
1606
  initBridge(thd);
 
1607
  
 
1608
  if (unlikely(records() == 0))
 
1609
    DBUG_RETURN(0); // DB2 doesn't like to reorganize a table with no data.
 
1610
  
 
1611
  quiesceAllFileHandles();
 
1612
  
 
1613
  int32 rc = bridge()->optimizeTable(db2Table->dataFile()->getMasterDefnHandle());
 
1614
  info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
1615
  
 
1616
  DBUG_RETURN(rc);
 
1617
}
 
1618
 
 
1619
 
 
1620
/**
 
1621
  @brief
 
1622
  Determines if an ALTER TABLE is allowed to switch the storage engine
 
1623
  for this table. If the table has a foreign key or is referenced by a
 
1624
  foreign key, then it cannot be switched. 
 
1625
*/
 
1626
bool ha_ibmdb2i::can_switch_engines(void)
 
1627
/*=================================*/
 
1628
{
 
1629
  DBUG_ENTER("ha_ibmdb2i::can_switch_engines");
 
1630
 
 
1631
  int rc = 0;
 
1632
  FILE_HANDLE queryFile = 0;
 
1633
  uint32 resultRowLen;  
 
1634
  uint count = 0; 
 
1635
  bool can_switch = FALSE;   // 1 if changing storage engine is allowed
 
1636
  
 
1637
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
1638
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
1639
  
 
1640
  String query(256);
 
1641
  query.append(STRING_WITH_LEN(" SELECT COUNT(*) FROM SYSIBM.SQLFOREIGNKEYS WHERE ((PKTABLE_SCHEM = '"));
 
1642
  query.append(libName+1, strlen(libName)-2);            // Remove quotes from parent schema name
 
1643
  query.append(STRING_WITH_LEN("' AND PKTABLE_NAME = '"));                   
 
1644
  query.append(fileName+1,strlen(fileName)-2);           // Remove quotes from file name
 
1645
  query.append(STRING_WITH_LEN("') OR (FKTABLE_SCHEM = '"));                                              
 
1646
  query.append(libName+1,strlen(libName)-2);             // Remove quotes from child schema
 
1647
  query.append(STRING_WITH_LEN("' AND FKTABLE_NAME = '"));          
 
1648
  query.append(fileName+1,strlen(fileName)-2);           // Remove quotes from child name 
 
1649
  query.append(STRING_WITH_LEN("'))"));
 
1650
                                               
 
1651
  SqlStatementStream sqlStream(query);
 
1652
  
 
1653
  rc = bridge()->prepOpen(sqlStream.getPtrToData(),
 
1654
                        &queryFile,
 
1655
                        &resultRowLen);
 
1656
  if (rc == 0)
 
1657
  {
 
1658
    IOReadBuffer rowBuffer(1, resultRowLen);
 
1659
 
 
1660
    rc =   bridge()->read(queryFile, 
 
1661
                        rowBuffer.ptr(),
 
1662
                        QMY_READ_ONLY, 
 
1663
                        QMY_NONE,
 
1664
                        QMY_FIRST);
 
1665
    if (!rc)
 
1666
    {
 
1667
       count = *(uint*)(rowBuffer.getRowN(0));
 
1668
       if (count == 0)
 
1669
         can_switch = TRUE;
 
1670
    }
 
1671
 
 
1672
    bridge()->deallocateFile(queryFile);
 
1673
  }
 
1674
  DBUG_RETURN(can_switch);
 
1675
}
 
1676
 
 
1677
 
 
1678
 
 
1679
bool ha_ibmdb2i::check_if_incompatible_data(HA_CREATE_INFO *info,
 
1680
                                         uint table_changes)
 
1681
{
 
1682
  DBUG_ENTER("ha_ibmdb2i::check_if_incompatible_data");
 
1683
  uint i;
 
1684
  /* Check that auto_increment value and field definitions were
 
1685
     not changed. */
 
1686
  if ((info->used_fields & HA_CREATE_USED_AUTO &&
 
1687
       info->auto_increment_value != 0) ||
 
1688
       table_changes != IS_EQUAL_YES)
 
1689
    DBUG_RETURN(COMPATIBLE_DATA_NO);
 
1690
  /* Check if any fields were renamed. */
 
1691
  for (i= 0; i < table->s->fields; i++)
 
1692
  {
 
1693
   Field *field= table->field[i];
 
1694
   if (field->flags & FIELD_IS_RENAMED)
 
1695
    {
 
1696
      DBUG_PRINT("info", ("Field has been renamed, copy table"));
 
1697
      DBUG_RETURN(COMPATIBLE_DATA_NO);
 
1698
    }
 
1699
  }
 
1700
  DBUG_RETURN(COMPATIBLE_DATA_YES);
 
1701
}
 
1702
 
 
1703
int ha_ibmdb2i::reset_auto_increment(ulonglong value)
 
1704
 {
 
1705
  DBUG_ENTER("ha_ibmdb2i::reset_auto_increment");
 
1706
  
 
1707
  int rc = 0;
 
1708
 
 
1709
  quiesceAllFileHandles();
 
1710
 
 
1711
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
1712
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
1713
 
 
1714
  String query(512);
 
1715
  query.append(STRING_WITH_LEN(" ALTER TABLE "));
 
1716
  query.append(libName);
 
1717
  query.append('.');
 
1718
  query.append(fileName);
 
1719
  query.append(STRING_WITH_LEN(" ALTER COLUMN "));
 
1720
  char colName[MAX_DB2_COLNAME_LENGTH+1];
 
1721
  convertMySQLNameToDB2Name(table->found_next_number_field->field_name, 
 
1722
                            colName, 
 
1723
                            sizeof(colName));
 
1724
  query.append(colName);
 
1725
  
 
1726
  char restart_value[22];  
 
1727
  CHARSET_INFO *cs= &my_charset_bin;
 
1728
  uint len = (uint)(cs->cset->longlong10_to_str)(cs,restart_value,sizeof(restart_value), 10, value);  
 
1729
  restart_value[len] = 0;
 
1730
  
 
1731
  query.append(STRING_WITH_LEN(" RESTART WITH "));
 
1732
  query.append(restart_value);
 
1733
  
 
1734
  SqlStatementStream sqlStream(query);
 
1735
  DBUG_PRINT("ha_ibmdb2i::reset_auto_increment", ("Sent to DB2: %s",query.c_ptr()));
 
1736
 
 
1737
  rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(),
 
1738
                                                     sqlStream.getStatementCount(),
 
1739
                                                     QMY_NONE, //getCommitLevel(),
 
1740
                                                     FALSE,
 
1741
                                                     FALSE,
 
1742
                                                     TRUE, //FALSE,
 
1743
                                                     dataHandle);
 
1744
  if (rc == 0)
 
1745
    db2Table->updateStartId(value); 
 
1746
 
 
1747
  DBUG_RETURN(rc);
 
1748
}
 
1749
 
 
1750
 
 
1751
/**
 
1752
  @brief
 
1753
  This function receives an error code that was previously set by the handler.
 
1754
  It returns to MySQL the error string associated with that error.   
 
1755
*/
 
1756
bool ha_ibmdb2i::get_error_message(int error, String *buf)
 
1757
{
 
1758
  DBUG_ENTER("ha_ibmdb2i::get_error_message");
 
1759
  if ((error >= DB2I_FIRST_ERR && error <= DB2I_LAST_ERR) ||
 
1760
      (error >= QMY_ERR_MIN && error <= QMY_ERR_MAX))
 
1761
  {
 
1762
    db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(ha_thd());
 
1763
    char* errMsg = bridge->getErrorStorage();
 
1764
    buf->copy(errMsg, strlen(errMsg),system_charset_info);
 
1765
    bridge->freeErrorStorage();
 
1766
  }
 
1767
  DBUG_RETURN(FALSE);                          
 
1768
}
 
1769
 
 
1770
 
 
1771
int ha_ibmdb2i::delete_all_rows()
 
1772
{
 
1773
  DBUG_ENTER("ha_ibmdb2i::delete_all_rows");
 
1774
  int rc = 0;
 
1775
  char queryBuffer[MAX_DB2_QUALIFIEDNAME_LENGTH + 64];
 
1776
  strcpy(queryBuffer, " DELETE FROM ");
 
1777
  db2Table->getDB2QualifiedName(strend(queryBuffer));
 
1778
  DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer));
 
1779
  
 
1780
  SqlStatementStream sqlStream(queryBuffer);
 
1781
  DBUG_PRINT("ha_ibmdb2i::delete_all_rows", ("Sent to DB2: %s",queryBuffer));
 
1782
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
1783
                         sqlStream.getStatementCount(),
 
1784
                         getCommitLevel(),
 
1785
                         false,
 
1786
                         false,
 
1787
                         true,
 
1788
                         dataHandle);
 
1789
  
 
1790
 /* If this method was called on behalf of a TRUNCATE TABLE statement, and if */
 
1791
 /* the table has an auto_increment field, then reset the starting value for  */
 
1792
 /* the auto_increment field to 1.
 
1793
                                            */
 
1794
  if (rc == 0 && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE &&
 
1795
      table->found_next_number_field )
 
1796
    rc = reset_auto_increment(1);
 
1797
 
 
1798
  invalidateCachedStats();
 
1799
  
 
1800
  DBUG_RETURN(rc);
 
1801
}
 
1802
 
 
1803
 
 
1804
int ha_ibmdb2i::external_lock(THD *thd, int lock_type)
 
1805
{
 
1806
  int rc = 0;
 
1807
 
 
1808
  DBUG_ENTER("ha_ibmdb2i::external_lock");
 
1809
  DBUG_PRINT("ha_ibmdb2i::external_lock",("Lock type: %d", lock_type));
 
1810
  
 
1811
  if (lock_type == F_RDLCK)
 
1812
    accessIntent = QMY_READ_ONLY;
 
1813
  else if (lock_type == F_WRLCK)
 
1814
    accessIntent = QMY_UPDATABLE;
 
1815
  
 
1816
  initBridge(thd);
 
1817
  int command = thd_sql_command(thd);
 
1818
  
 
1819
  if (!THDVAR(thd,transaction_unsafe))
 
1820
  {
 
1821
    if (lock_type != F_UNLCK)
 
1822
    {
 
1823
      if (autoCommitIsOn(thd) == QMY_YES)
 
1824
      {
 
1825
        trans_register_ha(thd, FALSE, ibmdb2i_hton);
 
1826
      }
 
1827
      else 
 
1828
      { 
 
1829
        trans_register_ha(thd, TRUE, ibmdb2i_hton);
 
1830
        if (likely(command != SQLCOM_CREATE_TABLE))
 
1831
        {
 
1832
          trans_register_ha(thd, FALSE, ibmdb2i_hton);
 
1833
          bridge()->beginStmtTx();
 
1834
        }
 
1835
      }
 
1836
    }    
 
1837
  }
 
1838
 
 
1839
  if (command == SQLCOM_LOCK_TABLES ||
 
1840
      command == SQLCOM_ALTER_TABLE ||
 
1841
      command == SQLCOM_UNLOCK_TABLES ||
 
1842
      (accessIntent == QMY_UPDATABLE &&
 
1843
       (command == SQLCOM_UPDATE ||
 
1844
        command == SQLCOM_UPDATE_MULTI ||
 
1845
        command == SQLCOM_DELETE ||
 
1846
        command == SQLCOM_DELETE_MULTI ||
 
1847
        command == SQLCOM_REPLACE ||
 
1848
        command == SQLCOM_REPLACE_SELECT) &&
 
1849
       getCommitLevel(thd) == QMY_NONE))
 
1850
  {
 
1851
    char action;
 
1852
    char type;
 
1853
    if (lock_type == F_UNLCK)
 
1854
    { 
 
1855
      action = QMY_UNLOCK;
 
1856
      type = accessIntent == QMY_READ_ONLY ? QMY_LSRD : QMY_LENR;
 
1857
    }
 
1858
    else
 
1859
    {
 
1860
      action = QMY_LOCK;
 
1861
      type = lock_type == F_RDLCK ? QMY_LSRD : QMY_LENR;
 
1862
    }
 
1863
 
 
1864
    DBUG_PRINT("ha_ibmdb2i::external_lock",("%socking table", action==QMY_LOCK ? "L" : "Unl"));
 
1865
 
 
1866
    if (!dataHandle)
 
1867
      rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);  
 
1868
 
 
1869
    rc = bridge()->lockObj(dataHandle, 
 
1870
                           0,
 
1871
                           action,               
 
1872
                           type,
 
1873
                           (command == SQLCOM_LOCK_TABLES ? QMY_NO : QMY_YES)); 
 
1874
    
 
1875
  } 
 
1876
  
 
1877
  // Cache this away so we don't have to access it on each row operation
 
1878
  cachedZeroDateOption = (enum_ZeroDate)THDVAR(thd, compat_opt_allow_zero_date_vals);
 
1879
  
 
1880
  DBUG_RETURN(rc);
 
1881
}
 
1882
 
 
1883
 
 
1884
THR_LOCK_DATA **ha_ibmdb2i::store_lock(THD *thd,
 
1885
                                       THR_LOCK_DATA **to,
 
1886
                                       enum thr_lock_type lock_type)
 
1887
{
 
1888
  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
 
1889
  {
 
1890
    if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
 
1891
         lock_type <= TL_WRITE) && !(thd->in_lock_tables && thd_sql_command(thd) == SQLCOM_LOCK_TABLES))
 
1892
      lock_type= TL_WRITE_ALLOW_WRITE;
 
1893
    lock.type=lock_type;
 
1894
  }
 
1895
  *to++= &lock;
 
1896
  return to;
 
1897
}
 
1898
 
 
1899
 
 
1900
int ha_ibmdb2i::delete_table(const char *name)
 
1901
{
 
1902
  DBUG_ENTER("ha_ibmdb2i::delete_table");
 
1903
  THD* thd = ha_thd();
 
1904
  db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(thd);  
 
1905
  
 
1906
  char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
 
1907
  db2i_table::getDB2QualifiedNameFromPath(name, db2Name);
 
1908
 
 
1909
  String query(128);
 
1910
  query.append(STRING_WITH_LEN(" DROP TABLE "));
 
1911
  query.append(db2Name);
 
1912
 
 
1913
  if (thd_sql_command(thd) == SQLCOM_DROP_TABLE &&
 
1914
      thd->lex->drop_mode == DROP_RESTRICT)
 
1915
    query.append(STRING_WITH_LEN(" RESTRICT "));  
 
1916
  DBUG_PRINT("ha_ibmdb2i::delete_table", ("Sent to DB2: %s",query.c_ptr()));
 
1917
 
 
1918
  SqlStatementStream sqlStream(query);
 
1919
 
 
1920
  db2i_table::getDB2LibNameFromPath(name, db2Name);  
 
1921
  bool isTemporary = (strcmp(db2Name, DB2I_TEMP_TABLE_SCHEMA) == 0 ? TRUE : FALSE);
 
1922
 
 
1923
  int rc = bridge->execSQL(sqlStream.getPtrToData(),
 
1924
                       sqlStream.getStatementCount(),
 
1925
                       (isTemporary ? QMY_NONE : getCommitLevel(thd)),
 
1926
                       FALSE,
 
1927
                       FALSE,
 
1928
                       isTemporary);
 
1929
 
 
1930
  if (rc == HA_ERR_NO_SUCH_TABLE)
 
1931
  {
 
1932
     warning(thd, DB2I_ERR_TABLE_NOT_FOUND, name);
 
1933
     rc = 0;
 
1934
  }
 
1935
  
 
1936
  if (rc == 0)
 
1937
  {
 
1938
    db2i_table::deleteAssocFiles(name);
 
1939
  }
 
1940
  
 
1941
  FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
 
1942
  while (savedHandle)
 
1943
  {
 
1944
    bridge->deallocateFile(savedHandle, TRUE);
 
1945
    DBUG_ASSERT(share);
 
1946
    if (free_share(share))
 
1947
      share = NULL;   
 
1948
    savedHandle = bridge->findAndRemovePreservedHandle(name, &share);
 
1949
  }
 
1950
    
 
1951
  my_errno = rc;
 
1952
  DBUG_RETURN(rc);
 
1953
}
 
1954
 
 
1955
 
 
1956
int ha_ibmdb2i::rename_table(const char * from, const char * to)
 
1957
{
 
1958
  DBUG_ENTER("ha_ibmdb2i::rename_table ");
 
1959
    
 
1960
  char db2FromFileName[MAX_DB2_FILENAME_LENGTH + 1];
 
1961
  char db2ToFileName[MAX_DB2_FILENAME_LENGTH+1];
 
1962
  char db2FromLibName[MAX_DB2_SCHEMANAME_LENGTH+1];
 
1963
  char db2ToLibName[MAX_DB2_SCHEMANAME_LENGTH+1];
 
1964
 
 
1965
  db2i_table::getDB2LibNameFromPath(from, db2FromLibName);
 
1966
  db2i_table::getDB2LibNameFromPath(to, db2ToLibName);
 
1967
 
 
1968
  if (strcmp(db2FromLibName, db2ToLibName) != 0 )
 
1969
  {
 
1970
    getErrTxt(DB2I_ERR_RENAME_MOVE,from,to);
 
1971
    DBUG_RETURN(DB2I_ERR_RENAME_MOVE);
 
1972
  }
 
1973
 
 
1974
  db2i_table::getDB2FileNameFromPath(from, db2FromFileName, db2i_table::ASCII_NATIVE);
 
1975
  db2i_table::getDB2FileNameFromPath(to, db2ToFileName);
 
1976
 
 
1977
  char escapedFromFileName[2 * MAX_DB2_FILENAME_LENGTH + 1];
 
1978
    
 
1979
  uint o = 0;
 
1980
  uint i = 1;
 
1981
  do
 
1982
  {
 
1983
    escapedFromFileName[o++] = db2FromFileName[i];
 
1984
    if (db2FromFileName[i] == '+')
 
1985
      escapedFromFileName[o++] = '+';
 
1986
  } while (db2FromFileName[++i]);
 
1987
  escapedFromFileName[o-1] = 0;
 
1988
 
 
1989
  
 
1990
  int rc = 0;
 
1991
  
 
1992
  char queryBuffer[sizeof(db2FromLibName) + 2 * sizeof(db2FromFileName) + 256];
 
1993
  SafeString selectQuery(queryBuffer, sizeof(queryBuffer));
 
1994
  selectQuery.strncat(STRING_WITH_LEN("SELECT CAST(INDEX_NAME AS VARCHAR(128) CCSID 1208) FROM QSYS2.SYSINDEXES WHERE INDEX_NAME LIKE '%+_+_+_%"));
 
1995
  selectQuery.strcat(escapedFromFileName);
 
1996
  selectQuery.strncat(STRING_WITH_LEN("' ESCAPE '+' AND TABLE_NAME='"));
 
1997
  selectQuery.strncat(db2FromFileName+1, strlen(db2FromFileName)-2);
 
1998
  selectQuery.strncat(STRING_WITH_LEN("' AND TABLE_SCHEMA='"));
 
1999
  selectQuery.strncat(db2FromLibName+1, strlen(db2FromLibName)-2);
 
2000
  selectQuery.strcat('\'');
 
2001
  DBUG_ASSERT(!selectQuery.overflowed());
 
2002
  
 
2003
  SqlStatementStream indexQuery(selectQuery.ptr());
 
2004
 
 
2005
  FILE_HANDLE queryFile = 0;
 
2006
  uint32 resultRowLen;
 
2007
    
 
2008
  initBridge();
 
2009
  rc = bridge()->prepOpen(indexQuery.getPtrToData(),
 
2010
                        &queryFile,
 
2011
                        &resultRowLen);
 
2012
 
 
2013
  if (unlikely(rc))
 
2014
    DBUG_RETURN(rc);
 
2015
    
 
2016
  IOReadBuffer rowBuffer(1, resultRowLen);  
 
2017
     
 
2018
  int tableNameLen = strlen(db2FromFileName) - 2;
 
2019
  
 
2020
  SqlStatementStream renameQuery(64);
 
2021
  String query;
 
2022
  while (rc == 0)
 
2023
  {
 
2024
    query.length(0);
 
2025
 
 
2026
    rc = bridge()->read(queryFile,
 
2027
                      rowBuffer.ptr(),
 
2028
                      QMY_READ_ONLY,
 
2029
                      QMY_NONE,
 
2030
                      QMY_NEXT);
 
2031
 
 
2032
    if (!rc)
 
2033
    {
 
2034
      const char* rowData = rowBuffer.getRowN(0);
 
2035
      char indexFileName[MAX_DB2_FILENAME_LENGTH];
 
2036
      memset(indexFileName, 0, sizeof(indexFileName));
 
2037
      
 
2038
      uint16 fileNameLen = *(uint16*)(rowData);
 
2039
      strncpy(indexFileName, rowData + sizeof(uint16), fileNameLen);
 
2040
            
 
2041
      int bytesToRetain = fileNameLen - tableNameLen;
 
2042
      if (bytesToRetain <= 0)
 
2043
      /* We can't handle index names in which the MySQL index name and
 
2044
         the table name together are longer than the max index name.      */
 
2045
      {
 
2046
        getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
2047
        DBUG_RETURN(DB2I_ERR_INVALID_NAME);     
 
2048
      }
 
2049
      char indexName[MAX_DB2_FILENAME_LENGTH];
 
2050
      memset(indexName, 0, sizeof(indexName));
 
2051
 
 
2052
      strncpy(indexName, 
 
2053
              indexFileName, 
 
2054
              bytesToRetain);
 
2055
      
 
2056
      char db2IndexName[MAX_DB2_FILENAME_LENGTH+1];
 
2057
      
 
2058
      convertMySQLNameToDB2Name(indexFileName, db2IndexName, sizeof(db2IndexName));
 
2059
 
 
2060
      query.append(STRING_WITH_LEN("RENAME INDEX "));
 
2061
      query.append(db2FromLibName);
 
2062
      query.append('.');
 
2063
      query.append(db2IndexName);
 
2064
      query.append(STRING_WITH_LEN(" TO "));
 
2065
      if (db2i_table::appendQualifiedIndexFileName(indexName, db2ToFileName, query, db2i_table::ASCII_SQL, typeNone) == -1)
 
2066
      {
 
2067
        getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
2068
        DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
2069
      }
 
2070
      renameQuery.addStatement(query);      
 
2071
      DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2072
    }    
 
2073
  }
 
2074
 
 
2075
    
 
2076
  if (queryFile)
 
2077
    bridge()->deallocateFile(queryFile);
 
2078
  
 
2079
  if (rc != HA_ERR_END_OF_FILE)
 
2080
    DBUG_RETURN(rc);
 
2081
  
 
2082
  char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH];
 
2083
          
 
2084
  /* Rename the table */
 
2085
  query.length(0);
 
2086
  query.append(STRING_WITH_LEN(" RENAME TABLE "));
 
2087
  db2i_table::getDB2QualifiedNameFromPath(from, db2Name);
 
2088
  query.append(db2Name);  
 
2089
  query.append(STRING_WITH_LEN(" TO "));
 
2090
  query.append(db2ToFileName);
 
2091
  DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2092
  renameQuery.addStatement(query);
 
2093
  rc = bridge()->execSQL(renameQuery.getPtrToData(),
 
2094
                       renameQuery.getStatementCount(),
 
2095
                       getCommitLevel());
 
2096
  
 
2097
  if (!rc)
 
2098
    db2i_table::renameAssocFiles(from, to);
 
2099
  
 
2100
  DBUG_RETURN(rc);
 
2101
}
 
2102
 
 
2103
 
 
2104
int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
 
2105
                       HA_CREATE_INFO *create_info)
 
2106
{
 
2107
  DBUG_ENTER("ha_ibmdb2i::create");
 
2108
 
 
2109
  int rc;
 
2110
  char fileSortSequence[11] = "*HEX";
 
2111
  char fileSortSequenceLibrary[11] = "";
 
2112
  char fileSortSequenceType = ' ';
 
2113
  char libName[MAX_DB2_SCHEMANAME_LENGTH+1];
 
2114
  char fileName[MAX_DB2_FILENAME_LENGTH+1];
 
2115
  char colName[MAX_DB2_COLNAME_LENGTH+1];
 
2116
  bool isTemporary;
 
2117
  ulong auto_inc_value;
 
2118
 
 
2119
  db2i_table::getDB2LibNameFromPath(name, libName);
 
2120
  db2i_table::getDB2FileNameFromPath(name, fileName);
 
2121
 
 
2122
  if (osVersion.v < 6)
 
2123
  {
 
2124
    if (strlen(libName) > 
 
2125
         MAX_DB2_V5R4_LIBNAME_LENGTH + (isUpperOrQuote(system_charset_info, libName) ? 2 : 0))
 
2126
    {
 
2127
      getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V5R4_LIBNAME_LENGTH);
 
2128
      DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
 
2129
    }
 
2130
  }
 
2131
  else if (strlen(libName) > MAX_DB2_V6R1_LIBNAME_LENGTH)
 
2132
  {
 
2133
    getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V6R1_LIBNAME_LENGTH);
 
2134
    DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA);
 
2135
  }
 
2136
  
 
2137
  String query(256);
 
2138
  
 
2139
  if (strcmp(libName, DB2I_TEMP_TABLE_SCHEMA))
 
2140
  {
 
2141
    query.append(STRING_WITH_LEN("CREATE TABLE "));
 
2142
    query.append(libName);
 
2143
    query.append('.');
 
2144
    query.append(fileName);
 
2145
    isTemporary = FALSE;
 
2146
  }
 
2147
  else
 
2148
  {
 
2149
    query.append(STRING_WITH_LEN("DECLARE GLOBAL TEMPORARY TABLE "));
 
2150
    query.append(fileName);
 
2151
    isTemporary = TRUE;
 
2152
  }
 
2153
  query.append(STRING_WITH_LEN(" ("));
 
2154
  
 
2155
  THD* thd = ha_thd();
 
2156
  enum_TimeFormat timeFormat = (enum_TimeFormat)(THDVAR(thd, compat_opt_time_as_duration));
 
2157
  enum_YearFormat yearFormat = (enum_YearFormat)(THDVAR(thd, compat_opt_year_as_int));
 
2158
  enum_BlobMapping blobMapping = (enum_BlobMapping)(THDVAR(thd, compat_opt_blob_cols));
 
2159
  enum_ZeroDate zeroDate = (enum_ZeroDate)(THDVAR(thd, compat_opt_allow_zero_date_vals));
 
2160
  bool propagateDefaults = THDVAR(thd, propagate_default_col_vals);
 
2161
  
 
2162
  Field **field;
 
2163
  for (field= table_arg->field; *field; field++)
 
2164
  {  
 
2165
    if ( field != table_arg->field ) // Not the first one
 
2166
      query.append(STRING_WITH_LEN(" , "));
 
2167
 
 
2168
    if (!convertMySQLNameToDB2Name((*field)->field_name, colName, sizeof(colName)))
 
2169
    {
 
2170
      getErrTxt(DB2I_ERR_INVALID_NAME,"field",(*field)->field_name);
 
2171
      DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
2172
    }
 
2173
 
 
2174
    query.append(colName);    
 
2175
    query.append(' ');
 
2176
 
 
2177
    if (rc = getFieldTypeMapping(*field, 
 
2178
                                 query, 
 
2179
                                 timeFormat, 
 
2180
                                 blobMapping,
 
2181
                                 zeroDate,
 
2182
                                 propagateDefaults,
 
2183
                                 yearFormat))
 
2184
      DBUG_RETURN(rc);
 
2185
 
 
2186
    if ( (*field)->flags & NOT_NULL_FLAG )
 
2187
    {
 
2188
      query.append(STRING_WITH_LEN(" NOT NULL "));
 
2189
    }
 
2190
    if ( (*field)->flags & AUTO_INCREMENT_FLAG )     
 
2191
    {
 
2192
#ifdef WITH_PARTITION_STORAGE_ENGINE      
 
2193
      if (table_arg->part_info)
 
2194
      {
 
2195
        getErrTxt(DB2I_ERR_PART_AUTOINC);
 
2196
        DBUG_RETURN(DB2I_ERR_PART_AUTOINC);
 
2197
      }
 
2198
#endif
 
2199
      query.append(STRING_WITH_LEN(" GENERATED BY DEFAULT AS IDENTITY ") );
 
2200
      if (create_info->auto_increment_value != 0) 
 
2201
      {
 
2202
        /* Query was ALTER TABLE...AUTO_INCREMENT = x; or
 
2203
        CREATE TABLE ...AUTO_INCREMENT = x;  Set the starting
 
2204
                    value for the auto_increment column.  */          
 
2205
        char stringValue[22];  
 
2206
        CHARSET_INFO *cs= &my_charset_bin;
 
2207
        uint len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, create_info->auto_increment_value);  
 
2208
        stringValue[len] = 0;
 
2209
        query.append(STRING_WITH_LEN(" (START WITH "));
 
2210
        query.append(stringValue);
 
2211
 
 
2212
        uint64 maxValue=maxValueForField(*field);
 
2213
        
 
2214
        if (maxValue)
 
2215
        {
 
2216
          len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, maxValue);  
 
2217
          stringValue[len] = 0;
 
2218
          query.append(STRING_WITH_LEN(" MAXVALUE "));
 
2219
          query.append(stringValue);
 
2220
        }
 
2221
        
 
2222
        query.append(STRING_WITH_LEN(") "));
 
2223
      }
 
2224
 
 
2225
    } 
 
2226
  }
 
2227
  
 
2228
  bool primaryHasStringField = false;
 
2229
 
 
2230
  if (table_arg->s->primary_key != MAX_KEY && !isTemporary)
 
2231
  {
 
2232
    KEY& curKey = table_arg->key_info[table_arg->s->primary_key];
 
2233
    query.append(STRING_WITH_LEN(", PRIMARY KEY( "));
 
2234
    for (int j = 0; j < curKey.key_parts; ++j)
 
2235
    {
 
2236
      if (j != 0)
 
2237
      {
 
2238
        query.append( STRING_WITH_LEN(" , ") );
 
2239
      }
 
2240
      Field* field = curKey.key_part[j].field;
 
2241
      convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
 
2242
      query.append(colName);
 
2243
      enum_field_types type = field->real_type();
 
2244
      if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_BLOB ||
 
2245
          type == MYSQL_TYPE_STRING)
 
2246
      {
 
2247
        rc = updateAssociatedSortSequence(field->charset(),
 
2248
                                          &fileSortSequenceType,
 
2249
                                          fileSortSequence,
 
2250
                                          fileSortSequenceLibrary);
 
2251
        if (rc) DBUG_RETURN (rc);
 
2252
        primaryHasStringField = true;
 
2253
      }
 
2254
    }
 
2255
    query.append(STRING_WITH_LEN(" ) "));
 
2256
  }
 
2257
 
 
2258
  rc = buildDB2ConstraintString(thd->lex, 
 
2259
                                query, 
 
2260
                                name,
 
2261
                                table_arg->field,
 
2262
                                &fileSortSequenceType,
 
2263
                                fileSortSequence,
 
2264
                                fileSortSequenceLibrary);  
 
2265
  if (rc) DBUG_RETURN (rc);
 
2266
  
 
2267
  query.append(STRING_WITH_LEN(" ) "));
 
2268
  
 
2269
  if (isTemporary)
 
2270
    query.append(STRING_WITH_LEN(" ON COMMIT PRESERVE ROWS "));
 
2271
    
 
2272
  DBUG_PRINT("ha_ibmdb2i::create", ("Sent to DB2: %s",query.c_ptr()));
 
2273
  SqlStatementStream sqlStream(query.length());
 
2274
  sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
 
2275
  
 
2276
  for (uint i = 0; i < table_arg->s->keys; ++i)
 
2277
  {
 
2278
    if (i != table_arg->s->primary_key || isTemporary)
 
2279
    {
 
2280
      rc = buildCreateIndexStatement(sqlStream, 
 
2281
                                table_arg->key_info[i], 
 
2282
                                false,
 
2283
                                libName,
 
2284
                                fileName);
 
2285
      if (rc) DBUG_RETURN (rc);
 
2286
    }
 
2287
  }
 
2288
  
 
2289
  bool noCommit = isTemporary || ((!autoCommitIsOn(thd)) && (thd_sql_command(thd) == SQLCOM_ALTER_TABLE));
 
2290
  
 
2291
  initBridge();
 
2292
  
 
2293
//   if (THDVAR(thd, discovery_mode) == 1)
 
2294
//     bridge()->expectErrors(QMY_ERR_TABLE_EXISTS);
 
2295
  
 
2296
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
2297
                         sqlStream.getStatementCount(),
 
2298
                         (isTemporary ? QMY_NONE : getCommitLevel(thd)),
 
2299
                         TRUE,
 
2300
                         FALSE,
 
2301
                         noCommit );
 
2302
  
 
2303
  if (unlikely(rc == QMY_ERR_MSGID) &&
 
2304
      memcmp(bridge()->getErrorMsgID(), DB2I_SQL0350, 7) == 0)
 
2305
  {
 
2306
    my_error(ER_BLOB_USED_AS_KEY, MYF(0), "*unknown*");
 
2307
    rc = ER_BLOB_USED_AS_KEY;
 
2308
  }
 
2309
/*   else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) &&
 
2310
            THDVAR(thd, discovery_mode) == 1)
 
2311
  {
 
2312
    db2i_table* temp = new db2i_table(table_arg->s, name);
 
2313
    int32 rc = temp->fastInitForCreate(name);
 
2314
    delete temp;
 
2315
    
 
2316
    if (!rc)
 
2317
      warning(thd, DB2I_ERR_WARN_CREATE_DISCOVER);
 
2318
    
 
2319
    DBUG_RETURN(rc);
 
2320
  }   
 
2321
*/
 
2322
  
 
2323
  if (!rc && !isTemporary)
 
2324
  {
 
2325
    db2i_table* temp = new db2i_table(table_arg->s, name);
 
2326
    int32 rc = temp->fastInitForCreate(name);
 
2327
    delete temp;
 
2328
    if (rc) 
 
2329
      delete_table(name);
 
2330
  }
 
2331
  
 
2332
  DBUG_RETURN(rc);
 
2333
}
 
2334
 
 
2335
 
 
2336
/**
 
2337
  @brief
 
2338
  Add an index on-line to a table. This method is called on behalf of
 
2339
  a CREATE INDEX or ALTER TABLE statement. 
 
2340
  It is implemented via a composed DDL statement passed to DB2.
 
2341
*/
 
2342
int ha_ibmdb2i::add_index(TABLE *table_arg, 
 
2343
                          KEY *key_info,
 
2344
                          uint num_of_keys)
 
2345
{
 
2346
  DBUG_ENTER("ha_ibmdb2i::add_index");
 
2347
 
 
2348
  int rc;
 
2349
  SqlStatementStream sqlStream(256);
 
2350
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
2351
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
2352
  
 
2353
  quiesceAllFileHandles();
 
2354
  
 
2355
  uint primaryKey = MAX_KEY;
 
2356
  if (table_arg->s->primary_key >= MAX_KEY && !db2Table->isTemporary())
 
2357
  {  
 
2358
    for (int i = 0; i < num_of_keys; ++i)
 
2359
    {
 
2360
      if (strcmp(key_info[i].name, "PRIMARY") == 0)
 
2361
      {
 
2362
        primaryKey = i;
 
2363
        break;
 
2364
      }
 
2365
      else if (primaryKey == MAX_KEY &&
 
2366
               key_info[i].flags & HA_NOSAME)
 
2367
      {
 
2368
        primaryKey = i;
 
2369
        for (int j=0 ; j < key_info[i].key_parts ;j++)
 
2370
        {
 
2371
          uint fieldnr= key_info[i].key_part[j].fieldnr;
 
2372
          if (table_arg->s->field[fieldnr]->null_ptr ||
 
2373
              table_arg->s->field[fieldnr]->key_length() !=
 
2374
              key_info[i].key_part[j].length)
 
2375
          {
 
2376
            primaryKey = MAX_KEY;
 
2377
            break;
 
2378
          }
 
2379
        }
 
2380
      }
 
2381
    }
 
2382
  }
 
2383
        
 
2384
        
 
2385
  for (int i = 0; i < num_of_keys; ++i)
 
2386
  {
 
2387
    KEY& curKey= key_info[i];
 
2388
    rc = buildCreateIndexStatement(sqlStream, 
 
2389
                              curKey, 
 
2390
                              (i == primaryKey),
 
2391
                              libName,
 
2392
                              fileName);
 
2393
    if (rc) DBUG_RETURN (rc);
 
2394
  }
 
2395
  
 
2396
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
2397
                         sqlStream.getStatementCount(),
 
2398
                         getCommitLevel(),
 
2399
                         FALSE,
 
2400
                         FALSE,
 
2401
                         FALSE,
 
2402
                         dataHandle);
 
2403
 
 
2404
  /* Handle the case where a unique index is being created but an error occurs
 
2405
     because the file contains duplicate key values.                           */ 
 
2406
  if (rc == ER_DUP_ENTRY)
 
2407
    print_keydup_error(MAX_KEY,ER(ER_DUP_ENTRY_WITH_KEY_NAME));
 
2408
 
 
2409
  DBUG_RETURN(rc);
 
2410
}
 
2411
 
 
2412
/**
 
2413
  @brief
 
2414
  Drop an index on-line from a table. This method is called on behalf of
 
2415
  a DROP INDEX or ALTER TABLE statement. 
 
2416
  It is implemented via a composed DDL statement passed to DB2.
 
2417
*/
 
2418
int ha_ibmdb2i::prepare_drop_index(TABLE *table_arg, 
 
2419
                                   uint *key_num, uint num_of_keys)
 
2420
{
 
2421
  DBUG_ENTER("ha_ibmdb2i::prepare_drop_index");
 
2422
  int rc;
 
2423
  int i = 0;
 
2424
  String query(64);
 
2425
  SqlStatementStream sqlStream(64 * num_of_keys);
 
2426
  SqlStatementStream shadowStream(64 * num_of_keys);
 
2427
 
 
2428
  quiesceAllFileHandles();
 
2429
  
 
2430
  const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
 
2431
  const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
 
2432
 
 
2433
  while (i < num_of_keys)
 
2434
  {
 
2435
    query.length(0);
 
2436
    DBUG_PRINT("info", ("ha_ibmdb2i::prepare_drop_index %u", key_num[i]));
 
2437
    KEY& curKey= table_arg->key_info[key_num[i]];
 
2438
    if (key_num[i] == table->s->primary_key && !db2Table->isTemporary())
 
2439
    {
 
2440
      query.append(STRING_WITH_LEN("ALTER TABLE "));
 
2441
      query.append(libName);
 
2442
      query.append(STRING_WITH_LEN("."));
 
2443
      query.append(fileName);
 
2444
      query.append(STRING_WITH_LEN(" DROP PRIMARY KEY"));
 
2445
    }
 
2446
    else
 
2447
    {
 
2448
      query.append(STRING_WITH_LEN("DROP INDEX "));
 
2449
      query.append(libName);
 
2450
      query.append(STRING_WITH_LEN("."));
 
2451
      db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query);
 
2452
    }
 
2453
    DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2454
    sqlStream.addStatement(query);
 
2455
    
 
2456
    query.length(0);
 
2457
    query.append(STRING_WITH_LEN("DROP INDEX "));
 
2458
    query.append(libName);
 
2459
    query.append(STRING_WITH_LEN("."));
 
2460
    db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query, db2i_table::ASCII_SQL, typeHex);
 
2461
    
 
2462
    DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe()));
 
2463
    shadowStream.addStatement(query);
 
2464
    
 
2465
    ++i;
 
2466
   }
 
2467
  
 
2468
  rc = bridge()->execSQL(sqlStream.getPtrToData(),
 
2469
                         sqlStream.getStatementCount(),
 
2470
                         getCommitLevel(),
 
2471
                         FALSE,
 
2472
                         FALSE,
 
2473
                         FALSE,
 
2474
                         dataHandle);
 
2475
  
 
2476
  if (rc == 0)
 
2477
    bridge()->execSQL(shadowStream.getPtrToData(),
 
2478
                         shadowStream.getStatementCount(),
 
2479
                         getCommitLevel());
 
2480
  
 
2481
  DBUG_RETURN(rc);
 
2482
}
 
2483
 
 
2484
 
 
2485
void
 
2486
ha_ibmdb2i::unlock_row()
 
2487
{
 
2488
  DBUG_ENTER("ha_ibmdb2i::unlock_row");
 
2489
  DBUG_VOID_RETURN;
 
2490
}    
 
2491
 
 
2492
int
 
2493
ha_ibmdb2i::index_end()
 
2494
{
 
2495
  DBUG_ENTER("ha_ibmdb2i::index_end");
 
2496
  warnIfInvalidData();
 
2497
  last_index_init_rc = 0;
 
2498
  if (likely(activeReadBuf))
 
2499
    activeReadBuf->endRead();
 
2500
  if (likely(!last_index_init_rc))
 
2501
    releaseIndexFile(active_index);
 
2502
  active_index= MAX_KEY;
 
2503
  DBUG_RETURN (0);
 
2504
}
 
2505
 
 
2506
int ha_ibmdb2i::doCommit(handlerton *hton, THD *thd, bool all)
 
2507
{
 
2508
  if (!THDVAR(thd, transaction_unsafe))
 
2509
  {
 
2510
    if (all || autoCommitIsOn(thd))
 
2511
    {
 
2512
      DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing all"));
 
2513
      return (db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_COMMIT));
 
2514
    }
 
2515
    else
 
2516
    {
 
2517
      DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing stmt"));
 
2518
      return (db2i_ileBridge::getBridgeForThread(thd)->commitStmtTx());
 
2519
    }
 
2520
  }
 
2521
  
 
2522
  return (0);
 
2523
 
2524
 
 
2525
 
 
2526
int ha_ibmdb2i::doRollback(handlerton *hton, THD *thd, bool all)
 
2527
{
 
2528
  if (!THDVAR(thd,transaction_unsafe))
 
2529
  {
 
2530
    if (all || autoCommitIsOn(thd))
 
2531
    {
 
2532
      DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back all"));
 
2533
      return ( db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_ROLLBACK));
 
2534
    }
 
2535
    else
 
2536
    {
 
2537
      DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back stmt"));
 
2538
      return (db2i_ileBridge::getBridgeForThread(thd)->rollbackStmtTx());
 
2539
    }
 
2540
  }
 
2541
  return (0);
 
2542
}
 
2543
 
 
2544
 
 
2545
void ha_ibmdb2i::start_bulk_insert(ha_rows rows)
 
2546
{
 
2547
  DBUG_ENTER("ha_ibmdb2i::start_bulk_insert");
 
2548
  DBUG_PRINT("ha_ibmdb2i::start_bulk_insert",("Rows hinted %d", rows));
 
2549
  int rc;
 
2550
  THD* thd = ha_thd();
 
2551
  int command = thd_sql_command(thd);
 
2552
  
 
2553
  if (db2Table->hasBlobs() || 
 
2554
      (command == SQLCOM_REPLACE || command == SQLCOM_REPLACE_SELECT))
 
2555
    rows = 1;
 
2556
  else if (rows == 0)
 
2557
    rows = DEFAULT_MAX_ROWS_TO_BUFFER; // Shoot the moon
 
2558
  
 
2559
 // If we're doing a multi-row insert, binlogging is active, and the table has an
 
2560
 // auto_increment column, then we'll attempt to lock the file while we perform a 'fast path' blocked
 
2561
 // insert.  If we can't get the lock, then we'll do a row-by-row 'slow path' insert instead.  The reason is
 
2562
 // because the MI generates the auto_increment (identity value), and if we can't lock the file,
 
2563
 // then we can't predetermine what that value will be for insertion into the MySQL write buffer.
 
2564
 
 
2565
  if ((rows > 1) &&                               // Multi-row insert
 
2566
      (thd->options & OPTION_BIN_LOG) &&          // Binlogging is on
 
2567
      (table->found_next_number_field))           // Table has an auto_increment column
 
2568
  {
 
2569
    if (!dataHandle)
 
2570
      rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);  
 
2571
 
 
2572
    rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LEAR, QMY_YES);
 
2573
    if (rc==0)                                     // Got the lock
 
2574
    {
 
2575
      autoIncLockAcquired = TRUE;               
 
2576
      got_auto_inc_values = FALSE;                    
 
2577
    }
 
2578
    else                                          // Didn't get the lock
 
2579
      rows = 1;                                   // No problem, but don't block inserts
 
2580
  }
 
2581
  
 
2582
  if (activeHandle == 0)
 
2583
  {
 
2584
    last_start_bulk_insert_rc = useDataFile();
 
2585
    if (last_start_bulk_insert_rc == 0)
 
2586
      last_start_bulk_insert_rc = prepWriteBuffer(rows, db2Table->dataFile());
 
2587
  }
 
2588
 
 
2589
  if (last_start_bulk_insert_rc == 0)
 
2590
    outstanding_start_bulk_insert = true;
 
2591
  else
 
2592
  {
 
2593
    if (autoIncLockAcquired == TRUE)
 
2594
    {
 
2595
      bridge()->lockObj(dataHandle,  0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
 
2596
      autoIncLockAcquired = FALSE;
 
2597
    }
 
2598
  }
 
2599
 
 
2600
  DBUG_VOID_RETURN;
 
2601
}
 
2602
 
 
2603
 
 
2604
int ha_ibmdb2i::end_bulk_insert()
 
2605
{
 
2606
  DBUG_ENTER("ha_ibmdb2i::end_bulk_insert");
 
2607
  int rc = 0;
 
2608
  
 
2609
  if (outstanding_start_bulk_insert)
 
2610
  {
 
2611
    rc = finishBulkInsert();
 
2612
  }
 
2613
 
 
2614
  my_errno = rc;
 
2615
    
 
2616
  DBUG_RETURN(rc);
 
2617
}
 
2618
 
 
2619
  
 
2620
int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent)    
 
2621
{
 
2622
  DBUG_ENTER("ha_ibmdb2i::prepReadBuffer");
 
2623
  DBUG_ASSERT(rowsToRead > 0);
 
2624
 
 
2625
  THD* thd = ha_thd();
 
2626
  char cmtLvl = getCommitLevel(thd);
 
2627
  
 
2628
  const db2i_file::RowFormat* format;
 
2629
  int rc = file->obtainRowFormat(activeHandle, intent, cmtLvl, &format);
 
2630
  
 
2631
  if (unlikely(rc)) DBUG_RETURN(rc);
 
2632
  
 
2633
  if (lobFieldsRequested())
 
2634
  {
 
2635
    forceSingleRowRead = true;
 
2636
    rowsToRead = 1;
 
2637
  }
 
2638
  
 
2639
  rowsToRead = min(stats.records+1,min(rowsToRead, DEFAULT_MAX_ROWS_TO_BUFFER));
 
2640
  
 
2641
  uint bufSize = min((format->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size));
 
2642
  multiRowReadBuf.allocBuf(format->readRowLen, format->readRowNullOffset, bufSize);
 
2643
  activeReadBuf = &multiRowReadBuf;
 
2644
    
 
2645
  if (db2Table->hasBlobs())
 
2646
  {
 
2647
    if (!blobReadBuffers)
 
2648
      blobReadBuffers = new BlobCollection(db2Table, THDVAR(thd, lob_alloc_size));  
 
2649
    rc = prepareReadBufferForLobs();
 
2650
    if (rc) DBUG_RETURN(rc);
 
2651
  }
 
2652
  
 
2653
//   if (accessIntent == QMY_UPDATABLE &&
 
2654
//       thd_tx_isolation(thd) == ISO_REPEATABLE_READ &&
 
2655
//       !THDVAR(thd, transaction_unsafe))
 
2656
//     activeReadBuf->update(QMY_READ_ONLY, &releaseRowNeeded, QMY_REPEATABLE_READ);
 
2657
//   else
 
2658
    activeReadBuf->update(intent, &releaseRowNeeded, cmtLvl);
 
2659
 
 
2660
  DBUG_RETURN(rc);
 
2661
}
 
2662
 
 
2663
 
 
2664
int ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file)
 
2665
{
 
2666
  DBUG_ENTER("ha_ibmdb2i::prepWriteBuffer");
 
2667
  DBUG_ASSERT(accessIntent == QMY_UPDATABLE && rowsToWrite > 0);
 
2668
  
 
2669
  const db2i_file::RowFormat* format;
 
2670
  int rc = file->obtainRowFormat(activeHandle,
 
2671
                                 QMY_UPDATABLE,
 
2672
                                 getCommitLevel(ha_thd()),
 
2673
                                 &format);
 
2674
 
 
2675
  if (unlikely(rc)) DBUG_RETURN(rc);
 
2676
  
 
2677
  rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER);
 
2678
  
 
2679
  uint bufSize = min((format->writeRowLen * rowsToWrite), THDVAR(ha_thd(), max_write_buffer_size));
 
2680
  multiRowWriteBuf.allocBuf(format->writeRowLen, format->writeRowNullOffset, bufSize);
 
2681
  activeWriteBuf = &multiRowWriteBuf;
 
2682
 
 
2683
  if (!blobWriteBuffers && db2Table->hasBlobs())
 
2684
  {
 
2685
    blobWriteBuffers = new ValidatedPointer<char>[db2Table->getBlobCount()];
 
2686
  }    
 
2687
  DBUG_RETURN(rc);
 
2688
}
 
2689
 
 
2690
 
 
2691
int ha_ibmdb2i::flushWrite(FILE_HANDLE fileHandle, uchar* buf )
 
2692
{
 
2693
  DBUG_ENTER("ha_ibmdb2i::flushWrite");
 
2694
  int rc;
 
2695
  int64 generatedIdValue = 0;
 
2696
  bool IdValueWasGenerated = FALSE;
 
2697
  char* lastDupKeyNamePtr = NULL;
 
2698
  uint32 lastDupKeyNameLen = 0;
 
2699
  int loopCnt = 0; 
 
2700
  bool retry_dup = FALSE; 
 
2701
 
 
2702
 while (loopCnt == 0 || retry_dup == TRUE) 
 
2703
 {
 
2704
  rc = bridge()->writeRows(fileHandle,
 
2705
                           activeWriteBuf->ptr(),
 
2706
                           getCommitLevel(),  
 
2707
                           &generatedIdValue,
 
2708
                           &IdValueWasGenerated,
 
2709
                           &lastDupKeyRRN,
 
2710
                           &lastDupKeyNamePtr,
 
2711
                           &lastDupKeyNameLen,
 
2712
                           &incrementByValue);
 
2713
  loopCnt++;  
 
2714
  retry_dup = FALSE;
 
2715
  invalidateCachedStats();
 
2716
  if (lastDupKeyNameLen)
 
2717
  {
 
2718
    rrnAssocHandle = fileHandle;
 
2719
    
 
2720
    int command = thd_sql_command(ha_thd());
 
2721
 
 
2722
    if (command == SQLCOM_REPLACE ||
 
2723
        command == SQLCOM_REPLACE_SELECT)
 
2724
      lastDupKeyID = 0;
 
2725
    else
 
2726
    {
 
2727
      lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen);
 
2728
      
 
2729
      if (likely(lastDupKeyID != MAX_KEY))
 
2730
      {
 
2731
        uint16 failedRow = activeWriteBuf->rowsWritten()+1; 
 
2732
 
 
2733
        if (buf && (failedRow != activeWriteBuf->rowCount()))
 
2734
        {
 
2735
          const char* badRow = activeWriteBuf->getRowN(failedRow-1);
 
2736
          bool savedReadAllColumns = readAllColumns;
 
2737
          readAllColumns = true;
 
2738
          mungeDB2row(buf, 
 
2739
                      badRow, 
 
2740
                      badRow + activeWriteBuf->getRowNullOffset(),
 
2741
                      true);
 
2742
          readAllColumns = savedReadAllColumns;
 
2743
 
 
2744
          if (table->found_next_number_field)
 
2745
          {
 
2746
            table->next_number_field->store(next_identity_value - (incrementByValue * (activeWriteBuf->rowCount() - (failedRow - 1))));
 
2747
          }
 
2748
        }
 
2749
 
 
2750
        if (default_identity_value &&                 // Table has ID colm and generating a value
 
2751
           (!autoIncLockAcquired || !got_auto_inc_values) &&
 
2752
                                                      // Writing first or only row in block
 
2753
            loopCnt == 1 &&                           // Didn't already retry
 
2754
            lastDupKeyID == table->s->next_number_index) // Autoinc column is in failed index
 
2755
        {  
 
2756
          if (alterStartWith() == 0)                  // Reset next Identity value to max+1
 
2757
            retry_dup = TRUE;                         // Rtry the write operation
 
2758
        } 
 
2759
      }
 
2760
      else
 
2761
      {
 
2762
        char unknownIndex[MAX_DB2_FILENAME_LENGTH+1];
 
2763
        convFromEbcdic(lastDupKeyNamePtr, unknownIndex, min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH));
 
2764
        unknownIndex[min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH)] = 0;        
 
2765
        getErrTxt(DB2I_ERR_UNKNOWN_IDX, unknownIndex);
 
2766
      }
 
2767
    }
 
2768
  }
 
2769
 } 
 
2770
 
 
2771
  if ((rc == 0 || rc == HA_ERR_FOUND_DUPP_KEY)
 
2772
         && default_identity_value && IdValueWasGenerated &&
 
2773
     (!autoIncLockAcquired || !got_auto_inc_values))
 
2774
  {
 
2775
    /* Save the generated identity value for the MySQL last_insert_id() function. */
 
2776
    insert_id_for_cur_row = generatedIdValue;
 
2777
 
 
2778
    /* Store the value into MySQL's buf for row-based replication
 
2779
       or for an 'on duplicate key update' clause.                      */
 
2780
    table->next_number_field->store((longlong) generatedIdValue, TRUE);
 
2781
    if (autoIncLockAcquired)
 
2782
    {
 
2783
      got_auto_inc_values = TRUE;
 
2784
      next_identity_value = generatedIdValue + incrementByValue;
 
2785
    }
 
2786
  } 
 
2787
  else
 
2788
  {
 
2789
    if (!autoIncLockAcquired)      // Don't overlay value for first row of a block  
 
2790
      insert_id_for_cur_row = 0;                                        
 
2791
  }
 
2792
  
 
2793
 
 
2794
  activeWriteBuf->resetAfterWrite();
 
2795
  DBUG_RETURN(rc);
 
2796
}
 
2797
 
 
2798
int ha_ibmdb2i::alterStartWith() 
 
2799
 
2800
  DBUG_ENTER("ha_ibmdb2i::alterStartWith");  
 
2801
  int rc = 0; 
 
2802
  ulonglong nextIdVal; 
 
2803
  if (!dataHandle) 
 
2804
     rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
 
2805
  if (!rc) {rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LENR, QMY_YES);}
 
2806
  if (!rc) 
 
2807
  {  
 
2808
    rc = getNextIdVal(&nextIdVal); 
 
2809
    if (!rc) {rc = reset_auto_increment(nextIdVal);} 
 
2810
    bridge()->lockObj(dataHandle,  0, QMY_UNLOCK, QMY_LENR, QMY_YES); 
 
2811
  } 
 
2812
  DBUG_RETURN(rc); 
 
2813
}
 
2814
 
 
2815
bool ha_ibmdb2i::lobFieldsRequested()
 
2816
{
 
2817
  if (!db2Table->hasBlobs())
 
2818
  {
 
2819
    DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs"));
 
2820
    return (false);
 
2821
  }
 
2822
 
 
2823
  if (readAllColumns)
 
2824
  {
 
2825
    DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("All cols requested"));
 
2826
    return (true);
 
2827
  }
 
2828
    
 
2829
  for (int i = 0; i < db2Table->getBlobCount(); ++i)
 
2830
  {
 
2831
    if (bitmap_is_set(table->read_set, db2Table->blobFields[i]))
 
2832
    {
 
2833
      DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("LOB requested"));
 
2834
      return (true);
 
2835
    }
 
2836
  }
 
2837
  
 
2838
  DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs requested"));
 
2839
  return (false);
 
2840
}
 
2841
 
 
2842
 
 
2843
int ha_ibmdb2i::prepareReadBufferForLobs()
 
2844
{
 
2845
  DBUG_ENTER("ha_ibmdb2i::prepareReadBufferForLobs");
 
2846
  DBUG_ASSERT(db2Table->hasBlobs());
 
2847
  
 
2848
  uint32 activeLobFields = 0;
 
2849
  DB2LobField* lobField;
 
2850
  uint16 blobCount = db2Table->getBlobCount();
 
2851
    
 
2852
  char* readBuf = activeReadBuf->getRowN(0);
 
2853
  
 
2854
  for (int i = 0; i < blobCount; ++i)
 
2855
  {
 
2856
    int fieldID = db2Table->blobFields[i];
 
2857
    DB2Field& db2Field = db2Table->db2Field(fieldID);
 
2858
    lobField = db2Field.asBlobField(readBuf);
 
2859
    if (readAllColumns ||
 
2860
        bitmap_is_set(table->read_set, fieldID))
 
2861
    {
 
2862
      lobField->dataHandle = (ILEMemHandle)blobReadBuffers->getBufferPtr(fieldID);
 
2863
      activeLobFields++;
 
2864
    }
 
2865
    else
 
2866
    {
 
2867
      lobField->dataHandle = NULL;
 
2868
    }
 
2869
  }
 
2870
  
 
2871
  if (activeLobFields == 0)
 
2872
  {
 
2873
    for (int i = 0; i < blobCount; ++i)
 
2874
    {
 
2875
      DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
 
2876
      uint16 offset = db2Field.getBufferOffset() + db2Field.calcBlobPad();
 
2877
 
 
2878
      for (int r = 1; r < activeReadBuf->getRowCapacity(); ++r)
 
2879
      { 
 
2880
        lobField = (DB2LobField*)(activeReadBuf->getRowN(r) + offset);
 
2881
        lobField->dataHandle = NULL;
 
2882
      }      
 
2883
    }
 
2884
  }
 
2885
 
 
2886
  activeReadBuf->setRowsToProcess((activeLobFields ? 1 : activeReadBuf->getRowCapacity()));
 
2887
  int rc = bridge()->objectOverride(activeHandle,
 
2888
                                    activeReadBuf->ptr(),
 
2889
                                    activeReadBuf->getRowLength());
 
2890
  DBUG_RETURN(rc);
 
2891
}
 
2892
 
 
2893
 
 
2894
uint32 ha_ibmdb2i::adjustLobBuffersForRead()
 
2895
{
 
2896
  DBUG_ENTER("ha_ibmdb2i::adjustLobBuffersForRead");
 
2897
 
 
2898
  char* readBuf = activeReadBuf->getRowN(0);
 
2899
   
 
2900
  for (int i = 0; i < db2Table->getBlobCount(); ++i)
 
2901
  {
 
2902
    DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]);
 
2903
    DB2LobField* lobField = db2Field.asBlobField(readBuf);
 
2904
    if (readAllColumns || 
 
2905
        bitmap_is_set(table->read_set, db2Table->blobFields[i]))
 
2906
    {
 
2907
      lobField->dataHandle = (ILEMemHandle)blobReadBuffers->reallocBuffer(db2Table->blobFields[i], lobField->length);
 
2908
 
 
2909
      if (lobField->dataHandle == NULL)
 
2910
        DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
2911
    }      
 
2912
    else
 
2913
    {
 
2914
      lobField->dataHandle = 0;
 
2915
    }
 
2916
  }
 
2917
  
 
2918
  int32 rc = bridge()->objectOverride(activeHandle,
 
2919
                                      activeReadBuf->ptr());
 
2920
  DBUG_RETURN(rc);
 
2921
}
 
2922
 
 
2923
 
 
2924
 
 
2925
int ha_ibmdb2i::reset()
 
2926
{
 
2927
  DBUG_ENTER("ha_ibmdb2i::reset");
 
2928
 
 
2929
  if (outstanding_start_bulk_insert)
 
2930
  {
 
2931
    finishBulkInsert();
 
2932
  }  
 
2933
  
 
2934
  if (activeHandle != 0)
 
2935
  {
 
2936
    releaseActiveHandle();
 
2937
  }
 
2938
  
 
2939
  cleanupBuffers();
 
2940
  
 
2941
  db2i_ileBridge::getBridgeForThread(ha_thd())->freeErrorStorage();
 
2942
    
 
2943
  last_rnd_init_rc = last_index_init_rc = last_start_bulk_insert_rc = 0;
 
2944
 
 
2945
  returnDupKeysImmediately = false;
 
2946
  onDupUpdate = false;
 
2947
  forceSingleRowRead = false; 
 
2948
 
 
2949
#ifndef DBUG_OFF
 
2950
  cachedBridge=NULL;
 
2951
#endif      
 
2952
      
 
2953
  DBUG_RETURN(0);
 
2954
}
 
2955
 
 
2956
 
 
2957
int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream, 
 
2958
                                           KEY& key,
 
2959
                                           bool isPrimary,
 
2960
                                           const char* db2LibName,    
 
2961
                                           const char* db2FileName)
 
2962
{
 
2963
  DBUG_ENTER("ha_ibmdb2i::buildCreateIndexStatement");
 
2964
 
 
2965
  char fileSortSequence[11] = "*HEX";
 
2966
  char fileSortSequenceLibrary[11] = "";
 
2967
  char fileSortSequenceType = ' ';
 
2968
  String query(256);
 
2969
  query.length(0);
 
2970
  int rc = 0;
 
2971
  
 
2972
  if (isPrimary)
 
2973
  {
 
2974
    query.append(STRING_WITH_LEN("ALTER TABLE "));
 
2975
    query.append(db2LibName);
 
2976
    query.append('.');
 
2977
    query.append(db2FileName);
 
2978
    query.append(STRING_WITH_LEN(" ADD PRIMARY KEY "));    
 
2979
  }
 
2980
  else
 
2981
  {
 
2982
    query.append(STRING_WITH_LEN("CREATE"));
 
2983
 
 
2984
    if (key.flags & HA_NOSAME)
 
2985
      query.append(STRING_WITH_LEN(" UNIQUE WHERE NOT NULL"));
 
2986
 
 
2987
    query.append(STRING_WITH_LEN(" INDEX "));
 
2988
 
 
2989
    query.append(db2LibName);
 
2990
    query.append('.');
 
2991
    if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, query))
 
2992
    {
 
2993
      getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
2994
      DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
2995
    }
 
2996
 
 
2997
    query.append(STRING_WITH_LEN(" ON "));
 
2998
 
 
2999
    query.append(db2LibName);
 
3000
    query.append('.');
 
3001
    query.append(db2FileName);
 
3002
  }
 
3003
  
 
3004
  String fieldDefinition(128);
 
3005
  fieldDefinition.length(0);
 
3006
  fieldDefinition.append(STRING_WITH_LEN(" ( "));
 
3007
  for (int j = 0; j < key.key_parts; ++j)
 
3008
  {
 
3009
    char colName[MAX_DB2_COLNAME_LENGTH+1];
 
3010
    if (j != 0)
 
3011
    {
 
3012
      fieldDefinition.append(STRING_WITH_LEN(" , "));
 
3013
    }
 
3014
    Field* field = key.key_part[j].field;
 
3015
    convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
 
3016
    fieldDefinition.append(colName);
 
3017
    rc = updateAssociatedSortSequence(field->charset(),
 
3018
                                      &fileSortSequenceType,
 
3019
                                      fileSortSequence,
 
3020
                                      fileSortSequenceLibrary);
 
3021
    if (rc) DBUG_RETURN (rc);
 
3022
  }
 
3023
  fieldDefinition.append(STRING_WITH_LEN(" ) "));
 
3024
  
 
3025
  query.append(fieldDefinition);
 
3026
  
 
3027
  if ((THDVAR(ha_thd(), create_index_option)==1) &&
 
3028
      (fileSortSequenceType != 'B'))
 
3029
  {
 
3030
    String shadowQuery(256);
 
3031
    shadowQuery.length(0);
 
3032
    
 
3033
    shadowQuery.append(STRING_WITH_LEN("CREATE INDEX "));
 
3034
 
 
3035
    shadowQuery.append(db2LibName);
 
3036
    shadowQuery.append('.');
 
3037
    if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, shadowQuery, db2i_table::ASCII_SQL, typeHex))
 
3038
    {
 
3039
      getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
 
3040
      DBUG_RETURN(DB2I_ERR_INVALID_NAME );
 
3041
    }
 
3042
 
 
3043
    shadowQuery.append(STRING_WITH_LEN(" ON "));
 
3044
 
 
3045
    shadowQuery.append(db2LibName);
 
3046
    shadowQuery.append('.');
 
3047
    shadowQuery.append(db2FileName);
 
3048
    shadowQuery.append(fieldDefinition);
 
3049
    DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",shadowQuery.c_ptr_safe()));
 
3050
    sqlStream.addStatement(shadowQuery,"*HEX","QSYS");
 
3051
  }
 
3052
    
 
3053
  DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",query.c_ptr_safe()));
 
3054
  sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
 
3055
 
 
3056
  DBUG_RETURN(0);
 
3057
}
 
3058
 
 
3059
 
 
3060
void ha_ibmdb2i::doInitialRead(char orientation,
 
3061
                                uint32 rowsToBuffer,
 
3062
                                ILEMemHandle key,
 
3063
                                int keyLength,
 
3064
                                int keyParts)
 
3065
{
 
3066
  DBUG_ENTER("ha_ibmdb2i::doInitialRead");
 
3067
  
 
3068
  if (forceSingleRowRead)
 
3069
    rowsToBuffer = 1;
 
3070
  else
 
3071
    rowsToBuffer = min(rowsToBuffer, activeReadBuf->getRowCapacity());
 
3072
        
 
3073
  activeReadBuf->newReadRequest(activeHandle,
 
3074
                                    orientation,
 
3075
                                    rowsToBuffer,
 
3076
                                    THDVAR(ha_thd(), async_enabled),
 
3077
                                    key, 
 
3078
                                    keyLength,
 
3079
                                    keyParts);
 
3080
  DBUG_VOID_RETURN;
 
3081
}
 
3082
 
 
3083
 
 
3084
int ha_ibmdb2i::start_stmt(THD *thd, thr_lock_type lock_type)
 
3085
{
 
3086
  DBUG_ENTER("ha_ibmdb2i::start_stmt");
 
3087
  initBridge(thd);
 
3088
  if (!THDVAR(thd, transaction_unsafe))
 
3089
  {
 
3090
    trans_register_ha(thd, FALSE, ibmdb2i_hton);
 
3091
    
 
3092
    if (!autoCommitIsOn(thd))
 
3093
    {
 
3094
      bridge()->beginStmtTx();
 
3095
    }
 
3096
  }
 
3097
 
 
3098
  DBUG_RETURN(0);
 
3099
}
 
3100
 
 
3101
int32 ha_ibmdb2i::handleLOBReadOverflow()
 
3102
{
 
3103
  DBUG_ENTER("ha_ibmdb2i::handleLOBReadOverflow");
 
3104
  DBUG_ASSERT(db2Table->hasBlobs() && (activeReadBuf->getRowCapacity() == 1));
 
3105
 
 
3106
  int32 rc = adjustLobBuffersForRead();
 
3107
 
 
3108
  if (!rc)
 
3109
  {
 
3110
    activeReadBuf->rewind();
 
3111
    rc = bridge()->expectErrors(QMY_ERR_END_OF_BLOCK)
 
3112
                 ->read(activeHandle, 
 
3113
                        activeReadBuf->ptr(),
 
3114
                        accessIntent,
 
3115
                        getCommitLevel(),
 
3116
                        QMY_SAME);
 
3117
    releaseRowNeeded = TRUE;
 
3118
 
 
3119
  }
 
3120
  DBUG_RETURN(rc);
 
3121
}
 
3122
 
 
3123
 
 
3124
int32 ha_ibmdb2i::finishBulkInsert()
 
3125
{
 
3126
  int32 rc = 0;
 
3127
 
 
3128
  if (activeWriteBuf->rowCount() && activeHandle)
 
3129
    rc = flushWrite(activeHandle, table->record[0]);
 
3130
 
 
3131
  if (activeHandle)
 
3132
    releaseActiveHandle();
 
3133
 
 
3134
  if (autoIncLockAcquired == TRUE)
 
3135
  {
 
3136
   // We could check the return code on the unlock, but beware not
 
3137
   // to overlay the return code from the flushwrite or we will mask
 
3138
   // duplicate key errors..
 
3139
    bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES);
 
3140
    autoIncLockAcquired = FALSE;
 
3141
  } 
 
3142
  outstanding_start_bulk_insert = false;
 
3143
  multiRowWriteBuf.freeBuf();    
 
3144
  last_start_bulk_insert_rc = 0;
 
3145
 
 
3146
  resetCharacterConversionBuffers();
 
3147
 
 
3148
  return rc;
 
3149
}
 
3150
 
 
3151
int ha_ibmdb2i::getKeyFromName(const char* name, size_t len)  
 
3152
{
 
3153
  for (int i = 0; i < table_share->keys; ++i)
 
3154
  {
 
3155
    const char* indexName = db2Table->indexFile(i)->getDB2FileName();
 
3156
    if ((strncmp(name, indexName, len) == 0) &&
 
3157
        (strlen(indexName) == len))
 
3158
    {
 
3159
      return i;        
 
3160
    }
 
3161
  }
 
3162
  return MAX_KEY;
 
3163
}
 
3164
 
 
3165
/*                                                                       
 
3166
Determine the number of I/O's it takes to read through the table.        
 
3167
                                                                      */
 
3168
double ha_ibmdb2i::scan_time()
 
3169
  {
 
3170
    DBUG_ENTER("ha_ibmdb2i::scan_time");
 
3171
    DBUG_RETURN(ulonglong2double((stats.data_file_length)/IO_SIZE));
 
3172
  }
 
3173
 
 
3174
 
 
3175
/**
 
3176
  Estimate the number of I/O's it takes to read a set of ranges through
 
3177
  an index.                                                            
 
3178
  
 
3179
  @param index  
 
3180
  @param ranges  
 
3181
  @param rows  
 
3182
  
 
3183
  @return The estimate number of I/Os
 
3184
*/
 
3185
 
 
3186
double ha_ibmdb2i::read_time(uint index, uint ranges, ha_rows rows)
 
3187
{
 
3188
  DBUG_ENTER("ha_ibmdb2i::read_time");
 
3189
  int rc;
 
3190
  uint64 idxPageCnt = 0;
 
3191
  double cost;
 
3192
  
 
3193
  if (unlikely(rows == HA_POS_ERROR))
 
3194
    DBUG_RETURN(double(rows) + ranges);
 
3195
 
 
3196
  rc = bridge()->retrieveIndexInfo(db2Table->indexFile(index)->getMasterDefnHandle(),
 
3197
                                                        &idxPageCnt);                     
 
3198
  if (!rc)
 
3199
  {
 
3200
     if ((idxPageCnt == 1) ||            // Retrieving rows in requested order or
 
3201
         (ranges == rows))               // 'Sweep' full records retrieval           
 
3202
       cost = idxPageCnt/4;
 
3203
     else
 
3204
     {  
 
3205
       uint64 totalRecords = stats.records + 1;
 
3206
       double dataPageCount = stats.data_file_length/IO_SIZE;
 
3207
                  
 
3208
       cost = (rows * dataPageCount / totalRecords) + 
 
3209
               min(idxPageCnt, (log_2(idxPageCnt) * ranges + 
 
3210
                                rows * (log_2(idxPageCnt) + log_2(rows) - log_2(totalRecords))));
 
3211
     } 
 
3212
  }
 
3213
  else
 
3214
  {
 
3215
     cost = rows2double(ranges+rows);    // Use default costing
 
3216
  }
 
3217
  DBUG_RETURN(cost);
 
3218
}
 
3219
 
 
3220
int ha_ibmdb2i::useIndexFile(int idx)
 
3221
{
 
3222
  DBUG_ENTER("ha_ibmdb2i::useIndexFile");
 
3223
 
 
3224
  if (activeHandle)
 
3225
    releaseActiveHandle();
 
3226
 
 
3227
  int rc = 0;
 
3228
 
 
3229
  if (!indexHandles[idx])
 
3230
    rc = db2Table->indexFile(idx)->allocateNewInstance(&indexHandles[idx], curConnection);
 
3231
 
 
3232
  if (rc == 0)
 
3233
  {
 
3234
      activeHandle = indexHandles[idx];
 
3235
      bumpInUseCounter(1);
 
3236
  }
 
3237
 
 
3238
   DBUG_RETURN(rc);
 
3239
}
 
3240
 
 
3241
 
 
3242
ulong ha_ibmdb2i::index_flags(uint inx, uint part, bool all_parts) const
 
3243
{
 
3244
  return  HA_READ_NEXT | HA_READ_PREV | HA_KEYREAD_ONLY | HA_READ_ORDER | HA_READ_RANGE;
 
3245
}
 
3246
 
 
3247
 
 
3248
static struct st_mysql_sys_var* ibmdb2i_system_variables[] = {
 
3249
  MYSQL_SYSVAR(rdb_name),
 
3250
  MYSQL_SYSVAR(transaction_unsafe),
 
3251
  MYSQL_SYSVAR(lob_alloc_size),
 
3252
  MYSQL_SYSVAR(max_read_buffer_size),
 
3253
  MYSQL_SYSVAR(max_write_buffer_size),
 
3254
  MYSQL_SYSVAR(async_enabled),
 
3255
  MYSQL_SYSVAR(assume_exclusive_use),
 
3256
  MYSQL_SYSVAR(compat_opt_blob_cols),
 
3257
  MYSQL_SYSVAR(compat_opt_time_as_duration),
 
3258
  MYSQL_SYSVAR(compat_opt_allow_zero_date_vals),
 
3259
  MYSQL_SYSVAR(compat_opt_year_as_int),
 
3260
  MYSQL_SYSVAR(propagate_default_col_vals),
 
3261
  MYSQL_SYSVAR(create_index_option),
 
3262
//   MYSQL_SYSVAR(discovery_mode),
 
3263
  MYSQL_SYSVAR(system_trace_level),
 
3264
  NULL
 
3265
};
 
3266
 
 
3267
 
 
3268
struct st_mysql_storage_engine ibmdb2i_storage_engine=
 
3269
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
 
3270
 
 
3271
mysql_declare_plugin(ibmdb2i)
 
3272
{
 
3273
  MYSQL_STORAGE_ENGINE_PLUGIN,
 
3274
  &ibmdb2i_storage_engine,
 
3275
  "IBMDB2I",
 
3276
  "The IBM development team in Rochester, Minnesota",
 
3277
  "IBM DB2 for i Storage Engine",
 
3278
  PLUGIN_LICENSE_GPL,
 
3279
  ibmdb2i_init_func,                            /* Plugin Init */
 
3280
  ibmdb2i_done_func,                            /* Plugin Deinit */
 
3281
  0x0100 /* 1.0 */,
 
3282
  NULL,                                         /* status variables */
 
3283
  ibmdb2i_system_variables,                       /* system variables */
 
3284
  NULL                                          /* config options */
 
3285
}
 
3286
mysql_declare_plugin_end;