~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/pbxt/src/myxt_xt.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2005 PrimeBase Technologies GmbH
 
2
 *
 
3
 * PrimeBase XT
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
18
 *
 
19
 * 2006-05-16   Paul McCullagh
 
20
 *
 
21
 * H&G2JCtL
 
22
 *
 
23
 * These functions implement the parts of PBXT which must conform to the
 
24
 * key and row format used by MySQL. 
 
25
 */
 
26
 
 
27
#include "xt_config.h"
 
28
#include "xt_defs.h"
 
29
 
 
30
#ifdef DRIZZLED
 
31
#include <drizzled/internal/my_pthread.h>
 
32
#include <drizzled/plugin.h>
 
33
#include <drizzled/plugin/client.h>
 
34
#include <drizzled/plugin/null_client.h>
 
35
#include <drizzled/plugin/listen.h>
 
36
#include <drizzled/show.h>
 
37
#include <drizzled/data_home.h>
 
38
#include <drizzled/field/blob.h>
 
39
#include <drizzled/field/enum.h>
 
40
#include <drizzled/field/varstring.h>
 
41
#include <drizzled/current_session.h>
 
42
#include <drizzled/sql_lex.h>
 
43
#include <drizzled/session.h>
 
44
#include <drizzled/charset_info.h>
 
45
#include <plugin/myisam/my_handler.h>
 
46
#include <plugin/myisam/myisampack.h>
 
47
//extern "C" struct charset_info_st *session_charset(Session *session);
 
48
extern pthread_key_t THR_Session;
 
49
 
 
50
using namespace drizzled;
 
51
#else
 
52
#include "mysql_priv.h"
 
53
#include <mysql/plugin.h>
 
54
#endif
 
55
 
 
56
#ifdef HAVE_ISNAN
 
57
#include <math.h>
 
58
#endif
 
59
#include <strings.h>
 
60
 
 
61
#include "ha_pbxt.h"
 
62
 
 
63
#include "myxt_xt.h"
 
64
#include "strutil_xt.h"
 
65
#include "database_xt.h"
 
66
#include "cache_xt.h"
 
67
#include "datalog_xt.h"
 
68
#include "memory_xt.h"
 
69
 
 
70
static void             myxt_bitmap_init(XTThreadPtr self, MX_BITMAP *map, u_int n_bits);
 
71
static void             myxt_bitmap_free(XTThreadPtr self, MX_BITMAP *map);
 
72
 
 
73
#ifdef DRIZZLED
 
74
#define swap_variables(TYPE, a, b) \
 
75
  do {                             \
 
76
    TYPE dummy;                    \
 
77
    dummy= a;                      \
 
78
    a= b;                          \
 
79
    b= dummy;                      \
 
80
  } while (0)
 
81
 
 
82
 
 
83
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
 
84
#else
 
85
#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \
 
86
        (((((uint16) (bit_ptr)[1] << 8) | (uint16) (bit_ptr)[0]) >> (bit_ofs)) & \
 
87
   ((1 << (bit_len)) - 1))
 
88
#endif
 
89
 
 
90
#define FIX_LENGTH(cs, pos, length, char_length) \
 
91
                                                do { \
 
92
                                                        if ((length) > char_length) \
 
93
                                                                char_length= my_charpos(cs, pos, pos+length, char_length); \
 
94
                                                        set_if_smaller(char_length,length); \
 
95
                                                } while(0)
 
96
 
 
97
#ifdef store_key_length_inc
 
98
#undef store_key_length_inc
 
99
#endif
 
100
#define store_key_length_inc(key,length) \
 
101
{ if ((length) < 255) \
 
102
        { *(key)++=(length); } \
 
103
        else \
 
104
        { *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
 
105
}
 
106
 
 
107
#define set_rec_bits(bits, bit_ptr, bit_ofs, bit_len) \
 
108
{ \
 
109
        (bit_ptr)[0]= ((bit_ptr)[0] & ~(((1 << (bit_len)) - 1) << (bit_ofs))) | \
 
110
                ((bits) << (bit_ofs)); \
 
111
        if ((bit_ofs) + (bit_len) > 8) \
 
112
    (bit_ptr)[1]= ((bit_ptr)[1] & ~((1 << ((bit_len) - 8 + (bit_ofs))) - 1)) | \
 
113
                  ((bits) >> (8 - (bit_ofs))); \
 
114
}
 
115
 
 
116
#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
 
117
        set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
 
118
 
 
119
#ifdef DRIZZLED
 
120
static const char hexchars[]= "0123456789abcdef";
 
121
 
 
122
static bool tablename_to_filename(const char *from, char *to, size_t to_length)
 
123
{
 
124
 
 
125
  size_t length= 0;
 
126
  for (; *from  && length < to_length; length++, from++)
 
127
  {
 
128
    if ((*from >= '0' && *from <= '9') ||
 
129
        (*from >= 'A' && *from <= 'Z') ||
 
130
        (*from >= 'a' && *from <= 'z') ||
 
131
/* OSX defines an extra set of high-bit and multi-byte characters
 
132
   that cannot be used on the filesystem. Instead of trying to sort
 
133
   those out, we'll just escape encode all high-bit-set chars on OSX.
 
134
   It won't really hurt anything - it'll just make some filenames ugly. */
 
135
#if !defined(TARGET_OS_OSX)
 
136
        ((unsigned char)*from >= 128) ||
 
137
#endif
 
138
        (*from == '_') ||
 
139
        (*from == ' ') ||
 
140
        (*from == '-'))
 
141
    {
 
142
      to[length]= *from;
 
143
      continue;
 
144
    }
 
145
 
 
146
    if (length + 3 >= to_length)
 
147
      return true;
 
148
 
 
149
    /* We need to escape this char in a way that can be reversed */
 
150
    to[length++]= '@';
 
151
    to[length++]= hexchars[(*from >> 4) & 15];
 
152
    to[length]= hexchars[(*from) & 15];
 
153
  }
 
154
 
 
155
  if (/*internal::check_if_legal_tablename(to) &&*/
 
156
      length + 4 < to_length)
 
157
  {
 
158
    memcpy(to + length, "@@@", 4);
 
159
    length+= 3;
 
160
  }
 
161
  return false;
 
162
}
 
163
#endif
 
164
 
 
165
static ulong my_calc_blob_length(uint length, xtWord1 *pos)
 
166
{
 
167
        switch (length) {
 
168
        case 1:
 
169
                return (uint) (uchar) *pos;
 
170
        case 2:
 
171
                return (uint) uint2korr(pos);
 
172
        case 3:
 
173
                return uint3korr(pos);
 
174
        case 4:
 
175
                return uint4korr(pos);
 
176
        default:
 
177
                break;
 
178
        }
 
179
        return 0; /* Impossible */
 
180
}
 
181
 
 
182
static void my_store_blob_length(byte *pos,uint pack_length,uint length)
 
183
{
 
184
        switch (pack_length) {
 
185
        case 1:
 
186
                *pos= (uchar) length;
 
187
                break;
 
188
        case 2:
 
189
                int2store(pos,length);
 
190
                break;
 
191
        case 3:
 
192
                int3store(pos,length);
 
193
                break;
 
194
        case 4:
 
195
                int4store(pos,length);
 
196
        default:
 
197
                break;
 
198
        }
 
199
        return;
 
200
}
 
201
 
 
202
static int my_compare_text(MX_CONST_CHARSET_INFO *charset_info, uchar *a, uint a_length,
 
203
                                uchar *b, uint b_length, my_bool part_key,
 
204
                                my_bool XT_UNUSED(skip_end_space))
 
205
{
 
206
        if (!part_key)
 
207
                /* The last parameter is diff_if_only_endspace_difference, which means
 
208
                 * that end spaces are not ignored. We actually always want
 
209
                 * to ignore end spaces!
 
210
                 */
 
211
                return charset_info->coll->strnncollsp(charset_info, a, a_length,
 
212
                                b, b_length, /*(my_bool)!skip_end_space*/0);
 
213
        return charset_info->coll->strnncoll(charset_info, a, a_length,
 
214
                        b, b_length, part_key);
 
215
}
 
216
 
 
217
/*
 
218
 * -----------------------------------------------------------------------
 
219
 * Create a key
 
220
 */
 
221
 
 
222
/*
 
223
 * Derived from _mi_pack_key()
 
224
 */
 
225
xtPublic u_int myxt_create_key_from_key(XTIndexPtr ind, xtWord1 *key, xtWord1 *old, u_int k_length)
 
226
{
 
227
        xtWord1                 *start_key = key;
 
228
        XTIndexSegRec   *keyseg = ind->mi_seg;
 
229
 
 
230
        for (u_int i=0; i<ind->mi_seg_count && (int) k_length > 0; i++, old += keyseg->length, keyseg++)
 
231
        {
 
232
#ifndef DRIZZLED
 
233
                enum ha_base_keytype    type = (enum ha_base_keytype) keyseg->type;
 
234
#endif
 
235
                u_int                                   length = keyseg->length < k_length ? keyseg->length : k_length;
 
236
                u_int                                   char_length;
 
237
                xtWord1                                 *pos;
 
238
                MX_CONST_CHARSET_INFO   *cs = keyseg->charset;
 
239
 
 
240
                if (keyseg->null_bit) {
 
241
                        k_length--;
 
242
                        if (!(*key++ = (xtWord1) 1 - *old++)) {                                 /* Copy null marker */
 
243
                                k_length -= length;
 
244
                                if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
 
245
                                        k_length -= 2;                                                                  /* Skip length */
 
246
                                        old += 2;
 
247
                                }
 
248
                                continue;                                                                                       /* Found NULL */
 
249
                        }
 
250
                }
 
251
                char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
 
252
                pos = old;
 
253
                if (keyseg->flag & HA_SPACE_PACK) {
 
254
                        uchar *end = pos + length;
 
255
#ifndef DRIZZLED
 
256
                        if (type != HA_KEYTYPE_NUM) {
 
257
#endif
 
258
                                while (end > pos && end[-1] == ' ')
 
259
                                        end--;
 
260
#ifndef DRIZZLED
 
261
                        }
 
262
                        else {
 
263
                                while (pos < end && pos[0] == ' ')
 
264
                                        pos++;
 
265
                        }
 
266
#endif
 
267
                        k_length -= length;
 
268
                        length = (u_int) (end-pos);
 
269
                        FIX_LENGTH(cs, pos, length, char_length);
 
270
                        store_key_length_inc(key, char_length);
 
271
                        memcpy((byte*) key,pos,(size_t) char_length);
 
272
                        key += char_length;
 
273
                        continue;
 
274
                }
 
275
                if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
 
276
                        /* Length of key-part used with mi_rkey() always 2 */
 
277
                        u_int tmp_length = uint2korr(pos);
 
278
                        k_length -= 2 + length;
 
279
                        pos += 2;
 
280
                        set_if_smaller(length, tmp_length);     /* Safety */
 
281
                        FIX_LENGTH(cs, pos, length, char_length);
 
282
                        store_key_length_inc(key,char_length);
 
283
                        old +=2;                                        /* Skip length */
 
284
                        memcpy((char *) key, pos, (size_t) char_length);
 
285
                        key += char_length;
 
286
                        continue;
 
287
                }
 
288
                if (keyseg->flag & HA_SWAP_KEY)
 
289
                {                                               /* Numerical column */
 
290
                        pos+=length;
 
291
                        k_length-=length;
 
292
                        while (length--) {
 
293
                                *key++ = *--pos;
 
294
                        }
 
295
                        continue;
 
296
                }
 
297
                FIX_LENGTH(cs, pos, length, char_length);
 
298
                memcpy((byte*) key, pos, char_length);
 
299
                if (length > char_length)
 
300
                        cs->cset->fill(cs, (char *) (key + char_length), length - char_length, ' ');
 
301
                key += length;
 
302
                k_length -= length;
 
303
        }
 
304
 
 
305
        return (u_int) (key - start_key);
 
306
}
 
307
 
 
308
/* Derived from _mi_make_key */
 
309
xtPublic u_int myxt_create_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, xtBool *no_duplicate)
 
310
{
 
311
        register XTIndexSegRec  *keyseg = ind->mi_seg;
 
312
        xtWord1                                 *pos;
 
313
        xtWord1                                 *end;
 
314
        xtWord1                                 *start;
 
315
 
 
316
#ifdef HAVE_valgrind
 
317
       if (ind->mi_fix_key)
 
318
               memset((byte*) key, 0,(size_t) (ind->mi_key_size) );
 
319
#endif
 
320
 
 
321
#ifdef HAVE_valgrind
 
322
       if (ind->mi_fix_key)
 
323
               memset((byte*) key, 0,(size_t) (ind->mi_key_size) );
 
324
#endif
 
325
 
 
326
        start = key;
 
327
        for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++)
 
328
        {
 
329
#ifndef DRIZZLED
 
330
                enum ha_base_keytype    type = (enum ha_base_keytype) keyseg->type;
 
331
#endif
 
332
                u_int                                   length = keyseg->length;
 
333
                u_int                                   char_length;
 
334
                MX_CONST_CHARSET_INFO   *cs = keyseg->charset;
 
335
 
 
336
                if (keyseg->null_bit) {
 
337
                        if (record[keyseg->null_pos] & keyseg->null_bit) {
 
338
                                *key++ = 0;                             /* NULL in key */
 
339
                                
 
340
                                /* The point is, if a key contains a NULL value
 
341
                                 * the duplicate checking must be disabled.
 
342
                                 * This is because a NULL value is not considered
 
343
                                 * equal to any other value.
 
344
                                 */ 
 
345
                                if (no_duplicate)
 
346
                                        *no_duplicate = FALSE;
 
347
                                continue;
 
348
                        }
 
349
                        *key++ = 1;                                     /* Not NULL */
 
350
                }
 
351
 
 
352
                char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length);
 
353
 
 
354
                pos = record + keyseg->start;
 
355
#ifndef DRIZZLED
 
356
                if (type == HA_KEYTYPE_BIT)
 
357
                {
 
358
                        if (keyseg->bit_length)
 
359
                        {
 
360
                                uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos,
 
361
                                                                                                                                 keyseg->bit_start, keyseg->bit_length);
 
362
                                *key++ = bits;
 
363
                                length--;
 
364
                        }
 
365
                        memcpy((byte*) key, pos, length);
 
366
                        key+= length;
 
367
                        continue;
 
368
                }
 
369
#endif
 
370
                if (keyseg->flag & HA_SPACE_PACK)
 
371
                {
 
372
                        end = pos + length;
 
373
#ifndef DRIZZLED
 
374
                        if (type != HA_KEYTYPE_NUM) {
 
375
#endif
 
376
                                while (end > pos && end[-1] == ' ')
 
377
                                        end--;
 
378
#ifndef DRIZZLED
 
379
                        }
 
380
                        else {
 
381
                                while (pos < end && pos[0] == ' ')
 
382
                                        pos++;
 
383
                        }
 
384
#endif
 
385
                        length = (u_int) (end-pos);
 
386
                        FIX_LENGTH(cs, pos, length, char_length);
 
387
                        store_key_length_inc(key,char_length);
 
388
                        memcpy((byte*) key,(byte*) pos,(size_t) char_length);
 
389
                        key += char_length;
 
390
                        continue;
 
391
                }
 
392
                if (keyseg->flag & HA_VAR_LENGTH_PART) {
 
393
                        uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
 
394
                        uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
 
395
                                                                                                uint2korr(pos));
 
396
                        pos += pack_length;                     /* Skip VARCHAR length */
 
397
                        set_if_smaller(length,tmp_length);
 
398
                        FIX_LENGTH(cs, pos, length, char_length);
 
399
                        store_key_length_inc(key,char_length);
 
400
                        memcpy((byte*) key,(byte*) pos,(size_t) char_length);
 
401
                        key += char_length;
 
402
                        continue;
 
403
                }
 
404
                if (keyseg->flag & HA_BLOB_PART)
 
405
                {
 
406
                        u_int tmp_length = my_calc_blob_length(keyseg->bit_start, pos);
 
407
                        memcpy((byte*) &pos,pos+keyseg->bit_start,sizeof(char*));
 
408
                        set_if_smaller(length,tmp_length);
 
409
                        FIX_LENGTH(cs, pos, length, char_length);
 
410
                        store_key_length_inc(key,char_length);
 
411
                        memcpy((byte*) key,(byte*) pos,(size_t) char_length);
 
412
                        key+= char_length;
 
413
                        continue;
 
414
                }
 
415
                if (keyseg->flag & HA_SWAP_KEY)
 
416
                {                                               /* Numerical column */
 
417
#ifdef HAVE_ISNAN
 
418
#ifndef DRIZZLED
 
419
                        if (type == HA_KEYTYPE_FLOAT)
 
420
                        {
 
421
                                float nr;
 
422
                                float4get(nr,pos);
 
423
                                if (isnan(nr))
 
424
                                {
 
425
                                        /* Replace NAN with zero */
 
426
                                        bzero(key,length);
 
427
                                        key+=length;
 
428
                                        continue;
 
429
                                }
 
430
                        }
 
431
                        else 
 
432
#endif                  
 
433
                        if (type == HA_KEYTYPE_DOUBLE) {
 
434
                                double nr;
 
435
 
 
436
                                float8get(nr,pos);
 
437
                                if (isnan(nr)) {
 
438
                                        bzero(key,length);
 
439
                                        key+=length;
 
440
                                        continue;
 
441
                                }
 
442
                        }
 
443
#endif
 
444
                        pos+=length;
 
445
                        while (length--) {
 
446
                                *key++ = *--pos;
 
447
                        }
 
448
                        continue;
 
449
                }
 
450
                FIX_LENGTH(cs, pos, length, char_length);
 
451
                memcpy((byte*) key, pos, char_length);
 
452
                if (length > char_length)
 
453
                        cs->cset->fill(cs, (char *) key + char_length, length - char_length, ' ');
 
454
                key += length;
 
455
        }
 
456
 
 
457
        return ind->mi_fix_key ? ind->mi_key_size : (u_int) (key - start);              /* Return keylength */
 
458
}
 
459
 
 
460
xtPublic u_int myxt_create_foreign_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, XTIndexPtr fkey_ind, xtBool *no_null)
 
461
{
 
462
        register XTIndexSegRec  *keyseg = ind->mi_seg;
 
463
        register XTIndexSegRec  *fkey_keyseg = fkey_ind->mi_seg;
 
464
        xtWord1                                 *pos;
 
465
        xtWord1                                 *end;
 
466
        xtWord1                                 *start;
 
467
 
 
468
        start = key;
 
469
        for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++, fkey_keyseg++)
 
470
        {
 
471
#ifndef DRIZZLED
 
472
                enum ha_base_keytype    type = (enum ha_base_keytype) keyseg->type;
 
473
#endif
 
474
                u_int                                   length = keyseg->length;
 
475
                u_int                                   char_length;
 
476
                MX_CONST_CHARSET_INFO   *cs = keyseg->charset;
 
477
                xtBool                                  is_null = FALSE;
 
478
 
 
479
                if (keyseg->null_bit) {
 
480
                        if (record[keyseg->null_pos] & keyseg->null_bit) {
 
481
                                is_null = TRUE;
 
482
                                if (no_null)
 
483
                                        *no_null = FALSE;
 
484
                        }
 
485
                }
 
486
 
 
487
                if (fkey_keyseg->null_bit) {
 
488
                        if (is_null) {
 
489
                                *key++ = 0;                             /* NULL in key */
 
490
                                
 
491
                                /* The point is, if a key contains a NULL value
 
492
                                 * the duplicate checking must be disabled.
 
493
                                 * This is because a NULL value is not considered
 
494
                                 * equal to any other value.
 
495
                                 */ 
 
496
                                continue;
 
497
                        }
 
498
                        *key++ = 1;                                     /* Not NULL */
 
499
                }
 
500
 
 
501
                char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length);
 
502
 
 
503
                pos = record + keyseg->start;
 
