~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/temporal_format.cc

  • Committer: Monty Taylor
  • Date: 2008-09-16 00:00:48 UTC
  • mto: This revision was merged to the branch mainline in revision 391.
  • Revision ID: monty@inaugust.com-20080916000048-3rvrv3gv9l0ad3gs
Fixed copyright headers in drizzled/

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
 
 *  Authors:
7
 
 *
8
 
 *  Jay Pipes <jay.pipes@sun.com>
9
 
 *
10
 
 *  This program is free software; you can redistribute it and/or modify
11
 
 *  it under the terms of the GNU General Public License as published by
12
 
 *  the Free Software Foundation; either version 2 of the License, or
13
 
 *  (at your option) any later version.
14
 
 *
15
 
 *  This program is distributed in the hope that it will be useful,
16
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
 *  GNU General Public License for more details.
19
 
 *
20
 
 *  You should have received a copy of the GNU General Public License
21
 
 *  along with this program; if not, write to the Free Software
22
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23
 
 */
24
 
 
25
 
/**
26
 
 * @file 
27
 
 *
28
 
 * Implementation of the server's date and time string matching utility.
29
 
 */
30
 
 
31
 
#include "config.h"
32
 
 
33
 
#include "drizzled/temporal_format.h"
34
 
#include "drizzled/temporal.h"
35
 
 
36
 
#include <string.h>
37
 
#include PCRE_HEADER
38
 
 
39
 
#include <string>
40
 
#include <vector>
41
 
 
42
 
using namespace std;
43
 
 
44
 
namespace drizzled
45
 
