1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
8
* Jay Pipes <jay.pipes@sun.com>
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.
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.
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
28
* Implementation of the server's date and time string matching utility.
33
#include "drizzled/temporal_format.h"
34
#include "drizzled/temporal.h"
36
#include <string> /** C++ string class used */
44
TemporalFormat::TemporalFormat(const char *pattern) :
49
, _month_part_index(0)
52
, _minute_part_index(0)
53
, _second_part_index(0)
54
, _usecond_part_index(0)
55
, _nsecond_part_index(0)
57
/* Compile our regular expression */
58
_re= pcre_compile(pattern
59
, 0 /* Default options */
62
, NULL /* Use default character table */
66
bool TemporalFormat::matches(const char *data, size_t data_len, Temporal *to)
71
int32_t match_vector[OUT_VECTOR_SIZE]; /**< Stores match substring indexes */
73
/* Make sure we've got no junk in the match_vector. */
74
memset(match_vector, 0, sizeof(match_vector));
76
/* Simply check the subject against the compiled regular expression */
77
int32_t result= pcre_exec(_re
78
, NULL /* No extra data */
81
, 0 /* Start at offset 0 of subject...*/
82
, 0 /* Default options */
90
case PCRE_ERROR_NOMATCH:
91
return false; /* No match, just return false */
98
int32_t expected_match_count= (_year_part_index > 1 ? 1 : 0)
99
+ (_month_part_index > 1 ? 1 : 0)
100
+ (_day_part_index > 1 ? 1 : 0)
101
+ (_hour_part_index > 1 ? 1 : 0)
102
+ (_minute_part_index > 1 ? 1 : 0)
103
+ (_second_part_index > 1 ? 1 : 0)
104
+ (_usecond_part_index > 1 ? 1 : 0)
105
+ (_nsecond_part_index > 1 ? 1 : 0)
106
+ 1; /* Add one for the entire match... */
107
if (result != expected_match_count)
110
/* C++ string class easy to use substr() method is very useful here */
111
std::string copy_data(data, data_len);
113
* OK, we have the expected substring matches, so grab
114
* the various temporal parts from the subject string
118
* TemporalFormatMatch is a friend class to Temporal, so
119
* we can access the temporal instance's protected data.
121
if (_year_part_index > 1)
123
size_t year_start= match_vector[_year_part_index];
124
size_t year_len= match_vector[_year_part_index + 1] - match_vector[_year_part_index];
125
to->_years= atoi(copy_data.substr(year_start, year_len).c_str());
127
to->_years+= (to->_years >= DRIZZLE_YY_PART_YEAR ? 1900 : 2000);
129
if (_month_part_index > 1)
131
size_t month_start= match_vector[_month_part_index];
132
size_t month_len= match_vector[_month_part_index + 1] - match_vector[_month_part_index];
133
to->_months= atoi(copy_data.substr(month_start, month_len).c_str());
135
if (_day_part_index > 1)
137
size_t day_start= match_vector[_day_part_index];
138
size_t day_len= match_vector[_day_part_index + 1] - match_vector[_day_part_index];
139
to->_days= atoi(copy_data.substr(day_start, day_len).c_str());
141
if (_hour_part_index > 1)
143
size_t hour_start= match_vector[_hour_part_index];
144
size_t hour_len= match_vector[_hour_part_index + 1] - match_vector[_hour_part_index];
145
to->_hours= atoi(copy_data.substr(hour_start, hour_len).c_str());
147
if (_minute_part_index > 1)
149
size_t minute_start= match_vector[_minute_part_index];
150
size_t minute_len= match_vector[_minute_part_index + 1] - match_vector[_minute_part_index];
151
to->_minutes= atoi(copy_data.substr(minute_start, minute_len).c_str());
153
if (_second_part_index > 1)
155
size_t second_start= match_vector[_second_part_index];
156
size_t second_len= match_vector[_second_part_index + 1] - match_vector[_second_part_index];
157
to->_seconds= atoi(copy_data.substr(second_start, second_len).c_str());
159
if (_usecond_part_index > 1)
161
size_t usecond_start= match_vector[_usecond_part_index];
162
size_t usecond_len= match_vector[_usecond_part_index + 1] - match_vector[_usecond_part_index];
164
* For microseconds, which are millionth of 1 second,
165
* we must ensure that we produce a correct result,
166
* even if < 6 places were specified. For instance, if we get .1,
167
* we must produce 100000. .11 should produce 110000, etc.
169
uint32_t multiplier= 1;
170
int32_t x= usecond_len;
176
to->_useconds= atoi(copy_data.substr(usecond_start, usecond_len).c_str()) * multiplier;
178
if (_nsecond_part_index > 1)
180
size_t nsecond_start= match_vector[_nsecond_part_index];
181
size_t nsecond_len= match_vector[_nsecond_part_index + 1] - match_vector[_nsecond_part_index];
183
* For nanoseconds, which are 1 billionth of a second,
184
* we must ensure that we produce a correct result,
185
* even if < 9 places were specified. For instance, if we get .1,
186
* we must produce 100000000. .11 should produce 110000000, etc.
188
uint32_t multiplier= 1;
189
int32_t x= nsecond_len;
195
to->_nseconds= atoi(copy_data.substr(nsecond_start, nsecond_len).c_str()) * multiplier;
200
} /* end namespace drizzled */
202
#define COUNT_KNOWN_FORMATS 19
204
struct temporal_format_args
207
int32_t year_part_index;
208
int32_t month_part_index;
209
int32_t day_part_index;
210
int32_t hour_part_index;
211
int32_t minute_part_index;
212
int32_t second_part_index;
213
int32_t usecond_part_index;
214
int32_t nsecond_part_index;
218
* A collection of all known format strings.
222
* IMPORTANT: Make sure TIMESTAMP and DATETIME formats precede DATE formats and TIME formats,
223
* as the matching functionality matches on the first hit.
227
* Remember to increment COUNT_KNOWN_FORMATS when you add a known format!
229
static struct temporal_format_args __format_args[COUNT_KNOWN_FORMATS]=
231
{"^(\\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 */
232
, {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYYMMDDHHmmSS */
233
, {"^(\\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 */
234
, {"^(\\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 */
235
, {"^(\\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 */
236
, {"^(\\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 */
237
, {"^(\\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 */
238
, {"^(\\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 */
239
, {"^(\\d{4})(\\d{2})(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYYMMDD */
240
, {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{4})$", 3, 1, 2, 0, 0, 0, 0, 0} /* MM[-/.]DD[-/.]YYYY (US common format)*/
241
, {"^(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.]MM[-/.]DD */
242
, {"^(\\d{2})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YY[-/.][M]M[-/.][D]D */
243
, {"^(\\d{4})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY[-/.][M]M[-/.][D]D */
244
, {"^(\\d{2}):*(\\d{2}):*(\\d{2})\\.(\\d{1,6})$", 0, 0, 0, 1, 2, 3, 4, 0} /* HHmmSS.uuuuuu, HH:mm:SS.uuuuuu */
245
, {"^(\\d{1,2}):*(\\d{2}):*(\\d{2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]HmmSS, [H]H:mm:SS */
246
, {"^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]H:[m]m:[S]S */
247
, {"^(\\d{1,2}):*(\\d{2})$", 0, 0, 0, 0, 1, 2, 0, 0} /* [m]mSS, [m]m:SS */
248
, {"^(\\d{1,2})$", 0, 0, 0, 0, 0, 1, 0, 0} /* SS, S */
249
, {"^(\\d{1,2})\\.(\\d{1,6})$", 0, 0, 0, 0, 0, 1, 2, 0} /* [S]S.uuuuuu */
252
std::vector<drizzled::TemporalFormat *> known_datetime_formats;
253
std::vector<drizzled::TemporalFormat *> known_date_formats;
254
std::vector<drizzled::TemporalFormat *> known_time_formats;
255
std::vector<drizzled::TemporalFormat *> all_temporal_formats;
258
* We allocate and initialize all known date/time formats.
260
* @TODO Cut down calls to new. Allocate as a block...
262
bool init_temporal_formats()
264
/* Compile all the regular expressions for the datetime formats */
265
drizzled::TemporalFormat *tmp;
266
struct temporal_format_args current_format_args;
269
for (x= 0; x<COUNT_KNOWN_FORMATS; ++x)
271
current_format_args= __format_args[x];
272
tmp= new drizzled::TemporalFormat(current_format_args.pattern);
273
tmp->set_year_part_index(current_format_args.year_part_index);
274
tmp->set_month_part_index(current_format_args.month_part_index);
275
tmp->set_day_part_index(current_format_args.day_part_index);
276
tmp->set_hour_part_index(current_format_args.hour_part_index);
277
tmp->set_minute_part_index(current_format_args.minute_part_index);
278
tmp->set_second_part_index(current_format_args.second_part_index);
279
tmp->set_usecond_part_index(current_format_args.usecond_part_index);
280
tmp->set_nsecond_part_index(current_format_args.nsecond_part_index);
283
* We store the pointer in all_temporal_formats because we
284
* delete pointers from that vector and only that vector
286
all_temporal_formats.push_back(tmp);
288
if (current_format_args.year_part_index > 0) /* A date must have a year */
290
known_datetime_formats.push_back(tmp);
291
if (current_format_args.second_part_index == 0) /* A time must have seconds. */
292
known_date_formats.push_back(tmp);
294
if (current_format_args.second_part_index > 0) /* A time must have seconds, but may not have minutes or hours */
295
if (current_format_args.year_part_index == 0) /* A time may not have a date part, and date parts must have a year */
296
known_time_formats.push_back(tmp);
301
/** Free all allocated temporal formats */
302
void deinit_temporal_formats()
304
std::vector<drizzled::TemporalFormat *>::iterator p= all_temporal_formats.begin();
305
while (p != all_temporal_formats.end())
310
known_date_formats.clear();
311
known_datetime_formats.clear();
312
known_time_formats.clear();
313
all_temporal_formats.clear();