504
#ifndef DRIZZLED
 
505
                if (type == HA_KEYTYPE_BIT)
 
506
                {
 
507
                        if (keyseg->bit_length)
 
508
                        {
 
509
                                uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos,
 
510
                                                                                                                                 keyseg->bit_start, keyseg->bit_length);
 
511
                                *key++ = bits;
 
512
                                length--;
 
513
                        }
 
514
                        memcpy((byte*) key, pos, length);
 
515
                        key+= length;
 
516
                        continue;
 
517
                }
 
518
#endif
 
519
                if (keyseg->flag & HA_SPACE_PACK)
 
520
                {
 
521
                        end = pos + length;
 
522
#ifndef DRIZZLED
 
523
                        if (type != HA_KEYTYPE_NUM) {
 
524
#endif
 
525
                                while (end > pos && end[-1] == ' ')
 
526
                                        end--;
 
527
#ifndef DRIZZLED
 
528
                        }
 
529
                        else {
 
530
                                while (pos < end && pos[0] == ' ')
 
531
                                        pos++;
 
532
                        }
 
533
#endif
 
534
                        length = (u_int) (end-pos);
 
535
                        FIX_LENGTH(cs, pos, length, char_length);
 
536
                        store_key_length_inc(key,char_length);
 
537
                        memcpy((byte*) key,(byte*) pos,(size_t) char_length);
 
538
                        key += char_length;
 
539
                        continue;
 
540
                }
 
541
                if (keyseg->flag & HA_VAR_LENGTH_PART) {
 
542
                        uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
 
543
                        uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
 
544
                                                                                                uint2korr(pos));
 
545
                        pos += pack_length;                     /* Skip VARCHAR length */
 
546
                        set_if_smaller(length,tmp_length);
 
547
                        FIX_LENGTH(cs, pos, length, char_length);
 
548
                        store_key_length_inc(key,char_length);
 
549
                        memcpy((byte*) key,(byte*) pos,(size_t) char_length);
 
550
                        key += char_length;
 
551
                        continue;
 
552
                }
 
553
                if (keyseg->flag & HA_BLOB_PART)
 
554
                {
 
555
                        u_int tmp_length = my_calc_blob_length(keyseg->bit_start, pos);
 
556
                        memcpy((byte*) &pos,pos+keyseg->bit_start,sizeof(char*));
 
557
                        set_if_smaller(length,tmp_length);
 
558
                        FIX_LENGTH(cs, pos, length, char_length);
 
559
                        store_key_length_inc(key,char_length);
 
560
                        memcpy((byte*) key,(byte*) pos,(size_t) char_length);
 
561
                        key+= char_length;
 
562
                        continue;
 
563
                }
 
564
                if (keyseg->flag & HA_SWAP_KEY)
 
565
                {                                               /* Numerical column */
 
566
#ifdef HAVE_ISNAN
 
567
#ifndef DRIZZLED
 
568
                        if (type == HA_KEYTYPE_FLOAT)
 
569
                        {
 
570
                                float nr;
 
571
                                float4get(nr,pos);
 
572
                                if (isnan(nr))
 
573
                                {
 
574
                                        /* Replace NAN with zero */
 
575
                                        bzero(key,length);
 
576
                                        key+=length;
 
577
                                        continue;
 
578
                                }
 
579
                        }
 
580
                        else 
 
581
#endif
 
582
                        if (type == HA_KEYTYPE_DOUBLE) {
 
583
                                double nr;
 
584
 
 
585
                                float8get(nr,pos);
 
586
                                if (isnan(nr)) {
 
587
                                        bzero(key,length);
 
588
                                        key+=length;
 
589
                                        continue;
 
590
                                }
 
591
                        }
 
592
#endif
 
593
                        pos+=length;
 
594
                        while (length--) {
 
595
                                *key++ = *--pos;
 
596
                        }
 
597
                        continue;
 
598
                }
 
599
                FIX_LENGTH(cs, pos, length, char_length);
 
600
                memcpy((byte*) key, pos, char_length);
 
601
                if (length > char_length)
 
602
                        cs->cset->fill(cs, (char *) key + char_length, length - char_length, ' ');
 
603
                key += length;
 
604
        }
 
605
 
 
606
        return (u_int) (key - start);
 
607
}
 
608
 
 
609
/* I may be overcautious here, but can I assume that
 
610
 * null_ptr refers to my buffer. If I cannot, then I
 
611
 * cannot use the set_notnull() method.
 
612
 */
 
613
static void mx_set_notnull_in_record(STRUCT_TABLE *table, Field *field, char *record)
 
614
{
 
615
        if (field->null_ptr)
 
616
                record[(uint) (field->null_ptr - (uchar *) table->getDefaultValues())] &= (uchar) ~field->null_bit;
 
617
}
 
618
 
 
619
static xtBool mx_is_null_in_record(STRUCT_TABLE *table, Field *field, char *record)
 
620
{
 
621
        if (field->null_ptr) {
 
622
                if (record[(uint) (field->null_ptr - (uchar *) table->getDefaultValues())] & (uchar) field->null_bit)
 
623
                        return TRUE;
 
624
        }
 
625
        return FALSE;
 
626
}
 
627
 
 
628
/*
 
629
 * PBXT uses a completely different disk format to MySQL so I need a
 
630
 * method that just returns the byte length and
 
631
 * pointer to the data in a row.
 
632
 */
 
633
static char *mx_get_length_and_data(STRUCT_TABLE *table, Field *field, char *dest, xtWord4 *len)
 
634
{
 
635
        char *from;
 
636
        
 
637
        from = dest + field->offset(table->getDefaultValues());
 
638
        switch (field->real_type()) {
 
639
#ifndef DRIZZLED
 
640
                case MYSQL_TYPE_TINY_BLOB:
 
641
                case MYSQL_TYPE_MEDIUM_BLOB:
 
642
                case MYSQL_TYPE_LONG_BLOB:
 
643
#endif
 
644
                case MYSQL_TYPE_BLOB: {
 
645
                        /* TODO - Check: this was the original comment: I must set
 
646
                         * *data to non-NULL value, *data == 0, means SQL NULL value.
 
647
                         */
 
648
                        char    *data;
 
649
 
 
650
                        /* GOTCHA: There is no way this can work! field is shared
 
651
                         * between threads.
 
652
                        char    *save = field->ptr;
 
653
 
 
654
                        field->ptr = (char *) from;
 
655
                        ((Field_blob *) field)->get_ptr(&data);
 
656
                        field->ptr = save;                                      // Restore org row pointer
 
657
                        */
 
658
 
 
659
                        xtWord4 packlength = ((Field_blob *) field)->pack_length_no_ptr();
 
660
 
 
661
                        memcpy(&data, ((char *) from)+packlength, sizeof(char*));
 
662
                        
 
663
                        //*len = ((Field_blob *) field)->get_length((byte *) from);
 
664
                        *len = ((Field_blob *) field)->get_length((byte *) from, packlength, GET_TABLE_SHARE(table)->db_low_byte_first);
 
665
                        return data;
 
666
                }
 
667
#ifndef DRIZZLED
 
668
                case MYSQL_TYPE_STRING:
 
669
                        /* To write this function you would think Field_string::pack
 
670
                         * would serve as a good example, but as far as I can tell
 
671
                         * it has a bug: the test from[length-1] == ' ' assumes
 
672
                         * 1-byte chars.
 
673
                         *
 
674
                         * But this is not relevant because I believe lengthsp
 
675
                         * will give me the correct answer!
 
676
                         */
 
677
                        *len = field->charset()->cset->lengthsp(field->charset(), from, field->field_length);
 
678
                        return from;
 
679
                case MYSQL_TYPE_VAR_STRING: {
 
680
                        uint length=uint2korr(from);
 
681
 
 
682
                        *len = length;
 
683
                        return from+HA_KEY_BLOB_LENGTH;
 
684
                }
 
685
#endif
 
686
                case MYSQL_TYPE_VARCHAR: {
 
687
                        uint length;
 
688
 
 
689
                        if (((Field_varstring *) field)->pack_length_no_ptr() == 1)
 
690
                                length = *((unsigned char *) from);
 
691
                        else
 
692
                                length = uint2korr(from);
 
693
                        
 
694
                        *len = length;
 
695
                        return from+((Field_varstring *) field)->pack_length_no_ptr();
 
696
                }
 
697
#ifndef DRIZZLED
 
698
                case MYSQL_TYPE_DECIMAL:
 
699
                case MYSQL_TYPE_TINY:
 
700
                case MYSQL_TYPE_SHORT:
 
701
                case MYSQL_TYPE_LONG:
 
702
                case MYSQL_TYPE_FLOAT:
 
703
                case MYSQL_TYPE_DOUBLE:
 
704
                case MYSQL_TYPE_NULL:
 
705
                case MYSQL_TYPE_TIMESTAMP:
 
706
                case MYSQL_TYPE_LONGLONG:
 
707
                case MYSQL_TYPE_INT24:
 
708
                case MYSQL_TYPE_DATE:
 
709
                case MYSQL_TYPE_TIME:
 
710
                case MYSQL_TYPE_DATETIME:
 
711
                case MYSQL_TYPE_YEAR:
 
712
                case MYSQL_TYPE_NEWDATE:
 
713
                case MYSQL_TYPE_BIT:
 
714
                case MYSQL_TYPE_NEWDECIMAL:
 
715
                case MYSQL_TYPE_ENUM:
 
716
                case MYSQL_TYPE_SET:
 
717
                case MYSQL_TYPE_GEOMETRY:
 
718
#else
 
719
                case DRIZZLE_TYPE_LONG:
 
720
                case DRIZZLE_TYPE_DOUBLE:
 
721
                case DRIZZLE_TYPE_NULL:
 
722
                case DRIZZLE_TYPE_TIMESTAMP:
 
723
                case DRIZZLE_TYPE_LONGLONG:
 
724
                case DRIZZLE_TYPE_DATETIME:
 
725
                case DRIZZLE_TYPE_DATE:
 
726
                case DRIZZLE_TYPE_DECIMAL:
 
727
                case DRIZZLE_TYPE_ENUM:
 
728
#endif
 
729
                        break;
 
730
        }
 
731
 
 
732
        *len = field->pack_length();
 
733
        return from;
 
734
}
 
735
 
 
736
/*
 
737
 * Set the length and data value of a field.
 
738
 * 
 
739
 * If input data is NULL this is a NULL value. In this case
 
740
 * we assume the null bit has been set and prepared
 
741
 * the field as follows:
 
742
 * 
 
743
 * According to the InnoDB implementation, we need
 
744
 * to zero out the field data...
 
745
 * "MySQL seems to assume the field for an SQL NULL
 
746
 * value is set to zero or space. Not taking this into
 
747
 * account caused seg faults with NULL BLOB fields, and
 
748
 * bug number 154 in the MySQL bug database: GROUP BY
 
749
 * and DISTINCT could treat NULL values inequal".
 
750
 */
 
751
static void mx_set_length_and_data(STRUCT_TABLE *table, Field *field, char *dest, xtWord4 len, char *data)
 
752
{
 
753
        char *from;
 
754
        
 
755
        from = dest + field->offset(table->getDefaultValues());
 
756
        switch (field->real_type()) {
 
757
#ifndef DRIZZLED
 
758
                case MYSQL_TYPE_TINY_BLOB:
 
759
                case MYSQL_TYPE_MEDIUM_BLOB:
 
760
                case MYSQL_TYPE_LONG_BLOB:
 
761
#endif
 
762
                case MYSQL_TYPE_BLOB: {
 
763
                        /* GOTCHA: There is no way that this can work.
 
764
                         * field is shared, because table is shared!
 
765
                        char *save = field->ptr;
 
766
                 
 
767
                        field->ptr = (char *) from;
 
768
                        ((Field_blob *) field)->set_ptr(len, data);
 
769
                        field->ptr = save;                                      // Restore org row pointer
 
770
                        */
 
771
                        xtWord4 packlength = ((Field_blob *) field)->pack_length_no_ptr();
 
772
 
 
773
                        ((Field_blob *) field)->store_length((byte *) from, packlength, len, GET_TABLE_SHARE(table)->db_low_byte_first);
 
774
                        memcpy_fixed(((char *) from)+packlength, &data, sizeof(char*));
 
775
 
 
776
                        if (data)
 
777
                                mx_set_notnull_in_record(table, field, dest);
 
778
                        return;
 
779
                }
 
780
#ifndef DRIZZLED
 
781
                case MYSQL_TYPE_STRING:
 
782
                        if (data) {
 
783
                                mx_set_notnull_in_record(field, dest);
 
784
                                memcpy(from, data, len);
 
785
                        }
 
786
                        else
 
787
                                len = 0;
 
788
 
 
789
                        /* And I think that fill will do this for me... */
 
790
                        field->charset()->cset->fill(field->charset(), from + len, field->field_length - len, ' ');
 
791
                        return;
 
792
                case MYSQL_TYPE_VAR_STRING:
 
793
                        int2store(from, len);
 
794
                        if (data) {
 
795
                                mx_set_notnull_in_record(field, dest);
 
796
                                memcpy(from+HA_KEY_BLOB_LENGTH, data, len);
 
797
                        }
 
798
                        return;
 
799
#endif
 
800
                case MYSQL_TYPE_VARCHAR:
 
801
                        if (((Field_varstring *) field)->pack_length_no_ptr() == 1)
 
802
                                *((unsigned char *) from) = (unsigned char) len;
 
803
                        else
 
804
                                int2store(from, len);
 
805
                        if (data) {
 
806
                                mx_set_notnull_in_record(table, field, dest);
 
807
                                memcpy(from+((Field_varstring *) field)->pack_length_no_ptr(), data, len);
 
808
                        }
 
809
                        return;
 
810
#ifndef DRIZZLED
 
811
                case MYSQL_TYPE_DECIMAL:
 
812
                case MYSQL_TYPE_TINY:
 
813
                case MYSQL_TYPE_SHORT:
 
814
                case MYSQL_TYPE_LONG:
 
815
                case MYSQL_TYPE_FLOAT:
 
816
                case MYSQL_TYPE_DOUBLE:
 
817
                case MYSQL_TYPE_NULL:
 
818
                case MYSQL_TYPE_TIMESTAMP:
 
819
                case MYSQL_TYPE_LONGLONG:
 
820
                case MYSQL_TYPE_INT24:
 
821
                case MYSQL_TYPE_DATE:
 
822
                case MYSQL_TYPE_TIME:
 
823
                case MYSQL_TYPE_DATETIME:
 
824
                case MYSQL_TYPE_YEAR:
 
825
                case MYSQL_TYPE_NEWDATE:
 
826
                case MYSQL_TYPE_BIT:
 
827
                case MYSQL_TYPE_NEWDECIMAL:
 
828
                case MYSQL_TYPE_ENUM:
 
829
                case MYSQL_TYPE_SET:
 
830
                case MYSQL_TYPE_GEOMETRY:
 
831
#else
 
832
                case DRIZZLE_TYPE_LONG:
 
833
                case DRIZZLE_TYPE_DOUBLE:
 
834
                case DRIZZLE_TYPE_NULL:
 
835
                case DRIZZLE_TYPE_TIMESTAMP:
 
836
                case DRIZZLE_TYPE_LONGLONG:
 
837
                case DRIZZLE_TYPE_DATETIME:
 
838
                case DRIZZLE_TYPE_DATE:
 
839
                case DRIZZLE_TYPE_DECIMAL:
 
840
                case DRIZZLE_TYPE_ENUM:
 
841
#endif
 
842
                        break;
 
843
        }
 
844
 
 
845
        if (data) {
 
846
                mx_set_notnull_in_record(table, field, dest);
 
847
                memcpy(from, data, len);
 
848
        }
 
849
        else
 
850
                bzero(from, field->pack_length());
 
851
}
 
852
 
 
853
xtPublic void myxt_set_null_row_from_key(XTOpenTablePtr XT_UNUSED(ot), XTIndexPtr ind, xtWord1 *record)
 
854
{
 
855
        register XTIndexSegRec *keyseg = ind->mi_seg;
 
856
 
 
857
        for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
 
858
                ASSERT_NS(keyseg->null_bit);
 
859
                record[keyseg->null_pos] |= keyseg->null_bit;
 
860
        }
 
861
}
 
862
 
 
863
xtPublic void myxt_set_default_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *record)
 
864
{
 
865
        XTTableHPtr             tab = ot->ot_table;
 
866
        STRUCT_TABLE    *table = tab->tab_dic.dic_my_table;
 
867
        XTIndexSegRec   *keyseg = ind->mi_seg;
 
868
 
 
869
        xt_lock_mutex_ns(&tab->tab_dic_field_lock);
 
870
 
 
871
        for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
 
872
                
 
873
                u_int col_idx = keyseg->col_idx;
 
874
                Field *field = GET_TABLE_FIELDS(table)[col_idx];
 
875
                byte  *field_save = field->ptr;
 
876
 
 
877
                field->ptr = GET_TABLE_SHARE(table)->getDefaultValues() + keyseg->start;
 
878
                memcpy(record + keyseg->start, field->ptr, field->pack_length());
 
879
                record[keyseg->null_pos] &= ~keyseg->null_bit;
 
880
                record[keyseg->null_pos] |= GET_TABLE_SHARE(table)->getDefaultValues()[keyseg->null_pos] & keyseg->null_bit;
 
881
 
 
882
                field->ptr = field_save;
 
883
        }
 
884
 
 
885
        xt_unlock_mutex_ns(&tab->tab_dic_field_lock);
 
886
}
 
887
 
 
888
/* Derived from _mi_put_key_in_record */
 
889
xtPublic xtBool myxt_create_row_from_key(XTOpenTablePtr XT_UNUSED(ot), XTIndexPtr ind, xtWord1 *b_value, u_int key_len, xtWord1 *dest_buff)
 
890
{
 
891
        byte                                    *record = (byte *) dest_buff;
 
892
        register byte                   *key;
 
893
        byte                                    *pos,*key_end;
 
894
        register XTIndexSegRec  *keyseg = ind->mi_seg;
 
895
 
 
896
        /* GOTCHA: When selecting from multiple
 
897
         * indexes the key values are "merged" into the
 
898
         * same buffer!!
 
899
         * This means that this function must not affect
 
900
         * the value of any other feilds.
 
901
         *
 
902
         * I was setting all to NULL:
 
903
        memset(dest_buff, 0xFF, GET_TABLE_SHARE(table)->null_bytes);
 
904
        */
 
905
        key = (byte *) b_value;
 
906
        key_end = key + key_len;
 
907
        for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
 
908
                if (keyseg->null_bit) {
 
909
                        if (!*key++)
 
910
                        {
 
911
                                record[keyseg->null_pos] |= keyseg->null_bit;
 
912
                                continue;
 
913
                        }
 
914
                        record[keyseg->null_pos] &= ~keyseg->null_bit;
 
915
                }
 
916
#ifndef DRIZZLED
 
917
                if (keyseg->type == HA_KEYTYPE_BIT)
 
918
                {
 
919
                        uint length = keyseg->length;
 
920
 
 
921
                        if (keyseg->bit_length)
 
922
                        {
 
923
                                uchar bits= *key++;
 
924
                                set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
 
925
                                                                                 keyseg->bit_length);
 
926
                                length--;
 
927
                        }
 
928
                        else
 
929
                        {
 
930
                                clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
 
931
                                                                                 keyseg->bit_length);
 
932
                        }
 
933
                        memcpy(record + keyseg->start, (byte*) key, length);
 
934
                        key+= length;
 
935
                        continue;
 
936
                }
 
937
#endif
 
938
                if (keyseg->flag & HA_SPACE_PACK)
 
