~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/field/epoch.cc

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++ c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008 Sun Microsystems, Inc.
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
#include <config.h>
22
 
 
23
 
#include <boost/lexical_cast.hpp>
24
 
#include <drizzled/field/epoch.h>
25
 
#include <drizzled/error.h>
26
 
#include <drizzled/tztime.h>
27
 
#include <drizzled/table.h>
28
 
#include <drizzled/session.h>
29
 
#include <drizzled/current_session.h>
30
 
 
31
 
#include <math.h>
32
 
 
33
 
#include <sstream>
34
 
 
35
 
#include <drizzled/temporal.h>
36
 
 
37
 
namespace drizzled
38
 
{
39
 
 
40
 
namespace field
41
 
{
42
 
 
43
 
/**
44
 
  TIMESTAMP type holds datetime values in range from 1970-01-01 00:00:01 UTC to
45
 
  2038-01-01 00:00:00 UTC stored as number of seconds since Unix
46
 
  Epoch in UTC.
47
 
 
48
 
  Up to one of timestamps columns in the table can be automatically
49
 
  set on row update and/or have NOW() as default value.
50
 
  TABLE::timestamp_field points to Field object for such timestamp with
51
 
  auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
52
 
  field, and is used by handler code which performs updates required.
53
 
 
54
 
  Actually SQL-99 says that we should allow niladic functions (like NOW())
55
 
  as defaults for any field. Current limitations (only NOW() and only
56
 
  for one TIMESTAMP field) are because of restricted binary .frm format
57
 
  and should go away in the future.
58
 
 
59
 
  Also because of this limitation of binary .frm format we use 5 different
60
 
  unireg_check values with TIMESTAMP field to distinguish various cases of
61
 
  DEFAULT or ON UPDATE values. These values are:
62
 
 
63
 
  TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
64
 
    auto-set-on-update (or now() as default) in this table before, then this
65
 
    field has NOW() as default and is updated when row changes, else it is
66
 
    field which has 0 as default value and is not automatically updated.
67
 
  TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
68
 
    automatically (TIMESTAMP DEFAULT NOW())
69
 
  TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
70
 
    NOW() as default (but it may has 0 or some other const timestamp as
71
 
    default) (TIMESTAMP ON UPDATE NOW()).
72
 
  TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
73
 
    update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW())
74
 
  NONE - field which is not auto-set on update with some other than NOW()
75
 
    default value (TIMESTAMP DEFAULT 0).
76
 
 
77
 
  Note that TIMESTAMP_OLD_FIELDs are never created explicitly now, they are
78
 
  left only for preserving ability to read old tables. Such fields replaced
79
 
  with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is
80
 
  because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for
81
 
  "TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such
82
 
  specification too but ignored default value for first timestamp, which of
83
 
  course is non-standard.) In most cases user won't notice any change, only
84
 
  exception is different behavior of old/new timestamps during ALTER TABLE.
85
 
 */
86
 
  Epoch::Epoch(unsigned char *ptr_arg,
87
 
               unsigned char *null_ptr_arg,
88
 
               unsigned char null_bit_arg,
89
 
               enum utype unireg_check_arg,
90
 
               const char *field_name_arg,
91
 
               drizzled::TableShare *share) :
92
 
  Field_str(ptr_arg,
93
 
            MicroTimestamp::MAX_STRING_LENGTH - 1, /* no \0 */
94
 
            null_ptr_arg,
95
 
            null_bit_arg,
96
 
            field_name_arg,
97
 
            &my_charset_bin)
98
 
{
99
 
  unireg_check= unireg_check_arg;
100
 
  if (! share->getTimestampField() && unireg_check != NONE)
101
 
  {
102
 
    /* This timestamp has auto-update */
103
 
    share->setTimestampField(this);
104
 
    flags|= FUNCTION_DEFAULT_FLAG;
105
 
    if (unireg_check != TIMESTAMP_DN_FIELD)
106
 
      flags|= ON_UPDATE_NOW_FLAG;
107
 
  }
108
 
}
109
 
 
110
 
Epoch::Epoch(bool maybe_null_arg,
111
 
             const char *field_name_arg) :
112
 
  Field_str((unsigned char*) NULL,
113
 
            MicroTimestamp::MAX_STRING_LENGTH - 1, /* no \0 */
114
 
            maybe_null_arg ? (unsigned char*) "": 0,
115
 
            0,
116
 
            field_name_arg,
117
 
            &my_charset_bin)
118
 
{
119
 
  if (unireg_check != TIMESTAMP_DN_FIELD)
120
 
    flags|= ON_UPDATE_NOW_FLAG;
121
 
}
122
 
 
123
 
/**
124
 
  Get auto-set type for TIMESTAMP field.
125
 
 
126
 
  Returns value indicating during which operations this TIMESTAMP field
127
 
  should be auto-set to current timestamp.
128
 
*/
129
 
timestamp_auto_set_type Epoch::get_auto_set_type() const
130
 
{
131
 
  switch (unireg_check)
132
 
  {
133
 
  case TIMESTAMP_DN_FIELD:
134
 
    return TIMESTAMP_AUTO_SET_ON_INSERT;
135
 
  case TIMESTAMP_UN_FIELD:
136
 
    return TIMESTAMP_AUTO_SET_ON_UPDATE;
137
 
  case TIMESTAMP_OLD_FIELD:
138
 
    /*
139
 
      Although we can have several such columns in legacy tables this
140
 
      function should be called only for first of them (i.e. the one
141
 
      having auto-set property).
142
 
    */
143
 
    assert(getTable()->timestamp_field == this);
144
 
    /* Fall-through */
145
 
  case TIMESTAMP_DNUN_FIELD:
146
 
    return TIMESTAMP_AUTO_SET_ON_BOTH;
147
 
  default:
148
 
    /*
149
 
      Normally this function should not be called for TIMESTAMPs without
150
 
      auto-set property.
151
 
    */
152
 
    assert(0);
153
 
    return TIMESTAMP_NO_AUTO_SET;
154
 
  }
155
 
}
156
 
 
157
 
int Epoch::store(const char *from,
158
 
                 uint32_t len,
159
 
                 const CHARSET_INFO * const )
160
 
{
161
 
  Timestamp temporal;
162
 
 
163
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
164
 
 
165
 
  if (not temporal.from_string(from, (size_t) len))
166
 
  {
167
 
    my_error(ER_INVALID_TIMESTAMP_VALUE, MYF(ME_FATALERROR), from);
168
 
    return 1;
169
 
  }
170
 
 
171
 
  time_t tmp;
172
 
  temporal.to_time_t(tmp);
173
 
 
174
 
  uint64_t time_tmp= tmp;
175
 
  pack_num(time_tmp);
176
 
  return 0;
177
 
}
178
 
 
179
 
int Epoch::store(double from)
180
 
{
181
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
182
 
 
183
 
  uint64_t from_tmp= (uint64_t)from;
184
 
 
185
 
  Timestamp temporal;
186
 
  if (not temporal.from_int64_t(from_tmp))
187
 
  {
188
 
    /* Convert the integer to a string using boost::lexical_cast */
189
 
    std::string tmp(boost::lexical_cast<std::string>(from));
190
 
 
191
 
    my_error(ER_INVALID_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
192
 
    return 2;
193
 
  }
194
 
 
195
 
  time_t tmp;
196
 
  temporal.to_time_t(tmp);
197
 
 
198
 
  uint64_t tmp_micro= tmp;
199
 
  pack_num(tmp_micro);
200
 
 
201
 
  return 0;
202
 
}
203
 
 
204
 
int Epoch::store_decimal(const type::Decimal *value)
205
 
{
206
 
  double tmp;
207
 
  value->convert(tmp);
208
 
 
209
 
  return store(tmp);
210
 
}
211
 
 
212
 
int Epoch::store(int64_t from, bool)
213
 
{
214
 
  ASSERT_COLUMN_MARKED_FOR_WRITE;
215
 
 
216
 
  /* 
217
 
   * Try to create a DateTime from the supplied integer.  Throw an error
218
 
   * if unable to create a valid DateTime.  
219
 
   */
220
 
  Timestamp temporal;
221
 
  if (not temporal.from_int64_t(from))
222
 
  {
223
 
    /* Convert the integer to a string using boost::lexical_cast */
224
 
    std::string tmp(boost::lexical_cast<std::string>(from));
225
 
 
226
 
    my_error(ER_INVALID_TIMESTAMP_VALUE, MYF(ME_FATALERROR), tmp.c_str());
227
 
    return 2;
228
 
  }
229
 
 
230
 
  time_t tmp;
231
 
  temporal.to_time_t(tmp);
232
 
 
233
 
  uint64_t tmp64= tmp;
234
 
  pack_num(tmp64);
235
 
 
236
 
  return 0;
237
 
}
238
 
 
239
 
double Epoch::val_real(void) const
240
 
{
241
 
  return (double) Epoch::val_int();
242
 
}
243
 
 
244
 
int64_t Epoch::val_int(void) const
245
 
{
246
 
  uint64_t temp;
247
 
 
248
 
  ASSERT_COLUMN_MARKED_FOR_READ;
249
 
 
250
 
  unpack_num(temp);
251
 
 
252
 
  Timestamp temporal;
253
 
  (void) temporal.from_time_t((time_t) temp);
254
 
 
255
 
  /* We must convert into a "timestamp-formatted integer" ... */
256
 
  int64_t result;
257
 
  temporal.to_int64_t(&result);
258
 
  return result;
259
 
}
260
 
 
261
 
String *Epoch::val_str(String *val_buffer, String *) const
262
 
{
263
 
  uint64_t temp= 0;
264
 
  char *to;
265
 
  int to_len= field_length + 1;
266
 
 
267
 
  val_buffer->alloc(to_len);
268
 
  to= (char *) val_buffer->ptr();
269
 
 
270
 
  unpack_num(temp);
271
 
 
272
 
  val_buffer->set_charset(&my_charset_bin);     /* Safety */
273
 
 
274
 
  Timestamp temporal;
275
 
  (void) temporal.from_time_t((time_t) temp);
276
 
 
277
 
  int rlen;
278
 
  rlen= temporal.to_string(to, to_len);
279
 
  assert(rlen < to_len);
280
 
 
281
 
  val_buffer->length(rlen);
282
 
  return val_buffer;
283
 
}
284
 
 
285
 
bool Epoch::get_date(type::Time &ltime, uint32_t) const
286
 
{
287
 
  uint64_t temp;
288
 
  type::Time::epoch_t time_temp;
289
 
 
290
 
  unpack_num(temp);
291
 
  time_temp= temp;
292
 
  
293
 
  ltime.reset();
294
 
 
295
 
  ltime.store(time_temp);
296
 
 
297
 
  return 0;
298
 
}
299
 
 
300
 
bool Epoch::get_time(type::Time &ltime) const
301
 
{
302
 
  return Epoch::get_date(ltime, 0);
303
 
}
304
 
 
305
 
int Epoch::cmp(const unsigned char *a_ptr, const unsigned char *b_ptr)
306
 
{
307
 
  uint64_t a,b;
308
 
 
309
 
  unpack_num(a, a_ptr);
310
 
  unpack_num(b, b_ptr);
311
 
 
312
 
  return (a < b) ? -1 : (a > b) ? 1 : 0;
313
 
}
314
 
 
315
 
 
316
 
void Epoch::sort_string(unsigned char *to,uint32_t )
317
 
{
318
 
#ifdef WORDS_BIGENDIAN
319
 
  if (!getTable() || !getTable()->getShare()->db_low_byte_first)
320
 
  {
321
 
    to[0] = ptr[0];
322
 
    to[1] = ptr[1];
323
 
    to[2] = ptr[2];
324
 
    to[3] = ptr[3];
325
 
    to[4] = ptr[4];
326
 
    to[5] = ptr[5];
327
 
    to[6] = ptr[6];
328
 
    to[7] = ptr[7];
329
 
  }
330
 
  else
331
 
#endif
332
 
  {
333
 
    to[0] = ptr[7];
334
 
    to[1] = ptr[6];
335
 
    to[2] = ptr[5];
336
 
    to[3] = ptr[4];
337
 
    to[4] = ptr[3];
338
 
    to[5] = ptr[2];
339
 
    to[6] = ptr[1];
340
 
    to[7] = ptr[0];
341
 
  }
342
 
}
343
 
 
344
 
void Epoch::sql_type(String &res) const
345
 
{
346
 
  res.set_ascii(STRING_WITH_LEN("timestamp"));
347
 
}
348
 
 
349
 
void Epoch::set_time()
350
 
{
351
 
  Session *session= getTable() ? getTable()->in_use : current_session;
352
 
  time_t tmp= session->getCurrentTimestampEpoch();
353
 
 
354
 
  set_notnull();
355
 
  pack_num(static_cast<uint32_t>(tmp));
356
 
}
357
 
 
358
 
void Epoch::set_default()
359
 
{
360
 
  if (getTable()->timestamp_field == this &&
361
 
      unireg_check != TIMESTAMP_UN_FIELD)
362
 
  {
363
 
    set_time();
364
 
  }
365
 
  else
366
 
  {
367
 
    Field::set_default();
368
 
  }
369
 
}
370
 
 
371
 
long Epoch::get_timestamp(bool *null_value) const
372
 
{
373
 
  if ((*null_value= is_null()))
374
 
    return 0;
375
 
 
376
 
  uint64_t tmp;
377
 
  return unpack_num(tmp);
378
 
}
379
 
 
380
 
size_t Epoch::max_string_length()
381
 
{
382
 
  return sizeof(uint64_t);
383
 
}
384
 
 
385
 
} /* namespace field */
386
 
} /* namespace drizzled */