~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/blob.cc

  • Committer: Jim Winstead
  • Date: 2008-07-19 02:56:45 UTC
  • mto: (202.1.8 codestyle)
  • mto: This revision was merged to the branch mainline in revision 207.
  • Revision ID: jimw@mysql.com-20080719025645-w2pwytebgzusjzjb
Various fixes to enable compilation on Mac OS X, and remove the glib dependency.
Temporarily disables tab-completion in the drizzle client until an appropriate
autoconf check can be added/enabled.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 MySQL
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
 
22
 
#include <config.h>
23
 
#include <drizzled/field/blob.h>
24
 
#include <drizzled/table.h>
25
 
#include <drizzled/session.h>
26
 
#include <plugin/myisam/myisam.h>
27
 
 
28
 
#include <string>
29
 
#include <algorithm>
30
 
 
31
 
using namespace std;
32
 
 
33
 
namespace drizzled
34
 
{
35
 
 
36
 
static uint32_t blob_pack_length_to_max_length(uint32_t arg)
37
 
{
38
 
  return max(UINT32_MAX,
39
 
             (uint32_t)((INT64_C(1) << min(arg, 4U) * 8) - INT64_C(1)));
40
 
}
41
 
 
42
 
 
43
 
/****************************************************************************
44
 
** blob type
45
 
** A blob is saved as a length and a pointer. The length is stored in the
46
 
** packlength slot and is sizeof(uint32_t) (4 bytes)
47
 
****************************************************************************/
48
 
 
49
 
Field_blob::Field_blob(unsigned char *ptr_arg,
50
 
                       unsigned char *null_ptr_arg,
51
 
                       unsigned char null_bit_arg,
52
 
                                   const char *field_name_arg,
53
 
                       TableShare *share,
54
 
                       const CHARSET_INFO * const cs)
55
 
  :Field_str(ptr_arg,
56
 
             blob_pack_length_to_max_length(sizeof(uint32_t)),
57
 
             null_ptr_arg,
58
 
             null_bit_arg,
59
 
             field_name_arg,
60
 
             cs)
61
 
{
62
 
  flags|= BLOB_FLAG;
63
 
  share->blob_fields++;
64
 
  /* TODO: why do not fill table->getShare()->blob_field array here? */
65
 
}
66
 
 
67
 
void Field_blob::store_length(unsigned char *i_ptr,
68
 
                              uint32_t i_number,
69
 
                              bool low_byte_first)
70
 
{
71
 
#ifndef WORDS_BIGENDIAN
72
 
  (void)low_byte_first;
73
 
#endif
74
 
 
75
 
#ifdef WORDS_BIGENDIAN
76
 
  if (low_byte_first)
77
 
  {
78
 
    int4store(i_ptr,i_number);
79
 
  }
80
 
  else
81
 
#endif
82
 
    longstore(i_ptr,i_number);
83
 
}
84
 
 
85
 
 
86
 
void Field_blob::store_length(unsigned char *i_ptr, uint32_t i_number)
87
 
{
88
 
  store_length(i_ptr, i_number, getTable()->getShare()->db_low_byte_first);
89
 
}
90
 
 
91
 
 
92
 
uint32_t Field_blob::get_length(const unsigned char *pos,
93
 
                                bool low_byte_first) const
94
 
{
95
 
#ifndef WORDS_BIGENDIAN
96
 
  (void)low_byte_first;
97
 
#endif
98
 
  uint32_t tmp;
99
 
#ifdef WORDS_BIGENDIAN
100
 
  if (low_byte_first)
101
 
    tmp=uint4korr(pos);
102
 
  else
103
 
#endif
104
 
    longget(tmp,pos);
105
 
  return (uint32_t) tmp;
106
 
}
107
 
 
108
 
 
109
 
uint32_t Field_blob::get_packed_size(const unsigned char *ptr_arg,
110
 
                                bool low_byte_first)
111
 
{
112
 
  return sizeof(uint32_t) + get_length(ptr_arg, low_byte_first);
113
 
}
114
 
 
115
 
 
116
 
uint32_t Field_blob::get_length(uint32_t row_offset) const
117
 
{
118
 
  return get_length(ptr+row_offset,
119
 
                    getTable()->getShare()->db_low_byte_first);
120
 
}
121
 
 
122
 
 
123
 
uint32_t Field_blob::get_length(const unsigned char *ptr_arg) const
124
 
{
125
 
  return get_length(ptr_arg, getTable()->getShare()->db_low_byte_first);
126
 
}
127
 
 
128
 
 
129
 
/**
130
 
  Put a blob length field into a record buffer.
131
 
 
132
 
  Blob length is always stored in sizeof(uint32_t) (4 bytes)
133
 
 
134
 
  @param pos                 Pointer into the record buffer.
135
 
  @param length              The length value to put.
136
 
*/
137
 
 
138
 
void Field_blob::put_length(unsigned char *pos, uint32_t length)
139
 
{
140
 
    int4store(pos, length);
141
 
}
142
 
 
143
 
 
144
 
int Field_blob::store(const char *from,uint32_t length, const CHARSET_INFO * const cs)
145
 
{
146
 
  uint32_t copy_length, new_length;
147
 
  const char *well_formed_error_pos;
148
 
  const char *cannot_convert_error_pos;
149
 
  const char *from_end_pos, *tmp;
150
 
  char buff[STRING_BUFFER_USUAL_SIZE];
151
 
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
152
 
 
153
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
154
 
 
155
 
  if (!length)
156
 
  {
157
 
    memset(ptr, 0, Field_blob::pack_length());
158
 
    return 0;
159
 
  }
160
 
 
161
 
  if (from == value.ptr())
162
 
  {
163
 
    size_t dummy_offset;
164
 
    if (!String::needs_conversion(length, cs, field_charset, &dummy_offset))
165
 
    {
166
 
      Field_blob::store_length(length);
167
 
      memmove(ptr+sizeof(uint32_t), &from, sizeof(char*));
168
 
      return 0;
169
 
    }
170
 
    if (tmpstr.copy(from, length, cs))
171
 
      goto oom_error;
172
 
    from= tmpstr.ptr();
173
 
  }
174
 
 
175
 
  new_length= min(max_data_length(), field_charset->mbmaxlen * length);
176
 
  if (value.alloc(new_length))
177
 
    goto oom_error;
178
 
 
179
 
  /*
180
 
    "length" is OK as "nchars" argument to well_formed_copy_nchars as this
181
 
    is never used to limit the length of the data. The cut of long data
182
 
    is done with the new_length value.
183
 
  */
184
 
  copy_length= well_formed_copy_nchars(field_charset,
185
 
                                       (char*) value.ptr(), new_length,
186
 
                                       cs, from, length,
187
 
                                       length,
188
 
                                       &well_formed_error_pos,
189
 
                                       &cannot_convert_error_pos,
190
 
                                       &from_end_pos);
191
 
 
192
 
  Field_blob::store_length(copy_length);
193
 
  tmp= value.ptr();
194
 
  memmove(ptr+sizeof(uint32_t), &tmp, sizeof(char*));
195
 
 
196
 
  if (check_string_copy_error(this, well_formed_error_pos,
197
 
                              cannot_convert_error_pos, from + length, cs))
198
 
    return 2;
199
 
 
200
 
  return report_if_important_data(from_end_pos, from + length);
201
 
 
202
 
oom_error:
203
 
  /* Fatal OOM error */
204
 
  memset(ptr, 0, Field_blob::pack_length());
205
 
  return -1;
206
 
}
207
 
 
208
 
 
209
 
int Field_blob::store(double nr)
210
 
{
211
 
  const CHARSET_INFO * const cs=charset();
212
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
213
 
  value.set_real(nr, NOT_FIXED_DEC, cs);
214
 
  return Field_blob::store(value.ptr(),(uint32_t) value.length(), cs);
215
 
}
216
 
 
217
 
 
218
 
int Field_blob::store(int64_t nr, bool unsigned_val)
219
 
{
220
 
  const CHARSET_INFO * const cs=charset();
221
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
222
 
  value.set_int(nr, unsigned_val, cs);
223
 
  return Field_blob::store(value.ptr(), (uint32_t) value.length(), cs);
224
 
}
225
 
 
226
 
 
227
 
double Field_blob::val_real(void) const
228
 
{
229
 
  int not_used;
230
 
  char *end_not_used, *blob;
231
 
  uint32_t length;
232
 
  const CHARSET_INFO *cs;
233
 
 
234
 
  ASSERT_COLUMN_MARKED_FOR_READ;
235
 
 
236
 
  memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
237
 
  if (!blob)
238
 
    return 0.0;
239
 
  length= get_length(ptr);
240
 
  cs= charset();
241
 
  return my_strntod(cs, blob, length, &end_not_used, &not_used);
242
 
}
243
 
 
244
 
 
245
 
int64_t Field_blob::val_int(void) const
246
 
{
247
 
  int not_used;
248
 
  char *blob;
249
 
 
250
 
  ASSERT_COLUMN_MARKED_FOR_READ;
251
 
 
252
 
  memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
253
 
  if (!blob)
254
 
    return 0;
255
 
  uint32_t length= get_length(ptr);
256
 
  return my_strntoll(charset(),blob,length,10,NULL,&not_used);
257
 
}
258
 
 
259
 
String *Field_blob::val_str(String *, String *val_ptr) const
260
 
{
261
 
  char *blob;
262
 
 
263
 
  ASSERT_COLUMN_MARKED_FOR_READ;
264
 
 
265
 
  memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
266
 
  if (!blob)
267
 
    val_ptr->set("",0,charset());       // A bit safer than ->length(0)
268
 
  else
269
 
    val_ptr->set((const char*) blob,get_length(ptr),charset());
270
 
  return val_ptr;
271
 
}
272
 
 
273
 
 
274
 
type::Decimal *Field_blob::val_decimal(type::Decimal *decimal_value) const
275
 
{
276
 
  const char *blob;
277
 
  size_t length;
278
 
 
279
 
  ASSERT_COLUMN_MARKED_FOR_READ;
280
 
 
281
 
  memcpy(&blob, ptr+sizeof(uint32_t), sizeof(const unsigned char*));
282
 
  if (!blob)
283
 
  {
284
 
    blob= "";
285
 
    length= 0;
286
 
  }
287
 
  else
288
 
  {
289
 
    length= get_length(ptr);
290
 
  }
291
 
 
292
 
  decimal_value->store(E_DEC_FATAL_ERROR, blob, length, charset());
293
 
 
294
 
  return decimal_value;
295
 
}
296
 
 
297
 
 
298
 
int Field_blob::cmp(const unsigned char *a,uint32_t a_length, const unsigned char *b,
299
 
                    uint32_t b_length)
300
 
{
301
 
  return field_charset->coll->strnncollsp(field_charset,
302
 
                                          a, a_length, b, b_length,
303
 
                                          0);
304
 
}
305
 
 
306
 
 
307
 
int Field_blob::cmp_max(const unsigned char *a_ptr, const unsigned char *b_ptr,
308
 
                        uint32_t max_length)
309
 
{
310
 
  unsigned char *blob1,*blob2;
311
 
  memcpy(&blob1,a_ptr+sizeof(uint32_t),sizeof(char*));
312
 
  memcpy(&blob2,b_ptr+sizeof(uint32_t),sizeof(char*));
313
 
  uint32_t a_len= get_length(a_ptr), b_len= get_length(b_ptr);
314
 
  set_if_smaller(a_len, max_length);
315
 
  set_if_smaller(b_len, max_length);
316
 
  return Field_blob::cmp(blob1,a_len,blob2,b_len);
317
 
}
318
 
 
319
 
 
320
 
int Field_blob::cmp_binary(const unsigned char *a_ptr, const unsigned char *b_ptr,
321
 
                           uint32_t max_length)
322
 
{
323
 
  char *a,*b;
324
 
  uint32_t diff;
325
 
  uint32_t a_length,b_length;
326
 
  memcpy(&a,a_ptr+sizeof(uint32_t),sizeof(char*));
327
 
  memcpy(&b,b_ptr+sizeof(uint32_t),sizeof(char*));
328
 
 
329
 
  a_length= get_length(a_ptr);
330
 
 
331
 
  if (a_length > max_length)
332
 
    a_length= max_length;
333
 
 
334
 
  b_length= get_length(b_ptr);
335
 
 
336
 
  if (b_length > max_length)
337
 
    b_length= max_length;
338
 
 
339
 
  diff= memcmp(a,b,min(a_length,b_length));
340
 
 
341
 
  return diff ? diff : (unsigned int) (a_length - b_length);
342
 
}
343
 
 
344
 
/* The following is used only when comparing a key */
345
 
uint32_t Field_blob::get_key_image(unsigned char *buff, uint32_t length)
346
 
{
347
 
  uint32_t blob_length= get_length(ptr);
348
 
  unsigned char *blob;
349
 
 
350
 
  get_ptr(&blob);
351
 
  uint32_t local_char_length= length / field_charset->mbmaxlen;
352
 
  local_char_length= my_charpos(field_charset, blob, blob + blob_length,
353
 
                          local_char_length);
354
 
  set_if_smaller(blob_length, local_char_length);
355
 
 
356
 
  if ((uint32_t) length > blob_length)
357
 
  {
358
 
    /*
359
 
      Must clear this as we do a memcmp in optimizer/range.cc to detect
360
 
      identical keys
361
 
    */
362
 
    memset(buff+HA_KEY_BLOB_LENGTH+blob_length, 0, (length-blob_length));
363
 
    length=(uint32_t) blob_length;
364
 
  }
365
 
  int2store(buff,length);
366
 
  memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
367
 
  return HA_KEY_BLOB_LENGTH+length;
368
 
}
369
 
 
370
 
 
371
 
uint32_t Field_blob::get_key_image(basic_string<unsigned char> &buff, uint32_t length)
372
 
{
373
 
  uint32_t blob_length= get_length(ptr);
374
 
  unsigned char *blob;
375
 
 
376
 
  get_ptr(&blob);
377
 
  uint32_t local_char_length= length / field_charset->mbmaxlen;
378
 
  local_char_length= my_charpos(field_charset, blob, blob + blob_length,
379
 
                                local_char_length);
380
 
  set_if_smaller(blob_length, local_char_length);
381
 
 
382
 
  unsigned char len_buff[HA_KEY_BLOB_LENGTH];
383
 
  int2store(len_buff,length);
384
 
  buff.append(len_buff);
385
 
  buff.append(blob, blob_length);
386
 
 
387
 
  if (length > blob_length)
388
 
  {
389
 
    /*
390
 
      Must clear this as we do a memcmp in optimizer/range.cc to detect
391
 
      identical keys
392
 
    */
393
 
 
394
 
    buff.append(length-blob_length, '0');
395
 
  }
396
 
  return HA_KEY_BLOB_LENGTH+length;
397
 
}
398
 
 
399
 
void Field_blob::set_key_image(const unsigned char *buff,uint32_t length)
400
 
{
401
 
  length= uint2korr(buff);
402
 
  (void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length, field_charset);
403
 
}
404
 
 
405
 
int Field_blob::key_cmp(const unsigned char *key_ptr, uint32_t max_key_length)
406
 
{
407
 
  unsigned char *blob1;
408
 
  uint32_t blob_length=get_length(ptr);
409
 
  memcpy(&blob1,ptr+sizeof(uint32_t),sizeof(char*));
410
 
  const CHARSET_INFO * const cs= charset();
411
 
  uint32_t local_char_length= max_key_length / cs->mbmaxlen;
412
 
  local_char_length= my_charpos(cs, blob1, blob1+blob_length,
413
 
                                local_char_length);
414
 
  set_if_smaller(blob_length, local_char_length);
415
 
  return Field_blob::cmp(blob1, blob_length,
416
 
                         key_ptr+HA_KEY_BLOB_LENGTH,
417
 
                         uint2korr(key_ptr));
418
 
}
419
 
 
420
 
int Field_blob::key_cmp(const unsigned char *a,const unsigned char *b)
421
 
{
422
 
  return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
423
 
                         b+HA_KEY_BLOB_LENGTH, uint2korr(b));
424
 
}
425
 
 
426
 