939
                {
 
940
                        uint length;
 
941
                        get_key_length(length,key);
 
942
#ifdef CHECK_KEYS
 
943
                        if (length > keyseg->length || key+length > key_end)
 
944
                                goto err;
 
945
#endif
 
946
                        pos = record+keyseg->start;
 
947
#ifndef DRIZZLED
 
948
                        if (keyseg->type != (int) HA_KEYTYPE_NUM)
 
949
                        {
 
950
#endif
 
951
                                memcpy(pos,key,(size_t) length);
 
952
                                bfill(pos+length,keyseg->length-length,' ');
 
953
#ifndef DRIZZLED
 
954
                        }
 
955
                        else
 
956
                        {
 
957
                                bfill(pos,keyseg->length-length,' ');
 
958
                                memcpy(pos+keyseg->length-length,key,(size_t) length);
 
959
                        }
 
960
#endif
 
961
                        key+=length;
 
962
                        continue;
 
963
                }
 
964
 
 
965
                if (keyseg->flag & HA_VAR_LENGTH_PART)
 
966
                {
 
967
                        uint length;
 
968
                        get_key_length(length,key);
 
969
#ifdef CHECK_KEYS
 
970
                        if (length > keyseg->length || key+length > key_end)
 
971
        goto err;
 
972
#endif
 
973
                        /* Store key length */
 
974
                        if (keyseg->bit_start == 1)
 
975
                                *(uchar*) (record+keyseg->start)= (uchar) length;
 
976
                        else
 
977
                                int2store(record+keyseg->start, length);
 
978
                        /* And key data */
 
979
                        memcpy(record+keyseg->start + keyseg->bit_start, (byte*) key, length);
 
980
                        key+= length;
 
981
                }
 
982
                else if (keyseg->flag & HA_BLOB_PART)
 
983
                {
 
984
                        uint length;
 
985
                        get_key_length(length,key);
 
986
#ifdef CHECK_KEYS
 
987
                        if (length > keyseg->length || key+length > key_end)
 
988
                                goto err;
 
989
#endif
 
990
                        /* key is a pointer into ot_ind_rbuf, which should be
 
991
                         * safe until we move to the next index item!
 
992
                         */
 
993
                        byte *key_ptr = key; // Cannot take the address of a register variable!
 
994
                        memcpy(record+keyseg->start+keyseg->bit_start,
 
995
                         (char*) &key_ptr,sizeof(char*));
 
996
 
 
997
                        my_store_blob_length(record+keyseg->start,
 
998
                                        (uint) keyseg->bit_start,length);
 
999
                        key+=length;
 
1000
                }
 
1001
                else if (keyseg->flag & HA_SWAP_KEY)
 
1002
                {
 
1003
                        byte *to=       record+keyseg->start+keyseg->length;
 
1004
                        byte *end= key+keyseg->length;
 
1005
#ifdef CHECK_KEYS
 
1006
                        if (end > key_end)
 
1007
                                goto err;
 
1008
#endif
 
1009
                        do {
 
1010
                                *--to= *key++;
 
1011
                        } while (key != end);
 
1012
                        continue;
 
1013
                }
 
1014
                else
 
1015
                {
 
1016
#ifdef CHECK_KEYS
 
1017
                        if (key+keyseg->length > key_end)
 
1018
                                goto err;
 
1019
#endif
 
1020
                        memcpy(record+keyseg->start,(byte*) key,
 
1021
                         (size_t) keyseg->length);
 
1022
                        key+= keyseg->length;
 
1023
                }
 
1024
        
 
1025
        }
 
1026
        return OK;
 
1027
 
 
1028
#ifdef CHECK_KEYS
 
1029
        err:
 
1030
        return FAILED;                          /* Crashed row */
 
1031
#endif
 
1032
}
 
1033
 
 
1034
/*
 
1035
 * -----------------------------------------------------------------------
 
1036
 * Compare keys
 
1037
 */
 
1038
 
 
1039
static int my_compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
 
1040
                                                                                         my_bool part_key, my_bool skip_end_space)
 
1041
{
 
1042
        uint length= a_length < b_length ? a_length : b_length;
 
1043
        uchar *end= a+ length;
 
1044
        int flag;
 
1045
 
 
1046
        while (a < end)
 
1047
                if ((flag= (int) *a++ - (int) *b++))
 
1048
                        return flag;
 
1049
        if (part_key && b_length < a_length)
 
1050
                return 0;
 
1051
        if (skip_end_space && a_length != b_length)
 
1052
        {
 
1053
                int swap= 1;
 
1054
                /*
 
1055
                        We are using space compression. We have to check if longer key
 
1056
                        has next character < ' ', in which case it's less than the shorter
 
1057
                        key that has an implicite space afterwards.
 
1058
 
 
1059
                        This code is identical to the one in
 
1060
                        strings/ctype-simple.c:my_strnncollsp_simple
 
1061
                */
 
1062
                if (a_length < b_length)
 
1063
                {
 
1064
                        /* put shorter key in a */
 
1065
                        a_length= b_length;
 
1066
                        a= b;
 
1067
                        swap= -1;                                       /* swap sign of result */
 
1068
                }
 
1069
                for (end= a + a_length-length; a < end ; a++)
 
1070
                {
 
1071
                        if (*a != ' ')
 
1072
                                return (*a < ' ') ? -swap : swap;
 
1073
                }
 
1074
                return 0;
 
1075
        }
 
1076
        return (int) (a_length-b_length);
 
1077
}
 
1078
 
 
1079
xtPublic u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *key_buf)
 
1080
{
 
1081
        register XTIndexSegRec  *keyseg = ind->mi_seg;
 
1082
        register uchar                  *key_data = (uchar *) key_buf;
 
1083
        uint                                    seg_len;
 
1084
        uint                                    pack_len;
 
1085
 
 
1086
        for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
 
1087
                /* Handle NULL part */
 
1088
                if (keyseg->null_bit) {
 
1089
                        if (!*key_data++)       
 
1090
                                continue;
 
1091
                }
 
1092
 
 
1093
                switch ((enum ha_base_keytype) keyseg->type) {
 
1094
                        case HA_KEYTYPE_TEXT:                                                                                    /* Ascii; Key is converted */
 
1095
                                if (keyseg->flag & HA_SPACE_PACK) {
 
1096
                                        get_key_pack_length(seg_len, pack_len, key_data);
 
1097
                                }
 
1098
                                else
 
1099
                                        seg_len = keyseg->length;
 
1100
                                key_data += seg_len;
 
1101
                                break;
 
1102
                        case HA_KEYTYPE_BINARY:
 
1103
                                if (keyseg->flag & HA_SPACE_PACK) {
 
1104
                                        get_key_pack_length(seg_len, pack_len, key_data);
 
1105
                                }
 
1106
                                else
 
1107
                                        seg_len = keyseg->length;
 
1108
                                key_data += seg_len;
 
1109
                                break;
 
1110
                        case HA_KEYTYPE_VARTEXT1:
 
1111
                        case HA_KEYTYPE_VARTEXT2:
 
1112
                                get_key_pack_length(seg_len, pack_len, key_data);
 
1113
                                key_data += seg_len;
 
1114
                                break;
 
1115
                        case HA_KEYTYPE_VARBINARY1:
 
1116
                        case HA_KEYTYPE_VARBINARY2:
 
1117
                                get_key_pack_length(seg_len, pack_len, key_data);
 
1118
                                key_data += seg_len;
 
1119
                                break;
 
1120
#ifndef DRIZZLED
 
1121
                        case HA_KEYTYPE_NUM: {
 
1122
                                /* Numeric key */
 
1123
                                if (keyseg->flag & HA_SPACE_PACK)
 
1124
                                        seg_len = *key_data++;
 
1125
                                else
 
1126
                                        seg_len = keyseg->length;
 
1127
                                key_data += seg_len;
 
1128
                                break;
 
1129
                        }
 
1130
                        case HA_KEYTYPE_INT8:
 
1131
                        case HA_KEYTYPE_SHORT_INT:
 
1132
                        case HA_KEYTYPE_USHORT_INT:
 
1133
                        case HA_KEYTYPE_INT24:
 
1134
                        case HA_KEYTYPE_FLOAT:
 
1135
                        case HA_KEYTYPE_BIT:
 
1136
#endif
 
1137
                        case HA_KEYTYPE_LONG_INT:
 
1138
                        case HA_KEYTYPE_ULONG_INT:
 
1139
                        case HA_KEYTYPE_DOUBLE:
 
1140
                        case HA_KEYTYPE_LONGLONG:
 
1141
                        case HA_KEYTYPE_ULONGLONG:
 
1142
                                key_data += keyseg->length;
 
1143
                                break;
 
1144
                        case HA_KEYTYPE_END:
 
1145
                                goto end;
 
1146
                }
 
1147
        }
 
1148
 
 
1149
        end:
 
1150
        u_int ilen = (xtWord1 *) key_data - key_buf;
 
1151
        if (ilen > XT_INDEX_MAX_KEY_SIZE)
 
1152
                ind->mi_key_corrupted = TRUE;
 
1153
        return ilen;
 
1154
}
 
1155
 
 
1156
/* Derived from ha_key_cmp */
 
1157
xtPublic int myxt_compare_key(XTIndexPtr ind, int search_flags, uint key_length, xtWord1 *key_value, xtWord1 *b_value)
 
1158
{
 
1159
        register XTIndexSegRec  *keyseg = ind->mi_seg;
 
1160
        int                                             flag;
 
1161
        register uchar                  *a = (uchar *) key_value;
 
1162
        uint                                    a_length;
 
1163
        register uchar                  *b = (uchar *) b_value;
 
1164
        uint                                    b_length;
 
1165
        uint                                    next_key_length;
 
1166
        uchar                                   *end;
 
1167
        uint                                    piks;
 
1168
        uint                                    pack_len;
 
1169
 
 
1170
        for (uint i=0; i < ind->mi_seg_count && (int) key_length > 0; key_length = next_key_length, keyseg++, i++) {
 
1171
                piks = !(keyseg->flag & HA_NO_SORT);
 
1172
 
 
1173
                /* Handle NULL part */
 
1174
                if (keyseg->null_bit) {
 
1175
                        /* 1 is not null, 0 is null */
 
1176
                        int b_not_null = (int) *b++;
 
1177
 
 
1178
                        key_length--;
 
1179
                        if ((int) *a != b_not_null && piks)
 
1180
                        {
 
1181
                                flag = (int) *a - b_not_null;
 
1182
                                return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1183
                        }
 
1184
                        if (!*a++) {            
 
1185
                                /* If key was NULL */
 
1186
                                if (search_flags == (SEARCH_FIND | SEARCH_UPDATE))
 
1187
                                        search_flags = SEARCH_SAME;                                                              /* Allow duplicate keys */
 
1188
                                else if (search_flags & SEARCH_NULL_ARE_NOT_EQUAL)
 
1189
                                {
 
1190
                                        /*
 
1191
                                         * This is only used from mi_check() to calculate cardinality.
 
1192
                                         * It can't be used when searching for a key as this would cause
 
1193
                                         * compare of (a,b) and (b,a) to return the same value.
 
1194
                                         */
 
1195
                                        return -1;
 
1196
                                }
 
1197
                                /* PMC - I don't know why I had next_key_length = key_length - keyseg->length;
 
1198
                                 * This was my comment: even when null we have the complete length
 
1199
                                 *
 
1200
                                 * The truth is, a NULL only takes up one byte in the key, and this has already
 
1201
                                 * been subtracted.
 
1202
                                 */
 
1203
                                next_key_length = key_length;
 
1204
                                continue;                                                                                                                        /* To next key part */
 
1205
                        }
 
1206
                }
 
1207
                
 
1208
                /* Both components are not null... */
 
1209
                if (keyseg->length < key_length) {
 
1210
                        end = a + keyseg->length;
 
1211
                        next_key_length = key_length - keyseg->length;
 
1212
                }
 
1213
                else {
 
1214
                        end = a + key_length;
 
1215
                        next_key_length = 0;
 
1216
                }
 
1217
 
 
1218
                switch ((enum ha_base_keytype) keyseg->type) {
 
1219
                        case HA_KEYTYPE_TEXT:                                                                                    /* Ascii; Key is converted */
 
1220
                                if (keyseg->flag & HA_SPACE_PACK) {
 
1221
                                        get_key_pack_length(a_length, pack_len, a);
 
1222
                                        next_key_length = key_length - a_length - pack_len;
 
1223
                                        get_key_pack_length(b_length, pack_len, b);
 
1224
 
 
1225
                                        if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length,
 
1226
                                                                        (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0),
 
1227
                                                                        (my_bool)!(search_flags & SEARCH_PREFIX))))
 
1228
                                                return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1229
                                        a += a_length;
 
1230
                                }
 
1231
                                else {
 
1232
                                        a_length = (uint) (end - a);
 
1233
                                        b_length = keyseg->length;
 
1234
                                        if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length,
 
1235
                                                                        (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0),
 
1236
                                                                        (my_bool)!(search_flags & SEARCH_PREFIX))))
 
1237
                                                return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1238
                                        a = end;
 
1239
                                }
 
1240
                                b += b_length;
 
1241
                                break;
 
1242
                        case HA_KEYTYPE_BINARY:
 
1243
                                if (keyseg->flag & HA_SPACE_PACK) {
 
1244
                                        get_key_pack_length(a_length, pack_len, a);
 
1245
                                        next_key_length = key_length - a_length - pack_len;
 
1246
                                        get_key_pack_length(b_length, pack_len, b);
 
1247
 
 
1248
                                        if (piks && (flag = my_compare_bin(a, a_length, b, b_length,
 
1249
                                                                (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 1)))
 
1250
                                                return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1251
                                }
 
1252
                                else {
 
1253
                                        a_length = keyseg->length;
 
1254
                                        b_length = keyseg->length;
 
1255
                                        if (piks && (flag = my_compare_bin(a, a_length, b, b_length,
 
1256
                                                                        (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 0)))
 
1257
                                                return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1258
                                }
 
1259
                                a += a_length;
 
1260
                                b += b_length;
 
1261
                                break;
 
1262
                        case HA_KEYTYPE_VARTEXT1:
 
1263
                        case HA_KEYTYPE_VARTEXT2:
 
1264
                        {
 
1265
                                get_key_pack_length(a_length, pack_len, a);
 
1266
                                next_key_length = key_length - a_length - pack_len;
 
1267
                                get_key_pack_length(b_length, pack_len, b);
 
1268
 
 
1269
                                if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length,
 
1270
                                                                (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0),
 
1271
                                                                (my_bool) ((search_flags & (SEARCH_FIND | SEARCH_UPDATE)) == SEARCH_FIND))))
 
1272
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1273
                                a += a_length;
 
1274
                                b += b_length;
 
1275
                                break;
 
1276
                        }
 
1277
                        case HA_KEYTYPE_VARBINARY1:
 
1278
                        case HA_KEYTYPE_VARBINARY2:
 
1279
                        {                               
 
1280
                                get_key_pack_length(a_length, pack_len, a);
 
1281
                                next_key_length = key_length - a_length - pack_len;
 
1282
                                get_key_pack_length(b_length, pack_len, b);
 
1283
 
 
1284
                                if (piks && (flag=my_compare_bin(a, a_length, b, b_length,
 
1285
                                                (my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 0)))
 
1286
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1287
                                a += a_length;
 
1288
                                b += b_length;
 
1289
                                break;
 
1290
                        }
 
1291
#ifndef DRIZZLED
 
1292
                        case HA_KEYTYPE_INT8:
 
1293
                        {
 
1294
                                int i_1 = (int) *((signed char *) a);
 
1295
                                int i_2 = (int) *((signed char *) b);
 
1296
                                if (piks && (flag = CMP_NUM(i_1,i_2)))
 
1297
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1298
                                a = end;
 
1299
                                b += keyseg->length;
 
1300
                                break;
 
1301
                        }
 
1302
                        case HA_KEYTYPE_SHORT_INT: {
 
1303
                                int16_t s_1 = sint2korr(a);
 
1304
                                int16_t s_2 = sint2korr(b);
 
1305
                                if (piks && (flag = CMP_NUM(s_1, s_2)))
 
1306
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1307
                                a = end;
 
1308
                                b += keyseg->length;
 
1309
                                break;
 
1310
                        }
 
1311
                        case HA_KEYTYPE_USHORT_INT: {
 
1312
                                uint16_t us_1= sint2korr(a);
 
1313
                                uint16_t us_2= sint2korr(b);
 
1314
                                if (piks && (flag = CMP_NUM(us_1, us_2)))
 
1315
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1316
                                a =     end;
 
1317
                                b += keyseg->length;
 
1318
                                break;
 
1319
                        }
 
1320
#endif
 
1321
                        case HA_KEYTYPE_LONG_INT: {
 
1322
                                int32_t l_1 = sint4korr(a);
 
1323
                                int32_t l_2 = sint4korr(b);
 
1324
                                if (piks && (flag = CMP_NUM(l_1, l_2)))
 
1325
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1326
                                a = end;
 
1327
                                b += keyseg->length;
 
1328
                                break;
 
1329
                        }
 
1330
                        case HA_KEYTYPE_ULONG_INT: {
 
1331
                                uint32_t u_1 = sint4korr(a);
 
1332
                                uint32_t u_2 = sint4korr(b);
 
1333
                                if (piks && (flag = CMP_NUM(u_1, u_2)))
 
1334
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1335
                                a = end;
 
1336
                                b += keyseg->length;
 
1337
                                break;
 
1338
                        }
 
1339
#ifndef DRIZZLED
 
1340
                        case HA_KEYTYPE_INT24: {
 
1341
                                int32 l_1 = sint3korr(a);
 
1342
                                int32 l_2 = sint3korr(b);
 
1343
                                if (piks && (flag = CMP_NUM(l_1, l_2)))
 
1344
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1345
                                a = end;
 
1346
                                b += keyseg->length;
 
1347
                                break;
 
1348
                        }
 
1349
                        case HA_KEYTYPE_UINT24: {
 
1350
                                int32_t l_1 = uint3korr(a);
 
1351
                                int32_t l_2 = uint3korr(b);
 
1352
                                if (piks && (flag = CMP_NUM(l_1, l_2)))
 
1353
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1354
                                a = end;
 
1355
                                b += keyseg->length;
 
1356
                                break;
 
1357
                        }
 
1358
                        case HA_KEYTYPE_FLOAT: {
 
1359
                                float f_1, f_2;
 
1360
 
 
1361
                                float4get(f_1, a);
 
1362
                                float4get(f_2, b);
 
1363
                                /*
 
1364
                                 * The following may give a compiler warning about floating point
 
1365
                                 * comparison not being safe, but this is ok in this context as
 
1366
                                 * we are bascily doing sorting
 
1367
                                 */
 
1368
                                if (piks && (flag = CMP_NUM(f_1, f_2)))
 
1369
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1370
                                a = end;
 
1371
                                b += keyseg->length;
 
1372
                                break;
 
1373
                        }
 
1374
#endif
 
1375
                        case HA_KEYTYPE_DOUBLE: {
 
1376
                                double d_1, d_2;
 
1377
 
 
1378
                                float8get(d_1, a);
 
1379
                                float8get(d_2, b);
 
1380
                                /*
 
1381
                                 * The following may give a compiler warning about floating point
 
1382
                                 * comparison not being safe, but this is ok in this context as
 
1383
                                 * we are bascily doing sorting
 
1384
                                 */
 
1385
                                if (piks && (flag = CMP_NUM(d_1, d_2)))
 
1386
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1387
                                a = end;
 
1388
                                b += keyseg->length;
 
1389
                                break;
 
1390
                        }
 
1391
#ifndef DRIZZLED
 
1392
                        case HA_KEYTYPE_NUM: {
 
1393
                                /* Numeric key */
 
1394
                                if (keyseg->flag & HA_SPACE_PACK) {
 
1395
                                        a_length = *a++;
 
1396
                                        end = a + a_length;
 
1397
                                        next_key_length = key_length - a_length - 1;
 
1398
                                        b_length = *b++;
 
1399
                                }
 
1400
                                else {
 
1401
                                        a_length = (int) (end - a);
 
1402
                                        b_length = keyseg->length;
 
1403
                                }
 
1404
 
 
1405
                                /* remove pre space from keys */
 
1406
                                for ( ; a_length && *a == ' ' ; a++, a_length--) ;
 
1407
                                for ( ; b_length && *b == ' ' ; b++, b_length--) ;
 
1408
 
 
1409
                                if (keyseg->flag & HA_REVERSE_SORT) {
 
1410
                                        swap_variables(uchar *, a, b);
 
1411
                                        swap_variables(uint, a_length, b_length);
 
1412
                                }
 
1413
                                
 
1414
                                if (piks) {
 
1415
                                        if (*a == '-') {
 
1416
                                                if (*b != '-')
 
1417
                                                        return -1;
 
1418
                                                a++; b++;
 
1419
                                                swap_variables(uchar *, a, b);
 
1420
                                                swap_variables(uint, a_length, b_length);
 
1421
                                                a_length--; b_length--;
 
1422
                                        }
 
1423
                                        else if (*b == '-')
 
1424
                                                return 1;
 
1425
                                        while (a_length && (*a == '+' || *a == '0')) {
 
1426
                                                a++; a_length--;
 
1427
                                        }
 
1428
                                        
 
1429
                                        while (b_length && (*b == '+' || *b == '0')) {
 
1430
                                                b++; b_length--;
 
1431
                                        }
 
1432
                                
 
1433
                                        if (a_length != b_length)
 
1434
                                                return (a_length < b_length) ? -1 : 1;
 
1435
                                        while (b_length) {
 
1436
                                                if (*a++ !=     *b++)
 
1437
                                                        return ((int) a[-1] - (int) b[-1]);
 
1438
                                                b_length--;
 
1439
                                        }
 
1440
                                }
 
1441
                                a = end;
 
1442
                                b += b_length;
 
1443
                                break;
 
1444
                        }
 
1445
#endif
 
1446
#ifdef HAVE_LONG_LONG
 
1447
                        case HA_KEYTYPE_LONGLONG: {
 
1448
                                longlong ll_a = sint8korr(a);
 
1449
                                longlong ll_b = sint8korr(b);
 
1450
                                if (piks && (flag = CMP_NUM(ll_a,ll_b)))
 
1451
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1452
                                a = end;
 
1453
                                b += keyseg->length;
 
1454
                                break;
 
1455
                        }
 
1456
                        case HA_KEYTYPE_ULONGLONG: {                                    
 
1457
                                ulonglong ll_a = uint8korr(a);
 
1458
                                ulonglong ll_b = uint8korr(b);
 
1459
                                if (piks && (flag = CMP_NUM(ll_a,ll_b)))
 
1460
                                        return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
 
1461
                                a = end;
 
1462
                                b += keyseg->length;
 
1463
                                break;
 
1464
                        }
 
1465
#endif
 
1466
#ifndef DRIZZLED
 
1467
                        case HA_KEYTYPE_BIT:
 
1468
                                /* TODO: What here? */
 
1469
                                break;
 
1470
#endif
 
1471
                        case HA_KEYTYPE_END:                                                                                            /* Ready */
 
1472
                                goto end;
 
1473
                }
 
