00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021 #include <drizzled/function/time/date_format.h>
00022 #include <drizzled/session.h>
00023 #include <drizzled/time_functions.h>
00024 #include <drizzled/internal/m_string.h>
00025 #include <drizzled/typelib.h>
00026
00027 #include <cstdio>
00028 #include <algorithm>
00029
00030 using namespace std;
00031
00032 namespace drizzled
00033 {
00034
00039 static bool make_date_time(Session &session,
00040 String *format, type::Time *l_time,
00041 type::timestamp_t type, String *str)
00042 {
00043 char intbuff[15];
00044 uint32_t hours_i;
00045 uint32_t weekday;
00046 ulong length;
00047 const char *ptr, *end;
00048 MY_LOCALE *locale= session.variables.lc_time_names;
00049
00050 str->length(0);
00051
00052 if (l_time->neg)
00053 str->append('-');
00054
00055 end= (ptr= format->c_ptr()) + format->length();
00056 for (; ptr != end ; ptr++)
00057 {
00058 if (*ptr != '%' || ptr+1 == end)
00059 str->append(*ptr);
00060 else
00061 {
00062 switch (*++ptr) {
00063 case 'M':
00064 if (!l_time->month)
00065 return 1;
00066 str->append(locale->month_names->type_names[l_time->month-1],
00067 strlen(locale->month_names->type_names[l_time->month-1]),
00068 system_charset_info);
00069 break;
00070 case 'b':
00071 if (!l_time->month)
00072 return 1;
00073 str->append(locale->ab_month_names->type_names[l_time->month-1],
00074 strlen(locale->ab_month_names->type_names[l_time->month-1]),
00075 system_charset_info);
00076 break;
00077 case 'W':
00078 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00079 return 1;
00080 weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
00081 l_time->day),0);
00082 str->append(locale->day_names->type_names[weekday],
00083 strlen(locale->day_names->type_names[weekday]),
00084 system_charset_info);
00085 break;
00086 case 'a':
00087 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00088 return 1;
00089 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
00090 l_time->day),0);
00091 str->append(locale->ab_day_names->type_names[weekday],
00092 strlen(locale->ab_day_names->type_names[weekday]),
00093 system_charset_info);
00094 break;
00095 case 'D':
00096 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00097 return 1;
00098 length= internal::int10_to_str(l_time->day, intbuff, 10) - intbuff;
00099 str->append_with_prefill(intbuff, length, 1, '0');
00100 if (l_time->day >= 10 && l_time->day <= 19)
00101 str->append(STRING_WITH_LEN("th"));
00102 else
00103 {
00104 switch (l_time->day %10) {
00105 case 1:
00106 str->append(STRING_WITH_LEN("st"));
00107 break;
00108 case 2:
00109 str->append(STRING_WITH_LEN("nd"));
00110 break;
00111 case 3:
00112 str->append(STRING_WITH_LEN("rd"));
00113 break;
00114 default:
00115 str->append(STRING_WITH_LEN("th"));
00116 break;
00117 }
00118 }
00119 break;
00120 case 'Y':
00121 length= internal::int10_to_str(l_time->year, intbuff, 10) - intbuff;
00122 str->append_with_prefill(intbuff, length, 4, '0');
00123 break;
00124 case 'y':
00125 length= internal::int10_to_str(l_time->year%100, intbuff, 10) - intbuff;
00126 str->append_with_prefill(intbuff, length, 2, '0');
00127 break;
00128 case 'm':
00129 length= internal::int10_to_str(l_time->month, intbuff, 10) - intbuff;
00130 str->append_with_prefill(intbuff, length, 2, '0');
00131 break;
00132 case 'c':
00133 length= internal::int10_to_str(l_time->month, intbuff, 10) - intbuff;
00134 str->append_with_prefill(intbuff, length, 1, '0');
00135 break;
00136 case 'd':
00137 length= internal::int10_to_str(l_time->day, intbuff, 10) - intbuff;
00138 str->append_with_prefill(intbuff, length, 2, '0');
00139 break;
00140 case 'e':
00141 length= internal::int10_to_str(l_time->day, intbuff, 10) - intbuff;
00142 str->append_with_prefill(intbuff, length, 1, '0');
00143 break;
00144 case 'f':
00145 length= internal::int10_to_str(l_time->second_part, intbuff, 10) - intbuff;
00146 str->append_with_prefill(intbuff, length, 6, '0');
00147 break;
00148 case 'H':
00149 length= internal::int10_to_str(l_time->hour, intbuff, 10) - intbuff;
00150 str->append_with_prefill(intbuff, length, 2, '0');
00151 break;
00152 case 'h':
00153 case 'I':
00154 hours_i= (l_time->hour%24 + 11)%12+1;
00155 length= internal::int10_to_str(hours_i, intbuff, 10) - intbuff;
00156 str->append_with_prefill(intbuff, length, 2, '0');
00157 break;
00158 case 'i':
00159 length= internal::int10_to_str(l_time->minute, intbuff, 10) - intbuff;
00160 str->append_with_prefill(intbuff, length, 2, '0');
00161 break;
00162 case 'j':
00163 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00164 return 1;
00165 length= internal::int10_to_str(calc_daynr(l_time->year,l_time->month,
00166 l_time->day) -
00167 calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff;
00168 str->append_with_prefill(intbuff, length, 3, '0');
00169 break;
00170 case 'k':
00171 length= internal::int10_to_str(l_time->hour, intbuff, 10) - intbuff;
00172 str->append_with_prefill(intbuff, length, 1, '0');
00173 break;
00174 case 'l':
00175 hours_i= (l_time->hour%24 + 11)%12+1;
00176 length= internal::int10_to_str(hours_i, intbuff, 10) - intbuff;
00177 str->append_with_prefill(intbuff, length, 1, '0');
00178 break;
00179 case 'p':
00180 hours_i= l_time->hour%24;
00181 str->append(hours_i < 12 ? "AM" : "PM",2);
00182 break;
00183 case 'r':
00184 length= snprintf(intbuff, sizeof(intbuff),
00185 ((l_time->hour % 24) < 12) ?
00186 "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM",
00187 (l_time->hour+11)%12+1,
00188 l_time->minute,
00189 l_time->second);
00190 str->append(intbuff, length);
00191 break;
00192 case 'S':
00193 case 's':
00194 length= internal::int10_to_str(l_time->second, intbuff, 10) - intbuff;
00195 str->append_with_prefill(intbuff, length, 2, '0');
00196 break;
00197 case 'T':
00198 length= snprintf(intbuff, sizeof(intbuff),
00199 "%02d:%02d:%02d",
00200 l_time->hour,
00201 l_time->minute,
00202 l_time->second);
00203 str->append(intbuff, length);
00204 break;
00205 case 'U':
00206 case 'u':
00207 {
00208 uint32_t year;
00209 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00210 return 1;
00211 length= internal::int10_to_str(calc_week(l_time,
00212 (*ptr) == 'U' ?
00213 WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST,
00214 &year),
00215 intbuff, 10) - intbuff;
00216 str->append_with_prefill(intbuff, length, 2, '0');
00217 }
00218 break;
00219 case 'v':
00220 case 'V':
00221 {
00222 uint32_t year;
00223 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00224 return 1;
00225 length= internal::int10_to_str(calc_week(l_time,
00226 ((*ptr) == 'V' ?
00227 (WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
00228 (WEEK_YEAR | WEEK_MONDAY_FIRST)),
00229 &year),
00230 intbuff, 10) - intbuff;
00231 str->append_with_prefill(intbuff, length, 2, '0');
00232 }
00233 break;
00234 case 'x':
00235 case 'X':
00236 {
00237 uint32_t year;
00238 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00239 return 1;
00240 (void) calc_week(l_time,
00241 ((*ptr) == 'X' ?
00242 WEEK_YEAR | WEEK_FIRST_WEEKDAY :
00243 WEEK_YEAR | WEEK_MONDAY_FIRST),
00244 &year);
00245 length= internal::int10_to_str(year, intbuff, 10) - intbuff;
00246 str->append_with_prefill(intbuff, length, 4, '0');
00247 }
00248 break;
00249 case 'w':
00250 if (type == type::DRIZZLE_TIMESTAMP_TIME)
00251 return 1;
00252 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
00253 l_time->day),1);
00254 length= internal::int10_to_str(weekday, intbuff, 10) - intbuff;
00255 str->append_with_prefill(intbuff, length, 1, '0');
00256 break;
00257
00258 default:
00259 str->append(*ptr);
00260 break;
00261 }
00262 }
00263 }
00264 return 0;
00265 }
00266
00267 void Item_func_date_format::fix_length_and_dec()
00268 {
00269 Item *arg1= args[1];
00270
00271 decimals=0;
00272 const CHARSET_INFO * const cs= getSession().variables.getCollation();
00273 collation.set(cs, arg1->collation.derivation);
00274 if (arg1->type() == STRING_ITEM)
00275 {
00276 fixed_length= 1;
00277 max_length= format_length(&arg1->str_value) *
00278 collation.collation->mbmaxlen;
00279 }
00280 else
00281 {
00282 fixed_length= 0;
00283 max_length= min(arg1->max_length,(uint32_t) MAX_BLOB_WIDTH) * 10 *
00284 collation.collation->mbmaxlen;
00285 set_if_smaller(max_length,MAX_BLOB_WIDTH);
00286 }
00287 maybe_null= 1;
00288 }
00289
00290 bool Item_func_date_format::eq(const Item *item, bool binary_cmp) const
00291 {
00292 Item_func_date_format *item_func;
00293
00294 if (item->type() != FUNC_ITEM)
00295 return 0;
00296 if (func_name() != ((Item_func*) item)->func_name())
00297 return 0;
00298 if (this == item)
00299 return 1;
00300 item_func= (Item_func_date_format*) item;
00301 if (!args[0]->eq(item_func->args[0], binary_cmp))
00302 return 0;
00303
00304
00305
00306
00307
00308 if (!args[1]->eq(item_func->args[1], 1))
00309 return 0;
00310 return 1;
00311 }
00312
00313 uint32_t Item_func_date_format::format_length(const String *format)
00314 {
00315 uint32_t size=0;
00316 const char *ptr=format->ptr();
00317 const char *end=ptr+format->length();
00318
00319 for (; ptr != end ; ptr++)
00320 {
00321 if (*ptr != '%' || ptr == end-1)
00322 size++;
00323 else
00324 {
00325 switch(*++ptr) {
00326 case 'M':
00327 case 'W':
00328 size += 64;
00329 break;
00330 case 'D':
00331 case 'Y':
00332 case 'x':
00333 case 'X':
00334 size += 4;
00335 break;
00336 case 'a':
00337 case 'b':
00338 size += 32;
00339 break;
00340 case 'j':
00341 size += 3;
00342 break;
00343 case 'U':
00344 case 'u':
00345 case 'V':
00346 case 'v':
00347 case 'y':
00348 case 'm':
00349 case 'd':
00350 case 'h':
00351 case 'I':
00352 case 'i':
00353 case 'l':
00354 case 'p':
00355 case 'S':
00356 case 's':
00357 case 'c':
00358 case 'e':
00359 size += 2;
00360 break;
00361 case 'k':
00362 case 'H':
00363 size += 7;
00364 break;
00365 case 'r':
00366 size += 11;
00367 break;
00368 case 'T':
00369 size += 8;
00370 break;
00371 case 'f':
00372 size += 6;
00373 break;
00374 case 'w':
00375 case '%':
00376 default:
00377 size++;
00378 break;
00379 }
00380 }
00381 }
00382 return size;
00383 }
00384
00385
00386 String *Item_func_date_format::val_str(String *str)
00387 {
00388 String *format;
00389 type::Time l_time;
00390 uint32_t size;
00391 assert(fixed == 1);
00392
00393 if (!is_time_format)
00394 {
00395 if (get_arg0_date(l_time, TIME_FUZZY_DATE))
00396 return 0;
00397 }
00398 else
00399 {
00400 String *res;
00401 if (!(res=args[0]->val_str(str)) ||
00402 (str_to_time_with_warn(&getSession(), res->ptr(), res->length(), &l_time)))
00403 goto null_date;
00404
00405 l_time.year=l_time.month=l_time.day=0;
00406 null_value=0;
00407 }
00408
00409 if (!(format = args[1]->val_str(str)) || !format->length())
00410 goto null_date;
00411
00412 if (fixed_length)
00413 size= max_length;
00414 else
00415 size= format_length(format);
00416
00417 if (size < type::Time::MAX_STRING_LENGTH)
00418 size= type::Time::MAX_STRING_LENGTH;
00419
00420 if (format == str)
00421 str= &value;
00422
00423 if (str->alloc(size))
00424 goto null_date;
00425
00426
00427 str->set_charset(collation.collation);
00428 if (not make_date_time(getSession(),
00429 format, &l_time,
00430 is_time_format ? type::DRIZZLE_TIMESTAMP_TIME :
00431 type::DRIZZLE_TIMESTAMP_DATE,
00432 str))
00433 return str;
00434
00435 null_date:
00436 null_value=1;
00437
00438 return 0;
00439 }
00440
00441 }