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.
31
#include <string> /** C++ string class used */
36
#include "drizzled/global.h"
37
#include "drizzled/temporal_format.h"
38
#include "drizzled/temporal.h"
43
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)
56
/* Make sure we've got no junk in the match_vector. */
57
memset(_match_vector, 0, sizeof(_match_vector));
59
/* Compile our regular expression */
60
_re= pcre_compile(pattern
61
, 0 /* Default options */
64
, NULL /* Use default character table */
68
bool TemporalFormat::matches(const char *data, size_t data_len, Temporal *to)
73
/* Simply check the subject against the compiled regular expression */
74
int32_t result= pcre_exec(_re
75
, NULL /* No extra data */
78
, 0 /* Start at offset 0 of subject...*/
79
, 0 /* Default options */
87
case PCRE_ERROR_NOMATCH:
88
return false; /* No match, just return false */
95
int32_t expected_match_count= (_year_part_index > 1 ? 1 : 0)
96
+ (_month_part_index > 1 ? 1 : 0)
97
+ (_day_part_index > 1 ? 1 : 0)
98
+ (_hour_part_index > 1 ? 1 : 0)
99
+ (_minute_part_index > 1 ? 1 : 0)
100
+ (_second_part_index > 1 ? 1 : 0)
101
+ 1; /* Add one for the entire match... */
102
if (result != expected_match_count)
105
/* C++ string class easy to use substr() method is very useful here */
106
std::string copy_data(data, data_len);
108
* OK, we have the expected substring matches, so grab
109
* the various temporal parts from the subject string
113
* TemporalFormatMatch is a friend class to Temporal, so
114
* we can access the temporal instance's protected data.
116
if (_year_part_index > 1)
118
size_t year_start= _match_vector[_year_part_index];
119
size_t year_len= _match_vector[_year_part_index + 1] - _match_vector[_year_part_index];
120
to->_years= atoi(copy_data.substr(year_start, year_len).c_str());
122
to->_years+= (to->_years >= DRIZZLE_YY_PART_YEAR ? 1900 : 2000);
124
if (_month_part_index > 1)
126
size_t month_start= _match_vector[_month_part_index];
127
size_t month_len= _match_vector[_month_part_index + 1] - _match_vector[_month_part_index];
128
to->_months= atoi(copy_data.substr(month_start, month_len).c_str());
130
if (_day_part_index > 1)
132
size_t day_start= _match_vector[_day_part_index];
133
size_t day_len= _match_vector[_day_part_index + 1] - _match_vector[_day_part_index];
134
to->_days= atoi(copy_data.substr(day_start, day_len).c_str());
136
if (_hour_part_index > 1)
138
size_t hour_start= _match_vector[_hour_part_index];
139
size_t hour_len= _match_vector[_hour_part_index + 1] - _match_vector[_hour_part_index];
140
to->_hours= atoi(copy_data.substr(hour_start, hour_len).c_str());
142
if (_minute_part_index > 1)
144
size_t minute_start= _match_vector[_minute_part_index];
145
size_t minute_len= _match_vector[_minute_part_index + 1] - _match_vector[_minute_part_index];
146
to->_minutes= atoi(copy_data.substr(minute_start, minute_len).c_str());
148
if (_second_part_index > 1)
150
size_t second_start= _match_vector[_second_part_index];
151
size_t second_len= _match_vector[_second_part_index + 1] - _match_vector[_second_part_index];
152
to->_seconds= atoi(copy_data.substr(second_start, second_len).c_str());
154
if (_usecond_part_index > 1)
156
size_t usecond_start= _match_vector[_usecond_part_index];
157
size_t usecond_len= _match_vector[_usecond_part_index + 1] - _match_vector[_usecond_part_index];
158
to->_useconds= atoi(copy_data.substr(usecond_start, usecond_len).c_str());
163
} /* end namespace drizzled */
165
#define COUNT_KNOWN_FORMATS 12
167
struct temporal_format_args
170
int32_t year_part_index;
171
int32_t month_part_index;
172
int32_t day_part_index;
173
int32_t hour_part_index;
174
int32_t minute_part_index;
175
int32_t second_part_index;
176
int32_t usecond_part_index;
180
* A collection of all known format strings.
184
* IMPORTANT: Make sure TIMESTAMP and DATETIME formats precede DATE formats and TIME formats,
185
* as the matching functionality matches on the first hit.
189
* Remember to increment COUNT_KNOWN_FORMATS when you add a known format!
191
static struct temporal_format_args __format_args[COUNT_KNOWN_FORMATS]=
193
{"(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})", 1, 2, 3, 4, 5, 6, 0} /* YYYYMMDDHHmmSS */
194
, {"(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})\\.(\\d{6})", 1, 2, 3, 4, 5, 6, 7} /* YYYYMMDDHHmmSS.uuuuuu */
195
, {"(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})[T|\\s+](\\d{2}):(\\d{2}):(\\d{2})", 1, 2, 3, 4, 5, 6, 0} /* YYYY-MM-DD[T]HH:mm:SS, YYYY.MM.DD[T]HH:mm:SS, YYYY/MM/DD[T]HH:mm:SS*/
196
, {"(\\d{4})[-/.](\\d{1,2})[-/.](\\d{1,2})", 1, 2, 3, 0, 0, 0, 0} /* YYYY-MM-DD, YYYY.MM.DD, YYYY/MM/DD */
197
, {"(\\d{4})(\\d{2})(\\d{2})", 1, 2, 3, 0, 0, 0, 0} /* YYYYMMDD */
198
, {"(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{4})", 3, 1, 2, 0, 0, 0, 0} /* MM[-/.]DD[-/.]YYYY (US common format)*/
199
, {"(\\d{2})[-/.]*(\\d{2})[-/.]*(\\d{2})", 1, 2, 3, 0, 0, 0, 0} /* YY[-/.]MM[-/.]DD */
200
, {"(\\d{2})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})", 1, 2, 3, 0, 0, 0, 0} /* YY[-/.][M]M[-/.][D]D */
201
, {"(\\d{2}):*(\\d{2}):*(\\d{2})\\.(\\d{6})", 0, 0, 0, 1, 2, 3, 4} /* HHmmSS.uuuuuu, HH:mm:SS.uuuuuu */
202
, {"(\\d{1,2}):*(\\d{2}):*(\\d{2})", 0, 0, 0, 1, 2, 3, 0} /* [H]HmmSS, [H]H:mm:SS */
203
, {"(\\d{1,2}):*(\\d{2})", 0, 0, 0, 0, 1, 2, 0} /* [m]mSS, [m]m:SS */
204
, {"(\\d{1,2})", 0, 0, 0, 0, 0, 1, 0} /* SS, S */
207
std::vector<drizzled::TemporalFormat*> known_datetime_formats;
208
std::vector<drizzled::TemporalFormat*> known_date_formats;
209
std::vector<drizzled::TemporalFormat*> known_time_formats;
212
* We allocate and initialize all known date/time formats.
214
* @TODO Cut down calls to new. Allocate as a block...
216
bool init_temporal_formats()
218
/* Compile all the regular expressions for the datetime formats */
219
drizzled::TemporalFormat *tmp;
220
struct temporal_format_args current_format_args;
223
for (x= 0; x<COUNT_KNOWN_FORMATS; ++x)
225
current_format_args= __format_args[x];
226
tmp= new drizzled::TemporalFormat(current_format_args.pattern);
227
tmp->set_year_part_index(current_format_args.year_part_index);
228
tmp->set_month_part_index(current_format_args.month_part_index);
229
tmp->set_day_part_index(current_format_args.day_part_index);
230
tmp->set_hour_part_index(current_format_args.hour_part_index);
231
tmp->set_minute_part_index(current_format_args.minute_part_index);
232
tmp->set_second_part_index(current_format_args.second_part_index);
233
tmp->set_usecond_part_index(current_format_args.usecond_part_index);
235
if (current_format_args.year_part_index > 0)
237
known_datetime_formats.push_back(tmp);
238
if (current_format_args.hour_part_index == 0)
239
known_date_formats.push_back(tmp);
241
if (current_format_args.hour_part_index > 0)
242
if (current_format_args.year_part_index == 0)
243
known_time_formats.push_back(tmp);