1474
        }
 
1475
 
 
1476
        end:
 
1477
        return 0;
 
1478
}
 
1479
 
 
1480
xtPublic u_int myxt_key_seg_length(XTIndexSegRec *keyseg, u_int key_offset, xtWord1 *key_value)
 
1481
{
 
1482
        register xtWord1        *a = (xtWord1 *) key_value + key_offset;
 
1483
        u_int                           a_length;
 
1484
        u_int                           has_null = 0;
 
1485
        u_int                           key_length = 0;
 
1486
        u_int                           pack_len;
 
1487
 
 
1488
        /* Handle NULL part */
 
1489
        if (keyseg->null_bit) {
 
1490
                has_null++;
 
1491
                /* If the value is null, then it only requires one byte: */
 
1492
                if (!*a++)
 
1493
                        return has_null;
 
1494
        }
 
1495
        
 
1496
        key_length = has_null + keyseg->length;
 
1497
 
 
1498
        switch ((enum ha_base_keytype) keyseg->type) {
 
1499
                case HA_KEYTYPE_TEXT:                                                                                    /* Ascii; Key is converted */
 
1500
                        if (keyseg->flag & HA_SPACE_PACK) {
 
1501
                                get_key_pack_length(a_length, pack_len, a);
 
1502
                                key_length = has_null + a_length + pack_len;
 
1503
                        }
 
1504
                        break;
 
1505
                case HA_KEYTYPE_BINARY:
 
1506
                        if (keyseg->flag & HA_SPACE_PACK) {
 
1507
                                get_key_pack_length(a_length, pack_len, a);
 
1508
                                key_length = has_null + a_length + pack_len;
 
1509
                        }
 
1510
                        break;
 
1511
                case HA_KEYTYPE_VARTEXT1:
 
1512
                case HA_KEYTYPE_VARTEXT2:
 
1513
                case HA_KEYTYPE_VARBINARY1:
 
1514
                case HA_KEYTYPE_VARBINARY2: {                           
 
1515
                        get_key_pack_length(a_length, pack_len, a);
 
1516
                        key_length = has_null + a_length + pack_len;
 
1517
                        break;
 
1518
                }
 
1519
#ifndef DRIZZLED
 
1520
                case HA_KEYTYPE_INT8:
 
1521
                case HA_KEYTYPE_SHORT_INT:
 
1522
                case HA_KEYTYPE_USHORT_INT:
 
1523
                case HA_KEYTYPE_INT24:
 
1524
                case HA_KEYTYPE_FLOAT:
 
1525
                case HA_KEYTYPE_UINT24:
 
1526
#endif          
 
1527
                case HA_KEYTYPE_LONG_INT:
 
1528
                case HA_KEYTYPE_ULONG_INT:
 
1529
                case HA_KEYTYPE_DOUBLE:
 
1530
                        break;
 
1531
#ifndef DRIZZLED
 
1532
                case HA_KEYTYPE_NUM: {
 
1533
                        /* Numeric key */
 
1534
                        if (keyseg->flag & HA_SPACE_PACK) {
 
1535
                                a_length = *a++;
 
1536
                                key_length = has_null + a_length + 1;
 
1537
                        }
 
1538
                        break;
 
1539
                }
 
1540
#endif
 
1541
#ifdef HAVE_LONG_LONG
 
1542
                case HA_KEYTYPE_LONGLONG:
 
1543
                case HA_KEYTYPE_ULONGLONG:
 
1544
                        break;
 
1545
#endif
 
1546
#ifndef DRIZZLED
 
1547
                case HA_KEYTYPE_BIT:
 
1548
                        /* TODO: What here? */
 
1549
                        break;
 
1550
#endif
 
1551
                case HA_KEYTYPE_END:                                                                                            /* Ready */
 
1552
                        break;
 
1553
        }
 
1554
 
 
1555
        return key_length;
 
1556
}
 
1557
 
 
1558
/*
 
1559
 * -----------------------------------------------------------------------
 
1560
 * Load and store rows
 
1561
 */
 
1562
 
 
1563
xtPublic xtWord4 myxt_store_row_length(XTOpenTablePtr ot, char *rec_buff)
 
1564
{
 
1565
        STRUCT_TABLE    *table = ot->ot_table->tab_dic.dic_my_table;
 
1566
        char                    *sdata;
 
1567
        xtWord4                 dlen;
 
1568
        xtWord4                 item_size;
 
1569
        xtWord4                 row_size = 0;
 
1570
 
 
1571
        for (Field* const *field=GET_TABLE_FIELDS(table); *field ; field++) {
 
1572
                if ((*field)->is_null_in_record((const uchar *) rec_buff)) {
 
1573
                        sdata = NULL;
 
1574
                        dlen = 0;
 
1575
                        item_size = 1;
 
1576
                }
 
1577
                else {
 
1578
                        sdata = mx_get_length_and_data(table, *field, rec_buff, &dlen);
 
1579
                        if (!dlen) {
 
1580
                                /* Empty, but not null (blobs may return NULL, when
 
1581
                                 * length is 0.
 
1582
                                 */
 
1583
                                sdata = rec_buff; // Any valid pointer will do
 
1584
                                item_size = 1 + dlen;
 
1585
                        }
 
1586
                        else if (dlen <= 240)
 
1587
                                item_size = 1 + dlen;
 
1588
                        else if (dlen <= 0xFFFF)
 
1589
                                item_size = 3 + dlen;
 
1590
                        else if (dlen <= 0xFFFFFF)
 
1591
                                item_size = 4 + dlen;
 
1592
                        else
 
1593
                                item_size = 5 + dlen;
 
1594
                }
 
1595
 
 
1596
                row_size += item_size;
 
1597
        }
 
1598
        return row_size;
 
1599
}
 
1600
 
 
1601
xtPublic xtWord4 myxt_store_row_data(XTOpenTablePtr ot, xtWord4 row_size, char *rec_buff)
 
1602
{
 
1603
        STRUCT_TABLE    *table = ot->ot_table->tab_dic.dic_my_table;
 
1604
        char                    *sdata;
 
1605
        xtWord4                 dlen;
 
1606
        xtWord4                 item_size;
 
1607
 
 
1608
        for (Field * const* field=GET_TABLE_FIELDS(table); *field; field++) {
 
1609
                if (mx_is_null_in_record(table, *field, rec_buff)) {
 
1610
                        sdata = NULL;
 
1611
                        dlen = 0;
 
1612
                        item_size = 1;
 
1613
                }
 
1614
                else {
 
1615
                        sdata = mx_get_length_and_data(table, *field, rec_buff, &dlen);
 
1616
                        if (!dlen) {
 
1617
                                /* Empty, but not null (blobs may return NULL, when
 
1618
                                 * length is 0.
 
1619
                                 */
 
1620
                                sdata = rec_buff; // Any valid pointer will do
 
1621
                                item_size = 1 + dlen;
 
1622
                        }
 
1623
                        else if (dlen <= 240)
 
1624
                                item_size = 1 + dlen;
 
1625
                        else if (dlen <= 0xFFFF)
 
1626
                                item_size = 3 + dlen;
 
1627
                        else if (dlen <= 0xFFFFFF)
 
1628
                                item_size = 4 + dlen;
 
1629
                        else
 
1630
                                item_size = 5 + dlen;
 
1631
                }
 
1632
 
 
1633
                if (row_size + item_size > ot->ot_row_wbuf_size) {
 
1634
                        if (!xt_realloc_ns((void **) &ot->ot_row_wbuffer, row_size + item_size))
 
1635
                                return 0;
 
1636
                        ot->ot_row_wbuf_size = row_size + item_size;
 
1637
                }
 
1638
 
 
1639
                if (!sdata)
 
1640
                        ot->ot_row_wbuffer[row_size] = 255;
 
1641
                else if (dlen <= 240) {
 
1642
                        ot->ot_row_wbuffer[row_size] = (unsigned char) dlen;
 
1643
                        memcpy(&ot->ot_row_wbuffer[row_size+1], sdata, dlen);
 
1644
                }
 
1645
                else if (dlen <= 0xFFFF) {
 
1646
                        ot->ot_row_wbuffer[row_size] = 254;
 
1647
                        XT_SET_DISK_2(&ot->ot_row_wbuffer[row_size+1], dlen);
 
1648
                        memcpy(&ot->ot_row_wbuffer[row_size+3], sdata, dlen);
 
1649
                }
 
1650
                else if (dlen <= 0xFFFFFF) {
 
1651
                        ot->ot_row_wbuffer[row_size] = 253;
 
1652
                        XT_SET_DISK_3(&ot->ot_row_wbuffer[row_size+1], dlen);
 
1653
                        memcpy(&ot->ot_row_wbuffer[row_size+4], sdata, dlen);
 
1654
                }
 
1655
                else {
 
1656
                        ot->ot_row_wbuffer[row_size] = 252;
 
1657
                        XT_SET_DISK_4(&ot->ot_row_wbuffer[row_size+1], dlen);
 
1658
                        memcpy(&ot->ot_row_wbuffer[row_size+5], sdata, dlen);
 
1659
                }
 
1660
 
 
1661
                row_size += item_size;
 
1662
        }
 
1663
        return row_size;
 
1664
}
 
1665
 
 
1666
/* Count the number and size of whole columns in the given buffer. */
 
1667
xtPublic size_t myxt_load_row_length(XTOpenTablePtr ot, size_t buffer_size, xtWord1 *source_buf, u_int *ret_col_cnt)
 
1668
{
 
1669
        u_int   col_cnt;
 
1670
        xtWord4 len;
 
1671
        size_t  size = 0;
 
1672
        u_int   i;
 
1673
 
 
1674
        col_cnt = ot->ot_table->tab_dic.dic_no_of_cols;
 
1675
        if (ret_col_cnt)
 
1676
                col_cnt = *ret_col_cnt;
 
1677
        for (i=0; i<col_cnt; i++) {
 
1678
                if (size + 1 > buffer_size)
 
1679
                        goto done;
 
1680
                switch (*source_buf) {
 
1681
                        case 255: // Indicate NULL value
 
1682
                                size++;
 
1683
                                source_buf++;
 
1684
                                break;
 
1685
                        case 254: // 2 bytes length
 
1686
                                if (size + 3 > buffer_size)
 
1687
                                        goto done;
 
1688
                                len = XT_GET_DISK_2(source_buf + 1);
 
1689
                                if (size + 3 + len > buffer_size)
 
1690
                                        goto done;
 
1691
                                size += 3 + len;
 
1692
                                source_buf += 3 + len;
 
1693
                                break;
 
1694
                        case 253: // 3 bytes length
 
1695
                                if (size + 4 > buffer_size)
 
1696
                                        goto done;
 
1697
                                len = XT_GET_DISK_3(source_buf + 1);
 
1698
                                if (size + 4 + len > buffer_size)
 
1699
                                        goto done;
 
1700
                                size += 4 + len;
 
1701
                                source_buf += 4 + len;
 
1702
                                break;
 
1703
                        case 252: // 4 bytes length
 
1704
                                if (size + 5 > buffer_size)
 
1705
                                        goto done;
 
1706
                                len = XT_GET_DISK_4(source_buf + 1);
 
1707
                                if (size + 5 + len > buffer_size)
 
1708
                                        goto done;
 
1709
                                size += 5 + len;
 
1710
                                source_buf += 5 + len;
 
1711
                                break;
 
1712
                        default: // Length byte
 
1713
                                len = *source_buf;
 
1714
                                if (size + 1 + len > buffer_size)
 
1715
                                        goto done;
 
1716
                                size += 1 + len;
 
1717
                                source_buf += 1 + len;
 
1718
                                break;
 
1719
                }
 
1720
        }
 
1721
        
 
1722
        done:
 
1723
        if (ret_col_cnt)
 
1724
                *ret_col_cnt = i;
 
1725
        return size;
 
1726
}
 
1727
 
 
1728
/* Unload from PBXT variable length format to the MySQL row format. */
 
1729
xtPublic xtWord4 myxt_load_row_data(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt)
 
1730
{
 
1731
        xtWord1                 *input_buf = source_buf;
 
1732
        STRUCT_TABLE    *table;
 
1733
        xtWord4                 len;
 
1734
        Field                   *curr_field;
 
1735
        xtBool                  is_null;
 
1736
        u_int                   i = 0;
 
1737
 
 
1738
        if (!(table = ot->ot_table->tab_dic.dic_my_table)) {
 
1739
                xt_register_taberr(XT_REG_CONTEXT, XT_ERR_NO_DICTIONARY, ot->ot_table->tab_name);
 
1740
                return 0;
 
1741
        }
 
1742
 
 
1743
        /* According to the InnoDB implementation:
 
1744
         * "MySQL assumes that all columns
 
1745
         * have the SQL NULL bit set unless it
 
1746
         * is a nullable column with a non-NULL value".
 
1747
         */
 
1748
        memset(dest_buff, 0xFF, GET_TABLE_SHARE(table)->null_bytes);
 
1749
        for (Field * const *field=GET_TABLE_FIELDS(table); *field && (!col_cnt || i<col_cnt); field++, i++) {
 
1750
                curr_field = *field;
 
1751
                is_null = FALSE;
 
1752
                switch (*source_buf) {
 
1753
                        case 255: // Indicate NULL value
 
1754
                                is_null = TRUE;
 
1755
                                len = 0;
 
1756
                                source_buf++;
 
1757
                                break;
 
1758
                        case 254: // 2 bytes length
 
1759
                                len = XT_GET_DISK_2(source_buf + 1);
 
1760
                                source_buf += 3;
 
1761
                                break;
 
1762
                        case 253: // 3 bytes length
 
1763
                                len = XT_GET_DISK_3(source_buf + 1);
 
1764
                                source_buf += 4;
 
1765
                                break;
 
1766
                        case 252: // 4 bytes length
 
1767
                                len = XT_GET_DISK_4(source_buf + 1);
 
1768
                                source_buf += 5;
 
1769
                                break;
 
1770
                        default: // Length byte
 
1771
                                if (*source_buf > 240) {
 
1772
                                        xt_register_xterr(XT_REG_CONTEXT, XT_ERR_BAD_RECORD_FORMAT);
 
1773
                                        return 0;
 
1774
                                }
 
1775
                                len = *source_buf;
 
1776
                                source_buf++;
 
1777
                                break;
 
1778
                }
 
1779
 
 
1780
                if (is_null)
 
1781
                        mx_set_length_and_data(table, curr_field, (char *) dest_buff, 0, NULL);
 
1782
                else
 
1783
                        mx_set_length_and_data(table, curr_field, (char *) dest_buff, len, (char *) source_buf);
 
1784
 
 
1785
                source_buf += len;
 
1786
        }
 
1787
        return (xtWord4) (source_buf - input_buf);
 
1788
}
 
1789
 
 
1790
xtPublic xtBool myxt_load_row(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt)
 
1791
{
 
1792
        return myxt_load_row_data(ot, source_buf, dest_buff, col_cnt) != 0;
 
1793
}
 
1794
 
 
1795
xtPublic xtBool myxt_find_column(XTOpenTablePtr ot, u_int *col_idx, const char *col_name)
 
1796
{
 
1797
        STRUCT_TABLE    *table = ot->ot_table->tab_dic.dic_my_table;
 
1798
        u_int                   i=0;
 
1799
 
 
1800
        for (Field * const *field=GET_TABLE_FIELDS(table); *field; field++, i++) {
 
1801
                if (!my_strcasecmp(system_charset_info, (*field)->field_name, col_name)) {
 
1802
                        *col_idx = i;
 
1803
                        return OK;
 
1804
                }
 
1805
        }
 
1806
        return FALSE;
 
1807
}
 
1808
 
 
1809
xtPublic void myxt_get_column_name(XTOpenTablePtr ot, u_int col_idx, u_int len, char *col_name)
 
1810
{
 
1811
        STRUCT_TABLE    *table = ot->ot_table->tab_dic.dic_my_table;
 
1812
        Field                   *field;
 
1813
 
 
1814
        field = GET_TABLE_FIELDS(table)[col_idx];
 
1815
        xt_strcpy(len, col_name, field->field_name);
 
1816
}
 
1817
 
 
1818
xtPublic void myxt_get_column_as_string(XTOpenTablePtr ot, char *buffer, u_int col_idx, u_int len, char *value)
 