uint32_t Field_blob::sort_length() const
427
 
{
428
 
  return (uint32_t) (getTable()->getSession()->variables.max_sort_length +
429
 
                     (field_charset == &my_charset_bin ? 0 : sizeof(uint32_t)));
430
 
}
431
 
 
432
 
void Field_blob::sort_string(unsigned char *to,uint32_t length)
433
 
{
434
 
  unsigned char *blob;
435
 
  uint32_t blob_length=get_length();
436
 
 
437
 
  if (!blob_length)
438
 
    memset(to, 0, length);
439
 
  else
440
 
  {
441
 
    if (field_charset == &my_charset_bin)
442
 
    {
443
 
      unsigned char *pos;
444
 
 
445
 
      /*
446
 
        Store length of blob last in blob to shorter blobs before longer blobs
447
 
      */
448
 
      length-= sizeof(uint32_t); // size of stored blob length
449
 
      pos= to+length;
450
 
 
451
 
      mi_int4store(pos, blob_length);
452
 
    }
453
 
    memcpy(&blob,ptr+sizeof(uint32_t),sizeof(char*));
454
 
 
455
 
    blob_length=my_strnxfrm(field_charset,
456
 
                            to, length, blob, blob_length);
457
 
    assert(blob_length == length);
458
 
  }
459
 
}
460
 
 
461
 
