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