1819
{
 
1820
        XTTableHPtr             tab = ot->ot_table;
 
1821
        XTThreadPtr             self = ot->ot_thread;
 
1822
        STRUCT_TABLE    *table = tab->tab_dic.dic_my_table;
 
1823
        Field                   *field = GET_TABLE_FIELDS(table)[col_idx];
 
1824
        char                    buf_val[MAX_FIELD_WIDTH];
 
1825
        String                  val(buf_val, sizeof(buf_val), &my_charset_bin);
 
1826
 
 
1827
        if (mx_is_null_in_record(table, field, buffer))
 
1828
                xt_strcpy(len, value, "NULL");
 
1829
        else {
 
1830
                byte    *save;
 
1831
 
 
1832
#ifndef DRIZZLED
 
1833
                /* Required by store() - or an assertion will fail: */
 
1834
                if (table->read_set)
 
1835
                        MX_BIT_SET(table->read_set, col_idx);
 
1836
#endif
 
1837
 
 
1838
                save = field->ptr;
 
1839
                xt_lock_mutex(self, &tab->tab_dic_field_lock);
 
1840
                pushr_(xt_unlock_mutex, &tab->tab_dic_field_lock);
 
1841
                field->ptr = (byte *) buffer + field->offset(table->getDefaultValues());
 
1842
                field->val_str(&val);
 
1843
                field->ptr = save;                                      // Restore org row pointer
 
1844
                freer_(); // xt_unlock_mutex(&tab->tab_dic_field_lock)
 
1845
                xt_strcpy(len, value, val.c_ptr());
 
1846
        }
 
1847
}
 
1848
 
 
1849
xtPublic xtBool myxt_set_column(XTOpenTablePtr ot, char *buffer, u_int col_idx, const char *value, u_int len)
 
1850
{
 
1851
        XTTableHPtr             tab = ot->ot_table;
 
1852
        XTThreadPtr             self = ot->ot_thread;
 
1853
        STRUCT_TABLE    *table = tab->tab_dic.dic_my_table;
 
1854
        Field                   *field = GET_TABLE_FIELDS(table)[col_idx];
 
1855
        byte                    *save;
 
1856
        int                             error;
 
1857
 
 
1858
#ifndef DRIZZLED
 
1859
        /* Required by store() - or an assertion will fail: */
 
1860
        if (table->write_set)
 
1861
                MX_BIT_SET(table->write_set, col_idx);
 
1862
#endif
 
1863
 
 
1864
        mx_set_notnull_in_record(table, field, buffer);
 
1865
 
 
1866
        save = field->ptr;
 
1867
        xt_lock_mutex(self, &tab->tab_dic_field_lock);
 
1868
        pushr_(xt_unlock_mutex, &tab->tab_dic_field_lock);
 
1869
        field->ptr = (byte *) buffer + field->offset(table->getDefaultValues());
 
1870
        error = field->store(value, len, &my_charset_utf8_general_ci);
 
1871
        field->ptr = save;                                      // Restore org row pointer
 
1872
        freer_(); // xt_unlock_mutex(&tab->tab_dic_field_lock)
 
1873
        return error ? FAILED : OK;
 
1874
}
 
1875
 
 
1876
xtPublic void myxt_get_column_data(XTOpenTablePtr ot, char *buffer, u_int col_idx, char **value, size_t *len)
 
1877
{
 
1878
        STRUCT_TABLE    *table = ot->ot_table->tab_dic.dic_my_table;
 
1879
        Field                   *field = GET_TABLE_FIELDS(table)[col_idx];
 
1880
        char                    *sdata;
 
1881
        xtWord4                 dlen;
 
1882
 
 
1883
        sdata = mx_get_length_and_data(table, field, buffer, &dlen);
 
1884
        *value = sdata;
 
1885
        *len = dlen;
 
1886
}
 
1887
 
 
1888
xtPublic xtBool myxt_store_row(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, char *rec_buff)
 
1889
{
 
1890
        if (ot->ot_rec_fixed) {
 
1891
                rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer;
 
1892
                rec_info->ri_rec_buf_size = ot->ot_rec_size;
 
1893
                rec_info->ri_ext_rec = NULL;
 
1894
 
 
1895
                rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_FIXED;
 
1896
                memcpy(rec_info->ri_fix_rec_buf->rf_data, rec_buff, ot->ot_rec_size - XT_REC_FIX_HEADER_SIZE);
 
1897
        }
 
1898
        else {
 
1899
                xtWord4 row_size;
 
1900
 
 
1901
                if (!(row_size = myxt_store_row_data(ot, XT_REC_EXT_HEADER_SIZE, rec_buff)))
 
1902
                        return FAILED;
 
1903
                if (row_size - XT_REC_FIX_EXT_HEADER_DIFF <= ot->ot_rec_size) { 
 
1904
                        rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) &ot->ot_row_wbuffer[XT_REC_FIX_EXT_HEADER_DIFF];
 
1905
                        rec_info->ri_rec_buf_size = row_size - XT_REC_FIX_EXT_HEADER_DIFF;
 
1906
                        rec_info->ri_ext_rec = NULL;
 
1907
 
 
1908
                        rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_VARIABLE;
 
1909
                }
 
1910
                else {
 
1911
                        rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer;
 
1912
                        rec_info->ri_rec_buf_size = ot->ot_rec_size;
 
1913
                        rec_info->ri_ext_rec = (XTTabRecExtDPtr) ot->ot_row_wbuffer;
 
1914
                        rec_info->ri_log_data_size = row_size - ot->ot_rec_size;
 
1915
                        rec_info->ri_log_buf = (XTactExtRecEntryDPtr) &ot->ot_row_wbuffer[ot->ot_rec_size - offsetof(XTactExtRecEntryDRec, er_data)];
 
1916
 
 
1917
                        rec_info->ri_ext_rec->tr_rec_type_1 = XT_TAB_STATUS_EXT_DLOG;
 
1918
                        XT_SET_DISK_4(rec_info->ri_ext_rec->re_log_dat_siz_4, rec_info->ri_log_data_size);
 
1919
                }
 
1920
        }
 
1921
        return OK;
 
1922
}
 
1923
 
 
1924
static void mx_print_string(uchar *s, uint count)
 
1925
{
 
1926
        while (count > 0) {
 
1927
                if (s[count - 1] != ' ')
 
1928
                        break;
 
1929
                count--;
 
1930
        }
 
1931
        printf("\"");
 
1932
        for (u_int i=0; i<count; i++, s++)
 
1933
                printf("%c", *s);
 
1934
        printf("\"");
 
1935
}
 
1936
 
 
1937
xtPublic void myxt_print_key(XTIndexPtr ind, xtWord1 *key_value)
 
1938
{
 
1939
        register XTIndexSegRec  *keyseg = ind->mi_seg;
 
1940
        register uchar                  *b = (uchar *) key_value;
 
1941
        uint                                    b_length;
 
1942
        uint                                    pack_len;
 
1943
 
 
1944
        for (u_int i = 0; i < ind->mi_seg_count; i++, keyseg++) {
 
1945
                if (i!=0)
 
1946
                        printf(" ");
 
1947
                if (keyseg->null_bit) {
 
1948
                        if (!*b++) {
 
1949
                                printf("NULL");
 
1950
                                continue;
 
1951
                        }
 
1952
                }
 
1953
                switch ((enum ha_base_keytype) keyseg->type) {
 
1954
                        case HA_KEYTYPE_TEXT:                                                                                    /* Ascii; Key is converted */
 
1955
                                if (keyseg->flag & HA_SPACE_PACK) {
 
1956
                                        get_key_pack_length(b_length, pack_len, b);
 
1957
                                }
 
1958
                                else
 
1959
                                        b_length = keyseg->length;
 
1960
                                mx_print_string(b, b_length);
 
1961
                                b += b_length;
 
1962
                                break;
 
1963
                        case HA_KEYTYPE_LONG_INT: {
 
1964
                                int32_t l_2 = sint4korr(b);
 
1965
                                b += keyseg->length;
 
1966
                                printf("%ld", (long) l_2);
 
1967
                                break;
 
1968
                        }
 
1969
                        case HA_KEYTYPE_ULONG_INT: {
 
1970
                                xtWord4 u_2 = sint4korr(b);
 
1971
                                b += keyseg->length;
 
1972
                                printf("%lu", (u_long) u_2);
 
1973
                                break;
 
1974
                        }
 
1975
                        default:
 
1976
                                break;
 
1977
                }
 
1978
        }
 
1979
}
 
1980
 
 
1981
/*
 
1982
 * -----------------------------------------------------------------------
 
1983
 * MySQL Data Dictionary
 
1984
 */
 
1985
 
 
1986
static void my_close_table(STRUCT_TABLE *share)
 
1987
{
 
1988
        delete share;
 
1989
}
 
1990
 
 
1991
/*
 
1992
 * This function returns NULL if the table cannot be opened 
 
1993
 * because this is not a MySQL thread.
 
1994
 */ 
 
1995
static STRUCT_TABLE *my_open_table(XTThreadPtr self, XTDatabaseHPtr XT_UNUSED(db), XTPathStrPtr tab_path, xtWord1 table_type)
 
1996
{
 
1997
        THD                     *thd = current_thd;
 
1998
        char            *tab_file_name;
 
1999
        char            database_name[XT_IDENTIFIER_NAME_SIZE];
 
2000
        char            tab_name[XT_IDENTIFIER_NAME_SIZE];
 
2001
        uint32_t        tab_name_len;   
 
2002
        TableShare      *share;
 
2003
        int                     error;
 
2004
 
 
2005
        /* If we have no MySQL thread, then we cannot open this table!
 
2006
         * What this means is the thread is probably the sweeper or the
 
2007
         * compactor.
 
2008
         */
 
2009
        if (!thd)
 
2010
                return NULL;
 
2011
 
 
2012
        tab_file_name = xt_last_name_of_path(tab_path->ps_path);
 
2013
        tab_name_len = TableIdentifier::filename_to_tablename(tab_file_name, tab_name, XT_IDENTIFIER_NAME_SIZE);
 
2014
 
 
2015
        xt_2nd_last_name_of_path(XT_IDENTIFIER_NAME_SIZE, database_name, tab_path->ps_path);
 
2016
 
 
2017
        TableIdentifier *ident = NULL;
 
2018
        
 
2019
        if (table_type == XT_TABLE_TYPE_TEMPORARY) {
 
2020
                std::string tmp_path(drizzle_tmpdir);
 
2021
                tmp_path.append("/");
 
2022
                tmp_path.append(tab_file_name);
 
2023
                ident = new TableIdentifier(database_name, tab_name, tmp_path);
 
2024
        }
 
2025
        else if (table_type == XT_TABLE_TYPE_STANDARD) {
 
2026
                ident = new TableIdentifier(
 
2027
                        std::string(database_name), 
 
2028
                        std::string(tab_name, tab_name_len), 
 
2029
                        message::Table::STANDARD);
 
2030
        }
 
2031
        else {
 
2032
                std::string n(getDataHomeCatalog());
 
2033
                n.append("/");
 
2034
                n.append(database_name);
 
2035
                n.append("/");
 
2036
                n.append(tab_file_name);
 
2037
                ident = new TableIdentifier(database_name, tab_name, n);
 
2038
        }
 
2039
        
 
2040
        share = new TableShare(message::Table::STANDARD);
 
2041
        if ((error = share->open_table_def(*thd, *ident))) {
 
2042
          xt_throw_sulxterr(XT_CONTEXT, XT_ERR_LOADING_MYSQL_DIC, tab_path->ps_path, (u_long) error);
 
2043
          delete ident;
 
2044
          return NULL;
 
2045
        }
 
2046
        delete ident;
 
2047
 
 
2048
        return share;
 
2049
}
 
2050
 
 
2051
/*
 
2052
static bool my_match_index(XTDDIndex *ind, KEY *index)
 
2053
{
 
2054
        KEY_PART_INFO   *key_part;
 
2055
        KEY_PART_INFO   *key_part_end;
 
2056
        u_int                   j;
 
2057
        XTDDColumnRef   *cref;
 
2058
 
 
2059
        if (index->key_parts != ind->co_cols.size())
 
2060
                return false;
 
2061
 
 
2062
        j=0;
 
2063
        key_part_end = index->key_part + index->key_parts;
 
2064
        for (key_part = index->key_part; key_part != key_part_end; key_part++, j++) {
 
2065
                if (!(cref = ind->co_cols.itemAt(j)))
 
2066
                        return false;
 
2067
                if (myxt_strcasecmp(cref->cr_col_name, (char *) key_part->field->field_name) != 0)
 
2068
                        return false;
 
2069
        }
 
2070
 
 
2071
        if (ind->co_type == XT_DD_KEY_PRIMARY) {
 
2072
                if (!(index->flags & HA_NOSAME))
 
2073
                        return false;
 
2074
        }
 
2075
        else {
 
2076
                if (ind->co_type == XT_DD_INDEX_UNIQUE) {
 
2077
                        if (!(index->flags & HA_NOSAME))
 
2078
                                return false;
 
2079
                }
 
2080
                if (ind->co_ind_name) {
 
2081
                        if (myxt_strcasecmp(ind->co_ind_name, index->name) != 0)
 
2082
                                return false;
 
2083
                }
 
2084
        }
 
2085
 
 
2086
        return true;
 
2087
}
 
2088
 
 
2089
static XTDDIndex *my_find_index(XTDDTable *dd_tab, KEY *index)
 
2090
{
 
2091
        XTDDIndex *ind;
 
2092
 
 
2093
        for (u_int i=0; i<dd_tab->dt_indexes.size(); i++)
 
2094
        {
 
2095
                ind = dd_tab->dt_indexes.itemAt(i);
 
2096
                if (my_match_index(ind, index))
 
2097
                        return ind;
 
2098
        }
 
2099
        return NULL;
 
2100
}
 
2101
*/
 
2102
 
 
2103
static void my_deref_index_data(struct XTThread *self, XTIndexPtr mi)
 
2104
{
 
2105
        enter_();
 
2106
        /* The dirty list of cache pages should be empty here! */
 
2107
        /* This is not the case if we were not able to flush data. E.g. when running out of disk space */
 
2108
        //ASSERT(!mi->mi_dirty_list);
 
2109
        ASSERT(!mi->mi_free_list);
 
2110
 
 
2111
        xt_spinlock_free(self, &mi->mi_dirty_lock);
 
2112
        XT_INDEX_FREE_LOCK(self, mi);
 
2113
        myxt_bitmap_free(self, &mi->mi_col_map);
 
2114
        if (mi->mi_free_list)
 
2115
                xt_free(self, mi->mi_free_list);
 
2116
 
 
2117
        xt_free(self, mi);
 
2118
        exit_();
 
2119
}
 
2120
 
 
2121
static xtBool my_is_not_null_int4(XTIndexSegPtr seg)
 
2122
{
 
2123
        return (seg->type == HA_KEYTYPE_LONG_INT && !(seg->flag & HA_NULL_PART));
 
2124
}
 
2125
 
 
2126
/* MY_BITMAP definition in Drizzle does not like if
 
2127
 * I use a NULL pointer to calculate the offset!?
 
2128
 */
 
2129
#define MX_OFFSETOF(x, y)               ((size_t)(&((x *) 8)->y) - 8)
 
2130
 
 
2131
/* Derived from ha_myisam::create and mi_create */
 
2132
static XTIndexPtr my_create_index(XTThreadPtr self, STRUCT_TABLE *table_arg, u_int idx, KeyInfo *index)
 
2133
{
 
2134
        XTIndexPtr                              ind;
 
2135
        KeyPartInfo                     *key_part;
 
2136
        KeyPartInfo                     *key_part_end;
 
2137
        XTIndexSegRec                   *seg;
 
2138
        Field                                   *field;
 
2139
        enum ha_base_keytype    type;
 
2140
        uint                                    options = 0;
 
2141
        u_int                                   key_length = 0;
 
2142
        xtBool                                  partial_field;
 
2143
 
 
2144
        enter_();
 
2145
 
 
2146
        pushsr_(ind, my_deref_index_data, (XTIndexPtr) xt_calloc(self, MX_OFFSETOF(XTIndexRec, mi_seg) + sizeof(XTIndexSegRec) * index->key_parts));
 
2147
 
 
2148
        XT_INDEX_INIT_LOCK(self, ind);
 
2149
        xt_spinlock_init_with_autoname(self, &ind->mi_dirty_lock);
 
2150
        ind->mi_index_no = idx;
 
2151
        ind->mi_flags = (index->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL | HA_UNIQUE_CHECK));
 
2152
        //ind->mi_low_byte_first = TS(table_arg)->db_low_byte_first;
 
2153
        ind->mi_key_corrupted = FALSE;
 
2154
        ind->mi_fix_key = TRUE;
 
2155
        ind->mi_select_total = 0;
 
2156
        ind->mi_subset_of = 0;
 
2157
        myxt_bitmap_init(self, &ind->mi_col_map, GET_TABLE_SHARE(table_arg)->fields);
 
2158
        
 
2159
        ind->mi_seg_count = (uint) index->key_parts;
 
2160
        key_part_end = index->key_part + index->key_parts;
 
2161
        seg = ind->mi_seg;
 
2162
        for (key_part = index->key_part; key_part != key_part_end; key_part++, seg++) {
 
2163
                partial_field = FALSE;
 
2164
                field = key_part->field;
 
2165
 
 
2166
                type = field->key_type();
 
2167
                seg->flag = key_part->key_part_flag;
 
2168
 
 
2169
                if (options & HA_OPTION_PACK_KEYS ||
 
2170
                        (index->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | HA_SPACE_PACK_USED)))
 