uint32_t Field_blob::pack_length() const
462
 
{
463
 
  return (uint32_t) (sizeof(uint32_t) + portable_sizeof_char_ptr);
464
 
}
465
 
 
466
 
void Field_blob::sql_type(String &res) const
467
 
{
468
 
  if (charset() == &my_charset_bin)
469
 
    res.set_ascii(STRING_WITH_LEN("blob"));
470
 
  else
471
 
    res.set_ascii(STRING_WITH_LEN("text"));
472
 
}
473
 
 
474
 
unsigned char *Field_blob::pack(unsigned char *to, const unsigned char *from,
475
 
                                uint32_t max_length, bool low_byte_first)
476
 
{
477
 
  unsigned char *save= ptr;
478
 
  ptr= (unsigned char*) from;
479
 
  uint32_t length= get_length();                        // Length of from string
480
 
 
481
 
  /*
482
 
    Store max length, which will occupy packlength bytes. If the max
483
 
    length given is smaller than the actual length of the blob, we
484
 
    just store the initial bytes of the blob.
485
 
  */
486
 
  store_length(to, min(length, max_length), low_byte_first);
487
 
 
488
 
  /*
489
 
    Store the actual blob data, which will occupy 'length' bytes.
490
 
   */
491
 
  if (length > 0)
492
 
  {
493
 
    get_ptr((unsigned char**) &from);
494
 
    memcpy(to+sizeof(uint32_t), from,length);
495
 
  }
496
 
 
497
 
  ptr= save;                                    // Restore org row pointer
498
 
  return(to+sizeof(uint32_t)+length);
499
 
}
500
 
 
501
 
