field.cc 132 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/*****************************************************************************
** This file implements classes defined in field.h
*****************************************************************************/

#ifdef __GNUC__
#pragma implementation				// gcc: Class implementation
#endif

#include "mysql_priv.h"
#include "sql_select.h"
#include <m_ctype.h>
#include <errno.h>
#ifdef HAVE_FCONVERT
#include <floatingpoint.h>
#endif

peter@mysql.com's avatar
peter@mysql.com committed
34 35 36
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024

bk@work.mysql.com's avatar
bk@work.mysql.com committed
37
/*****************************************************************************
38
  Instansiate templates and static variables
bk@work.mysql.com's avatar
bk@work.mysql.com committed
39 40 41 42 43 44 45 46 47 48 49
*****************************************************************************/

#ifdef __GNUC__
template class List<create_field>;
template class List_iterator<create_field>;
#endif

uchar Field_null::null[1]={1};
const char field_separator=',';

/*****************************************************************************
50
  Static help functions
bk@work.mysql.com's avatar
bk@work.mysql.com committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
*****************************************************************************/

void Field_num::prepend_zeros(String *value)
{
  int diff;
  if ((diff= (int) (field_length - value->length())) > 0)
  {
    bmove_upp((char*) value->ptr()+field_length,value->ptr()+value->length(),
	      value->length());
    bfill((char*) value->ptr(),diff,'0');
    value->length(field_length);
    (void) value->c_ptr_quick();		// Avoid warnings in purify
  }
}

/*
67
  Test if given number is a int (or a fixed format float with .000)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

  SYNOPSIS
    test_if_int()
    str		String to test
    end		Pointer to char after last used digit
    cs		Character set

  NOTES
    This is called after one has called my_strntol() or similar function.
    This is only used to give warnings in ALTER TABLE or LOAD DATA...

  TODO
    Make this multi-byte-character safe

  RETURN
    0	ok
    1	error
bk@work.mysql.com's avatar
bk@work.mysql.com committed
85 86
*/