2171
                {
 
2172
                        if (key_part->length > 8 && (type == HA_KEYTYPE_TEXT || 
 
2173
#ifndef DRIZZLED
 
2174
                                type == HA_KEYTYPE_NUM ||
 
2175
#endif
 
2176
                                (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
 
2177
                        {
 
2178
                                /* No blobs here */
 
2179
                                if (key_part == index->key_part)
 
2180
                                        ind->mi_flags |= HA_PACK_KEY;
 
2181
#ifndef DRIZZLED
 
2182
                                if (!(field->flags & ZEROFILL_FLAG) &&
 
2183
                                        (field->type() == MYSQL_TYPE_STRING ||
 
2184
                                        field->type() == MYSQL_TYPE_VAR_STRING ||
 
2185
                                        ((int) (key_part->length - field->decimals())) >= 4))
 
2186
                                seg->flag |= HA_SPACE_PACK;
 
2187
#endif
 
2188
                        }
 
2189
                }
 
2190
 
 
2191
                seg->col_idx = field->field_index;
 
2192
                seg->is_recs_in_range = 1;
 
2193
                seg->is_selectivity = 1;
 
2194
                seg->type = (int) type;
 
2195
                seg->start = key_part->offset;
 
2196
                seg->length = key_part->length;
 
2197
                seg->bit_start = seg->bit_end = 0;
 
2198
                seg->bit_length = seg->bit_pos = 0;
 
2199
                seg->charset = field->charset();
 
2200
 
 
2201
                if (field->null_ptr) {
 
2202
                        key_length++;
 
2203
                        seg->flag |= HA_NULL_PART;
 
2204
                        seg->null_bit = field->null_bit;
 
2205
                        seg->null_pos = (uint) (field->null_ptr - (uchar*) table_arg->getDefaultValues());
 
2206
                }
 
2207
                else {
 
2208
                        seg->null_bit = 0;
 
2209
                        seg->null_pos = 0;
 
2210
                }
 
2211
 
 
2212
                if (field->real_type() == MYSQL_TYPE_ENUM
 
2213
#ifndef DRIZZLED
 
2214
                        || field->real_type() == MYSQL_TYPE_SET
 
2215
#endif
 
2216
                        ) {
 
2217
                        /* This values are not indexed as string!!
 
2218
                         * The index will not be built correctly if this value is non-NULL.
 
2219
                         */
 
2220
                        seg->charset = NULL;
 
2221
                }
 
2222
 
 
2223
                if (field->type() == MYSQL_TYPE_BLOB
 
2224
#ifndef DRIZZLED
 
2225
                        || field->type() == MYSQL_TYPE_GEOMETRY
 
2226
#endif
 
2227
                        ) {
 
2228
                        seg->flag |= HA_BLOB_PART;
 
2229
                        /* save number of bytes used to pack length */
 
2230
                        seg->bit_start = (uint) ((Field_blob *) field)->pack_length_no_ptr();
 
2231
                }
 
2232
#ifndef DRIZZLED
 
2233
                else if (field->type() == MYSQL_TYPE_BIT) {
 
2234
                        seg->bit_length = ((Field_bit *) field)->bit_len;
 
2235
                        seg->bit_start = ((Field_bit *) field)->bit_ofs;
 
2236
                        seg->bit_pos = (uint) (((Field_bit *) field)->bit_ptr - (uchar*) table_arg->getInsertRecord());
 
2237
                }
 
2238
#else
 
2239
                /* Drizzle uses HA_KEYTYPE_ULONG_INT keys for enums > 1 byte, which is not consistent with MySQL, so we fix it here  */
 
2240
                else if (field->type() == MYSQL_TYPE_ENUM) {
 
2241
                        switch (seg->length) {
 
2242
                                case 2: 
 
2243
#ifdef DRIZZLED
 
2244
                                        ASSERT_NS(FALSE);
 
2245
#else
 
2246
                                        seg->type = HA_KEYTYPE_USHORT_INT;
 
2247
                                        break;
 
2248
                                case 3:
 
2249
                                        seg->type = HA_KEYTYPE_UINT24;
 
2250
                                        break;
 
2251
#endif
 
2252
                        }
 
2253
                }
 
2254
#endif
 
2255
 
 
2256
                switch (seg->type) {
 
2257
                        case HA_KEYTYPE_VARTEXT1:
 
2258
                        case HA_KEYTYPE_VARTEXT2:
 
2259
                        case HA_KEYTYPE_VARBINARY1:
 
2260
                        case HA_KEYTYPE_VARBINARY2:
 
2261
                                if (!(seg->flag & HA_BLOB_PART)) {
 
2262
                                        /* Make a flag that this is a VARCHAR */
 
2263
                                        seg->flag |= HA_VAR_LENGTH_PART;
 
2264
                                        /* Store in bit_start number of bytes used to pack the length */
 
2265
                                        seg->bit_start = ((seg->type == HA_KEYTYPE_VARTEXT1 || seg->type == HA_KEYTYPE_VARBINARY1) ? 1 : 2);
 
2266
                                }
 
2267
                                break;
 
2268
                }
 
2269
 
 
2270
                /* All packed fields start with a length (1 or 3 bytes): */
 
2271
                if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) {
 
2272
                        key_length++;                           /* At least one length byte */
 
2273
                        if (seg->length >= 255) /* prefix may be 3 bytes */
 
2274
                        key_length +=2;
 
2275
                }
 
2276
 
 
2277
                key_length += seg->length;
 
2278
                if (seg->length > 40)
 
2279
                        ind->mi_fix_key = FALSE;
 
2280
 
 
2281
                /* Determine if only part of the field is in the key:
 
2282
                 * This is important for index coverage!
 
2283
                 * Note, BLOB fields are never retrieved from
 
2284
                 * an index!
 
2285
                 */
 
2286
                if (field->type() == MYSQL_TYPE_BLOB)
 
2287
                        partial_field = TRUE;
 
2288
                else if (field->real_type() == MYSQL_TYPE_VARCHAR               // For varbinary type
 
2289
#ifndef DRIZZLED
 
2290
                        || field->real_type() == MYSQL_TYPE_VAR_STRING          // For varbinary type
 
2291
                        || field->real_type() == MYSQL_TYPE_STRING                      // For binary type
 
2292
#endif
 
2293
                        )
 
2294
                {
 
2295
                        Field   *tab_field = GET_TABLE_FIELDS(table_arg)[key_part->fieldnr-1];
 
2296
                        u_int   field_len = tab_field->key_length();
 
2297
 
 
2298
                        if (key_part->length != field_len)
 
2299
                                partial_field = TRUE;
 
2300
                }
 
2301
 
 
2302
                /* NOTE: do not set if the field is only partially in the index!!! */
 
2303
                if (!partial_field)
 
2304
                        MX_BIT_FAST_TEST_AND_SET(&ind->mi_col_map, field->field_index);
 
2305
        }
 
2306
 
 
2307
        if (key_length > XT_INDEX_MAX_KEY_SIZE)
 
2308
                xt_throw_sulxterr(XT_CONTEXT, XT_ERR_KEY_TOO_LARGE, index->name, (u_long) XT_INDEX_MAX_KEY_SIZE);
 
2309
 
 
2310
        /* This is the maximum size of the index on disk: */
 
2311
        ind->mi_key_size = key_length;
 
2312
        ind->mi_max_items = (XT_INDEX_PAGE_SIZE-2) / (key_length+XT_RECORD_REF_SIZE);
 
2313
 
 
2314
        if (ind->mi_fix_key) {
 
2315
                /* Special case for not-NULL 4 byte int value: */
 
2316
                switch (ind->mi_seg_count) {
 
2317
                        case 1:
 
2318
                                ind->mi_single_type = ind->mi_seg[0].type;
 
2319
                                if (ind->mi_seg[0].type == HA_KEYTYPE_LONG_INT ||
 
2320
                                        ind->mi_seg[0].type == HA_KEYTYPE_ULONG_INT) {
 
2321
                                        if (!(ind->mi_seg[0].flag & HA_NULL_PART))
 
2322
                                                ind->mi_scan_branch = xt_scan_branch_single;
 
2323
                                }
 
2324
                                break;
 
2325
                        case 2:
 
2326
                                if (my_is_not_null_int4(&ind->mi_seg[0]) &&
 
2327
                                        my_is_not_null_int4(&ind->mi_seg[1])) {
 
2328
                                        ind->mi_scan_branch = xt_scan_branch_fix_simple;
 
2329
                                        ind->mi_simple_comp_key = xt_compare_2_int4;
 
2330
                                }
 
2331
                                break;
 
2332
                        case 3:
 
2333
                                if (my_is_not_null_int4(&ind->mi_seg[0]) &&
 
2334
                                        my_is_not_null_int4(&ind->mi_seg[1]) &&
 
2335
                                        my_is_not_null_int4(&ind->mi_seg[2])) {
 
2336
                                        ind->mi_scan_branch = xt_scan_branch_fix_simple;
 
2337
                                        ind->mi_simple_comp_key = xt_compare_3_int4;
 
2338
                                }
 
2339
                                break;
 
2340
                }
 
2341
                if (!ind->mi_scan_branch)
 
2342
                        ind->mi_scan_branch = xt_scan_branch_fix;
 
2343
                ind->mi_prev_item = xt_prev_branch_item_fix;
 
2344
                ind->mi_last_item = xt_last_branch_item_fix;
 
2345
        }
 
2346
        else {
 
2347
                ind->mi_scan_branch = xt_scan_branch_var;
 
2348
                ind->mi_prev_item = xt_prev_branch_item_var;
 
2349
                ind->mi_last_item = xt_last_branch_item_var;
 
2350
        }
 
2351
        ind->mi_lazy_delete = ind->mi_fix_key && ind->mi_max_items >= 4;
 
2352
 
 
2353
        XT_NODE_ID(ind->mi_root) = 0;
 
2354
 
 
2355
        popr_(); // Discard my_deref_index_data(ind)
 
2356
 
 
2357
        return_(ind);
 
2358
}
 
2359
 
 
2360
/* We estimate the size of BLOBs depending on the number
 
2361
 * of BLOBs in the table.
 
2362
 */
 
2363
static u_int mx_blob_field_size_total[] = {
 
2364
        500,    // 1
 
2365
        400,    // 2
 
2366
        350,    // 3
 
2367
        320,    // 4
 
2368
        300,    // 5
 
2369
        280,    // 6
 
2370
        260,    // 7
 
2371
        240,    // 8
 
2372
        220,    // 9
 
2373
        210             // 10
 
2374
};
 
2375
 
 
2376
static u_int mxvarchar_field_min_ave[] = {
 
2377
        120,    // 1
 
2378
        105,    // 2
 
2379
        90,             // 3
 
2380
        65,             // 4
 
2381
        50,             // 5
 
2382
        40,             // 6
 
2383
        40,             // 7
 
2384
        40,             // 8
 
2385
        40,             // 9
 
2386
        40              // 10
 
2387
};
 
2388
 
 
2389
xtPublic void myxt_setup_dictionary(XTThreadPtr self, XTDictionaryPtr dic)
 
2390
{
 
2391
        STRUCT_TABLE    *my_tab = dic->dic_my_table;
 
2392
        u_int   field_count;
 
2393
        u_int   var_field_count = 0;
 
2394
        u_int   varchar_field_count = 0;
 
2395
        u_int   blob_field_count = 0;
 
2396
        u_int   large_blob_field_count = 0;
 
2397
        xtWord8 min_data_size = 0;
 
2398
        xtWord8 max_data_size = 0;
 
2399
        xtWord8 ave_data_size = 0;
 
2400
        xtWord8 min_row_size = 0;
 
2401
        xtWord8 max_row_size = 0;
 
2402
        xtWord8 ave_row_size = 0;
 
2403
        xtWord8 min_ave_row_size = 0;
 
2404
        xtWord8 max_ave_row_size = 0;
 
2405
        u_int   dic_rec_size;
 
2406
        xtBool  dic_rec_fixed;
 
2407
        Field   *curr_field;
 
2408
        Field * const *field;
 
2409
 
 
2410
        /* How many columns are required for all indexes. */
 
2411
        KeyInfo                         *index;
 
2412
        KeyPartInfo     *key_part;
 
2413
        KeyPartInfo     *key_part_end;
 
2414
 
 
2415
#ifndef XT_USE_LAZY_DELETE
 
2416
        dic->dic_no_lazy_delete = TRUE;
 
2417
#endif
 
2418
 
 
2419
        dic->dic_ind_cols_req = 0;
 
2420
        for (uint i=0; i<GET_TABLE_SHARE(my_tab)->keys; i++) {
 
2421
                index = &my_tab->getKeyInfo(i);
 
2422
 
 
2423
                key_part_end = index->key_part + index->key_parts;
 
2424
                for (key_part = index->key_part; key_part != key_part_end; key_part++) {
 
2425
                        curr_field = key_part->field;
 
2426
 
 
2427
                        if ((u_int) curr_field->field_index+1 > dic->dic_ind_cols_req)
 
2428
                                dic->dic_ind_cols_req = curr_field->field_index+1;
 
2429
                }
 
2430
        }
 
2431
 
 
2432
        /* We will work out how many columns are required for all blobs: */
 
2433
        dic->dic_blob_cols_req = 0;     
 
2434
        field_count = 0;
 
2435
        for (field=GET_TABLE_FIELDS(my_tab); (curr_field = *field); field++) {
 
2436
                field_count++;
 
2437
                min_data_size = curr_field->key_length();
 
2438
                max_data_size = curr_field->key_length();
 
2439
                enum_field_types tno = curr_field->type();
 
2440
 
 
2441
                min_ave_row_size = 40;
 
2442
                max_ave_row_size = 128;
 
2443
                if (tno == MYSQL_TYPE_BLOB) {
 
2444
                        blob_field_count++;
 
2445
                        min_data_size = 0;
 
2446
                        max_data_size = ((Field_blob *) curr_field)->max_data_length();
 
2447
                        /* Set the average length higher for BLOBs: */
 
2448
                        if (max_data_size == 0xFFFF ||
 
2449
                                max_data_size == 0xFFFFFF) {
 
2450
                                if (large_blob_field_count < 10)
 
2451
                                        max_ave_row_size = mx_blob_field_size_total[large_blob_field_count];
 
2452
                                else
 
2453
                                        max_ave_row_size = 200;
 
2454
                                large_blob_field_count++;
 
2455
                        }
 
2456
                        else if (max_data_size == 0xFFFFFFFF) {
 
2457
                                /* Scale the estimated size of the blob depending on how many BLOBs
 
2458
                                 * are in the table!
 
2459
                                 */
 
2460
                                if (large_blob_field_count < 10)
 
2461
                                        max_ave_row_size = mx_blob_field_size_total[large_blob_field_count];
 
2462
                                else
 
2463
                                        max_ave_row_size = 200;
 
2464
                                large_blob_field_count++;
 
2465
                                if ((u_int) curr_field->field_index+1 > dic->dic_blob_cols_req)
 
2466
                                        dic->dic_blob_cols_req = curr_field->field_index+1;
 
2467
                                dic->dic_blob_count++;
 
2468
                                xt_realloc(self, (void **) &dic->dic_blob_cols, sizeof(Field *) * dic->dic_blob_count);
 
2469
                                dic->dic_blob_cols[dic->dic_blob_count-1] = curr_field;
 
2470
                        }
 
2471
                }
 
2472
                else if (tno == MYSQL_TYPE_VARCHAR
 
2473
#ifndef DRIZZLED
 
2474
                        || tno == MYSQL_TYPE_VAR_STRING
 
2475
#endif
 
2476
                        ) {
 
2477
                        /* GOTCHA: MYSQL_TYPE_VAR_STRING does not exist as MYSQL_TYPE_VARCHAR define, but
 
2478
                         * is used when creating a table with
 
2479
                         * VARCHAR()
 
2480
                         */
 
2481
                        min_data_size = 0;
 
2482
                        if (varchar_field_count < 10)
 
2483
                                min_ave_row_size = mxvarchar_field_min_ave[varchar_field_count];
 
2484
                        else
 
2485
                                min_ave_row_size = 40;
 
2486
                        varchar_field_count++;
 
2487
                }
 
2488
 
 
2489
                if (max_data_size == min_data_size)
 
2490
                        ave_data_size = max_data_size;
 
2491
                else {
 
2492
                        var_field_count++;
 
2493
                        /* Take the average a 25% of the maximum: */
 
2494
                        ave_data_size = max_data_size / 4;
 
2495
 
 
2496
                        /* Set the average based on min and max parameters: */
 
2497
                        if (ave_data_size < min_ave_row_size)
 
2498
                                ave_data_size = min_ave_row_size;
 
2499
                        else if (ave_data_size > max_ave_row_size)
 
2500
                                ave_data_size = max_ave_row_size;
 
2501
 
 
2502
                        if (ave_data_size > max_data_size)
 
2503
                                ave_data_size = max_data_size;
 
2504
                }
 
2505
 
 
2506
                /* Add space for the length indicators: */
 
2507
                if (min_data_size <= 240)
 
2508
                        min_row_size += 1 + min_data_size;
 
2509
                else if (min_data_size <= 0xFFFF)
 
2510
                        min_row_size += 3 + min_data_size;
 
2511
                else if (min_data_size <= 0xFFFFFF)
 
2512
                        min_row_size += 4 + min_data_size;
 
2513
                else
 
2514
                        min_row_size += 5 + min_data_size;
 
2515
 
 
2516
                if (max_data_size <= 240)
 
2517
                        max_row_size += 1 + max_data_size;
 
2518
                else if (max_data_size <= 0xFFFF)
 
2519
                        max_row_size += 3 + max_data_size;
 
2520
                else if (max_data_size <= 0xFFFFFF)
 
2521
                        max_row_size += 4 + max_data_size;
 
2522
                else
 
2523
                        max_row_size += 5 + max_data_size;
 
2524
 
 
2525
                if (ave_data_size <= 240)
 
2526
                        ave_row_size += 1 + ave_data_size;
 
2527
                else /* Should not be more than this! */
 
2528
                        ave_row_size += 3 + ave_data_size;
 
2529
 
 
2530
                /* This is the length of the record required for all indexes: */
 
2531
                /* This was calculated incorrectly. Not a serius bug because it
 
2532
                 * is only used in the case of fixed length row, and in this
 
2533
                 * case the dic_ind_rec_len is set correctly below.
 
2534
                 */
 
2535
                if (field_count == dic->dic_ind_cols_req)
 
2536
                        dic->dic_ind_rec_len = max_row_size;
 
2537
        }
 
2538
 
 
2539
        dic->dic_min_row_size = min_row_size;
 
2540
        dic->dic_max_row_size = max_row_size;
 
2541
        dic->dic_ave_row_size = ave_row_size;
 
2542
        dic->dic_no_of_cols = field_count;
 
2543
 
 
2544
        if (dic->dic_def_ave_row_size) {
 
2545
                /* The average row size has been set: */
 
2546
                dic_rec_size = offsetof(XTTabRecFix, rf_data) + GET_TABLE_SHARE(my_tab)->getRecordLength();
 
2547
 
 
2548
                /* The conditions for a fixed record are: */
 
2549
                if (dic->dic_def_ave_row_size >= (xtWord8) GET_TABLE_SHARE(my_tab)->getRecordLength() &&
 
2550
                        dic_rec_size <= XT_TAB_MAX_FIX_REC_LENGTH &&
 
2551
                        !blob_field_count) {
 
2552
                        dic_rec_fixed = TRUE;
 
2553
                }
 
2554
                else {
 
2555
                        xtWord8 new_rec_size;
 
2556
 
 
2557
                        dic_rec_fixed = FALSE;
 
2558
                        if (dic->dic_def_ave_row_size > max_row_size)
 
2559
                                new_rec_size = offsetof(XTTabRecFix, rf_data) + max_row_size;
 
2560
                        else
 
2561
                                new_rec_size = offsetof(XTTabRecFix, rf_data) + dic->dic_def_ave_row_size;
 
2562
 
 
2563
                        /* The maximum record size 64K for explicit AVG_ROW_LENGTH! */
 
2564
                        if (new_rec_size > XT_TAB_MAX_FIX_REC_LENGTH_SPEC)
 
2565
                                new_rec_size = XT_TAB_MAX_FIX_REC_LENGTH_SPEC;
 
2566
 
 
2567
                        dic_rec_size = (u_int) new_rec_size;
 
2568
                }
 
2569
        }
 
2570
        else {
 
2571
                /* If the average size is within 10% if of the maximum size, then we
 
2572
                 * we handle these rows as fixed size rows.
 
2573
                 * Fixed size rows use the internal MySQL format.
 
2574
                 */
 
2575
                dic_rec_size = offsetof(XTTabRecFix, rf_data) + GET_TABLE_SHARE(my_tab)->getRecordLength();
 
2576
                /* Fixed length records must be less than 16K in size,
 
2577
                 * have an average size which is very close (20%) to the maximum size or
 
2578
                 * be less than a minimum size,
 
2579
                 * and not contain any BLOBs:
 
2580
                 */
 
2581
                if (dic_rec_size <= XT_TAB_MAX_FIX_REC_LENGTH &&
 
2582
                        (ave_row_size + ave_row_size / 4 >= max_row_size ||
 
2583
                        dic_rec_size < XT_TAB_MIN_VAR_REC_LENGTH) &&
 
2584
                        !blob_field_count) {
 
2585
                        dic_rec_fixed = TRUE;
 
2586
                }
 
2587
                else {
 
2588
                        dic_rec_fixed = FALSE;
 
2589
                        /* Note I add offsetof(XTTabRecFix, rf_data) insteard of
 
2590
                         * offsetof(XTTabRecExt, re_data) here!
 
2591
                         * The reason is that, we want to include the average size
 
2592
                         * record in the fixed data part. To do this we only need to
 
2593
                         * calculate a fixed header size, because in the cases in which
 
2594
                         * it fits, we will only be using a fixed header!
 
2595
                         */
 
2596
                        dic_rec_size = (u_int) (offsetof(XTTabRecFix, rf_data) + ave_row_size);
 
2597
                        /* The maximum record size (16K for autorow sizing)! */
 
2598
                        if (dic_rec_size > XT_TAB_MAX_FIX_REC_LENGTH)
 
2599
                                dic_rec_size = XT_TAB_MAX_FIX_REC_LENGTH;
 
2600
                }
 
2601
        }
 
2602
 
 
2603
        /* Ensure that handle data record size is big enough to
 
2604
         * include the extended record reference, in the case of
 
2605
         * variable length rows
 
2606
         */
 
2607
        if (!dic_rec_fixed) {
 
2608
                if (dic_rec_size < offsetof(XTTabRecExtDRec, re_data))
 
2609
                        dic_rec_size = offsetof(XTTabRecExtDRec, re_data);
 
2610
        }
 
2611
#ifdef DEBUG
 
2612
        else {
 
2613
                ASSERT_NS(dic_rec_size > offsetof(XTTabRecFix, rf_data));
 
2614
        }
 
2615
#endif
 
2616
 
 
2617
        if (!dic->dic_rec_size) {
 
2618
                dic->dic_rec_size = dic_rec_size;
 
2619
                dic->dic_rec_fixed = dic_rec_fixed;
 
2620
        }
 
2621
        else {
 
2622
                /* This just confirms that our original calculation on
 
2623
                 * create table agrees with the current calculation.
 
2624
                 * (i.e. if non-zero values were loaded from the table).
 
2625
                 *
 
2626
                 * It may be the criteria for calculating the data record size
 
2627
                 * and whether to used a fixed or variable record has changed,
 
2628
                 * but we need to stick to the current physical layout of the
 
2629
                 * table.
 
2630
                 *
 
2631
                 * Note that this can occur in rename table when the
 
2632
                 * method of calculation has changed.
 
2633
                 *
 
2634
                 * On rename, the format of the table does not change, so we
 
2635
                 * will not take the calculated values.
 
2636
                 */
 
2637
                //ASSERT(dic->dic_rec_size == dic_rec_size);
 
2638
                //ASSERT(dic->dic_rec_fixed == dic_rec_fixed);
 
2639
        }
 
2640
 
 
2641
        if (dic_rec_fixed) {
 
2642
                /* Recalculate the length of the required required to address all
 
2643
                 * index columns!
 
2644
                 */              
 
2645
                if (field_count == dic->dic_ind_cols_req)
 
2646
                        dic->dic_ind_rec_len = GET_TABLE_SHARE(my_tab)->getRecordLength();
 
2647
                else {
 
2648
                        field=GET_TABLE_FIELDS(my_tab);
 
2649
                        
 
2650
                        curr_field = field[dic->dic_ind_cols_req];
 
2651
                        dic->dic_ind_rec_len = curr_field->offset(my_tab->getDefaultValues());
 
2652
                }
 
2653
        }
 
2654
 
 
2655
        /* We now calculate how many of the first columns in the row
 
2656
         * will definitely fit into the buffer, when the record is
 
2657
         * of type extended.
 
2658
         *
 
2659
         * In this way we can figure out if we need to load the extended
 
2660
         * record at all.
 
2661
         */
 
2662
        dic->dic_fix_col_count = 0;
 
2663
        if (!dic_rec_fixed) {
 
2664
                xtWord8 max_rec_size = offsetof(XTTabRecExt, re_data);
 
2665
 
 
2666
                for (Field * const *f=GET_TABLE_FIELDS(my_tab); (curr_field = *f); f++) {
 
2667
                        max_data_size = curr_field->key_length();
 
2668
                        enum_field_types tno = curr_field->type();
 
2669
                        if (tno == MYSQL_TYPE_BLOB)
 
2670
                                max_data_size = ((Field_blob *) curr_field)->max_data_length();
 
2671
                        if (max_data_size <= 240)
 
2672
                                max_rec_size += 1 + max_data_size;
 
2673
                        else if (max_data_size <= 0xFFFF)
 
2674
                                max_rec_size += 3 + max_data_size;
 
2675
                        else if (max_data_size <= 0xFFFFFF)
 
2676
                                max_rec_size += 4 + max_data_size;
 
2677
                        else
 
2678
                                max_rec_size += 5 + max_data_size;
 
2679
                        if (max_rec_size > (xtWord8) dic_rec_size)
 
2680
                                break;
 
2681
                        dic->dic_fix_col_count++;
 
2682
                }               
 
2683
                ASSERT(dic->dic_fix_col_count < dic->dic_no_of_cols);
 
2684
        }
 
2685
 
 
2686
        dic->dic_key_count = GET_TABLE_SHARE(my_tab)->keys;
 
2687
        dic->dic_mysql_buf_size = GET_TABLE_SHARE(my_tab)->rec_buff_length;
 
2688
        dic->dic_mysql_rec_size = GET_TABLE_SHARE(my_tab)->getRecordLength();
 
2689
}
 