/**
502
 
   Unpack a blob field from row data.
503
 
 
504
 
   This method is used to unpack a blob field from a master whose size of
505
 
   the field is less than that of the slave. Note: This method is included
506
 
   to satisfy inheritance rules, but is not needed for blob fields. It
507
 
   simply is used as a pass-through to the original unpack() method for
508
 
   blob fields.
509
 
 
510
 
   @param   to         Destination of the data
511
 
   @param   from       Source of the data
512
 
   @param   param_data @c true if base types should be stored in little-
513
 
                       endian format, @c false if native format should
514
 
                       be used.
515
 
 
516
 
   @return  New pointer into memory based on from + length of the data
517
 
*/
518
 
const unsigned char *Field_blob::unpack(unsigned char *,
519
 
                                        const unsigned char *from,
520
 
                                        uint32_t,
521
 
                                        bool low_byte_first)
522
 
{
523
 
  uint32_t const length= get_length(from, low_byte_first);
524
 
  getTable()->setWriteSet(position());
525
 
  store(reinterpret_cast<const char*>(from) + sizeof(uint32_t),
526
 
        length, field_charset);
527
 
  return(from + sizeof(uint32_t) + length);
528
 
}
529
 
 
530
 
/** Create a packed key that will be used for storage from a MySQL row. */
531
 
 
532
 