87 88
bool test_if_int(const char *str, int length, const char *int_end,
		 CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
89
{
90 91
  if (str == int_end)
    return 0;					// Empty string
bk@work.mysql.com's avatar
bk@work.mysql.com committed
92
  const char *end=str+length;
93 94
  if ((str= int_end) == end)
    return 1;					// All digits was used
bk@work.mysql.com's avatar
bk@work.mysql.com committed
95

96 97
  /* Allow end .0000 */
  if (*str == '.')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
98
  {
99 100 101 102 103 104 105
    for (str++ ; str != end && *str == '0'; str++) ;
  }
  /* Allow end space */
  for (str++ ; str != end ; str++)
  {
    if (!my_isspace(cs,*str))
      return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
106 107 108 109 110
  }
  return 1;
}


111
static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
112
{
113
  cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct
114 115

  while (length && my_isspace(cs,*str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
116 117 118 119 120 121 122 123
  {						// Allow start space
    length--; str++;
  }
  if (!length)
    return 0;
  if (*str == '+' || *str == '-')
  {
    length--; str++;
124
    if (!length || !(my_isdigit(cs,*str) || *str == '.'))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
125 126
      return 0;
  }
127
  while (length && my_isdigit(cs,*str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
128 129 130 131 132 133 134 135
  {
    length--; str++;
  }
  if (!length)
    return 1;
  if (*str == '.')
  {
    length--; str++;
136
    while (length && my_isdigit(cs,*str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
137 138 139 140 141 142 143 144
    {
      length--; str++;
    }
  }
  if (!length)
    return 1;
  if (*str == 'E' || *str == 'e')
  {
145
    if (length < 3 || (str[1] != '+' && str[1] != '-') || 
146
        !my_isdigit(cs,str[2]))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
147 148 149
      return 0;
    length-=3;
    str+=3;
150
    while (length && my_isdigit(cs,*str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
151 152 153 154
    {
      length--; str++;
    }
  }
155
  for (; length ; length--, str++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
156
  {						// Allow end space
157
    if (!my_isspace(cs,*str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
158 159 160 161 162 163
      return 0;
  }
  return 1;
}


164 165 166 167 168 169 170 171
static inline uint field_length_without_space(const char *ptr, uint length)
{
  const char *end= ptr+length;
  while (end > ptr && end[-1] == ' ')
    end--;
  return (uint) (end-ptr);
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
/*
 Tables of filed type compatibility.

 There are tables for every type, table consist of list of types in which
 given type can be converted without data lost, list should be ended with
 FIELD_CAST_STOP
*/
static Field::field_cast_enum field_cast_decimal[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_tiny[]=
{Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
 Field::FIELD_CAST_LONGLONG,
 Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_short[]=
{Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
 Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_medium[]=
{Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
 Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_long[]=
{Field::FIELD_CAST_LONGLONG,
 Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_longlong[]=
{Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_float[]=
{Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_double[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_null[]=
{Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT,
 Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG,
 Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_TIMESTAMP, Field::FIELD_CAST_YEAR,
 Field::FIELD_CAST_DATE, Field::FIELD_CAST_NEWDATE,
 Field::FIELD_CAST_TIME, Field::FIELD_CAST_DATETIME,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB,
 Field::FIELD_CAST_GEOM, Field::FIELD_CAST_ENUM, Field::FIELD_CAST_SET,
 Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_timestamp[]=
{Field::FIELD_CAST_DATETIME,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_year[]=
{Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
 Field::FIELD_CAST_LONGLONG,
 Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_date[]=
{Field::FIELD_CAST_DATETIME,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_newdate[]=
{Field::FIELD_CAST_DATETIME,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_time[]=
{Field::FIELD_CAST_DATETIME,
 Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_datetime[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_string[]=
{Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_varstring[]=
{Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_blob[]=
{Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_geom[]=
{Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_enum[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_set[]=
{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
 Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
// Array of pointers on conversion table for all fields types casting
static Field::field_cast_enum *field_cast_array[]=
{0, //FIELD_CAST_STOP
 field_cast_decimal, field_cast_tiny, field_cast_short,
 field_cast_medium, field_cast_long, field_cast_longlong,
 field_cast_float, field_cast_double,
 field_cast_null,
 field_cast_timestamp, field_cast_year, field_cast_date, field_cast_newdate,
 field_cast_time, field_cast_datetime,
 field_cast_string, field_cast_varstring, field_cast_blob,
 field_cast_geom, field_cast_enum, field_cast_set
};


bool Field::field_cast_compatible(Field::field_cast_enum type)
{
  DBUG_ASSERT(type != FIELD_CAST_STOP);
  Field::field_cast_enum *array= field_cast_array[field_cast_type()];
  uint i= 0;
  Field::field_cast_enum tp;
  do
  {
    tp=  array[i++];
    if (tp == type)
      return 1;
  } while (tp != FIELD_CAST_STOP);
  return 0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
294 295
/****************************************************************************
** Functions for the base classes
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
296
** This is an unpacked number.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
297 298 299
****************************************************************************/

Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
300
	     uchar null_bit_arg,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
301 302
	     utype unireg_check_arg, const char *field_name_arg,
	     struct st_table *table_arg)
303 304 305
  :ptr(ptr_arg),null_ptr(null_ptr_arg),
   table(table_arg),table_name(table_arg ? table_arg->table_name : 0),
   field_name(field_name_arg),
serg@serg.mylan's avatar
serg@serg.mylan committed
306 307
   query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
   unireg_check(unireg_check_arg),
wax@kishkin.ru's avatar
wax@kishkin.ru committed
308
   field_length(length_arg),null_bit(null_bit_arg),abs_offset(0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
309 310
{
  flags=null_ptr ? 0: NOT_NULL_FLAG;
311 312
  comment.str= (char*) "";
  comment.length=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
313 314 315 316 317 318 319 320 321 322 323 324 325
}

uint Field::offset()
{
  return (uint) (ptr - (char*) table->record[0]);
}


void Field::copy_from_tmp(int row_offset)
{
  memcpy(ptr,ptr+row_offset,pack_length());
  if (null_ptr)
  {
326 327
    *null_ptr= (uchar) ((null_ptr[0] & (uchar) ~(uint) null_bit) |
			null_ptr[row_offset] & (uchar) null_bit);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
328 329 330 331
  }
}


332
bool Field::send_binary(Protocol *protocol)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
333 334
{
  char buff[MAX_FIELD_WIDTH];
335
  String tmp(buff,sizeof(buff),charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
336
  val_str(&tmp,&tmp);
337
  return protocol->store(tmp.ptr(), tmp.length(), tmp.charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
338 339 340 341 342
}


void Field_num::add_zerofill_and_unsigned(String &res) const
{
343 344 345 346
  if (unsigned_flag)
    res.append(" unsigned");
  if (zerofill)
    res.append(" zerofill");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
347 348 349 350
}

void Field_num::make_field(Send_field *field)
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
351
  /* table_cache_key is not set for temp tables */
352 353
  field->db_name=table->table_cache_key ? table->table_cache_key : ""; 
  field->org_table_name=table->real_name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
354
  field->table_name=table_name;
355
  field->col_name=field->org_col_name=field_name;
356
  field->charsetnr= charset()->number;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
357 358 359 360 361 362 363 364 365
  field->length=field_length;
  field->type=type();
  field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
  field->decimals=dec;
}


void Field_str::make_field(Send_field *field)
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
366
  /* table_cache_key is not set for temp tables */
367 368
  field->db_name=table->table_cache_key ? table->table_cache_key : ""; 
  field->org_table_name=table->real_name;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
369
  field->table_name=table_name;
370
  field->col_name=field->org_col_name=field_name;
371
  field->charsetnr= charset()->number;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
372 373 374 375 376 377
  field->length=field_length;
  field->type=type();
  field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
  field->decimals=0;
}

378

bk@work.mysql.com's avatar
bk@work.mysql.com committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
uint Field::fill_cache_field(CACHE_FIELD *copy)
{
  copy->str=ptr;
  copy->length=pack_length();
  copy->blob_field=0;
  if (flags & BLOB_FLAG)
  {
    copy->blob_field=(Field_blob*) this;
    copy->strip=0;
    copy->length-=table->blob_ptr_size;
    return copy->length;
  }
  else if (!zero_pack() && (type() == FIELD_TYPE_STRING && copy->length > 4 ||
			    type() == FIELD_TYPE_VAR_STRING))
    copy->strip=1;				/* Remove end space */
  else
    copy->strip=0;
  return copy->length+(int) copy->strip;
}

399 400

bool Field::get_date(TIME *ltime,uint fuzzydate)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
401 402
{
  char buff[40];
403
  String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
404
  if (!(res=val_str(&tmp,&tmp2)) ||
405 406
      str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <=
      TIMESTAMP_DATETIME_ERROR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
407 408 409 410 411 412 413
    return 1;
  return 0;
}

bool Field::get_time(TIME *ltime)
{
  char buff[40];
414
  String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
415
  if (!(res=val_str(&tmp,&tmp2)) ||
416
      str_to_time(res->ptr(),res->length(),ltime))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
417 418 419 420
    return 1;
  return 0;
}

421 422 423 424 425 426
/*
  This is called when storing a date in a string

  NOTES
    Needs to be changed if/when we want to support different time formats
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
427 428 429 430 431 432

void Field::store_time(TIME *ltime,timestamp_type type)
{
  char buff[25];
  switch (type)  {
  case TIMESTAMP_NONE:
433
  case TIMESTAMP_DATETIME_ERROR:
434
    store("",0,&my_charset_bin);	// Probably an error
435
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
436
  case TIMESTAMP_DATE:
437 438
    sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
    store(buff,10,&my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
439
    break;
440 441 442 443 444
  case TIMESTAMP_DATETIME:
    sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
	    ltime->year,ltime->month,ltime->day,
	    ltime->hour,ltime->minute,ltime->second);
    store(buff,19,&my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
445 446
    break;
  case TIMESTAMP_TIME:
447 448 449 450
  {
    ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
				    ltime->hour,ltime->minute,ltime->second));
    store(buff,(uint) length, &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
451 452
    break;
  }
453
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
454 455 456
}


457
bool Field::optimize_range(uint idx)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
458
{
459
  return !test(table->file->index_flags(idx) & HA_WRONG_ASCII_ORDER);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
460 461
}

462
/****************************************************************************
463
  Field_null, a field that always return NULL
464 465 466 467
****************************************************************************/

void Field_null::sql_type(String &res) const
{
468
  res.set_ascii("null", 4);
469 470 471
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
472
/****************************************************************************
473 474
  Functions for the Field_decimal class
  This is an number stored as a pre-space (or pre-zero) string
bk@work.mysql.com's avatar
bk@work.mysql.com committed
475 476 477 478 479
****************************************************************************/

void
Field_decimal::reset(void)
{
480
  Field_decimal::store("0",1,&my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
481 482 483 484 485
}

void Field_decimal::overflow(bool negative)
{
  uint len=field_length;
486
  char *to=ptr, filler= '9';
487

488
  set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
489
  if (negative)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
490
  {
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
    if (!unsigned_flag)
    {
      /* Put - sign as a first digit so we'll have -999..999 or 999..999 */
      *to++ = '-';
      len--;
    }
    else
    {
      filler= '0';				// Fill up with 0
      if (!zerofill)
      {
	/*
	  Handle unsigned integer without zerofill, in which case
	  the number should be of format '   0' or '   0.000'
	*/
	uint whole_part=field_length- (dec ? dec+2 : 1);
	// Fill with spaces up to the first digit
	bfill(to, whole_part, ' ');
	to+=  whole_part;
	len-= whole_part;
	// The main code will also handle the 0 before the decimal point
      }
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
514
  }
515
  bfill(to, len, filler);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
516 517 518 519 520 521
  if (dec)
    ptr[field_length-dec-1]='.';
  return;
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
522
int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
523
{
524
  char buff[80];
525
  String tmp(buff,sizeof(buff), &my_charset_bin);
526

527 528 529
  /* Convert character set if the old one is multi byte */
  if (cs->mbmaxlen > 1)
  { 
530
    tmp.copy(from, len, cs, &my_charset_bin);
531 532 533
    from= tmp.ptr();
    len=  tmp.length();
  }
534

535 536 537 538 539 540 541 542 543
  const char *end= from+len;
  /* The pointer where the field value starts (i.e., "where to write") */
  char *to=ptr;
  uint tmp_dec, tmp_uint;
  /*
    The sign of the number : will be 0 (means positive but sign not
    specified), '+' or '-'
  */
  char sign_char=0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
544
  /* The pointers where prezeros start and stop */
545
  const char *pre_zeros_from, *pre_zeros_end;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
546
  /* The pointers where digits at the left of '.' start and stop */
547
  const char *int_digits_from, *int_digits_end;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
548
  /* The pointers where digits at the right of '.' start and stop */
549
  const char *frac_digits_from, *frac_digits_end;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
550
  /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
551
  char expo_sign_char=0;
peter@mysql.com's avatar
peter@mysql.com committed
552
  uint exponent=0;                                // value of the exponent
553 554 555 556 557 558 559
  /*
    Pointers used when digits move from the left of the '.' to the
    right of the '.' (explained below)
  */
  const char *int_digits_tail_from;
  /* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */
  uint int_digits_added_zeros;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
560 561 562 563
  /*
    Pointer used when digits move from the right of the '.' to the left
    of the '.'
  */
564
  const char *frac_digits_head_end;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
565
  /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
566 567 568 569 570
  uint frac_digits_added_zeros;
  char *pos,*tmp_left_pos,*tmp_right_pos;
  /* Pointers that are used as limits (begin and end of the field buffer) */
  char *left_wall,*right_wall;
  char tmp_char;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
571 572 573 574
  /*
    To remember if current_thd->cuted_fields has already been incremented,
    to do that only once
  */
575 576 577 578 579 580 581 582 583
  bool is_cuted_fields_incr=0;

  LINT_INIT(int_digits_tail_from);
  LINT_INIT(int_digits_added_zeros);
  LINT_INIT(frac_digits_head_end);
  LINT_INIT(frac_digits_added_zeros);

  /*
    There are three steps in this function :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
584 585
    - parse the input string
    - modify the position of digits around the decimal dot '.' 
586
      according to the exponent value (if specified)
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
587
    - write the formatted number
588 589 590 591 592
  */

  if ((tmp_dec=dec))
    tmp_dec++;

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
593
  /* skip pre-space */
594
  while (from != end && my_isspace(&my_charset_bin,*from))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
595
    from++;
596
  if (from == end)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
597
  {
598
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
599
    is_cuted_fields_incr=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
600
  }
601
  else if (*from == '+' || *from == '-')	// Found some sign ?
bk@work.mysql.com's avatar
bk@work.mysql.com committed
602
  {
603
    sign_char= *from++;
604
    /*
605 606 607
      We allow "+" for unsigned decimal unless defined different
      Both options allowed as one may wish not to have "+" for unsigned numbers
      because of data processing issues
608 609 610 611
    */ 
    if (unsigned_flag)  
    { 
      if (sign_char=='-')
612
      {
613
        Field_decimal::overflow(1);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
614
        return 1;
615
      }
616
      /* 
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
617 618
	 Defining this will not store "+" for unsigned decimal type even if
	 it is passed in numeric string. This will make some tests to fail
619 620
      */	 
#ifdef DONT_ALLOW_UNSIGNED_PLUS      
621 622
      else 
        sign_char=0;
623
#endif 	
bk@work.mysql.com's avatar
bk@work.mysql.com committed
624
    }
625
  }
626

627 628 629 630
  pre_zeros_from= from;
  for (; from!=end && *from == '0'; from++) ;	// Read prezeros
  pre_zeros_end=int_digits_from=from;      
  /* Read non zero digits at the left of '.'*/
631
  for (; from != end && my_isdigit(&my_charset_bin, *from) ; from++) ;
632 633 634 635 636
  int_digits_end=from;
  if (from!=end && *from == '.')		// Some '.' ?
    from++;
  frac_digits_from= from;
  /* Read digits at the right of '.' */
637
  for (;from!=end && my_isdigit(&my_charset_bin, *from); from++) ;
638 639 640 641 642 643 644 645 646 647
  frac_digits_end=from;
  // Some exponentiation symbol ?
  if (from != end && (*from == 'e' || *from == 'E'))
  {   
    from++;
    if (from != end && (*from == '+' || *from == '-'))  // Some exponent sign ?
      expo_sign_char= *from++;
    else
      expo_sign_char= '+';
    /*
648 649 650 651
      Read digits of the exponent and compute its value.  We must care about
      'exponent' overflow, because as unsigned arithmetic is "modulo", big 
      exponents will become small (e.g. 1e4294967296 will become 1e0, and the 
      field will finally contain 1 instead of its max possible value).
652
    */
653
    for (;from!=end && my_isdigit(&my_charset_bin, *from); from++)
654
    {
655
      exponent=10*exponent+(*from-'0');
peter@mysql.com's avatar
peter@mysql.com committed
656
      if (exponent>MAX_EXPONENT)
657 658
        break;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
659
  }
660
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
661
  /*
662 663 664 665
    We only have to generate warnings if count_cuted_fields is set.
    This is to avoid extra checks of the number when they are not needed.
    Even if this flag is not set, it's ok to increment warnings, if
    it makes the code easer to read.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
666
  */
667 668

  if (current_thd->count_cuted_fields)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
669
  {
670
    // Skip end spaces
671
    for (;from != end && my_isspace(&my_charset_bin, *from); from++) ;
672
    if (from != end)                     // If still something left, warn
bk@work.mysql.com's avatar
bk@work.mysql.com committed
673
    {
674
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); 
675
      is_cuted_fields_incr=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
676
    }
677 678 679 680 681 682
  }
  
  /*
    Now "move" digits around the decimal dot according to the exponent value,
    and add necessary zeros.
    Examples :
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
683 684 685
    - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3)
    - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed
    between '.' and '1'
686
    - 1234.5E-3 : '234' moves at the right of '.'
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
687 688
    These moves are implemented with pointers which point at the begin
    and end of each moved segment. Examples :
689
    - 1234.5E-3 : before the code below is executed, the int_digits part is
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
690 691 692
    from '1' to '4' and the frac_digits part from '5' to '5'. After the code
    below, the int_digits part is from '1' to '1', the frac_digits_head
    part is from '2' to '4', and the frac_digits part from '5' to '5'.
693
    - 1234.5E3 : before the code below is executed, the int_digits part is
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
694 695 696 697
    from '1' to '4' and the frac_digits part from '5' to '5'. After the code
    below, the int_digits part is from '1' to '4', the int_digits_tail
    part is from '5' to '5', the frac_digits part is empty, and
    int_digits_added_zeros=2 (to make 1234500).
698 699
  */
  
700
  /* 
peter@mysql.com's avatar
peter@mysql.com committed
701
     Below tmp_uint cannot overflow with small enough MAX_EXPONENT setting,
702
     as int_digits_added_zeros<=exponent<4G and 
703 704
     (int_digits_end-int_digits_from)<=max_allowed_packet<=2G and
     (frac_digits_from-int_digits_tail_from)<=max_allowed_packet<=2G
705 706
  */

707 708 709 710 711 712 713 714
  if (!expo_sign_char)
    tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
  else if (expo_sign_char == '-') 
  {
    tmp_uint=min(exponent,(uint)(int_digits_end-int_digits_from));
    frac_digits_added_zeros=exponent-tmp_uint;
    int_digits_end -= tmp_uint;
    frac_digits_head_end=int_digits_end+tmp_uint;
peter@mysql.com's avatar
peter@mysql.com committed
715
    tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);     
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
  }
  else // (expo_sign_char=='+') 
  {
    tmp_uint=min(exponent,(uint)(frac_digits_end-frac_digits_from));
    int_digits_added_zeros=exponent-tmp_uint;
    int_digits_tail_from=frac_digits_from;
    frac_digits_from=frac_digits_from+tmp_uint;
    /*
      We "eat" the heading zeros of the 
      int_digits.int_digits_tail.int_digits_added_zeros concatenation
      (for example 0.003e3 must become 3 and not 0003)
    */
    if (int_digits_from == int_digits_end) 
    {
      /*
	There was nothing in the int_digits part, so continue
	eating int_digits_tail zeros
      */
      for (; int_digits_tail_from != frac_digits_from &&
	     *int_digits_tail_from == '0'; int_digits_tail_from++) ;
      if (int_digits_tail_from == frac_digits_from) 
      {
	// there were only zeros in int_digits_tail too
	int_digits_added_zeros=0;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
741
    }
742 743 744
    tmp_uint= (tmp_dec+(int_digits_end-int_digits_from)+
               (uint)(frac_digits_from-int_digits_tail_from)+
               int_digits_added_zeros);
745 746 747 748 749 750 751 752 753 754
  }
  
  /*
    Now write the formated number
    
    First the digits of the int_% parts.
    Do we have enough room to write these digits ?
    If the sign is defined and '-', we need one position for it
  */

755
  if (field_length < tmp_uint + (int) (sign_char == '-')) 
756
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
757
    // too big number, change to max or min number
758
    Field_decimal::overflow(sign_char == '-');
759
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
760
  }
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
 
  /*
    Tmp_left_pos is the position where the leftmost digit of
    the int_% parts will be written
  */
  tmp_left_pos=pos=to+(uint)(field_length-tmp_uint);
  
  // Write all digits of the int_% parts
  while (int_digits_from != int_digits_end)
    *pos++ = *int_digits_from++ ;

  if (expo_sign_char == '+')
  {    
    while (int_digits_tail_from != frac_digits_from)
      *pos++= *int_digits_tail_from++;
    while (int_digits_added_zeros-- >0)
      *pos++= '0';  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
778
  }
779 780 781 782 783 784
  /*
    Note the position where the rightmost digit of the int_% parts has been
    written (this is to later check if the int_% parts contained nothing,
    meaning an extra 0 is needed).
  */
  tmp_right_pos=pos;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
785 786

  /*
787 788
    Step back to the position of the leftmost digit of the int_% parts,
    to write sign and fill with zeros or blanks or prezeros.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
789
  */
790 791 792 793 794 795 796 797 798
  pos=tmp_left_pos-1;
  if (zerofill)
  {
    left_wall=to-1;
    while (pos != left_wall)			// Fill with zeros
      *pos--='0';
  }
  else
  {
799
    left_wall=to+(sign_char != 0)-1;
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
    if (!expo_sign_char)	// If exponent was specified, ignore prezeros
    {
      for (;pos != left_wall && pre_zeros_from !=pre_zeros_end;
	   pre_zeros_from++)
	*pos--= '0';
    }
    if (pos == tmp_right_pos-1)
      *pos--= '0';		// no 0 has ever been written, so write one
    left_wall= to-1;
    if (sign_char && pos != left_wall)
    {
      /* Write sign if possible (it is if sign is '-') */
      *pos--= sign_char;
    }
    while (pos != left_wall)
      *pos--=' ';  //fill with blanks
  }
  
818 819 820 821 822 823 824 825
  /*
    Write digits of the frac_% parts ;
    Depending on current_thd->count_cutted_fields, we may also want
    to know if some non-zero tail of these parts will
    be truncated (for example, 0.002->0.00 will generate a warning,
    while 0.000->0.00 will not)
    (and 0E1000000000 will not, while 1E-1000000000 will)
  */
826
      
827 828 829
  pos=to+(uint)(field_length-tmp_dec);	// Calculate post to '.'
  right_wall=to+field_length;
  if (pos != right_wall) 
830 831
    *pos++='.';

832 833 834
  if (expo_sign_char == '-')
  {
    while (frac_digits_added_zeros-- > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
835
    {
836
      if (pos == right_wall) 
837
      {
838 839
        if (current_thd->count_cuted_fields && !is_cuted_fields_incr) 
          break; // Go on below to see if we lose non zero digits
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
840
        return 0;
841
      }
842 843 844 845 846 847
      *pos++='0';
    }
    while (int_digits_end != frac_digits_head_end)
    {
      tmp_char= *int_digits_end++;
      if (pos == right_wall)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
848
      {
849 850 851
        if (tmp_char != '0')			// Losing a non zero digit ?
        {
          if (!is_cuted_fields_incr)
852
            set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
853
          return 0;
854 855
        }
        continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
856
      }
857
      *pos++= tmp_char;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
858
    }
859
  }
860

861 862 863 864
  for (;frac_digits_from!=frac_digits_end;) 
  {
    tmp_char= *frac_digits_from++;
    if (pos == right_wall)
865
    {
866
      if (tmp_char != '0')			// Losing a non zero digit ?
867
      {
868
        if (!is_cuted_fields_incr)
869
	  set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
870
        return 0;
871
      }
872
      continue;
873
    }
874
    *pos++= tmp_char;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
875
  }
876 877 878
      
  while (pos != right_wall)
   *pos++='0';			// Fill with zeros at right of '.'
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
879
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
880 881 882
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
883
int Field_decimal::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
884 885 886 887
{
  if (unsigned_flag && nr < 0)
  {
    overflow(1);
888
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
889
  }
890
  
891 892
#ifdef HAVE_FINITE
  if (!finite(nr)) // Handle infinity as special case
893 894
  {
    overflow(nr < 0.0);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
895
    return 1;
896
  }
897
#endif
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
898

bk@work.mysql.com's avatar
bk@work.mysql.com committed
899 900 901 902 903
  reg4 uint i,length;
  char fyllchar,*to;
  char buff[320];

  fyllchar = zerofill ? (char) '0' : (char) ' ';
serg@serg.mylan's avatar
serg@serg.mylan committed
904
#ifdef HAVE_SNPRINTF
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
905 906
  buff[sizeof(buff)-1]=0;			// Safety
  snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
907
  length=(uint) strlen(buff);
908
#else
909
  length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr));
910
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
911 912 913 914

  if (length > field_length)
  {
    overflow(nr < 0.0);
915
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
916 917 918 919 920 921 922
  }
  else
  {
    to=ptr;
    for (i=field_length-length ; i-- > 0 ;)
      *to++ = fyllchar;
    memcpy(to,buff,length);
923
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
924 925 926 927
  }
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
928
int Field_decimal::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
929 930 931 932
{
  if (unsigned_flag && nr < 0)
  {
    overflow(1);
933
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
934 935 936 937 938 939 940 941
  }
  char buff[22];
  uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff);
  uint int_part=field_length- (dec  ? dec+1 : 0);

  if (length > int_part)
  {
    overflow(test(nr < 0L));			/* purecov: inspected */
942
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
943 944 945 946 947 948 949 950 951 952 953 954 955
  }
  else
  {
    char fyllchar = zerofill ? (char) '0' : (char) ' ';
    char *to=ptr;
    for (uint i=int_part-length ; i-- > 0 ;)
      *to++ = fyllchar;
    memcpy(to,buff,length);
    if (dec)
    {
      to[length]='.';
      bfill(to+length+1,dec,'0');
    }
956
    return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
957 958 959 960 961 962
  }
}


double Field_decimal::val_real(void)
{
963
  int not_used;
964
  return my_strntod(&my_charset_bin, ptr, field_length, NULL, &not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
965 966 967 968
}

longlong Field_decimal::val_int(void)
{
969
  int not_used;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
970
  if (unsigned_flag)
971
    return my_strntoull(&my_charset_bin, ptr, field_length, 10, NULL,
972
			&not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
973
  else
974
    return my_strntoll(&my_charset_bin, ptr, field_length, 10, NULL,
975
			&not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
976 977
}

978

bk@work.mysql.com's avatar
bk@work.mysql.com committed
979 980 981 982 983 984
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
			       String *val_ptr)
{
  char *str;
  for (str=ptr ; *str == ' ' ; str++) ;
  uint tmp_length=(uint) (str-ptr);
985
  val_ptr->set_charset(&my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
986 987 988
  if (field_length < tmp_length)		// Error in data
    val_ptr->length(0);
  else
989
    val_ptr->set_ascii((const char*) str, field_length-tmp_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
990 991 992 993 994 995 996 997 998 999 1000
  return val_ptr;
}

/*
** Should be able to handle at least the following fixed decimal formats:
** 5.00 , -1.0,  05,  -05, +5 with optional pre/end space
*/

int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
{
  const char *end;
1001
  int swap=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1002 1003 1004 1005
  /* First remove prefixes '0', ' ', and '-' */
  for (end=a_ptr+field_length;
       a_ptr != end &&
	 (*a_ptr == *b_ptr ||
1006
	  ((my_isspace(&my_charset_bin,*a_ptr)  || *a_ptr == '+' || 
1007
            *a_ptr == '0') &&
1008
	   (my_isspace(&my_charset_bin,*b_ptr) || *b_ptr == '+' || 
1009
            *b_ptr == '0')));
1010 1011 1012 1013 1014
       a_ptr++,b_ptr++)
  {
    if (*a_ptr == '-')				// If both numbers are negative
      swap= -1 ^ 1;				// Swap result      
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1015 1016 1017
  if (a_ptr == end)
    return 0;
  if (*a_ptr == '-')
1018 1019
    return -1;
  else if (*b_ptr == '-')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
    return 1;

  while (a_ptr != end)
  {
    if (*a_ptr++ != *b_ptr++)
      return swap ^ (a_ptr[-1] < b_ptr[-1] ? -1 : 1); // compare digits
  }
  return 0;
}


void Field_decimal::sort_string(char *to,uint length)
{
  char *str,*end;
  for (str=ptr,end=ptr+length;
       str != end &&
1036
	 ((my_isspace(&my_charset_bin,*str) || *str == '+' ||
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1037
	   *str == '0')) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
       str++)
    *to++=' ';
  if (str == end)
    return;					/* purecov: inspected */

  if (*str == '-')
  {
    *to++=1;					// Smaller than any number
    str++;
    while (str != end)
1048
      if (my_isdigit(&my_charset_bin,*str))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1049 1050 1051 1052 1053 1054 1055
	*to++= (char) ('9' - *str++);
      else
	*to++= *str++;
  }
  else memcpy(to,str,(uint) (end-str));
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1056

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1057 1058
void Field_decimal::sql_type(String &res) const
{
1059
  CHARSET_INFO *cs=res.charset();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1060 1061 1062 1063 1064
  uint tmp=field_length;
  if (!unsigned_flag)
    tmp--;
  if (dec)
    tmp--;
1065
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
1066
			  "decimal(%d,%d)",tmp,dec));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1067 1068 1069 1070 1071 1072 1073 1074
  add_zerofill_and_unsigned(res);
}


/****************************************************************************
** tiny int
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1075
int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1076
{
1077
  int not_used;				// We can ignore result from str2int
1078
  char *end;
1079
  long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1080
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1081 1082 1083 1084 1085 1086

  if (unsigned_flag)
  {
    if (tmp < 0)
    {
      tmp=0; /* purecov: inspected */
1087
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);      
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1088
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1089 1090 1091 1092
    }
    else if (tmp > 255)
    {
      tmp= 255;
1093
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1094
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1095
    }
1096
    else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
1097
    {
1098
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1099
      error= 1;
1100
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1101 1102 1103 1104 1105 1106
  }
  else
  {
    if (tmp < -128)
    {
      tmp= -128;
1107
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1108
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1109 1110 1111 1112
    }
    else if (tmp >= 128)
    {
      tmp= 127;
1113
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1114
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1115
    }
1116
    else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
1117
    {
1118
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1119
      error= 1;
1120
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1121 1122
  }
  ptr[0]= (char) tmp;
1123
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1124 1125 1126
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1127
int Field_tiny::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1128
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1129
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1130 1131 1132 1133 1134 1135
  nr=rint(nr);
  if (unsigned_flag)
  {
    if (nr < 0.0)
    {
      *ptr=0;
1136
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1137
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1138 1139 1140 1141
    }
    else if (nr > 255.0)
    {
      *ptr=(char) 255;
1142
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1143
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1144 1145 1146 1147 1148 1149 1150 1151 1152
    }
    else
      *ptr=(char) nr;
  }
  else
  {
    if (nr < -128.0)
    {
      *ptr= (char) -128;
1153
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1154
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1155 1156 1157 1158
    }
    else if (nr > 127.0)
    {
      *ptr=127;
1159
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1160
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1161 1162 1163 1164
    }
    else
      *ptr=(char) nr;
  }
1165
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1166 1167
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1168
int Field_tiny::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1169
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1170
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1171 1172 1173 1174 1175
  if (unsigned_flag)
  {
    if (nr < 0L)
    {
      *ptr=0;
1176
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1177
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1178 1179 1180 1181
    }
    else if (nr > 255L)
    {
      *ptr= (char) 255;
1182
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1183
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1184 1185 1186 1187 1188 1189 1190 1191 1192
    }
    else
      *ptr=(char) nr;
  }
  else
  {
    if (nr < -128L)
    {
      *ptr= (char) -128;
1193
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1194
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1195 1196 1197 1198
    }
    else if (nr > 127L)
    {
      *ptr=127;
1199
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1200
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1201 1202 1203 1204
    }
    else
      *ptr=(char) nr;
  }
1205
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
}


double Field_tiny::val_real(void)
{
  int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
    (int) ((signed char*) ptr)[0];
  return (double) tmp;
}

longlong Field_tiny::val_int(void)
{
  int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
    (int) ((signed char*) ptr)[0];
  return (longlong) tmp;
}

String *Field_tiny::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
1226
  CHARSET_INFO *cs= &my_charset_bin;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1227
  uint length;
1228 1229
  uint mlength=max(field_length+1,5*cs->mbmaxlen);
  val_buffer->alloc(mlength);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1230
  char *to=(char*) val_buffer->ptr();
1231

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1232
  if (unsigned_flag)
1233 1234
    length= (uint) cs->cset->long10_to_str(cs,to,mlength, 10,
					   (long) *((uchar*) ptr));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1235
  else
1236 1237
    length= (uint) cs->cset->long10_to_str(cs,to,mlength,-10,
					   (long) *((signed char*) ptr));
1238
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1239 1240 1241 1242 1243 1244
  val_buffer->length(length);
  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}

1245 1246 1247 1248
bool Field_tiny::send_binary(Protocol *protocol)
{
  return protocol->store_tiny((longlong) (int8) ptr[0]);
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268

int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
{
  signed char a,b;
  a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
  if (unsigned_flag)
    return ((uchar) a < (uchar) b) ? -1 : ((uchar) a > (uchar) b) ? 1 : 0;
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_tiny::sort_string(char *to,uint length __attribute__((unused)))
{
  if (unsigned_flag)
    *to= *ptr;
  else
    to[0] = (char) ((uchar) ptr[0] ^ (uchar) 128);	/* Revers signbit */
}

void Field_tiny::sql_type(String &res) const
{
1269
  CHARSET_INFO *cs=res.charset();
1270
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
1271
			  "tinyint(%d)",(int) field_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1272 1273 1274 1275
  add_zerofill_and_unsigned(res);
}

/****************************************************************************
1276
 Field type short int (2 byte)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1277 1278
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1279
int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1280
{
1281
  int not_used;				// We can ignore result from str2int
1282
  char *end;
1283
  long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1284
  int error= 0;
1285

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1286 1287 1288 1289 1290
  if (unsigned_flag)
  {
    if (tmp < 0)
    {
      tmp=0;
1291
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1292
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1293 1294 1295 1296
    }
    else if (tmp > (uint16) ~0)
    {
      tmp=(uint16) ~0;
1297
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1298
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1299
    }
1300
    else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
1301
    {
1302
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1303
      error= 1;
1304
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1305 1306 1307 1308 1309 1310
  }
  else
  {
    if (tmp < INT_MIN16)
    {
      tmp= INT_MIN16;
1311
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1312
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1313 1314 1315 1316
    }
    else if (tmp > INT_MAX16)
    {
      tmp=INT_MAX16;
1317
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1318
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1319
    }
1320
    else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
1321
    {
1322
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1323
      error= 1;
1324
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1325 1326 1327 1328 1329 1330 1331 1332 1333
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int2store(ptr,tmp);
  }
  else
#endif
    shortstore(ptr,(short) tmp);
1334
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1335 1336 1337
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1338
int Field_short::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1339
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1340
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1341 1342 1343 1344 1345 1346 1347
  int16 res;
  nr=rint(nr);
  if (unsigned_flag)
  {
    if (nr < 0)
    {
      res=0;
1348
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1349
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1350 1351 1352 1353
    }
    else if (nr > (double) (uint16) ~0)
    {
      res=(int16) (uint16) ~0;
1354
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1355
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1356 1357 1358 1359 1360 1361 1362 1363 1364
    }
    else
      res=(int16) (uint16) nr;
  }
  else
  {
    if (nr < (double) INT_MIN16)
    {
      res=INT_MIN16;
1365
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1366
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1367 1368 1369 1370
    }
    else if (nr > (double) INT_MAX16)
    {
      res=INT_MAX16;
1371
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1372
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
    }
    else
      res=(int16) nr;
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int2store(ptr,res);
  }
  else
#endif
    shortstore(ptr,res);
1385
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1386 1387
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1388
int Field_short::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1389
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1390
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1391 1392 1393 1394 1395 1396
  int16 res;
  if (unsigned_flag)
  {
    if (nr < 0L)
    {
      res=0;
1397
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1398
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1399 1400 1401 1402
    }
    else if (nr > (longlong) (uint16) ~0)
    {
      res=(int16) (uint16) ~0;
1403
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1404
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1405 1406 1407 1408 1409 1410 1411 1412 1413
    }
    else
      res=(int16) (uint16) nr;
  }
  else
  {
    if (nr < INT_MIN16)
    {
      res=INT_MIN16;
1414
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1415
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1416 1417 1418 1419
    }
    else if (nr > INT_MAX16)
    {
      res=INT_MAX16;
1420
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1421
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
    }
    else
      res=(int16) nr;
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int2store(ptr,res);
  }
  else
#endif
    shortstore(ptr,res);
1434
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
}


double Field_short::val_real(void)
{
  short j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint2korr(ptr);
  else
#endif
    shortget(j,ptr);
  return unsigned_flag ? (double) (unsigned short) j : (double) j;
}

longlong Field_short::val_int(void)
{
  short j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint2korr(ptr);
  else
#endif
    shortget(j,ptr);
  return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
}

1462

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1463 1464 1465
String *Field_short::val_str(String *val_buffer,
			     String *val_ptr __attribute__((unused)))
{
1466
  CHARSET_INFO *cs= &my_charset_bin;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1467
  uint length;
1468 1469
  uint mlength=max(field_length+1,7*cs->mbmaxlen);
  val_buffer->alloc(mlength);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
  char *to=(char*) val_buffer->ptr();
  short j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint2korr(ptr);
  else
#endif
    shortget(j,ptr);

  if (unsigned_flag)
1480 1481
    length=(uint) cs->cset->long10_to_str(cs, to, mlength, 10, 
					  (long) (uint16) j);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1482
  else
1483
    length=(uint) cs->cset->long10_to_str(cs, to, mlength,-10, (long) j);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1484 1485 1486 1487 1488 1489 1490
  val_buffer->length(length);
  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}


1491 1492 1493 1494 1495 1496
bool Field_short::send_binary(Protocol *protocol)
{
  return protocol->store_short(Field_short::val_int());
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
int Field_short::cmp(const char *a_ptr, const char *b_ptr)
{
  short a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    a=sint2korr(a_ptr);
    b=sint2korr(b_ptr);
  }
  else
#endif
  {
    shortget(a,a_ptr);
    shortget(b,b_ptr);
  }

  if (unsigned_flag)
    return ((unsigned short) a < (unsigned short) b) ? -1 :
    ((unsigned short) a > (unsigned short) b) ? 1 : 0;
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_short::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
  if (!table->db_low_byte_first)
  {
    if (unsigned_flag)
      to[0] = ptr[0];
    else
1527
      to[0] = (char) (ptr[0] ^ 128);		/* Revers signbit */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1528 1529 1530 1531 1532 1533 1534 1535
    to[1]   = ptr[1];
  }
  else
#endif
  {
    if (unsigned_flag)
      to[0] = ptr[1];
    else
1536
      to[0] = (char) (ptr[1] ^ 128);		/* Revers signbit */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1537 1538 1539 1540 1541 1542
    to[1]   = ptr[0];
  }
}

void Field_short::sql_type(String &res) const
{
1543
  CHARSET_INFO *cs=res.charset();
1544
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
1545
			  "smallint(%d)",(int) field_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1546 1547 1548 1549 1550
  add_zerofill_and_unsigned(res);
}


/****************************************************************************
1551
  Field type medium int (3 byte)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1552 1553
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1554
int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1555
{
1556
  int not_used;				// We can ignore result from str2int
1557
  char *end;
1558
  long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1559
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1560 1561 1562 1563 1564 1565

  if (unsigned_flag)
  {
    if (tmp < 0)
    {
      tmp=0;
1566
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1567
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1568 1569 1570 1571
    }
    else if (tmp >= (long) (1L << 24))
    {
      tmp=(long) (1L << 24)-1L;
1572
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1573
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1574
    }
1575
    else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
1576
    {
1577
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1578
      error= 1;
1579
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1580 1581 1582 1583 1584 1585
  }
  else
  {
    if (tmp < INT_MIN24)
    {
      tmp= INT_MIN24;
1586
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1587
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1588 1589 1590 1591
    }
    else if (tmp > INT_MAX24)
    {
      tmp=INT_MAX24;
1592
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1593
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1594
    }
1595
    else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
1596
    {
1597
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1598
      error= 1;
1599
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1600 1601 1602
  }

  int3store(ptr,tmp);
1603
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1604 1605 1606
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1607
int Field_medium::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1608
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1609
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1610 1611 1612 1613 1614 1615
  nr=rint(nr);
  if (unsigned_flag)
  {
    if (nr < 0)
    {
      int3store(ptr,0);
1616
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1617
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1618 1619 1620
    }
    else if (nr >= (double) (long) (1L << 24))
    {
1621
      uint32 tmp=(uint32) (1L << 24)-1L;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1622
      int3store(ptr,tmp);
1623
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1624
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1625 1626
    }
    else
1627
      int3store(ptr,(uint32) nr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1628 1629 1630 1631 1632 1633 1634
  }
  else
  {
    if (nr < (double) INT_MIN24)
    {
      long tmp=(long) INT_MIN24;
      int3store(ptr,tmp);
1635
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1636
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1637 1638 1639 1640 1641
    }
    else if (nr > (double) INT_MAX24)
    {
      long tmp=(long) INT_MAX24;
      int3store(ptr,tmp);
1642
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1643
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1644 1645 1646 1647
    }
    else
      int3store(ptr,(long) nr);
  }
1648
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1649 1650
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1651
int Field_medium::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1652
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1653
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1654 1655 1656 1657 1658
  if (unsigned_flag)
  {
    if (nr < 0L)
    {
      int3store(ptr,0);
1659
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1660
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1661 1662 1663 1664 1665
    }
    else if (nr >= (longlong) (long) (1L << 24))
    {
      long tmp=(long) (1L << 24)-1L;;
      int3store(ptr,tmp);
1666
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1667
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1668 1669
    }
    else
1670
      int3store(ptr,(uint32) nr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1671 1672 1673 1674 1675 1676 1677
  }
  else
  {
    if (nr < (longlong) INT_MIN24)
    {
      long tmp=(long) INT_MIN24;
      int3store(ptr,tmp);
1678
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1679
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1680 1681 1682 1683 1684
    }
    else if (nr > (longlong) INT_MAX24)
    {
      long tmp=(long) INT_MAX24;
      int3store(ptr,tmp);
1685
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1686
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1687 1688 1689 1690
    }
    else
      int3store(ptr,(long) nr);
  }
1691
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1692 1693 1694 1695 1696 1697 1698 1699 1700
}


double Field_medium::val_real(void)
{
  long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
  return (double) j;
}

1701

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1702 1703 1704 1705 1706 1707
longlong Field_medium::val_int(void)
{
  long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
  return (longlong) j;
}

1708

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1709 1710 1711
String *Field_medium::val_str(String *val_buffer,
			      String *val_ptr __attribute__((unused)))
{
1712
  CHARSET_INFO *cs= &my_charset_bin;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1713
  uint length;
1714 1715
  uint mlength=max(field_length+1,10*cs->mbmaxlen);
  val_buffer->alloc(mlength);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1716 1717 1718
  char *to=(char*) val_buffer->ptr();
  long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);

1719
  length=(uint) cs->cset->long10_to_str(cs,to,mlength,-10,j);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1720 1721 1722 1723 1724 1725 1726
  val_buffer->length(length);
  if (zerofill)
    prepend_zeros(val_buffer); /* purecov: inspected */
  return val_buffer;
}


1727 1728 1729 1730 1731 1732
bool Field_medium::send_binary(Protocol *protocol)
{
  return protocol->store_long(Field_medium::val_int());
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
{
  long a,b;
  if (unsigned_flag)
  {
    a=uint3korr(a_ptr);
    b=uint3korr(b_ptr);
  }
  else
  {
    a=sint3korr(a_ptr);
    b=sint3korr(b_ptr);
  }
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_medium::sort_string(char *to,uint length __attribute__((unused)))
{
  if (unsigned_flag)
    to[0] = ptr[2];
  else
    to[0] = (uchar) (ptr[2] ^ 128);		/* Revers signbit */
  to[1] = ptr[1];
  to[2] = ptr[0];
}


void Field_medium::sql_type(String &res) const
{
1762
  CHARSET_INFO *cs=res.charset();
1763
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), 
1764
			  "mediumint(%d)",(int) field_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1765 1766 1767 1768 1769 1770 1771 1772
  add_zerofill_and_unsigned(res);
}

/****************************************************************************
** long int
****************************************************************************/


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1773
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1774
{
1775 1776
  long tmp;
  int error= 0;
1777
  char *end;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1778
  
1779
  tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
1780 1781
  len-= tmp;
  from+= tmp;
1782
  my_errno=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1783 1784 1785 1786 1787
  if (unsigned_flag)
  {
    if (!len || *from == '-')
    {
      tmp=0;					// Set negative to 0
1788
      my_errno=ERANGE;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1789
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1790 1791
    }
    else
1792
      tmp=(long) my_strntoul(cs,from,len,10,&end,&error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1793 1794
  }
  else
1795 1796
    tmp=my_strntol(cs,from,len,10,&end,&error);
  if (error ||
1797
      (from+len != end && current_thd->count_cuted_fields &&
1798
       !test_if_int(from,len,end,cs)))
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1799
  {
1800
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
1801
    error= 1;
1802
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1803 1804 1805 1806 1807 1808 1809 1810
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,tmp);
  }
  else
#endif
    longstore(ptr,tmp);
1811
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1812 1813 1814
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1815
int Field_long::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1816
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1817
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1818 1819 1820 1821 1822 1823 1824
  int32 res;
  nr=rint(nr);
  if (unsigned_flag)
  {
    if (nr < 0)
    {
      res=0;
1825
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1826
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1827 1828 1829 1830
    }
    else if (nr > (double) (ulong) ~0L)
    {
      res=(int32) (uint32) ~0L;
1831
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1832
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1833 1834 1835 1836 1837 1838 1839 1840 1841
    }
    else
      res=(int32) (ulong) nr;
  }
  else
  {
    if (nr < (double) INT_MIN32)
    {
      res=(int32) INT_MIN32;
1842
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1843
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1844 1845 1846 1847
    }
    else if (nr > (double) INT_MAX32)
    {
      res=(int32) INT_MAX32;
1848
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1849
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
    }
    else
      res=(int32) nr;
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,res);
  }
  else
#endif
    longstore(ptr,res);
1862
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1863 1864 1865
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1866
int Field_long::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1867
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1868
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1869 1870 1871 1872 1873 1874
  int32 res;
  if (unsigned_flag)
  {
    if (nr < 0)
    {
      res=0;
1875
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1876
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1877 1878 1879 1880
    }
    else if (nr >= (LL(1) << 32))
    {
      res=(int32) (uint32) ~0L;
1881
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1882
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1883 1884 1885 1886 1887 1888 1889 1890 1891
    }
    else
      res=(int32) (uint32) nr;
  }
  else
  {
    if (nr < (longlong) INT_MIN32)
    {
      res=(int32) INT_MIN32;
1892
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1893
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1894 1895 1896 1897
    }
    else if (nr > (longlong) INT_MAX32)
    {
      res=(int32) INT_MAX32;
1898
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1899
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911
    }
    else
      res=(int32) nr;
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,res);
  }
  else
#endif
    longstore(ptr,res);
1912
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
}


double Field_long::val_real(void)
{
  int32 j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint4korr(ptr);
  else
#endif
    longget(j,ptr);
  return unsigned_flag ? (double) (uint32) j : (double) j;
}

longlong Field_long::val_int(void)
{
  int32 j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint4korr(ptr);
  else
#endif
    longget(j,ptr);
  return unsigned_flag ? (longlong) (uint32) j : (longlong) j;
}

String *Field_long::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
1943
  CHARSET_INFO *cs= &my_charset_bin;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1944
  uint length;
1945 1946
  uint mlength=max(field_length+1,12*cs->mbmaxlen);
  val_buffer->alloc(mlength);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1947 1948 1949 1950 1951 1952 1953 1954 1955
  char *to=(char*) val_buffer->ptr();
  int32 j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint4korr(ptr);
  else
#endif
    longget(j,ptr);

1956
  if (unsigned_flag)
1957
    length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j);
1958
  else
1959
    length=cs->cset->long10_to_str(cs,to,mlength,-10,(long) j);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1960 1961 1962 1963 1964 1965 1966
  val_buffer->length(length);
  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}


1967 1968 1969 1970 1971
bool Field_long::send_binary(Protocol *protocol)
{
  return protocol->store_long(Field_long::val_int());
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987
int Field_long::cmp(const char *a_ptr, const char *b_ptr)
{
  int32 a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    a=sint4korr(a_ptr);
    b=sint4korr(b_ptr);
  }
  else
#endif
  {
    longget(a,a_ptr);
    longget(b,b_ptr);
  }
  if (unsigned_flag)
1988
    return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_long::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
  if (!table->db_low_byte_first)
  {
    if (unsigned_flag)
      to[0] = ptr[0];
    else
2000
      to[0] = (char) (ptr[0] ^ 128);		/* Revers signbit */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
    to[1]   = ptr[1];
    to[2]   = ptr[2];
    to[3]   = ptr[3];
  }
  else
#endif
  {
    if (unsigned_flag)
      to[0] = ptr[3];
    else
2011
      to[0] = (char) (ptr[3] ^ 128);		/* Revers signbit */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2012 2013 2014 2015 2016 2017 2018 2019 2020
    to[1]   = ptr[2];
    to[2]   = ptr[1];
    to[3]   = ptr[0];
  }
}


void Field_long::sql_type(String &res) const
{
2021
  CHARSET_INFO *cs=res.charset();
2022
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
2023
			  "int(%d)",(int) field_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2024 2025 2026 2027
  add_zerofill_and_unsigned(res);
}

/****************************************************************************
2028
 Field type longlong int (8 bytes)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2029 2030
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2031
int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2032
{
2033 2034
  longlong tmp;
  int error= 0;
2035
  char *end;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
2036
  
2037
  tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
2038
  len-= (uint)tmp;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
2039
  from+= tmp;
2040
  my_errno=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2041 2042 2043 2044 2045
  if (unsigned_flag)
  {
    if (!len || *from == '-')
    {
      tmp=0;					// Set negative to 0
2046
      my_errno= ERANGE;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2047
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2048 2049
    }
    else
2050
      tmp=(longlong) my_strntoull(cs,from,len,10,&end,&error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2051 2052
  }
  else
2053 2054
    tmp=my_strntoll(cs,from,len,10,&end,&error);
  if (error ||
2055
      (from+len != end && current_thd->count_cuted_fields &&
2056
       !test_if_int(from,len,end,cs)))
2057
  {
2058
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
2059 2060
    error= 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2061 2062 2063 2064 2065 2066 2067 2068
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,tmp);
  }
  else
#endif
    longlongstore(ptr,tmp);
2069
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2070 2071 2072
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2073
int Field_longlong::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2074
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2075
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2076 2077 2078 2079 2080 2081 2082
  longlong res;
  nr=rint(nr);
  if (unsigned_flag)
  {
    if (nr < 0)
    {
      res=0;
2083
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2084
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2085 2086 2087 2088
    }
    else if (nr >= (double) ~ (ulonglong) 0)
    {
      res= ~(longlong) 0;
2089
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2090
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2091 2092 2093 2094 2095 2096 2097 2098 2099
    }
    else
      res=(longlong) (ulonglong) nr;
  }
  else
  {
    if (nr <= (double) LONGLONG_MIN)
    {
      res=(longlong) LONGLONG_MIN;
2100
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2101
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2102 2103 2104 2105
    }
    else if (nr >= (double) LONGLONG_MAX)
    {
      res=(longlong) LONGLONG_MAX;
2106
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2107
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
    }
    else
      res=(longlong) nr;
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,res);
  }
  else
#endif
    longlongstore(ptr,res);
2120
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2121 2122 2123
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2124
int Field_longlong::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2125 2126 2127 2128 2129 2130 2131 2132 2133
{
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,nr);
  }
  else
#endif
    longlongstore(ptr,nr);
2134
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
}


double Field_longlong::val_real(void)
{
  longlong j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    j=sint8korr(ptr);
  }
  else
#endif
    longlongget(j,ptr);
2149 2150 2151 2152 2153 2154 2155
  /* The following is open coded to avoid a bug in gcc 3.3 */
  if (unsigned_flag)
  {
    ulonglong tmp= (ulonglong) j;
    return ulonglong2double(tmp);
  }
  return (double) j;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2156 2157
}

2158

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
longlong Field_longlong::val_int(void)
{
  longlong j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint8korr(ptr);
  else
#endif
    longlongget(j,ptr);
  return j;
}


String *Field_longlong::val_str(String *val_buffer,
				String *val_ptr __attribute__((unused)))
{
2175
  CHARSET_INFO *cs= &my_charset_bin;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2176
  uint length;
2177 2178
  uint mlength=max(field_length+1,22*cs->mbmaxlen);
  val_buffer->alloc(mlength);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2179 2180 2181 2182 2183 2184 2185 2186 2187
  char *to=(char*) val_buffer->ptr();
  longlong j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint8korr(ptr);
  else
#endif
    longlongget(j,ptr);

2188
  length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength,
2189
					unsigned_flag ? 10 : -10, j);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2190 2191 2192 2193 2194 2195 2196
  val_buffer->length(length);
  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}


2197 2198 2199 2200 2201 2202
bool Field_longlong::send_binary(Protocol *protocol)
{
  return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231
int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
{
  longlong a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    a=sint8korr(a_ptr);
    b=sint8korr(b_ptr);
  }
  else
#endif
  {
    longlongget(a,a_ptr);
    longlongget(b,b_ptr);
  }
  if (unsigned_flag)
    return ((ulonglong) a < (ulonglong) b) ? -1 :
    ((ulonglong) a > (ulonglong) b) ? 1 : 0;
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
  if (!table->db_low_byte_first)
  {
    if (unsigned_flag)
      to[0] = ptr[0];
    else
2232
      to[0] = (char) (ptr[0] ^ 128);		/* Revers signbit */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246
    to[1]   = ptr[1];
    to[2]   = ptr[2];
    to[3]   = ptr[3];
    to[4]   = ptr[4];
    to[5]   = ptr[5];
    to[6]   = ptr[6];
    to[7]   = ptr[7];
  }
  else
#endif
  {
    if (unsigned_flag)
      to[0] = ptr[7];
    else
2247
      to[0] = (char) (ptr[7] ^ 128);		/* Revers signbit */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260
    to[1]   = ptr[6];
    to[2]   = ptr[5];
    to[3]   = ptr[4];
    to[4]   = ptr[3];
    to[5]   = ptr[2];
    to[6]   = ptr[1];
    to[7]   = ptr[0];
  }
}


void Field_longlong::sql_type(String &res) const
{
2261
  CHARSET_INFO *cs=res.charset();
2262
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
2263
			  "bigint(%d)",(int) field_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2264 2265 2266 2267 2268 2269 2270
  add_zerofill_and_unsigned(res);
}

/****************************************************************************
** single precision float
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2271
int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2272
{
2273
  int err;
2274 2275
  Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL,&err));
  if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
2276
  {
2277
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
2278 2279
    return 1;
  }
2280
  return (err) ? 1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2281 2282 2283
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2284
int Field_float::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2285 2286
{
  float j;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2287
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2288 2289
  if (dec < NOT_FIXED_DEC)
    nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
2290 2291
  if (unsigned_flag && nr < 0)
  {
2292
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
2293
    nr=0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2294
    error= 1;
2295
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2296 2297 2298
  if (nr < -FLT_MAX)
  {
    j= -FLT_MAX;
2299
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2300
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2301 2302 2303 2304
  }
  else if (nr > FLT_MAX)
  {
    j=FLT_MAX;
2305
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2306
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317
  }
  else
    j= (float) nr;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4store(ptr,j);
  }
  else
#endif
    memcpy_fixed(ptr,(byte*) &j,sizeof(j));
2318
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2319 2320 2321
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2322
int Field_float::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2323
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2324
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2325
  float j= (float) nr;
2326 2327
  if (unsigned_flag && j < 0)
  {
2328
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
2329
    j=0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2330
    error= 1;
2331
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2332 2333 2334 2335 2336 2337 2338 2339
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4store(ptr,j);
  }
  else
#endif
    memcpy_fixed(ptr,(byte*) &j,sizeof(j));
2340
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385
}


double Field_float::val_real(void)
{
  float j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4get(j,ptr);
  }
  else
#endif
    memcpy_fixed((byte*) &j,ptr,sizeof(j));
  return ((double) j);
}

longlong Field_float::val_int(void)
{
  float j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4get(j,ptr);
  }
  else
#endif
    memcpy_fixed((byte*) &j,ptr,sizeof(j));
  return ((longlong) j);
}


String *Field_float::val_str(String *val_buffer,
			     String *val_ptr __attribute__((unused)))
{
  float nr;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4get(nr,ptr);
  }
  else
#endif
    memcpy_fixed((byte*) &nr,ptr,sizeof(nr));

2386 2387
  uint to_length=max(field_length,70);
  val_buffer->alloc(to_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
  char *to=(char*) val_buffer->ptr();

  if (dec >= NOT_FIXED_DEC)
  {
    sprintf(to,"%-*.*g",(int) field_length,FLT_DIG,nr);
    to=strcend(to,' ');
    *to=0;
  }
  else
  {
#ifdef HAVE_FCONVERT
    char buff[70],*pos=buff;
    int decpt,sign,tmp_dec=dec;

    VOID(sfconvert(&nr,tmp_dec,&decpt,&sign,buff));
    if (sign)
    {
      *to++='-';
    }
    if (decpt < 0)
    {					/* val_buffer is < 0 */
      *to++='0';
      if (!tmp_dec)
	goto end;
      *to++='.';
      if (-decpt > tmp_dec)
	decpt= - (int) tmp_dec;
      tmp_dec=(uint) ((int) tmp_dec+decpt);
      while (decpt++ < 0)
	*to++='0';
    }
    else if (decpt == 0)
    {
      *to++= '0';
      if (!tmp_dec)
	goto end;
      *to++='.';
    }
    else
    {
      while (decpt-- > 0)
	*to++= *pos++;
      if (!tmp_dec)
	goto end;
      *to++='.';
    }
    while (tmp_dec--)
      *to++= *pos++;
2436
#else
2437 2438 2439
#ifdef HAVE_SNPRINTF
    to[to_length-1]=0;			// Safety
    snprintf(to,to_length-1,"%.*f",dec,nr);
2440
    to=strend(to);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2441
#else
2442
    to+= my_sprintf(to,(to,"%.*f",dec,nr));
2443
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504
#endif
  }
#ifdef HAVE_FCONVERT
 end:
#endif
  val_buffer->length((uint) (to-val_buffer->ptr()));
  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}


int Field_float::cmp(const char *a_ptr, const char *b_ptr)
{
  float a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4get(a,a_ptr);
    float4get(b,b_ptr);
  }
  else
#endif
  {
    memcpy_fixed(&a,a_ptr,sizeof(float));
    memcpy_fixed(&b,b_ptr,sizeof(float));
  }
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

#define FLT_EXP_DIG (sizeof(float)*8-FLT_MANT_DIG)

void Field_float::sort_string(char *to,uint length __attribute__((unused)))
{
  float nr;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float4get(nr,ptr);
  }
  else
#endif
    memcpy_fixed(&nr,ptr,sizeof(float));

  uchar *tmp= (uchar*) to;
  if (nr == (float) 0.0)
  {						/* Change to zero string */
    tmp[0]=(uchar) 128;
    bzero((char*) tmp+1,sizeof(nr)-1);
  }
  else
  {
#ifdef WORDS_BIGENDIAN
    memcpy_fixed(tmp,&nr,sizeof(nr));
#else
    tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
#endif
    if (tmp[0] & 128)				/* Negative */
    {						/* make complement */
      uint i;
      for (i=0 ; i < sizeof(nr); i++)
2505
	tmp[i]= (uchar) (tmp[i] ^ (uchar) 255);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518
    }
    else
    {
      ushort exp_part=(((ushort) tmp[0] << 8) | (ushort) tmp[1] |
		       (ushort) 32768);
      exp_part+= (ushort) 1 << (16-1-FLT_EXP_DIG);
      tmp[0]= (uchar) (exp_part >> 8);
      tmp[1]= (uchar) exp_part;
    }
  }
}


2519 2520 2521 2522 2523 2524
bool Field_float::send_binary(Protocol *protocol)
{
  return protocol->store((float) Field_float::val_real(), dec, (String*) 0);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
2525 2526 2527
void Field_float::sql_type(String &res) const
{
  if (dec == NOT_FIXED_DEC)
2528
  {
2529
    res.set_ascii("float", 5);
2530
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2531
  else
2532
  {
2533
    CHARSET_INFO *cs= res.charset();
2534
    res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
2535
			    "float(%d,%d)",(int) field_length,dec));
2536
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2537 2538 2539 2540 2541 2542 2543
  add_zerofill_and_unsigned(res);
}

/****************************************************************************
** double precision floating point numbers
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2544
int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2545
{
2546
  int err;
2547 2548
  double j= my_strntod(cs,(char*) from,len,(char**)0,&err);
  if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
2549
  {
2550
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
2551
    err= 1;
2552
  }
2553 2554
  if (unsigned_flag && j < 0)
  {
2555
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
2556
    j=0;
2557
    err= 1;
2558
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2559 2560 2561 2562 2563 2564 2565 2566
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8store(ptr,j);
  }
  else
#endif
    doublestore(ptr,j);
2567
  return err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2568 2569 2570
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2571
int Field_double::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2572
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2573
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2574 2575
  if (dec < NOT_FIXED_DEC)
    nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
2576 2577
  if (unsigned_flag && nr < 0)
  {
2578
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
2579
    nr=0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2580
    error= 1;
2581
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2582 2583 2584 2585 2586 2587 2588 2589
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8store(ptr,nr);
  }
  else
#endif
    doublestore(ptr,nr);
2590
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2591 2592 2593
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2594
int Field_double::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2595 2596
{
  double j= (double) nr;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2597
  int error= 0;
2598 2599
  if (unsigned_flag && j < 0)
  {
2600
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2601
    error= 1;
2602 2603
    j=0;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2604 2605 2606 2607 2608 2609 2610 2611
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8store(ptr,j);
  }
  else
#endif
    doublestore(ptr,j);
2612
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
}


double Field_double::val_real(void)
{
  double j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8get(j,ptr);
  }
  else
#endif
    doubleget(j,ptr);
  return j;
}

longlong Field_double::val_int(void)
{
  double j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8get(j,ptr);
  }
  else
#endif
    doubleget(j,ptr);
  return ((longlong) j);
}


String *Field_double::val_str(String *val_buffer,
			      String *val_ptr __attribute__((unused)))
{
  double nr;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8get(nr,ptr);
  }
  else
#endif
    doubleget(nr,ptr);

  uint to_length=max(field_length,320);
  val_buffer->alloc(to_length);
  char *to=(char*) val_buffer->ptr();

  if (dec >= NOT_FIXED_DEC)
  {
    sprintf(to,"%-*.*g",(int) field_length,DBL_DIG,nr);
    to=strcend(to,' ');
  }
  else
  {
#ifdef HAVE_FCONVERT
    char buff[320],*pos=buff;
    int decpt,sign,tmp_dec=dec;

    VOID(fconvert(nr,tmp_dec,&decpt,&sign,buff));
    if (sign)
    {
      *to++='-';
    }
    if (decpt < 0)
    {					/* val_buffer is < 0 */
      *to++='0';
      if (!tmp_dec)
	goto end;
      *to++='.';
      if (-decpt > tmp_dec)
	decpt= - (int) tmp_dec;
      tmp_dec=(uint) ((int) tmp_dec+decpt);
      while (decpt++ < 0)
	*to++='0';
    }
    else if (decpt == 0)
    {
      *to++= '0';
      if (!tmp_dec)
	goto end;
      *to++='.';
    }
    else
    {
      while (decpt-- > 0)
	*to++= *pos++;
      if (!tmp_dec)
	goto end;
      *to++='.';
    }
    while (tmp_dec--)
      *to++= *pos++;
#else
#ifdef HAVE_SNPRINTF
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2709
    to[to_length-1]=0;			// Safety
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
2710
    snprintf(to,to_length-1,"%.*f",dec,nr);
2711
    to=strend(to);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2712
#else
2713
    to+= my_sprintf(to,(to,"%.*f",dec,nr));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
#endif
#endif
  }
#ifdef HAVE_FCONVERT
 end:
#endif

  val_buffer->length((uint) (to-val_buffer->ptr()));
  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}

2727 2728
bool Field_double::send_binary(Protocol *protocol)
{
2729
  return protocol->store((double) Field_double::val_real(), dec, (String*) 0);
2730 2731
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744

int Field_double::cmp(const char *a_ptr, const char *b_ptr)
{
  double a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8get(a,a_ptr);
    float8get(b,b_ptr);
  }
  else
#endif
  {
2745
/* could this ALWAYS be 2 calls to doubleget() ?? */
2746
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
2747 2748 2749
    doubleget(a, a_ptr);
    doubleget(b, b_ptr);
#else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2750 2751
    memcpy_fixed(&a,a_ptr,sizeof(double));
    memcpy_fixed(&b,b_ptr,sizeof(double));
2752
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771
  }
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}


#define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)

/* The following should work for IEEE */

void Field_double::sort_string(char *to,uint length __attribute__((unused)))
{
  double nr;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    float8get(nr,ptr);
  }
  else
#endif
2772
/* could this ALWAYS be 2 calls to doubleget() ?? */
2773
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
2774 2775
    doubleget(nr,ptr);
#else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2776
    memcpy_fixed(&nr,ptr,sizeof(nr));
2777
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2778 2779 2780 2781 2782 2783
  change_double_for_sort(nr, (byte*) to);
}


void Field_double::sql_type(String &res) const
{
2784
  CHARSET_INFO *cs=res.charset();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2785
  if (dec == NOT_FIXED_DEC)
2786
  {
2787
    res.set_ascii("double",6);
2788
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2789
  else
2790
  {
2791
    res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
2792
			    "double(%d,%d)",(int) field_length,dec));
2793
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806
  add_zerofill_and_unsigned(res);
}


/****************************************************************************
** timestamp
** The first timestamp in the table is automaticly updated
** by handler.cc.  The form->timestamp points at the automatic timestamp.
****************************************************************************/

Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
				 enum utype unireg_check_arg,
				 const char *field_name_arg,
2807 2808 2809 2810
				 struct st_table *table_arg,
				 CHARSET_INFO *cs)
  :Field_str(ptr_arg, 19, (uchar*) 0,0,
	     unireg_check_arg, field_name_arg, table_arg, cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2811
{
2812
  flags|=ZEROFILL_FLAG; /* 4.0 MYD compatibility */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2813 2814 2815 2816 2817 2818 2819 2820 2821
  if (table && !table->timestamp_field)
  {
    table->timestamp_field= this;		// Automatic timestamp
    table->time_stamp=(ulong) (ptr_arg - (char*) table->record[0])+1;
    flags|=TIMESTAMP_FLAG;
  }
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2822
int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2823
{
2824
  long tmp=(long) str_to_timestamp(from,len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2825 2826 2827 2828 2829 2830 2831 2832
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,tmp);
  }
  else
#endif
    longstore(ptr,tmp);
2833
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2834 2835
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2836
int Field_timestamp::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2837
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2838
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2839 2840
  if (nr < 0 || nr > 99991231235959.0)
  {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2841
    nr= 0;					// Avoid overflow on buff
2842
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2843
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2844
  }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2845
  error|= Field_timestamp::store((longlong) rint(nr));
2846
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2847 2848 2849 2850
}


/*
2851 2852 2853
  Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to
  YYYYMMDDHHMMSS.  The high date '99991231235959' is checked before this
  function.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2854 2855 2856 2857
*/

static longlong fix_datetime(longlong nr)
{
2858
  current_thd->last_cuted_field= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882
  if (nr == LL(0) || nr >= LL(10000101000000))
    return nr;					// Normal datetime >= Year 1000
  if (nr < 101)
    goto err;
  if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
    return (nr+20000000L)*1000000L;		// YYMMDD, year: 2000-2069
  if (nr < (YY_PART_YEAR)*10000L+101L)
    goto err;
  if (nr <= 991231L)
    return (nr+19000000L)*1000000L;		// YYMMDD, year: 1970-1999
  if (nr < 10000101L)
    goto err;
  if (nr <= 99991231L)
    return nr*1000000L;
  if (nr < 101000000L)
    goto err;
  if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959))
    return nr+LL(20000000000000);		// YYMMDDHHMMSS, 2000-2069
  if (nr <  YY_PART_YEAR*LL(10000000000)+ LL(101000000))
    goto err;
  if (nr <= LL(991231235959))
    return nr+LL(19000000000000);		// YYMMDDHHMMSS, 1970-1999

 err:
2883
    current_thd->last_cuted_field= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2884 2885 2886 2887
  return LL(0);
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
2888
int Field_timestamp::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2889 2890 2891 2892 2893 2894 2895
{
  TIME l_time;
  time_t timestamp;
  long part1,part2;

  if ((nr=fix_datetime(nr)))
  {
2896
    long not_used;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2897 2898
    part1=(long) (nr/LL(1000000));
    part2=(long) (nr - (longlong) part1*LL(1000000));
2899
    l_time.year=  (int) (part1/10000L);  part1%=10000L;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2900
    l_time.month= (int) part1 / 100;
2901 2902
    l_time.day=	  (int) part1 % 100; 
    l_time.hour=  (int) (part2/10000L);  part2%=10000L;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2903 2904
    l_time.minute=(int) part2 / 100;
    l_time.second=(int) part2 % 100; 
2905
    timestamp=my_gmt_sec(&l_time, &not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
  }
  else
    timestamp=0;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,timestamp);
  }
  else
#endif
2916
    longstore(ptr,(uint32) timestamp);
2917 2918
  if (current_thd->last_cuted_field)    
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
2919
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
}


double Field_timestamp::val_real(void)
{
  return (double) Field_timestamp::val_int();
}

longlong Field_timestamp::val_int(void)
{
  int part_time;
  uint32 temp;
  time_t time_arg;
  struct tm *l_time;
  longlong res;
  struct tm tm_tmp;

#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    temp=uint4korr(ptr);
  else
#endif
    longget(temp,ptr);

  if (temp == 0L)				// No time
    return(0);					/* purecov: inspected */
  time_arg=(time_t) temp;
  localtime_r(&time_arg,&tm_tmp);
  l_time=&tm_tmp;
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962

  part_time= l_time->tm_year % 100;
  res= ((longlong) (part_time+ ((part_time < YY_PART_YEAR) ? 2000 : 1900))*
	LL(10000000000));
  part_time= l_time->tm_mon+1;
  res+= (longlong) part_time * LL(100000000);
  part_time=l_time->tm_mday;
  res+= (longlong) ((long) part_time * 1000000L);
  part_time=l_time->tm_hour;
  res+= (longlong) (part_time * 10000L);
  part_time=l_time->tm_min;
  res+= (longlong) (part_time * 100);
  part_time=l_time->tm_sec;
  return res+part_time;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2963 2964 2965 2966 2967 2968
}


String *Field_timestamp::val_str(String *val_buffer,
				 String *val_ptr __attribute__((unused)))
{
2969
  uint32 temp, temp2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2970 2971 2972 2973 2974
  time_t time_arg;
  struct tm *l_time;
  struct tm tm_tmp;

  val_buffer->alloc(field_length+1);
2975
  char *to= (char*) val_buffer->ptr();
2976
  val_buffer->length(field_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2977 2978 2979 2980 2981 2982 2983 2984 2985 2986

#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    temp=uint4korr(ptr);
  else
#endif
    longget(temp,ptr);

  if (temp == 0L)
  {				      /* Zero time is "000000" */
2987
    val_ptr->set("0000-00-00 00:00:00", 19, &my_charset_bin);
2988
    return val_ptr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2989
  }
2990
  val_buffer->set_charset(&my_charset_bin);	// Safety
bk@work.mysql.com's avatar
bk@work.mysql.com committed
2991 2992 2993
  time_arg=(time_t) temp;
  localtime_r(&time_arg,&tm_tmp);
  l_time=&tm_tmp;
2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034

  temp= l_time->tm_year % 100;
  if (temp < YY_PART_YEAR)
  {
    *to++= '2';
    *to++= '0';
  }
  else
  {
    *to++= '1';
    *to++= '9';
  }
  temp2=temp/10; temp=temp-temp2*10;
  *to++= (char) ('0'+(char) (temp2));
  *to++= (char) ('0'+(char) (temp));
  *to++= '-';
  temp=l_time->tm_mon+1;
  temp2=temp/10; temp=temp-temp2*10;
  *to++= (char) ('0'+(char) (temp2));
  *to++= (char) ('0'+(char) (temp));
  *to++= '-';
  temp=l_time->tm_mday;
  temp2=temp/10; temp=temp-temp2*10;
  *to++= (char) ('0'+(char) (temp2));
  *to++= (char) ('0'+(char) (temp));
  *to++= ' ';
  temp=l_time->tm_hour;
  temp2=temp/10; temp=temp-temp2*10;
  *to++= (char) ('0'+(char) (temp2));
  *to++= (char) ('0'+(char) (temp));
  *to++= ':';
  temp=l_time->tm_min;
  temp2=temp/10; temp=temp-temp2*10;
  *to++= (char) ('0'+(char) (temp2));
  *to++= (char) ('0'+(char) (temp));
  *to++= ':';
  temp=l_time->tm_sec;
  temp2=temp/10; temp=temp-temp2*10;
  *to++= (char) ('0'+(char) (temp2));
  *to++= (char) ('0'+(char) (temp));
  *to= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3035 3036 3037
  return val_buffer;
}

3038

3039
bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
{
  long temp;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    temp=uint4korr(ptr);
  else
#endif
    longget(temp,ptr);
  if (temp == 0L)
  {				      /* Zero time is "000000" */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3050 3051
    if (!fuzzydate)
      return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067
    bzero((char*) ltime,sizeof(*ltime));
  }
  else
  {
    struct tm tm_tmp;
    time_t time_arg= (time_t) temp;
    localtime_r(&time_arg,&tm_tmp);
    struct tm *start= &tm_tmp;
    ltime->year=	start->tm_year+1900;
    ltime->month=	start->tm_mon+1;
    ltime->day=		start->tm_mday;
    ltime->hour=	start->tm_hour;
    ltime->minute=	start->tm_min;
    ltime->second=	start->tm_sec;
    ltime->second_part=	0;
    ltime->neg=		0;
3068
    ltime->time_type=TIMESTAMP_DATETIME;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3069 3070 3071 3072 3073 3074
  }
  return 0;
}

bool Field_timestamp::get_time(TIME *ltime)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3075
  return Field_timestamp::get_date(ltime,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3076 3077
}

3078 3079 3080 3081

bool Field_timestamp::send_binary(Protocol *protocol)
{
  TIME tm;
3082
  Field_timestamp::get_date(&tm, TIME_FUZZY_DATE);
3083 3084 3085 3086
  return protocol->store(&tm);
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104
int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
{
  int32 a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    a=sint4korr(a_ptr);
    b=sint4korr(b_ptr);
  }
  else
#endif
  {
  longget(a,a_ptr);
  longget(b,b_ptr);
  }
  return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}

3105

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128
void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
  if (!table->db_low_byte_first)
  {
    to[0] = ptr[0];
    to[1] = ptr[1];
    to[2] = ptr[2];
    to[3] = ptr[3];
  }
  else
#endif
  {
    to[0] = ptr[3];
    to[1] = ptr[2];
    to[2] = ptr[1];
    to[3] = ptr[0];
  }
}


void Field_timestamp::sql_type(String &res) const
{
3129
  res.set_ascii("timestamp", 9);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152
}


void Field_timestamp::set_time()
{
  long tmp= (long) current_thd->query_start();
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,tmp);
  }
  else
#endif
    longstore(ptr,tmp);
}

/****************************************************************************
** time type
** In string context: HH:MM:SS
** In number context: HHMMSS
** Stored as a 3 byte unsigned int
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3153
int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3154 3155 3156
{
  TIME ltime;
  long tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3157
  int error= 0;
3158
  if (str_to_time(from,len,&ltime))
3159
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3160
    tmp=0L;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3161
    error= 1;
3162
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
3163
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3164 3165 3166 3167 3168 3169 3170 3171
  else
  {
    if (ltime.month)
      ltime.day=0;
    tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
    if (tmp > 8385959)
    {
      tmp=8385959;
3172
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3173
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3174 3175 3176 3177
    }
  }
  if (ltime.neg)
    tmp= -tmp;
3178 3179
  error |= Field_time::store((longlong) tmp);
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3180 3181 3182
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3183
int Field_time::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3184 3185
{
  long tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3186
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3187 3188 3189
  if (nr > 8385959.0)
  {
    tmp=8385959L;
3190
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3191
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3192 3193 3194 3195
  }
  else if (nr < -8385959.0)
  {
    tmp= -8385959L;
3196
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3197
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3198 3199 3200 3201 3202 3203 3204 3205 3206
  }
  else
  {
    tmp=(long) floor(fabs(nr));			// Remove fractions
    if (nr < 0)
      tmp= -tmp;
    if (tmp % 100 > 59 || tmp/100 % 100 > 59)
    {
      tmp=0;
3207
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3208
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3209 3210 3211
    }
  }
  int3store(ptr,tmp);
3212
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3213 3214 3215
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3216
int Field_time::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3217 3218
{
  long tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3219
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3220 3221 3222
  if (nr > (longlong) 8385959L)
  {
    tmp=8385959L;
3223
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3224
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3225 3226 3227 3228
  }
  else if (nr < (longlong) -8385959L)
  {
    tmp= -8385959L;
3229
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3230
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3231 3232 3233 3234 3235 3236 3237
  }
  else
  {
    tmp=(long) nr;
    if (tmp % 100 > 59 || tmp/100 % 100 > 59)
    {
      tmp=0;
3238
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3239
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3240 3241 3242
    }
  }
  int3store(ptr,tmp);
3243
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3244 3245 3246 3247 3248
}


double Field_time::val_real(void)
{
3249
  uint32 j= (uint32) uint3korr(ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3250 3251 3252 3253 3254 3255 3256 3257
  return (double) j;
}

longlong Field_time::val_int(void)
{
  return (longlong) sint3korr(ptr);
}

3258 3259 3260 3261 3262 3263

/*
  This function is multi-byte safe as the result string is always of type
  my_charset_bin
*/

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3264 3265 3266
String *Field_time::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
3267
  TIME ltime;
3268
  val_buffer->alloc(19);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3269
  long tmp=(long) sint3korr(ptr);
3270
  ltime.neg= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3271 3272 3273
  if (tmp < 0)
  {
    tmp= -tmp;
3274 3275 3276 3277 3278 3279
    ltime.neg= 1;
  }
  ltime.day= (uint) 0;
  ltime.hour= (uint) (tmp/10000);
  ltime.minute= (uint) (tmp/100 % 100);
  ltime.second= (uint) (tmp % 100);
3280
  make_time((DATE_TIME_FORMAT*) 0, &ltime, val_buffer);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3281 3282 3283
  return val_buffer;
}

3284

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3285 3286 3287 3288 3289 3290 3291 3292 3293
bool Field_time::get_time(TIME *ltime)
{
  long tmp=(long) sint3korr(ptr);
  ltime->neg=0;
  if (tmp < 0)
  {
    ltime->neg= 1;
    tmp=-tmp;
  }
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3294
  ltime->day= 0;
3295
  ltime->hour=   (int) (tmp/10000);
3296
  tmp-=ltime->hour*10000;
3297 3298
  ltime->minute= (int) tmp/100;
  ltime->second= (int) tmp % 100;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3299
  ltime->second_part=0;
gluh@gluh.mysql.r18.ru's avatar
gluh@gluh.mysql.r18.ru committed
3300
  ltime->time_type= TIMESTAMP_TIME;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3301 3302 3303
  return 0;
}

3304 3305 3306 3307 3308 3309 3310

bool Field_time::send_binary(Protocol *protocol)
{
  TIME tm;
  Field_time::get_time(&tm);
  tm.day= tm.hour/3600;				// Move hours to days
  tm.hour-= tm.day*3600;
3311
  return protocol->store_time(&tm);
3312 3313 3314
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
3315 3316
int Field_time::cmp(const char *a_ptr, const char *b_ptr)
{
3317 3318 3319
  int32 a,b;
  a=(int32) sint3korr(a_ptr);
  b=(int32) sint3korr(b_ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_time::sort_string(char *to,uint length __attribute__((unused)))
{
  to[0] = (uchar) (ptr[2] ^ 128);
  to[1] = ptr[1];
  to[2] = ptr[0];
}

void Field_time::sql_type(String &res) const
{
3332
  res.set_ascii("time", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3333 3334 3335 3336 3337 3338 3339 3340
}

/****************************************************************************
** year type
** Save in a byte the year 0, 1901->2155
** Can handle 2 byte or 4 byte years!
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3341
int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3342
{
3343
  int not_used;				// We can ignore result from str2int
3344
  char *end;
3345
  long nr= my_strntol(cs, from, len, 10, &end, &not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3346 3347 3348 3349

  if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
  {
    *ptr=0;
3350
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
3351
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3352
  }
3353
  else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
3354
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3355 3356 3357 3358 3359 3360 3361 3362
  if (nr != 0 || len != 4)
  {
    if (nr < YY_PART_YEAR)
      nr+=100;					// 2000 - 2069
    else if (nr > 1900)
      nr-= 1900;
  }
  *ptr= (char) (unsigned char) nr;
3363
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3364 3365
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3366
int Field_year::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3367 3368
{
  if (nr < 0.0 || nr >= 2155.0)
3369 3370 3371 3372
  {
    (void) Field_year::store((longlong) -1);
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3373
  else
3374
    return Field_year::store((longlong) nr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3375 3376
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3377
int Field_year::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3378 3379 3380 3381
{
  if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
  {
    *ptr=0;
3382
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
3383
    return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3384 3385 3386 3387 3388 3389 3390 3391 3392
  }
  if (nr != 0 || field_length != 4)		// 0000 -> 0; 00 -> 2000
  {
    if (nr < YY_PART_YEAR)
      nr+=100;					// 2000 - 2069
    else if (nr > 1900)
      nr-= 1900;
  }
  *ptr= (char) (unsigned char) nr;
3393
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3394 3395
}

3396 3397 3398
bool Field_year::send_binary(Protocol *protocol)
{
  ulonglong tmp= Field_year::val_int();
3399
  return protocol->store_short(tmp);
3400
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428

double Field_year::val_real(void)
{
  return (double) Field_year::val_int();
}

longlong Field_year::val_int(void)
{
  int tmp= (int) ((uchar*) ptr)[0];
  if (field_length != 4)
    tmp%=100;					// Return last 2 char
  else if (tmp)
    tmp+=1900;
  return (longlong) tmp;
}

String *Field_year::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
  val_buffer->alloc(5);
  val_buffer->length(field_length);
  char *to=(char*) val_buffer->ptr();
  sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
  return val_buffer;
}

void Field_year::sql_type(String &res) const
{
3429
  CHARSET_INFO *cs=res.charset();
3430
  res.length(cs->cset->snprintf(cs,(char*)res.ptr(),res.alloced_length(),
3431
			  "year(%d)",(int) field_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3432 3433 3434 3435 3436 3437 3438 3439 3440 3441
}


/****************************************************************************
** date type
** In string context: YYYY-MM-DD
** In number context: YYYYMMDD
** Stored as a 4 byte unsigned int
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3442
int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3443 3444
{
  TIME l_time;
3445
  uint32 tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3446
  int error= 0;
3447
  if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR)
3448
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3449
    tmp=0;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3450
    error= 1;
3451
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
3452
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3453
  else
3454
    tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3455 3456 3457 3458 3459 3460 3461 3462
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,tmp);
  }
  else
#endif
    longstore(ptr,tmp);
3463
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3464 3465 3466
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3467
int Field_date::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3468 3469
{
  long tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3470
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3471 3472 3473 3474 3475
  if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
    nr=floor(nr/1000000.0);			// Timestamp to date
  if (nr < 0.0 || nr > 99991231.0)
  {
    tmp=0L;
3476
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3477
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488
  }
  else
    tmp=(long) rint(nr);
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,tmp);
  }
  else
#endif
    longstore(ptr,tmp);
3489
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3490 3491 3492
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3493
int Field_date::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3494 3495
{
  long tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3496
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3497 3498 3499 3500 3501
  if (nr >= LL(19000000000000) && nr < LL(99991231235959))
    nr=nr/LL(1000000);			// Timestamp to date
  if (nr < 0 || nr > LL(99991231))
  {
    tmp=0L;
3502
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3503
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514
  }
  else
    tmp=(long) nr;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,tmp);
  }
  else
#endif
    longstore(ptr,tmp);
3515
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3516 3517 3518
}


3519 3520 3521 3522 3523 3524 3525 3526 3527 3528
bool Field_date::send_binary(Protocol *protocol)
{
  longlong tmp= Field_date::val_int();
  TIME tm;
  tm.year= (uint32) tmp/10000L % 10000;
  tm.month= (uint32) tmp/100 % 100;
  tm.day= (uint32) tmp % 100;
  return protocol->store_date(&tm);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556

double Field_date::val_real(void)
{
  int32 j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint4korr(ptr);
  else
#endif
    longget(j,ptr);
  return (double) (uint32) j;
}

longlong Field_date::val_int(void)
{
  int32 j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint4korr(ptr);
  else
#endif
    longget(j,ptr);
  return (longlong) (uint32) j;
}

String *Field_date::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
3557
  TIME ltime;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3558 3559 3560 3561 3562 3563 3564 3565
  val_buffer->alloc(field_length);
  int32 tmp;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    tmp=sint4korr(ptr);
  else
#endif
    longget(tmp,ptr);
3566 3567 3568 3569
  ltime.neg= 0;
  ltime.year= (int) ((uint32) tmp/10000L % 10000);
  ltime.month= (int) ((uint32) tmp/100 % 100);
  ltime.day= (int) ((uint32) tmp % 100);
3570
  make_date((DATE_TIME_FORMAT *) 0, &ltime, val_buffer);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3571 3572 3573
  return val_buffer;
}

3574

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615
int Field_date::cmp(const char *a_ptr, const char *b_ptr)
{
  int32 a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    a=sint4korr(a_ptr);
    b=sint4korr(b_ptr);
  }
  else
#endif
  {
    longget(a,a_ptr);
    longget(b,b_ptr);
  }
  return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}


void Field_date::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
  if (!table->db_low_byte_first)
  {
    to[0] = ptr[0];
    to[1] = ptr[1];
    to[2] = ptr[2];
    to[3] = ptr[3];
  }
  else
#endif
  {
    to[0] = ptr[3];
    to[1] = ptr[2];
    to[2] = ptr[1];
    to[3] = ptr[0];
  }
}

void Field_date::sql_type(String &res) const
{
3616
  res.set_ascii("date", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3617 3618 3619 3620 3621 3622 3623 3624
}

/****************************************************************************
** The new date type
** This is identical to the old date type, but stored on 3 bytes instead of 4
** In number context: YYYYMMDD
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3625
int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3626 3627 3628
{
  TIME l_time;
  long tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3629
  int error= 0;
3630
  if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR)
3631
  {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3632
    tmp=0L;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3633
    error= 1;
3634
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
3635
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3636 3637 3638
  else
    tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
  int3store(ptr,tmp);
3639
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3640 3641
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3642
int Field_newdate::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3643 3644
{
  if (nr < 0.0 || nr > 99991231235959.0)
3645 3646
  {
    (void) Field_newdate::store((longlong) -1);
3647
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
3648 3649
    return 1;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3650
  else
3651
    return Field_newdate::store((longlong) rint(nr));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3652 3653 3654
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3655
int Field_newdate::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3656
{
3657
  int32 tmp;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3658
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3659 3660 3661 3662 3663
  if (nr >= LL(100000000) && nr <= LL(99991231235959))
    nr=nr/LL(1000000);			// Timestamp to date
  if (nr < 0L || nr > 99991231L)
  {
    tmp=0;
3664
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3665
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3666 3667 3668
  }
  else
  {
3669
    tmp=(int32) nr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3670 3671 3672
    if (tmp)
    {
      if (tmp < YY_PART_YEAR*10000L)			// Fix short dates
3673
	tmp+= (uint32) 20000000L;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3674
      else if (tmp < 999999L)
3675
	tmp+= (uint32) 19000000L;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3676
    }
3677 3678
    uint month= (uint) ((tmp/100) % 100);
    uint day=   (uint) (tmp%100);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3679 3680 3681
    if (month > 12 || day > 31)
    {
      tmp=0L;					// Don't allow date to change
3682
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3683
      error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3684 3685 3686 3687
    }
    else
      tmp= day + month*32 + (tmp/10000)*16*32;
  }
3688
  int3store(ptr,(int32) tmp);
3689
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3690 3691 3692 3693 3694
}

void Field_newdate::store_time(TIME *ltime,timestamp_type type)
{
  long tmp;
3695
  if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3696 3697 3698 3699
    tmp=ltime->year*16*32+ltime->month*32+ltime->day;
  else
  {
    tmp=0;
3700
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3701 3702 3703 3704
  }
  int3store(ptr,tmp);
}

3705 3706 3707 3708 3709 3710
bool Field_newdate::send_binary(Protocol *protocol)
{
  TIME tm;
  Field_newdate::get_date(&tm,0);
  return protocol->store_date(&tm);
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3711 3712 3713 3714 3715 3716 3717 3718

double Field_newdate::val_real(void)
{
  return (double) Field_newdate::val_int();
}

longlong Field_newdate::val_int(void)
{
3719
  ulong j= uint3korr(ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3720 3721 3722 3723 3724 3725 3726 3727 3728
  j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
  return (longlong) j;
}

String *Field_newdate::val_str(String *val_buffer,
			       String *val_ptr __attribute__((unused)))
{
  val_buffer->alloc(field_length);
  val_buffer->length(field_length);
3729
  uint32 tmp=(uint32) uint3korr(ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3730 3731 3732 3733
  int part;
  char *pos=(char*) val_buffer->ptr()+10;

  /* Open coded to get more speed */
3734
  *pos--=0;					// End NULL
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3735
  part=(int) (tmp & 31);
3736 3737 3738
  *pos--= (char) ('0'+part%10);
  *pos--= (char) ('0'+part/10);
  *pos--= '-';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3739
  part=(int) (tmp >> 5 & 15);
3740 3741 3742
  *pos--= (char) ('0'+part%10);
  *pos--= (char) ('0'+part/10);
  *pos--= '-';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3743
  part=(int) (tmp >> 9);
3744 3745 3746 3747
  *pos--= (char) ('0'+part%10); part/=10;
  *pos--= (char) ('0'+part%10); part/=10;
  *pos--= (char) ('0'+part%10); part/=10;
  *pos=   (char) ('0'+part);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3748 3749 3750
  return val_buffer;
}

3751
bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3752 3753 3754
{
  if (is_null())
    return 1;
3755
  uint32 tmp=(uint32) uint3korr(ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3756 3757 3758
  ltime->day=   tmp & 31;
  ltime->month= (tmp >> 5) & 15;
  ltime->year=  (tmp >> 9);
3759
  ltime->time_type=TIMESTAMP_DATE;
3760
  ltime->hour= ltime->minute= ltime->second= ltime->second_part= ltime->neg= 0;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3761
  return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3762 3763 3764 3765
}

bool Field_newdate::get_time(TIME *ltime)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3766
  return Field_newdate::get_date(ltime,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3767 3768 3769 3770
}

int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
{
3771 3772 3773
  uint32 a,b;
  a=(uint32) uint3korr(a_ptr);
  b=(uint32) uint3korr(b_ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
{
  to[0] = ptr[2];
  to[1] = ptr[1];
  to[2] = ptr[0];
}

void Field_newdate::sql_type(String &res) const
{
3786
  res.set_ascii("date", 4);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3787 3788 3789 3790 3791 3792 3793 3794 3795 3796
}


/****************************************************************************
** datetime type
** In string context: YYYY-MM-DD HH:MM:DD
** In number context: YYYYMMDDHHMMDD
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3797
int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3798
{
3799
  longlong tmp=str_to_datetime(from,len,1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3800 3801 3802 3803 3804 3805 3806 3807
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,tmp);
  }
  else
#endif
    longlongstore(ptr,tmp);
3808
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3809 3810 3811
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3812
int Field_datetime::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3813
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3814
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3815 3816 3817
  if (nr < 0.0 || nr > 99991231235959.0)
  {
    nr=0.0;
3818
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3819
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3820
  }
3821 3822
  error |= Field_datetime::store((longlong) rint(nr));
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3823 3824 3825
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3826
int Field_datetime::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3827
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3828
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3829 3830 3831
  if (nr < 0 || nr > LL(99991231235959))
  {
    nr=0;
3832
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
3833
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844
  }
  else
    nr=fix_datetime(nr);
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,nr);
  }
  else
#endif
    longlongstore(ptr,nr);
3845 3846
  if (current_thd->last_cuted_field)    
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
3847
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3848 3849 3850 3851 3852
}

void Field_datetime::store_time(TIME *ltime,timestamp_type type)
{
  longlong tmp;
3853
  if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3854 3855 3856 3857 3858
    tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
	 (ltime->hour*10000L+ltime->minute*100+ltime->second));
  else
  {
    tmp=0;
3859
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870
  }
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,tmp);
  }
  else
#endif
    longlongstore(ptr,tmp);
}

3871 3872 3873
bool Field_datetime::send_binary(Protocol *protocol)
{
  TIME tm;
3874
  Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
3875 3876 3877
  return protocol->store(&tm);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922

double Field_datetime::val_real(void)
{
  return (double) Field_datetime::val_int();
}

longlong Field_datetime::val_int(void)
{
  longlong j;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    j=sint8korr(ptr);
  else
#endif
    longlongget(j,ptr);
  return j;
}


String *Field_datetime::val_str(String *val_buffer,
				String *val_ptr __attribute__((unused)))
{
  val_buffer->alloc(field_length);
  val_buffer->length(field_length);
  ulonglong tmp;
  long part1,part2;
  char *pos;
  int part3;

#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
    tmp=sint8korr(ptr);
  else
#endif
    longlongget(tmp,ptr);

  /*
    Avoid problem with slow longlong aritmetic and sprintf
  */

  part1=(long) (tmp/LL(1000000));
  part2=(long) (tmp - (ulonglong) part1*LL(1000000));

  pos=(char*) val_buffer->ptr()+19;
  *pos--=0;
3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941
  *pos--= (char) ('0'+(char) (part2%10)); part2/=10;
  *pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
  *pos--= ':';
  *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
  *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
  *pos--= ':';
  *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
  *pos--= (char) ('0'+(char) part3);
  *pos--= ' ';
  *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
  *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
  *pos--= '-';
  *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
  *pos--= (char) ('0'+(char) (part1%10)); part3= (int) (part1/10);
  *pos--= '-';
  *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
  *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
  *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
  *pos=(char) ('0'+(char) part3);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3942 3943 3944
  return val_buffer;
}

3945
bool Field_datetime::get_date(TIME *ltime, uint fuzzydate)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3946 3947
{
  longlong tmp=Field_datetime::val_int();
3948 3949 3950
  uint32 part1,part2;
  part1=(uint32) (tmp/LL(1000000));
  part2=(uint32) (tmp - (ulonglong) part1*LL(1000000));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3951

3952
  ltime->time_type=	TIMESTAMP_DATETIME;
3953 3954 3955 3956 3957 3958 3959 3960
  ltime->neg=		0;
  ltime->second_part=	0;
  ltime->second=	(int) (part2%100);
  ltime->minute=	(int) (part2/100%100);
  ltime->hour=		(int) (part2/10000);
  ltime->day=		(int) (part1%100);
  ltime->month= 	(int) (part1/100%100);
  ltime->year= 		(int) (part1/10000);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3961
  return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3962 3963 3964 3965
}

bool Field_datetime::get_time(TIME *ltime)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3966
  return Field_datetime::get_date(ltime,0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018
}

int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
{
  longlong a,b;
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    a=sint8korr(a_ptr);
    b=sint8korr(b_ptr);
  }
  else
#endif
  {
    longlongget(a,a_ptr);
    longlongget(b,b_ptr);
  }
  return ((ulonglong) a < (ulonglong) b) ? -1 :
    ((ulonglong) a > (ulonglong) b) ? 1 : 0;
}

void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
  if (!table->db_low_byte_first)
  {
    to[0] = ptr[0];
    to[1] = ptr[1];
    to[2] = ptr[2];
    to[3] = ptr[3];
    to[4] = ptr[4];
    to[5] = ptr[5];
    to[6] = ptr[6];
    to[7] = ptr[7];
  }
  else
#endif
  {
    to[0] = ptr[7];
    to[1] = ptr[6];
    to[2] = ptr[5];
    to[3] = ptr[4];
    to[4] = ptr[3];
    to[5] = ptr[2];
    to[6] = ptr[1];
    to[7] = ptr[0];
  }
}


void Field_datetime::sql_type(String &res) const
{
4019
  res.set_ascii("datetime", 8);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4020 4021 4022 4023 4024 4025 4026 4027 4028
}

/****************************************************************************
** string type
** A string may be varchar or binary
****************************************************************************/

	/* Copy a string and fill with space */

4029 4030 4031 4032 4033
static bool use_conversion(CHARSET_INFO *cs1, CHARSET_INFO *cs2)
{
  return (cs1 != &my_charset_bin) && (cs2 != &my_charset_bin) && (cs1!=cs2);
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4034
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4035
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4036
  int error= 0;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4037 4038 4039
  char buff[80];
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
  /* Convert character set if nesessary */
4040
  if (use_conversion(cs, field_charset))
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4041 4042 4043 4044 4045
  { 
    tmpstr.copy(from, length, cs, field_charset);
    from= tmpstr.ptr();
    length=  tmpstr.length();
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4046 4047 4048 4049
  if (length <= field_length)
  {
    memcpy(ptr,from,length);
    if (length < field_length)
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4050 4051
      field_charset->cset->fill(field_charset,ptr+length,field_length-length,
				' ');
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4052 4053 4054 4055 4056 4057 4058
  }
  else
  {
    memcpy(ptr,from,field_length);
    if (current_thd->count_cuted_fields)
    {						// Check if we loosed some info
      const char *end=from+length;
4059
      from+= field_length;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4060 4061
      from+= field_charset->cset->scan(field_charset, from, end,
				       MY_SEQ_SPACES);
4062
      if (from != end)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4063
      {
4064
        set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
4065
	error=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4066 4067 4068
      }
    }
  }
4069
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4070 4071 4072
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4073
int Field_string::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4074 4075 4076 4077 4078
{
  char buff[MAX_FIELD_WIDTH],*end;
  int width=min(field_length,DBL_DIG+5);
  sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
  end=strcend(buff,' ');
4079
  return Field_string::store(buff,(uint) (end - buff), &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4080 4081 4082
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4083
int Field_string::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4084
{
4085 4086 4087
  char buff[64];
  int  l;
  CHARSET_INFO *cs=charset();
4088
  l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
4089
  return Field_string::store(buff,(uint)l,cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4090 4091 4092 4093 4094
}


double Field_string::val_real(void)
{
4095
  int not_used;
4096
  CHARSET_INFO *cs=charset();
4097
  return my_strntod(cs,ptr,field_length,(char**)0,&not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4098 4099 4100 4101 4102
}


longlong Field_string::val_int(void)
{
4103
  int not_used;
4104
  CHARSET_INFO *cs=charset();
4105
  return my_strntoll(cs,ptr,field_length,10,NULL,&not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4106 4107 4108 4109 4110 4111
}


String *Field_string::val_str(String *val_buffer __attribute__((unused)),
			      String *val_ptr)
{
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4112 4113
  uint length= field_charset->cset->lengthsp(field_charset, ptr, field_length);
  val_ptr->set((const char*) ptr, length, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4114 4115 4116 4117 4118 4119
  return val_ptr;
}


int Field_string::cmp(const char *a_ptr, const char *b_ptr)
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4120
  if (field_charset->strxfrm_multiply > 1)
4121 4122 4123 4124 4125
  {
    /*
      We have to remove end space to be able to compare multi-byte-characters
      like in latin_de 'ae' and 0xe4
    */
4126
    return field_charset->coll->strnncollsp(field_charset,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4127 4128
				      (const uchar*) a_ptr, field_length,
				      (const uchar*) b_ptr, field_length);
4129
  }
4130
  return field_charset->coll->strnncoll(field_charset,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
4131 4132
				  (const uchar*) a_ptr, field_length,
				  (const uchar*) b_ptr, field_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4133 4134 4135 4136
}

void Field_string::sort_string(char *to,uint length)
{
4137
  uint tmp=my_strnxfrm(field_charset,
4138 4139
                          (unsigned char *)to, length,
                          (unsigned char *) ptr, field_length);
4140 4141
  if (tmp < length)
    bzero(to + tmp, length - tmp);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4142 4143 4144 4145 4146
}


void Field_string::sql_type(String &res) const
{
4147
  CHARSET_INFO *cs=res.charset();
4148
  ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
4149
			    res.alloced_length(), "%s(%d)",
4150 4151 4152 4153
			    (field_length > 3 &&
			     (table->db_options_in_use &
			      HA_OPTION_PACK_RECORD) ?
			     "varchar" : "char"),
4154
			    (int) field_length / charset()->mbmaxlen);
4155
  res.length(length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183
}


char *Field_string::pack(char *to, const char *from, uint max_length)
{
  const char *end=from+min(field_length,max_length);
  uchar length;
  while (end > from && end[-1] == ' ')
    end--;
  *to= length=(uchar) (end-from);
  memcpy(to+1, from, (int) length);
  return to+1+length;
}


const char *Field_string::unpack(char *to, const char *from)
{
  uint length= (uint) (uchar) *from++;
  memcpy(to, from, (int) length);
  bfill(to+length, field_length - length, ' ');
  return from+length;
}


int Field_string::pack_cmp(const char *a, const char *b, uint length)
{
  uint a_length= (uint) (uchar) *a++;
  uint b_length= (uint) (uchar) *b++;
4184 4185 4186
  return my_strnncoll(field_charset,
		      (const uchar*)a,a_length,
		      (const uchar*)b,b_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4187 4188 4189
}


4190 4191 4192 4193 4194 4195 4196
int Field_string::pack_cmp(const char *b, uint length)
{
  uint b_length= (uint) (uchar) *b++;
  char *end= ptr + field_length;
  while (end > ptr && end[-1] == ' ')
    end--;
  uint a_length = (uint) (end - ptr);
4197 4198 4199
  return my_strnncoll(field_charset,
		     (const uchar*)ptr,a_length,
		     (const uchar*)b, b_length);
4200 4201 4202
}


4203
uint Field_string::packed_col_length(const char *data_ptr, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4204
{
4205
  if (length > 255)
4206
    return uint2korr(data_ptr)+2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4207
  else
4208
    return (uint) ((uchar) *data_ptr)+1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4209 4210 4211 4212
}

uint Field_string::max_packed_col_length(uint max_length)
{
4213
  return (max_length > 255 ? 2 : 1)+max_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4214 4215 4216 4217 4218 4219 4220 4221
}


/****************************************************************************
** VARCHAR type  (Not available for the end user yet)
****************************************************************************/


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4222
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4223
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4224
  int error= 0;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4225 4226 4227
  char buff[80];
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
  /* Convert character set if nesessary */
4228
  if (use_conversion(cs, field_charset))
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4229 4230 4231 4232 4233
  { 
    tmpstr.copy(from, length, cs, field_charset);
    from= tmpstr.ptr();
    length=  tmpstr.length();
  }
4234
  if (length > field_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4235 4236
  {
    length=field_length;
4237
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4238
    error= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4239
  }
4240 4241
  memcpy(ptr+2,from,length);
  int2store(ptr, length);
4242
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4243 4244 4245
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4246
int Field_varstring::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4247 4248 4249 4250 4251
{
  char buff[MAX_FIELD_WIDTH],*end;
  int width=min(field_length,DBL_DIG+5);
  sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
  end=strcend(buff,' ');
4252
  return Field_varstring::store(buff,(uint) (end - buff), &my_charset_bin);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4253 4254 4255
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4256
int Field_varstring::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4257
{
4258 4259 4260
  char buff[64];
  int  l;
  CHARSET_INFO *cs=charset();
4261
  l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
4262
  return Field_varstring::store(buff,(uint)l,cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4263 4264 4265 4266 4267
}


double Field_varstring::val_real(void)
{
4268
  int not_used;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4269
  uint length=uint2korr(ptr)+2;
4270
  CHARSET_INFO *cs=charset();
4271
  return my_strntod(cs,ptr+2,length,(char**)0, &not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4272 4273 4274 4275 4276
}


longlong Field_varstring::val_int(void)
{
4277
  int not_used;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4278
  uint length=uint2korr(ptr)+2;
4279
  CHARSET_INFO *cs=charset();
4280
  return my_strntoll(cs,ptr+2,length,10,NULL, &not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4281 4282 4283 4284 4285 4286 4287
}


String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
				 String *val_ptr)
{
  uint length=uint2korr(ptr);
4288
  val_ptr->set((const char*) ptr+2,length,field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4289 4290 4291 4292 4293 4294 4295 4296 4297
  return val_ptr;
}


int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
{
  uint a_length=uint2korr(a_ptr);
  uint b_length=uint2korr(b_ptr);
  int diff;
4298
  diff=my_strnncoll(field_charset,
4299 4300
		      (const uchar*)a_ptr+2,min(a_length,b_length),
		      (const uchar*)b_ptr+2,min(a_length,b_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4301 4302 4303 4304 4305 4306
  return diff ? diff : (int) (a_length - b_length);
}

void Field_varstring::sort_string(char *to,uint length)
{
  uint tot_length=uint2korr(ptr);
4307
  tot_length=my_strnxfrm(field_charset,
4308 4309
                             (unsigned char *) to, length,
                             (unsigned char *)ptr+2, tot_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4310 4311 4312 4313 4314 4315 4316
  if (tot_length < length)
    bzero(to+tot_length,length-tot_length);
}


void Field_varstring::sql_type(String &res) const
{
4317
  CHARSET_INFO *cs=res.charset();
4318
  ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
4319
			     res.alloced_length(),"varchar(%u)",
4320
			     field_length / charset()->mbmaxlen);
4321
  res.length(length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4322 4323 4324 4325
}

char *Field_varstring::pack(char *to, const char *from, uint max_length)
{
4326
  uint length=uint2korr(from);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4327 4328
  if (length > max_length)
    length=max_length;
4329
  *to++= (char) (length & 255);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4330
  if (max_length > 255)
4331
    *to++= (char) (length >> 8);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371
  if (length)
    memcpy(to, from+2, length);
  return to+length;
}


const char *Field_varstring::unpack(char *to, const char *from)
{
  uint length;
  if (field_length > 255)
  {
    length= (uint) (uchar) (*to= *from++);
    to[1]=0;
  }
  else
  {
    length=uint2korr(from);
    to[0] = *from++;
    to[1] = *from++;
  }
  if (length)
    memcpy(to+2, from, length);
  return from+length;
}


int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
{
  uint a_length;
  uint b_length;
  if (key_length > 255)
  {
    a_length=uint2korr(a); a+=2;
    b_length=uint2korr(b); b+=2;
  }
  else
  {
    a_length= (uint) (uchar) *a++;
    b_length= (uint) (uchar) *b++;
  }
4372 4373 4374
  return my_strnncoll(field_charset,
		     (const uchar *)a,a_length,
		     (const uchar *)b,b_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4375 4376
}

4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389
int Field_varstring::pack_cmp(const char *b, uint key_length)
{
  char *a=ptr+2;
  uint a_length=uint2korr(ptr);
  uint b_length;
  if (key_length > 255)
  {
    b_length=uint2korr(b); b+=2;
  }
  else
  {
    b_length= (uint) (uchar) *b++;
  }
4390 4391 4392
  return my_strnncoll(field_charset,
		     (const uchar *)a,a_length,
		     (const uchar *)b,b_length);
4393 4394
}

4395
uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4396
{
4397
  if (length > 255)
4398
    return uint2korr(data_ptr)+2;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4399
  else
4400
    return (uint) ((uchar) *data_ptr)+1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4401 4402 4403 4404
}

uint Field_varstring::max_packed_col_length(uint max_length)
{
4405
  return (max_length > 255 ? 2 : 1)+max_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4406 4407
}

4408 4409
void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
				    imagetype type)
4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422
{
  length-= HA_KEY_BLOB_LENGTH;
  uint f_length=uint2korr(ptr);
  if (f_length > length)
    f_length= length;
  int2store(buff,length);
  memcpy(buff+2,ptr+2,length);
#ifdef HAVE_purify
  if (f_length < length)
    bzero(buff+2+f_length, (length-f_length));
#endif
}

4423
void Field_varstring::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
4424 4425
{
  length=uint2korr(buff);			// Real length is here
4426
  (void) Field_varstring::store(buff+2, length, cs);
4427 4428 4429 4430
}



bk@work.mysql.com's avatar
bk@work.mysql.com committed
4431 4432 4433 4434 4435 4436
/****************************************************************************
** blob type
** A blob is saved as a length and a pointer. The length is stored in the
** packlength slot and may be from 1-4.
****************************************************************************/

4437
Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4438 4439
		       enum utype unireg_check_arg, const char *field_name_arg,
		       struct st_table *table_arg,uint blob_pack_length,
4440
		       CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4441 4442
  :Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
	     null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
4443
	     table_arg, cs),
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
4444
   geom_flag(true), packlength(blob_pack_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4445 4446 4447 4448 4449 4450 4451
{
  flags|= BLOB_FLAG;
  if (table)
    table->blob_fields++;
}


4452
void Field_blob::store_length(uint32 number)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4453 4454 4455 4456 4457 4458
{
  switch (packlength) {
  case 1:
    if (number > 255)
    {
      number=255;
4459
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4460 4461 4462 4463 4464 4465 4466
    }
    ptr[0]= (uchar) number;
    break;
  case 2:
    if (number > (uint16) ~0)
    {
      number= (uint16) ~0;
4467
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478
    }
#ifdef WORDS_BIGENDIAN
    if (table->db_low_byte_first)
    {
      int2store(ptr,(unsigned short) number);
    }
    else
#endif
      shortstore(ptr,(unsigned short) number);
    break;
  case 3:
4479
    if (number > (uint32) (1L << 24))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4480
    {
4481
      number= (uint32) (1L << 24)-1L;
4482
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498
    }
    int3store(ptr,number);
    break;
  case 4:
#ifdef WORDS_BIGENDIAN
    if (table->db_low_byte_first)
    {
      int4store(ptr,number);
    }
    else
#endif
      longstore(ptr,number);
  }
}


4499
uint32 Field_blob::get_length(const char *pos)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4500 4501 4502
{
  switch (packlength) {
  case 1:
4503
    return (uint32) (uchar) pos[0];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4504 4505 4506 4507 4508 4509 4510 4511 4512
  case 2:
    {
      uint16 tmp;
#ifdef WORDS_BIGENDIAN
      if (table->db_low_byte_first)
	tmp=sint2korr(pos);
      else
#endif
	shortget(tmp,pos);
4513
      return (uint32) tmp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4514 4515
    }
  case 3:
4516
    return (uint32) uint3korr(pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4517 4518 4519 4520 4521 4522 4523 4524 4525
  case 4:
    {
      uint32 tmp;
#ifdef WORDS_BIGENDIAN
      if (table->db_low_byte_first)
	tmp=uint4korr(pos);
      else
#endif
	longget(tmp,pos);
4526
      return (uint32) tmp;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4527 4528 4529 4530 4531 4532
    }
  }
  return 0;					// Impossible
}


bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4533
int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4534
{
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4535
  if (!length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4536 4537 4538 4539 4540
  {
    bzero(ptr,Field_blob::pack_length());
  }
  else
  {
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4541 4542 4543
    char buff[80];
    String tmpstr(buff,sizeof(buff), &my_charset_bin);
    /* Convert character set if nesessary */
4544
    if (use_conversion(cs, field_charset))
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4545 4546 4547 4548 4549
    { 
      tmpstr.copy(from, length, cs, field_charset);
      from= tmpstr.ptr();
      length=  tmpstr.length();
    }
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4550 4551
    Field_blob::store_length(length);
    if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4552
    {						// Must make a copy
4553 4554
      if (from != value.ptr())			// For valgrind
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4555 4556
	value.copy(from,length,charset());
	from=value.ptr();
4557
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4558 4559 4560
    }
    bmove(ptr+packlength,(char*) &from,sizeof(char*));
  }
4561
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4562 4563 4564
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4565
int Field_blob::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4566
{
4567 4568 4569
  CHARSET_INFO *cs=charset();
  value.set(nr, 2, cs);
  return Field_blob::store(value.ptr(),(uint) value.length(), cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4570 4571 4572
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4573
int Field_blob::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4574
{
4575 4576 4577
  CHARSET_INFO *cs=charset();
  value.set(nr, cs);
  return Field_blob::store(value.ptr(), (uint) value.length(), cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4578 4579 4580 4581 4582
}


double Field_blob::val_real(void)
{
4583
  int not_used;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4584 4585 4586 4587
  char *blob;
  memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
  if (!blob)
    return 0.0;
4588
  uint32 length=get_length(ptr);
4589
  CHARSET_INFO *cs=charset();
4590
  return my_strntod(cs,blob,length,(char**)0, &not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4591 4592 4593 4594 4595
}


longlong Field_blob::val_int(void)
{
4596
  int not_used;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4597 4598 4599 4600
  char *blob;
  memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
  if (!blob)
    return 0;
4601
  uint32 length=get_length(ptr);
4602
  return my_strntoll(charset(),blob,length,10,NULL,&not_used);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4603 4604 4605 4606 4607 4608 4609 4610 4611
}


String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
			    String *val_ptr)
{
  char *blob;
  memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
  if (!blob)
4612
    val_ptr->set("",0,charset());	// A bit safer than ->length(0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4613
  else
4614
    val_ptr->set((const char*) blob,get_length(ptr),charset());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4615 4616 4617 4618
  return val_ptr;
}


4619 4620
int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
		    uint32 b_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4621
{
4622 4623 4624
  int diff=my_strnncoll(field_charset,
			(const uchar*)a,min(a_length,b_length),
			(const uchar*)b,min(a_length,b_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651
  return diff ? diff : (int) (a_length - b_length);
}


int Field_blob::cmp(const char *a_ptr, const char *b_ptr)
{
  char *blob1,*blob2;
  memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
  memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
  return Field_blob::cmp(blob1,get_length(a_ptr),
			 blob2,get_length(b_ptr));
}


int Field_blob::cmp_offset(uint row_offset)
{
  return Field_blob::cmp(ptr,ptr+row_offset);
}


int Field_blob::cmp_binary_offset(uint row_offset)
{
  return cmp_binary(ptr, ptr+row_offset);
}


int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
4652
			   uint32 max_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4653 4654 4655
{
  char *a,*b;
  uint diff;
4656
  uint32 a_length,b_length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671
  memcpy_fixed(&a,a_ptr+packlength,sizeof(char*));
  memcpy_fixed(&b,b_ptr+packlength,sizeof(char*));
  a_length=get_length(a_ptr);
  if (a_length > max_length)
    a_length=max_length;
  b_length=get_length(b_ptr);
  if (b_length > max_length)
    b_length=max_length;
  diff=memcmp(a,b,min(a_length,b_length));
  return diff ? diff : (int) (a_length - b_length);
}


/* The following is used only when comparing a key */

4672
void Field_blob::get_key_image(char *buff,uint length,
4673
			       CHARSET_INFO *cs, imagetype type)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4674
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4675 4676
  length-= HA_KEY_BLOB_LENGTH;
  uint32 blob_length= get_length(ptr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4677
  char *blob;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4678 4679

  if (type == itMBR)
4680
  {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4681
    if (!blob_length)
4682
      return;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4683
    get_ptr(&blob);
4684 4685 4686

    MBR mbr;
    Geometry gobj;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
4687
    gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE);
4688 4689 4690 4691 4692 4693 4694 4695
    gobj.get_mbr(&mbr);
    float8store(buff,    mbr.xmin);
    float8store(buff+8,  mbr.xmax);
    float8store(buff+16, mbr.ymin);
    float8store(buff+24, mbr.ymax);
    return;
  }

4696
  if ((uint32) length > blob_length)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
4697
  {
4698 4699 4700 4701
    /*
      Must clear this as we do a memcmp in opt_range.cc to detect
      identical keys
    */
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
4702
    bzero(buff+2+blob_length, (length-blob_length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4703
    length=(uint) blob_length;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
4704
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4705 4706 4707 4708 4709
  int2store(buff,length);
  get_ptr(&blob);
  memcpy(buff+2,blob,length);
}

4710
void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4711 4712
{
  length=uint2korr(buff);
4713
  (void) Field_blob::store(buff+2,length,cs);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4714 4715
}

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
4716

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
  char *blob1;
  uint blob_length=get_length(ptr);
  max_key_length-=2;
  memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
  return Field_blob::cmp(blob1,min(blob_length, max_key_length),
			 (char*) key_ptr+2,uint2korr(key_ptr));
}

int Field_blob::key_cmp(const byte *a,const byte *b)
{
  return Field_blob::cmp((char*) a+2,uint2korr(a),
			 (char*) b+2,uint2korr(b));
}


void Field_blob::sort_string(char *to,uint length)
{
  char *blob;
  uint blob_length=get_length();
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4738

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4739 4740 4741 4742 4743
  if (!blob_length)
    bzero(to,length);
  else
  {
    memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
4744 4745 4746 4747
    
    blob_length=my_strnxfrm(field_charset,
                            (unsigned char *)to, length, 
                            (unsigned char *)blob, blob_length);
4748 4749
    if (blob_length < length)
      bzero(to+blob_length, length-blob_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4750 4751 4752 4753 4754 4755 4756
  }
}


void Field_blob::sql_type(String &res) const
{
  const char *str;
4757
  uint length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4758
  switch (packlength) {
4759 4760 4761 4762 4763
  default: str="tiny"; length=4; break;
  case 2:  str="";     length=0; break;
  case 3:  str="medium"; length= 6; break;
  case 4:  str="long";  length=4; break;
  }
4764
  res.set_ascii(str,length);
4765
  if (charset() == &my_charset_bin)
4766 4767 4768 4769
    res.append("blob");
  else
  {
    res.append("text");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4770 4771 4772 4773
  }
}


4774 4775 4776 4777
char *Field_blob::pack(char *to, const char *from, uint max_length)
{
  char *save=ptr;
  ptr=(char*) from;
4778
  uint32 length=get_length();			// Length of from string
4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800
  if (length > max_length)
  {
    ptr=to;
    length=max_length;
    store_length(length);			// Store max length
    ptr=(char*) from;
  }
  else
    memcpy(to,from,packlength);			// Copy length
  if (length)
  {
    get_ptr((char**) &from);
    memcpy(to+packlength, from,length);
  }
  ptr=save;					// Restore org row pointer
  return to+packlength+length;
}


const char *Field_blob::unpack(char *to, const char *from)
{
  memcpy(to,from,packlength);
4801
  uint32 length=get_length(from);
4802 4803 4804 4805 4806 4807 4808 4809
  from+=packlength;
  if (length)
    memcpy_fixed(to+packlength, &from, sizeof(from));
  else
    bzero(to+packlength,sizeof(from));
  return from+length;
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825
/* Keys for blobs are like keys on varchars */

int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
{
  uint a_length;
  uint b_length;
  if (key_length > 255)
  {
    a_length=uint2korr(a); a+=2;
    b_length=uint2korr(b); b+=2;
  }
  else
  {
    a_length= (uint) (uchar) *a++;
    b_length= (uint) (uchar) *b++;
  }
4826 4827 4828
  return my_strnncoll(field_charset,
		     (const uchar *)a,a_length,
		     (const uchar *)b,b_length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4829 4830
}

4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848

int Field_blob::pack_cmp(const char *b, uint key_length)
{
  char *a;
  memcpy_fixed(&a,ptr+packlength,sizeof(char*));
  if (!a)
    return key_length > 0 ? -1 : 0;
  uint a_length=get_length(ptr);
  uint b_length;

  if (key_length > 255)
  {
    b_length=uint2korr(b); b+=2;
  }
  else
  {
    b_length= (uint) (uchar) *b++;
  }
4849 4850 4851
  return my_strnncoll(field_charset,
		     (const uchar *)a,a_length,
		     (const uchar *)b,b_length);
4852 4853
}

4854
/* Create a packed key that will be used for storage from a MySQL row */
4855

bk@work.mysql.com's avatar
bk@work.mysql.com committed
4856 4857
char *Field_blob::pack_key(char *to, const char *from, uint max_length)
{
4858 4859
  char *save=ptr;
  ptr=(char*) from;
4860
  uint32 length=get_length();			// Length of from string
4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880
  if (length > max_length)
    length=max_length;
  *to++= (uchar) length;
  if (max_length > 255)				// 2 byte length
    *to++= (uchar) (length >> 8);
  if (length)
  {
    get_ptr((char**) &from);
    memcpy(to, from, length);
  }
  ptr=save;					// Restore org row pointer
  return to+length;
}

/* Create a packed key that will be used for storage from a MySQL key */

char *Field_blob::pack_key_from_key_image(char *to, const char *from,
					  uint max_length)
{
  uint length=uint2korr(from);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4881 4882
  if (length > max_length)
    length=max_length;
4883
  *to++= (char) (length & 255);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4884
  if (max_length > 255)
4885
    *to++= (char) (length >> 8);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
4886 4887 4888 4889 4890
  if (length)
    memcpy(to, from+2, length);
  return to+length;
}

4891
uint Field_blob::packed_col_length(const char *data_ptr, uint length)
4892 4893
{
  if (length > 255)
4894
    return uint2korr(data_ptr)+2;
4895
  else
4896
    return (uint) ((uchar) *data_ptr)+1;
4897 4898 4899 4900 4901 4902
}

uint Field_blob::max_packed_col_length(uint max_length)
{
  return (max_length > 255 ? 2 : 1)+max_length;
}
4903

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931

void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
			       imagetype type)
{
  length-= HA_KEY_BLOB_LENGTH;
  ulong blob_length= get_length(ptr);
  char *blob;
  get_ptr(&blob);

  MBR mbr;
  Geometry gobj;
  gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE);
  gobj.get_mbr(&mbr);
  float8store(buff, mbr.xmin);
  float8store(buff + 8, mbr.xmax);
  float8store(buff + 16, mbr.ymin);
  float8store(buff + 24, mbr.ymax);
  return;
}


void Field_geom::set_key_image(char *buff, uint length, CHARSET_INFO *cs)
{
  Field_blob::set_key_image(buff, length, cs);
}

void Field_geom::sql_type(String &res) const
{
4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958
  CHARSET_INFO *cs= &my_charset_latin1;
  switch (geom_type)
  {
    case GEOM_POINT:
     res.set("point", 5, cs);
     break;
    case GEOM_LINESTRING:
     res.set("linestring", 10, cs);
     break;
    case GEOM_POLYGON:
     res.set("polygon", 7, cs);
     break;
    case GEOM_MULTIPOINT:
     res.set("multipoint", 10, cs);
     break;
    case GEOM_MULTILINESTRING:
     res.set("multilinestring", 15, cs);
     break;
    case GEOM_MULTIPOLYGON:
     res.set("multipolygon", 12, cs);
     break;
    case GEOM_GEOMETRYCOLLECTION:
     res.set("geometrycollection", 18, cs);
     break;
    default:
     res.set("geometry", 8, cs);
  }
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987
}


int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
{
  if (!length)
  {
    bzero(ptr, Field_blob::pack_length());
  }
  else
  {
    // Should check given WKB
    if (length < 4 + 1 + 4 + 8 + 8)		// SRID + WKB_HEADER + X + Y
      return 1;
    uint32 wkb_type= uint4korr(from + 5);
    if (wkb_type < 1 || wkb_type > 7)
      return 1;
    Field_blob::store_length(length);
    if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
    {						// Must make a copy
      value.copy(from, length, cs);
      from= value.ptr();
    }
    bmove(ptr + packlength, (char*) &from, sizeof(char*));
  }
  return 0;
}


bk@work.mysql.com's avatar
bk@work.mysql.com committed
4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047
/****************************************************************************
** enum type.
** This is a string which only can have a selection of different values.
** If one uses this string in a number context one gets the type number.
****************************************************************************/

enum ha_base_keytype Field_enum::key_type() const
{
  switch (packlength) {
  default: return HA_KEYTYPE_BINARY;
  case 2: return HA_KEYTYPE_USHORT_INT;
  case 3: return HA_KEYTYPE_UINT24;
  case 4: return HA_KEYTYPE_ULONG_INT;
  case 8: return HA_KEYTYPE_ULONGLONG;
  }
}

void Field_enum::store_type(ulonglong value)
{
  switch (packlength) {
  case 1: ptr[0]= (uchar) value;  break;
  case 2:
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int2store(ptr,(unsigned short) value);
  }
  else
#endif
    shortstore(ptr,(unsigned short) value);
  break;
  case 3: int3store(ptr,(long) value); break;
  case 4:
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int4store(ptr,value);
  }
  else
#endif
    longstore(ptr,(long) value);
  break;
  case 8:
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
    int8store(ptr,value);
  }
  else
#endif
    longlongstore(ptr,value); break;
  }
}


/*
** Note. Storing a empty string in a enum field gives a warning
** (if there isn't a empty value in the enum)
*/

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5048
int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5049
{
5050
  int err= 0;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
5051 5052 5053
  char buff[80];
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
  /* Convert character set if nesessary */
5054
  if (use_conversion(cs, field_charset))
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
5055 5056 5057 5058 5059
  { 
    tmpstr.copy(from, length, cs, field_charset);
    from= tmpstr.ptr();
    length=  tmpstr.length();
  }
5060 5061 5062 5063 5064

  /* Remove end space */
  while (length > 0 && my_isspace(system_charset_info,from[length-1]))
    length--;
  uint tmp=find_type(typelib, from, length, 0);
5065
  if (!tmp)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5066
  {
5067
    if (length < 6)			// Can't be more than 99999 enums
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5068
    {
5069
      /* This is for reading numbers with LOAD DATA INFILE */
5070
      char *end;
5071 5072
      tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
      if (err || end != from+length || tmp > typelib->count)
5073 5074
      {
	tmp=0;
5075
	set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
5076
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5077 5078
    }
    else
5079
      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5080
  }
5081
  store_type((ulonglong) tmp);
5082
  return err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5083 5084 5085
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5086
int Field_enum::store(double nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5087
{
5088
  return Field_enum::store((longlong) nr);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5089 5090 5091
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5092
int Field_enum::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5093
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5094
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5095 5096
  if ((uint) nr > typelib->count || nr == 0)
  {
5097
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5098
    nr=0;
5099
    error=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5100 5101
  }
  store_type((ulonglong) (uint) nr);
5102
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164
}


double Field_enum::val_real(void)
{
  return (double) Field_enum::val_int();
}


longlong Field_enum::val_int(void)
{
  switch (packlength) {
  case 1:
    return (longlong) (uchar) ptr[0];
  case 2:
    {
      uint16 tmp;
#ifdef WORDS_BIGENDIAN
      if (table->db_low_byte_first)
	tmp=sint2korr(ptr);
      else
#endif
	shortget(tmp,ptr);
      return (longlong) tmp;
    }
  case 3:
    return (longlong) uint3korr(ptr);
  case 4:
    {
      uint32 tmp;
#ifdef WORDS_BIGENDIAN
      if (table->db_low_byte_first)
	tmp=uint4korr(ptr);
      else
#endif
	longget(tmp,ptr);
      return (longlong) tmp;
    }
  case 8:
    {
      longlong tmp;
#ifdef WORDS_BIGENDIAN
      if (table->db_low_byte_first)
	tmp=sint8korr(ptr);
      else
#endif
	longlongget(tmp,ptr);
      return tmp;
    }
  }
  return 0;					// impossible
}


String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
			    String *val_ptr)
{
  uint tmp=(uint) Field_enum::val_int();
  if (!tmp || tmp > typelib->count)
    val_ptr->length(0);
  else
    val_ptr->set((const char*) typelib->type_names[tmp-1],
5165
		 (uint) strlen(typelib->type_names[tmp-1]),
5166
		 field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202
  return val_ptr;
}

int Field_enum::cmp(const char *a_ptr, const char *b_ptr)
{
  char *old=ptr;
  ptr=(char*) a_ptr;
  ulonglong a=Field_enum::val_int();
  ptr=(char*) b_ptr;
  ulonglong b=Field_enum::val_int();
  ptr=old;
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}

void Field_enum::sort_string(char *to,uint length __attribute__((unused)))
{
  ulonglong value=Field_enum::val_int();
  to+=packlength-1;
  for (uint i=0 ; i < packlength ; i++)
  {
    *to-- = (uchar) (value & 255);
    value>>=8;
  }
}


void Field_enum::sql_type(String &res) const
{
  res.length(0);
  res.append("enum(");

  bool flag=0;
  for (const char **pos=typelib->type_names; *pos ; pos++)
  {
    if (flag)
      res.append(',');
5203
    append_unescaped(&res, *pos, strlen(*pos));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5204 5205 5206 5207 5208 5209
    flag=1;
  }
  res.append(')');
}


5210 5211 5212 5213 5214 5215 5216 5217
/*
   set type.
   This is a string which can have a collection of different values.
   Each string value is separated with a ','.
   For example "One,two,five"
   If one uses this string in a number context one gets the bits as a longlong
   number.
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5218 5219


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5220
int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5221
{
5222
  bool set_warning= 0;
5223
  int err= 0;
5224 5225
  char *not_used;
  uint not_used2;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
5226 5227 5228
  char buff[80];
  String tmpstr(buff,sizeof(buff), &my_charset_bin);
  /* Convert character set if nesessary */
5229
  if (use_conversion(cs, field_charset))
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
5230 5231 5232 5233 5234
  { 
    tmpstr.copy(from, length, cs, field_charset);
    from= tmpstr.ptr();
    length=  tmpstr.length();
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
5235 5236
  ulonglong tmp= find_set(typelib, from, length, &not_used, &not_used2,
			  &set_warning);
5237 5238 5239
  if (!tmp && length && length < 22)
  {
    /* This is for reading numbers with LOAD DATA INFILE */
5240
    char *end;
5241 5242
    tmp=my_strntoull(cs,from,length,10,&end,&err);
    if (err || end != from+length ||
5243
	tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
5244
    {
5245
      tmp=0;      
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
5246 5247 5248 5249 5250 5251 5252 5253
      THD *thd= current_thd;
      if (thd->count_cuted_fields)
      {
	thd->cuted_fields++;
	push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
			    ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
			    field_name, 0);
      }
5254
    }
5255 5256
  }
  store_type(tmp);
5257
  return err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5258 5259 5260
}


monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5261
int Field_set::store(longlong nr)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5262
{
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
5263
  int error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5264 5265 5266
  if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
				    (longlong) 1))
  {
5267 5268
    nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);    
    set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
5269
    error=1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5270 5271
  }
  store_type((ulonglong) nr);
5272
  return error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289
}


String *Field_set::val_str(String *val_buffer,
			   String *val_ptr __attribute__((unused)))
{
  ulonglong tmp=(ulonglong) Field_enum::val_int();
  uint bitnr=0;

  val_buffer->length(0);
  while (tmp && bitnr < (uint) typelib->count)
  {
    if (tmp & 1)
    {
      if (val_buffer->length())
	val_buffer->append(field_separator);
      String str(typelib->type_names[bitnr],
5290
		 (uint) strlen(typelib->type_names[bitnr]),
5291
		 field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310
      val_buffer->append(str);
    }
    tmp>>=1;
    bitnr++;
  }
  return val_buffer;
}


void Field_set::sql_type(String &res) const
{
  res.length(0);
  res.append("set(");

  bool flag=0;
  for (const char **pos=typelib->type_names; *pos ; pos++)
  {
    if (flag)
      res.append(',');
5311
    append_unescaped(&res, *pos, strlen(*pos));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5312 5313 5314 5315 5316 5317 5318 5319 5320
    flag=1;
  }
  res.append(')');
}

/* returns 1 if the fields are equally defined */

bool Field::eq_def(Field *field)
{
5321
  if (real_type() != field->real_type() || charset() != field->charset() ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5322 5323 5324 5325 5326 5327 5328 5329 5330 5331
      pack_length() != field->pack_length())
    return 0;
  return 1;
}

bool Field_enum::eq_def(Field *field)
{
  if (!Field::eq_def(field))
    return 0;
  TYPELIB *from_lib=((Field_enum*) field)->typelib;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
5332

bk@work.mysql.com's avatar
bk@work.mysql.com committed
5333 5334 5335
  if (typelib->count < from_lib->count)
    return 0;
  for (uint i=0 ; i < from_lib->count ; i++)
5336 5337
    if (my_strcasecmp(field_charset,
                      typelib->type_names[i],from_lib->type_names[i]))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5338 5339 5340 5341 5342
      return 0;
  return 1;
}

bool Field_num::eq_def(Field *field)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
5343
{
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359
  if (!Field::eq_def(field))
    return 0;
  Field_num *from_num= (Field_num*) field;

  if (unsigned_flag != from_num->unsigned_flag ||
      zerofill && !from_num->zerofill && !zero_pack() ||
      dec != from_num->dec)
    return 0;
  return 1;
}


/*****************************************************************************
** Handling of field and create_field
*****************************************************************************/

5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379
void create_field::create_length_to_internal_length(void)
{
  switch (sql_type)
  {
    case MYSQL_TYPE_TINY_BLOB:
    case MYSQL_TYPE_MEDIUM_BLOB:
    case MYSQL_TYPE_LONG_BLOB:
    case MYSQL_TYPE_BLOB:
    case MYSQL_TYPE_VAR_STRING:
    case MYSQL_TYPE_STRING:
      length*= charset->mbmaxlen;
      pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ?
				    FIELD_TYPE_STRING : sql_type, length);
      break;
    default:
      /* do nothing */
      break;
  }
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
5380
/*
5381
  Make a field from the .frm file info
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404
*/

uint32 calc_pack_length(enum_field_types type,uint32 length)
{
  switch (type) {
  case FIELD_TYPE_STRING:
  case FIELD_TYPE_DECIMAL: return (length);
  case FIELD_TYPE_VAR_STRING: return (length+2);
  case FIELD_TYPE_YEAR:
  case FIELD_TYPE_TINY	: return 1;
  case FIELD_TYPE_SHORT : return 2;
  case FIELD_TYPE_INT24:
  case FIELD_TYPE_NEWDATE:
  case FIELD_TYPE_TIME:   return 3;
  case FIELD_TYPE_TIMESTAMP:
  case FIELD_TYPE_DATE:
  case FIELD_TYPE_LONG	: return 4;
  case FIELD_TYPE_FLOAT : return sizeof(float);
  case FIELD_TYPE_DOUBLE: return sizeof(double);
  case FIELD_TYPE_DATETIME:
  case FIELD_TYPE_LONGLONG: return 8;	/* Don't crash if no longlong */
  case FIELD_TYPE_NULL	: return 0;
  case FIELD_TYPE_TINY_BLOB:	return 1+portable_sizeof_char_ptr;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
5405
  case FIELD_TYPE_BLOB:		return 2+portable_sizeof_char_ptr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5406 5407
  case FIELD_TYPE_MEDIUM_BLOB:	return 3+portable_sizeof_char_ptr;
  case FIELD_TYPE_LONG_BLOB:	return 4+portable_sizeof_char_ptr;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
5408
  case FIELD_TYPE_GEOMETRY:	return 4+portable_sizeof_char_ptr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5409 5410
  case FIELD_TYPE_SET:
  case FIELD_TYPE_ENUM: abort(); return 0;	// This shouldn't happen
5411
  default: return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430
  }
  return 0;					// This shouldn't happen
}


uint pack_length_to_packflag(uint type)
{
  switch (type) {
    case 1: return f_settype((uint) FIELD_TYPE_TINY);
    case 2: return f_settype((uint) FIELD_TYPE_SHORT);
    case 3: return f_settype((uint) FIELD_TYPE_INT24);
    case 4: return f_settype((uint) FIELD_TYPE_LONG);
    case 8: return f_settype((uint) FIELD_TYPE_LONGLONG);
  }
  return 0;					// This shouldn't happen
}


Field *make_field(char *ptr, uint32 field_length,
5431
		  uchar *null_pos, uchar null_bit,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5432
		  uint pack_flag,
5433
		  enum_field_types field_type,
5434
		  CHARSET_INFO *field_charset,
5435
		  Field::geometry_type geom_type,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449
		  Field::utype unireg_check,
		  TYPELIB *interval,
		  const char *field_name,
		  struct st_table *table)
{
  if (!f_maybe_null(pack_flag))
  {
    null_pos=0;
    null_bit=0;
  }
  if (f_is_alpha(pack_flag))
  {
    if (!f_is_packed(pack_flag))
      return new Field_string(ptr,field_length,null_pos,null_bit,
5450
			      unireg_check, field_name, table, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5451 5452 5453 5454 5455

    uint pack_length=calc_pack_length((enum_field_types)
				      f_packtype(pack_flag),
				      field_length);

5456 5457
    if (f_is_geom(pack_flag))
      return new Field_geom(ptr,null_pos,null_bit,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5458
			    unireg_check, field_name, table,
5459
			    pack_length, geom_type);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5460 5461 5462
    if (f_is_blob(pack_flag))
      return new Field_blob(ptr,null_pos,null_bit,
			    unireg_check, field_name, table,
hf@deer.mysql.r18.ru's avatar
hf@deer.mysql.r18.ru committed
5463
			    pack_length, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5464 5465 5466 5467 5468
    if (interval)
    {
      if (f_is_enum(pack_flag))
	return new Field_enum(ptr,field_length,null_pos,null_bit,
				  unireg_check, field_name, table,
5469
				  pack_length, interval, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5470 5471 5472
      else
	return new Field_set(ptr,field_length,null_pos,null_bit,
			     unireg_check, field_name, table,
5473
			     pack_length, interval, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5474 5475 5476
    }
  }

5477
  switch (field_type) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522
  case FIELD_TYPE_DECIMAL:
    return new Field_decimal(ptr,field_length,null_pos,null_bit,
			     unireg_check, field_name, table,
			     f_decimals(pack_flag),
			     f_is_zerofill(pack_flag) != 0,
			     f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_FLOAT:
    return new Field_float(ptr,field_length,null_pos,null_bit,
			   unireg_check, field_name, table,
			   f_decimals(pack_flag),
			   f_is_zerofill(pack_flag) != 0,
			   f_is_dec(pack_flag)== 0);
  case FIELD_TYPE_DOUBLE:
    return new Field_double(ptr,field_length,null_pos,null_bit,
			    unireg_check, field_name, table,
			    f_decimals(pack_flag),
			    f_is_zerofill(pack_flag) != 0,
			    f_is_dec(pack_flag)== 0);
  case FIELD_TYPE_TINY:
    return new Field_tiny(ptr,field_length,null_pos,null_bit,
			  unireg_check, field_name, table,
			  f_is_zerofill(pack_flag) != 0,
			  f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_SHORT:
    return new Field_short(ptr,field_length,null_pos,null_bit,
			   unireg_check, field_name, table,
			   f_is_zerofill(pack_flag) != 0,
			   f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_INT24:
    return new Field_medium(ptr,field_length,null_pos,null_bit,
			    unireg_check, field_name, table,
			    f_is_zerofill(pack_flag) != 0,
			    f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_LONG:
    return new Field_long(ptr,field_length,null_pos,null_bit,
			   unireg_check, field_name, table,
			   f_is_zerofill(pack_flag) != 0,
			   f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_LONGLONG:
    return new Field_longlong(ptr,field_length,null_pos,null_bit,
			      unireg_check, field_name, table,
			      f_is_zerofill(pack_flag) != 0,
			      f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_TIMESTAMP:
    return new Field_timestamp(ptr,field_length,
5523
			       unireg_check, field_name, table, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5524 5525 5526 5527 5528
  case FIELD_TYPE_YEAR:
    return new Field_year(ptr,field_length,null_pos,null_bit,
			  unireg_check, field_name, table);
  case FIELD_TYPE_DATE:
    return new Field_date(ptr,null_pos,null_bit,
5529
			  unireg_check, field_name, table, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5530 5531
  case FIELD_TYPE_NEWDATE:
    return new Field_newdate(ptr,null_pos,null_bit,
5532
			     unireg_check, field_name, table, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5533 5534
  case FIELD_TYPE_TIME:
    return new Field_time(ptr,null_pos,null_bit,
5535
			  unireg_check, field_name, table, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5536 5537
  case FIELD_TYPE_DATETIME:
    return new Field_datetime(ptr,null_pos,null_bit,
5538
			      unireg_check, field_name, table, field_charset);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5539
  case FIELD_TYPE_NULL:
5540
    return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
5541 5542
  default:					// Impossible (Wrong version)
    break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5543
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
5544
  return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5545 5546 5547 5548 5549
}


/* Create a field suitable for create of table */

5550
create_field::create_field(Field *old_field,Field *orig_field)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5551 5552 5553 5554 5555 5556 5557 5558
{
  field=      old_field;
  field_name=change=old_field->field_name;
  length=     old_field->field_length;
  flags=      old_field->flags;
  unireg_check=old_field->unireg_check;
  pack_length=old_field->pack_length();
  sql_type=   old_field->real_type();
5559 5560
  charset=    old_field->charset();		// May be NULL ptr
  comment=    old_field->comment;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5561 5562 5563 5564 5565

  /* Fix if the original table had 4 byte pointer blobs */
  if (flags & BLOB_FLAG)
    pack_length= (pack_length- old_field->table->blob_ptr_size +
		  portable_sizeof_char_ptr);
5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576

  switch (sql_type)
  {
    case FIELD_TYPE_BLOB:
      switch (pack_length - portable_sizeof_char_ptr)
      {
        case  1: sql_type= FIELD_TYPE_TINY_BLOB; break;
        case  2: sql_type= FIELD_TYPE_BLOB; break;
        case  3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
        default: sql_type= FIELD_TYPE_LONG_BLOB; break;
      }
5577
      length /= charset->mbmaxlen;		// QQ: Probably not needed
5578 5579 5580 5581 5582 5583 5584 5585 5586
      break;
    case FIELD_TYPE_STRING:
    case FIELD_TYPE_VAR_STRING:
      length /= charset->mbmaxlen;
      break;
    default:
      break;
  }
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5587 5588 5589
  decimals= old_field->decimals();
  if (sql_type == FIELD_TYPE_STRING)
  {
5590
    /* Change CHAR -> VARCHAR if dynamic record length */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5591 5592 5593 5594 5595 5596 5597
    sql_type=old_field->type();
    decimals=0;
  }
  if (flags & (ENUM_FLAG | SET_FLAG))
    interval= ((Field_enum*) old_field)->typelib;
  else
    interval=0;
5598
  def=0;
5599 5600 5601
  if (!old_field->is_real_null() && ! (flags & BLOB_FLAG) &&
      old_field->type() != FIELD_TYPE_TIMESTAMP && old_field->ptr &&
      orig_field)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5602 5603
  {
    char buff[MAX_FIELD_WIDTH],*pos;
5604
    String tmp(buff,sizeof(buff), charset);
5605

5606
    /* Get the value from default_values */
5607
    my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2);
5608
    orig_field->move_field(diff);		// Points now at default_values
5609
    bool is_null=orig_field->is_real_null();
5610
    orig_field->val_str(&tmp,&tmp);
5611
    orig_field->move_field(-diff);		// Back to record[0]
5612
    if (!is_null)
5613 5614 5615
    {
      pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1);
      pos[tmp.length()]=0;
5616
      def=new Item_string(pos,tmp.length(), charset);
5617
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5618
  }
5619 5620 5621 5622
  if (sql_type == FIELD_TYPE_GEOMETRY)
  {
    geom_type= ((Field_geom*)old_field)->geom_type;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
5623
}
5624 5625 5626 5627 5628 5629


/* Warning handling */
void Field::set_warning(const uint level, const uint code)
{
  THD *thd= current_thd;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
5630 5631 5632 5633 5634 5635
  if (thd->count_cuted_fields)
  {
    thd->cuted_fields++;
    push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level, 
			code, ER(code), field_name, thd->row_count);
  }
5636
}