1
/* Copyright (C) 2005 PrimeBase Technologies GmbH
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
* 2006-05-16 Paul McCullagh
23
* These functions implement the parts of PBXT which must conform to the
24
* key and row format used by MySQL.
27
#include "xt_config.h"
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
#include <boost/filesystem.hpp>
48
//extern "C" struct charset_info_st *session_charset(Session *session);
49
extern pthread_key_t THR_Session;
51
namespace fs=boost::filesystem;
52
using namespace drizzled;
54
#include "mysql_priv.h"
55
#include <mysql/plugin.h>
66
#include "strutil_xt.h"
67
#include "database_xt.h"
69
#include "datalog_xt.h"
70
#include "memory_xt.h"
72
static void myxt_bitmap_init(XTThreadPtr self, MX_BITMAP *map, u_int n_bits);
73
static void myxt_bitmap_free(XTThreadPtr self, MX_BITMAP *map);
76
#define swap_variables(TYPE, a, b) \
85
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
87
#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \
88
(((((uint16) (bit_ptr)[1] << 8) | (uint16) (bit_ptr)[0]) >> (bit_ofs)) & \
89
((1 << (bit_len)) - 1))
92
#define FIX_LENGTH(cs, pos, length, char_length) \
94
if ((length) > char_length) \
95
char_length= my_charpos(cs, pos, pos+length, char_length); \
96
set_if_smaller(char_length,length); \
99
#ifdef store_key_length_inc
100
#undef store_key_length_inc
102
#define store_key_length_inc(key,length) \
103
{ if ((length) < 255) \
104
{ *(key)++=(length); } \
106
{ *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
109
#define set_rec_bits(bits, bit_ptr, bit_ofs, bit_len) \
111
(bit_ptr)[0]= ((bit_ptr)[0] & ~(((1 << (bit_len)) - 1) << (bit_ofs))) | \
112
((bits) << (bit_ofs)); \
113
if ((bit_ofs) + (bit_len) > 8) \
114
(bit_ptr)[1]= ((bit_ptr)[1] & ~((1 << ((bit_len) - 8 + (bit_ofs))) - 1)) | \
115
((bits) >> (8 - (bit_ofs))); \
118
#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
119
set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
122
static const char hexchars[]= "0123456789abcdef";
124
static bool tablename_to_filename(const char *from, char *to, size_t to_length)
128
for (; *from && length < to_length; length++, from++)
130
if ((*from >= '0' && *from <= '9') ||
131
(*from >= 'A' && *from <= 'Z') ||
132
(*from >= 'a' && *from <= 'z') ||
133
/* OSX defines an extra set of high-bit and multi-byte characters
134
that cannot be used on the filesystem. Instead of trying to sort
135
those out, we'll just escape encode all high-bit-set chars on OSX.
136
It won't really hurt anything - it'll just make some filenames ugly. */
137
#if !defined(TARGET_OS_OSX)
138
((unsigned char)*from >= 128) ||
148
if (length + 3 >= to_length)
151
/* We need to escape this char in a way that can be reversed */
153
to[length++]= hexchars[(*from >> 4) & 15];
154
to[length]= hexchars[(*from) & 15];
157
if (/*internal::check_if_legal_tablename(to) &&*/
158
length + 4 < to_length)
160
memcpy(to + length, "@@@", 4);
167
static ulong my_calc_blob_length(uint length, xtWord1 *pos)
171
return (uint) (uchar) *pos;
173
return (uint) uint2korr(pos);
175
return uint3korr(pos);
177
return uint4korr(pos);
181
return 0; /* Impossible */
184
static void my_store_blob_length(byte *pos,uint pack_length,uint length)
186
switch (pack_length) {
188
*pos= (uchar) length;
191
int2store(pos,length);
194
int3store(pos,length);
197
int4store(pos,length);
204
static int my_compare_text(MX_CONST_CHARSET_INFO *charset_info, uchar *a, uint a_length,
205
uchar *b, uint b_length, my_bool part_key,
206
my_bool XT_UNUSED(skip_end_space))
209
/* The last parameter is diff_if_only_endspace_difference, which means
210
* that end spaces are not ignored. We actually always want
211
* to ignore end spaces!
213
return charset_info->coll->strnncollsp(charset_info, a, a_length,
214
b, b_length, /*(my_bool)!skip_end_space*/0);
215
return charset_info->coll->strnncoll(charset_info, a, a_length,
216
b, b_length, part_key);
220
* -----------------------------------------------------------------------
225
* Derived from _mi_pack_key()
227
xtPublic u_int myxt_create_key_from_key(XTIndexPtr ind, xtWord1 *key, xtWord1 *old, u_int k_length)
229
xtWord1 *start_key = key;
230
XTIndexSegRec *keyseg = ind->mi_seg;
232
for (u_int i=0; i<ind->mi_seg_count && (int) k_length > 0; i++, old += keyseg->length, keyseg++)
235
enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type;
237
u_int length = keyseg->length < k_length ? keyseg->length : k_length;
240
MX_CONST_CHARSET_INFO *cs = keyseg->charset;
242
if (keyseg->null_bit) {
244
if (!(*key++ = (xtWord1) 1 - *old++)) { /* Copy null marker */
246
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
247
k_length -= 2; /* Skip length */
250
continue; /* Found NULL */
253
char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
255
if (keyseg->flag & HA_SPACE_PACK) {
256
uchar *end = pos + length;
258
if (type != HA_KEYTYPE_NUM) {
260
while (end > pos && end[-1] == ' ')
265
while (pos < end && pos[0] == ' ')
270
length = (u_int) (end-pos);
271
FIX_LENGTH(cs, pos, length, char_length);
272
store_key_length_inc(key, char_length);
273
memcpy((byte*) key,pos,(size_t) char_length);
277
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
278
/* Length of key-part used with mi_rkey() always 2 */
279
u_int tmp_length = uint2korr(pos);
280
k_length -= 2 + length;
282
set_if_smaller(length, tmp_length); /* Safety */
283
FIX_LENGTH(cs, pos, length, char_length);
284
store_key_length_inc(key,char_length);
285
old +=2; /* Skip length */
286
memcpy((char *) key, pos, (size_t) char_length);
290
if (keyseg->flag & HA_SWAP_KEY)
291
{ /* Numerical column */
299
FIX_LENGTH(cs, pos, length, char_length);
300
memcpy((byte*) key, pos, char_length);
301
if (length > char_length)
302
cs->cset->fill(cs, (char *) (key + char_length), length - char_length, ' ');
307
return (u_int) (key - start_key);
310
/* Derived from _mi_make_key */
311
xtPublic u_int myxt_create_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, xtBool *no_duplicate)
313
register XTIndexSegRec *keyseg = ind->mi_seg;
320
memset((byte*) key, 0,(size_t) (ind->mi_key_size) );
325
memset((byte*) key, 0,(size_t) (ind->mi_key_size) );
329
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++)
332
enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type;
334
u_int length = keyseg->length;
336
MX_CONST_CHARSET_INFO *cs = keyseg->charset;
338
if (keyseg->null_bit) {
339
if (record[keyseg->null_pos] & keyseg->null_bit) {
340
*key++ = 0; /* NULL in key */
342
/* The point is, if a key contains a NULL value
343
* the duplicate checking must be disabled.
344
* This is because a NULL value is not considered
345
* equal to any other value.
348
*no_duplicate = FALSE;
351
*key++ = 1; /* Not NULL */
354
char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length);
356
pos = record + keyseg->start;
358
if (type == HA_KEYTYPE_BIT)
360
if (keyseg->bit_length)
362
uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos,
363
keyseg->bit_start, keyseg->bit_length);
367
memcpy((byte*) key, pos, length);
372
if (keyseg->flag & HA_SPACE_PACK)
376
if (type != HA_KEYTYPE_NUM) {
378
while (end > pos && end[-1] == ' ')
383
while (pos < end && pos[0] == ' ')
387
length = (u_int) (end-pos);
388
FIX_LENGTH(cs, pos, length, char_length);
389
store_key_length_inc(key,char_length);
390
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
394
if (keyseg->flag & HA_VAR_LENGTH_PART) {
395
uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
396
uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
398
pos += pack_length; /* Skip VARCHAR length */
399
set_if_smaller(length,tmp_length);
400
FIX_LENGTH(cs, pos, length, char_length);
401
store_key_length_inc(key,char_length);
402
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
406
if (keyseg->flag & HA_BLOB_PART)
408
u_int tmp_length = my_calc_blob_length(keyseg->bit_start, pos);
409
memcpy((byte*) &pos,pos+keyseg->bit_start,sizeof(char*));
410
set_if_smaller(length,tmp_length);
411
FIX_LENGTH(cs, pos, length, char_length);
412
store_key_length_inc(key,char_length);
413
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
417
if (keyseg->flag & HA_SWAP_KEY)
418
{ /* Numerical column */
421
if (type == HA_KEYTYPE_FLOAT)
427
/* Replace NAN with zero */
435
if (type == HA_KEYTYPE_DOUBLE) {
452
FIX_LENGTH(cs, pos, length, char_length);
453
memcpy((byte*) key, pos, char_length);
454
if (length > char_length)
455
cs->cset->fill(cs, (char *) key + char_length, length - char_length, ' ');
459
return ind->mi_fix_key ? ind->mi_key_size : (u_int) (key - start); /* Return keylength */
462
xtPublic u_int myxt_create_foreign_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, XTIndexPtr fkey_ind, xtBool *no_null)
464
register XTIndexSegRec *keyseg = ind->mi_seg;
465
register XTIndexSegRec *fkey_keyseg = fkey_ind->mi_seg;
471
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++, fkey_keyseg++)
474
enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type;
476
u_int length = keyseg->length;
478
MX_CONST_CHARSET_INFO *cs = keyseg->charset;
479
xtBool is_null = FALSE;
481
if (keyseg->null_bit) {
482
if (record[keyseg->null_pos] & keyseg->null_bit) {
489
if (fkey_keyseg->null_bit) {
491
*key++ = 0; /* NULL in key */
493
/* The point is, if a key contains a NULL value
494
* the duplicate checking must be disabled.
495
* This is because a NULL value is not considered
496
* equal to any other value.
500
*key++ = 1; /* Not NULL */
503
char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length);
505
pos = record + keyseg->start;
507
if (type == HA_KEYTYPE_BIT)
509
if (keyseg->bit_length)
511
uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos,
512
keyseg->bit_start, keyseg->bit_length);
516
memcpy((byte*) key, pos, length);
521
if (keyseg->flag & HA_SPACE_PACK)
525
if (type != HA_KEYTYPE_NUM) {
527
while (end > pos && end[-1] == ' ')
532
while (pos < end && pos[0] == ' ')
536
length = (u_int) (end-pos);
537
FIX_LENGTH(cs, pos, length, char_length);
538
store_key_length_inc(key,char_length);
539
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
543
if (keyseg->flag & HA_VAR_LENGTH_PART) {
544
uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
545
uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
547
pos += pack_length; /* Skip VARCHAR length */
548
set_if_smaller(length,tmp_length);
549
FIX_LENGTH(cs, pos, length, char_length);
550
store_key_length_inc(key,char_length);
551
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
555
if (keyseg->flag & HA_BLOB_PART)
557
u_int tmp_length = my_calc_blob_length(keyseg->bit_start, pos);
558
memcpy((byte*) &pos,pos+keyseg->bit_start,sizeof(char*));
559
set_if_smaller(length,tmp_length);
560
FIX_LENGTH(cs, pos, length, char_length);
561
store_key_length_inc(key,char_length);
562
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
566
if (keyseg->flag & HA_SWAP_KEY)
567
{ /* Numerical column */
570
if (type == HA_KEYTYPE_FLOAT)
576
/* Replace NAN with zero */
584
if (type == HA_KEYTYPE_DOUBLE) {
601
FIX_LENGTH(cs, pos, length, char_length);
602
memcpy((byte*) key, pos, char_length);
603
if (length > char_length)
604
cs->cset->fill(cs, (char *) key + char_length, length - char_length, ' ');
608
return (u_int) (key - start);
611
/* I may be overcautious here, but can I assume that
612
* null_ptr refers to my buffer. If I cannot, then I
613
* cannot use the set_notnull() method.
615
static void mx_set_notnull_in_record(STRUCT_TABLE *table, Field *field, char *record)
618
record[(uint) (field->null_ptr - (uchar *) table->getDefaultValues())] &= (uchar) ~field->null_bit;
621
static xtBool mx_is_null_in_record(STRUCT_TABLE *table, Field *field, char *record)
623
if (field->null_ptr) {
624
if (record[(uint) (field->null_ptr - (uchar *) table->getDefaultValues())] & (uchar) field->null_bit)
631
* PBXT uses a completely different disk format to MySQL so I need a
632
* method that just returns the byte length and
633
* pointer to the data in a row.
635
static char *mx_get_length_and_data(STRUCT_TABLE *table, Field *field, char *dest, xtWord4 *len)
639
from = dest + field->offset(table->getDefaultValues());
640
switch (field->real_type()) {
642
case MYSQL_TYPE_TINY_BLOB:
643
case MYSQL_TYPE_MEDIUM_BLOB:
644
case MYSQL_TYPE_LONG_BLOB:
646
case MYSQL_TYPE_BLOB: {
647
/* TODO - Check: this was the original comment: I must set
648
* *data to non-NULL value, *data == 0, means SQL NULL value.
652
/* GOTCHA: There is no way this can work! field is shared
654
char *save = field->ptr;
656
field->ptr = (char *) from;
657
((Field_blob *) field)->get_ptr(&data);
658
field->ptr = save; // Restore org row pointer
661
xtWord4 packlength = ((Field_blob *) field)->pack_length_no_ptr();
663
memcpy(&data, ((char *) from)+packlength, sizeof(char*));
665
//*len = ((Field_blob *) field)->get_length((byte *) from);
666
*len = ((Field_blob *) field)->get_length((byte *) from, GET_TABLE_SHARE(table)->db_low_byte_first);
670
case MYSQL_TYPE_STRING:
671
/* To write this function you would think Field_string::pack
672
* would serve as a good example, but as far as I can tell
673
* it has a bug: the test from[length-1] == ' ' assumes
676
* But this is not relevant because I believe lengthsp
677
* will give me the correct answer!
679
*len = field->charset()->cset->lengthsp(field->charset(), from, field->field_length);
681
case MYSQL_TYPE_VAR_STRING: {
682
uint length=uint2korr(from);
685
return from+HA_KEY_BLOB_LENGTH;
688
case MYSQL_TYPE_VARCHAR: {
691
if (((Field_varstring *) field)->pack_length_no_ptr() == 1)
692
length = *((unsigned char *) from);
694
length = uint2korr(from);
697
return from+((Field_varstring *) field)->pack_length_no_ptr();
700
case MYSQL_TYPE_DECIMAL:
701
case MYSQL_TYPE_TINY:
702
case MYSQL_TYPE_SHORT:
703
case MYSQL_TYPE_LONG:
704
case MYSQL_TYPE_FLOAT:
705
case MYSQL_TYPE_DOUBLE:
706
case MYSQL_TYPE_NULL:
707
case MYSQL_TYPE_TIMESTAMP:
708
case MYSQL_TYPE_LONGLONG:
709
case MYSQL_TYPE_INT24:
710
case MYSQL_TYPE_DATE:
711
case MYSQL_TYPE_TIME:
712
case MYSQL_TYPE_DATETIME:
713
case MYSQL_TYPE_YEAR:
714
case MYSQL_TYPE_NEWDATE:
716
case MYSQL_TYPE_NEWDECIMAL:
717
case MYSQL_TYPE_ENUM:
719
case MYSQL_TYPE_GEOMETRY:
721
case DRIZZLE_TYPE_LONG:
722
case DRIZZLE_TYPE_DOUBLE:
723
case DRIZZLE_TYPE_NULL:
724
case DRIZZLE_TYPE_TIMESTAMP:
725
case DRIZZLE_TYPE_LONGLONG:
726
case DRIZZLE_TYPE_DATETIME:
727
case DRIZZLE_TYPE_TIME:
728
case DRIZZLE_TYPE_DATE:
729
case DRIZZLE_TYPE_DECIMAL:
730
case DRIZZLE_TYPE_ENUM:
731
case DRIZZLE_TYPE_UUID:
736
*len = field->pack_length();
741
* Set the length and data value of a field.
743
* If input data is NULL this is a NULL value. In this case
744
* we assume the null bit has been set and prepared
745
* the field as follows:
747
* According to the InnoDB implementation, we need
748
* to zero out the field data...
749
* "MySQL seems to assume the field for an SQL NULL
750
* value is set to zero or space. Not taking this into
751
* account caused seg faults with NULL BLOB fields, and
752
* bug number 154 in the MySQL bug database: GROUP BY
753
* and DISTINCT could treat NULL values inequal".
755
static void mx_set_length_and_data(STRUCT_TABLE *table, Field *field, char *dest, xtWord4 len, char *data)
759
from = dest + field->offset(table->getDefaultValues());
760
switch (field->real_type()) {
762
case MYSQL_TYPE_TINY_BLOB:
763
case MYSQL_TYPE_MEDIUM_BLOB:
764
case MYSQL_TYPE_LONG_BLOB:
766
case MYSQL_TYPE_BLOB: {
767
/* GOTCHA: There is no way that this can work.
768
* field is shared, because table is shared!
769
char *save = field->ptr;
771
field->ptr = (char *) from;
772
((Field_blob *) field)->set_ptr(len, data);
773
field->ptr = save; // Restore org row pointer
775
xtWord4 packlength = ((Field_blob *) field)->pack_length_no_ptr();
777
((Field_blob *) field)->store_length((byte *) from, len, GET_TABLE_SHARE(table)->db_low_byte_first);
778
memcpy_fixed(((char *) from)+packlength, &data, sizeof(char*));
781
mx_set_notnull_in_record(table, field, dest);
785
case MYSQL_TYPE_STRING:
787
mx_set_notnull_in_record(field, dest);
788
memcpy(from, data, len);
793
/* And I think that fill will do this for me... */
794
field->charset()->cset->fill(field->charset(), from + len, field->field_length - len, ' ');
796
case MYSQL_TYPE_VAR_STRING:
797
int2store(from, len);
799
mx_set_notnull_in_record(field, dest);
800
memcpy(from+HA_KEY_BLOB_LENGTH, data, len);
804
case MYSQL_TYPE_VARCHAR:
805
if (((Field_varstring *) field)->pack_length_no_ptr() == 1)
806
*((unsigned char *) from) = (unsigned char) len;
808
int2store(from, len);
810
mx_set_notnull_in_record(table, field, dest);
811
memcpy(from+((Field_varstring *) field)->pack_length_no_ptr(), data, len);
815
case MYSQL_TYPE_DECIMAL:
816
case MYSQL_TYPE_TINY:
817
case MYSQL_TYPE_SHORT:
818
case MYSQL_TYPE_LONG:
819
case MYSQL_TYPE_FLOAT:
820
case MYSQL_TYPE_DOUBLE:
821
case MYSQL_TYPE_NULL:
822
case MYSQL_TYPE_TIMESTAMP:
823
case MYSQL_TYPE_LONGLONG:
824
case MYSQL_TYPE_INT24:
825
case MYSQL_TYPE_DATE:
826
case MYSQL_TYPE_TIME:
827
case MYSQL_TYPE_DATETIME:
828
case MYSQL_TYPE_YEAR:
829
case MYSQL_TYPE_NEWDATE:
831
case MYSQL_TYPE_NEWDECIMAL:
832
case MYSQL_TYPE_ENUM:
834
case MYSQL_TYPE_GEOMETRY:
836
case DRIZZLE_TYPE_LONG:
837
case DRIZZLE_TYPE_DOUBLE:
838
case DRIZZLE_TYPE_NULL:
839
case DRIZZLE_TYPE_TIMESTAMP:
840
case DRIZZLE_TYPE_LONGLONG:
841
case DRIZZLE_TYPE_DATETIME:
842
case DRIZZLE_TYPE_TIME:
843
case DRIZZLE_TYPE_DATE:
844
case DRIZZLE_TYPE_DECIMAL:
845
case DRIZZLE_TYPE_ENUM:
846
case DRIZZLE_TYPE_UUID:
852
mx_set_notnull_in_record(table, field, dest);
853
memcpy(from, data, len);
856
bzero(from, field->pack_length());
859
xtPublic void myxt_set_null_row_from_key(XTOpenTablePtr XT_UNUSED(ot), XTIndexPtr ind, xtWord1 *record)
861
register XTIndexSegRec *keyseg = ind->mi_seg;
863
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
864
ASSERT_NS(keyseg->null_bit);
865
record[keyseg->null_pos] |= keyseg->null_bit;
869
xtPublic void myxt_set_default_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *record)
871
XTTableHPtr tab = ot->ot_table;
872
STRUCT_TABLE *table = tab->tab_dic.dic_my_table;
873
XTIndexSegRec *keyseg = ind->mi_seg;
875
xt_lock_mutex_ns(&tab->tab_dic_field_lock);
877
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
879
u_int col_idx = keyseg->col_idx;
880
Field *field = GET_TABLE_FIELDS(table)[col_idx];
881
byte *field_save = field->ptr;
883
field->ptr = GET_TABLE_SHARE(table)->getDefaultValues() + keyseg->start;
884
memcpy(record + keyseg->start, field->ptr, field->pack_length());
885
record[keyseg->null_pos] &= ~keyseg->null_bit;
886
record[keyseg->null_pos] |= GET_TABLE_SHARE(table)->getDefaultValues()[keyseg->null_pos] & keyseg->null_bit;
888
field->ptr = field_save;
891
xt_unlock_mutex_ns(&tab->tab_dic_field_lock);
894
/* Derived from _mi_put_key_in_record */
895
xtPublic xtBool myxt_create_row_from_key(XTOpenTablePtr XT_UNUSED(ot), XTIndexPtr ind, xtWord1 *b_value, u_int key_len, xtWord1 *dest_buff)
897
byte *record = (byte *) dest_buff;
900
register XTIndexSegRec *keyseg = ind->mi_seg;
902
/* GOTCHA: When selecting from multiple
903
* indexes the key values are "merged" into the
905
* This means that this function must not affect
906
* the value of any other feilds.
908
* I was setting all to NULL:
909
memset(dest_buff, 0xFF, GET_TABLE_SHARE(table)->null_bytes);
911
key = (byte *) b_value;
912
key_end = key + key_len;
913
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
914
if (keyseg->null_bit) {
917
record[keyseg->null_pos] |= keyseg->null_bit;
920
record[keyseg->null_pos] &= ~keyseg->null_bit;
923
if (keyseg->type == HA_KEYTYPE_BIT)
925
uint length = keyseg->length;
927
if (keyseg->bit_length)
930
set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
936
clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
939
memcpy(record + keyseg->start, (byte*) key, length);
944
if (keyseg->flag & HA_SPACE_PACK)
947
get_key_length(length,key);
949
if (length > keyseg->length || key+length > key_end)
952
pos = record+keyseg->start;
954
if (keyseg->type != (int) HA_KEYTYPE_NUM)
957
memcpy(pos,key,(size_t) length);
958
bfill(pos+length,keyseg->length-length,' ');
963
bfill(pos,keyseg->length-length,' ');
964
memcpy(pos+keyseg->length-length,key,(size_t) length);
971
if (keyseg->flag & HA_VAR_LENGTH_PART)
974
get_key_length(length,key);
976
if (length > keyseg->length || key+length > key_end)
979
/* Store key length */
980
if (keyseg->bit_start == 1)
981
*(uchar*) (record+keyseg->start)= (uchar) length;
983
int2store(record+keyseg->start, length);
985
memcpy(record+keyseg->start + keyseg->bit_start, (byte*) key, length);
988
else if (keyseg->flag & HA_BLOB_PART)
991
get_key_length(length,key);
993
if (length > keyseg->length || key+length > key_end)
996
/* key is a pointer into ot_ind_rbuf, which should be
997
* safe until we move to the next index item!
999
byte *key_ptr = key; // Cannot take the address of a register variable!
1000
memcpy(record+keyseg->start+keyseg->bit_start,
1001
(char*) &key_ptr,sizeof(char*));
1003
my_store_blob_length(record+keyseg->start,
1004
(uint) keyseg->bit_start,length);
1007
else if (keyseg->flag & HA_SWAP_KEY)
1009
byte *to= record+keyseg->start+keyseg->length;
1010
byte *end= key+keyseg->length;
1017
} while (key != end);
1023
if (key+keyseg->length > key_end)
1026
memcpy(record+keyseg->start,(byte*) key,
1027
(size_t) keyseg->length);
1028
key+= keyseg->length;
1036
return FAILED; /* Crashed row */
1041
* -----------------------------------------------------------------------
1045
static int my_compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
1046
my_bool part_key, my_bool skip_end_space)
1048
uint length= a_length < b_length ? a_length : b_length;
1049
uchar *end= a+ length;
1053
if ((flag= (int) *a++ - (int) *b++))
1055
if (part_key && b_length < a_length)
1057
if (skip_end_space && a_length != b_length)
1061
We are using space compression. We have to check if longer key
1062
has next character < ' ', in which case it's less than the shorter
1063
key that has an implicite space afterwards.
1065
This code is identical to the one in
1066
strings/ctype-simple.c:my_strnncollsp_simple
1068
if (a_length < b_length)
1070
/* put shorter key in a */
1073
swap= -1; /* swap sign of result */
1075
for (end= a + a_length-length; a < end ; a++)
1078
return (*a < ' ') ? -swap : swap;
1082
return (int) (a_length-b_length);
1085
xtPublic u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *key_buf)
1087
register XTIndexSegRec *keyseg = ind->mi_seg;
1088
register uchar *key_data = (uchar *) key_buf;
1092
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
1093
/* Handle NULL part */
1094
if (keyseg->null_bit) {
1099
switch ((enum ha_base_keytype) keyseg->type) {
1100
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
1101
if (keyseg->flag & HA_SPACE_PACK) {
1102
get_key_pack_length(seg_len, pack_len, key_data);
1105
seg_len = keyseg->length;
1106
key_data += seg_len;
1108
case HA_KEYTYPE_BINARY:
1109
if (keyseg->flag & HA_SPACE_PACK) {
1110
get_key_pack_length(seg_len, pack_len, key_data);
1113
seg_len = keyseg->length;
1114
key_data += seg_len;
1116
case HA_KEYTYPE_VARTEXT1:
1117
case HA_KEYTYPE_VARTEXT2:
1118
get_key_pack_length(seg_len, pack_len, key_data);
1119
key_data += seg_len;
1121
case HA_KEYTYPE_VARBINARY1:
1122
case HA_KEYTYPE_VARBINARY2:
1123
get_key_pack_length(seg_len, pack_len, key_data);
1124
key_data += seg_len;
1127
case HA_KEYTYPE_NUM: {
1129
if (keyseg->flag & HA_SPACE_PACK)
1130
seg_len = *key_data++;
1132
seg_len = keyseg->length;
1133
key_data += seg_len;
1136
case HA_KEYTYPE_INT8:
1137
case HA_KEYTYPE_SHORT_INT:
1138
case HA_KEYTYPE_USHORT_INT:
1139
case HA_KEYTYPE_INT24:
1140
case HA_KEYTYPE_FLOAT:
1141
case HA_KEYTYPE_BIT:
1143
case HA_KEYTYPE_LONG_INT:
1144
case HA_KEYTYPE_ULONG_INT:
1145
case HA_KEYTYPE_DOUBLE:
1146
case HA_KEYTYPE_LONGLONG:
1147
case HA_KEYTYPE_ULONGLONG:
1148
key_data += keyseg->length;
1150
case HA_KEYTYPE_END:
1156
u_int ilen = (xtWord1 *) key_data - key_buf;
1157
if (ilen > XT_INDEX_MAX_KEY_SIZE)
1158
ind->mi_key_corrupted = TRUE;
1162
/* Derived from ha_key_cmp */
1163
xtPublic int myxt_compare_key(XTIndexPtr ind, int search_flags, uint key_length, xtWord1 *key_value, xtWord1 *b_value)
1165
register XTIndexSegRec *keyseg = ind->mi_seg;
1167
register uchar *a = (uchar *) key_value;
1169
register uchar *b = (uchar *) b_value;
1171
uint next_key_length;
1176
for (uint i=0; i < ind->mi_seg_count && (int) key_length > 0; key_length = next_key_length, keyseg++, i++) {
1177
piks = !(keyseg->flag & HA_NO_SORT);
1179
/* Handle NULL part */
1180
if (keyseg->null_bit) {
1181
/* 1 is not null, 0 is null */
1182
int b_not_null = (int) *b++;
1185
if ((int) *a != b_not_null && piks)
1187
flag = (int) *a - b_not_null;
1188
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1191
/* If key was NULL */
1192
if (search_flags == (SEARCH_FIND | SEARCH_UPDATE))
1193
search_flags = SEARCH_SAME; /* Allow duplicate keys */
1194
else if (search_flags & SEARCH_NULL_ARE_NOT_EQUAL)
1197
* This is only used from mi_check() to calculate cardinality.
1198
* It can't be used when searching for a key as this would cause
1199
* compare of (a,b) and (b,a) to return the same value.
1203
/* PMC - I don't know why I had next_key_length = key_length - keyseg->length;
1204
* This was my comment: even when null we have the complete length
1206
* The truth is, a NULL only takes up one byte in the key, and this has already
1209
next_key_length = key_length;
1210
continue; /* To next key part */
1214
/* Both components are not null... */
1215
if (keyseg->length < key_length) {
1216
end = a + keyseg->length;
1217
next_key_length = key_length - keyseg->length;
1220
end = a + key_length;
1221
next_key_length = 0;
1224
switch ((enum ha_base_keytype) keyseg->type) {
1225
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
1226
if (keyseg->flag & HA_SPACE_PACK) {
1227
get_key_pack_length(a_length, pack_len, a);
1228
next_key_length = key_length - a_length - pack_len;
1229
get_key_pack_length(b_length, pack_len, b);
1231
if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length,
1232
(my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0),
1233
(my_bool)!(search_flags & SEARCH_PREFIX))))
1234
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1238
a_length = (uint) (end - a);
1239
b_length = keyseg->length;
1240
if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length,
1241
(my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0),
1242
(my_bool)!(search_flags & SEARCH_PREFIX))))
1243
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1248
case HA_KEYTYPE_BINARY:
1249
if (keyseg->flag & HA_SPACE_PACK) {
1250
get_key_pack_length(a_length, pack_len, a);
1251
next_key_length = key_length - a_length - pack_len;
1252
get_key_pack_length(b_length, pack_len, b);
1254
if (piks && (flag = my_compare_bin(a, a_length, b, b_length,
1255
(my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 1)))
1256
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1259
a_length = keyseg->length;
1260
b_length = keyseg->length;
1261
if (piks && (flag = my_compare_bin(a, a_length, b, b_length,
1262
(my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 0)))
1263
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1268
case HA_KEYTYPE_VARTEXT1:
1269
case HA_KEYTYPE_VARTEXT2:
1271
get_key_pack_length(a_length, pack_len, a);
1272
next_key_length = key_length - a_length - pack_len;
1273
get_key_pack_length(b_length, pack_len, b);
1275
if (piks && (flag = my_compare_text(keyseg->charset, a, a_length, b, b_length,
1276
(my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0),
1277
(my_bool) ((search_flags & (SEARCH_FIND | SEARCH_UPDATE)) == SEARCH_FIND))))
1278
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1283
case HA_KEYTYPE_VARBINARY1:
1284
case HA_KEYTYPE_VARBINARY2:
1286
get_key_pack_length(a_length, pack_len, a);
1287
next_key_length = key_length - a_length - pack_len;
1288
get_key_pack_length(b_length, pack_len, b);
1290
if (piks && (flag=my_compare_bin(a, a_length, b, b_length,
1291
(my_bool) ((search_flags & SEARCH_PREFIX) && next_key_length <= 0), 0)))
1292
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1298
case HA_KEYTYPE_INT8:
1300
int i_1 = (int) *((signed char *) a);
1301
int i_2 = (int) *((signed char *) b);
1302
if (piks && (flag = CMP_NUM(i_1,i_2)))
1303
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1305
b += keyseg->length;
1308
case HA_KEYTYPE_SHORT_INT: {
1309
int16_t s_1 = sint2korr(a);
1310
int16_t s_2 = sint2korr(b);
1311
if (piks && (flag = CMP_NUM(s_1, s_2)))
1312
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1314
b += keyseg->length;
1317
case HA_KEYTYPE_USHORT_INT: {
1318
uint16_t us_1= sint2korr(a);
1319
uint16_t us_2= sint2korr(b);
1320
if (piks && (flag = CMP_NUM(us_1, us_2)))
1321
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1323
b += keyseg->length;
1327
case HA_KEYTYPE_LONG_INT: {
1328
int32_t l_1 = sint4korr(a);
1329
int32_t l_2 = sint4korr(b);
1330
if (piks && (flag = CMP_NUM(l_1, l_2)))
1331
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1333
b += keyseg->length;
1336
case HA_KEYTYPE_ULONG_INT: {
1337
uint32_t u_1 = sint4korr(a);
1338
uint32_t u_2 = sint4korr(b);
1339
if (piks && (flag = CMP_NUM(u_1, u_2)))
1340
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1342
b += keyseg->length;
1346
case HA_KEYTYPE_INT24: {
1347
int32 l_1 = sint3korr(a);
1348
int32 l_2 = sint3korr(b);
1349
if (piks && (flag = CMP_NUM(l_1, l_2)))
1350
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1352
b += keyseg->length;
1355
case HA_KEYTYPE_UINT24: {
1356
int32_t l_1 = uint3korr(a);
1357
int32_t l_2 = uint3korr(b);
1358
if (piks && (flag = CMP_NUM(l_1, l_2)))
1359
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1361
b += keyseg->length;
1364
case HA_KEYTYPE_FLOAT: {
1370
* The following may give a compiler warning about floating point
1371
* comparison not being safe, but this is ok in this context as
1372
* we are bascily doing sorting
1374
if (piks && (flag = CMP_NUM(f_1, f_2)))
1375
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1377
b += keyseg->length;
1381
case HA_KEYTYPE_DOUBLE: {
1387
* The following may give a compiler warning about floating point
1388
* comparison not being safe, but this is ok in this context as
1389
* we are bascily doing sorting
1391
if (piks && (flag = CMP_NUM(d_1, d_2)))
1392
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1394
b += keyseg->length;
1398
case HA_KEYTYPE_NUM: {
1400
if (keyseg->flag & HA_SPACE_PACK) {
1403
next_key_length = key_length - a_length - 1;
1407
a_length = (int) (end - a);
1408
b_length = keyseg->length;
1411
/* remove pre space from keys */
1412
for ( ; a_length && *a == ' ' ; a++, a_length--) ;
1413
for ( ; b_length && *b == ' ' ; b++, b_length--) ;
1415
if (keyseg->flag & HA_REVERSE_SORT) {
1416
swap_variables(uchar *, a, b);
1417
swap_variables(uint, a_length, b_length);
1425
swap_variables(uchar *, a, b);
1426
swap_variables(uint, a_length, b_length);
1427
a_length--; b_length--;
1431
while (a_length && (*a == '+' || *a == '0')) {
1435
while (b_length && (*b == '+' || *b == '0')) {
1439
if (a_length != b_length)
1440
return (a_length < b_length) ? -1 : 1;
1443
return ((int) a[-1] - (int) b[-1]);
1452
#ifdef HAVE_LONG_LONG
1453
case HA_KEYTYPE_LONGLONG: {
1454
longlong ll_a = sint8korr(a);
1455
longlong ll_b = sint8korr(b);
1456
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
1457
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1459
b += keyseg->length;
1462
case HA_KEYTYPE_ULONGLONG: {
1463
ulonglong ll_a = uint8korr(a);
1464
ulonglong ll_b = uint8korr(b);
1465
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
1466
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1468
b += keyseg->length;
1473
case HA_KEYTYPE_BIT:
1474
/* TODO: What here? */
1477
case HA_KEYTYPE_END: /* Ready */
1486
xtPublic u_int myxt_key_seg_length(XTIndexSegRec *keyseg, u_int key_offset, xtWord1 *key_value)
1488
register xtWord1 *a = (xtWord1 *) key_value + key_offset;
1491
u_int key_length = 0;
1494
/* Handle NULL part */
1495
if (keyseg->null_bit) {
1497
/* If the value is null, then it only requires one byte: */
1502
key_length = has_null + keyseg->length;
1504
switch ((enum ha_base_keytype) keyseg->type) {
1505
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
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;
1511
case HA_KEYTYPE_BINARY:
1512
if (keyseg->flag & HA_SPACE_PACK) {
1513
get_key_pack_length(a_length, pack_len, a);
1514
key_length = has_null + a_length + pack_len;
1517
case HA_KEYTYPE_VARTEXT1:
1518
case HA_KEYTYPE_VARTEXT2:
1519
case HA_KEYTYPE_VARBINARY1:
1520
case HA_KEYTYPE_VARBINARY2: {
1521
get_key_pack_length(a_length, pack_len, a);
1522
key_length = has_null + a_length + pack_len;
1526
case HA_KEYTYPE_INT8:
1527
case HA_KEYTYPE_SHORT_INT:
1528
case HA_KEYTYPE_USHORT_INT:
1529
case HA_KEYTYPE_INT24:
1530
case HA_KEYTYPE_FLOAT:
1531
case HA_KEYTYPE_UINT24:
1533
case HA_KEYTYPE_LONG_INT:
1534
case HA_KEYTYPE_ULONG_INT:
1535
case HA_KEYTYPE_DOUBLE:
1538
case HA_KEYTYPE_NUM: {
1540
if (keyseg->flag & HA_SPACE_PACK) {
1542
key_length = has_null + a_length + 1;
1547
#ifdef HAVE_LONG_LONG
1548
case HA_KEYTYPE_LONGLONG:
1549
case HA_KEYTYPE_ULONGLONG:
1553
case HA_KEYTYPE_BIT:
1554
/* TODO: What here? */
1557
case HA_KEYTYPE_END: /* Ready */
1565
* -----------------------------------------------------------------------
1566
* Load and store rows
1569
xtPublic xtWord4 myxt_store_row_length(XTOpenTablePtr ot, char *rec_buff)
1571
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1575
xtWord4 row_size = 0;
1577
for (Field* const *field=GET_TABLE_FIELDS(table); *field ; field++) {
1578
if ((*field)->is_null_in_record((const uchar *) rec_buff)) {
1584
sdata = mx_get_length_and_data(table, *field, rec_buff, &dlen);
1586
/* Empty, but not null (blobs may return NULL, when
1589
sdata = rec_buff; // Any valid pointer will do
1590
item_size = 1 + dlen;
1592
else if (dlen <= 240)
1593
item_size = 1 + dlen;
1594
else if (dlen <= 0xFFFF)
1595
item_size = 3 + dlen;
1596
else if (dlen <= 0xFFFFFF)
1597
item_size = 4 + dlen;
1599
item_size = 5 + dlen;
1602
row_size += item_size;
1607
xtPublic xtWord4 myxt_store_row_data(XTOpenTablePtr ot, xtWord4 row_size, char *rec_buff)
1609
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1614
for (Field * const* field=GET_TABLE_FIELDS(table); *field; field++) {
1615
if (mx_is_null_in_record(table, *field, rec_buff)) {
1621
sdata = mx_get_length_and_data(table, *field, rec_buff, &dlen);
1623
/* Empty, but not null (blobs may return NULL, when
1626
sdata = rec_buff; // Any valid pointer will do
1627
item_size = 1 + dlen;
1629
else if (dlen <= 240)
1630
item_size = 1 + dlen;
1631
else if (dlen <= 0xFFFF)
1632
item_size = 3 + dlen;
1633
else if (dlen <= 0xFFFFFF)
1634
item_size = 4 + dlen;
1636
item_size = 5 + dlen;
1639
if (row_size + item_size > ot->ot_row_wbuf_size) {
1640
if (!xt_realloc_ns((void **) &ot->ot_row_wbuffer, row_size + item_size))
1642
ot->ot_row_wbuf_size = row_size + item_size;
1646
ot->ot_row_wbuffer[row_size] = 255;
1647
else if (dlen <= 240) {
1648
ot->ot_row_wbuffer[row_size] = (unsigned char) dlen;
1649
memcpy(&ot->ot_row_wbuffer[row_size+1], sdata, dlen);
1651
else if (dlen <= 0xFFFF) {
1652
ot->ot_row_wbuffer[row_size] = 254;
1653
XT_SET_DISK_2(&ot->ot_row_wbuffer[row_size+1], dlen);
1654
memcpy(&ot->ot_row_wbuffer[row_size+3], sdata, dlen);
1656
else if (dlen <= 0xFFFFFF) {
1657
ot->ot_row_wbuffer[row_size] = 253;
1658
XT_SET_DISK_3(&ot->ot_row_wbuffer[row_size+1], dlen);
1659
memcpy(&ot->ot_row_wbuffer[row_size+4], sdata, dlen);
1662
ot->ot_row_wbuffer[row_size] = 252;
1663
XT_SET_DISK_4(&ot->ot_row_wbuffer[row_size+1], dlen);
1664
memcpy(&ot->ot_row_wbuffer[row_size+5], sdata, dlen);
1667
row_size += item_size;
1672
/* Count the number and size of whole columns in the given buffer. */
1673
xtPublic size_t myxt_load_row_length(XTOpenTablePtr ot, size_t buffer_size, xtWord1 *source_buf, u_int *ret_col_cnt)
1680
col_cnt = ot->ot_table->tab_dic.dic_no_of_cols;
1682
col_cnt = *ret_col_cnt;
1683
for (i=0; i<col_cnt; i++) {
1684
if (size + 1 > buffer_size)
1686
switch (*source_buf) {
1687
case 255: // Indicate NULL value
1691
case 254: // 2 bytes length
1692
if (size + 3 > buffer_size)
1694
len = XT_GET_DISK_2(source_buf + 1);
1695
if (size + 3 + len > buffer_size)
1698
source_buf += 3 + len;
1700
case 253: // 3 bytes length
1701
if (size + 4 > buffer_size)
1703
len = XT_GET_DISK_3(source_buf + 1);
1704
if (size + 4 + len > buffer_size)
1707
source_buf += 4 + len;
1709
case 252: // 4 bytes length
1710
if (size + 5 > buffer_size)
1712
len = XT_GET_DISK_4(source_buf + 1);
1713
if (size + 5 + len > buffer_size)
1716
source_buf += 5 + len;
1718
default: // Length byte
1720
if (size + 1 + len > buffer_size)
1723
source_buf += 1 + len;
1734
/* Unload from PBXT variable length format to the MySQL row format. */
1735
xtPublic xtWord4 myxt_load_row_data(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt)
1737
xtWord1 *input_buf = source_buf;
1738
STRUCT_TABLE *table;
1744
if (!(table = ot->ot_table->tab_dic.dic_my_table)) {
1745
xt_register_taberr(XT_REG_CONTEXT, XT_ERR_NO_DICTIONARY, ot->ot_table->tab_name);
1749
/* According to the InnoDB implementation:
1750
* "MySQL assumes that all columns
1751
* have the SQL NULL bit set unless it
1752
* is a nullable column with a non-NULL value".
1754
memset(dest_buff, 0xFF, GET_TABLE_SHARE(table)->null_bytes);
1755
for (Field * const *field=GET_TABLE_FIELDS(table); *field && (!col_cnt || i<col_cnt); field++, i++) {
1756
curr_field = *field;
1758
switch (*source_buf) {
1759
case 255: // Indicate NULL value
1764
case 254: // 2 bytes length
1765
len = XT_GET_DISK_2(source_buf + 1);
1768
case 253: // 3 bytes length
1769
len = XT_GET_DISK_3(source_buf + 1);
1772
case 252: // 4 bytes length
1773
len = XT_GET_DISK_4(source_buf + 1);
1776
default: // Length byte
1777
if (*source_buf > 240) {
1778
xt_register_xterr(XT_REG_CONTEXT, XT_ERR_BAD_RECORD_FORMAT);
1787
mx_set_length_and_data(table, curr_field, (char *) dest_buff, 0, NULL);
1789
mx_set_length_and_data(table, curr_field, (char *) dest_buff, len, (char *) source_buf);
1793
return (xtWord4) (source_buf - input_buf);
1796
xtPublic xtBool myxt_load_row(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt)
1798
return myxt_load_row_data(ot, source_buf, dest_buff, col_cnt) != 0;
1801
xtPublic xtBool myxt_find_column(XTOpenTablePtr ot, u_int *col_idx, const char *col_name)
1803
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1806
for (Field * const *field=GET_TABLE_FIELDS(table); *field; field++, i++) {
1807
if (!my_strcasecmp(system_charset_info, (*field)->field_name, col_name)) {
1815
xtPublic void myxt_get_column_name(XTOpenTablePtr ot, u_int col_idx, u_int len, char *col_name)
1817
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1820
field = GET_TABLE_FIELDS(table)[col_idx];
1821
xt_strcpy(len, col_name, field->field_name);
1824
xtPublic void myxt_get_column_as_string(XTOpenTablePtr ot, char *buffer, u_int col_idx, u_int len, char *value)
1826
XTTableHPtr tab = ot->ot_table;
1827
XTThreadPtr self = ot->ot_thread;
1828
STRUCT_TABLE *table = tab->tab_dic.dic_my_table;
1829
Field *field = GET_TABLE_FIELDS(table)[col_idx];
1830
char buf_val[MAX_FIELD_WIDTH];
1831
String val(buf_val, sizeof(buf_val), &my_charset_bin);
1833
if (mx_is_null_in_record(table, field, buffer))
1834
xt_strcpy(len, value, "NULL");
1839
/* Required by store() - or an assertion will fail: */
1840
if (table->read_set)
1841
MX_BIT_SET(table->read_set, col_idx);
1845
xt_lock_mutex(self, &tab->tab_dic_field_lock);
1846
pushr_(xt_unlock_mutex, &tab->tab_dic_field_lock);
1847
field->ptr = (byte *) buffer + field->offset(table->getDefaultValues());
1848
field->val_str_internal(&val);
1849
field->ptr = save; // Restore org row pointer
1850
freer_(); // xt_unlock_mutex(&tab->tab_dic_field_lock)
1851
xt_strcpy(len, value, val.c_ptr());
1855
xtPublic xtBool myxt_set_column(XTOpenTablePtr ot, char *buffer, u_int col_idx, const char *value, u_int len)
1857
XTTableHPtr tab = ot->ot_table;
1858
XTThreadPtr self = ot->ot_thread;
1859
STRUCT_TABLE *table = tab->tab_dic.dic_my_table;
1860
Field *field = GET_TABLE_FIELDS(table)[col_idx];
1865
/* Required by store() - or an assertion will fail: */
1866
if (table->write_set)
1867
MX_BIT_SET(table->write_set, col_idx);
1870
mx_set_notnull_in_record(table, field, buffer);
1873
xt_lock_mutex(self, &tab->tab_dic_field_lock);
1874
pushr_(xt_unlock_mutex, &tab->tab_dic_field_lock);
1875
field->ptr = (byte *) buffer + field->offset(table->getDefaultValues());
1876
error = field->store(value, len, &my_charset_utf8_general_ci);
1877
field->ptr = save; // Restore org row pointer
1878
freer_(); // xt_unlock_mutex(&tab->tab_dic_field_lock)
1879
return error ? FAILED : OK;
1882
xtPublic void myxt_get_column_data(XTOpenTablePtr ot, char *buffer, u_int col_idx, char **value, size_t *len)
1884
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1885
Field *field = GET_TABLE_FIELDS(table)[col_idx];
1889
sdata = mx_get_length_and_data(table, field, buffer, &dlen);
1894
xtPublic xtBool myxt_store_row(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, char *rec_buff)
1896
if (ot->ot_rec_fixed) {
1897
rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer;
1898
rec_info->ri_rec_buf_size = ot->ot_rec_size;
1899
rec_info->ri_ext_rec = NULL;
1901
rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_FIXED;
1902
memcpy(rec_info->ri_fix_rec_buf->rf_data, rec_buff, ot->ot_rec_size - XT_REC_FIX_HEADER_SIZE);
1907
if (!(row_size = myxt_store_row_data(ot, XT_REC_EXT_HEADER_SIZE, rec_buff)))
1909
if (row_size - XT_REC_FIX_EXT_HEADER_DIFF <= ot->ot_rec_size) {
1910
rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) &ot->ot_row_wbuffer[XT_REC_FIX_EXT_HEADER_DIFF];
1911
rec_info->ri_rec_buf_size = row_size - XT_REC_FIX_EXT_HEADER_DIFF;
1912
rec_info->ri_ext_rec = NULL;
1914
rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_VARIABLE;
1917
rec_info->ri_fix_rec_buf = (XTTabRecFixDPtr) ot->ot_row_wbuffer;
1918
rec_info->ri_rec_buf_size = ot->ot_rec_size;
1919
rec_info->ri_ext_rec = (XTTabRecExtDPtr) ot->ot_row_wbuffer;
1920
rec_info->ri_log_data_size = row_size - ot->ot_rec_size;
1921
rec_info->ri_log_buf = (XTactExtRecEntryDPtr) &ot->ot_row_wbuffer[ot->ot_rec_size - offsetof(XTactExtRecEntryDRec, er_data)];
1923
rec_info->ri_ext_rec->tr_rec_type_1 = XT_TAB_STATUS_EXT_DLOG;
1924
XT_SET_DISK_4(rec_info->ri_ext_rec->re_log_dat_siz_4, rec_info->ri_log_data_size);
1930
static void mx_print_string(uchar *s, uint count)
1933
if (s[count - 1] != ' ')
1938
for (u_int i=0; i<count; i++, s++)
1943
xtPublic void myxt_print_key(XTIndexPtr ind, xtWord1 *key_value)
1945
register XTIndexSegRec *keyseg = ind->mi_seg;
1946
register uchar *b = (uchar *) key_value;
1950
for (u_int i = 0; i < ind->mi_seg_count; i++, keyseg++) {
1953
if (keyseg->null_bit) {
1959
switch ((enum ha_base_keytype) keyseg->type) {
1960
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
1961
if (keyseg->flag & HA_SPACE_PACK) {
1962
get_key_pack_length(b_length, pack_len, b);
1965
b_length = keyseg->length;
1966
mx_print_string(b, b_length);
1969
case HA_KEYTYPE_LONG_INT: {
1970
int32_t l_2 = sint4korr(b);
1971
b += keyseg->length;
1972
printf("%ld", (long) l_2);
1975
case HA_KEYTYPE_ULONG_INT: {
1976
xtWord4 u_2 = sint4korr(b);
1977
b += keyseg->length;
1978
printf("%lu", (u_long) u_2);
1988
* -----------------------------------------------------------------------
1989
* MySQL Data Dictionary
1992
static void my_close_table(STRUCT_TABLE *share)
1998
* This function returns NULL if the table cannot be opened
1999
* because this is not a MySQL thread.
2001
static STRUCT_TABLE *my_open_table(XTThreadPtr self, XTDatabaseHPtr XT_UNUSED(db), XTPathStrPtr tab_path, xtWord1 table_type)
2003
THD *thd = current_thd;
2004
char *tab_file_name;
2005
char database_name[XT_IDENTIFIER_NAME_SIZE];
2006
char tab_name[XT_IDENTIFIER_NAME_SIZE];
2007
uint32_t tab_name_len;
2011
/* If we have no MySQL thread, then we cannot open this table!
2012
* What this means is the thread is probably the sweeper or the
2018
tab_file_name = xt_last_name_of_path(tab_path->ps_path);
2019
tab_name_len = TableIdentifier::filename_to_tablename(tab_file_name, tab_name, XT_IDENTIFIER_NAME_SIZE);
2021
xt_2nd_last_name_of_path(XT_IDENTIFIER_NAME_SIZE, database_name, tab_path->ps_path);
2023
TableIdentifier *ident = NULL;
2025
if (table_type == XT_TABLE_TYPE_TEMPORARY) {
2026
std::string tmp_path(drizzle_tmpdir);
2027
tmp_path.append("/");
2028
tmp_path.append(tab_file_name);
2029
ident = new TableIdentifier(database_name, tab_name, tmp_path);
2031
else if (table_type == XT_TABLE_TYPE_STANDARD) {
2032
ident = new TableIdentifier(
2033
std::string(database_name),
2034
std::string(tab_name, tab_name_len),
2035
message::Table::STANDARD);
2038
fs::path n(getDataHomeCatalog());
2041
ident = new TableIdentifier(database_name, tab_name, n.file_string());
2044
share = new TableShare(message::Table::STANDARD);
2045
if ((error = share->open_table_def(*thd, *ident))) {
2046
xt_throw_sulxterr(XT_CONTEXT, XT_ERR_LOADING_MYSQL_DIC, tab_path->ps_path, (u_long) error);
2056
static bool my_match_index(XTDDIndex *ind, KEY *index)
2058
KEY_PART_INFO *key_part;
2059
KEY_PART_INFO *key_part_end;
2061
XTDDColumnRef *cref;
2063
if (index->key_parts != ind->co_cols.size())
2067
key_part_end = index->key_part + index->key_parts;
2068
for (key_part = index->key_part; key_part != key_part_end; key_part++, j++) {
2069
if (!(cref = ind->co_cols.itemAt(j)))
2071
if (myxt_strcasecmp(cref->cr_col_name, (char *) key_part->field->field_name) != 0)
2075
if (ind->co_type == XT_DD_KEY_PRIMARY) {
2076
if (!(index->flags & HA_NOSAME))
2080
if (ind->co_type == XT_DD_INDEX_UNIQUE) {
2081
if (!(index->flags & HA_NOSAME))
2084
if (ind->co_ind_name) {
2085
if (myxt_strcasecmp(ind->co_ind_name, index->name) != 0)
2093
static XTDDIndex *my_find_index(XTDDTable *dd_tab, KEY *index)
2097
for (u_int i=0; i<dd_tab->dt_indexes.size(); i++)
2099
ind = dd_tab->dt_indexes.itemAt(i);
2100
if (my_match_index(ind, index))
2107
static void my_deref_index_data(struct XTThread *self, XTIndexPtr mi)
2110
/* The dirty list of cache pages should be empty here! */
2111
/* This is not the case if we were not able to flush data. E.g. when running out of disk space */
2112
//ASSERT(!mi->mi_dirty_list);
2113
ASSERT(!mi->mi_free_list);
2115
xt_spinlock_free(self, &mi->mi_dirty_lock);
2116
XT_INDEX_FREE_LOCK(self, mi);
2118
myxt_bitmap_free(self, &mi->mi_col_map);
2120
if (mi->mi_free_list)
2121
xt_free(self, mi->mi_free_list);
2127
static xtBool my_is_not_null_int4(XTIndexSegPtr seg)
2129
return (seg->type == HA_KEYTYPE_LONG_INT && !(seg->flag & HA_NULL_PART));
2132
/* MY_BITMAP definition in Drizzle does not like if
2133
* I use a NULL pointer to calculate the offset!?
2135
#define MX_OFFSETOF(x, y) ((size_t)(&((x *) 8)->y) - 8)
2137
/* Derived from ha_myisam::create and mi_create */
2138
static XTIndexPtr my_create_index(XTThreadPtr self, STRUCT_TABLE *table_arg, u_int idx, KeyInfo *index)
2141
KeyPartInfo *key_part;
2142
KeyPartInfo *key_part_end;
2145
enum ha_base_keytype type;
2147
u_int key_length = 0;
2148
xtBool partial_field;
2149
MX_BITMAP mi_col_map;
2153
pushsr_(ind, my_deref_index_data, (XTIndexPtr) xt_calloc(self, MX_OFFSETOF(XTIndexRec, mi_seg) + sizeof(XTIndexSegRec) * index->key_parts));
2155
XT_INDEX_INIT_LOCK(self, ind);
2156
xt_spinlock_init_with_autoname(self, &ind->mi_dirty_lock);
2157
ind->mi_index_no = idx;
2158
ind->mi_flags = (index->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL | HA_UNIQUE_CHECK));
2159
//ind->mi_low_byte_first = TS(table_arg)->db_low_byte_first;
2160
ind->mi_key_corrupted = FALSE;
2161
ind->mi_fix_key = TRUE;
2162
ind->mi_select_total = 0;
2163
ind->mi_subset_of = 0;
2165
mi_col_map.resize(GET_TABLE_SHARE(table_arg)->fields);
2167
ind->mi_col_map= mi_col_map.to_ulong();
2168
ind->mi_col_map_size= GET_TABLE_SHARE(table_arg)->fields;
2170
myxt_bitmap_init(self, &ind->mi_col_map, GET_TABLE_SHARE(table_arg)->fields);
2173
ind->mi_seg_count = (uint) index->key_parts;
2174
key_part_end = index->key_part + index->key_parts;
2176
for (key_part = index->key_part; key_part != key_part_end; key_part++, seg++) {
2177
partial_field = FALSE;
2178
field = key_part->field;
2180
type = field->key_type();
2181
seg->flag = key_part->key_part_flag;
2183
if (options & HA_OPTION_PACK_KEYS ||
2184
(index->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | HA_SPACE_PACK_USED)))
2186
if (key_part->length > 8 && (type == HA_KEYTYPE_TEXT ||
2188
type == HA_KEYTYPE_NUM ||
2190
(type == HA_KEYTYPE_BINARY && !field->zero_pack())))
2193
if (key_part == index->key_part)
2194
ind->mi_flags |= HA_PACK_KEY;
2196
if (!(field->flags & ZEROFILL_FLAG) &&
2197
(field->type() == MYSQL_TYPE_STRING ||
2198
field->type() == MYSQL_TYPE_VAR_STRING ||
2199
((int) (key_part->length - field->decimals())) >= 4))
2200
seg->flag |= HA_SPACE_PACK;
2205
seg->col_idx = field->position();
2206
seg->is_recs_in_range = 1;
2207
seg->is_selectivity = 1;
2208
seg->type = (int) type;
2209
seg->start = key_part->offset;
2210
seg->length = key_part->length;
2211
seg->bit_start = seg->bit_end = 0;
2212
seg->bit_length = seg->bit_pos = 0;
2213
seg->charset = field->charset();
2215
if (field->null_ptr) {
2217
seg->flag |= HA_NULL_PART;
2218
seg->null_bit = field->null_bit;
2219
seg->null_pos = (uint) (field->null_ptr - (uchar*) table_arg->getDefaultValues());
2226
if (field->real_type() == MYSQL_TYPE_ENUM
2228
|| field->real_type() == MYSQL_TYPE_SET
2231
/* This values are not indexed as string!!
2232
* The index will not be built correctly if this value is non-NULL.
2234
seg->charset = NULL;
2237
if (field->type() == MYSQL_TYPE_BLOB
2239
|| field->type() == MYSQL_TYPE_GEOMETRY
2242
seg->flag |= HA_BLOB_PART;
2243
/* save number of bytes used to pack length */
2244
seg->bit_start = (uint) ((Field_blob *) field)->pack_length_no_ptr();
2247
else if (field->type() == MYSQL_TYPE_BIT) {
2248
seg->bit_length = ((Field_bit *) field)->bit_len;
2249
seg->bit_start = ((Field_bit *) field)->bit_ofs;
2250
seg->bit_pos = (uint) (((Field_bit *) field)->bit_ptr - (uchar*) table_arg->getInsertRecord());
2253
/* Drizzle uses HA_KEYTYPE_ULONG_INT keys for enums > 1 byte, which is not consistent with MySQL, so we fix it here */
2254
else if (field->type() == MYSQL_TYPE_ENUM) {
2255
switch (seg->length) {
2260
seg->type = HA_KEYTYPE_USHORT_INT;
2263
seg->type = HA_KEYTYPE_UINT24;
2270
switch (seg->type) {
2271
case HA_KEYTYPE_VARTEXT1:
2272
case HA_KEYTYPE_VARTEXT2:
2273
case HA_KEYTYPE_VARBINARY1:
2274
case HA_KEYTYPE_VARBINARY2:
2275
if (!(seg->flag & HA_BLOB_PART)) {
2276
/* Make a flag that this is a VARCHAR */
2277
seg->flag |= HA_VAR_LENGTH_PART;
2278
/* Store in bit_start number of bytes used to pack the length */
2279
seg->bit_start = ((seg->type == HA_KEYTYPE_VARTEXT1 || seg->type == HA_KEYTYPE_VARBINARY1) ? 1 : 2);
2284
/* All packed fields start with a length (1 or 3 bytes): */
2285
if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) {
2286
key_length++; /* At least one length byte */
2287
if (seg->length >= 255) /* prefix may be 3 bytes */
2291
key_length += seg->length;
2292
if (seg->length > 40)
2293
ind->mi_fix_key = FALSE;
2295
/* Determine if only part of the field is in the key:
2296
* This is important for index coverage!
2297
* Note, BLOB fields are never retrieved from
2300
if (field->type() == MYSQL_TYPE_BLOB)
2301
partial_field = TRUE;
2302
else if (field->real_type() == MYSQL_TYPE_VARCHAR // For varbinary type
2304
|| field->real_type() == MYSQL_TYPE_VAR_STRING // For varbinary type
2305
|| field->real_type() == MYSQL_TYPE_STRING // For binary type
2309
Field *tab_field = GET_TABLE_FIELDS(table_arg)[key_part->fieldnr-1];
2310
u_int field_len = tab_field->key_length();
2312
if (key_part->length != field_len)
2313
partial_field = TRUE;
2316
/* NOTE: do not set if the field is only partially in the index!!! */
2319
MX_BIT_FAST_TEST_AND_SET(&mi_col_map, field->position());
2321
MX_BIT_FAST_TEST_AND_SET(&ind->mi_col_map, field->position());
2325
if (key_length > XT_INDEX_MAX_KEY_SIZE)
2326
xt_throw_sulxterr(XT_CONTEXT, XT_ERR_KEY_TOO_LARGE, index->name, (u_long) XT_INDEX_MAX_KEY_SIZE);
2328
/* This is the maximum size of the index on disk: */
2329
ind->mi_key_size = key_length;
2330
ind->mi_max_items = (XT_INDEX_PAGE_SIZE-2) / (key_length+XT_RECORD_REF_SIZE);
2332
if (ind->mi_fix_key) {
2333
/* Special case for not-NULL 4 byte int value: */
2334
switch (ind->mi_seg_count) {
2336
ind->mi_single_type = ind->mi_seg[0].type;
2337
if (ind->mi_seg[0].type == HA_KEYTYPE_LONG_INT ||
2338
ind->mi_seg[0].type == HA_KEYTYPE_ULONG_INT) {
2339
if (!(ind->mi_seg[0].flag & HA_NULL_PART))
2340
ind->mi_scan_branch = xt_scan_branch_single;
2344
if (my_is_not_null_int4(&ind->mi_seg[0]) &&
2345
my_is_not_null_int4(&ind->mi_seg[1])) {
2346
ind->mi_scan_branch = xt_scan_branch_fix_simple;
2347
ind->mi_simple_comp_key = xt_compare_2_int4;
2351
if (my_is_not_null_int4(&ind->mi_seg[0]) &&
2352
my_is_not_null_int4(&ind->mi_seg[1]) &&
2353
my_is_not_null_int4(&ind->mi_seg[2])) {
2354
ind->mi_scan_branch = xt_scan_branch_fix_simple;
2355
ind->mi_simple_comp_key = xt_compare_3_int4;
2359
if (!ind->mi_scan_branch)
2360
ind->mi_scan_branch = xt_scan_branch_fix;
2361
ind->mi_prev_item = xt_prev_branch_item_fix;
2362
ind->mi_last_item = xt_last_branch_item_fix;
2365
ind->mi_scan_branch = xt_scan_branch_var;
2366
ind->mi_prev_item = xt_prev_branch_item_var;
2367
ind->mi_last_item = xt_last_branch_item_var;
2369
ind->mi_lazy_delete = ind->mi_fix_key && ind->mi_max_items >= 4;
2371
XT_NODE_ID(ind->mi_root) = 0;
2373
popr_(); // Discard my_deref_index_data(ind)
2378
/* We estimate the size of BLOBs depending on the number
2379
* of BLOBs in the table.
2381
static u_int mx_blob_field_size_total[] = {
2394
static u_int mxvarchar_field_min_ave[] = {
2407
xtPublic void myxt_setup_dictionary(XTThreadPtr self, XTDictionaryPtr dic)
2409
STRUCT_TABLE *my_tab = dic->dic_my_table;
2411
u_int var_field_count = 0;
2412
u_int varchar_field_count = 0;
2413
u_int blob_field_count = 0;
2414
u_int large_blob_field_count = 0;
2415
xtWord8 min_data_size = 0;
2416
xtWord8 max_data_size = 0;
2417
xtWord8 ave_data_size = 0;
2418
xtWord8 min_row_size = 0;
2419
xtWord8 max_row_size = 0;
2420
xtWord8 ave_row_size = 0;
2421
xtWord8 min_ave_row_size = 0;
2422
xtWord8 max_ave_row_size = 0;
2424
xtBool dic_rec_fixed;
2426
Field * const *field;
2428
/* How many columns are required for all indexes. */
2430
KeyPartInfo *key_part;
2431
KeyPartInfo *key_part_end;
2433
#ifndef XT_USE_LAZY_DELETE
2434
dic->dic_no_lazy_delete = TRUE;
2437
dic->dic_ind_cols_req = 0;
2438
for (uint i=0; i<GET_TABLE_SHARE(my_tab)->keys; i++) {
2439
index = &my_tab->getKeyInfo(i);
2441
key_part_end = index->key_part + index->key_parts;
2442
for (key_part = index->key_part; key_part != key_part_end; key_part++) {
2443
curr_field = key_part->field;
2445
if ((u_int) curr_field->position()+1 > dic->dic_ind_cols_req)
2446
dic->dic_ind_cols_req = curr_field->position()+1;
2450
/* We will work out how many columns are required for all blobs: */
2451
dic->dic_blob_cols_req = 0;
2453
for (field=GET_TABLE_FIELDS(my_tab); (curr_field = *field); field++) {
2455
min_data_size = curr_field->key_length();
2456
max_data_size = curr_field->key_length();
2457
enum_field_types tno = curr_field->type();
2459
min_ave_row_size = 40;
2460
max_ave_row_size = 128;
2461
if (tno == MYSQL_TYPE_BLOB) {
2464
max_data_size = ((Field_blob *) curr_field)->max_data_length();
2465
/* Set the average length higher for BLOBs: */
2466
if (max_data_size == 0xFFFF ||
2467
max_data_size == 0xFFFFFF) {
2468
if (large_blob_field_count < 10)
2469
max_ave_row_size = mx_blob_field_size_total[large_blob_field_count];
2471
max_ave_row_size = 200;
2472
large_blob_field_count++;
2474
else if (max_data_size == 0xFFFFFFFF) {
2475
/* Scale the estimated size of the blob depending on how many BLOBs
2478
if (large_blob_field_count < 10)
2479
max_ave_row_size = mx_blob_field_size_total[large_blob_field_count];
2481
max_ave_row_size = 200;
2482
large_blob_field_count++;
2483
if ((u_int) curr_field->position()+1 > dic->dic_blob_cols_req)
2484
dic->dic_blob_cols_req = curr_field->position()+1;
2485
dic->dic_blob_count++;
2486
xt_realloc(self, (void **) &dic->dic_blob_cols, sizeof(Field *) * dic->dic_blob_count);
2487
dic->dic_blob_cols[dic->dic_blob_count-1] = curr_field;
2490
else if (tno == MYSQL_TYPE_VARCHAR
2492
|| tno == MYSQL_TYPE_VAR_STRING
2495
/* GOTCHA: MYSQL_TYPE_VAR_STRING does not exist as MYSQL_TYPE_VARCHAR define, but
2496
* is used when creating a table with
2500
if (varchar_field_count < 10)
2501
min_ave_row_size = mxvarchar_field_min_ave[varchar_field_count];
2503
min_ave_row_size = 40;
2504
varchar_field_count++;
2507
if (max_data_size == min_data_size)
2508
ave_data_size = max_data_size;
2511
/* Take the average a 25% of the maximum: */
2512
ave_data_size = max_data_size / 4;
2514
/* Set the average based on min and max parameters: */
2515
if (ave_data_size < min_ave_row_size)
2516
ave_data_size = min_ave_row_size;
2517
else if (ave_data_size > max_ave_row_size)
2518
ave_data_size = max_ave_row_size;
2520
if (ave_data_size > max_data_size)
2521
ave_data_size = max_data_size;
2524
/* Add space for the length indicators: */
2525
if (min_data_size <= 240)
2526
min_row_size += 1 + min_data_size;
2527
else if (min_data_size <= 0xFFFF)
2528
min_row_size += 3 + min_data_size;
2529
else if (min_data_size <= 0xFFFFFF)
2530
min_row_size += 4 + min_data_size;
2532
min_row_size += 5 + min_data_size;
2534
if (max_data_size <= 240)
2535
max_row_size += 1 + max_data_size;
2536
else if (max_data_size <= 0xFFFF)
2537
max_row_size += 3 + max_data_size;
2538
else if (max_data_size <= 0xFFFFFF)
2539
max_row_size += 4 + max_data_size;
2541
max_row_size += 5 + max_data_size;
2543
if (ave_data_size <= 240)
2544
ave_row_size += 1 + ave_data_size;
2545
else /* Should not be more than this! */
2546
ave_row_size += 3 + ave_data_size;
2548
/* This is the length of the record required for all indexes: */
2549
/* This was calculated incorrectly. Not a serius bug because it
2550
* is only used in the case of fixed length row, and in this
2551
* case the dic_ind_rec_len is set correctly below.
2553
if (field_count == dic->dic_ind_cols_req)
2554
dic->dic_ind_rec_len = max_row_size;
2557
dic->dic_min_row_size = min_row_size;
2558
dic->dic_max_row_size = max_row_size;
2559
dic->dic_ave_row_size = ave_row_size;
2560
dic->dic_no_of_cols = field_count;
2562
if (dic->dic_def_ave_row_size) {
2563
/* The average row size has been set: */
2564
dic_rec_size = offsetof(XTTabRecFix, rf_data) + GET_TABLE_SHARE(my_tab)->getRecordLength();
2566
/* The conditions for a fixed record are: */
2567
if (dic->dic_def_ave_row_size >= (xtWord8) GET_TABLE_SHARE(my_tab)->getRecordLength() &&
2568
dic_rec_size <= XT_TAB_MAX_FIX_REC_LENGTH &&
2569
!blob_field_count) {
2570
dic_rec_fixed = TRUE;
2573
xtWord8 new_rec_size;
2575
dic_rec_fixed = FALSE;
2576
if (dic->dic_def_ave_row_size > max_row_size)
2577
new_rec_size = offsetof(XTTabRecFix, rf_data) + max_row_size;
2579
new_rec_size = offsetof(XTTabRecFix, rf_data) + dic->dic_def_ave_row_size;
2581
/* The maximum record size 64K for explicit AVG_ROW_LENGTH! */
2582
if (new_rec_size > XT_TAB_MAX_FIX_REC_LENGTH_SPEC)
2583
new_rec_size = XT_TAB_MAX_FIX_REC_LENGTH_SPEC;
2585
dic_rec_size = (u_int) new_rec_size;
2589
/* If the average size is within 10% if of the maximum size, then we
2590
* we handle these rows as fixed size rows.
2591
* Fixed size rows use the internal MySQL format.
2593
dic_rec_size = offsetof(XTTabRecFix, rf_data) + GET_TABLE_SHARE(my_tab)->getRecordLength();
2594
/* Fixed length records must be less than 16K in size,
2595
* have an average size which is very close (20%) to the maximum size or
2596
* be less than a minimum size,
2597
* and not contain any BLOBs:
2599
if (dic_rec_size <= XT_TAB_MAX_FIX_REC_LENGTH &&
2600
(ave_row_size + ave_row_size / 4 >= max_row_size ||
2601
dic_rec_size < XT_TAB_MIN_VAR_REC_LENGTH) &&
2602
!blob_field_count) {
2603
dic_rec_fixed = TRUE;
2606
dic_rec_fixed = FALSE;
2607
/* Note I add offsetof(XTTabRecFix, rf_data) insteard of
2608
* offsetof(XTTabRecExt, re_data) here!
2609
* The reason is that, we want to include the average size
2610
* record in the fixed data part. To do this we only need to
2611
* calculate a fixed header size, because in the cases in which
2612
* it fits, we will only be using a fixed header!
2614
dic_rec_size = (u_int) (offsetof(XTTabRecFix, rf_data) + ave_row_size);
2615
/* The maximum record size (16K for autorow sizing)! */
2616
if (dic_rec_size > XT_TAB_MAX_FIX_REC_LENGTH)
2617
dic_rec_size = XT_TAB_MAX_FIX_REC_LENGTH;
2621
/* Ensure that handle data record size is big enough to
2622
* include the extended record reference, in the case of
2623
* variable length rows
2625
if (!dic_rec_fixed) {
2626
if (dic_rec_size < offsetof(XTTabRecExtDRec, re_data))
2627
dic_rec_size = offsetof(XTTabRecExtDRec, re_data);
2631
ASSERT_NS(dic_rec_size > offsetof(XTTabRecFix, rf_data));
2635
if (!dic->dic_rec_size) {
2636
dic->dic_rec_size = dic_rec_size;
2637
dic->dic_rec_fixed = dic_rec_fixed;
2640
/* This just confirms that our original calculation on
2641
* create table agrees with the current calculation.
2642
* (i.e. if non-zero values were loaded from the table).
2644
* It may be the criteria for calculating the data record size
2645
* and whether to used a fixed or variable record has changed,
2646
* but we need to stick to the current physical layout of the
2649
* Note that this can occur in rename table when the
2650
* method of calculation has changed.
2652
* On rename, the format of the table does not change, so we
2653
* will not take the calculated values.
2655
//ASSERT(dic->dic_rec_size == dic_rec_size);
2656
//ASSERT(dic->dic_rec_fixed == dic_rec_fixed);
2659
if (dic_rec_fixed) {
2660
/* Recalculate the length of the required required to address all
2663
if (field_count == dic->dic_ind_cols_req)
2664
dic->dic_ind_rec_len = GET_TABLE_SHARE(my_tab)->getRecordLength();
2666
field=GET_TABLE_FIELDS(my_tab);
2668
curr_field = field[dic->dic_ind_cols_req];
2669
dic->dic_ind_rec_len = curr_field->offset(my_tab->getDefaultValues());
2673
/* We now calculate how many of the first columns in the row
2674
* will definitely fit into the buffer, when the record is
2677
* In this way we can figure out if we need to load the extended
2680
dic->dic_fix_col_count = 0;
2681
if (!dic_rec_fixed) {
2682
xtWord8 max_rec_size = offsetof(XTTabRecExt, re_data);
2684
for (Field * const *f=GET_TABLE_FIELDS(my_tab); (curr_field = *f); f++) {
2685
max_data_size = curr_field->key_length();
2686
enum_field_types tno = curr_field->type();
2687
if (tno == MYSQL_TYPE_BLOB)
2688
max_data_size = ((Field_blob *) curr_field)->max_data_length();
2689
if (max_data_size <= 240)
2690
max_rec_size += 1 + max_data_size;
2691
else if (max_data_size <= 0xFFFF)
2692
max_rec_size += 3 + max_data_size;
2693
else if (max_data_size <= 0xFFFFFF)
2694
max_rec_size += 4 + max_data_size;
2696
max_rec_size += 5 + max_data_size;
2697
if (max_rec_size > (xtWord8) dic_rec_size)
2699
dic->dic_fix_col_count++;
2701
ASSERT(dic->dic_fix_col_count < dic->dic_no_of_cols);
2704
dic->dic_key_count = GET_TABLE_SHARE(my_tab)->keys;
2705
dic->dic_mysql_buf_size = GET_TABLE_SHARE(my_tab)->rec_buff_length;
2706
dic->dic_mysql_rec_size = GET_TABLE_SHARE(my_tab)->getRecordLength();
2709
static u_int my_get_best_superset(XTThreadPtr XT_UNUSED(self), XTDictionaryPtr dic, XTIndexPtr ind)
2711
XTIndexPtr super_ind;
2713
u_int super_seg_count = ind->mi_seg_count;
2715
for (u_int i=0; i<dic->dic_key_count; i++) {
2716
super_ind = dic->dic_keys[i];
2717
if (ind->mi_index_no != super_ind->mi_index_no &&
2718
super_seg_count < super_ind->mi_seg_count) {
2719
for (u_int j=0; j<ind->mi_seg_count; j++) {
2720
if (ind->mi_seg[j].col_idx != super_ind->mi_seg[j].col_idx)
2723
super_seg_count = super_ind->mi_seg_count;
2732
* Return FAILED if the MySQL dictionary is not available.
2734
xtPublic xtBool myxt_load_dictionary(XTThreadPtr self, XTDictionaryPtr dic, XTDatabaseHPtr db, XTPathStrPtr tab_path)
2736
STRUCT_TABLE *my_tab;
2738
if (!(my_tab = my_open_table(self, db, tab_path, dic->dic_table_type)))
2740
dic->dic_my_table = my_tab;
2742
dic->dic_def_ave_row_size = (xtWord8) GET_TABLE_SHARE(my_tab)->getTableProto()->options().avg_row_length();
2744
dic->dic_def_ave_row_size = (xtWord8) GET_TABLE_SHARE(my_tab)->avg_row_length;
2746
myxt_setup_dictionary(self, dic);
2747
dic->dic_keys = (XTIndexPtr *) xt_calloc(self, sizeof(XTIndexPtr) * GET_TABLE_SHARE(my_tab)->keys);
2748
for (uint i=0; i<GET_TABLE_SHARE(my_tab)->keys; i++)
2749
dic->dic_keys[i] = my_create_index(self, my_tab, i, &my_tab->getKeyInfo(i));
2751
/* Check if any key is a subset of another: */
2752
for (u_int i=0; i<dic->dic_key_count; i++)
2753
dic->dic_keys[i]->mi_subset_of = my_get_best_superset(self, dic, dic->dic_keys[i]);
2758
xtPublic void myxt_free_dictionary(XTThreadPtr self, XTDictionaryPtr dic)
2760
if (dic->dic_table) {
2761
dic->dic_table->release(self);
2762
dic->dic_table = NULL;
2765
if (dic->dic_my_table) {
2766
my_close_table(dic->dic_my_table);
2767
dic->dic_my_table = NULL;
2770
if (dic->dic_blob_cols) {
2771
xt_free(self, dic->dic_blob_cols);
2772
dic->dic_blob_cols = NULL;
2774
dic->dic_blob_count = 0;
2776
/* If we have opened a table, then this data is freed with the dictionary: */
2777
if (dic->dic_keys) {
2778
for (uint i=0; i<dic->dic_key_count; i++) {
2779
if (dic->dic_keys[i])
2780
my_deref_index_data(self, (XTIndexPtr) dic->dic_keys[i]);
2782
xt_free(self, dic->dic_keys);
2783
dic->dic_key_count = 0;
2784
dic->dic_keys = NULL;
2788
xtPublic void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic)
2790
dic->dic_my_table = source_dic->dic_my_table;
2791
source_dic->dic_my_table = NULL;
2793
if (!dic->dic_rec_size) {
2794
dic->dic_rec_size = source_dic->dic_rec_size;
2795
dic->dic_rec_fixed = source_dic->dic_rec_fixed;
2798
/* This just confirms that our original calculation on
2799
* create table agrees with the current calculation.
2800
* (i.e. if non-zero values were loaded from the table).
2802
* It may be the criteria for calculating the data record size
2803
* and whether to used a fixed or variable record has changed,
2804
* but we need to stick to the current physical layout of the
2807
ASSERT_NS(dic->dic_rec_size == source_dic->dic_rec_size);
2808
ASSERT_NS(dic->dic_rec_fixed == source_dic->dic_rec_fixed);
2811
dic->dic_tab_flags = source_dic->dic_tab_flags;
2812
dic->dic_blob_cols_req = source_dic->dic_blob_cols_req;
2813
dic->dic_blob_count = source_dic->dic_blob_count;
2814
dic->dic_blob_cols = source_dic->dic_blob_cols;
2815
source_dic->dic_blob_cols = NULL;
2817
dic->dic_mysql_buf_size = source_dic->dic_mysql_buf_size;
2818
dic->dic_mysql_rec_size = source_dic->dic_mysql_rec_size;
2819
dic->dic_key_count = source_dic->dic_key_count;
2820
dic->dic_keys = source_dic->dic_keys;
2822
/* Set this to zero, bcause later xt_flush_tables() may be called.
2823
* This can occur when using the BLOB streaming engine,
2824
* in command ALTER TABLE x ENGINE = PBXT;
2826
source_dic->dic_key_count = 0;
2827
source_dic->dic_keys = NULL;
2829
dic->dic_min_row_size = source_dic->dic_min_row_size;
2830
dic->dic_max_row_size = source_dic->dic_max_row_size;
2831
dic->dic_ave_row_size = source_dic->dic_ave_row_size;
2832
dic->dic_def_ave_row_size = source_dic->dic_def_ave_row_size;
2834
dic->dic_no_of_cols = source_dic->dic_no_of_cols;
2835
dic->dic_fix_col_count = source_dic->dic_fix_col_count;
2836
dic->dic_ind_cols_req = source_dic->dic_ind_cols_req;
2837
dic->dic_ind_rec_len = source_dic->dic_ind_rec_len;
2840
static void my_free_dd_table(XTThreadPtr self, XTDDTable *dd_tab)
2843
dd_tab->release(self);
2846
static void ha_create_dd_index(XTThreadPtr self, XTDDIndex *ind, KeyInfo *key)
2848
KeyPartInfo *key_part;
2849
KeyPartInfo *key_part_end;
2850
XTDDColumnRef *cref;
2852
if (strcmp(key->name, "PRIMARY") == 0)
2853
ind->co_type = XT_DD_KEY_PRIMARY;
2854
else if (key->flags & HA_NOSAME)
2855
ind->co_type = XT_DD_INDEX_UNIQUE;
2857
ind->co_type = XT_DD_INDEX;
2859
if (ind->co_type == XT_DD_KEY_PRIMARY)
2860
ind->co_name = xt_dup_string(self, key->name);
2862
ind->co_ind_name = xt_dup_string(self, key->name);
2864
key_part_end = key->key_part + key->key_parts;
2865
for (key_part = key->key_part; key_part != key_part_end; key_part++) {
2866
if (!(cref = new XTDDColumnRef()))
2867
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
2869
ind->co_cols.append(self, cref);
2870
cref->cr_col_name = xt_dup_string(self, (char *) key_part->field->field_name);
2874
static char *my_type_to_string(XTThreadPtr self, Field *field, STRUCT_TABLE *XT_UNUSED(my_tab))
2876
char buffer[MAX_FIELD_WIDTH + 400];
2878
String type((char *) buffer, sizeof(buffer), system_charset_info);
2882
* - Above sets the string length to the same as the buffer,
2883
* so we must set the length to zero.
2884
* - The result is not necessarilly zero terminated.
2885
* - We cannot assume that the input buffer is the one
2886
* we get back (for example text field).
2889
field->sql_type(type);
2891
len = type.length();
2893
if (len >= sizeof(buffer))
2894
len = sizeof(buffer)-1;
2897
xt_strcpy(sizeof(buffer), buffer, ptr);
2901
if (field->has_charset()) {
2902
/* Always include the charset so that we can compare types
2903
* for FK/PK releations.
2905
xt_strcat(sizeof(buffer), buffer, " CHARACTER SET ");
2906
xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->csname);
2908
/* For string types dump collation name only if
2909
* collation is not primary for the given charset
2911
if (!(field->charset()->state & MY_CS_PRIMARY)) {
2912
xt_strcat(sizeof(buffer), buffer, " COLLATE ");
2913
xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->name);
2917
return xt_dup_string(self, buffer); // type.length()
2920
xtPublic XTDDTable *myxt_create_table_from_table(XTThreadPtr self, STRUCT_TABLE *my_tab)
2927
if (!(dd_tab = new XTDDTable()))
2928
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
2930
pushr_(my_free_dd_table, dd_tab);
2932
for (Field * const *field=GET_TABLE_FIELDS(my_tab); (curr_field = *field); field++) {
2933
col = XTDDColumnFactory::createFromMySQLField(self, my_tab, curr_field);
2934
dd_tab->dt_cols.append(self, col);
2937
for (uint i=0; i<GET_TABLE_SHARE(my_tab)->keys; i++) {
2938
if (!(ind = (XTDDIndex *) new XTDDIndex(XT_DD_UNKNOWN)))
2939
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
2940
dd_tab->dt_indexes.append(self, ind);
2941
ind->co_table = dd_tab;
2943
ha_create_dd_index(self, ind, &my_tab->getKeyInfo(i));
2946
popr_(); // my_free_dd_table(dd_tab)
2951
* -----------------------------------------------------------------------
2952
* MySQL CHARACTER UTILITIES
2955
xtPublic void myxt_static_convert_identifier(XTThreadPtr XT_UNUSED(self), MX_CONST_CHARSET_INFO *cs, char *from, char *to, size_t to_len)
2959
xt_strcpy(to_len, to, from);
2965
* Check that identifiers and strings are not converted
2966
* when the client character set is binary.
2968
if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin)
2969
xt_strcpy(to_len, to, from);
2971
strconvert(cs, from, &my_charset_utf8_general_ci, to, to_len, &errors);
2975
// cs == current_thd->charset()
2976
xtPublic char *myxt_convert_identifier(XTThreadPtr self, MX_CONST_CHARSET_INFO *cs, char *from)
2979
char *to = xt_dup_string(self, from);
2986
if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin)
2987
to = xt_dup_string(self, from);
2989
len = strlen(from) * 3 + 1;
2990
to = (char *) xt_malloc(self, len);
2991
strconvert(cs, from, &my_charset_utf8_general_ci, to, len, &errors);
2997
xtPublic char *myxt_convert_table_name(XTThreadPtr self, char *from)
3002
len = strlen(from) * 5 + 1;
3003
to = (char *) xt_malloc(self, len);
3004
tablename_to_filename(from, to, len);
3009
* This works because if you create a table
3010
* with a '#' in it, MySQL will translate it
3011
* to @0023 in the file name.
3013
xtPublic xtBool myxt_temp_table_name(const char *table)
3018
name = xt_last_name_of_path(table);
3020
yup = (strncmp(name, "#sql", 4) == 0);
3023
yup = (strncmp(name, "#sql-", 5) == 0) || (strncmp(name, "#sql2-", 6) == 0);
3028
xtPublic void myxt_static_convert_table_name(XTThreadPtr XT_UNUSED(self), char *from, char *to, size_t to_len)
3030
tablename_to_filename(from, to, to_len);
3033
xtPublic void myxt_static_convert_file_name(char *from, char *to, size_t to_len)
3035
uint32_t len = TableIdentifier::filename_to_tablename(from, to, to_len);
3041
xtPublic int myxt_strcasecmp(char * a, char *b)
3043
return my_strcasecmp(&my_charset_utf8_general_ci, a, b);
3046
xtPublic int myxt_isspace(MX_CONST_CHARSET_INFO *cs, char a)
3048
return my_isspace(cs, a);
3051
xtPublic int myxt_ispunct(MX_CONST_CHARSET_INFO *cs, char a)
3053
return my_ispunct(cs, a);
3056
xtPublic int myxt_isdigit(MX_CONST_CHARSET_INFO *cs, char a)
3058
return my_isdigit(cs, a);
3061
xtPublic MX_CONST_CHARSET_INFO *myxt_getcharset(bool convert)
3064
THD *thd = current_thd;
3067
return (MX_CHARSET_INFO *)thd->charset();
3069
return (MX_CHARSET_INFO *)&my_charset_utf8_general_ci;
3072
xtPublic xtBool myxt_create_thread_possible()
3075
if (!global_system_variables.table_plugin) {
3076
xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MYSQL_NO_THREAD);
3083
xtPublic void *myxt_create_thread()
3089
if (drizzled::internal::my_thread_init()) {
3090
xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading");
3094
if (!(client = new NullClient()))
3096
session = new Session(client);
3097
session->thread_stack = (char *) &session;
3098
session->storeGlobals();
3099
return (void *) session;
3103
if (my_thread_init()) {
3104
xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading");
3109
* Unfortunately, if PBXT is the default engine, and we are shutting down
3110
* then global_system_variables.table_plugin may be NULL. Which will cause
3111
* a crash if we try to create a thread!
3113
* The following call in plugin_shutdown() sets the global reference
3116
* unlock_variables(NULL, &global_system_variables);
3118
* Later plugin_deinitialize() is called.
3120
* The following stack is an example crash which occurs when I call
3121
* myxt_create_thread() in ha_exit(), to force the error.
3123
* if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
3125
* #0 0x002ff684 in intern_plugin_lock at sql_plugin.cc:617
3126
* #1 0x0030296d in plugin_thdvar_init at sql_plugin.cc:2432
3127
* #2 0x000db4a4 in THD::init at sql_class.cc:756
3128
* #3 0x000e02ed in THD::THD at sql_class.cc:638
3129
* #4 0x00e2678d in myxt_create_thread at myxt_xt.cc:2990
3130
* #5 0x00e05d43 in ha_exit at ha_pbxt.cc:1011
3131
* #6 0x00e065c2 in pbxt_end at ha_pbxt.cc:1330
3132
* #7 0x00e065df in pbxt_panic at ha_pbxt.cc:1343
3133
* #8 0x0023e57d in ha_finalize_handlerton at handler.cc:392
3134
* #9 0x002ffc8b in plugin_deinitialize at sql_plugin.cc:816
3135
* #10 0x003037d9 in plugin_shutdown at sql_plugin.cc:1572
3136
* #11 0x000f7b2b in clean_up at mysqld.cc:1266
3137
* #12 0x000f7fca in unireg_end at mysqld.cc:1192
3138
* #13 0x000fa021 in kill_server at mysqld.cc:1134
3139
* #14 0x000fa6df in kill_server_thread at mysqld.cc:1155
3140
* #15 0x91fdb155 in _pthread_start
3141
* #16 0x91fdb012 in thread_start
3143
if (!global_system_variables.table_plugin) {
3144
xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MYSQL_NO_THREAD);
3148
if (!(new_thd = new THD)) {
3150
xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to create MySQL thread (THD)");
3155
* If PBXT is the default storage engine, then creating any THD objects will add extra
3156
* references to the PBXT plugin object. because the threads are created but PBXT
3157
* this creates a self reference, and the reference count does not go to zero
3160
* The server then issues a message that it is forcing shutdown of the plugin.
3162
* However, the engine reference is not required by the THDs used by PBXT, so
3163
* I just remove them here.
3165
plugin_unlock(NULL, new_thd->variables.table_plugin);
3166
new_thd->variables.table_plugin = NULL;
3168
new_thd->thread_stack = (char *) &new_thd;
3169
new_thd->store_globals();
3172
return (void *) new_thd;
3177
xtPublic void myxt_destroy_thread(void *s, xtBool end_threads)
3179
Session *session = (Session *) s;
3184
drizzled::internal::my_thread_end();
3187
xtPublic void myxt_destroy_thread(void *thread, xtBool end_threads)
3189
THD *thd = (THD *) thread;
3191
#if MYSQL_VERSION_ID > 60005
3192
/* PMC - This is a HACK! It is required because
3193
* MySQL shuts down MDL before shutting down the
3198
close_thread_tables(thd);
3202
close_thread_tables(thd);
3207
/* Remember that we don't have a THD */
3208
my_pthread_setspecific_ptr(THR_THD, 0);
3215
xtPublic void myxt_delete_remaining_thread()
3219
if ((thd = current_thd))
3220
myxt_destroy_thread((void *) thd, TRUE);
3223
xtPublic XTThreadPtr myxt_get_self()
3227
if ((thd = current_thd))
3228
return xt_ha_thd_to_self(thd);
3233
* -----------------------------------------------------------------------
3234
* INFORMATION SCHEMA FUNCTIONS
3239
static int mx_put_record(THD *thd, TABLE *table)
3241
return schema_table_store_record(thd, table);
3245
static void mx_put_int(TABLE *table, int column, int value)
3247
GET_TABLE_FIELDS(table)[column]->store(value, false);
3250
static void mx_put_real8(TABLE *table, int column, xtReal8 value)
3252
GET_TABLE_FIELDS(table)[column]->store(value);
3255
static void mx_put_string(TABLE *table, int column, const char *string, u_int len, charset_info_st *charset)
3257
GET_TABLE_FIELDS(table)[column]->store(string, len, charset);
3261
static void mx_put_u_llong(TABLE *table, int column, u_llong value)
3263
GET_TABLE_FIELDS(table)[column]->store(value, false);
3266
static void mx_put_string(TABLE *table, int column, const char *string, charset_info_st *charset)
3268
GET_TABLE_FIELDS(table)[column]->store(string, strlen(string), charset);
3271
xtPublic int myxt_statistics_fill_table(XTThreadPtr self, void *th, void *ta, void *, MX_CONST void *ch)
3273
THD *thd = (THD *) th;
3274
TABLE_LIST *tables = (TABLE_LIST *) ta;
3275
charset_info_st *charset = (charset_info_st *) ch;
3276
TABLE *table = (TABLE *) tables->table;
3279
const char *stat_name;
3281
XTStatisticsRec statistics;
3282
XTDatabaseHPtr db = self->st_database;
3284
xt_gather_statistics(&statistics);
3285
for (u_int rec_id=0; !err && rec_id<XT_STAT_CURRENT_MAX; rec_id++) {
3286
stat_name = xt_get_stat_meta_data(rec_id)->sm_name;
3287
stat_value = xt_get_statistic(&statistics, db, rec_id);
3290
mx_put_u_llong(table, col++, rec_id+1);
3291
mx_put_string(table, col++, stat_name, charset);
3292
mx_put_u_llong(table, col++, stat_value);
3293
err = mx_put_record(thd, table);
3300
xtPublic void myxt_get_status(XTThreadPtr self, XTStringBufferPtr strbuf)
3304
xt_sb_concat(self, strbuf, "\n");
3305
xt_get_now(string, 200);
3306
xt_sb_concat(self, strbuf, string);
3307
xt_sb_concat(self, strbuf, " PBXT ");
3308
xt_sb_concat(self, strbuf, xt_get_version());
3309
xt_sb_concat(self, strbuf, " STATUS OUTPUT");
3310
xt_sb_concat(self, strbuf, "\n");
3312
xt_sb_concat(self, strbuf, "Record cache usage: ");
3313
xt_sb_concat_int8(self, strbuf, xt_tc_get_usage());
3314
xt_sb_concat(self, strbuf, "\n");
3315
xt_sb_concat(self, strbuf, "Record cache size: ");
3316
xt_sb_concat_int8(self, strbuf, xt_tc_get_size());
3317
xt_sb_concat(self, strbuf, "\n");
3318
xt_sb_concat(self, strbuf, "Record cache high: ");
3319
xt_sb_concat_int8(self, strbuf, xt_tc_get_high());
3320
xt_sb_concat(self, strbuf, "\n");
3321
xt_sb_concat(self, strbuf, "Index cache usage: ");
3322
xt_sb_concat_int8(self, strbuf, xt_ind_get_usage());
3323
xt_sb_concat(self, strbuf, "\n");
3324
xt_sb_concat(self, strbuf, "Index cache size: ");
3325
xt_sb_concat_int8(self, strbuf, xt_ind_get_size());
3326
xt_sb_concat(self, strbuf, "\n");
3327
xt_sb_concat(self, strbuf, "Log cache usage: ");
3328
xt_sb_concat_int8(self, strbuf, xt_xlog_get_usage());
3329
xt_sb_concat(self, strbuf, "\n");
3330
xt_sb_concat(self, strbuf, "Log cache size: ");
3331
xt_sb_concat_int8(self, strbuf, xt_xlog_get_size());
3332
xt_sb_concat(self, strbuf, "\n");
3334
xt_ht_lock(self, xt_db_open_databases);
3335
pushr_(xt_ht_unlock, xt_db_open_databases);
3337
XTDatabaseHPtr *dbptr;
3338
size_t len = xt_sl_get_size(xt_db_open_db_by_id);
3341
xt_sb_concat(self, strbuf, "Data log files:\n");
3342
for (u_int i=0; i<len; i++) {
3343
dbptr = (XTDatabaseHPtr *) xt_sl_item_at(xt_db_open_db_by_id, i);
3345
#ifndef XT_USE_GLOBAL_DB
3346
xt_sb_concat(self, strbuf, "Database: ");
3347
xt_sb_concat(self, strbuf, (*dbptr)->db_name);
3348
xt_sb_concat(self, strbuf, "\n");
3350
xt_dl_log_status(self, *dbptr, strbuf);
3354
xt_sb_concat(self, strbuf, "No data logs in use\n");
3356
freer_(); // xt_ht_unlock(xt_db_open_databases)
3360
* -----------------------------------------------------------------------
3364
static void myxt_bitmap_init(XTThreadPtr self, MX_BITMAP *map, u_int n_bits)
3368
map= new boost::dynamic_bitset<>(n_bits);
3369
map->resize(n_bits);
3373
uint size_in_bytes = (((n_bits) + 31) / 32) * 4;
3374
buf = (my_bitmap_map *) xt_malloc(self, size_in_bytes);
3376
map->n_bits= n_bits;
3377
create_last_word_mask(map);
3378
bitmap_clear_all(map);
3382
static void myxt_bitmap_free(XTThreadPtr self, MX_BITMAP *map)
3391
xt_free(self, map->bitmap);
3398
* -----------------------------------------------------------------------
3399
* XTDDColumnFactory methods
3402
XTDDColumn *XTDDColumnFactory::createFromMySQLField(XTThread *self, STRUCT_TABLE *my_tab, Field *field)
3404
XTDDEnumerableColumn *en_col;
3406
xtBool is_enum = FALSE;
3408
switch(field->real_type()) {
3409
case MYSQL_TYPE_ENUM:
3414
case MYSQL_TYPE_SET:
3416
col = en_col = new XTDDEnumerableColumn();
3418
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
3420
en_col->enum_size = ((Field_enum *)field)->typelib->count;
3421
en_col->is_enum = is_enum;
3425
col = new XTDDColumn();
3427
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
3431
col->dc_name = xt_dup_string(self, (char *) field->field_name);
3432
col->dc_data_type = my_type_to_string(self, field, my_tab);
3433
col->dc_null_ok = field->null_ptr != NULL;
3439
* -----------------------------------------------------------------------
3444
* MySQL (not sure about Drizzle) first calls hton->init and then assigns the plugin a thread slot
3445
* which is used by xt_get_self(). This is a problem as pbxt_init() starts a number of daemon threads
3446
* which could try to use the slot before it is assigned. This code waits till slot is inited.
3447
* We cannot directly check hton->slot as in some versions of MySQL it can be 0 before init which is a
3450
extern ulong total_ha;
3452
xtPublic void myxt_wait_pbxt_plugin_slot_assigned(XTThread *self)
3455
static std::string plugin_name("PBXT");
3457
while (!self->t_quit && !module::Registry::singleton().find(plugin_name))
3458
xt_sleep_milli_second(1);
3460
while(!self->t_quit && (pbxt_hton->slot >= total_ha))
3461
xt_sleep_milli_second(1);