2690
 
 
2691
static u_int my_get_best_superset(XTThreadPtr XT_UNUSED(self), XTDictionaryPtr dic, XTIndexPtr ind)
 
2692
{
 
2693
        XTIndexPtr      super_ind;
 
2694
        u_int           super = 0;
 
2695
        u_int           super_seg_count = ind->mi_seg_count;
 
2696
 
 
2697
        for (u_int i=0; i<dic->dic_key_count; i++) {
 
2698
                super_ind = dic->dic_keys[i];
 
2699
                if (ind->mi_index_no != super_ind->mi_index_no &&
 
2700
                        super_seg_count < super_ind->mi_seg_count) {
 
2701
                        for (u_int j=0; j<ind->mi_seg_count; j++) {
 
2702
                                if (ind->mi_seg[j].col_idx != super_ind->mi_seg[j].col_idx)
 
2703
                                        goto next;
 
2704
                        }
 
2705
                        super_seg_count = super_ind->mi_seg_count;
 
2706
                        super = i+1;
 
2707
                        next:;
 
2708
                }
 
2709
        }
 
2710
        return super;
 
2711
}
 
2712
 
 
2713
/*
 
2714
 * Return FAILED if the MySQL dictionary is not available.
 
2715
 */
 
2716
xtPublic xtBool myxt_load_dictionary(XTThreadPtr self, XTDictionaryPtr dic, XTDatabaseHPtr db, XTPathStrPtr tab_path)
 
2717
{
 
2718
        STRUCT_TABLE *my_tab;
 
2719
 
 
2720
        if (!(my_tab = my_open_table(self, db, tab_path, dic->dic_table_type)))
 
2721
                return FAILED;
 
2722
        dic->dic_my_table = my_tab;
 
2723
#ifdef DRIZZLED
 
2724
        dic->dic_def_ave_row_size = (xtWord8) GET_TABLE_SHARE(my_tab)->getTableProto()->options().avg_row_length();
 
2725
#else
 
2726
        dic->dic_def_ave_row_size = (xtWord8) GET_TABLE_SHARE(my_tab)->avg_row_length;
 
2727
#endif
 
2728
        myxt_setup_dictionary(self, dic);
 
2729
        dic->dic_keys = (XTIndexPtr *) xt_calloc(self, sizeof(XTIndexPtr) * GET_TABLE_SHARE(my_tab)->keys);
 
2730
        for (uint i=0; i<GET_TABLE_SHARE(my_tab)->keys; i++)
 
2731
                dic->dic_keys[i] = my_create_index(self, my_tab, i, &my_tab->getKeyInfo(i));
 
2732
 
 
2733
        /* Check if any key is a subset of another: */
 
2734
        for (u_int i=0; i<dic->dic_key_count; i++)
 
2735
                dic->dic_keys[i]->mi_subset_of = my_get_best_superset(self, dic, dic->dic_keys[i]);
 
2736
 
 
2737
        return OK;
 
2738
}
 
2739
 
 
2740
xtPublic void myxt_free_dictionary(XTThreadPtr self, XTDictionaryPtr dic)
 
2741
{
 
2742
        if (dic->dic_table) {
 
2743
                dic->dic_table->release(self);
 
2744
                dic->dic_table = NULL;
 
2745
        }
 
2746
 
 
2747
        if (dic->dic_my_table) {
 
2748
                my_close_table(dic->dic_my_table);
 
2749
                dic->dic_my_table = NULL;
 
2750
        }
 
2751
 
 
2752
        if (dic->dic_blob_cols) {
 
2753
                xt_free(self, dic->dic_blob_cols);
 
2754
                dic->dic_blob_cols = NULL;
 
2755
        }
 
2756
        dic->dic_blob_count = 0;
 
2757
 
 
2758
        /* If we have opened a table, then this data is freed with the dictionary: */
 
2759
        if (dic->dic_keys) {
 
2760
                for (uint i=0; i<dic->dic_key_count; i++) {
 
2761
                        if (dic->dic_keys[i])
 
2762
                                my_deref_index_data(self, (XTIndexPtr) dic->dic_keys[i]);
 
2763
                }
 
2764
                xt_free(self, dic->dic_keys);
 
2765
                dic->dic_key_count = 0;
 
2766
                dic->dic_keys = NULL;
 
2767
        }
 
2768
}
 
2769
 
 
2770
xtPublic void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic)
 
2771
{
 
2772
        dic->dic_my_table = source_dic->dic_my_table;
 
2773
        source_dic->dic_my_table = NULL;
 
2774
 
 
2775
        if (!dic->dic_rec_size) {
 
2776
                dic->dic_rec_size = source_dic->dic_rec_size;
 
2777
                dic->dic_rec_fixed = source_dic->dic_rec_fixed;
 
2778
        }
 
2779
        else {
 
2780
                /* This just confirms that our original calculation on
 
2781
                 * create table agrees with the current calculation.
 
2782
                 * (i.e. if non-zero values were loaded from the table).
 
2783
                 *
 
2784
                 * It may be the criteria for calculating the data record size
 
2785
                 * and whether to used a fixed or variable record has changed,
 
2786
                 * but we need to stick to the current physical layout of the
 
2787
                 * table.
 
2788
                 */
 
2789
                ASSERT_NS(dic->dic_rec_size == source_dic->dic_rec_size);
 
2790
                ASSERT_NS(dic->dic_rec_fixed == source_dic->dic_rec_fixed);
 
2791
        }
 
2792
 
 
2793
        dic->dic_tab_flags = source_dic->dic_tab_flags;
 
2794
        dic->dic_blob_cols_req = source_dic->dic_blob_cols_req;
 
2795
        dic->dic_blob_count = source_dic->dic_blob_count;
 
2796
        dic->dic_blob_cols = source_dic->dic_blob_cols;
 
2797
        source_dic->dic_blob_cols = NULL;
 
2798
 
 
2799
        dic->dic_mysql_buf_size = source_dic->dic_mysql_buf_size;
 
2800
        dic->dic_mysql_rec_size = source_dic->dic_mysql_rec_size;
 
2801
        dic->dic_key_count = source_dic->dic_key_count;
 
2802
        dic->dic_keys = source_dic->dic_keys;
 
2803
 
 
2804
        /* Set this to zero, bcause later xt_flush_tables() may be called. 
 
2805
         * This can occur when using the BLOB streaming engine,
 
2806
         * in command ALTER TABLE x ENGINE = PBXT;
 
2807
         */
 
2808
        source_dic->dic_key_count = 0;
 
2809
        source_dic->dic_keys = NULL;
 
2810
 
 
2811
        dic->dic_min_row_size = source_dic->dic_min_row_size;
 
2812
        dic->dic_max_row_size = source_dic->dic_max_row_size;
 
2813
        dic->dic_ave_row_size = source_dic->dic_ave_row_size;
 
2814
        dic->dic_def_ave_row_size = source_dic->dic_def_ave_row_size;
 
2815
 
 
2816
        dic->dic_no_of_cols = source_dic->dic_no_of_cols;
 
2817
        dic->dic_fix_col_count = source_dic->dic_fix_col_count;
 
2818
        dic->dic_ind_cols_req = source_dic->dic_ind_cols_req;
 
2819
        dic->dic_ind_rec_len = source_dic->dic_ind_rec_len;
 
2820
}
 
2821
 
 
2822
static void my_free_dd_table(XTThreadPtr self, XTDDTable *dd_tab)
 
2823
{
 
2824
        if (dd_tab)
 
2825
                dd_tab->release(self);
 
2826
}
 
2827
 
 
2828
static void ha_create_dd_index(XTThreadPtr self, XTDDIndex *ind, KeyInfo *key)
 
2829
{
 
2830
        KeyPartInfo     *key_part;
 
2831
        KeyPartInfo     *key_part_end;
 
2832
        XTDDColumnRef   *cref;
 
2833
 
 
2834
        if (strcmp(key->name, "PRIMARY") == 0)
 
2835
                ind->co_type = XT_DD_KEY_PRIMARY;
 
2836
        else if (key->flags & HA_NOSAME)
 
2837
                ind->co_type = XT_DD_INDEX_UNIQUE;
 
2838
        else
 
2839
                ind->co_type = XT_DD_INDEX;
 
2840
 
 
2841
        if (ind->co_type == XT_DD_KEY_PRIMARY)
 
2842
                ind->co_name = xt_dup_string(self, key->name);
 
2843
        else
 
2844
                ind->co_ind_name = xt_dup_string(self, key->name);
 
2845
 
 
2846
        key_part_end = key->key_part + key->key_parts;
 
2847
        for (key_part = key->key_part; key_part != key_part_end; key_part++) {
 
2848
                if (!(cref = new XTDDColumnRef()))
 
2849
                        xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
 
2850
                cref->init(self);
 
2851
                ind->co_cols.append(self, cref);
 
2852
                cref->cr_col_name = xt_dup_string(self, (char *) key_part->field->field_name);
 
2853
        }
 
2854
}
 
2855
 
 
2856
static char *my_type_to_string(XTThreadPtr self, Field *field, STRUCT_TABLE *XT_UNUSED(my_tab))
 
2857
{
 
2858
        char            buffer[MAX_FIELD_WIDTH + 400];
 
2859
        const char      *ptr;
 
2860
        String          type((char *) buffer, sizeof(buffer), system_charset_info);
 
2861
        xtWord4         len;
 
2862
 
 
2863
        /* GOTCHA:
 
2864
         * - Above sets the string length to the same as the buffer,
 
2865
         *   so we must set the length to zero.
 
2866
         * - The result is not necessarilly zero terminated.
 
2867
         * - We cannot assume that the input buffer is the one
 
2868
         *   we get back (for example text field).
 
2869
         */
 
2870
        type.length(0);
 
2871
        field->sql_type(type);
 
2872
        ptr = type.ptr();
 
2873
        len = type.length();
 
2874
 
 
2875
        if (len >= sizeof(buffer))
 
2876
                len = sizeof(buffer)-1;
 
2877
 
 
2878
        if (ptr != buffer)
 
2879
                xt_strcpy(sizeof(buffer), buffer, ptr);
 
2880
 
 
2881
        buffer[len] = 0;
 
2882
                        
 
2883
        if (field->has_charset()) {
 
2884
                /* Always include the charset so that we can compare types
 
2885
                 * for FK/PK releations.
 
2886
                 */
 
2887
                xt_strcat(sizeof(buffer), buffer, " CHARACTER SET ");
 
2888
                xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->csname);
 
2889
 
 
2890
                /* For string types dump collation name only if 
 
2891
                 * collation is not primary for the given charset
 
2892
                 */
 
2893
                if (!(field->charset()->state & MY_CS_PRIMARY)) {
 
2894
                        xt_strcat(sizeof(buffer), buffer, " COLLATE ");
 
2895
                        xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->name);
 
2896
                }
 
2897
        }
 
2898
 
 
2899
        return xt_dup_string(self, buffer); // type.length()
 
2900
}
 
2901
 
 
2902
xtPublic XTDDTable *myxt_create_table_from_table(XTThreadPtr self, STRUCT_TABLE *my_tab)
 
2903
{
 
2904
        XTDDTable               *dd_tab;
 
2905
        Field                   *curr_field;
 
2906
        XTDDColumn              *col;
 
2907
        XTDDIndex               *ind;
 
2908
 
 
2909
        if (!(dd_tab = new XTDDTable()))
 
2910
                xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
 
2911
        dd_tab->init(self);
 
2912
        pushr_(my_free_dd_table, dd_tab);
 
2913
 
 
2914
        for (Field * const *field=GET_TABLE_FIELDS(my_tab); (curr_field = *field); field++) {
 
2915
                col = XTDDColumnFactory::createFromMySQLField(self, my_tab, curr_field);
 
2916
                dd_tab->dt_cols.append(self, col);
 
2917
        }
 
2918
 
 
2919
        for (uint i=0; i<GET_TABLE_SHARE(my_tab)->keys; i++) {
 
2920
                if (!(ind = (XTDDIndex *) new XTDDIndex(XT_DD_UNKNOWN)))
 
2921
                        xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
 
2922
                dd_tab->dt_indexes.append(self, ind);
 
2923
                ind->co_table = dd_tab;
 
2924
                ind->in_index = i;
 
2925
                ha_create_dd_index(self, ind, &my_tab->getKeyInfo(i));
 
2926
        }
 
2927
 
 
2928
        popr_(); // my_free_dd_table(dd_tab)
 
2929
        return dd_tab;
 
2930
}
 
2931
 
 
2932
/*
 
2933
 * -----------------------------------------------------------------------
 
2934
 * MySQL CHARACTER UTILITIES
 
2935
 */
 
2936
 
 
2937
xtPublic void myxt_static_convert_identifier(XTThreadPtr XT_UNUSED(self), MX_CONST_CHARSET_INFO *cs, char *from, char *to, size_t to_len)
 
2938
{
 
2939
#ifdef DRIZZLED
 
2940
        ((void *)cs);
 
2941
         xt_strcpy(to_len, to, from);
 
2942
#else
 
2943
        uint errors;
 
2944
 
 
2945
        /*
 
2946
         * Bug#4417
 
2947
         * Check that identifiers and strings are not converted 
 
2948
         * when the client character set is binary.
 
2949
         */
 
2950
        if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin)
 
2951
                xt_strcpy(to_len, to, from);
 
2952
        else
 
2953
                strconvert(cs, from, &my_charset_utf8_general_ci, to, to_len, &errors);
 
2954
#endif
 
2955
}
 
2956
 
 
2957
// cs == current_thd->charset()
 
2958
xtPublic char *myxt_convert_identifier(XTThreadPtr self, MX_CONST_CHARSET_INFO *cs, char *from)
 
2959
{
 
2960
#ifdef DRIZZLED
 
2961
        char *to = xt_dup_string(self, from);
 
2962
        ((void *)cs);
 
2963
#else
 
2964
        uint    errors;
 
2965
        u_int   len;
 
2966
        char    *to;
 
2967
 
 
2968
        if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin)
 
2969
                to = xt_dup_string(self, from);
 
2970
        else {
 
2971
                len = strlen(from) * 3 + 1;
 
2972
                to = (char *) xt_malloc(self, len);
 
2973
                strconvert(cs, from, &my_charset_utf8_general_ci, to, len, &errors);
 
2974
        }
 
2975
#endif
 
2976
        return to;
 
2977
}
 
2978
 
 
2979
xtPublic char *myxt_convert_table_name(XTThreadPtr self, char *from)
 
2980
{
 
2981
        u_int   len;
 
2982
        char    *to;
 
2983
 
 
2984
        len = strlen(from) * 5 + 1;
 
2985
        to = (char *) xt_malloc(self, len);
 
2986
        tablename_to_filename(from, to, len);
 
2987
        return to;
 
2988
}
 
2989
 
 
2990
/*
 
2991
 * This works because if you create a table
 
2992
 * with a '#' in it, MySQL will translate it
 
2993
 * to @0023 in the file name.
 
2994
 */
 
2995
xtPublic xtBool myxt_temp_table_name(const char *table)
 
2996
{
 
2997
        char    *name;
 
2998
        xtBool  yup = FALSE;
 
2999
 
 
3000
        name = xt_last_name_of_path(table);
 
3001
#ifdef DRIZZED
 
3002
        yup = (strncmp(name, "#sql", 4) == 0);
 
3003
#else
 
3004
        if (*name == '#')
 
3005
                yup = (strncmp(name, "#sql-", 5) == 0) || (strncmp(name, "#sql2-", 6) == 0);
 
3006
#endif
 
3007
        return yup;
 
3008
}
 
3009
 
 
3010
xtPublic void myxt_static_convert_table_name(XTThreadPtr XT_UNUSED(self), char *from, char *to, size_t to_len)
 