{
46
 
 
47
 
TemporalFormat::TemporalFormat(const char *pattern) :
48
 
  _pattern(pattern)
49
 
, _error_offset(0)
50
 
, _error(NULL)
51
 
, _year_part_index(0)
52
 
, _month_part_index(0)
53
 
, _day_part_index(0)
54
 
, _hour_part_index(0)
55
 
, _minute_part_index(0)
56
 
, _second_part_index(0)
57
 
, _usecond_part_index(0)
58
 
, _nsecond_part_index(0)
59
 
{
60
 
  /* Compile our regular expression */
61
 
  _re= pcre_compile(pattern
62
 
                    , 0 /* Default options */
63
 
                    , &_error
64
 
                    , &_error_offset
65
 
                    , NULL /* Use default character table */
66
 
                    );
67
 
}
68
 
 
69
 
bool TemporalFormat::matches(const char *data, size_t data_len, Temporal *to)
70
 
{
71
 
  if (! is_valid()) 
72
 
    return false;
73
 
 
74
 
  int32_t match_vector[OUT_VECTOR_SIZE]; /**< Stores match substring indexes */
75
 
  
76
 
  /* Make sure we've got no junk in the match_vector. */
77
 
  memset(match_vector, 0, sizeof(match_vector));
78
 
 
79
 
  /* Simply check the subject against the compiled regular expression */
80
 
  int32_t result= pcre_exec(_re
81
 
                            , NULL /* No extra data */
82
 
                            , data
83
 
                            , data_len
84
 
                            , 0 /* Start at offset 0 of subject...*/
85
 
                            , 0 /* Default options */
86
 
                            , match_vector
87
 
                            , OUT_VECTOR_SIZE
88
 
                            );
89
 
  if (result < 0)
90
 
  {
91
 
    switch (result)
92
 
    {
93
 
      case PCRE_ERROR_NOMATCH:
94
 
        return false; /* No match, just return false */
95
 
      default:
96
 
        return false;
97
 
    }
98
 
    return false;
99
 
  }
100
 
 
101
 
  int32_t expected_match_count= (_year_part_index > 1 ? 1 : 0)
102
 
                              + (_month_part_index > 1 ? 1 : 0)
103
 
                              + (_day_part_index > 1 ? 1 : 0)
104
 
                              + (_hour_part_index > 1 ? 1 : 0)
105
 
                              + (_minute_part_index > 1 ? 1 : 0)
106
 
                              + (_second_part_index > 1 ? 1 : 0)
107
 
                              + (_usecond_part_index > 1 ? 1 : 0)
108
 
                              + (_nsecond_part_index > 1 ? 1 : 0)
109
 
                              + 1; /* Add one for the entire match... */
110
 
  if (result != expected_match_count)
111
 
    return false;
112
 
 
113
 
  /* C++ string class easy to use substr() method is very useful here */
114
 
  string copy_data(data, data_len);
115
 
  /* 
116
 
   * OK, we have the expected substring matches, so grab
117
 
   * the various temporal parts from the subject string
118
 
   *
119
 
   * @note 
120
 
   *
121
 
   * TemporalFormatMatch is a friend class to Temporal, so
122
 
   * we can access the temporal instance's protected data.
123
 
   */
124
 
  if (_year_part_index > 1)
125
 
  {
126
 
    size_t year_start= match_vector[_year_part_index];
127
 
    size_t year_len= match_vector[_year_part_index + 1] - match_vector[_year_part_index];
128
 
    to->_years= atoi(copy_data.substr(year_start, year_len).c_str());
129
 
    if (year_len == 2)
130
 
      to->_years+= (to->_years >= DRIZZLE_YY_PART_YEAR ? 1900 : 2000);
131
 
  }
132
 
  if (_month_part_index > 1)
133
 
  {
134
 
    size_t month_start= match_vector[_month_part_index];
135
 
    size_t month_len= match_vector[_month_part_index + 1] - match_vector[_month_part_index];
136
 
    to->_months= atoi(copy_data.substr(month_start, month_len).c_str());
137
 
  }
138
 
  if (_day_part_index > 1)
139
 
  {
140
 
    size_t day_start= match_vector[_day_part_index];
141
 
    size_t day_len= match_vector[_day_part_index + 1] - match_vector[_day_part_index];
142
 
    to->_days= atoi(copy_data.substr(day_start, day_len).c_str());
143
 
  }
144
 
  if (_hour_part_index > 1)
145
 
  {
146
 
    size_t hour_start= match_vector[_hour_part_index];
147
 
    size_t hour_len= match_vector[_hour_part_index + 1] - match_vector[_hour_part_index];
148
 
    to->_hours= atoi(copy_data.substr(hour_start, hour_len).c_str());
149
 
  }
150
 
  if (_minute_part_index > 1)
151
 
  {
152
 
    size_t minute_start= match_vector[_minute_part_index];
153
 
    size_t minute_len= match_vector[_minute_part_index + 1] - match_vector[_minute_part_index];
154
 
    to->_minutes= atoi(copy_data.substr(minute_start, minute_len).c_str());
155
 
  }
156
 
  if (_second_part_index > 1)
157
 
  {
158
 
    size_t second_start= match_vector[_second_part_index];
159
 
    size_t second_len= match_vector[_second_part_index + 1] - match_vector[_second_part_index];
160
 
    to->_seconds= atoi(copy_data.substr(second_start, second_len).c_str());
161
 
  }
162
 
  if (_usecond_part_index > 1)
163
 
  {
164
 
    size_t usecond_start= match_vector[_usecond_part_index];
165
 
    size_t usecond_len= match_vector[_usecond_part_index + 1] - match_vector[_usecond_part_index];
166
 
    /* 
167
 
     * For microseconds, which are millionth of 1 second, 
168
 
     * we must ensure that we produce a correct result, 
169
 
     * even if < 6 places were specified.  For instance, if we get .1, 
170
 
     * we must produce 100000. .11 should produce 110000, etc.
171
 
     */
172
 
    uint32_t multiplier= 1;
173
 
    int32_t x= usecond_len;
174
 
    while (x < 6)
175
 
    {
176
 
      multiplier*= 10;
177
 
      ++x;
178
 
    }
179
 
    to->_useconds= atoi(copy_data.substr(usecond_start, usecond_len).c_str()) * multiplier;
180
 
  }
181
 
  if (_nsecond_part_index > 1)
182
 
  {
183
 
    size_t nsecond_start= match_vector[_nsecond_part_index];
184
 
    size_t nsecond_len= match_vector[_nsecond_part_index + 1] - match_vector[_nsecond_part_index];
185
 
    /* 
186
 
     * For nanoseconds, which are 1 billionth of a second, 
187
 
     * we must ensure that we produce a correct result, 
188
 
     * even if < 9 places were specified.  For instance, if we get .1, 
189
 
     * we must produce 100000000. .11 should produce 110000000, etc.
190
 
     */
191
 
    uint32_t multiplier= 1;
192
 
    int32_t x= nsecond_len;
193
 
    while (x < 9)
194
 
    {
195
 
      multiplier*= 10;
196
 
      ++x;
197
 
    }
198
 
    to->_nseconds= atoi(copy_data.substr(nsecond_start, nsecond_len).c_str()) * multiplier;
199
 
  }
200
 
  return true;
201
 
}
202
 
 
203
 
 
204
 
#define COUNT_KNOWN_FORMATS 19
205
 
 
206
 
struct temporal_format_args
207
 
{
208
 
  const char *pattern;
209
 
  int32_t year_part_index;
210
 
  int32_t month_part_index;
211
 
  int32_t day_part_index;
212
 
  int32_t hour_part_index;
213
 
  int32_t minute_part_index;
214
 
  int32_t second_part_index;
215
 
  int32_t usecond_part_index;
216
 
  int32_t nsecond_part_index;
217
 
};
218
 
 
219
 
/**
220
 
 * A collection of all known format strings.
221
 
 *
222
 
 * @note
223
 
 *
224
 
 * IMPORTANT: Make sure TIMESTAMP and DATETIME formats precede DATE formats and TIME formats, 
225
 
 * as the matching functionality matches on the first hit.
226
 
 *
227
 
 * @note 
228
 
 *
229
 
 * Remember to increment COUNT_KNOWN_FORMATS when you add a known format!
230
 
 */
231
 
static struct temporal_format_args __format_args[COUNT_KNOWN_FORMATS]= 
232
 
{
233
 
  {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})\\.(\\d{1,6})$", 1, 2, 3, 4, 5, 6, 7, 0} /* YYYYMMDDHHmmSS.uuuuuu */
234
 
, {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYYMMDDHHmmSS */
235
 
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{1,6})$", 1, 2, 3, 4, 5, 6, 7, 0} /* YYYY[/-.]MM[/-.]DD[T]HH:mm:SS.uuuuuu */
236
 
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYY[/-.][M]M[/-.][D]D[T]HH:mm:SS */
237
 
, {"^(\\d{2})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YY[/-.][M]M[/-.][D]D HH:mm:SS */
238
 
, {"^(\\d{2})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 0, 0, 0} /* YY[/-.][M]M[/-.][D]D HH:mm */
239
 
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[\\s+](\\d{2}):(\\d{2})$", 1, 2, 3, 4, 5, 0, 0, 0} /* YYYY[/-.][M]M[/-.][D]D HH:mm */
240
 
, {"^(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY-[M]M-[D]D, YYYY.[M]M.[D]D, YYYY/[M]M/[D]D */ 
241
 
, {"^(\\d{4})(\\d{2})(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYYMMDD */
242
 
, {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{4})$", 3, 1, 2, 0, 0, 0, 0, 0} /* MM[-/.]DD[-/.]YYYY (US common format)*/
243
 
, {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.]MM[-/.]DD */
244
 
, {"^(\\d{2})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.][M]M[-/.][D]D */
245
 
, {"^(\\d{4})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY[-/.][M]M[-/.][D]D */
246
 
, {"^(\\d{2}):*(\\d{2}):*(\\d{2})\\.(\\d{1,6})$", 0, 0, 0, 1, 2, 3, 4, 0} /* HHmmSS.uuuuuu, HH:mm:SS.uuuuuu */
247
 
, {"^(\\d{1,2}):*(\\d{2}):*(\\d{2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]HmmSS, [H]H:mm:SS */
248
 
, {"^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]H:[m]m:[S]S */
249
 
, {"^(\\d{1,2}):*(\\d{2})$", 0, 0, 0, 0, 1, 2, 0, 0} /* [m]mSS, [m]m:SS */
250
 
, {"^(\\d{1,2})$", 0, 0, 0, 0, 0, 1, 0, 0} /* SS, S */
251
 
, {"^(\\d{1,2})\\.(\\d{1,6})$", 0, 0, 0, 0, 0, 1, 2, 0} /* [S]S.uuuuuu */
252
 
};
253
 
 
254
 
vector<TemporalFormat *> known_datetime_formats;
255
 
vector<TemporalFormat *> known_date_formats;
256
 
vector<TemporalFormat *> known_time_formats;
257
 
vector<TemporalFormat *> all_temporal_formats;
258
 
 
259
 
/**
260
 
 * We allocate and initialize all known date/time formats.
261
 
 *
262
 
 * @TODO Cut down calls to new. Allocate as a block...
263
 
 */
264
 
bool init_temporal_formats()
265
 
{
266
 
  /* Compile all the regular expressions for the datetime formats */
267
 
  TemporalFormat *tmp;
268
 
  struct temporal_format_args current_format_args;
269
 
  
270
 
  for (int32_t x= 0; x < COUNT_KNOWN_FORMATS; ++x)
271
 
  {
272
 
    current_format_args= __format_args[x];
273
 
    tmp= new TemporalFormat(current_format_args.pattern);
274
 
    tmp->set_year_part_index(current_format_args.year_part_index);
275
 
    tmp->set_month_part_index(current_format_args.month_part_index);
276
 
    tmp->set_day_part_index(current_format_args.day_part_index);
277
 
    tmp->set_hour_part_index(current_format_args.hour_part_index);
278
 
    tmp->set_minute_part_index(current_format_args.minute_part_index);
279
 
    tmp->set_second_part_index(current_format_args.second_part_index);
280
 
    tmp->set_usecond_part_index(current_format_args.usecond_part_index);
281
 
    tmp->set_nsecond_part_index(current_format_args.nsecond_part_index);
282
 
    
283
 
    /* 
284
 
     * We store the pointer in all_temporal_formats because we 
285
 
     * delete pointers from that vector and only that vector
286
 
     */
287
 
    all_temporal_formats.push_back(tmp); 
288
 
 
289
 
    if (current_format_args.year_part_index > 0) /* A date must have a year */
290
 
    {
291
 
      known_datetime_formats.push_back(tmp);
292
 
      if (current_format_args.second_part_index == 0) /* A time must have seconds. */
293
 
        known_date_formats.push_back(tmp);
294
 
    }
295
 
 
296
 
    if (current_format_args.second_part_index > 0) /* A time must have seconds, but may not have minutes or hours */
297
 
      known_time_formats.push_back(tmp);
298
 
  }
299
 
  return true;
300
 
}
301
 
 
302
 
/** Free all allocated temporal formats */
303
 
void deinit_temporal_formats()
304
 
{
305
 
  vector<TemporalFormat *>::iterator p= all_temporal_formats.begin();
306
 
  while (p != all_temporal_formats.end())
307
 
  {
308
 
    delete *p;
309
 
    ++p;
310
 
  }
311
 
  known_date_formats.clear();
312
 
  known_datetime_formats.clear();
313
 
  known_time_formats.clear();
314
 
  all_temporal_formats.clear();
315
 
}
316
 
 
317
 
} /* end namespace drizzled */