~drizzle-trunk/drizzle/development

813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
31
#include "config.h"
873.1.3 by Jay Pipes
Fixed PCRE header and include order.
32
33
#include "drizzled/temporal_format.h"
34
#include "drizzled/temporal.h"
35
873.1.1 by Jay Pipes
Fixes the Field_date class to not allow any invalid input at
36
#include <string.h>
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
37
#include PCRE_HEADER
38
39
#include <string>
873.1.1 by Jay Pipes
Fixes the Field_date class to not allow any invalid input at
40
#include <vector>
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
41
42
using namespace std;
859.1.6 by Monty Taylor
Fix for multi-versions of PCRE thing.
43
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
44
namespace drizzled
45
{
46
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
47
TemporalFormat::TemporalFormat(const char *pattern) :
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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)
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
58
, _nsecond_part_index(0)
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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;
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
73
74
  int32_t match_vector[OUT_VECTOR_SIZE]; /**< Stores match substring indexes */
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
75
  
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
76
  /* Make sure we've got no junk in the match_vector. */
77
  memset(match_vector, 0, sizeof(match_vector));
78
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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 */
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
86
                            , match_vector
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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)
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
107
                              + (_usecond_part_index > 1 ? 1 : 0)
108
                              + (_nsecond_part_index > 1 ? 1 : 0)
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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 */
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
114
  string copy_data(data, data_len);
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
136
    to->_months= atoi(copy_data.substr(month_start, month_len).c_str());
137
  }
138
  if (_day_part_index > 1)
139
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
142
    to->_days= atoi(copy_data.substr(day_start, day_len).c_str());
143
  }
144
  if (_hour_part_index > 1)
145
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
148
    to->_hours= atoi(copy_data.substr(hour_start, hour_len).c_str());
149
  }
150
  if (_minute_part_index > 1)
151
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
154
    to->_minutes= atoi(copy_data.substr(minute_start, minute_len).c_str());
155
  }
156
  if (_second_part_index > 1)
157
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
160
    to->_seconds= atoi(copy_data.substr(second_start, second_len).c_str());
161
  }
162
  if (_usecond_part_index > 1)
163
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
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;
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
180
  }
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
181
  if (_nsecond_part_index > 1)
182
  {
1252.1.1 by Jay Pipes
Fixes LP Bug #500031:
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];
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
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;
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
199
  }
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
200
  return true;
201
}
202
203
907.1.7 by Jay Pipes
Merged in remove-timezone work
204
#define COUNT_KNOWN_FORMATS 19
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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;
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
216
  int32_t nsecond_part_index;
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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
{
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
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 */
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
234
, {"^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})$", 1, 2, 3, 4, 5, 6, 0, 0} /* YYYYMMDDHHmmSS */
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
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 */
907.1.7 by Jay Pipes
Merged in remove-timezone work
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 */
1377.8.27 by Paweł Blokus
tests for to_decimal methods
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 */ 
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
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 */
873.1.1 by Jay Pipes
Fixes the Field_date class to not allow any invalid input at
245
, {"^(\\d{4})[-/.]*(\\d{1,2})[-/.]*(\\d{1,2})$", 1, 2, 3, 0, 0, 0, 0, 0} /* YYYY[-/.][M]M[-/.][D]D */
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
246
, {"^(\\d{2}):*(\\d{2}):*(\\d{2})\\.(\\d{1,6})$", 0, 0, 0, 1, 2, 3, 4, 0} /* HHmmSS.uuuuuu, HH:mm:SS.uuuuuu */
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
247
, {"^(\\d{1,2}):*(\\d{2}):*(\\d{2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]HmmSS, [H]H:mm:SS */
873.1.1 by Jay Pipes
Fixes the Field_date class to not allow any invalid input at
248
, {"^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$", 0, 0, 0, 1, 2, 3, 0, 0} /* [H]H:[m]m:[S]S */
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
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 */
813.1.19 by Jay Pipes
To remain in compatibility with MySQL, added ability to interpret
251
, {"^(\\d{1,2})\\.(\\d{1,6})$", 0, 0, 0, 0, 0, 1, 2, 0} /* [S]S.uuuuuu */
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
252
};
253
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
254
vector<TemporalFormat *> known_datetime_formats;
255
vector<TemporalFormat *> known_date_formats;
256
vector<TemporalFormat *> known_time_formats;
257
vector<TemporalFormat *> all_temporal_formats;
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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 */
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
267
  TemporalFormat *tmp;
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
268
  struct temporal_format_args current_format_args;
269
  
2020 by Brian Aker
This takes time and turns it into a fuzzy type so that we can do
270
  for (int32_t x= 0; x < COUNT_KNOWN_FORMATS; ++x)
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
271
  {
272
    current_format_args= __format_args[x];
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
273
    tmp= new TemporalFormat(current_format_args.pattern);
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
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);
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
281
    tmp->set_nsecond_part_index(current_format_args.nsecond_part_index);
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
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); 
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
288
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
289
    if (current_format_args.year_part_index > 0) /* A date must have a year */
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
290
    {
291
      known_datetime_formats.push_back(tmp);
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
292
      if (current_format_args.second_part_index == 0) /* A time must have seconds. */
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
293
        known_date_formats.push_back(tmp);
294
    }
2019 by Brian Aker
Merge in change to allow for SQL Server style patterns.
295
813.1.12 by Jay Pipes
Fixes for SECOND() function to use new Temporal system. Because
296
    if (current_format_args.second_part_index > 0) /* A time must have seconds, but may not have minutes or hours */
2019 by Brian Aker
Merge in change to allow for SQL Server style patterns.
297
      known_time_formats.push_back(tmp);
813.1.2 by Jay Pipes
First function cleanup for temporal handling: YEAR()
298
  }
299
  return true;
300
}
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
301
302
/** Free all allocated temporal formats */
303
void deinit_temporal_formats()
304
{
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
305
  vector<TemporalFormat *>::iterator p= all_temporal_formats.begin();
1089.1.3 by Brian Aker
Fix protobuf to release memory. Add in assert() for wrong column usage. Fix
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
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
316
317
} /* end namespace drizzled */