3011
{
 
3012
        tablename_to_filename(from, to, to_len);
 
3013
}
 
3014
 
 
3015
xtPublic void myxt_static_convert_file_name(char *from, char *to, size_t to_len)
 
3016
{
 
3017
        uint32_t len = TableIdentifier::filename_to_tablename(from, to, to_len);
 
3018
        if (len >= to_len)
 
3019
                len = to_len-1;
 
3020
        to[len] = 0;
 
3021
}
 
3022
 
 
3023
xtPublic int myxt_strcasecmp(char * a, char *b)
 
3024
{
 
3025
        return my_strcasecmp(&my_charset_utf8_general_ci, a, b);
 
3026
}
 
3027
 
 
3028
xtPublic int myxt_isspace(MX_CONST_CHARSET_INFO *cs, char a)
 
3029
{
 
3030
        return my_isspace(cs, a);
 
3031
}
 
3032
 
 
3033
xtPublic int myxt_ispunct(MX_CONST_CHARSET_INFO *cs, char a)
 
3034
{
 
3035
        return my_ispunct(cs, a);
 
3036
}
 
3037
 
 
3038
xtPublic int myxt_isdigit(MX_CONST_CHARSET_INFO *cs, char a)
 
3039
{
 
3040
        return my_isdigit(cs, a);
 
3041
}
 
3042
 
 
3043
xtPublic MX_CONST_CHARSET_INFO *myxt_getcharset(bool convert)
 
3044
{
 
3045
        if (convert) {
 
3046
                THD *thd = current_thd;
 
3047
 
 
3048
                if (thd)
 
3049
                        return (MX_CHARSET_INFO *)thd_charset(thd);
 
3050
        }
 
3051
        return (MX_CHARSET_INFO *)&my_charset_utf8_general_ci;
 
3052
}
 
3053
 
 
3054
xtPublic xtBool myxt_create_thread_possible()
 
3055
{
 
3056
#ifndef DRIZZLED
 
3057
        if (!global_system_variables.table_plugin) {
 
3058
                xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MYSQL_NO_THREAD);
 
3059
                return FAILED;
 
3060
        }
 
3061
#endif
 
3062
        return OK;
 
3063
}
 
3064
 
 
3065
xtPublic void *myxt_create_thread()
 
3066
{
 
3067
#ifdef DRIZZLED
 
3068
        Client          *client;
 
3069
        Session         *session;
 
3070
 
 
3071
        if (drizzled::internal::my_thread_init()) {
 
3072
                xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading");
 
3073
                return NULL;
 
3074
        }
 
3075
 
 
3076
        if (!(client = new NullClient()))
 
3077
                return NULL;
 
3078
        session = new Session(client);
 
3079
        session->thread_stack = (char *) &session;
 
3080
        session->storeGlobals();
 
3081
        return (void *) session;
 
3082
#else
 
3083
        THD *new_thd;
 
3084
 
 
3085
        if (my_thread_init()) {
 
3086
                xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading");
 
3087
                return NULL;
 
3088
        }
 
3089
 
 
3090
        /*
 
3091
         * Unfortunately, if PBXT is the default engine, and we are shutting down
 
3092
         * then global_system_variables.table_plugin may be NULL. Which will cause
 
3093
         * a crash if we try to create a thread!
 
3094
         *
 
3095
         * The following call in plugin_shutdown() sets the global reference
 
3096
         * to NULL:
 
3097
         *
 
3098
         * unlock_variables(NULL, &global_system_variables);
 
3099
         *
 
3100
         * Later plugin_deinitialize() is called.
 
3101
         *
 
3102
         * The following stack is an example crash which occurs when I call
 
3103
         * myxt_create_thread() in ha_exit(), to force the error.
 
3104
         *
 
3105
         *   if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
 
3106
         *   pi is NULL!
 
3107
         * #0   0x002ff684 in intern_plugin_lock at sql_plugin.cc:617
 
3108
         * #1   0x0030296d in plugin_thdvar_init at sql_plugin.cc:2432
 
3109
         * #2   0x000db4a4 in THD::init at sql_class.cc:756
 
3110
         * #3   0x000e02ed in THD::THD at sql_class.cc:638
 
3111
         * #4   0x00e2678d in myxt_create_thread at myxt_xt.cc:2990
 
3112
         * #5   0x00e05d43 in ha_exit at ha_pbxt.cc:1011
 
3113
         * #6   0x00e065c2 in pbxt_end at ha_pbxt.cc:1330
 
3114
         * #7   0x00e065df in pbxt_panic at ha_pbxt.cc:1343
 
3115
         * #8   0x0023e57d in ha_finalize_handlerton at handler.cc:392
 
3116
         * #9   0x002ffc8b in plugin_deinitialize at sql_plugin.cc:816
 
3117
         * #10  0x003037d9 in plugin_shutdown at sql_plugin.cc:1572
 
3118
         * #11  0x000f7b2b in clean_up at mysqld.cc:1266
 
3119
         * #12  0x000f7fca in unireg_end at mysqld.cc:1192
 
3120
         * #13  0x000fa021 in kill_server at mysqld.cc:1134
 
3121
         * #14  0x000fa6df in kill_server_thread at mysqld.cc:1155
 
3122
         * #15  0x91fdb155 in _pthread_start
 
3123
         * #16  0x91fdb012 in thread_start
 
3124
         */
 
3125
        if (!global_system_variables.table_plugin) {
 
3126
                xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MYSQL_NO_THREAD);
 
3127
                return NULL;
 
3128
        }
 
3129
 
 
3130
        if (!(new_thd = new THD)) {
 
3131
                my_thread_end();
 
3132
                xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to create MySQL thread (THD)");
 
3133
                return NULL;
 
3134
        }
 
3135
 
 
3136
        /*
 
3137
         * If PBXT is the default storage engine, then creating any THD objects will add extra 
 
3138
         * references to the PBXT plugin object. because the threads are created but PBXT
 
3139
         * this creates a self reference, and the reference count does not go to zero
 
3140
         * on shutdown.
 
3141
         *
 
3142
         * The server then issues a message that it is forcing shutdown of the plugin.
 
3143
         *
 
3144
         * However, the engine reference is not required by the THDs used by PBXT, so 
 
3145
         * I just remove them here.
 
3146
         */
 
3147
        plugin_unlock(NULL, new_thd->variables.table_plugin);
 
3148
        new_thd->variables.table_plugin = NULL;
 
3149
 
 
3150
        new_thd->thread_stack = (char *) &new_thd;
 
3151
        new_thd->store_globals();
 
3152
        lex_start(new_thd);
 
3153
 
 
3154
        return (void *) new_thd;
 
3155
#endif
 
3156
}
 
3157
 
 
3158
#ifdef DRIZZLED
 
3159
xtPublic void myxt_destroy_thread(void *s, xtBool end_threads)
 
3160
{
 
3161
        Session *session = (Session *) s;
 
3162
 
 
3163
        session->lockForDelete();
 
3164
        delete session;
 
3165
 
 
3166
        if (end_threads)
 
3167
                drizzled::internal::my_thread_end();
 
3168
}
 
3169
#else
 
3170
xtPublic void myxt_destroy_thread(void *thread, xtBool end_threads)
 
3171
{
 
3172
        THD *thd = (THD *) thread;
 
3173
 
 
3174
#if MYSQL_VERSION_ID > 60005
 
3175
        /* PMC - This is a HACK! It is required because
 
3176
         * MySQL shuts down MDL before shutting down the
 
3177
         * plug-ins.
 
3178
         */
 
3179
        if (!pbxt_inited)
 
3180
                mdl_init();
 
3181
        close_thread_tables(thd);
 
3182
        if (!pbxt_inited)
 
3183
                mdl_destroy();
 
3184
#else
 
3185
        close_thread_tables(thd);
 
3186
#endif
 
3187
        
 
3188
        delete thd;
 
3189
 
 
3190
        /* Remember that we don't have a THD */
 
3191
        my_pthread_setspecific_ptr(THR_THD, 0);
 
3192
 
 
3193
        if (end_threads)
 
3194
                my_thread_end();
 
3195
}
 
3196
#endif
 
3197
 
 
3198
xtPublic void myxt_delete_remaining_thread()
 
3199
{
 
3200
        THD *thd;
 
3201
 
 
3202
        if ((thd = current_thd))
 
3203
                myxt_destroy_thread((void *) thd, TRUE);
 
3204
}
 
3205
 
 
3206
xtPublic XTThreadPtr myxt_get_self()
 
3207
{
 
3208
        THD *thd;
 
3209
        
 
3210
        if ((thd = current_thd))
 
3211
                return xt_ha_thd_to_self(thd);
 
3212
        return NULL;
 
3213
}
 
3214
 
 
3215
/*
 
3216
 * -----------------------------------------------------------------------
 
3217
 * INFORMATION SCHEMA FUNCTIONS
 
3218
 *
 
3219
 */
 
3220
 
 
3221
#ifndef DRIZZLED
 
3222
static int mx_put_record(THD *thd, TABLE *table)
 
3223
{
 
3224
        return schema_table_store_record(thd, table);
 
3225
}
 
3226
 
 
3227
#ifdef UNUSED_CODE
 
3228
static void mx_put_int(TABLE *table, int column, int value)
 
3229
{
 
3230
        GET_TABLE_FIELDS(table)[column]->store(value, false);
 
3231
}
 
3232
 
 
3233
static void mx_put_real8(TABLE *table, int column, xtReal8 value)
 
3234
{
 
3235
        GET_TABLE_FIELDS(table)[column]->store(value);
 
3236
}
 
3237
 
 
3238
static void mx_put_string(TABLE *table, int column, const char *string, u_int len, charset_info_st *charset)
 
3239
{
 
3240
        GET_TABLE_FIELDS(table)[column]->store(string, len, charset);
 
3241
}
 
3242
#endif
 
3243
 
 
3244
static void mx_put_u_llong(TABLE *table, int column, u_llong value)
 
3245
{
 
3246
        GET_TABLE_FIELDS(table)[column]->store(value, false);
 
3247
}
 
3248
 
 
3249
static void mx_put_string(TABLE *table, int column, const char *string, charset_info_st *charset)
 
3250
{
 
3251
        GET_TABLE_FIELDS(table)[column]->store(string, strlen(string), charset);
 
3252
}
 
3253
 
 
3254
xtPublic int myxt_statistics_fill_table(XTThreadPtr self, void *th, void *ta, void *, MX_CONST void *ch)
 
3255
{
 
3256
        THD                             *thd = (THD *) th;
 
3257
        TABLE_LIST              *tables = (TABLE_LIST *) ta;
 
3258
        charset_info_st *charset = (charset_info_st *) ch;
 
3259
        TABLE                   *table = (TABLE *) tables->table;
 
3260
        int                             err = 0;
 
3261
        int                             col;
 
3262
        const char              *stat_name;
 
3263
        u_llong                 stat_value;
 
3264
        XTStatisticsRec statistics;
 
3265
        XTDatabaseHPtr  db = self->st_database;
 
3266
 
 
3267
        xt_gather_statistics(&statistics);
 
3268
        for (u_int rec_id=0; !err && rec_id<XT_STAT_CURRENT_MAX; rec_id++) {
 
3269
                stat_name = xt_get_stat_meta_data(rec_id)->sm_name;
 
3270
                stat_value = xt_get_statistic(&statistics, db, rec_id);
 
3271
 
 
3272
                col=0;
 
3273
                mx_put_u_llong(table, col++, rec_id+1);
 
3274
                mx_put_string(table, col++, stat_name, charset);
 
3275
                mx_put_u_llong(table, col++, stat_value);
 
3276
                err = mx_put_record(thd, table);
 
3277
        }
 
3278
 
 
3279
        return err;
 
3280
}
 
3281
#endif // !DRIZZLED
 
3282
 
 
3283
xtPublic void myxt_get_status(XTThreadPtr self, XTStringBufferPtr strbuf)
 
3284
{
 
3285
        char string[200];
 
3286
 
 
3287
        xt_sb_concat(self, strbuf, "\n");
 
3288
        xt_get_now(string, 200);
 
3289
        xt_sb_concat(self, strbuf, string);
 
3290
        xt_sb_concat(self, strbuf, " PBXT ");
 
3291
        xt_sb_concat(self, strbuf, xt_get_version());
 
3292
        xt_sb_concat(self, strbuf, " STATUS OUTPUT");
 
3293
        xt_sb_concat(self, strbuf, "\n");
 
3294
 
 
3295
        xt_sb_concat(self, strbuf, "Record cache usage: ");
 
3296
        xt_sb_concat_int8(self, strbuf, xt_tc_get_usage());
 
3297
        xt_sb_concat(self, strbuf, "\n");
 
3298
        xt_sb_concat(self, strbuf, "Record cache size:  ");
 
3299
        xt_sb_concat_int8(self, strbuf, xt_tc_get_size());
 
3300
        xt_sb_concat(self, strbuf, "\n");
 
3301
        xt_sb_concat(self, strbuf, "Record cache high:  ");
 
3302
        xt_sb_concat_int8(self, strbuf, xt_tc_get_high());
 
3303
        xt_sb_concat(self, strbuf, "\n");
 
3304
        xt_sb_concat(self, strbuf, "Index cache usage:  ");
 
3305
        xt_sb_concat_int8(self, strbuf, xt_ind_get_usage());
 
3306
        xt_sb_concat(self, strbuf, "\n");
 
3307
        xt_sb_concat(self, strbuf, "Index cache size:   ");
 
3308
        xt_sb_concat_int8(self, strbuf, xt_ind_get_size());
 
3309
        xt_sb_concat(self, strbuf, "\n");
 
3310
        xt_sb_concat(self, strbuf, "Log cache usage:    ");
 
3311
        xt_sb_concat_int8(self, strbuf, xt_xlog_get_usage());
 
3312
        xt_sb_concat(self, strbuf, "\n");
 
3313
        xt_sb_concat(self, strbuf, "Log cache size:     ");
 
3314
        xt_sb_concat_int8(self, strbuf, xt_xlog_get_size());
 
3315
        xt_sb_concat(self, strbuf, "\n");
 
3316
 
 
3317
        xt_ht_lock(self, xt_db_open_databases);
 
3318
        pushr_(xt_ht_unlock, xt_db_open_databases);
 
3319
 
 
3320
        XTDatabaseHPtr  *dbptr;
 
3321
        size_t len = xt_sl_get_size(xt_db_open_db_by_id);
 
3322
 
 
3323
        if (len > 0) {
 
3324
                xt_sb_concat(self, strbuf, "Data log files:\n");
 
3325
                for (u_int i=0; i<len; i++) {
 
3326
                        dbptr = (XTDatabaseHPtr *) xt_sl_item_at(xt_db_open_db_by_id, i);
 
3327
                        
 
3328
#ifndef XT_USE_GLOBAL_DB
 
3329
                        xt_sb_concat(self, strbuf, "Database: ");
 
3330
                        xt_sb_concat(self, strbuf, (*dbptr)->db_name);
 
3331
                        xt_sb_concat(self, strbuf, "\n");
 
3332
#endif
 
3333
                        xt_dl_log_status(self, *dbptr, strbuf);
 
3334
                }
 
3335
        }
 
3336
        else
 
3337
                xt_sb_concat(self, strbuf, "No data logs in use\n");
 
3338
 
 
3339
        freer_(); // xt_ht_unlock(xt_db_open_databases)
 
3340
}
 
3341
 
 
3342
/*
 
3343
 * -----------------------------------------------------------------------
 
3344
 * MySQL Bit Maps
 
3345
 */
 
3346
 
 
3347
static void myxt_bitmap_init(XTThreadPtr self, MX_BITMAP *map, u_int n_bits)
 
3348
{
 
3349
        my_bitmap_map   *buf;
 
3350
    uint                        size_in_bytes = (((n_bits) + 31) / 32) * 4;
 
3351
 
 
3352
        buf = (my_bitmap_map *) xt_malloc(self, size_in_bytes);
 
3353
 
 
3354
#ifdef DRIZZLED
 
3355
        map->init(buf, n_bits);
 
3356
#else
 
3357
        map->bitmap= buf;
 
3358
        map->n_bits= n_bits;
 
3359
        create_last_word_mask(map);
 
3360
        bitmap_clear_all(map);
 
3361
#endif
 
3362
}
 
3363
 
 
3364
static void myxt_bitmap_free(XTThreadPtr self, MX_BITMAP *map)
 
3365
{
 
3366
#ifdef DRIZZLED
 
3367
        my_bitmap_map *buf = map->getBitmap();
 
3368
        if (buf)
 
3369
                xt_free(self, buf);
 
3370
        map->setBitmap(NULL);
 
3371
#else
 
3372
        if (map->bitmap) {
 
3373
                xt_free(self, map->bitmap);
 
3374
                map->bitmap = NULL;
 
3375
        }
 
3376
#endif
 
3377
}
 
3378
 
 
3379
/*
 
3380
 * -----------------------------------------------------------------------
 
3381
 * XTDDColumnFactory methods
 
3382
 */
 
3383
 
 
3384
XTDDColumn *XTDDColumnFactory::createFromMySQLField(XTThread *self, STRUCT_TABLE *my_tab, Field *field)
 
3385
{
 
3386
        XTDDEnumerableColumn *en_col;
 
3387
        XTDDColumn *col;
 
3388
        xtBool is_enum = FALSE;
 
3389
 
 
3390
        switch(field->real_type()) {
 
3391
                case MYSQL_TYPE_ENUM:
 
3392
                        is_enum = TRUE;
 
3393
                        /* fallthrough */
 
3394
 
 
3395
#ifndef DRIZZLED
 
3396
                case MYSQL_TYPE_SET:
 
3397
#endif
 
3398
                        col = en_col = new XTDDEnumerableColumn();
 
3399
                    if (!col)
 
3400
                                xt_throw_errno(XT_CONTEXT, XT_ENOMEM); 
 
3401
                        col->init(self);
 
3402
                        en_col->enum_size = ((Field_enum *)field)->typelib->count;
 
3403
                        en_col->is_enum = is_enum;
 
3404
                        break;
 
3405
 
 
3406
                default:
 
3407
                        col = new XTDDColumn();
 
3408
                        if (!col)
 
3409
                                xt_throw_errno(XT_CONTEXT, XT_ENOMEM); 
 
3410
                        col->init(self);
 
3411
        }
 
3412
 
 
3413
        col->dc_name = xt_dup_string(self, (char *) field->field_name);
 
3414
        col->dc_data_type = my_type_to_string(self, field, my_tab);
 
3415
        col->dc_null_ok = field->null_ptr != NULL;
 
3416
 
 
3417
        return col;
 
3418
}
 
3419
 
 
3420
/*
 
3421
 * -----------------------------------------------------------------------
 
3422
 * utilities
 
3423
 */
 
3424
 
 
3425
/*
 
3426
 * MySQL (not sure about Drizzle) first calls hton->init and then assigns the plugin a thread slot
 
3427
 * which is used by xt_get_self(). This is a problem as pbxt_init() starts a number of daemon threads
 
3428
 * which could try to use the slot before it is assigned. This code waits till slot is inited.
 
3429
 * We cannot directly check hton->slot as in some versions of MySQL it can be 0 before init which is a 
 
3430
 * valid value.
 
3431
 */
 
3432
extern ulong total_ha;
 
3433
 
 
3434
xtPublic void myxt_wait_pbxt_plugin_slot_assigned(XTThread *self)
 
3435
{
 
3436
#ifdef DRIZZLED
 
3437
        static std::string plugin_name("PBXT");
 
3438
 
 
3439
        while (!self->t_quit && !module::Registry::singleton().find(plugin_name))
 
3440
                xt_sleep_milli_second(1);
 
3441
#else
 
3442
        while(!self->t_quit && (pbxt_hton->slot >= total_ha))
 
3443
                xt_sleep_milli_second(1);
 
3444
#endif
 
3445
}