~ubuntu-branches/ubuntu/natty/mysql-5.1/natty

« back to all changes in this revision

Viewing changes to storage/ibmdb2i/db2i_rir.cc

Tags: 5.1.54-1ubuntu1
* Synchronize from Debian Experimental:
* Merge from debian unstable:
  + debian/control:
     * Update maintainer according to spec.
     * Move section from "misc" to "database".
     * Added libmysqlclient16-dev an empty transitional package. 
     * Added mysql-client-core-5.1 package.
     * Suggest mailx for mysql-server-5.1
     * Add mysql-testsuite package so you can run the testsuite seperately.
  + debian/additions/my.cnf:
    * Remove language options. Error message files are located in a different directory in Mysql
      5.0. Setting the language option to use /usr/share/mysql/english breaks Mysql 5.0. Both 5.0
      and 5.1 use a different value that works. (LP: #316974)
  + Add apparmor profile:
    + debian/apparmor-profile: apparmor-profile
    + debian/rules, debian/mysql-server-5.1.files: install apparmor profile
    + debian/mysql-server-5.1.dirs: add etc/apparmor.d/fore-complain
    + debian/mysql-server-5.1.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
  * Convert the package from sysvinit to upstart:
    + debian/mysql-server-5.1.mysql.upstart: Add upstart script.
    + debian/mysql-server-5.1.mysql.init: Dropped, unused now with upstart.
    + debian/additions/mysqld_safe_syslog.cnf: Dropped, unused now with upstart.
    + debian/additons/my.cnf: Remove pid declaration and setup error logging to /var/log/mysql since
      we're not piping anything around logger anymore.
    + debian/rules, debian/mysql-server-5.1.logcheck.ignore.{paranoid,worstation},
      debian/mysql-server-5.1.logcheck.ignore.server: : Remove references to mysqld_safe
    + debian/patches/38_scripts_mysqld_safe.sh_signals.dpatch: Dropped
  * Added -fno-strict-aliasing to CFLAGS to get around mysql testsuite build failures.
  * Add Apport hook (LP: #354188):
    + debian/mysql-server-5.1.py: apport package hook
    + debian/rules: Make it installable
  * debian/mysql-server-5.1.mysql-server.logrotate: Check to see if mysql is running before
    running logrotate. (LP: #513135)
  * Make the testsuite installable. (LP: #530752)
    + debian/mysql-server-5.1.files, debian/rules: install apport package hook
  * debian/mysql-server-5.1.preinst: Set mysql user's home directory
    to /nonexistent to protect against having the /var/lib/mysql
    user-writeable. If an attacker can trick mysqld into creating
    dot files in the home directory, he could do .rhost-like attacks
    on the system. (LP: #293258)
  * debian/control: mysql-client-5.1 should depend on mysql-core-client-5.1.
    (LP: #590952)
  * debian/mysql-server.5.1.postinst: Specify the mysql user when installing 
    the mysql databases. (LP: #591875)
  * Installing mysql_config_pic in /usr/bin so users of libmysqld-pic
    can extract the appropriate compile flags. (LP: #605021) 

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
 
#include "ha_ibmdb2i.h"
38
 
 
39
 
/* Helper function for records_in_range.
40
 
     Input: Bitmap of used key parts.
41
 
     Output: Number of used key parts.                                        */
42
 
 
43
 
static inline int getKeyCntFromMap(key_part_map keypart_map)  
44
 
{
45
 
  int cnt = 0;
46
 
  while (keypart_map)
47
 
  {
48
 
    keypart_map = keypart_map >> 1;
49
 
    cnt++;
50
 
  }
51
 
  return (cnt); 
52
 
}
53
 
 
54
 
/**
55
 
  @brief
56
 
  Given a starting key and an ending key, estimate the number of rows that
57
 
  will exist between the two keys.
58
 
 
59
 
 INPUT
60
 
    inx      Index to use
61
 
    min_key    Min key. Is NULL if no min range
62
 
    max_key    Max key. Is NULL if no max range
63
 
 
64
 
 NOTES
65
 
    min_key.flag can have one of the following values:
66
 
      HA_READ_KEY_EXACT    Include the key in the range
67
 
      HA_READ_AFTER_KEY    Don't include key in range
68
 
 
69
 
    max_key.flag can have one of the following values:  
70
 
      HA_READ_BEFORE_KEY   Don't include key in range
71
 
      HA_READ_AFTER_KEY    Include all 'end_key' values in the range
72
 
 
73
 
  RETURN
74
 
   HA_POS_ERROR         Error or the storage engine cannot estimate the number of rows
75
 
   1                    There are no matching keys in the given range
76
 
   n > 0                There are approximately n rows in the range
77
 
*/
78
 
ha_rows ha_ibmdb2i::records_in_range(uint inx,
79
 
                                     key_range *min_key,
80
 
                                     key_range *max_key)
81
 
{
82
 
  DBUG_ENTER("ha_ibmdb2i::records_in_range");
83
 
  int rc = 0;                 // Return code
84
 
  ha_rows rows = 0;           // Row count returned to caller of this method 
85
 
  uint32 spcLen;              // Length of space passed to DB2   
86
 
  uint32 keyCnt;              // Number of fields in the key composite
87
 
  uint32 literalCnt = 0;      // Number of literals
88
 
  uint32 boundsOff;           // Offset from beginning of space to range bounds     
89
 
  uint32 litDefOff;           // Offset from beginning of space to literal definitions
90
 
  uint32 literalsOff;         // Offset from beginning of space to literal values
91
 
  uint32 cutoff = 0;          // Early exit cutoff (currently not used)
92
 
  uint64 recCnt;              // Row count from DB2       
93
 
  uint16 rtnCode;             // Return code from DB2
94
 
  Bounds* boundsPtr;          // Pointer to a pair of range bounds      
95
 
  Bound* boundPtr;            // Pointer to a single (high or low) range bound
96
 
  LitDef* litDefPtr;          // Pointer to a literal definition
97
 
  char* literalsPtr;          // Pointer to the start of all literal values
98
 
  char* literalPtr;           // Pointer to the start of this literal value
99
 
  char* tempPtr;              // Temporary pointer
100
 
  char* tempMinPtr;           // Temporary pointer into min_key
101
 
  int minKeyCnt = 0;          // Number of fields in the min_key composite 
102
 
  int maxKeyCnt = 0;          // Number of fields in the max_key composite
103
 
  size_t tempLen = 0;         // Temporary length
104
 
  uint16 DB2FieldWidth = 0;   // DB2 field width
105
 
  uint32 workFieldLen = 0;    // Length of workarea needed for CCSID conversions
106
 
  bool overrideInclusion;     // Indicator for inclusion/exclusion     
107
 
  char* endOfLiteralPtr;      // Pointer to the end of this literal
108
 
  char* endOfMinPtr;          // Pointer to end of min_key
109
 
  uint16 endByte = 0;         // End byte of char or graphic literal (padding not included) 
110
 
  bool reuseLiteral;          // Indicator that hi and lo bounds use same literal
111
 
  char* minPtr = NULL;               // Work pointer for traversing min_key  
112
 
  char* maxPtr = NULL;               // Work pointer for traversing max_key    
113
 
  /*                                                                                  
114
 
     Handle the special case of 'x < null' anywhere in the key range. There are
115
 
     no values less than null, but return 1 so that MySQL does not assume
116
 
     the empty set for the query. 
117
 
                                                                              */
118
 
  if (min_key != NULL && max_key != NULL &&
119
 
      min_key->flag == HA_READ_AFTER_KEY && max_key->flag == HA_READ_BEFORE_KEY && 
120
 
      min_key->length == max_key->length &&
121
 
     (memcmp((uchar*)min_key->key,(uchar*)max_key->key,min_key->length)==0))
122
 
  {
123
 
    DBUG_PRINT("ha_ibmdb2i::records_in_range",("Estimate 1 row for key %d; special case: < null", inx));
124
 
    DBUG_RETURN((ha_rows) 1 );                               
125
 
  }
126
 
  /*                                                                                  
127
 
     Determine the number of fields in the key composite.                             
128
 
                                                                              */
129
 
 
130
 
  if (min_key)
131
 
  {
132
 
    minKeyCnt = getKeyCntFromMap(min_key->keypart_map);
133
 
    minPtr = (char*)min_key->key;
134
 
  }
135
 
  if (max_key)
136
 
  {
137
 
    maxKeyCnt = getKeyCntFromMap(max_key->keypart_map);
138
 
    maxPtr = (char*)max_key->key;
139
 
  }
140
 
  keyCnt = maxKeyCnt >= minKeyCnt ? maxKeyCnt : minKeyCnt;
141
 
 
142
 
  /*
143
 
     Handle the special case where MySQL does not pass either a min or max
144
 
     key range. In this case, set the key count to 1 (knowing that there
145
 
     is at least one key field) to flow through and create one bounds structure.
146
 
     When both the min and max key ranges are nil, the bounds structure will
147
 
     specify positive and negative infinity and DB2 will estimate the total 
148
 
     number of rows.                                                                                                                                                            */
149
 
 
150
 
  if (keyCnt == 0)
151
 
    keyCnt = 1;
152
 
 
153
 
  /*                                                                               
154
 
     Allocate the space needed to pass range information to DB2. The            
155
 
     space must be large enough to store the following:                         
156
 
        - one pair of bounds (high and low) per field in the key composite            
157
 
        - one literal definition per literal value                              
158
 
        - the literal values                                                    
159
 
        - work area for literal CCSID conversions                                     
160
 
     Since we don't know yet how many of these structures are needed,           
161
 
     allocate enough space for the maximum that we will possibly need.        
162
 
     The workarea for the literal conversion must be big enough to hold the     
163
 
     largest of the DB2 key fields.                                             
164
 
                                                                              */
165
 
  KEY& curKey = table->key_info[inx];
166
 
 
167
 
  for (int i = 0; i < keyCnt; i++)  
168
 
  {
169
 
    DB2FieldWidth =
170
 
      db2Table->db2Field(curKey.key_part[i].field->field_index).getByteLengthInRecord();  
171
 
    if (DB2FieldWidth > workFieldLen)
172
 
      workFieldLen = DB2FieldWidth;      // Get length of largest DB2 field
173
 
    tempLen = tempLen + DB2FieldWidth;   // Tally the DB2 field lengths
174
 
  }
175
 
  spcLen = (sizeof(Bounds)*keyCnt) + (sizeof(LitDef)*keyCnt*2) + (tempLen*2) + workFieldLen;
176
 
 
177
 
  ValidatedPointer<char>  spcPtr(spcLen); // Pointer to space passed to DB2
178
 
  memset(spcPtr, 0, spcLen);             // Clear the allocated space 
179
 
  /*                                                                            
180
 
     Set addressability to the various sections of the DB2 interface space.     
181
 
                                                                              */
182
 
  boundsOff = 0;                         // Range bounds are at the start of the space
183
 
  litDefOff = sizeof(Bounds) * keyCnt;   // Literal defs follow all the range bounds       
184
 
  literalsOff = litDefOff + (sizeof(LitDef) * keyCnt * 2); // Literal values are last
185
 
  boundsPtr = (Bounds_t*)(void*)spcPtr;  // Address first bounds structure
186
 
  tempPtr = (char*)((char*)spcPtr + litDefOff);
187
 
  litDefPtr = (LitDef_t*)tempPtr;        // Address first literal definition
188
 
  tempPtr = (char*)((char*)spcPtr + literalsOff); 
189
 
  literalsPtr = (char*)tempPtr;          // Address start of literal values
190
 
  literalPtr = literalsPtr;              // Address first literal value 
191
 
  /*                                                                             
192
 
     For each key part, build the low (min) and high (max) DB2 range bounds.  
193
 
     If literals are specified in the MySQL range, build DB2 literal          
194
 
     definitions and store the literal values for access by DB2.              
195
 
                                                                              
196
 
     If no value is specified for a key part, assume infinity.  Negative      
197
 
     infinity will cause processing to start at the first index entry.        
198
 
     Positive infinity will cause processing to end at the last index entry.  
199
 
     When infinity is specified in a bound, inclusion/exclusion and position  
200
 
     are ignored, and there is no literal definition or literal value for     
201
 
     the bound.                                                               
202
 
                                                                              
203
 
     If the keypart value is null, the null indicator is set in the range     
204
 
     bound and the other fields in the bound are ignored. When the bound is   
205
 
     null, only index entries with the null value will be included in the     
206
 
     estimate. If one bound is null, both bounds must be null. When the bound 
207
 
     is not null, the data offset and length must be set, and the literal     
208
 
     value stored for access by DB2.                                          
209
 
                                                                                         */
210
 
  for (int partsInUse = 0; partsInUse < keyCnt; ++partsInUse)
211
 
  {
212
 
   Field *field= curKey.key_part[partsInUse].field;
213
 
   overrideInclusion = false;
214
 
   reuseLiteral = false;
215
 
   endOfLiteralPtr = NULL;
216
 
   /*
217
 
    Build the low bound for the key range.                                       
218
 
                                                                             */
219
 
    if ((partsInUse + 1) > minKeyCnt)                             // if no min_key info for this part
220
 
      boundsPtr->LoBound.Infinity[0] = QMY_NEG_INFINITY;          // select...where 3 between x and y    
221
 
    else
222
 
    {
223
 
      if ((curKey.key_part[partsInUse].null_bit) && (char*)minPtr[0])     
224
 
      {                                                           // min_key is null
225
 
        if (max_key == NULL ||
226
 
           ((partsInUse + 1) > maxKeyCnt))                        // select...where x='ab' and y=null and z != 'c'
227
 
          boundsPtr->LoBound.Infinity[0] = QMY_NEG_INFINITY;      // select...where x not null or
228
 
                                                                  // select...where x > null
229
 
        else                                                      // max_key is not null 
230
 
        {
231
 
          if (min_key->flag == HA_READ_KEY_EXACT) 
232
 
            boundsPtr->LoBound.IsNull[0] = QMY_YES;               // select...where x is null
233
 
          else                                                 
234
 
          {
235
 
            if ((char*)maxPtr[0])                                       
236
 
              boundsPtr->LoBound.IsNull[0] = QMY_YES;             // select...where a = null and b < 5 (max-before)
237
 
                                                                  // select...where a='a' and b is null and c !='a' (max-after)
238
 
            else 
239
 
              boundsPtr->LoBound.Infinity[0] = QMY_NEG_INFINITY;  // select...where x < y
240
 
          }
241
 
        }                                                         // end min_key is null
242
 
      }
243
 
      else                                                        // min_key is not null 
244
 
      {
245
 
        if (literalCnt) litDefPtr = litDefPtr + 1;
246
 
        literalCnt = literalCnt + 1;
247
 
        boundsPtr->LoBound.Position = literalCnt;
248
 
        /*
249
 
           Determine inclusion or exclusion.
250
 
                                                                                               */
251
 
        if (min_key->flag == HA_READ_KEY_EXACT ||                //select...where a like 'this%'
252
 
            
253
 
            /* An example for the following conditions is 'select...where a = 5 and b > null'. */
254
 
 
255
 
            (max_key &&
256
 
            (memcmp((uchar*)minPtr,(uchar*)maxPtr,
257
 
                    curKey.key_part[partsInUse].store_length)==0))) 
258
 
   
259
 
        {
260
 
          if ((min_key->flag != HA_READ_KEY_EXACT) ||
261
 
              (max_key &&
262
 
              (memcmp((uchar*)minPtr,(uchar*)maxPtr,
263
 
                    curKey.key_part[partsInUse].store_length)==0)))
264
 
            overrideInclusion = true;                     // Need inclusion for both min and max 
265
 
        }
266
 
        else
267
 
          boundsPtr->LoBound.Embodiment[0] = QMY_EXCLUSION;
268
 
        litDefPtr->FieldNbr = field->field_index + 1;
269
 
        DB2Field& db2Field = db2Table->db2Field(field->field_index);
270
 
        litDefPtr->DataType = db2Field.getType();
271
 
        /*
272
 
           Convert the literal to DB2 format
273
 
                                                                                               */
274
 
        if ((field->type() != MYSQL_TYPE_BIT) &&           // Don't do conversion on BIT data
275
 
            (field->charset() != &my_charset_bin) &&       // Don't do conversion on BINARY data
276
 
            (litDefPtr->DataType == QMY_CHAR ||
277
 
             litDefPtr->DataType == QMY_VARCHAR ||
278
 
             litDefPtr->DataType == QMY_GRAPHIC ||
279
 
             litDefPtr->DataType == QMY_VARGRAPHIC))
280
 
        {
281
 
          // Most of the code is required by the considerable wrangling needed
282
 
          // to prepare partial keys for use by DB2
283
 
          // 1. UTF8 (CCSID 1208) data can be copied across unmodified if it is
284
 
          //    utf8_bin. Otherwise, we need to convert the min and max
285
 
          //    characters into the min and max characters employed
286
 
          //    by the DB2 sort sequence. This is complicated by the fact that
287
 
          //    the character widths are not always equal.
288
 
          //  2. Likewise, UCS2 (CCSID 13488) data can be copied across unmodified
289
 
          //     if it is ucs2_bin or ucs2_general_ci. Otherwise, we need to
290
 
          //     convert the min and max characters into the min and max characters
291
 
          //     employed by the DB2 sort sequence.
292
 
          //  3. All other data will use standard iconv conversions. If an
293
 
          //     unconvertible character is encountered, we assume it is the min
294
 
          //     char and fill the remainder of the DB2 key with 0s. This may not
295
 
          //     always be accurate, but it is probably sufficient for range
296
 
          //     estimations.
297
 
          const char* keyData = minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
298
 
          char* db2Data = literalPtr;
299
 
          uint16 outLen = db2Field.getByteLengthInRecord();
300
 
          uint16 inLen;
301
 
          if (litDefPtr->DataType == QMY_VARCHAR ||
302
 
              litDefPtr->DataType == QMY_VARGRAPHIC)
303
 
          {
304
 
            inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
305
 
            keyData += 2;
306
 
            outLen -= sizeof(uint16);
307
 
            db2Data += sizeof(uint16);
308
 
          }
309
 
          else
310
 
          {
311
 
            inLen = field->max_display_length();
312
 
          }
313
 
          
314
 
          size_t convertedBytes = 0;
315
 
          if (db2Field.getCCSID() == 1208)
316
 
          {
317
 
            DBUG_ASSERT(inLen <= outLen);
318
 
            if (strcmp(field->charset()->name, "utf8_bin"))
319
 
            {
320
 
              const char* end = keyData+inLen;
321
 
              const char* curKey = keyData;
322
 
              char* curDB2 = db2Data;
323
 
              uint32 min = field->charset()->min_sort_char;
324
 
              while ((curKey < end) && (curDB2 < db2Data+outLen-3))
325
 
              {
326
 
                my_wc_t temp;
327
 
                int len = field->charset()->cset->mb_wc(field->charset(),
328
 
                                                        &temp, 
329
 
                                                        (const uchar*)curKey, 
330
 
                                                        (const uchar*)end);
331
 
                if (temp != min)
332
 
                {
333
 
                  DBUG_ASSERT(len <= 3);
334
 
                  switch (len)
335
 
                  {
336
 
                    case 3: *(curDB2+2) = *(curKey+2);
337
 
                    case 2: *(curDB2+1) = *(curKey+1);
338
 
                    case 1: *(curDB2) = *(curKey);
339
 
                  }                      
340
 
                  curDB2 += len;
341
 
                }
342
 
                else
343
 
                {
344
 
                  *(curDB2++) = 0xEF;
345
 
                  *(curDB2++) = 0xBF;
346
 
                  *(curDB2++) = 0xBF;
347
 
                }
348
 
                curKey += len;
349
 
              }
350
 
              convertedBytes = curDB2 - db2Data;
351
 
            }
352
 
            else
353
 
            {
354
 
              memcpy(db2Data, keyData, inLen);
355
 
              convertedBytes = inLen;
356
 
            }
357
 
            rc = 0;
358
 
          }
359
 
          else if (db2Field.getCCSID() == 13488)
360
 
          {
361
 
            DBUG_ASSERT(inLen <= outLen);
362
 
            if (strcmp(field->charset()->name, "ucs2_bin") &&
363
 
                strcmp(field->charset()->name, "ucs2_general_ci"))
364
 
            {
365
 
              const char* end = keyData+inLen;
366
 
              const uint16* curKey = (uint16*)keyData;
367
 
              uint16* curDB2 = (uint16*)db2Data;
368
 
              uint16 min = field->charset()->min_sort_char;
369
 
              while (curKey < (uint16*)end)
370
 
              {
371
 
                if (*curKey != min)
372
 
                  *curDB2 = *curKey;
373
 
                else
374
 
                  *curDB2 = 0xFFFF;
375
 
                ++curKey;
376
 
                ++curDB2;
377
 
              }
378
 
            }
379
 
            else
380
 
            {
381
 
              memcpy(db2Data, keyData, inLen);
382
 
            }
383
 
            convertedBytes = inLen;
384
 
            rc = 0;
385
 
          }
386
 
          else
387
 
          {
388
 
            rc = convertFieldChars(toDB2, 
389
 
                                   field->field_index, 
390
 
                                   keyData,
391
 
                                   db2Data,
392
 
                                   inLen,
393
 
                                   outLen,
394
 
                                   &convertedBytes,
395
 
                                   true);
396
 
 
397
 
            if (rc == DB2I_ERR_ILL_CHAR)
398
 
            {
399
 
              // If an illegal character is encountered, we fill the remainder
400
 
              // of the key with 0x00. This was implemented as a corollary to
401
 
              // Bug#45012, though it should probably remain even after that
402
 
              // bug is fixed.
403
 
              memset(db2Data+convertedBytes, 0x00, outLen-convertedBytes);
404
 
              convertedBytes = outLen;
405
 
              rc = 0;
406
 
            }
407
 
          }
408
 
          
409
 
          if (!rc &&
410
 
              (litDefPtr->DataType == QMY_VARGRAPHIC ||
411
 
               litDefPtr->DataType == QMY_VARCHAR))
412
 
          {
413
 
            *(uint16*)(db2Data-sizeof(uint16)) = 
414
 
                convertedBytes / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
415
 
          }
416
 
 
417
 
        }
418
 
        else // Non-character fields
419
 
        {
420
 
          rc = convertMySQLtoDB2(field,
421
 
                                 db2Field,
422
 
                                 literalPtr,
423
 
                                 (uchar*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
424
 
        }
425
 
 
426
 
        if (rc != 0) break;
427
 
        litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
428
 
        litDefPtr->Length = db2Field.getByteLengthInRecord();
429
 
        literalPtr = literalPtr + litDefPtr->Length;  // Bump pointer for next literal
430
 
      }
431
 
      /* If there is a max_key value for this field, and if the max_key value is 
432
 
         the same as the min_key value, then the low bound literal can be reused              
433
 
         for the high bound literal. This eliminates the overhead of copying and
434
 
         converting the same value twice.                                        */ 
435
 
      if (max_key && ((partsInUse + 1) <= maxKeyCnt) && 
436
 
          (memcmp((uchar*)minPtr,(uchar*)maxPtr,
437
 
                    curKey.key_part[partsInUse].store_length)==0 || endOfLiteralPtr))   
438
 
        reuseLiteral = true;
439
 
      minPtr += curKey.key_part[partsInUse].store_length;
440
 
    }
441
 
   /*
442
 
      Build the high bound for the key range. 
443
 
                                                                              */
444
 
    if (max_key == NULL || ((partsInUse + 1) > maxKeyCnt))                                         
445
 
      boundsPtr->HiBound.Infinity[0] = QMY_POS_INFINITY;     
446
 
    else                                                      
447
 
    {
448
 
      if ((curKey.key_part[partsInUse].null_bit) && (char*)maxPtr[0])
449
 
      {
450
 
        if (min_key == NULL)
451
 
          boundsPtr->HiBound.Infinity[0] = QMY_POS_INFINITY;   
452
 
        else
453
 
          boundsPtr->HiBound.IsNull[0] = QMY_YES;             // select...where x is null
454
 
      }  
455
 
      else                                                    // max_key field is not null
456
 
      {
457
 
        if (boundsPtr->LoBound.IsNull[0] == QMY_YES)          // select where x < 10 or x is null
458
 
        {
459
 
          rc = HA_POS_ERROR;
460
 
          break;
461
 
        }
462
 
        if (!reuseLiteral)                                    
463
 
        {  
464
 
          if (literalCnt)             
465
 
            litDefPtr = litDefPtr + 1;
466
 
          literalCnt = literalCnt + 1;
467
 
          litDefPtr->FieldNbr = field->field_index + 1;
468
 
          DB2Field& db2Field = db2Table->db2Field(field->field_index);
469
 
          litDefPtr->DataType = db2Field.getType();
470
 
        /*
471
 
           Convert the literal to DB2 format
472
 
                                                                                               */
473
 
        if ((field->type() != MYSQL_TYPE_BIT) &&           // Don't do conversion on BIT data
474
 
            (field->charset() != &my_charset_bin) &&       // Don't do conversion on BINARY data
475
 
            (litDefPtr->DataType == QMY_CHAR ||
476
 
             litDefPtr->DataType == QMY_VARCHAR ||
477
 
             litDefPtr->DataType == QMY_GRAPHIC ||
478
 
             litDefPtr->DataType == QMY_VARGRAPHIC))
479
 
          {
480
 
            // We need to handle char fields in a special way in order to account
481
 
            // for partial keys. Refer to the note above for a description of the
482
 
            // basic design.
483
 
            char* keyData = maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
484
 
            char* db2Data = literalPtr;
485
 
            uint16 outLen = db2Field.getByteLengthInRecord();
486
 
            uint16 inLen;
487
 
            if (litDefPtr->DataType == QMY_VARCHAR ||
488
 
                litDefPtr->DataType == QMY_VARGRAPHIC)
489
 
            {
490
 
              inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
491
 
              keyData += 2;
492
 
              outLen -= sizeof(uint16);
493
 
              db2Data += sizeof(uint16);
494
 
            }
495
 
            else
496
 
            {
497
 
              inLen = field->max_display_length();
498
 
            }
499
 
            
500
 
            size_t convertedBytes;
501
 
            if (db2Field.getCCSID() == 1208)
502
 
            {
503
 
              if (strcmp(field->charset()->name, "utf8_bin"))
504
 
              {
505
 
                const char* end = keyData+inLen;
506
 
                const char* curKey = keyData;
507
 
                char* curDB2 = db2Data;
508
 
                uint32 max = field->charset()->max_sort_char;
509
 
                while (curKey < end && (curDB2 < db2Data+outLen-3))
510
 
                {
511
 
                  my_wc_t temp;
512
 
                  int len = field->charset()->cset->mb_wc(field->charset(), &temp, (const uchar*)curKey, (const uchar*)end);
513
 
                  if (temp != max)
514
 
                  {
515
 
                    DBUG_ASSERT(len <= 3);
516
 
                    switch (len)
517
 
                    {
518
 
                      case 3: *(curDB2+2) = *(curKey+2);
519
 
                      case 2: *(curDB2+1) = *(curKey+1);
520
 
                      case 1: *(curDB2) = *(curKey);
521
 
                    }                      
522
 
                    curDB2 += len;
523
 
                  }
524
 
                  else
525
 
                  {
526
 
                    *(curDB2++) = 0xE4;
527
 
                    *(curDB2++) = 0xB6;
528
 
                    *(curDB2++) = 0xBF;
529
 
                  }
530
 
                  curKey += len;
531
 
                }
532
 
                convertedBytes = curDB2 - db2Data;
533
 
              }
534
 
              else
535
 
              {
536
 
                DBUG_ASSERT(inLen <= outLen);
537
 
                memcpy(db2Data, keyData, inLen);
538
 
                convertedBytes = inLen;
539
 
              }
540
 
              rc = 0;
541
 
            }
542
 
            else if (db2Field.getCCSID() == 13488)
543
 
            {
544
 
              if (strcmp(field->charset()->name, "ucs2_bin") &&
545
 
                  strcmp(field->charset()->name, "ucs2_general_ci"))
546
 
              {
547
 
                char* end = keyData+inLen;
548
 
                uint16* curKey = (uint16*)keyData;
549
 
                uint16* curDB2 = (uint16*)db2Data;
550
 
                uint16 max = field->charset()->max_sort_char;
551
 
                while (curKey < (uint16*)end)
552
 
                {
553
 
                  if (*curKey != max)
554
 
                    *curDB2 = *curKey;
555
 
                  else
556
 
                    *curDB2 = 0x4DBF;
557
 
                  ++curKey;
558
 
                  ++curDB2;
559
 
                }
560
 
              }
561
 
              else
562
 
              {
563
 
                memcpy(db2Data, keyData, outLen);
564
 
              }
565
 
              rc = 0;
566
 
            }
567
 
            else
568
 
            {
569
 
              size_t substituteChars = 0;
570
 
              rc = convertFieldChars(toDB2, 
571
 
                                     field->field_index, 
572
 
                                     keyData,
573
 
                                     db2Data,
574
 
                                     inLen,
575
 
                                     outLen,
576
 
                                     &convertedBytes,
577
 
                                     true,
578
 
                                     &substituteChars);
579
 
 
580
 
              if (rc == DB2I_ERR_ILL_CHAR)
581
 
              {
582
 
                // If an illegal character is encountered, we fill the remainder
583
 
                // of the key with 0xFF. This was implemented to work around
584
 
                // Bug#45012, though it should probably remain even after that
585
 
                // bug is fixed.
586
 
                memset(db2Data+convertedBytes, 0xFF, outLen-convertedBytes);
587
 
                rc = 0;
588
 
              }
589
 
              else if ((substituteChars &&
590
 
                        (litDefPtr->DataType == QMY_VARCHAR ||
591
 
                         litDefPtr->DataType == QMY_CHAR)) ||
592
 
                       strcmp(field->charset()->name, "cp1251_bulgarian_ci") == 0)
593
 
              {
594
 
                // When iconv translates the max_sort_char with a substitute 
595
 
                // character, we have no way to know whether this affects
596
 
                // the sort order of the key. Therefore, to be safe, when
597
 
                // we know that substitute characters have been used in a
598
 
                // single-byte string, we traverse the translated key
599
 
                // in reverse, replacing substitue characters with 0xFF, which
600
 
                // always sorts with the greatest weight in DB2 sort sequences.
601
 
                // cp1251_bulgarian_ci is also handled this way because the
602
 
                // max_sort_char is a control character which does not sort
603
 
                // equivalently in DB2.
604
 
                DBUG_ASSERT(inLen == outLen);
605
 
                char* tmpKey = keyData + inLen - 1;
606
 
                char* tmpDB2 = db2Data + outLen - 1;
607
 
                while (*tmpKey == field->charset()->max_sort_char &&
608
 
                       *tmpDB2 != 0xFF)
609
 
                {
610
 
                  *tmpDB2 = 0xFF;
611
 
                  --tmpKey;
612
 
                  --tmpDB2;
613
 
                }                  
614
 
              }
615
 
            }
616
 
            
617
 
            if (!rc &&
618
 
                (litDefPtr->DataType == QMY_VARGRAPHIC ||
619
 
                 litDefPtr->DataType == QMY_VARCHAR))
620
 
            {
621
 
              *(uint16*)(db2Data-sizeof(uint16)) = 
622
 
                  outLen / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
623
 
            }
624
 
          }
625
 
          else
626
 
          {
627
 
            rc = convertMySQLtoDB2(field,
628
 
                                   db2Field,
629
 
                                   literalPtr,
630
 
                                   (uchar*)maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
631
 
          }
632
 
          if (rc != 0) break;
633
 
          litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
634
 
          litDefPtr->Length = db2Field.getByteLengthInRecord();
635
 
          literalPtr = literalPtr + litDefPtr->Length;   // Bump pointer for next literal
636
 
        }
637
 
        boundsPtr->HiBound.Position = literalCnt;
638
 
        if (max_key->flag == HA_READ_BEFORE_KEY && !overrideInclusion)
639
 
          boundsPtr->HiBound.Embodiment[0] = QMY_EXCLUSION;
640
 
      }
641
 
      maxPtr += curKey.key_part[partsInUse].store_length;
642
 
    }
643
 
  /*                                                                            
644
 
     Bump to the next field in the key composite.                                     
645
 
                                                                              */
646
 
 
647
 
    if ((partsInUse+1) < keyCnt)
648
 
      boundsPtr = boundsPtr + 1;
649
 
  }
650
 
 
651
 
  /*                                                                            
652
 
     Call DB2 to estimate the number of rows in the key range.                  
653
 
                                                                              */
654
 
  if (rc == 0)
655
 
  {    
656
 
    rc = db2i_ileBridge::getBridgeForThread()->recordsInRange((indexHandles[inx] ? indexHandles[inx] : db2Table->indexFile(inx)->getMasterDefnHandle()),
657
 
                                                            spcPtr,  
658
 
                                                            keyCnt,  
659
 
                                                            literalCnt,
660
 
                                                            boundsOff,
661
 
                                                            litDefOff,
662
 
                                                            literalsOff,
663
 
                                                            cutoff,
664
 
                                                            (uint32_t)(literalPtr - (char*)spcPtr),            
665
 
                                                            endByte,
666
 
                                                            &recCnt,
667
 
                                                            &rtnCode);
668
 
  }
669
 
    /*                                                                            
670
 
     Set the row count and return.                                            
671
 
     Beware that if this method returns a zero row count, MySQL assumes the
672
 
     result set for the query is zero; never return a zero row count.                      
673
 
                                                                              */
674
 
  if ((rc == 0) && (rtnCode == QMY_SUCCESS || rtnCode == QMY_EARLY_EXIT))
675
 
  {
676
 
    rows = recCnt ? (ha_rows)recCnt : 1;                                                 
677
 
  }
678
 
 
679
 
  rows = (rows > 0 ? rows : HA_POS_ERROR);
680
 
 
681
 
  setIndexReadEstimate(inx, rows);
682
 
  
683
 
  DBUG_PRINT("ha_ibmdb2i::recordsInRange",("Estimate %d rows for key %d", uint32(rows), inx));  
684
 
  
685
 
  DBUG_RETURN(rows);                              
686
 
}