unsigned char *
533
 
Field_blob::pack_key(unsigned char *to, const unsigned char *from, uint32_t max_length,
534
 
                     bool )
535
 
{
536
 
  unsigned char *save= ptr;
537
 
  ptr= (unsigned char*) from;
538
 
  uint32_t length=get_length();        // Length of from string
539
 
  uint32_t local_char_length= ((field_charset->mbmaxlen > 1) ?
540
 
                           max_length/field_charset->mbmaxlen : max_length);
541
 
  if (length)
542
 
    get_ptr((unsigned char**) &from);
543
 
  if (length > local_char_length)
544
 
    local_char_length= my_charpos(field_charset, from, from+length,
545
 
                                  local_char_length);
546
 
  set_if_smaller(length, local_char_length);
547
 
  *to++= (unsigned char) length;
548
 
  if (max_length > 255)                         // 2 byte length
549
 
    *to++= (unsigned char) (length >> 8);
550
 
  memcpy(to, from, length);
551
 
  ptr=save;                                     // Restore org row pointer
552
 
  return to+length;
553
 
}
554
 
 
555
 
 
556
 
/**
557
 
  maximum possible display length for blob.
558
 
 
559
 
  @return
560
 
    length
561
 
*/
562
 
 
563
 
uint32_t Field_blob::max_display_length()
564
 
{
565
 
    return (uint32_t) 4294967295U;
566
 
}
567
 
 
568
 
} /* namespace drizzled */