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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
//extern "C" struct charset_info_st *session_charset(Session *session);
48
extern pthread_key_t THR_Session;
50
using namespace drizzled;
52
#include "mysql_priv.h"
53
#include <mysql/plugin.h>
64
#include "strutil_xt.h"
65
#include "database_xt.h"
67
#include "datalog_xt.h"
68
#include "memory_xt.h"
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);
74
#define swap_variables(TYPE, a, b) \
83
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
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))
90
#define FIX_LENGTH(cs, pos, length, char_length) \
92
if ((length) > char_length) \
93
char_length= my_charpos(cs, pos, pos+length, char_length); \
94
set_if_smaller(char_length,length); \
97
#ifdef store_key_length_inc
98
#undef store_key_length_inc
100
#define store_key_length_inc(key,length) \
101
{ if ((length) < 255) \
102
{ *(key)++=(length); } \
104
{ *(key)=255; mi_int2store((key)+1,(length)); (key)+=3; } \
107
#define set_rec_bits(bits, bit_ptr, bit_ofs, bit_len) \
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))); \
116
#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
117
set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
120
static const char hexchars[]= "0123456789abcdef";
122
static bool tablename_to_filename(const char *from, char *to, size_t to_length)
126
for (; *from && length < to_length; length++, from++)
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) ||
146
if (length + 3 >= to_length)
149
/* We need to escape this char in a way that can be reversed */
151
to[length++]= hexchars[(*from >> 4) & 15];
152
to[length]= hexchars[(*from) & 15];
155
if (/*internal::check_if_legal_tablename(to) &&*/
156
length + 4 < to_length)
158
memcpy(to + length, "@@@", 4);
165
static ulong my_calc_blob_length(uint length, xtWord1 *pos)
169
return (uint) (uchar) *pos;
171
return (uint) uint2korr(pos);
173
return uint3korr(pos);
175
return uint4korr(pos);
179
return 0; /* Impossible */
182
static void my_store_blob_length(byte *pos,uint pack_length,uint length)
184
switch (pack_length) {
186
*pos= (uchar) length;
189
int2store(pos,length);
192
int3store(pos,length);
195
int4store(pos,length);
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))
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!
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);
218
* -----------------------------------------------------------------------
223
* Derived from _mi_pack_key()
225
xtPublic u_int myxt_create_key_from_key(XTIndexPtr ind, xtWord1 *key, xtWord1 *old, u_int k_length)
227
xtWord1 *start_key = key;
228
XTIndexSegRec *keyseg = ind->mi_seg;
230
for (u_int i=0; i<ind->mi_seg_count && (int) k_length > 0; i++, old += keyseg->length, keyseg++)
233
enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type;
235
u_int length = keyseg->length < k_length ? keyseg->length : k_length;
238
MX_CONST_CHARSET_INFO *cs = keyseg->charset;
240
if (keyseg->null_bit) {
242
if (!(*key++ = (xtWord1) 1 - *old++)) { /* Copy null marker */
244
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
245
k_length -= 2; /* Skip length */
248
continue; /* Found NULL */
251
char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
253
if (keyseg->flag & HA_SPACE_PACK) {
254
uchar *end = pos + length;
256
if (type != HA_KEYTYPE_NUM) {
258
while (end > pos && end[-1] == ' ')
263
while (pos < end && pos[0] == ' ')
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);
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;
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);
288
if (keyseg->flag & HA_SWAP_KEY)
289
{ /* Numerical column */
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, ' ');
305
return (u_int) (key - start_key);
308
/* Derived from _mi_make_key */
309
xtPublic u_int myxt_create_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, xtBool *no_duplicate)
311
register XTIndexSegRec *keyseg = ind->mi_seg;
318
memset((byte*) key, 0,(size_t) (ind->mi_key_size) );
323
memset((byte*) key, 0,(size_t) (ind->mi_key_size) );
327
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++)
330
enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type;
332
u_int length = keyseg->length;
334
MX_CONST_CHARSET_INFO *cs = keyseg->charset;
336
if (keyseg->null_bit) {
337
if (record[keyseg->null_pos] & keyseg->null_bit) {
338
*key++ = 0; /* NULL in key */
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.
346
*no_duplicate = FALSE;
349
*key++ = 1; /* Not NULL */
352
char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length);
354
pos = record + keyseg->start;
356
if (type == HA_KEYTYPE_BIT)
358
if (keyseg->bit_length)
360
uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos,
361
keyseg->bit_start, keyseg->bit_length);
365
memcpy((byte*) key, pos, length);
370
if (keyseg->flag & HA_SPACE_PACK)
374
if (type != HA_KEYTYPE_NUM) {
376
while (end > pos && end[-1] == ' ')
381
while (pos < end && pos[0] == ' ')
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);
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 :
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);
404
if (keyseg->flag & HA_BLOB_PART)
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);
415
if (keyseg->flag & HA_SWAP_KEY)
416
{ /* Numerical column */
419
if (type == HA_KEYTYPE_FLOAT)
425
/* Replace NAN with zero */
433
if (type == HA_KEYTYPE_DOUBLE) {
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, ' ');
457
return ind->mi_fix_key ? ind->mi_key_size : (u_int) (key - start); /* Return keylength */
460
xtPublic u_int myxt_create_foreign_key_from_row(XTIndexPtr ind, xtWord1 *key, xtWord1 *record, XTIndexPtr fkey_ind, xtBool *no_null)
462
register XTIndexSegRec *keyseg = ind->mi_seg;
463
register XTIndexSegRec *fkey_keyseg = fkey_ind->mi_seg;
469
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++, fkey_keyseg++)
472
enum ha_base_keytype type = (enum ha_base_keytype) keyseg->type;
474
u_int length = keyseg->length;
476
MX_CONST_CHARSET_INFO *cs = keyseg->charset;
477
xtBool is_null = FALSE;
479
if (keyseg->null_bit) {
480
if (record[keyseg->null_pos] & keyseg->null_bit) {
487
if (fkey_keyseg->null_bit) {
489
*key++ = 0; /* NULL in key */
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.
498
*key++ = 1; /* Not NULL */
501
char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length);
503
pos = record + keyseg->start;
505
if (type == HA_KEYTYPE_BIT)
507
if (keyseg->bit_length)
509
uchar bits = get_rec_bits((uchar*) record + keyseg->bit_pos,
510
keyseg->bit_start, keyseg->bit_length);
514
memcpy((byte*) key, pos, length);
519
if (keyseg->flag & HA_SPACE_PACK)
523
if (type != HA_KEYTYPE_NUM) {
525
while (end > pos && end[-1] == ' ')
530
while (pos < end && pos[0] == ' ')
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);
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 :
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);
553
if (keyseg->flag & HA_BLOB_PART)
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);
564
if (keyseg->flag & HA_SWAP_KEY)
565
{ /* Numerical column */
568
if (type == HA_KEYTYPE_FLOAT)
574
/* Replace NAN with zero */
582
if (type == HA_KEYTYPE_DOUBLE) {
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, ' ');
606
return (u_int) (key - start);
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.
613
static void mx_set_notnull_in_record(STRUCT_TABLE *table, Field *field, char *record)
616
record[(uint) (field->null_ptr - (uchar *) table->getDefaultValues())] &= (uchar) ~field->null_bit;
619
static xtBool mx_is_null_in_record(STRUCT_TABLE *table, Field *field, char *record)
621
if (field->null_ptr) {
622
if (record[(uint) (field->null_ptr - (uchar *) table->getDefaultValues())] & (uchar) field->null_bit)
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.
633
static char *mx_get_length_and_data(STRUCT_TABLE *table, Field *field, char *dest, xtWord4 *len)
637
from = dest + field->offset(table->getDefaultValues());
638
switch (field->real_type()) {
640
case MYSQL_TYPE_TINY_BLOB:
641
case MYSQL_TYPE_MEDIUM_BLOB:
642
case MYSQL_TYPE_LONG_BLOB:
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.
650
/* GOTCHA: There is no way this can work! field is shared
652
char *save = field->ptr;
654
field->ptr = (char *) from;
655
((Field_blob *) field)->get_ptr(&data);
656
field->ptr = save; // Restore org row pointer
659
xtWord4 packlength = ((Field_blob *) field)->pack_length_no_ptr();
661
memcpy(&data, ((char *) from)+packlength, sizeof(char*));
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);
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
674
* But this is not relevant because I believe lengthsp
675
* will give me the correct answer!
677
*len = field->charset()->cset->lengthsp(field->charset(), from, field->field_length);
679
case MYSQL_TYPE_VAR_STRING: {
680
uint length=uint2korr(from);
683
return from+HA_KEY_BLOB_LENGTH;
686
case MYSQL_TYPE_VARCHAR: {
689
if (((Field_varstring *) field)->pack_length_no_ptr() == 1)
690
length = *((unsigned char *) from);
692
length = uint2korr(from);
695
return from+((Field_varstring *) field)->pack_length_no_ptr();
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:
714
case MYSQL_TYPE_NEWDECIMAL:
715
case MYSQL_TYPE_ENUM:
717
case MYSQL_TYPE_GEOMETRY:
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:
732
*len = field->pack_length();
737
* Set the length and data value of a field.
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:
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".
751
static void mx_set_length_and_data(STRUCT_TABLE *table, Field *field, char *dest, xtWord4 len, char *data)
755
from = dest + field->offset(table->getDefaultValues());
756
switch (field->real_type()) {
758
case MYSQL_TYPE_TINY_BLOB:
759
case MYSQL_TYPE_MEDIUM_BLOB:
760
case MYSQL_TYPE_LONG_BLOB:
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;
767
field->ptr = (char *) from;
768
((Field_blob *) field)->set_ptr(len, data);
769
field->ptr = save; // Restore org row pointer
771
xtWord4 packlength = ((Field_blob *) field)->pack_length_no_ptr();
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*));
777
mx_set_notnull_in_record(table, field, dest);
781
case MYSQL_TYPE_STRING:
783
mx_set_notnull_in_record(field, dest);
784
memcpy(from, data, len);
789
/* And I think that fill will do this for me... */
790
field->charset()->cset->fill(field->charset(), from + len, field->field_length - len, ' ');
792
case MYSQL_TYPE_VAR_STRING:
793
int2store(from, len);
795
mx_set_notnull_in_record(field, dest);
796
memcpy(from+HA_KEY_BLOB_LENGTH, data, len);
800
case MYSQL_TYPE_VARCHAR:
801
if (((Field_varstring *) field)->pack_length_no_ptr() == 1)
802
*((unsigned char *) from) = (unsigned char) len;
804
int2store(from, len);
806
mx_set_notnull_in_record(table, field, dest);
807
memcpy(from+((Field_varstring *) field)->pack_length_no_ptr(), data, len);
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:
827
case MYSQL_TYPE_NEWDECIMAL:
828
case MYSQL_TYPE_ENUM:
830
case MYSQL_TYPE_GEOMETRY:
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:
846
mx_set_notnull_in_record(table, field, dest);
847
memcpy(from, data, len);
850
bzero(from, field->pack_length());
853
xtPublic void myxt_set_null_row_from_key(XTOpenTablePtr XT_UNUSED(ot), XTIndexPtr ind, xtWord1 *record)
855
register XTIndexSegRec *keyseg = ind->mi_seg;
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;
863
xtPublic void myxt_set_default_row_from_key(XTOpenTablePtr ot, XTIndexPtr ind, xtWord1 *record)
865
XTTableHPtr tab = ot->ot_table;
866
STRUCT_TABLE *table = tab->tab_dic.dic_my_table;
867
XTIndexSegRec *keyseg = ind->mi_seg;
869
xt_lock_mutex_ns(&tab->tab_dic_field_lock);
871
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
873
u_int col_idx = keyseg->col_idx;
874
Field *field = GET_TABLE_FIELDS(table)[col_idx];
875
byte *field_save = field->ptr;
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;
882
field->ptr = field_save;
885
xt_unlock_mutex_ns(&tab->tab_dic_field_lock);
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)
891
byte *record = (byte *) dest_buff;
894
register XTIndexSegRec *keyseg = ind->mi_seg;
896
/* GOTCHA: When selecting from multiple
897
* indexes the key values are "merged" into the
899
* This means that this function must not affect
900
* the value of any other feilds.
902
* I was setting all to NULL:
903
memset(dest_buff, 0xFF, GET_TABLE_SHARE(table)->null_bytes);
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) {
911
record[keyseg->null_pos] |= keyseg->null_bit;
914
record[keyseg->null_pos] &= ~keyseg->null_bit;
917
if (keyseg->type == HA_KEYTYPE_BIT)
919
uint length = keyseg->length;
921
if (keyseg->bit_length)
924
set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
930
clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
933
memcpy(record + keyseg->start, (byte*) key, length);
938
if (keyseg->flag & HA_SPACE_PACK)
941
get_key_length(length,key);
943
if (length > keyseg->length || key+length > key_end)
946
pos = record+keyseg->start;
948
if (keyseg->type != (int) HA_KEYTYPE_NUM)
951
memcpy(pos,key,(size_t) length);
952
bfill(pos+length,keyseg->length-length,' ');
957
bfill(pos,keyseg->length-length,' ');
958
memcpy(pos+keyseg->length-length,key,(size_t) length);
965
if (keyseg->flag & HA_VAR_LENGTH_PART)
968
get_key_length(length,key);
970
if (length > keyseg->length || key+length > key_end)
973
/* Store key length */
974
if (keyseg->bit_start == 1)
975
*(uchar*) (record+keyseg->start)= (uchar) length;
977
int2store(record+keyseg->start, length);
979
memcpy(record+keyseg->start + keyseg->bit_start, (byte*) key, length);
982
else if (keyseg->flag & HA_BLOB_PART)
985
get_key_length(length,key);
987
if (length > keyseg->length || key+length > key_end)
990
/* key is a pointer into ot_ind_rbuf, which should be
991
* safe until we move to the next index item!
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*));
997
my_store_blob_length(record+keyseg->start,
998
(uint) keyseg->bit_start,length);
1001
else if (keyseg->flag & HA_SWAP_KEY)
1003
byte *to= record+keyseg->start+keyseg->length;
1004
byte *end= key+keyseg->length;
1011
} while (key != end);
1017
if (key+keyseg->length > key_end)
1020
memcpy(record+keyseg->start,(byte*) key,
1021
(size_t) keyseg->length);
1022
key+= keyseg->length;
1030
return FAILED; /* Crashed row */
1035
* -----------------------------------------------------------------------
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)
1042
uint length= a_length < b_length ? a_length : b_length;
1043
uchar *end= a+ length;
1047
if ((flag= (int) *a++ - (int) *b++))
1049
if (part_key && b_length < a_length)
1051
if (skip_end_space && a_length != b_length)
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.
1059
This code is identical to the one in
1060
strings/ctype-simple.c:my_strnncollsp_simple
1062
if (a_length < b_length)
1064
/* put shorter key in a */
1067
swap= -1; /* swap sign of result */
1069
for (end= a + a_length-length; a < end ; a++)
1072
return (*a < ' ') ? -swap : swap;
1076
return (int) (a_length-b_length);
1079
xtPublic u_int myxt_get_key_length(XTIndexPtr ind, xtWord1 *key_buf)
1081
register XTIndexSegRec *keyseg = ind->mi_seg;
1082
register uchar *key_data = (uchar *) key_buf;
1086
for (u_int i=0; i<ind->mi_seg_count; i++, keyseg++) {
1087
/* Handle NULL part */
1088
if (keyseg->null_bit) {
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);
1099
seg_len = keyseg->length;
1100
key_data += seg_len;
1102
case HA_KEYTYPE_BINARY:
1103
if (keyseg->flag & HA_SPACE_PACK) {
1104
get_key_pack_length(seg_len, pack_len, key_data);
1107
seg_len = keyseg->length;
1108
key_data += seg_len;
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;
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;
1121
case HA_KEYTYPE_NUM: {
1123
if (keyseg->flag & HA_SPACE_PACK)
1124
seg_len = *key_data++;
1126
seg_len = keyseg->length;
1127
key_data += seg_len;
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:
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;
1144
case HA_KEYTYPE_END:
1150
u_int ilen = (xtWord1 *) key_data - key_buf;
1151
if (ilen > XT_INDEX_MAX_KEY_SIZE)
1152
ind->mi_key_corrupted = TRUE;
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)
1159
register XTIndexSegRec *keyseg = ind->mi_seg;
1161
register uchar *a = (uchar *) key_value;
1163
register uchar *b = (uchar *) b_value;
1165
uint next_key_length;
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);
1173
/* Handle NULL part */
1174
if (keyseg->null_bit) {
1175
/* 1 is not null, 0 is null */
1176
int b_not_null = (int) *b++;
1179
if ((int) *a != b_not_null && piks)
1181
flag = (int) *a - b_not_null;
1182
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
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)
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.
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
1200
* The truth is, a NULL only takes up one byte in the key, and this has already
1203
next_key_length = key_length;
1204
continue; /* To next key part */
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;
1214
end = a + key_length;
1215
next_key_length = 0;
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);
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);
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);
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);
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);
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);
1262
case HA_KEYTYPE_VARTEXT1:
1263
case HA_KEYTYPE_VARTEXT2:
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);
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);
1277
case HA_KEYTYPE_VARBINARY1:
1278
case HA_KEYTYPE_VARBINARY2:
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);
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);
1292
case HA_KEYTYPE_INT8:
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);
1299
b += keyseg->length;
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);
1308
b += keyseg->length;
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);
1317
b += keyseg->length;
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);
1327
b += keyseg->length;
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);
1336
b += keyseg->length;
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);
1346
b += keyseg->length;
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);
1355
b += keyseg->length;
1358
case HA_KEYTYPE_FLOAT: {
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
1368
if (piks && (flag = CMP_NUM(f_1, f_2)))
1369
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1371
b += keyseg->length;
1375
case HA_KEYTYPE_DOUBLE: {
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
1385
if (piks && (flag = CMP_NUM(d_1, d_2)))
1386
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
1388
b += keyseg->length;
1392
case HA_KEYTYPE_NUM: {
1394
if (keyseg->flag & HA_SPACE_PACK) {
1397
next_key_length = key_length - a_length - 1;
1401
a_length = (int) (end - a);
1402
b_length = keyseg->length;
1405
/* remove pre space from keys */
1406
for ( ; a_length && *a == ' ' ; a++, a_length--) ;
1407
for ( ; b_length && *b == ' ' ; b++, b_length--) ;
1409
if (keyseg->flag & HA_REVERSE_SORT) {
1410
swap_variables(uchar *, a, b);
1411
swap_variables(uint, a_length, b_length);
1419
swap_variables(uchar *, a, b);
1420
swap_variables(uint, a_length, b_length);
1421
a_length--; b_length--;
1425
while (a_length && (*a == '+' || *a == '0')) {
1429
while (b_length && (*b == '+' || *b == '0')) {
1433
if (a_length != b_length)
1434
return (a_length < b_length) ? -1 : 1;
1437
return ((int) a[-1] - (int) b[-1]);
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);
1453
b += keyseg->length;
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);
1462
b += keyseg->length;
1467
case HA_KEYTYPE_BIT:
1468
/* TODO: What here? */
1471
case HA_KEYTYPE_END: /* Ready */
1480
xtPublic u_int myxt_key_seg_length(XTIndexSegRec *keyseg, u_int key_offset, xtWord1 *key_value)
1482
register xtWord1 *a = (xtWord1 *) key_value + key_offset;
1485
u_int key_length = 0;
1488
/* Handle NULL part */
1489
if (keyseg->null_bit) {
1491
/* If the value is null, then it only requires one byte: */
1496
key_length = has_null + keyseg->length;
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;
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;
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;
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:
1527
case HA_KEYTYPE_LONG_INT:
1528
case HA_KEYTYPE_ULONG_INT:
1529
case HA_KEYTYPE_DOUBLE:
1532
case HA_KEYTYPE_NUM: {
1534
if (keyseg->flag & HA_SPACE_PACK) {
1536
key_length = has_null + a_length + 1;
1541
#ifdef HAVE_LONG_LONG
1542
case HA_KEYTYPE_LONGLONG:
1543
case HA_KEYTYPE_ULONGLONG:
1547
case HA_KEYTYPE_BIT:
1548
/* TODO: What here? */
1551
case HA_KEYTYPE_END: /* Ready */
1559
* -----------------------------------------------------------------------
1560
* Load and store rows
1563
xtPublic xtWord4 myxt_store_row_length(XTOpenTablePtr ot, char *rec_buff)
1565
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1569
xtWord4 row_size = 0;
1571
for (Field* const *field=GET_TABLE_FIELDS(table); *field ; field++) {
1572
if ((*field)->is_null_in_record((const uchar *) rec_buff)) {
1578
sdata = mx_get_length_and_data(table, *field, rec_buff, &dlen);
1580
/* Empty, but not null (blobs may return NULL, when
1583
sdata = rec_buff; // Any valid pointer will do
1584
item_size = 1 + dlen;
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;
1593
item_size = 5 + dlen;
1596
row_size += item_size;
1601
xtPublic xtWord4 myxt_store_row_data(XTOpenTablePtr ot, xtWord4 row_size, char *rec_buff)
1603
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1608
for (Field * const* field=GET_TABLE_FIELDS(table); *field; field++) {
1609
if (mx_is_null_in_record(table, *field, rec_buff)) {
1615
sdata = mx_get_length_and_data(table, *field, rec_buff, &dlen);
1617
/* Empty, but not null (blobs may return NULL, when
1620
sdata = rec_buff; // Any valid pointer will do
1621
item_size = 1 + dlen;
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;
1630
item_size = 5 + dlen;
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))
1636
ot->ot_row_wbuf_size = row_size + item_size;
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);
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);
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);
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);
1661
row_size += item_size;
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)
1674
col_cnt = ot->ot_table->tab_dic.dic_no_of_cols;
1676
col_cnt = *ret_col_cnt;
1677
for (i=0; i<col_cnt; i++) {
1678
if (size + 1 > buffer_size)
1680
switch (*source_buf) {
1681
case 255: // Indicate NULL value
1685
case 254: // 2 bytes length
1686
if (size + 3 > buffer_size)
1688
len = XT_GET_DISK_2(source_buf + 1);
1689
if (size + 3 + len > buffer_size)
1692
source_buf += 3 + len;
1694
case 253: // 3 bytes length
1695
if (size + 4 > buffer_size)
1697
len = XT_GET_DISK_3(source_buf + 1);
1698
if (size + 4 + len > buffer_size)
1701
source_buf += 4 + len;
1703
case 252: // 4 bytes length
1704
if (size + 5 > buffer_size)
1706
len = XT_GET_DISK_4(source_buf + 1);
1707
if (size + 5 + len > buffer_size)
1710
source_buf += 5 + len;
1712
default: // Length byte
1714
if (size + 1 + len > buffer_size)
1717
source_buf += 1 + len;
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)
1731
xtWord1 *input_buf = source_buf;
1732
STRUCT_TABLE *table;
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);
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".
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;
1752
switch (*source_buf) {
1753
case 255: // Indicate NULL value
1758
case 254: // 2 bytes length
1759
len = XT_GET_DISK_2(source_buf + 1);
1762
case 253: // 3 bytes length
1763
len = XT_GET_DISK_3(source_buf + 1);
1766
case 252: // 4 bytes length
1767
len = XT_GET_DISK_4(source_buf + 1);
1770
default: // Length byte
1771
if (*source_buf > 240) {
1772
xt_register_xterr(XT_REG_CONTEXT, XT_ERR_BAD_RECORD_FORMAT);
1781
mx_set_length_and_data(table, curr_field, (char *) dest_buff, 0, NULL);
1783
mx_set_length_and_data(table, curr_field, (char *) dest_buff, len, (char *) source_buf);
1787
return (xtWord4) (source_buf - input_buf);
1790
xtPublic xtBool myxt_load_row(XTOpenTablePtr ot, xtWord1 *source_buf, xtWord1 *dest_buff, u_int col_cnt)
1792
return myxt_load_row_data(ot, source_buf, dest_buff, col_cnt) != 0;
1795
xtPublic xtBool myxt_find_column(XTOpenTablePtr ot, u_int *col_idx, const char *col_name)
1797
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1800
for (Field * const *field=GET_TABLE_FIELDS(table); *field; field++, i++) {
1801
if (!my_strcasecmp(system_charset_info, (*field)->field_name, col_name)) {
1809
xtPublic void myxt_get_column_name(XTOpenTablePtr ot, u_int col_idx, u_int len, char *col_name)
1811
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1814
field = GET_TABLE_FIELDS(table)[col_idx];
1815
xt_strcpy(len, col_name, field->field_name);
1818
xtPublic void myxt_get_column_as_string(XTOpenTablePtr ot, char *buffer, u_int col_idx, u_int len, char *value)
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);
1827
if (mx_is_null_in_record(table, field, buffer))
1828
xt_strcpy(len, value, "NULL");
1833
/* Required by store() - or an assertion will fail: */
1834
if (table->read_set)
1835
MX_BIT_SET(table->read_set, col_idx);
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());
1849
xtPublic xtBool myxt_set_column(XTOpenTablePtr ot, char *buffer, u_int col_idx, const char *value, u_int len)
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];
1859
/* Required by store() - or an assertion will fail: */
1860
if (table->write_set)
1861
MX_BIT_SET(table->write_set, col_idx);
1864
mx_set_notnull_in_record(table, field, buffer);
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;
1876
xtPublic void myxt_get_column_data(XTOpenTablePtr ot, char *buffer, u_int col_idx, char **value, size_t *len)
1878
STRUCT_TABLE *table = ot->ot_table->tab_dic.dic_my_table;
1879
Field *field = GET_TABLE_FIELDS(table)[col_idx];
1883
sdata = mx_get_length_and_data(table, field, buffer, &dlen);
1888
xtPublic xtBool myxt_store_row(XTOpenTablePtr ot, XTTabRecInfoPtr rec_info, char *rec_buff)
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;
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);
1901
if (!(row_size = myxt_store_row_data(ot, XT_REC_EXT_HEADER_SIZE, rec_buff)))
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;
1908
rec_info->ri_fix_rec_buf->tr_rec_type_1 = XT_TAB_STATUS_VARIABLE;
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)];
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);
1924
static void mx_print_string(uchar *s, uint count)
1927
if (s[count - 1] != ' ')
1932
for (u_int i=0; i<count; i++, s++)
1937
xtPublic void myxt_print_key(XTIndexPtr ind, xtWord1 *key_value)
1939
register XTIndexSegRec *keyseg = ind->mi_seg;
1940
register uchar *b = (uchar *) key_value;
1944
for (u_int i = 0; i < ind->mi_seg_count; i++, keyseg++) {
1947
if (keyseg->null_bit) {
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);
1959
b_length = keyseg->length;
1960
mx_print_string(b, b_length);
1963
case HA_KEYTYPE_LONG_INT: {
1964
int32_t l_2 = sint4korr(b);
1965
b += keyseg->length;
1966
printf("%ld", (long) l_2);
1969
case HA_KEYTYPE_ULONG_INT: {
1970
xtWord4 u_2 = sint4korr(b);
1971
b += keyseg->length;
1972
printf("%lu", (u_long) u_2);
1982
* -----------------------------------------------------------------------
1983
* MySQL Data Dictionary
1986
static void my_close_table(STRUCT_TABLE *share)
1992
* This function returns NULL if the table cannot be opened
1993
* because this is not a MySQL thread.
1995
static STRUCT_TABLE *my_open_table(XTThreadPtr self, XTDatabaseHPtr XT_UNUSED(db), XTPathStrPtr tab_path, xtWord1 table_type)
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;
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
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);
2015
xt_2nd_last_name_of_path(XT_IDENTIFIER_NAME_SIZE, database_name, tab_path->ps_path);
2017
TableIdentifier *ident = NULL;
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);
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);
2032
std::string n(getDataHomeCatalog());
2034
n.append(database_name);
2036
n.append(tab_file_name);
2037
ident = new TableIdentifier(database_name, tab_name, n);
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);
2052
static bool my_match_index(XTDDIndex *ind, KEY *index)
2054
KEY_PART_INFO *key_part;
2055
KEY_PART_INFO *key_part_end;
2057
XTDDColumnRef *cref;
2059
if (index->key_parts != ind->co_cols.size())
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)))
2067
if (myxt_strcasecmp(cref->cr_col_name, (char *) key_part->field->field_name) != 0)
2071
if (ind->co_type == XT_DD_KEY_PRIMARY) {
2072
if (!(index->flags & HA_NOSAME))
2076
if (ind->co_type == XT_DD_INDEX_UNIQUE) {
2077
if (!(index->flags & HA_NOSAME))
2080
if (ind->co_ind_name) {
2081
if (myxt_strcasecmp(ind->co_ind_name, index->name) != 0)
2089
static XTDDIndex *my_find_index(XTDDTable *dd_tab, KEY *index)
2093
for (u_int i=0; i<dd_tab->dt_indexes.size(); i++)
2095
ind = dd_tab->dt_indexes.itemAt(i);
2096
if (my_match_index(ind, index))
2103
static void my_deref_index_data(struct XTThread *self, XTIndexPtr mi)
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);
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);
2121
static xtBool my_is_not_null_int4(XTIndexSegPtr seg)
2123
return (seg->type == HA_KEYTYPE_LONG_INT && !(seg->flag & HA_NULL_PART));
2126
/* MY_BITMAP definition in Drizzle does not like if
2127
* I use a NULL pointer to calculate the offset!?
2129
#define MX_OFFSETOF(x, y) ((size_t)(&((x *) 8)->y) - 8)
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)
2135
KeyPartInfo *key_part;
2136
KeyPartInfo *key_part_end;
2139
enum ha_base_keytype type;
2141
u_int key_length = 0;
2142
xtBool partial_field;
2146
pushsr_(ind, my_deref_index_data, (XTIndexPtr) xt_calloc(self, MX_OFFSETOF(XTIndexRec, mi_seg) + sizeof(XTIndexSegRec) * index->key_parts));
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);
2159
ind->mi_seg_count = (uint) index->key_parts;
2160
key_part_end = index->key_part + index->key_parts;
2162
for (key_part = index->key_part; key_part != key_part_end; key_part++, seg++) {
2163
partial_field = FALSE;
2164
field = key_part->field;
2166
type = field->key_type();
2167
seg->flag = key_part->key_part_flag;
2169
if (options & HA_OPTION_PACK_KEYS ||
2170
(index->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | HA_SPACE_PACK_USED)))
2172
if (key_part->length > 8 && (type == HA_KEYTYPE_TEXT ||
2174
type == HA_KEYTYPE_NUM ||
2176
(type == HA_KEYTYPE_BINARY && !field->zero_pack())))
2179
if (key_part == index->key_part)
2180
ind->mi_flags |= HA_PACK_KEY;
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;
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();
2201
if (field->null_ptr) {
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());
2212
if (field->real_type() == MYSQL_TYPE_ENUM
2214
|| field->real_type() == MYSQL_TYPE_SET
2217
/* This values are not indexed as string!!
2218
* The index will not be built correctly if this value is non-NULL.
2220
seg->charset = NULL;
2223
if (field->type() == MYSQL_TYPE_BLOB
2225
|| field->type() == MYSQL_TYPE_GEOMETRY
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();
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());
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) {
2246
seg->type = HA_KEYTYPE_USHORT_INT;
2249
seg->type = HA_KEYTYPE_UINT24;
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);
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 */
2277
key_length += seg->length;
2278
if (seg->length > 40)
2279
ind->mi_fix_key = FALSE;
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
2286
if (field->type() == MYSQL_TYPE_BLOB)
2287
partial_field = TRUE;
2288
else if (field->real_type() == MYSQL_TYPE_VARCHAR // For varbinary type
2290
|| field->real_type() == MYSQL_TYPE_VAR_STRING // For varbinary type
2291
|| field->real_type() == MYSQL_TYPE_STRING // For binary type
2295
Field *tab_field = GET_TABLE_FIELDS(table_arg)[key_part->fieldnr-1];
2296
u_int field_len = tab_field->key_length();
2298
if (key_part->length != field_len)
2299
partial_field = TRUE;
2302
/* NOTE: do not set if the field is only partially in the index!!! */
2304
MX_BIT_FAST_TEST_AND_SET(&ind->mi_col_map, field->field_index);
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);
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);
2314
if (ind->mi_fix_key) {
2315
/* Special case for not-NULL 4 byte int value: */
2316
switch (ind->mi_seg_count) {
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;
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;
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;
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;
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;
2351
ind->mi_lazy_delete = ind->mi_fix_key && ind->mi_max_items >= 4;
2353
XT_NODE_ID(ind->mi_root) = 0;
2355
popr_(); // Discard my_deref_index_data(ind)
2360
/* We estimate the size of BLOBs depending on the number
2361
* of BLOBs in the table.
2363
static u_int mx_blob_field_size_total[] = {
2376
static u_int mxvarchar_field_min_ave[] = {
2389
xtPublic void myxt_setup_dictionary(XTThreadPtr self, XTDictionaryPtr dic)
2391
STRUCT_TABLE *my_tab = dic->dic_my_table;
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;
2406
xtBool dic_rec_fixed;
2408
Field * const *field;
2410
/* How many columns are required for all indexes. */
2412
KeyPartInfo *key_part;
2413
KeyPartInfo *key_part_end;
2415
#ifndef XT_USE_LAZY_DELETE
2416
dic->dic_no_lazy_delete = TRUE;
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);
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;
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;
2432
/* We will work out how many columns are required for all blobs: */
2433
dic->dic_blob_cols_req = 0;
2435
for (field=GET_TABLE_FIELDS(my_tab); (curr_field = *field); field++) {
2437
min_data_size = curr_field->key_length();
2438
max_data_size = curr_field->key_length();
2439
enum_field_types tno = curr_field->type();
2441
min_ave_row_size = 40;
2442
max_ave_row_size = 128;
2443
if (tno == MYSQL_TYPE_BLOB) {
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];
2453
max_ave_row_size = 200;
2454
large_blob_field_count++;
2456
else if (max_data_size == 0xFFFFFFFF) {
2457
/* Scale the estimated size of the blob depending on how many BLOBs
2460
if (large_blob_field_count < 10)
2461
max_ave_row_size = mx_blob_field_size_total[large_blob_field_count];
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;
2472
else if (tno == MYSQL_TYPE_VARCHAR
2474
|| tno == MYSQL_TYPE_VAR_STRING
2477
/* GOTCHA: MYSQL_TYPE_VAR_STRING does not exist as MYSQL_TYPE_VARCHAR define, but
2478
* is used when creating a table with
2482
if (varchar_field_count < 10)
2483
min_ave_row_size = mxvarchar_field_min_ave[varchar_field_count];
2485
min_ave_row_size = 40;
2486
varchar_field_count++;
2489
if (max_data_size == min_data_size)
2490
ave_data_size = max_data_size;
2493
/* Take the average a 25% of the maximum: */
2494
ave_data_size = max_data_size / 4;
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;
2502
if (ave_data_size > max_data_size)
2503
ave_data_size = max_data_size;
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;
2514
min_row_size += 5 + min_data_size;
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;
2523
max_row_size += 5 + max_data_size;
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;
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.
2535
if (field_count == dic->dic_ind_cols_req)
2536
dic->dic_ind_rec_len = max_row_size;
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;
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();
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;
2555
xtWord8 new_rec_size;
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;
2561
new_rec_size = offsetof(XTTabRecFix, rf_data) + dic->dic_def_ave_row_size;
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;
2567
dic_rec_size = (u_int) new_rec_size;
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.
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:
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;
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!
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;
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
2607
if (!dic_rec_fixed) {
2608
if (dic_rec_size < offsetof(XTTabRecExtDRec, re_data))
2609
dic_rec_size = offsetof(XTTabRecExtDRec, re_data);
2613
ASSERT_NS(dic_rec_size > offsetof(XTTabRecFix, rf_data));
2617
if (!dic->dic_rec_size) {
2618
dic->dic_rec_size = dic_rec_size;
2619
dic->dic_rec_fixed = dic_rec_fixed;
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).
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
2631
* Note that this can occur in rename table when the
2632
* method of calculation has changed.
2634
* On rename, the format of the table does not change, so we
2635
* will not take the calculated values.
2637
//ASSERT(dic->dic_rec_size == dic_rec_size);
2638
//ASSERT(dic->dic_rec_fixed == dic_rec_fixed);
2641
if (dic_rec_fixed) {
2642
/* Recalculate the length of the required required to address all
2645
if (field_count == dic->dic_ind_cols_req)
2646
dic->dic_ind_rec_len = GET_TABLE_SHARE(my_tab)->getRecordLength();
2648
field=GET_TABLE_FIELDS(my_tab);
2650
curr_field = field[dic->dic_ind_cols_req];
2651
dic->dic_ind_rec_len = curr_field->offset(my_tab->getDefaultValues());
2655
/* We now calculate how many of the first columns in the row
2656
* will definitely fit into the buffer, when the record is
2659
* In this way we can figure out if we need to load the extended
2662
dic->dic_fix_col_count = 0;
2663
if (!dic_rec_fixed) {
2664
xtWord8 max_rec_size = offsetof(XTTabRecExt, re_data);
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;
2678
max_rec_size += 5 + max_data_size;
2679
if (max_rec_size > (xtWord8) dic_rec_size)
2681
dic->dic_fix_col_count++;
2683
ASSERT(dic->dic_fix_col_count < dic->dic_no_of_cols);
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();
2691
static u_int my_get_best_superset(XTThreadPtr XT_UNUSED(self), XTDictionaryPtr dic, XTIndexPtr ind)
2693
XTIndexPtr super_ind;
2695
u_int super_seg_count = ind->mi_seg_count;
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)
2705
super_seg_count = super_ind->mi_seg_count;
2714
* Return FAILED if the MySQL dictionary is not available.
2716
xtPublic xtBool myxt_load_dictionary(XTThreadPtr self, XTDictionaryPtr dic, XTDatabaseHPtr db, XTPathStrPtr tab_path)
2718
STRUCT_TABLE *my_tab;
2720
if (!(my_tab = my_open_table(self, db, tab_path, dic->dic_table_type)))
2722
dic->dic_my_table = my_tab;
2724
dic->dic_def_ave_row_size = (xtWord8) GET_TABLE_SHARE(my_tab)->getTableProto()->options().avg_row_length();
2726
dic->dic_def_ave_row_size = (xtWord8) GET_TABLE_SHARE(my_tab)->avg_row_length;
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));
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]);
2740
xtPublic void myxt_free_dictionary(XTThreadPtr self, XTDictionaryPtr dic)
2742
if (dic->dic_table) {
2743
dic->dic_table->release(self);
2744
dic->dic_table = NULL;
2747
if (dic->dic_my_table) {
2748
my_close_table(dic->dic_my_table);
2749
dic->dic_my_table = NULL;
2752
if (dic->dic_blob_cols) {
2753
xt_free(self, dic->dic_blob_cols);
2754
dic->dic_blob_cols = NULL;
2756
dic->dic_blob_count = 0;
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]);
2764
xt_free(self, dic->dic_keys);
2765
dic->dic_key_count = 0;
2766
dic->dic_keys = NULL;
2770
xtPublic void myxt_move_dictionary(XTDictionaryPtr dic, XTDictionaryPtr source_dic)
2772
dic->dic_my_table = source_dic->dic_my_table;
2773
source_dic->dic_my_table = NULL;
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;
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).
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
2789
ASSERT_NS(dic->dic_rec_size == source_dic->dic_rec_size);
2790
ASSERT_NS(dic->dic_rec_fixed == source_dic->dic_rec_fixed);
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;
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;
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;
2808
source_dic->dic_key_count = 0;
2809
source_dic->dic_keys = NULL;
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;
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;
2822
static void my_free_dd_table(XTThreadPtr self, XTDDTable *dd_tab)
2825
dd_tab->release(self);
2828
static void ha_create_dd_index(XTThreadPtr self, XTDDIndex *ind, KeyInfo *key)
2830
KeyPartInfo *key_part;
2831
KeyPartInfo *key_part_end;
2832
XTDDColumnRef *cref;
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;
2839
ind->co_type = XT_DD_INDEX;
2841
if (ind->co_type == XT_DD_KEY_PRIMARY)
2842
ind->co_name = xt_dup_string(self, key->name);
2844
ind->co_ind_name = xt_dup_string(self, key->name);
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);
2851
ind->co_cols.append(self, cref);
2852
cref->cr_col_name = xt_dup_string(self, (char *) key_part->field->field_name);
2856
static char *my_type_to_string(XTThreadPtr self, Field *field, STRUCT_TABLE *XT_UNUSED(my_tab))
2858
char buffer[MAX_FIELD_WIDTH + 400];
2860
String type((char *) buffer, sizeof(buffer), system_charset_info);
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).
2871
field->sql_type(type);
2873
len = type.length();
2875
if (len >= sizeof(buffer))
2876
len = sizeof(buffer)-1;
2879
xt_strcpy(sizeof(buffer), buffer, ptr);
2883
if (field->has_charset()) {
2884
/* Always include the charset so that we can compare types
2885
* for FK/PK releations.
2887
xt_strcat(sizeof(buffer), buffer, " CHARACTER SET ");
2888
xt_strcat(sizeof(buffer), buffer, (char *) field->charset()->csname);
2890
/* For string types dump collation name only if
2891
* collation is not primary for the given charset
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);
2899
return xt_dup_string(self, buffer); // type.length()
2902
xtPublic XTDDTable *myxt_create_table_from_table(XTThreadPtr self, STRUCT_TABLE *my_tab)
2909
if (!(dd_tab = new XTDDTable()))
2910
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
2912
pushr_(my_free_dd_table, dd_tab);
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);
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;
2925
ha_create_dd_index(self, ind, &my_tab->getKeyInfo(i));
2928
popr_(); // my_free_dd_table(dd_tab)
2933
* -----------------------------------------------------------------------
2934
* MySQL CHARACTER UTILITIES
2937
xtPublic void myxt_static_convert_identifier(XTThreadPtr XT_UNUSED(self), MX_CONST_CHARSET_INFO *cs, char *from, char *to, size_t to_len)
2941
xt_strcpy(to_len, to, from);
2947
* Check that identifiers and strings are not converted
2948
* when the client character set is binary.
2950
if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin)
2951
xt_strcpy(to_len, to, from);
2953
strconvert(cs, from, &my_charset_utf8_general_ci, to, to_len, &errors);
2957
// cs == current_thd->charset()
2958
xtPublic char *myxt_convert_identifier(XTThreadPtr self, MX_CONST_CHARSET_INFO *cs, char *from)
2961
char *to = xt_dup_string(self, from);
2968
if (cs == &my_charset_utf8_general_ci || cs == &my_charset_bin)
2969
to = xt_dup_string(self, from);
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);
2979
xtPublic char *myxt_convert_table_name(XTThreadPtr self, char *from)
2984
len = strlen(from) * 5 + 1;
2985
to = (char *) xt_malloc(self, len);
2986
tablename_to_filename(from, to, len);
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.
2995
xtPublic xtBool myxt_temp_table_name(const char *table)
3000
name = xt_last_name_of_path(table);
3002
yup = (strncmp(name, "#sql", 4) == 0);
3005
yup = (strncmp(name, "#sql-", 5) == 0) || (strncmp(name, "#sql2-", 6) == 0);
3010
xtPublic void myxt_static_convert_table_name(XTThreadPtr XT_UNUSED(self), char *from, char *to, size_t to_len)
3012
tablename_to_filename(from, to, to_len);
3015
xtPublic void myxt_static_convert_file_name(char *from, char *to, size_t to_len)
3017
uint32_t len = TableIdentifier::filename_to_tablename(from, to, to_len);
3023
xtPublic int myxt_strcasecmp(char * a, char *b)
3025
return my_strcasecmp(&my_charset_utf8_general_ci, a, b);
3028
xtPublic int myxt_isspace(MX_CONST_CHARSET_INFO *cs, char a)
3030
return my_isspace(cs, a);
3033
xtPublic int myxt_ispunct(MX_CONST_CHARSET_INFO *cs, char a)
3035
return my_ispunct(cs, a);
3038
xtPublic int myxt_isdigit(MX_CONST_CHARSET_INFO *cs, char a)
3040
return my_isdigit(cs, a);
3043
xtPublic MX_CONST_CHARSET_INFO *myxt_getcharset(bool convert)
3046
THD *thd = current_thd;
3049
return (MX_CHARSET_INFO *)thd_charset(thd);
3051
return (MX_CHARSET_INFO *)&my_charset_utf8_general_ci;
3054
xtPublic xtBool myxt_create_thread_possible()
3057
if (!global_system_variables.table_plugin) {
3058
xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MYSQL_NO_THREAD);
3065
xtPublic void *myxt_create_thread()
3071
if (drizzled::internal::my_thread_init()) {
3072
xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading");
3076
if (!(client = new NullClient()))
3078
session = new Session(client);
3079
session->thread_stack = (char *) &session;
3080
session->storeGlobals();
3081
return (void *) session;
3085
if (my_thread_init()) {
3086
xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to initialize MySQL threading");
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!
3095
* The following call in plugin_shutdown() sets the global reference
3098
* unlock_variables(NULL, &global_system_variables);
3100
* Later plugin_deinitialize() is called.
3102
* The following stack is an example crash which occurs when I call
3103
* myxt_create_thread() in ha_exit(), to force the error.
3105
* if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
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
3125
if (!global_system_variables.table_plugin) {
3126
xt_register_xterr(XT_REG_CONTEXT, XT_ERR_MYSQL_NO_THREAD);
3130
if (!(new_thd = new THD)) {
3132
xt_register_error(XT_REG_CONTEXT, XT_ERR_MYSQL_ERROR, 0, "Unable to create MySQL thread (THD)");
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
3142
* The server then issues a message that it is forcing shutdown of the plugin.
3144
* However, the engine reference is not required by the THDs used by PBXT, so
3145
* I just remove them here.
3147
plugin_unlock(NULL, new_thd->variables.table_plugin);
3148
new_thd->variables.table_plugin = NULL;
3150
new_thd->thread_stack = (char *) &new_thd;
3151
new_thd->store_globals();
3154
return (void *) new_thd;
3159
xtPublic void myxt_destroy_thread(void *s, xtBool end_threads)
3161
Session *session = (Session *) s;
3163
session->lockForDelete();
3167
drizzled::internal::my_thread_end();
3170
xtPublic void myxt_destroy_thread(void *thread, xtBool end_threads)
3172
THD *thd = (THD *) thread;
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
3181
close_thread_tables(thd);
3185
close_thread_tables(thd);
3190
/* Remember that we don't have a THD */
3191
my_pthread_setspecific_ptr(THR_THD, 0);
3198
xtPublic void myxt_delete_remaining_thread()
3202
if ((thd = current_thd))
3203
myxt_destroy_thread((void *) thd, TRUE);
3206
xtPublic XTThreadPtr myxt_get_self()
3210
if ((thd = current_thd))
3211
return xt_ha_thd_to_self(thd);
3216
* -----------------------------------------------------------------------
3217
* INFORMATION SCHEMA FUNCTIONS
3222
static int mx_put_record(THD *thd, TABLE *table)
3224
return schema_table_store_record(thd, table);
3228
static void mx_put_int(TABLE *table, int column, int value)
3230
GET_TABLE_FIELDS(table)[column]->store(value, false);
3233
static void mx_put_real8(TABLE *table, int column, xtReal8 value)
3235
GET_TABLE_FIELDS(table)[column]->store(value);
3238
static void mx_put_string(TABLE *table, int column, const char *string, u_int len, charset_info_st *charset)
3240
GET_TABLE_FIELDS(table)[column]->store(string, len, charset);
3244
static void mx_put_u_llong(TABLE *table, int column, u_llong value)
3246
GET_TABLE_FIELDS(table)[column]->store(value, false);
3249
static void mx_put_string(TABLE *table, int column, const char *string, charset_info_st *charset)
3251
GET_TABLE_FIELDS(table)[column]->store(string, strlen(string), charset);
3254
xtPublic int myxt_statistics_fill_table(XTThreadPtr self, void *th, void *ta, void *, MX_CONST void *ch)
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;
3262
const char *stat_name;
3264
XTStatisticsRec statistics;
3265
XTDatabaseHPtr db = self->st_database;
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);
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);
3283
xtPublic void myxt_get_status(XTThreadPtr self, XTStringBufferPtr strbuf)
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");
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");
3317
xt_ht_lock(self, xt_db_open_databases);
3318
pushr_(xt_ht_unlock, xt_db_open_databases);
3320
XTDatabaseHPtr *dbptr;
3321
size_t len = xt_sl_get_size(xt_db_open_db_by_id);
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);
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");
3333
xt_dl_log_status(self, *dbptr, strbuf);
3337
xt_sb_concat(self, strbuf, "No data logs in use\n");
3339
freer_(); // xt_ht_unlock(xt_db_open_databases)
3343
* -----------------------------------------------------------------------
3347
static void myxt_bitmap_init(XTThreadPtr self, MX_BITMAP *map, u_int n_bits)
3350
uint size_in_bytes = (((n_bits) + 31) / 32) * 4;
3352
buf = (my_bitmap_map *) xt_malloc(self, size_in_bytes);
3355
map->init(buf, n_bits);
3358
map->n_bits= n_bits;
3359
create_last_word_mask(map);
3360
bitmap_clear_all(map);
3364
static void myxt_bitmap_free(XTThreadPtr self, MX_BITMAP *map)
3367
my_bitmap_map *buf = map->getBitmap();
3370
map->setBitmap(NULL);
3373
xt_free(self, map->bitmap);
3380
* -----------------------------------------------------------------------
3381
* XTDDColumnFactory methods
3384
XTDDColumn *XTDDColumnFactory::createFromMySQLField(XTThread *self, STRUCT_TABLE *my_tab, Field *field)
3386
XTDDEnumerableColumn *en_col;
3388
xtBool is_enum = FALSE;
3390
switch(field->real_type()) {
3391
case MYSQL_TYPE_ENUM:
3396
case MYSQL_TYPE_SET:
3398
col = en_col = new XTDDEnumerableColumn();
3400
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
3402
en_col->enum_size = ((Field_enum *)field)->typelib->count;
3403
en_col->is_enum = is_enum;
3407
col = new XTDDColumn();
3409
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
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;
3421
* -----------------------------------------------------------------------
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
3432
extern ulong total_ha;
3434
xtPublic void myxt_wait_pbxt_plugin_slot_assigned(XTThread *self)
3437
static std::string plugin_name("PBXT");
3439
while (!self->t_quit && !module::Registry::singleton().find(plugin_name))
3440
xt_sleep_milli_second(1);
3442
while(!self->t_quit && (pbxt_hton->slot >= total_ha))
3443
xt_sleep_milli_second(1);