00001 /* Copyright (C) 2000-2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 00018 /* This file defines all time functions */ 00019 00020 #ifdef USE_PRAGMA_IMPLEMENTATION 00021 #pragma implementation // gcc: Class implementation 00022 #endif 00023 00024 #include "mysql_priv.h" 00025 #include <m_ctype.h> 00026 #include <time.h> 00027 00028 /* TODO: Move month and days to language files */ 00029 00030 /* Day number for Dec 31st, 9999 */ 00031 #define MAX_DAY_NUMBER 3652424L 00032 00033 /* 00034 OPTIMIZATION TODO: 00035 - Replace the switch with a function that should be called for each 00036 date type. 00037 - Remove sprintf and opencode the conversion, like we do in 00038 Field_datetime. 00039 00040 The reason for this functions existence is that as we don't have a 00041 way to know if a datetime/time value has microseconds in them 00042 we are now only adding microseconds to the output if the 00043 value has microseconds. 00044 00045 We can't use a standard make_date_time() for this as we don't know 00046 if someone will use %f in the format specifier in which case we would get 00047 the microseconds twice. 00048 */ 00049 00050 static bool make_datetime(date_time_format_types format, TIME *ltime, 00051 String *str) 00052 { 00053 char *buff; 00054 CHARSET_INFO *cs= &my_charset_bin; 00055 uint length= 30; 00056 00057 if (str->alloc(length)) 00058 return 1; 00059 buff= (char*) str->ptr(); 00060 00061 switch (format) { 00062 case TIME_ONLY: 00063 length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d", 00064 ltime->neg ? "-" : "", 00065 ltime->hour, ltime->minute, ltime->second); 00066 break; 00067 case TIME_MICROSECOND: 00068 length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d.%06d", 00069 ltime->neg ? "-" : "", 00070 ltime->hour, ltime->minute, ltime->second, 00071 ltime->second_part); 00072 break; 00073 case DATE_ONLY: 00074 length= cs->cset->snprintf(cs, buff, length, "%04d-%02d-%02d", 00075 ltime->year, ltime->month, ltime->day); 00076 break; 00077 case DATE_TIME: 00078 length= cs->cset->snprintf(cs, buff, length, 00079 "%04d-%02d-%02d %02d:%02d:%02d", 00080 ltime->year, ltime->month, ltime->day, 00081 ltime->hour, ltime->minute, ltime->second); 00082 break; 00083 case DATE_TIME_MICROSECOND: 00084 length= cs->cset->snprintf(cs, buff, length, 00085 "%04d-%02d-%02d %02d:%02d:%02d.%06d", 00086 ltime->year, ltime->month, ltime->day, 00087 ltime->hour, ltime->minute, ltime->second, 00088 ltime->second_part); 00089 break; 00090 } 00091 00092 str->length(length); 00093 str->set_charset(cs); 00094 return 0; 00095 } 00096 00097 00098 /* 00099 Date formats corresponding to compound %r and %T conversion specifiers 00100 00101 Note: We should init at least first element of "positions" array 00102 (first member) or hpux11 compiler will die horribly. 00103 */ 00104 static DATE_TIME_FORMAT time_ampm_format= {{0}, '\0', 0, 00105 {(char *)"%I:%i:%S %p", 11}}; 00106 static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0, 00107 {(char *)"%H:%i:%S", 8}}; 00108 00109 /* 00110 Extract datetime value to TIME struct from string value 00111 according to format string. 00112 00113 SYNOPSIS 00114 extract_date_time() 00115 format date/time format specification 00116 val String to decode 00117 length Length of string 00118 l_time Store result here 00119 cached_timestamp_type 00120 It uses to get an appropriate warning 00121 in the case when the value is truncated. 00122 sub_pattern_end if non-zero then we are parsing string which 00123 should correspond compound specifier (like %T or 00124 %r) and this parameter is pointer to place where 00125 pointer to end of string matching this specifier 00126 should be stored. 00127 NOTE 00128 Possibility to parse strings matching to patterns equivalent to compound 00129 specifiers is mainly intended for use from inside of this function in 00130 order to understand %T and %r conversion specifiers, so number of 00131 conversion specifiers that can be used in such sub-patterns is limited. 00132 Also most of checks are skipped in this case. 00133 00134 If one adds new format specifiers to this function he should also 00135 consider adding them to get_date_time_result_type() function. 00136 00137 RETURN 00138 0 ok 00139 1 error 00140 */ 00141 00142 static bool extract_date_time(DATE_TIME_FORMAT *format, 00143 const char *val, uint length, TIME *l_time, 00144 timestamp_type cached_timestamp_type, 00145 const char **sub_pattern_end, 00146 const char *date_time_type) 00147 { 00148 int weekday= 0, yearday= 0, daypart= 0; 00149 int week_number= -1; 00150 int error= 0; 00151 int strict_week_number_year= -1; 00152 int frac_part; 00153 bool usa_time= 0; 00154 bool sunday_first_n_first_week_non_iso; 00155 bool strict_week_number; 00156 bool strict_week_number_year_type; 00157 const char *val_begin= val; 00158 const char *val_end= val + length; 00159 const char *ptr= format->format.str; 00160 const char *end= ptr + format->format.length; 00161 CHARSET_INFO *cs= &my_charset_bin; 00162 DBUG_ENTER("extract_date_time"); 00163 00164 LINT_INIT(strict_week_number); 00165 /* Remove valgrind varnings when using gcc 3.3 and -O1 */ 00166 PURIFY_OR_LINT_INIT(strict_week_number_year_type); 00167 PURIFY_OR_LINT_INIT(sunday_first_n_first_week_non_iso); 00168 00169 if (!sub_pattern_end) 00170 bzero((char*) l_time, sizeof(*l_time)); 00171 00172 for (; ptr != end && val != val_end; ptr++) 00173 { 00174 if (*ptr == '%' && ptr+1 != end) 00175 { 00176 int val_len; 00177 char *tmp; 00178 00179 error= 0; 00180 /* Skip pre-space between each argument */ 00181 while (val != val_end && my_isspace(cs, *val)) 00182 val++; 00183 00184 val_len= (uint) (val_end - val); 00185 switch (*++ptr) { 00186 /* Year */ 00187 case 'Y': 00188 tmp= (char*) val + min(4, val_len); 00189 l_time->year= (int) my_strtoll10(val, &tmp, &error); 00190 val= tmp; 00191 break; 00192 case 'y': 00193 tmp= (char*) val + min(2, val_len); 00194 l_time->year= (int) my_strtoll10(val, &tmp, &error); 00195 val= tmp; 00196 l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); 00197 break; 00198 00199 /* Month */ 00200 case 'm': 00201 case 'c': 00202 tmp= (char*) val + min(2, val_len); 00203 l_time->month= (int) my_strtoll10(val, &tmp, &error); 00204 val= tmp; 00205 break; 00206 case 'M': 00207 if ((l_time->month= check_word(my_locale_en_US.month_names, 00208 val, val_end, &val)) <= 0) 00209 goto err; 00210 break; 00211 case 'b': 00212 if ((l_time->month= check_word(my_locale_en_US.ab_month_names, 00213 val, val_end, &val)) <= 0) 00214 goto err; 00215 break; 00216 /* Day */ 00217 case 'd': 00218 case 'e': 00219 tmp= (char*) val + min(2, val_len); 00220 l_time->day= (int) my_strtoll10(val, &tmp, &error); 00221 val= tmp; 00222 break; 00223 case 'D': 00224 tmp= (char*) val + min(2, val_len); 00225 l_time->day= (int) my_strtoll10(val, &tmp, &error); 00226 /* Skip 'st, 'nd, 'th .. */ 00227 val= tmp + min((int) (end-tmp), 2); 00228 break; 00229 00230 /* Hour */ 00231 case 'h': 00232 case 'I': 00233 case 'l': 00234 usa_time= 1; 00235 /* fall through */ 00236 case 'k': 00237 case 'H': 00238 tmp= (char*) val + min(2, val_len); 00239 l_time->hour= (int) my_strtoll10(val, &tmp, &error); 00240 val= tmp; 00241 break; 00242 00243 /* Minute */ 00244 case 'i': 00245 tmp= (char*) val + min(2, val_len); 00246 l_time->minute= (int) my_strtoll10(val, &tmp, &error); 00247 val= tmp; 00248 break; 00249 00250 /* Second */ 00251 case 's': 00252 case 'S': 00253 tmp= (char*) val + min(2, val_len); 00254 l_time->second= (int) my_strtoll10(val, &tmp, &error); 00255 val= tmp; 00256 break; 00257 00258 /* Second part */ 00259 case 'f': 00260 tmp= (char*) val_end; 00261 if (tmp - val > 6) 00262 tmp= (char*) val + 6; 00263 l_time->second_part= (int) my_strtoll10(val, &tmp, &error); 00264 frac_part= 6 - (tmp - val); 00265 if (frac_part > 0) 00266 l_time->second_part*= (ulong) log_10_int[frac_part]; 00267 val= tmp; 00268 break; 00269 00270 /* AM / PM */ 00271 case 'p': 00272 if (val_len < 2 || ! usa_time) 00273 goto err; 00274 if (!my_strnncoll(&my_charset_latin1, 00275 (const uchar *) val, 2, 00276 (const uchar *) "PM", 2)) 00277 daypart= 12; 00278 else if (my_strnncoll(&my_charset_latin1, 00279 (const uchar *) val, 2, 00280 (const uchar *) "AM", 2)) 00281 goto err; 00282 val+= 2; 00283 break; 00284 00285 /* Exotic things */ 00286 case 'W': 00287 if ((weekday= check_word(my_locale_en_US.day_names, val, val_end, &val)) <= 0) 00288 goto err; 00289 break; 00290 case 'a': 00291 if ((weekday= check_word(my_locale_en_US.ab_day_names, val, val_end, &val)) <= 0) 00292 goto err; 00293 break; 00294 case 'w': 00295 tmp= (char*) val + 1; 00296 if ((weekday= (int) my_strtoll10(val, &tmp, &error)) < 0 || 00297 weekday >= 7) 00298 goto err; 00299 /* We should use the same 1 - 7 scale for %w as for %W */ 00300 if (!weekday) 00301 weekday= 7; 00302 val= tmp; 00303 break; 00304 case 'j': 00305 tmp= (char*) val + min(val_len, 3); 00306 yearday= (int) my_strtoll10(val, &tmp, &error); 00307 val= tmp; 00308 break; 00309 00310 /* Week numbers */ 00311 case 'V': 00312 case 'U': 00313 case 'v': 00314 case 'u': 00315 sunday_first_n_first_week_non_iso= (*ptr=='U' || *ptr== 'V'); 00316 strict_week_number= (*ptr=='V' || *ptr=='v'); 00317 tmp= (char*) val + min(val_len, 2); 00318 if ((week_number= (int) my_strtoll10(val, &tmp, &error)) < 0 || 00319 strict_week_number && !week_number || 00320 week_number > 53) 00321 goto err; 00322 val= tmp; 00323 break; 00324 00325 /* Year used with 'strict' %V and %v week numbers */ 00326 case 'X': 00327 case 'x': 00328 strict_week_number_year_type= (*ptr=='X'); 00329 tmp= (char*) val + min(4, val_len); 00330 strict_week_number_year= (int) my_strtoll10(val, &tmp, &error); 00331 val= tmp; 00332 break; 00333 00334 /* Time in AM/PM notation */ 00335 case 'r': 00336 /* 00337 We can't just set error here, as we don't want to generate two 00338 warnings in case of errors 00339 */ 00340 if (extract_date_time(&time_ampm_format, val, 00341 (uint)(val_end - val), l_time, 00342 cached_timestamp_type, &val, "time")) 00343 DBUG_RETURN(1); 00344 break; 00345 00346 /* Time in 24-hour notation */ 00347 case 'T': 00348 if (extract_date_time(&time_24hrs_format, val, 00349 (uint)(val_end - val), l_time, 00350 cached_timestamp_type, &val, "time")) 00351 DBUG_RETURN(1); 00352 break; 00353 00354 /* Conversion specifiers that match classes of characters */ 00355 case '.': 00356 while (my_ispunct(cs, *val) && val != val_end) 00357 val++; 00358 break; 00359 case '@': 00360 while (my_isalpha(cs, *val) && val != val_end) 00361 val++; 00362 break; 00363 case '#': 00364 while (my_isdigit(cs, *val) && val != val_end) 00365 val++; 00366 break; 00367 default: 00368 goto err; 00369 } 00370 if (error) // Error from my_strtoll10 00371 goto err; 00372 } 00373 else if (!my_isspace(cs, *ptr)) 00374 { 00375 if (*val != *ptr) 00376 goto err; 00377 val++; 00378 } 00379 } 00380 if (usa_time) 00381 { 00382 if (l_time->hour > 12 || l_time->hour < 1) 00383 goto err; 00384 l_time->hour= l_time->hour%12+daypart; 00385 } 00386 00387 /* 00388 If we are recursively called for parsing string matching compound 00389 specifiers we are already done. 00390 */ 00391 if (sub_pattern_end) 00392 { 00393 *sub_pattern_end= val; 00394 DBUG_RETURN(0); 00395 } 00396 00397 if (yearday > 0) 00398 { 00399 uint days= calc_daynr(l_time->year,1,1) + yearday - 1; 00400 if (days <= 0 || days > MAX_DAY_NUMBER) 00401 goto err; 00402 get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); 00403 } 00404 00405 if (week_number >= 0 && weekday) 00406 { 00407 int days; 00408 uint weekday_b; 00409 00410 /* 00411 %V,%v require %X,%x resprectively, 00412 %U,%u should be used with %Y and not %X or %x 00413 */ 00414 if (strict_week_number && 00415 (strict_week_number_year < 0 || 00416 strict_week_number_year_type != sunday_first_n_first_week_non_iso) || 00417 !strict_week_number && strict_week_number_year >= 0) 00418 goto err; 00419 00420 /* Number of days since year 0 till 1st Jan of this year */ 00421 days= calc_daynr((strict_week_number ? strict_week_number_year : 00422 l_time->year), 00423 1, 1); 00424 /* Which day of week is 1st Jan of this year */ 00425 weekday_b= calc_weekday(days, sunday_first_n_first_week_non_iso); 00426 00427 /* 00428 Below we are going to sum: 00429 1) number of days since year 0 till 1st day of 1st week of this year 00430 2) number of days between 1st week and our week 00431 3) and position of our day in the week 00432 */ 00433 if (sunday_first_n_first_week_non_iso) 00434 { 00435 days+= ((weekday_b == 0) ? 0 : 7) - weekday_b + 00436 (week_number - 1) * 7 + 00437 weekday % 7; 00438 } 00439 else 00440 { 00441 days+= ((weekday_b <= 3) ? 0 : 7) - weekday_b + 00442 (week_number - 1) * 7 + 00443 (weekday - 1); 00444 } 00445 00446 if (days <= 0 || days > MAX_DAY_NUMBER) 00447 goto err; 00448 get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); 00449 } 00450 00451 if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || 00452 l_time->minute > 59 || l_time->second > 59) 00453 goto err; 00454 00455 if (val != val_end) 00456 { 00457 do 00458 { 00459 if (!my_isspace(&my_charset_latin1,*val)) 00460 { 00461 make_truncated_value_warning(current_thd, val_begin, length, 00462 cached_timestamp_type, NullS); 00463 break; 00464 } 00465 } while (++val != val_end); 00466 } 00467 DBUG_RETURN(0); 00468 00469 err: 00470 { 00471 char buff[128]; 00472 strmake(buff, val_begin, min(length, sizeof(buff)-1)); 00473 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, 00474 ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE), 00475 date_time_type, buff, "str_to_time"); 00476 } 00477 DBUG_RETURN(1); 00478 } 00479 00480 00481 /* 00482 Create a formated date/time value in a string 00483 */ 00484 00485 bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, 00486 timestamp_type type, String *str) 00487 { 00488 char intbuff[15]; 00489 uint hours_i; 00490 uint weekday; 00491 ulong length; 00492 const char *ptr, *end; 00493 MY_LOCALE *locale; 00494 THD *thd= current_thd; 00495 char buf[STRING_BUFFER_USUAL_SIZE]; 00496 String tmp(buf, sizeof(buf), thd->variables.character_set_results); 00497 uint errors= 0; 00498 00499 tmp.length(0); 00500 str->length(0); 00501 str->set_charset(&my_charset_bin); 00502 locale = thd->variables.lc_time_names; 00503 00504 if (l_time->neg) 00505 str->append('-'); 00506 00507 end= (ptr= format->format.str) + format->format.length; 00508 for (; ptr != end ; ptr++) 00509 { 00510 if (*ptr != '%' || ptr+1 == end) 00511 str->append(*ptr); 00512 else 00513 { 00514 switch (*++ptr) { 00515 case 'M': 00516 if (!l_time->month) 00517 return 1; 00518 tmp.copy(locale->month_names->type_names[l_time->month-1], 00519 strlen(locale->month_names->type_names[l_time->month-1]), 00520 system_charset_info, tmp.charset(), &errors); 00521 str->append(tmp.ptr(), tmp.length()); 00522 break; 00523 case 'b': 00524 if (!l_time->month) 00525 return 1; 00526 tmp.copy(locale->ab_month_names->type_names[l_time->month-1], 00527 strlen(locale->ab_month_names->type_names[l_time->month-1]), 00528 system_charset_info, tmp.charset(), &errors); 00529 str->append(tmp.ptr(), tmp.length()); 00530 break; 00531 case 'W': 00532 if (type == MYSQL_TIMESTAMP_TIME) 00533 return 1; 00534 weekday= calc_weekday(calc_daynr(l_time->year,l_time->month, 00535 l_time->day),0); 00536 tmp.copy(locale->day_names->type_names[weekday], 00537 strlen(locale->day_names->type_names[weekday]), 00538 system_charset_info, tmp.charset(), &errors); 00539 str->append(tmp.ptr(), tmp.length()); 00540 break; 00541 case 'a': 00542 if (type == MYSQL_TIMESTAMP_TIME) 00543 return 1; 00544 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, 00545 l_time->day),0); 00546 tmp.copy(locale->ab_day_names->type_names[weekday], 00547 strlen(locale->ab_day_names->type_names[weekday]), 00548 system_charset_info, tmp.charset(), &errors); 00549 str->append(tmp.ptr(), tmp.length()); 00550 break; 00551 case 'D': 00552 if (type == MYSQL_TIMESTAMP_TIME) 00553 return 1; 00554 length= int10_to_str(l_time->day, intbuff, 10) - intbuff; 00555 str->append_with_prefill(intbuff, length, 1, '0'); 00556 if (l_time->day >= 10 && l_time->day <= 19) 00557 str->append(STRING_WITH_LEN("th")); 00558 else 00559 { 00560 switch (l_time->day %10) { 00561 case 1: 00562 str->append(STRING_WITH_LEN("st")); 00563 break; 00564 case 2: 00565 str->append(STRING_WITH_LEN("nd")); 00566 break; 00567 case 3: 00568 str->append(STRING_WITH_LEN("rd")); 00569 break; 00570 default: 00571 str->append(STRING_WITH_LEN("th")); 00572 break; 00573 } 00574 } 00575 break; 00576 case 'Y': 00577 length= int10_to_str(l_time->year, intbuff, 10) - intbuff; 00578 str->append_with_prefill(intbuff, length, 4, '0'); 00579 break; 00580 case 'y': 00581 length= int10_to_str(l_time->year%100, intbuff, 10) - intbuff; 00582 str->append_with_prefill(intbuff, length, 2, '0'); 00583 break; 00584 case 'm': 00585 length= int10_to_str(l_time->month, intbuff, 10) - intbuff; 00586 str->append_with_prefill(intbuff, length, 2, '0'); 00587 break; 00588 case 'c': 00589 length= int10_to_str(l_time->month, intbuff, 10) - intbuff; 00590 str->append_with_prefill(intbuff, length, 1, '0'); 00591 break; 00592 case 'd': 00593 length= int10_to_str(l_time->day, intbuff, 10) - intbuff; 00594 str->append_with_prefill(intbuff, length, 2, '0'); 00595 break; 00596 case 'e': 00597 length= int10_to_str(l_time->day, intbuff, 10) - intbuff; 00598 str->append_with_prefill(intbuff, length, 1, '0'); 00599 break; 00600 case 'f': 00601 length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; 00602 str->append_with_prefill(intbuff, length, 6, '0'); 00603 break; 00604 case 'H': 00605 length= int10_to_str(l_time->hour, intbuff, 10) - intbuff; 00606 str->append_with_prefill(intbuff, length, 2, '0'); 00607 break; 00608 case 'h': 00609 case 'I': 00610 hours_i= (l_time->hour%24 + 11)%12+1; 00611 length= int10_to_str(hours_i, intbuff, 10) - intbuff; 00612 str->append_with_prefill(intbuff, length, 2, '0'); 00613 break; 00614 case 'i': /* minutes */ 00615 length= int10_to_str(l_time->minute, intbuff, 10) - intbuff; 00616 str->append_with_prefill(intbuff, length, 2, '0'); 00617 break; 00618 case 'j': 00619 if (type == MYSQL_TIMESTAMP_TIME) 00620 return 1; 00621 length= int10_to_str(calc_daynr(l_time->year,l_time->month, 00622 l_time->day) - 00623 calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff; 00624 str->append_with_prefill(intbuff, length, 3, '0'); 00625 break; 00626 case 'k': 00627 length= int10_to_str(l_time->hour, intbuff, 10) - intbuff; 00628 str->append_with_prefill(intbuff, length, 1, '0'); 00629 break; 00630 case 'l': 00631 hours_i= (l_time->hour%24 + 11)%12+1; 00632 length= int10_to_str(hours_i, intbuff, 10) - intbuff; 00633 str->append_with_prefill(intbuff, length, 1, '0'); 00634 break; 00635 case 'p': 00636 hours_i= l_time->hour%24; 00637 str->append(hours_i < 12 ? "AM" : "PM",2); 00638 break; 00639 case 'r': 00640 length= my_sprintf(intbuff, 00641 (intbuff, 00642 ((l_time->hour % 24) < 12) ? 00643 "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", 00644 (l_time->hour+11)%12+1, 00645 l_time->minute, 00646 l_time->second)); 00647 str->append(intbuff, length); 00648 break; 00649 case 'S': 00650 case 's': 00651 length= int10_to_str(l_time->second, intbuff, 10) - intbuff; 00652 str->append_with_prefill(intbuff, length, 2, '0'); 00653 break; 00654 case 'T': 00655 length= my_sprintf(intbuff, 00656 (intbuff, 00657 "%02d:%02d:%02d", 00658 l_time->hour, 00659 l_time->minute, 00660 l_time->second)); 00661 str->append(intbuff, length); 00662 break; 00663 case 'U': 00664 case 'u': 00665 { 00666 uint year; 00667 if (type == MYSQL_TIMESTAMP_TIME) 00668 return 1; 00669 length= int10_to_str(calc_week(l_time, 00670 (*ptr) == 'U' ? 00671 WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST, 00672 &year), 00673 intbuff, 10) - intbuff; 00674 str->append_with_prefill(intbuff, length, 2, '0'); 00675 } 00676 break; 00677 case 'v': 00678 case 'V': 00679 { 00680 uint year; 00681 if (type == MYSQL_TIMESTAMP_TIME) 00682 return 1; 00683 length= int10_to_str(calc_week(l_time, 00684 ((*ptr) == 'V' ? 00685 (WEEK_YEAR | WEEK_FIRST_WEEKDAY) : 00686 (WEEK_YEAR | WEEK_MONDAY_FIRST)), 00687 &year), 00688 intbuff, 10) - intbuff; 00689 str->append_with_prefill(intbuff, length, 2, '0'); 00690 } 00691 break; 00692 case 'x': 00693 case 'X': 00694 { 00695 uint year; 00696 if (type == MYSQL_TIMESTAMP_TIME) 00697 return 1; 00698 (void) calc_week(l_time, 00699 ((*ptr) == 'X' ? 00700 WEEK_YEAR | WEEK_FIRST_WEEKDAY : 00701 WEEK_YEAR | WEEK_MONDAY_FIRST), 00702 &year); 00703 length= int10_to_str(year, intbuff, 10) - intbuff; 00704 str->append_with_prefill(intbuff, length, 4, '0'); 00705 } 00706 break; 00707 case 'w': 00708 if (type == MYSQL_TIMESTAMP_TIME) 00709 return 1; 00710 weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, 00711 l_time->day),1); 00712 length= int10_to_str(weekday, intbuff, 10) - intbuff; 00713 str->append_with_prefill(intbuff, length, 1, '0'); 00714 break; 00715 00716 default: 00717 str->append(*ptr); 00718 break; 00719 } 00720 } 00721 } 00722 return 0; 00723 } 00724 00725 00726 /* 00727 Get a array of positive numbers from a string object. 00728 Each number is separated by 1 non digit character 00729 Return error if there is too many numbers. 00730 If there is too few numbers, assume that the numbers are left out 00731 from the high end. This allows one to give: 00732 DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds. 00733 00734 SYNOPSIS 00735 str: string value 00736 length: length of str 00737 cs: charset of str 00738 values: array of results 00739 count: count of elements in result array 00740 transform_msec: if value is true we suppose 00741 that the last part of string value is microseconds 00742 and we should transform value to six digit value. 00743 For example, '1.1' -> '1.100000' 00744 */ 00745 00746 static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs, 00747 uint count, ulonglong *values, 00748 bool transform_msec) 00749 { 00750 const char *end=str+length; 00751 uint i; 00752 while (str != end && !my_isdigit(cs,*str)) 00753 str++; 00754 00755 for (i=0 ; i < count ; i++) 00756 { 00757 longlong value; 00758 const char *start= str; 00759 for (value=0; str != end && my_isdigit(cs,*str) ; str++) 00760 value= value*LL(10) + (longlong) (*str - '0'); 00761 if (transform_msec && i == count - 1) // microseconds always last 00762 { 00763 long msec_length= 6 - (str - start); 00764 if (msec_length > 0) 00765 value*= (long) log_10_int[msec_length]; 00766 } 00767 values[i]= value; 00768 while (str != end && !my_isdigit(cs,*str)) 00769 str++; 00770 if (str == end && i != count-1) 00771 { 00772 i++; 00773 /* Change values[0...i-1] -> values[0...count-1] */ 00774 bmove_upp((char*) (values+count), (char*) (values+i), 00775 sizeof(*values)*i); 00776 bzero((char*) values, sizeof(*values)*(count-i)); 00777 break; 00778 } 00779 } 00780 return (str != end); 00781 } 00782 00783 00784 longlong Item_func_period_add::val_int() 00785 { 00786 DBUG_ASSERT(fixed == 1); 00787 ulong period=(ulong) args[0]->val_int(); 00788 int months=(int) args[1]->val_int(); 00789 00790 if ((null_value=args[0]->null_value || args[1]->null_value) || 00791 period == 0L) 00792 return 0; /* purecov: inspected */ 00793 return (longlong) 00794 convert_month_to_period((uint) ((int) convert_period_to_month(period)+ 00795 months)); 00796 } 00797 00798 00799 longlong Item_func_period_diff::val_int() 00800 { 00801 DBUG_ASSERT(fixed == 1); 00802 ulong period1=(ulong) args[0]->val_int(); 00803 ulong period2=(ulong) args[1]->val_int(); 00804 00805 if ((null_value=args[0]->null_value || args[1]->null_value)) 00806 return 0; /* purecov: inspected */ 00807 return (longlong) ((long) convert_period_to_month(period1)- 00808 (long) convert_period_to_month(period2)); 00809 } 00810 00811 00812 00813 longlong Item_func_to_days::val_int() 00814 { 00815 DBUG_ASSERT(fixed == 1); 00816 TIME ltime; 00817 if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) 00818 return 0; 00819 return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); 00820 } 00821 00822 00823 /* 00824 Get information about this Item tree monotonicity 00825 00826 SYNOPSIS 00827 Item_func_to_days::get_monotonicity_info() 00828 00829 DESCRIPTION 00830 Get information about monotonicity of the function represented by this item 00831 tree. 00832 00833 RETURN 00834 See enum_monotonicity_info. 00835 */ 00836 00837 enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const 00838 { 00839 if (args[0]->type() == Item::FIELD_ITEM) 00840 { 00841 if (args[0]->field_type() == MYSQL_TYPE_DATE) 00842 return MONOTONIC_STRICT_INCREASING; 00843 if (args[0]->field_type() == MYSQL_TYPE_DATETIME) 00844 return MONOTONIC_INCREASING; 00845 } 00846 return NON_MONOTONIC; 00847 } 00848 00849 00850 longlong Item_func_dayofyear::val_int() 00851 { 00852 DBUG_ASSERT(fixed == 1); 00853 TIME ltime; 00854 if (get_arg0_date(<ime,TIME_NO_ZERO_DATE)) 00855 return 0; 00856 return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) - 00857 calc_daynr(ltime.year,1,1) + 1; 00858 } 00859 00860 longlong Item_func_dayofmonth::val_int() 00861 { 00862 DBUG_ASSERT(fixed == 1); 00863 TIME ltime; 00864 (void) get_arg0_date(<ime, TIME_FUZZY_DATE); 00865 return (longlong) ltime.day; 00866 } 00867 00868 longlong Item_func_month::val_int() 00869 { 00870 DBUG_ASSERT(fixed == 1); 00871 TIME ltime; 00872 (void) get_arg0_date(<ime, TIME_FUZZY_DATE); 00873 return (longlong) ltime.month; 00874 } 00875 00876 00877 String* Item_func_monthname::val_str(String* str) 00878 { 00879 DBUG_ASSERT(fixed == 1); 00880 const char *month_name; 00881 uint month= (uint) val_int(); 00882 THD *thd= current_thd; 00883 00884 if (null_value || !month) 00885 { 00886 null_value=1; 00887 return (String*) 0; 00888 } 00889 null_value=0; 00890 month_name= thd->variables.lc_time_names->month_names->type_names[month-1]; 00891 str->set(month_name, strlen(month_name), system_charset_info); 00892 return str; 00893 } 00894 00895 00896 // Returns the quarter of the year 00897 00898 longlong Item_func_quarter::val_int() 00899 { 00900 DBUG_ASSERT(fixed == 1); 00901 TIME ltime; 00902 (void) get_arg0_date(<ime, TIME_FUZZY_DATE); 00903 return (longlong) ((ltime.month+2)/3); 00904 } 00905 00906 longlong Item_func_hour::val_int() 00907 { 00908 DBUG_ASSERT(fixed == 1); 00909 TIME ltime; 00910 (void) get_arg0_time(<ime); 00911 return ltime.hour; 00912 } 00913 00914 longlong Item_func_minute::val_int() 00915 { 00916 DBUG_ASSERT(fixed == 1); 00917 TIME ltime; 00918 (void) get_arg0_time(<ime); 00919 return ltime.minute; 00920 } 00921 // Returns the second in time_exp in the range of 0 - 59 00922 00923 longlong Item_func_second::val_int() 00924 { 00925 DBUG_ASSERT(fixed == 1); 00926 TIME ltime; 00927 (void) get_arg0_time(<ime); 00928 return ltime.second; 00929 } 00930 00931 00932 uint week_mode(uint mode) 00933 { 00934 uint week_format= (mode & 7); 00935 if (!(week_format & WEEK_MONDAY_FIRST)) 00936 week_format^= WEEK_FIRST_WEEKDAY; 00937 return week_format; 00938 } 00939 00940 /* 00941 The bits in week_format(for calc_week() function) has the following meaning: 00942 WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week 00943 If set Monday is first day of week 00944 WEEK_YEAR (1) If not set Week is in range 0-53 00945 00946 Week 0 is returned for the the last week of the previous year (for 00947 a date at start of january) In this case one can get 53 for the 00948 first week of next year. This flag ensures that the week is 00949 relevant for the given year. Note that this flag is only 00950 releveant if WEEK_JANUARY is not set. 00951 00952 If set Week is in range 1-53. 00953 00954 In this case one may get week 53 for a date in January (when 00955 the week is that last week of previous year) and week 1 for a 00956 date in December. 00957 00958 WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according 00959 to ISO 8601:1988 00960 If set The week that contains the first 00961 'first-day-of-week' is week 1. 00962 00963 ISO 8601:1988 means that if the week containing January 1 has 00964 four or more days in the new year, then it is week 1; 00965 Otherwise it is the last week of the previous year, and the 00966 next week is week 1. 00967 */ 00968 00969 longlong Item_func_week::val_int() 00970 { 00971 DBUG_ASSERT(fixed == 1); 00972 uint year; 00973 TIME ltime; 00974 if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) 00975 return 0; 00976 return (longlong) calc_week(<ime, 00977 week_mode((uint) args[1]->val_int()), 00978 &year); 00979 } 00980 00981 00982 longlong Item_func_yearweek::val_int() 00983 { 00984 DBUG_ASSERT(fixed == 1); 00985 uint year,week; 00986 TIME ltime; 00987 if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) 00988 return 0; 00989 week= calc_week(<ime, 00990 (week_mode((uint) args[1]->val_int()) | WEEK_YEAR), 00991 &year); 00992 return week+year*100; 00993 } 00994 00995 00996 longlong Item_func_weekday::val_int() 00997 { 00998 DBUG_ASSERT(fixed == 1); 00999 TIME ltime; 01000 01001 if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) 01002 return 0; 01003 01004 return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month, 01005 ltime.day), 01006 odbc_type) + test(odbc_type); 01007 } 01008 01009 01010 String* Item_func_dayname::val_str(String* str) 01011 { 01012 DBUG_ASSERT(fixed == 1); 01013 uint weekday=(uint) val_int(); // Always Item_func_daynr() 01014 const char *name; 01015 THD *thd= current_thd; 01016 01017 if (null_value) 01018 return (String*) 0; 01019 01020 name= thd->variables.lc_time_names->day_names->type_names[weekday]; 01021 str->set(name, strlen(name), system_charset_info); 01022 return str; 01023 } 01024 01025 01026 longlong Item_func_year::val_int() 01027 { 01028 DBUG_ASSERT(fixed == 1); 01029 TIME ltime; 01030 (void) get_arg0_date(<ime, TIME_FUZZY_DATE); 01031 return (longlong) ltime.year; 01032 } 01033 01034 01035 /* 01036 Get information about this Item tree monotonicity 01037 01038 SYNOPSIS 01039 Item_func_to_days::get_monotonicity_info() 01040 01041 DESCRIPTION 01042 Get information about monotonicity of the function represented by this item 01043 tree. 01044 01045 RETURN 01046 See enum_monotonicity_info. 01047 */ 01048 01049 enum_monotonicity_info Item_func_year::get_monotonicity_info() const 01050 { 01051 if (args[0]->type() == Item::FIELD_ITEM && 01052 (args[0]->field_type() == MYSQL_TYPE_DATE || 01053 args[0]->field_type() == MYSQL_TYPE_DATETIME)) 01054 return MONOTONIC_INCREASING; 01055 return NON_MONOTONIC; 01056 } 01057 01058 longlong Item_func_unix_timestamp::val_int() 01059 { 01060 TIME ltime; 01061 my_bool not_used; 01062 01063 DBUG_ASSERT(fixed == 1); 01064 if (arg_count == 0) 01065 return (longlong) current_thd->query_start(); 01066 if (args[0]->type() == FIELD_ITEM) 01067 { // Optimize timestamp field 01068 Field *field=((Item_field*) args[0])->field; 01069 if (field->type() == FIELD_TYPE_TIMESTAMP) 01070 return ((Field_timestamp*) field)->get_timestamp(&null_value); 01071 } 01072 01073 if (get_arg0_date(<ime, 0)) 01074 { 01075 /* 01076 We have to set null_value again because get_arg0_date will also set it 01077 to true if we have wrong datetime parameter (and we should return 0 in 01078 this case). 01079 */ 01080 null_value= args[0]->null_value; 01081 return 0; 01082 } 01083 01084 return (longlong) TIME_to_timestamp(current_thd, <ime, ¬_used); 01085 } 01086 01087 01088 longlong Item_func_time_to_sec::val_int() 01089 { 01090 DBUG_ASSERT(fixed == 1); 01091 TIME ltime; 01092 longlong seconds; 01093 (void) get_arg0_time(<ime); 01094 seconds=ltime.hour*3600L+ltime.minute*60+ltime.second; 01095 return ltime.neg ? -seconds : seconds; 01096 } 01097 01098 01099 /* 01100 Convert a string to a interval value 01101 To make code easy, allow interval objects without separators. 01102 */ 01103 01104 bool get_interval_value(Item *args,interval_type int_type, 01105 String *str_value, INTERVAL *interval) 01106 { 01107 ulonglong array[5]; 01108 longlong value; 01109 const char *str; 01110 uint32 length; 01111 CHARSET_INFO *cs=str_value->charset(); 01112 01113 LINT_INIT(value); 01114 LINT_INIT(str); 01115 LINT_INIT(length); 01116 01117 bzero((char*) interval,sizeof(*interval)); 01118 if ((int) int_type <= INTERVAL_MICROSECOND) 01119 { 01120 value= args->val_int(); 01121 if (args->null_value) 01122 return 1; 01123 if (value < 0) 01124 { 01125 interval->neg=1; 01126 value= -value; 01127 } 01128 } 01129 else 01130 { 01131 String *res; 01132 if (!(res=args->val_str(str_value))) 01133 return (1); 01134 01135 /* record negative intervalls in interval->neg */ 01136 str=res->ptr(); 01137 const char *end=str+res->length(); 01138 while (str != end && my_isspace(cs,*str)) 01139 str++; 01140 if (str != end && *str == '-') 01141 { 01142 interval->neg=1; 01143 str++; 01144 } 01145 length=(uint32) (end-str); // Set up pointers to new str 01146 } 01147 01148 switch (int_type) { 01149 case INTERVAL_YEAR: 01150 interval->year= (ulong) value; 01151 break; 01152 case INTERVAL_QUARTER: 01153 interval->month= (ulong)(value*3); 01154 break; 01155 case INTERVAL_MONTH: 01156 interval->month= (ulong) value; 01157 break; 01158 case INTERVAL_WEEK: 01159 interval->day= (ulong)(value*7); 01160 break; 01161 case INTERVAL_DAY: 01162 interval->day= (ulong) value; 01163 break; 01164 case INTERVAL_HOUR: 01165 interval->hour= (ulong) value; 01166 break; 01167 case INTERVAL_MICROSECOND: 01168 interval->second_part=value; 01169 break; 01170 case INTERVAL_MINUTE: 01171 interval->minute=value; 01172 break; 01173 case INTERVAL_SECOND: 01174 interval->second=value; 01175 break; 01176 case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM 01177 if (get_interval_info(str,length,cs,2,array,0)) 01178 return (1); 01179 interval->year= (ulong) array[0]; 01180 interval->month= (ulong) array[1]; 01181 break; 01182 case INTERVAL_DAY_HOUR: 01183 if (get_interval_info(str,length,cs,2,array,0)) 01184 return (1); 01185 interval->day= (ulong) array[0]; 01186 interval->hour= (ulong) array[1]; 01187 break; 01188 case INTERVAL_DAY_MICROSECOND: 01189 if (get_interval_info(str,length,cs,5,array,1)) 01190 return (1); 01191 interval->day= (ulong) array[0]; 01192 interval->hour= (ulong) array[1]; 01193 interval->minute= array[2]; 01194 interval->second= array[3]; 01195 interval->second_part= array[4]; 01196 break; 01197 case INTERVAL_DAY_MINUTE: 01198 if (get_interval_info(str,length,cs,3,array,0)) 01199 return (1); 01200 interval->day= (ulong) array[0]; 01201 interval->hour= (ulong) array[1]; 01202 interval->minute= array[2]; 01203 break; 01204 case INTERVAL_DAY_SECOND: 01205 if (get_interval_info(str,length,cs,4,array,0)) 01206 return (1); 01207 interval->day= (ulong) array[0]; 01208 interval->hour= (ulong) array[1]; 01209 interval->minute= array[2]; 01210 interval->second= array[3]; 01211 break; 01212 case INTERVAL_HOUR_MICROSECOND: 01213 if (get_interval_info(str,length,cs,4,array,1)) 01214 return (1); 01215 interval->hour= (ulong) array[0]; 01216 interval->minute= array[1]; 01217 interval->second= array[2]; 01218 interval->second_part= array[3]; 01219 break; 01220 case INTERVAL_HOUR_MINUTE: 01221 if (get_interval_info(str,length,cs,2,array,0)) 01222 return (1); 01223 interval->hour= (ulong) array[0]; 01224 interval->minute= array[1]; 01225 break; 01226 case INTERVAL_HOUR_SECOND: 01227 if (get_interval_info(str,length,cs,3,array,0)) 01228 return (1); 01229 interval->hour= (ulong) array[0]; 01230 interval->minute= array[1]; 01231 interval->second= array[2]; 01232 break; 01233 case INTERVAL_MINUTE_MICROSECOND: 01234 if (get_interval_info(str,length,cs,3,array,1)) 01235 return (1); 01236 interval->minute= array[0]; 01237 interval->second= array[1]; 01238 interval->second_part= array[2]; 01239 break; 01240 case INTERVAL_MINUTE_SECOND: 01241 if (get_interval_info(str,length,cs,2,array,0)) 01242 return (1); 01243 interval->minute= array[0]; 01244 interval->second= array[1]; 01245 break; 01246 case INTERVAL_SECOND_MICROSECOND: 01247 if (get_interval_info(str,length,cs,2,array,1)) 01248 return (1); 01249 interval->second= array[0]; 01250 interval->second_part= array[1]; 01251 break; 01252 } 01253 return 0; 01254 } 01255 01256 01257 String *Item_date::val_str(String *str) 01258 { 01259 DBUG_ASSERT(fixed == 1); 01260 TIME ltime; 01261 if (get_date(<ime, TIME_FUZZY_DATE)) 01262 return (String *) 0; 01263 if (str->alloc(11)) 01264 { 01265 null_value= 1; 01266 return (String *) 0; 01267 } 01268 make_date((DATE_TIME_FORMAT *) 0, <ime, str); 01269 return str; 01270 } 01271 01272 01273 int Item_date::save_in_field(Field *field, bool no_conversions) 01274 { 01275 TIME ltime; 01276 if (get_date(<ime, TIME_FUZZY_DATE)) 01277 return set_field_to_null(field); 01278 field->set_notnull(); 01279 field->store_time(<ime, MYSQL_TIMESTAMP_DATE); 01280 return 0; 01281 } 01282 01283 01284 longlong Item_date::val_int() 01285 { 01286 DBUG_ASSERT(fixed == 1); 01287 TIME ltime; 01288 if (get_date(<ime, TIME_FUZZY_DATE)) 01289 return 0; 01290 return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day); 01291 } 01292 01293 01294 bool Item_func_from_days::get_date(TIME *ltime, uint fuzzy_date) 01295 { 01296 longlong value=args[0]->val_int(); 01297 if ((null_value=args[0]->null_value)) 01298 return 1; 01299 bzero(ltime, sizeof(TIME)); 01300 get_date_from_daynr((long) value, <ime->year, <ime->month, <ime->day); 01301 ltime->time_type= MYSQL_TIMESTAMP_DATE; 01302 return 0; 01303 } 01304 01305 01306 void Item_func_curdate::fix_length_and_dec() 01307 { 01308 collation.set(&my_charset_bin); 01309 decimals=0; 01310 max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 01311 01312 store_now_in_TIME(<ime); 01313 01314 /* We don't need to set second_part and neg because they already 0 */ 01315 ltime.hour= ltime.minute= ltime.second= 0; 01316 ltime.time_type= MYSQL_TIMESTAMP_DATE; 01317 value= (longlong) TIME_to_ulonglong_date(<ime); 01318 } 01319 01320 String *Item_func_curdate::val_str(String *str) 01321 { 01322 DBUG_ASSERT(fixed == 1); 01323 if (str->alloc(11)) 01324 { 01325 null_value= 1; 01326 return (String *) 0; 01327 } 01328 make_date((DATE_TIME_FORMAT *) 0, <ime, str); 01329 return str; 01330 } 01331 01332 /* 01333 Converts current time in my_time_t to TIME represenatation for local 01334 time zone. Defines time zone (local) used for whole CURDATE function. 01335 */ 01336 void Item_func_curdate_local::store_now_in_TIME(TIME *now_time) 01337 { 01338 THD *thd= current_thd; 01339 thd->variables.time_zone->gmt_sec_to_TIME(now_time, 01340 (my_time_t)thd->query_start()); 01341 thd->time_zone_used= 1; 01342 } 01343 01344 01345 /* 01346 Converts current time in my_time_t to TIME represenatation for UTC 01347 time zone. Defines time zone (UTC) used for whole UTC_DATE function. 01348 */ 01349 void Item_func_curdate_utc::store_now_in_TIME(TIME *now_time) 01350 { 01351 my_tz_UTC->gmt_sec_to_TIME(now_time, 01352 (my_time_t)(current_thd->query_start())); 01353 /* 01354 We are not flagging this query as using time zone, since it uses fixed 01355 UTC-SYSTEM time-zone. 01356 */ 01357 } 01358 01359 01360 bool Item_func_curdate::get_date(TIME *res, 01361 uint fuzzy_date __attribute__((unused))) 01362 { 01363 *res=ltime; 01364 return 0; 01365 } 01366 01367 01368 String *Item_func_curtime::val_str(String *str) 01369 { 01370 DBUG_ASSERT(fixed == 1); 01371 str_value.set(buff, buff_length, &my_charset_bin); 01372 return &str_value; 01373 } 01374 01375 01376 void Item_func_curtime::fix_length_and_dec() 01377 { 01378 TIME ltime; 01379 01380 decimals= DATETIME_DEC; 01381 collation.set(&my_charset_bin); 01382 store_now_in_TIME(<ime); 01383 value= TIME_to_ulonglong_time(<ime); 01384 buff_length= (uint) my_time_to_str(<ime, buff); 01385 max_length= buff_length; 01386 } 01387 01388 01389 /* 01390 Converts current time in my_time_t to TIME represenatation for local 01391 time zone. Defines time zone (local) used for whole CURTIME function. 01392 */ 01393 void Item_func_curtime_local::store_now_in_TIME(TIME *now_time) 01394 { 01395 THD *thd= current_thd; 01396 thd->variables.time_zone->gmt_sec_to_TIME(now_time, 01397 (my_time_t)thd->query_start()); 01398 thd->time_zone_used= 1; 01399 } 01400 01401 01402 /* 01403 Converts current time in my_time_t to TIME represenatation for UTC 01404 time zone. Defines time zone (UTC) used for whole UTC_TIME function. 01405 */ 01406 void Item_func_curtime_utc::store_now_in_TIME(TIME *now_time) 01407 { 01408 my_tz_UTC->gmt_sec_to_TIME(now_time, 01409 (my_time_t)(current_thd->query_start())); 01410 /* 01411 We are not flagging this query as using time zone, since it uses fixed 01412 UTC-SYSTEM time-zone. 01413 */ 01414 } 01415 01416 01417 String *Item_func_now::val_str(String *str) 01418 { 01419 DBUG_ASSERT(fixed == 1); 01420 str_value.set(buff,buff_length, &my_charset_bin); 01421 return &str_value; 01422 } 01423 01424 01425 void Item_func_now::fix_length_and_dec() 01426 { 01427 decimals= DATETIME_DEC; 01428 collation.set(&my_charset_bin); 01429 01430 store_now_in_TIME(<ime); 01431 value= (longlong) TIME_to_ulonglong_datetime(<ime); 01432 01433 buff_length= (uint) my_datetime_to_str(<ime, buff); 01434 max_length= buff_length; 01435 } 01436 01437 01438 /* 01439 Converts current time in my_time_t to TIME represenatation for local 01440 time zone. Defines time zone (local) used for whole NOW function. 01441 */ 01442 void Item_func_now_local::store_now_in_TIME(TIME *now_time) 01443 { 01444 THD *thd= current_thd; 01445 thd->variables.time_zone->gmt_sec_to_TIME(now_time, 01446 (my_time_t)thd->query_start()); 01447 thd->time_zone_used= 1; 01448 } 01449 01450 01451 /* 01452 Converts current time in my_time_t to TIME represenatation for UTC 01453 time zone. Defines time zone (UTC) used for whole UTC_TIMESTAMP function. 01454 */ 01455 void Item_func_now_utc::store_now_in_TIME(TIME *now_time) 01456 { 01457 my_tz_UTC->gmt_sec_to_TIME(now_time, 01458 (my_time_t)(current_thd->query_start())); 01459 /* 01460 We are not flagging this query as using time zone, since it uses fixed 01461 UTC-SYSTEM time-zone. 01462 */ 01463 } 01464 01465 01466 bool Item_func_now::get_date(TIME *res, 01467 uint fuzzy_date __attribute__((unused))) 01468 { 01469 *res= ltime; 01470 return 0; 01471 } 01472 01473 01474 int Item_func_now::save_in_field(Field *to, bool no_conversions) 01475 { 01476 to->set_notnull(); 01477 to->store_time(<ime, MYSQL_TIMESTAMP_DATETIME); 01478 return 0; 01479 } 01480 01481 01482 /* 01483 Converts current time in my_time_t to TIME represenatation for local 01484 time zone. Defines time zone (local) used for whole SYSDATE function. 01485 */ 01486 void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time) 01487 { 01488 THD *thd= current_thd; 01489 thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL)); 01490 thd->time_zone_used= 1; 01491 } 01492 01493 01494 String *Item_func_sysdate_local::val_str(String *str) 01495 { 01496 DBUG_ASSERT(fixed == 1); 01497 store_now_in_TIME(<ime); 01498 buff_length= (uint) my_datetime_to_str(<ime, buff); 01499 str_value.set(buff, buff_length, &my_charset_bin); 01500 return &str_value; 01501 } 01502 01503 01504 longlong Item_func_sysdate_local::val_int() 01505 { 01506 DBUG_ASSERT(fixed == 1); 01507 store_now_in_TIME(<ime); 01508 return (longlong) TIME_to_ulonglong_datetime(<ime); 01509 } 01510 01511 01512 double Item_func_sysdate_local::val_real() 01513 { 01514 DBUG_ASSERT(fixed == 1); 01515 store_now_in_TIME(<ime); 01516 return ulonglong2double(TIME_to_ulonglong_datetime(<ime)); 01517 } 01518 01519 01520 void Item_func_sysdate_local::fix_length_and_dec() 01521 { 01522 decimals= 0; 01523 collation.set(&my_charset_bin); 01524 max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 01525 } 01526 01527 01528 bool Item_func_sysdate_local::get_date(TIME *res, 01529 uint fuzzy_date __attribute__((unused))) 01530 { 01531 store_now_in_TIME(<ime); 01532 *res= ltime; 01533 return 0; 01534 } 01535 01536 01537 int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions) 01538 { 01539 store_now_in_TIME(<ime); 01540 to->set_notnull(); 01541 to->store_time(<ime, MYSQL_TIMESTAMP_DATETIME); 01542 return 0; 01543 } 01544 01545 01546 String *Item_func_sec_to_time::val_str(String *str) 01547 { 01548 DBUG_ASSERT(fixed == 1); 01549 longlong seconds=(longlong) args[0]->val_int(); 01550 uint sec; 01551 TIME ltime; 01552 01553 if ((null_value=args[0]->null_value) || str->alloc(19)) 01554 { 01555 null_value= 1; 01556 return (String*) 0; 01557 } 01558 01559 ltime.neg= 0; 01560 if (seconds < 0) 01561 { 01562 seconds= -seconds; 01563 ltime.neg= 1; 01564 } 01565 01566 sec= (uint) ((ulonglong) seconds % 3600); 01567 ltime.day= 0; 01568 ltime.hour= (uint) (seconds/3600); 01569 ltime.minute= sec/60; 01570 ltime.second= sec % 60; 01571 01572 make_time((DATE_TIME_FORMAT *) 0, <ime, str); 01573 return str; 01574 } 01575 01576 01577 longlong Item_func_sec_to_time::val_int() 01578 { 01579 DBUG_ASSERT(fixed == 1); 01580 longlong seconds=args[0]->val_int(); 01581 longlong sign=1; 01582 if ((null_value=args[0]->null_value)) 01583 return 0; 01584 if (seconds < 0) 01585 { 01586 seconds= -seconds; 01587 sign= -1; 01588 } 01589 return sign*((seconds / 3600)*10000+((seconds/60) % 60)*100+ (seconds % 60)); 01590 } 01591 01592 01593 void Item_func_date_format::fix_length_and_dec() 01594 { 01595 /* 01596 Must use this_item() in case it's a local SP variable 01597 (for ->max_length and ->str_value) 01598 */ 01599 Item *arg1= args[1]->this_item(); 01600 01601 decimals=0; 01602 collation.set(&my_charset_bin); 01603 if (arg1->type() == STRING_ITEM) 01604 { // Optimize the normal case 01605 fixed_length=1; 01606 01607 /* 01608 The result is a binary string (no reason to use collation->mbmaxlen 01609 This is becasue make_date_time() only returns binary strings 01610 */ 01611 max_length= format_length(&arg1->str_value); 01612 } 01613 else 01614 { 01615 fixed_length=0; 01616 /* The result is a binary string (no reason to use collation->mbmaxlen */ 01617 max_length=min(arg1->max_length, MAX_BLOB_WIDTH) * 10; 01618 set_if_smaller(max_length,MAX_BLOB_WIDTH); 01619 } 01620 maybe_null=1; // If wrong date 01621 } 01622 01623 01624 bool Item_func_date_format::eq(const Item *item, bool binary_cmp) const 01625 { 01626 Item_func_date_format *item_func; 01627 01628 if (item->type() != FUNC_ITEM) 01629 return 0; 01630 if (func_name() != ((Item_func*) item)->func_name()) 01631 return 0; 01632 if (this == item) 01633 return 1; 01634 item_func= (Item_func_date_format*) item; 01635 if (!args[0]->eq(item_func->args[0], binary_cmp)) 01636 return 0; 01637 /* 01638 We must compare format string case sensitive. 01639 This needed because format modifiers with different case, 01640 for example %m and %M, have different meaning. 01641 */ 01642 if (!args[1]->eq(item_func->args[1], 1)) 01643 return 0; 01644 return 1; 01645 } 01646 01647 01648 01649 uint Item_func_date_format::format_length(const String *format) 01650 { 01651 uint size=0; 01652 const char *ptr=format->ptr(); 01653 const char *end=ptr+format->length(); 01654 01655 for (; ptr != end ; ptr++) 01656 { 01657 if (*ptr != '%' || ptr == end-1) 01658 size++; 01659 else 01660 { 01661 switch(*++ptr) { 01662 case 'M': /* month, textual */ 01663 case 'W': /* day (of the week), textual */ 01664 size += 64; /* large for UTF8 locale data */ 01665 break; 01666 case 'D': /* day (of the month), numeric plus english suffix */ 01667 case 'Y': /* year, numeric, 4 digits */ 01668 case 'x': /* Year, used with 'v' */ 01669 case 'X': /* Year, used with 'v, where week starts with Monday' */ 01670 size += 4; 01671 break; 01672 case 'a': /* locale's abbreviated weekday name (Sun..Sat) */ 01673 case 'b': /* locale's abbreviated month name (Jan.Dec) */ 01674 size += 32; /* large for UTF8 locale data */ 01675 break; 01676 case 'j': /* day of year (001..366) */ 01677 size += 3; 01678 break; 01679 case 'U': /* week (00..52) */ 01680 case 'u': /* week (00..52), where week starts with Monday */ 01681 case 'V': /* week 1..53 used with 'x' */ 01682 case 'v': /* week 1..53 used with 'x', where week starts with Monday */ 01683 case 'y': /* year, numeric, 2 digits */ 01684 case 'm': /* month, numeric */ 01685 case 'd': /* day (of the month), numeric */ 01686 case 'h': /* hour (01..12) */ 01687 case 'I': /* --||-- */ 01688 case 'i': /* minutes, numeric */ 01689 case 'l': /* hour ( 1..12) */ 01690 case 'p': /* locale's AM or PM */ 01691 case 'S': /* second (00..61) */ 01692 case 's': /* seconds, numeric */ 01693 case 'c': /* month (0..12) */ 01694 case 'e': /* day (0..31) */ 01695 size += 2; 01696 break; 01697 case 'k': /* hour ( 0..23) */ 01698 case 'H': /* hour (00..23; value > 23 OK, padding always 2-digit) */ 01699 size += 7; /* docs allow > 23, range depends on sizeof(unsigned int) */ 01700 break; 01701 case 'r': /* time, 12-hour (hh:mm:ss [AP]M) */ 01702 size += 11; 01703 break; 01704 case 'T': /* time, 24-hour (hh:mm:ss) */ 01705 size += 8; 01706 break; 01707 case 'f': /* microseconds */ 01708 size += 6; 01709 break; 01710 case 'w': /* day (of the week), numeric */ 01711 case '%': 01712 default: 01713 size++; 01714 break; 01715 } 01716 } 01717 } 01718 return size; 01719 } 01720 01721 01722 String *Item_func_date_format::val_str(String *str) 01723 { 01724 String *format; 01725 TIME l_time; 01726 uint size; 01727 DBUG_ASSERT(fixed == 1); 01728 01729 if (!is_time_format) 01730 { 01731 if (get_arg0_date(&l_time, TIME_FUZZY_DATE)) 01732 return 0; 01733 } 01734 else 01735 { 01736 String *res; 01737 if (!(res=args[0]->val_str(str)) || 01738 (str_to_time_with_warn(res->ptr(), res->length(), &l_time))) 01739 goto null_date; 01740 01741 l_time.year=l_time.month=l_time.day=0; 01742 null_value=0; 01743 } 01744 01745 if (!(format = args[1]->val_str(str)) || !format->length()) 01746 goto null_date; 01747 01748 if (fixed_length) 01749 size=max_length; 01750 else 01751 size=format_length(format); 01752 if (format == str) 01753 str= &value; // Save result here 01754 if (str->alloc(size)) 01755 goto null_date; 01756 01757 DATE_TIME_FORMAT date_time_format; 01758 date_time_format.format.str= (char*) format->ptr(); 01759 date_time_format.format.length= format->length(); 01760 01761 /* Create the result string */ 01762 if (!make_date_time(&date_time_format, &l_time, 01763 is_time_format ? MYSQL_TIMESTAMP_TIME : 01764 MYSQL_TIMESTAMP_DATE, 01765 str)) 01766 return str; 01767 01768 null_date: 01769 null_value=1; 01770 return 0; 01771 } 01772 01773 01774 void Item_func_from_unixtime::fix_length_and_dec() 01775 { 01776 thd= current_thd; 01777 collation.set(&my_charset_bin); 01778 decimals= DATETIME_DEC; 01779 max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 01780 maybe_null= 1; 01781 thd->time_zone_used= 1; 01782 } 01783 01784 01785 String *Item_func_from_unixtime::val_str(String *str) 01786 { 01787 TIME time_tmp; 01788 01789 DBUG_ASSERT(fixed == 1); 01790 01791 if (get_date(&time_tmp, 0)) 01792 return 0; 01793 01794 if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) 01795 { 01796 null_value= 1; 01797 return 0; 01798 } 01799 01800 make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str); 01801 return str; 01802 } 01803 01804 01805 longlong Item_func_from_unixtime::val_int() 01806 { 01807 TIME time_tmp; 01808 01809 DBUG_ASSERT(fixed == 1); 01810 01811 if (get_date(&time_tmp, 0)) 01812 return 0; 01813 01814 return (longlong) TIME_to_ulonglong_datetime(&time_tmp); 01815 } 01816 01817 bool Item_func_from_unixtime::get_date(TIME *ltime, 01818 uint fuzzy_date __attribute__((unused))) 01819 { 01820 ulonglong tmp= (ulonglong)(args[0]->val_int()); 01821 /* 01822 "tmp > TIMESTAMP_MAX_VALUE" check also covers case of negative 01823 from_unixtime() argument since tmp is unsigned. 01824 */ 01825 if ((null_value= (args[0]->null_value || tmp > TIMESTAMP_MAX_VALUE))) 01826 return 1; 01827 01828 thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)tmp); 01829 01830 return 0; 01831 } 01832 01833 01834 void Item_func_convert_tz::fix_length_and_dec() 01835 { 01836 collation.set(&my_charset_bin); 01837 decimals= 0; 01838 max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 01839 maybe_null= 1; 01840 } 01841 01842 01843 bool 01844 Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref) 01845 { 01846 String str; 01847 if (Item_date_func::fix_fields(thd_arg, ref)) 01848 return TRUE; 01849 01850 tz_tables= thd_arg->lex->time_zone_tables_used; 01851 01852 return FALSE; 01853 } 01854 01855 01856 String *Item_func_convert_tz::val_str(String *str) 01857 { 01858 TIME time_tmp; 01859 01860 if (get_date(&time_tmp, 0)) 01861 return 0; 01862 01863 if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) 01864 { 01865 null_value= 1; 01866 return 0; 01867 } 01868 01869 make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str); 01870 return str; 01871 } 01872 01873 01874 longlong Item_func_convert_tz::val_int() 01875 { 01876 TIME time_tmp; 01877 01878 if (get_date(&time_tmp, 0)) 01879 return 0; 01880 01881 return (longlong)TIME_to_ulonglong_datetime(&time_tmp); 01882 } 01883 01884 01885 bool Item_func_convert_tz::get_date(TIME *ltime, 01886 uint fuzzy_date __attribute__((unused))) 01887 { 01888 my_time_t my_time_tmp; 01889 String str; 01890 01891 if (!from_tz_cached) 01892 { 01893 from_tz= my_tz_find(args[1]->val_str(&str), tz_tables); 01894 from_tz_cached= args[1]->const_item(); 01895 } 01896 01897 if (!to_tz_cached) 01898 { 01899 to_tz= my_tz_find(args[2]->val_str(&str), tz_tables); 01900 to_tz_cached= args[2]->const_item(); 01901 } 01902 01903 if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, TIME_NO_ZERO_DATE)) 01904 { 01905 null_value= 1; 01906 return 1; 01907 } 01908 01909 /* Check if we in range where we treat datetime values as non-UTC */ 01910 if (ltime->year < TIMESTAMP_MAX_YEAR && ltime->year > TIMESTAMP_MIN_YEAR || 01911 ltime->year==TIMESTAMP_MAX_YEAR && ltime->month==1 && ltime->day==1 || 01912 ltime->year==TIMESTAMP_MIN_YEAR && ltime->month==12 && ltime->day==31) 01913 { 01914 my_bool not_used; 01915 my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, ¬_used); 01916 if (my_time_tmp >= TIMESTAMP_MIN_VALUE && my_time_tmp <= TIMESTAMP_MAX_VALUE) 01917 to_tz->gmt_sec_to_TIME(ltime, my_time_tmp); 01918 } 01919 01920 null_value= 0; 01921 return 0; 01922 } 01923 01924 01925 void Item_func_convert_tz::cleanup() 01926 { 01927 from_tz_cached= to_tz_cached= 0; 01928 Item_date_func::cleanup(); 01929 } 01930 01931 01932 void Item_date_add_interval::fix_length_and_dec() 01933 { 01934 enum_field_types arg0_field_type; 01935 01936 collation.set(&my_charset_bin); 01937 maybe_null=1; 01938 max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 01939 value.alloc(max_length); 01940 01941 /* 01942 The field type for the result of an Item_date function is defined as 01943 follows: 01944 01945 - If first arg is a MYSQL_TYPE_DATETIME result is MYSQL_TYPE_DATETIME 01946 - If first arg is a MYSQL_TYPE_DATE and the interval type uses hours, 01947 minutes or seconds then type is MYSQL_TYPE_DATETIME. 01948 - Otherwise the result is MYSQL_TYPE_STRING 01949 (This is because you can't know if the string contains a DATE, TIME or 01950 DATETIME argument) 01951 */ 01952 cached_field_type= MYSQL_TYPE_STRING; 01953 arg0_field_type= args[0]->field_type(); 01954 if (arg0_field_type == MYSQL_TYPE_DATETIME || 01955 arg0_field_type == MYSQL_TYPE_TIMESTAMP) 01956 cached_field_type= MYSQL_TYPE_DATETIME; 01957 else if (arg0_field_type == MYSQL_TYPE_DATE) 01958 { 01959 if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) 01960 cached_field_type= arg0_field_type; 01961 else 01962 cached_field_type= MYSQL_TYPE_DATETIME; 01963 } 01964 } 01965 01966 01967 /* Here arg[1] is a Item_interval object */ 01968 01969 bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) 01970 { 01971 INTERVAL interval; 01972 01973 if (args[0]->get_date(ltime, TIME_NO_ZERO_DATE) || 01974 get_interval_value(args[1], int_type, &value, &interval)) 01975 return (null_value=1); 01976 01977 if (date_sub_interval) 01978 interval.neg = !interval.neg; 01979 if (ltime->year < YY_MAGIC_BELOW) 01980 return (null_value=1); 01981 01982 return (null_value= date_add_interval(ltime, int_type, interval)); 01983 } 01984 01985 01986 String *Item_date_add_interval::val_str(String *str) 01987 { 01988 DBUG_ASSERT(fixed == 1); 01989 TIME ltime; 01990 enum date_time_format_types format; 01991 01992 if (Item_date_add_interval::get_date(<ime, TIME_NO_ZERO_DATE)) 01993 return 0; 01994 01995 if (ltime.time_type == MYSQL_TIMESTAMP_DATE) 01996 format= DATE_ONLY; 01997 else if (ltime.second_part) 01998 format= DATE_TIME_MICROSECOND; 01999 else 02000 format= DATE_TIME; 02001 02002 if (!make_datetime(format, <ime, str)) 02003 return str; 02004 02005 null_value=1; 02006 return 0; 02007 } 02008 02009 02010 longlong Item_date_add_interval::val_int() 02011 { 02012 DBUG_ASSERT(fixed == 1); 02013 TIME ltime; 02014 longlong date; 02015 if (Item_date_add_interval::get_date(<ime, TIME_NO_ZERO_DATE)) 02016 return (longlong) 0; 02017 date = (ltime.year*100L + ltime.month)*100L + ltime.day; 02018 return ltime.time_type == MYSQL_TIMESTAMP_DATE ? date : 02019 ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second; 02020 } 02021 02022 02023 02024 bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const 02025 { 02026 Item_date_add_interval *other= (Item_date_add_interval*) item; 02027 if (!Item_func::eq(item, binary_cmp)) 02028 return 0; 02029 return ((int_type == other->int_type) && 02030 (date_sub_interval == other->date_sub_interval)); 02031 } 02032 02033 02034 static const char *interval_names[]= 02035 { 02036 "year", "quarter", "month", "day", "hour", 02037 "minute", "week", "second", "microsecond", 02038 "year_month", "day_hour", "day_minute", 02039 "day_second", "hour_minute", "hour_second", 02040 "minute_second", "day_microsecond", 02041 "hour_microsecond", "minute_microsecond", 02042 "second_microsecond" 02043 }; 02044 02045 void Item_date_add_interval::print(String *str) 02046 { 02047 str->append('('); 02048 args[0]->print(str); 02049 str->append(date_sub_interval?" - interval ":" + interval "); 02050 args[1]->print(str); 02051 str->append(' '); 02052 str->append(interval_names[int_type]); 02053 str->append(')'); 02054 } 02055 02056 void Item_extract::print(String *str) 02057 { 02058 str->append(STRING_WITH_LEN("extract(")); 02059 str->append(interval_names[int_type]); 02060 str->append(STRING_WITH_LEN(" from ")); 02061 args[0]->print(str); 02062 str->append(')'); 02063 } 02064 02065 void Item_extract::fix_length_and_dec() 02066 { 02067 value.alloc(32); // alloc buffer 02068 02069 maybe_null=1; // If wrong date 02070 switch (int_type) { 02071 case INTERVAL_YEAR: max_length=4; date_value=1; break; 02072 case INTERVAL_YEAR_MONTH: max_length=6; date_value=1; break; 02073 case INTERVAL_QUARTER: max_length=2; date_value=1; break; 02074 case INTERVAL_MONTH: max_length=2; date_value=1; break; 02075 case INTERVAL_WEEK: max_length=2; date_value=1; break; 02076 case INTERVAL_DAY: max_length=2; date_value=1; break; 02077 case INTERVAL_DAY_HOUR: max_length=9; date_value=0; break; 02078 case INTERVAL_DAY_MINUTE: max_length=11; date_value=0; break; 02079 case INTERVAL_DAY_SECOND: max_length=13; date_value=0; break; 02080 case INTERVAL_HOUR: max_length=2; date_value=0; break; 02081 case INTERVAL_HOUR_MINUTE: max_length=4; date_value=0; break; 02082 case INTERVAL_HOUR_SECOND: max_length=6; date_value=0; break; 02083 case INTERVAL_MINUTE: max_length=2; date_value=0; break; 02084 case INTERVAL_MINUTE_SECOND: max_length=4; date_value=0; break; 02085 case INTERVAL_SECOND: max_length=2; date_value=0; break; 02086 case INTERVAL_MICROSECOND: max_length=2; date_value=0; break; 02087 case INTERVAL_DAY_MICROSECOND: max_length=20; date_value=0; break; 02088 case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break; 02089 case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break; 02090 case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break; 02091 } 02092 } 02093 02094 02095 longlong Item_extract::val_int() 02096 { 02097 DBUG_ASSERT(fixed == 1); 02098 TIME ltime; 02099 uint year; 02100 ulong week_format; 02101 long neg; 02102 if (date_value) 02103 { 02104 if (get_arg0_date(<ime, TIME_FUZZY_DATE)) 02105 return 0; 02106 neg=1; 02107 } 02108 else 02109 { 02110 String *res= args[0]->val_str(&value); 02111 if (!res || str_to_time_with_warn(res->ptr(), res->length(), <ime)) 02112 { 02113 null_value=1; 02114 return 0; 02115 } 02116 neg= ltime.neg ? -1 : 1; 02117 null_value=0; 02118 } 02119 switch (int_type) { 02120 case INTERVAL_YEAR: return ltime.year; 02121 case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month; 02122 case INTERVAL_QUARTER: return (ltime.month+2)/3; 02123 case INTERVAL_MONTH: return ltime.month; 02124 case INTERVAL_WEEK: 02125 { 02126 week_format= current_thd->variables.default_week_format; 02127 return calc_week(<ime, week_mode(week_format), &year); 02128 } 02129 case INTERVAL_DAY: return ltime.day; 02130 case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg; 02131 case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+ 02132 ltime.hour*100L+ 02133 ltime.minute)*neg; 02134 case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+ 02135 (longlong) (ltime.hour*10000L+ 02136 ltime.minute*100+ 02137 ltime.second))*neg; 02138 case INTERVAL_HOUR: return (long) ltime.hour*neg; 02139 case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg; 02140 case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+ 02141 ltime.second)*neg; 02142 case INTERVAL_MINUTE: return (long) ltime.minute*neg; 02143 case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg; 02144 case INTERVAL_SECOND: return (long) ltime.second*neg; 02145 case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg; 02146 case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L + 02147 (longlong)ltime.hour*10000L + 02148 ltime.minute*100 + 02149 ltime.second)*1000000L + 02150 ltime.second_part)*neg; 02151 case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L + 02152 ltime.minute*100 + 02153 ltime.second)*1000000L + 02154 ltime.second_part)*neg; 02155 case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+ 02156 ltime.second))*1000000L+ 02157 ltime.second_part)*neg; 02158 case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+ 02159 ltime.second_part)*neg; 02160 } 02161 return 0; // Impossible 02162 } 02163 02164 bool Item_extract::eq(const Item *item, bool binary_cmp) const 02165 { 02166 if (this == item) 02167 return 1; 02168 if (item->type() != FUNC_ITEM || 02169 functype() != ((Item_func*)item)->functype()) 02170 return 0; 02171 02172 Item_extract* ie= (Item_extract*)item; 02173 if (ie->int_type != int_type) 02174 return 0; 02175 02176 if (!args[0]->eq(ie->args[0], binary_cmp)) 02177 return 0; 02178 return 1; 02179 } 02180 02181 02182 bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const 02183 { 02184 if (this == item) 02185 return 1; 02186 if (item->type() != FUNC_ITEM || 02187 functype() != ((Item_func*)item)->functype()) 02188 return 0; 02189 02190 Item_char_typecast *cast= (Item_char_typecast*)item; 02191 if (cast_length != cast->cast_length || 02192 cast_cs != cast->cast_cs) 02193 return 0; 02194 02195 if (!args[0]->eq(cast->args[0], binary_cmp)) 02196 return 0; 02197 return 1; 02198 } 02199 02200 void Item_typecast::print(String *str) 02201 { 02202 str->append(STRING_WITH_LEN("cast(")); 02203 args[0]->print(str); 02204 str->append(STRING_WITH_LEN(" as ")); 02205 str->append(cast_type()); 02206 str->append(')'); 02207 } 02208 02209 02210 void Item_char_typecast::print(String *str) 02211 { 02212 str->append(STRING_WITH_LEN("cast(")); 02213 args[0]->print(str); 02214 str->append(STRING_WITH_LEN(" as char")); 02215 if (cast_length >= 0) 02216 { 02217 str->append('('); 02218 char buffer[20]; 02219 // my_charset_bin is good enough for numbers 02220 String st(buffer, sizeof(buffer), &my_charset_bin); 02221 st.set((ulonglong)cast_length, &my_charset_bin); 02222 str->append(st); 02223 str->append(')'); 02224 } 02225 if (cast_cs) 02226 { 02227 str->append(STRING_WITH_LEN(" charset ")); 02228 str->append(cast_cs->csname); 02229 } 02230 str->append(')'); 02231 } 02232 02233 String *Item_char_typecast::val_str(String *str) 02234 { 02235 DBUG_ASSERT(fixed == 1); 02236 String *res; 02237 uint32 length; 02238 02239 if (!charset_conversion) 02240 { 02241 if (!(res= args[0]->val_str(str))) 02242 { 02243 null_value= 1; 02244 return 0; 02245 } 02246 } 02247 else 02248 { 02249 // Convert character set if differ 02250 uint dummy_errors; 02251 if (!(res= args[0]->val_str(&tmp_value)) || 02252 str->copy(res->ptr(), res->length(), from_cs, 02253 cast_cs, &dummy_errors)) 02254 { 02255 null_value= 1; 02256 return 0; 02257 } 02258 res= str; 02259 } 02260 02261 res->set_charset(cast_cs); 02262 02263 /* 02264 Cut the tail if cast with length 02265 and the result is longer than cast length, e.g. 02266 CAST('string' AS CHAR(1)) 02267 */ 02268 if (cast_length >= 0) 02269 { 02270 if (res->length() > (length= (uint32) res->charpos(cast_length))) 02271 { // Safe even if const arg 02272 char char_type[40]; 02273 my_snprintf(char_type, sizeof(char_type), "%s(%lu)", 02274 cast_cs == &my_charset_bin ? "BINARY" : "CHAR", length); 02275 02276 if (!res->alloced_length()) 02277 { // Don't change const str 02278 str_value= *res; // Not malloced string 02279 res= &str_value; 02280 } 02281 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, 02282 ER_TRUNCATED_WRONG_VALUE, 02283 ER(ER_TRUNCATED_WRONG_VALUE), char_type, 02284 res->c_ptr_safe()); 02285 res->length((uint) length); 02286 } 02287 else if (cast_cs == &my_charset_bin && res->length() < (uint) cast_length) 02288 { 02289 if (res->alloced_length() < (uint) cast_length) 02290 { 02291 str->alloc(cast_length); 02292 str->copy(*res); 02293 res= str; 02294 } 02295 bzero((char*) res->ptr() + res->length(), 02296 (uint) cast_length - res->length()); 02297 res->length(cast_length); 02298 } 02299 } 02300 null_value= 0; 02301 return res; 02302 } 02303 02304 02305 void Item_char_typecast::fix_length_and_dec() 02306 { 02307 uint32 char_length; 02308 /* 02309 We always force character set conversion if cast_cs 02310 is a multi-byte character set. It garantees that the 02311 result of CAST is a well-formed string. 02312 For single-byte character sets we allow just to copy 02313 from the argument. A single-byte character sets string 02314 is always well-formed. 02315 02316 There is a special trick to convert form a number to ucs2. 02317 As numbers have my_charset_bin as their character set, 02318 it wouldn't do conversion to ucs2 without an additional action. 02319 To force conversion, we should pretend to be non-binary. 02320 Let's choose from_cs this way: 02321 - If the argument in a number and cast_cs is ucs2 (i.e. mbminlen > 1), 02322 then from_cs is set to latin1, to perform latin1 -> ucs2 conversion. 02323 - If the argument is a number and cast_cs is ASCII-compatible 02324 (i.e. mbminlen == 1), then from_cs is set to cast_cs, 02325 which allows just to take over the args[0]->val_str() result 02326 and thus avoid unnecessary character set conversion. 02327 - If the argument is not a number, then from_cs is set to 02328 the argument's charset. 02329 */ 02330 from_cs= (args[0]->result_type() == INT_RESULT || 02331 args[0]->result_type() == DECIMAL_RESULT || 02332 args[0]->result_type() == REAL_RESULT) ? 02333 (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) : 02334 args[0]->collation.collation; 02335 charset_conversion= (cast_cs->mbmaxlen > 1) || 02336 !my_charset_same(from_cs, cast_cs) && 02337 from_cs != &my_charset_bin && 02338 cast_cs != &my_charset_bin; 02339 collation.set(cast_cs, DERIVATION_IMPLICIT); 02340 char_length= (cast_length >= 0) ? cast_length : 02341 args[0]->max_length/from_cs->mbmaxlen; 02342 max_length= char_length * cast_cs->mbmaxlen; 02343 } 02344 02345 02346 String *Item_datetime_typecast::val_str(String *str) 02347 { 02348 DBUG_ASSERT(fixed == 1); 02349 TIME ltime; 02350 if (!get_arg0_date(<ime, TIME_FUZZY_DATE) && 02351 !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, 02352 <ime, str)) 02353 return str; 02354 02355 null_value=1; 02356 return 0; 02357 } 02358 02359 02360 longlong Item_datetime_typecast::val_int() 02361 { 02362 DBUG_ASSERT(fixed == 1); 02363 TIME ltime; 02364 if (get_arg0_date(<ime,1)) 02365 { 02366 null_value= 1; 02367 return 0; 02368 } 02369 02370 return TIME_to_ulonglong_datetime(<ime); 02371 } 02372 02373 02374 bool Item_time_typecast::get_time(TIME *ltime) 02375 { 02376 bool res= get_arg0_time(ltime); 02377 /* 02378 For MYSQL_TIMESTAMP_TIME value we can have non-zero day part, 02379 which we should not lose. 02380 */ 02381 if (ltime->time_type == MYSQL_TIMESTAMP_DATETIME) 02382 ltime->year= ltime->month= ltime->day= 0; 02383 ltime->time_type= MYSQL_TIMESTAMP_TIME; 02384 return res; 02385 } 02386 02387 02388 longlong Item_time_typecast::val_int() 02389 { 02390 TIME ltime; 02391 if (get_time(<ime)) 02392 { 02393 null_value= 1; 02394 return 0; 02395 } 02396 return ltime.hour * 10000L + ltime.minute * 100 + ltime.second; 02397 } 02398 02399 String *Item_time_typecast::val_str(String *str) 02400 { 02401 DBUG_ASSERT(fixed == 1); 02402 TIME ltime; 02403 02404 if (!get_arg0_time(<ime) && 02405 !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY, 02406 <ime, str)) 02407 return str; 02408 02409 null_value=1; 02410 return 0; 02411 } 02412 02413 02414 bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date) 02415 { 02416 bool res= get_arg0_date(ltime, TIME_FUZZY_DATE); 02417 ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; 02418 ltime->time_type= MYSQL_TIMESTAMP_DATE; 02419 return res; 02420 } 02421 02422 02423 String *Item_date_typecast::val_str(String *str) 02424 { 02425 DBUG_ASSERT(fixed == 1); 02426 TIME ltime; 02427 02428 if (!get_arg0_date(<ime, TIME_FUZZY_DATE) && !str->alloc(11)) 02429 { 02430 make_date((DATE_TIME_FORMAT *) 0, <ime, str); 02431 return str; 02432 } 02433 02434 null_value=1; 02435 return 0; 02436 } 02437 02438 longlong Item_date_typecast::val_int() 02439 { 02440 DBUG_ASSERT(fixed == 1); 02441 TIME ltime; 02442 if (args[0]->get_date(<ime, TIME_FUZZY_DATE)) 02443 return 0; 02444 return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day); 02445 } 02446 02447 /* 02448 MAKEDATE(a,b) is a date function that creates a date value 02449 from a year and day value. 02450 */ 02451 02452 String *Item_func_makedate::val_str(String *str) 02453 { 02454 DBUG_ASSERT(fixed == 1); 02455 TIME l_time; 02456 long daynr= (long) args[1]->val_int(); 02457 long yearnr= (long) args[0]->val_int(); 02458 long days; 02459 02460 if (args[0]->null_value || args[1]->null_value || 02461 yearnr < 0 || daynr <= 0) 02462 goto err; 02463 02464 days= calc_daynr(yearnr,1,1) + daynr - 1; 02465 /* Day number from year 0 to 9999-12-31 */ 02466 if (days >= 0 && days <= MAX_DAY_NUMBER) 02467 { 02468 null_value=0; 02469 get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); 02470 if (str->alloc(11)) 02471 goto err; 02472 make_date((DATE_TIME_FORMAT *) 0, &l_time, str); 02473 return str; 02474 } 02475 02476 err: 02477 null_value=1; 02478 return 0; 02479 } 02480 02481 02482 longlong Item_func_makedate::val_int() 02483 { 02484 DBUG_ASSERT(fixed == 1); 02485 TIME l_time; 02486 long daynr= (long) args[1]->val_int(); 02487 long yearnr= (long) args[0]->val_int(); 02488 long days; 02489 02490 if (args[0]->null_value || args[1]->null_value || 02491 yearnr < 0 || daynr <= 0) 02492 goto err; 02493 02494 days= calc_daynr(yearnr,1,1) + daynr - 1; 02495 /* Day number from year 0 to 9999-12-31 */ 02496 if (days >= 0 && days < MAX_DAY_NUMBER) 02497 { 02498 null_value=0; 02499 get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); 02500 return (longlong) (l_time.year * 10000L + l_time.month * 100 + l_time.day); 02501 } 02502 02503 err: 02504 null_value= 1; 02505 return 0; 02506 } 02507 02508 02509 void Item_func_add_time::fix_length_and_dec() 02510 { 02511 enum_field_types arg0_field_type; 02512 decimals=0; 02513 max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 02514 maybe_null= 1; 02515 02516 /* 02517 The field type for the result of an Item_func_add_time function is defined 02518 as follows: 02519 02520 - If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP 02521 result is MYSQL_TYPE_DATETIME 02522 - If first arg is a MYSQL_TYPE_TIME result is MYSQL_TYPE_TIME 02523 - Otherwise the result is MYSQL_TYPE_STRING 02524 */ 02525 02526 cached_field_type= MYSQL_TYPE_STRING; 02527 arg0_field_type= args[0]->field_type(); 02528 if (arg0_field_type == MYSQL_TYPE_DATE || 02529 arg0_field_type == MYSQL_TYPE_DATETIME || 02530 arg0_field_type == MYSQL_TYPE_TIMESTAMP) 02531 cached_field_type= MYSQL_TYPE_DATETIME; 02532 else if (arg0_field_type == MYSQL_TYPE_TIME) 02533 cached_field_type= MYSQL_TYPE_TIME; 02534 } 02535 02536 /* 02537 ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a 02538 time/datetime value 02539 02540 t: time_or_datetime_expression 02541 a: time_expression 02542 02543 Result: Time value or datetime value 02544 */ 02545 02546 String *Item_func_add_time::val_str(String *str) 02547 { 02548 DBUG_ASSERT(fixed == 1); 02549 TIME l_time1, l_time2, l_time3; 02550 bool is_time= 0; 02551 long days, microseconds; 02552 longlong seconds; 02553 int l_sign= sign; 02554 02555 null_value=0; 02556 if (is_date) // TIMESTAMP function 02557 { 02558 if (get_arg0_date(&l_time1, TIME_FUZZY_DATE) || 02559 args[1]->get_time(&l_time2) || 02560 l_time1.time_type == MYSQL_TIMESTAMP_TIME || 02561 l_time2.time_type != MYSQL_TIMESTAMP_TIME) 02562 goto null_date; 02563 } 02564 else // ADDTIME function 02565 { 02566 if (args[0]->get_time(&l_time1) || 02567 args[1]->get_time(&l_time2) || 02568 l_time2.time_type == MYSQL_TIMESTAMP_DATETIME) 02569 goto null_date; 02570 is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME); 02571 } 02572 if (l_time1.neg != l_time2.neg) 02573 l_sign= -l_sign; 02574 02575 l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign, 02576 &seconds, µseconds); 02577 02578 /* 02579 If first argument was negative and diff between arguments 02580 is non-zero we need to swap sign to get proper result. 02581 */ 02582 if (l_time1.neg && (seconds || microseconds)) 02583 l_time3.neg= 1-l_time3.neg; // Swap sign of result 02584 02585 if (!is_time && l_time3.neg) 02586 goto null_date; 02587 02588 days= (long)(seconds/86400L); 02589 02590 calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds); 02591 if (!is_time) 02592 { 02593 get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); 02594 if (l_time3.day && 02595 !make_datetime(l_time1.second_part || l_time2.second_part ? 02596 DATE_TIME_MICROSECOND : DATE_TIME, 02597 &l_time3, str)) 02598 return str; 02599 goto null_date; 02600 } 02601 02602 l_time3.hour+= days*24; 02603 if (!make_datetime(l_time1.second_part || l_time2.second_part ? 02604 TIME_MICROSECOND : TIME_ONLY, 02605 &l_time3, str)) 02606 return str; 02607 02608 null_date: 02609 null_value=1; 02610 return 0; 02611 } 02612 02613 02614 void Item_func_add_time::print(String *str) 02615 { 02616 if (is_date) 02617 { 02618 DBUG_ASSERT(sign > 0); 02619 str->append(STRING_WITH_LEN("timestamp(")); 02620 } 02621 else 02622 { 02623 if (sign > 0) 02624 str->append(STRING_WITH_LEN("addtime(")); 02625 else 02626 str->append(STRING_WITH_LEN("subtime(")); 02627 } 02628 args[0]->print(str); 02629 str->append(','); 02630 args[1]->print(str); 02631 str->append(')'); 02632 } 02633 02634 02635 /* 02636 TIMEDIFF(t,s) is a time function that calculates the 02637 time value between a start and end time. 02638 02639 t and s: time_or_datetime_expression 02640 Result: Time value 02641 */ 02642 02643 String *Item_func_timediff::val_str(String *str) 02644 { 02645 DBUG_ASSERT(fixed == 1); 02646 longlong seconds; 02647 long microseconds; 02648 int l_sign= 1; 02649 TIME l_time1 ,l_time2, l_time3; 02650 02651 null_value= 0; 02652 if (args[0]->get_time(&l_time1) || 02653 args[1]->get_time(&l_time2) || 02654 l_time1.time_type != l_time2.time_type) 02655 goto null_date; 02656 02657 if (l_time1.neg != l_time2.neg) 02658 l_sign= -l_sign; 02659 02660 l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign, 02661 &seconds, µseconds); 02662 02663 /* 02664 For MYSQL_TIMESTAMP_TIME only: 02665 If first argument was negative and diff between arguments 02666 is non-zero we need to swap sign to get proper result. 02667 */ 02668 if (l_time1.neg && (seconds || microseconds)) 02669 l_time3.neg= 1-l_time3.neg; // Swap sign of result 02670 02671 calc_time_from_sec(&l_time3, (long) seconds, microseconds); 02672 02673 if (!make_datetime(l_time1.second_part || l_time2.second_part ? 02674 TIME_MICROSECOND : TIME_ONLY, 02675 &l_time3, str)) 02676 return str; 02677 02678 null_date: 02679 null_value=1; 02680 return 0; 02681 } 02682 02683 /* 02684 MAKETIME(h,m,s) is a time function that calculates a time value 02685 from the total number of hours, minutes, and seconds. 02686 Result: Time value 02687 */ 02688 02689 String *Item_func_maketime::val_str(String *str) 02690 { 02691 DBUG_ASSERT(fixed == 1); 02692 TIME ltime; 02693 02694 long hour= (long) args[0]->val_int(); 02695 long minute= (long) args[1]->val_int(); 02696 long second= (long) args[2]->val_int(); 02697 02698 if ((null_value=(args[0]->null_value || 02699 args[1]->null_value || 02700 args[2]->null_value || 02701 minute > 59 || minute < 0 || 02702 second > 59 || second < 0 || 02703 str->alloc(19)))) 02704 return 0; 02705 02706 ltime.neg= 0; 02707 if (hour < 0) 02708 { 02709 ltime.neg= 1; 02710 hour= -hour; 02711 } 02712 ltime.hour= (ulong) hour; 02713 ltime.minute= (ulong) minute; 02714 ltime.second= (ulong) second; 02715 make_time((DATE_TIME_FORMAT *) 0, <ime, str); 02716 return str; 02717 } 02718 02719 02720 /* 02721 MICROSECOND(a) is a function ( extraction) that extracts the microseconds 02722 from a. 02723 02724 a: Datetime or time value 02725 Result: int value 02726 */ 02727 02728 longlong Item_func_microsecond::val_int() 02729 { 02730 DBUG_ASSERT(fixed == 1); 02731 TIME ltime; 02732 if (!get_arg0_time(<ime)) 02733 return ltime.second_part; 02734 return 0; 02735 } 02736 02737 02738 longlong Item_func_timestamp_diff::val_int() 02739 { 02740 TIME ltime1, ltime2; 02741 longlong seconds; 02742 long microseconds; 02743 long months= 0; 02744 int neg= 1; 02745 02746 null_value= 0; 02747 if (args[0]->get_date(<ime1, TIME_NO_ZERO_DATE) || 02748 args[1]->get_date(<ime2, TIME_NO_ZERO_DATE)) 02749 goto null_date; 02750 02751 if (calc_time_diff(<ime2,<ime1, 1, 02752 &seconds, µseconds)) 02753 neg= -1; 02754 02755 if (int_type == INTERVAL_YEAR || 02756 int_type == INTERVAL_QUARTER || 02757 int_type == INTERVAL_MONTH) 02758 { 02759 uint year_beg, year_end, month_beg, month_end, day_beg, day_end; 02760 uint years= 0; 02761 uint second_beg, second_end, microsecond_beg, microsecond_end; 02762 02763 if (neg == -1) 02764 { 02765 year_beg= ltime2.year; 02766 year_end= ltime1.year; 02767 month_beg= ltime2.month; 02768 month_end= ltime1.month; 02769 day_beg= ltime2.day; 02770 day_end= ltime1.day; 02771 second_beg= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second; 02772 second_end= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second; 02773 microsecond_beg= ltime2.second_part; 02774 microsecond_end= ltime1.second_part; 02775 } 02776 else 02777 { 02778 year_beg= ltime1.year; 02779 year_end= ltime2.year; 02780 month_beg= ltime1.month; 02781 month_end= ltime2.month; 02782 day_beg= ltime1.day; 02783 day_end= ltime2.day; 02784 second_beg= ltime1.hour * 3600 + ltime1.minute * 60 + ltime1.second; 02785 second_end= ltime2.hour * 3600 + ltime2.minute * 60 + ltime2.second; 02786 microsecond_beg= ltime1.second_part; 02787 microsecond_end= ltime2.second_part; 02788 } 02789 02790 /* calc years */ 02791 years= year_end - year_beg; 02792 if (month_end < month_beg || (month_end == month_beg && day_end < day_beg)) 02793 years-= 1; 02794 02795 /* calc months */ 02796 months= 12*years; 02797 if (month_end < month_beg || (month_end == month_beg && day_end < day_beg)) 02798 months+= 12 - (month_beg - month_end); 02799 else 02800 months+= (month_end - month_beg); 02801 02802 if (day_end < day_beg) 02803 months-= 1; 02804 else if ((day_end == day_beg) && 02805 ((second_end < second_beg) || 02806 (second_end == second_beg && microsecond_end < microsecond_beg))) 02807 months-= 1; 02808 } 02809 02810 switch (int_type) { 02811 case INTERVAL_YEAR: 02812 return months/12*neg; 02813 case INTERVAL_QUARTER: 02814 return months/3*neg; 02815 case INTERVAL_MONTH: 02816 return months*neg; 02817 case INTERVAL_WEEK: 02818 return seconds/86400L/7L*neg; 02819 case INTERVAL_DAY: 02820 return seconds/86400L*neg; 02821 case INTERVAL_HOUR: 02822 return seconds/3600L*neg; 02823 case INTERVAL_MINUTE: 02824 return seconds/60L*neg; 02825 case INTERVAL_SECOND: 02826 return seconds*neg; 02827 case INTERVAL_MICROSECOND: 02828 /* 02829 In MySQL difference between any two valid datetime values 02830 in microseconds fits into longlong. 02831 */ 02832 return (seconds*1000000L+microseconds)*neg; 02833 default: 02834 break; 02835 } 02836 02837 null_date: 02838 null_value=1; 02839 return 0; 02840 } 02841 02842 02843 void Item_func_timestamp_diff::print(String *str) 02844 { 02845 str->append(func_name()); 02846 str->append('('); 02847 02848 switch (int_type) { 02849 case INTERVAL_YEAR: 02850 str->append(STRING_WITH_LEN("YEAR")); 02851 break; 02852 case INTERVAL_QUARTER: 02853 str->append(STRING_WITH_LEN("QUARTER")); 02854 break; 02855 case INTERVAL_MONTH: 02856 str->append(STRING_WITH_LEN("MONTH")); 02857 break; 02858 case INTERVAL_WEEK: 02859 str->append(STRING_WITH_LEN("WEEK")); 02860 break; 02861 case INTERVAL_DAY: 02862 str->append(STRING_WITH_LEN("DAY")); 02863 break; 02864 case INTERVAL_HOUR: 02865 str->append(STRING_WITH_LEN("HOUR")); 02866 break; 02867 case INTERVAL_MINUTE: 02868 str->append(STRING_WITH_LEN("MINUTE")); 02869 break; 02870 case INTERVAL_SECOND: 02871 str->append(STRING_WITH_LEN("SECOND")); 02872 break; 02873 case INTERVAL_MICROSECOND: 02874 str->append(STRING_WITH_LEN("SECOND_FRAC")); 02875 break; 02876 default: 02877 break; 02878 } 02879 02880 for (uint i=0 ; i < 2 ; i++) 02881 { 02882 str->append(','); 02883 args[i]->print(str); 02884 } 02885 str->append(')'); 02886 } 02887 02888 02889 String *Item_func_get_format::val_str(String *str) 02890 { 02891 DBUG_ASSERT(fixed == 1); 02892 const char *format_name; 02893 KNOWN_DATE_TIME_FORMAT *format; 02894 String *val= args[0]->val_str(str); 02895 ulong val_len; 02896 02897 if ((null_value= args[0]->null_value)) 02898 return 0; 02899 02900 val_len= val->length(); 02901 for (format= &known_date_time_formats[0]; 02902 (format_name= format->format_name); 02903 format++) 02904 { 02905 uint format_name_len; 02906 format_name_len= strlen(format_name); 02907 if (val_len == format_name_len && 02908 !my_strnncoll(&my_charset_latin1, 02909 (const uchar *) val->ptr(), val_len, 02910 (const uchar *) format_name, val_len)) 02911 { 02912 const char *format_str= get_date_time_format_str(format, type); 02913 str->set(format_str, strlen(format_str), &my_charset_bin); 02914 return str; 02915 } 02916 } 02917 02918 null_value= 1; 02919 return 0; 02920 } 02921 02922 02923 void Item_func_get_format::print(String *str) 02924 { 02925 str->append(func_name()); 02926 str->append('('); 02927 02928 switch (type) { 02929 case MYSQL_TIMESTAMP_DATE: 02930 str->append(STRING_WITH_LEN("DATE, ")); 02931 break; 02932 case MYSQL_TIMESTAMP_DATETIME: 02933 str->append(STRING_WITH_LEN("DATETIME, ")); 02934 break; 02935 case MYSQL_TIMESTAMP_TIME: 02936 str->append(STRING_WITH_LEN("TIME, ")); 02937 break; 02938 default: 02939 DBUG_ASSERT(0); 02940 } 02941 args[0]->print(str); 02942 str->append(')'); 02943 } 02944 02945 02946 /* 02947 Get type of datetime value (DATE/TIME/...) which will be produced 02948 according to format string. 02949 02950 SYNOPSIS 02951 get_date_time_result_type() 02952 format - format string 02953 length - length of format string 02954 02955 NOTE 02956 We don't process day format's characters('D', 'd', 'e') because day 02957 may be a member of all date/time types. 02958 02959 Format specifiers supported by this function should be in sync with 02960 specifiers supported by extract_date_time() function. 02961 02962 RETURN VALUE 02963 One of date_time_format_types values: 02964 DATE_TIME_MICROSECOND, DATE_TIME, DATE_ONLY, TIME_MICROSECOND, TIME_ONLY 02965 */ 02966 02967 static date_time_format_types 02968 get_date_time_result_type(const char *format, uint length) 02969 { 02970 const char *time_part_frms= "HISThiklrs"; 02971 const char *date_part_frms= "MVUXYWabcjmvuxyw"; 02972 bool date_part_used= 0, time_part_used= 0, frac_second_used= 0; 02973 02974 const char *val= format; 02975 const char *end= format + length; 02976 02977 for (; val != end && val != end; val++) 02978 { 02979 if (*val == '%' && val+1 != end) 02980 { 02981 val++; 02982 if (*val == 'f') 02983 frac_second_used= time_part_used= 1; 02984 else if (!time_part_used && strchr(time_part_frms, *val)) 02985 time_part_used= 1; 02986 else if (!date_part_used && strchr(date_part_frms, *val)) 02987 date_part_used= 1; 02988 if (date_part_used && frac_second_used) 02989 { 02990 /* 02991 frac_second_used implies time_part_used, and thus we already 02992 have all types of date-time components and can end our search. 02993 */ 02994 return DATE_TIME_MICROSECOND; 02995 } 02996 } 02997 } 02998 02999 /* We don't have all three types of date-time components */ 03000 if (frac_second_used) 03001 return TIME_MICROSECOND; 03002 if (time_part_used) 03003 { 03004 if (date_part_used) 03005 return DATE_TIME; 03006 return TIME_ONLY; 03007 } 03008 return DATE_ONLY; 03009 } 03010 03011 03012 void Item_func_str_to_date::fix_length_and_dec() 03013 { 03014 char format_buff[64]; 03015 String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; 03016 maybe_null= 1; 03017 decimals=0; 03018 cached_field_type= MYSQL_TYPE_STRING; 03019 max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 03020 cached_timestamp_type= MYSQL_TIMESTAMP_NONE; 03021 format= args[1]->val_str(&format_str); 03022 if (!args[1]->null_value && (const_item= args[1]->const_item())) 03023 { 03024 cached_format_type= get_date_time_result_type(format->ptr(), 03025 format->length()); 03026 switch (cached_format_type) { 03027 case DATE_ONLY: 03028 cached_timestamp_type= MYSQL_TIMESTAMP_DATE; 03029 cached_field_type= MYSQL_TYPE_DATE; 03030 max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 03031 break; 03032 case TIME_ONLY: 03033 case TIME_MICROSECOND: 03034 cached_timestamp_type= MYSQL_TIMESTAMP_TIME; 03035 cached_field_type= MYSQL_TYPE_TIME; 03036 max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; 03037 break; 03038 default: 03039 cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; 03040 cached_field_type= MYSQL_TYPE_DATETIME; 03041 break; 03042 } 03043 } 03044 } 03045 03046 bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) 03047 { 03048 DATE_TIME_FORMAT date_time_format; 03049 char val_buff[64], format_buff[64]; 03050 String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val; 03051 String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; 03052 03053 val= args[0]->val_str(&val_str); 03054 format= args[1]->val_str(&format_str); 03055 if (args[0]->null_value || args[1]->null_value) 03056 goto null_date; 03057 03058 null_value= 0; 03059 bzero((char*) ltime, sizeof(ltime)); 03060 date_time_format.format.str= (char*) format->ptr(); 03061 date_time_format.format.length= format->length(); 03062 if (extract_date_time(&date_time_format, val->ptr(), val->length(), 03063 ltime, cached_timestamp_type, 0, "datetime")) 03064 goto null_date; 03065 if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day) 03066 { 03067 /* 03068 Day part for time type can be nonzero value and so 03069 we should add hours from day part to hour part to 03070 keep valid time value. 03071 */ 03072 ltime->hour+= ltime->day*24; 03073 ltime->day= 0; 03074 } 03075 return 0; 03076 03077 null_date: 03078 return (null_value=1); 03079 } 03080 03081 03082 String *Item_func_str_to_date::val_str(String *str) 03083 { 03084 DBUG_ASSERT(fixed == 1); 03085 TIME ltime; 03086 03087 if (Item_func_str_to_date::get_date(<ime, TIME_FUZZY_DATE)) 03088 return 0; 03089 03090 if (!make_datetime((const_item ? cached_format_type : 03091 (ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME)), 03092 <ime, str)) 03093 return str; 03094 return 0; 03095 } 03096 03097 03098 bool Item_func_last_day::get_date(TIME *ltime, uint fuzzy_date) 03099 { 03100 if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE)) 03101 return 1; 03102 uint month_idx= ltime->month-1; 03103 ltime->day= days_in_month[month_idx]; 03104 if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366) 03105 ltime->day= 29; 03106 ltime->time_type= MYSQL_TIMESTAMP_DATE; 03107 return 0; 03108 }
1.4.7

