You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
Fixed string conversion to MYSQL_TIME_TYPE:
- added support for negative time values - invalid strings (and/or conversion) and invalid values will result in MYSQL_TIMESTAMP_ERROR time type - added support for 2digit year representation: values < 69 will be converted to 20YY values >= 69 will be converted to 19YY
This commit is contained in:
@@ -198,42 +198,90 @@ double my_atod(const char *number, const char *end, int *error)
|
|||||||
|
|
||||||
my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm)
|
my_bool str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm)
|
||||||
{
|
{
|
||||||
my_bool is_time=0, is_date=0, has_time_frac=0;
|
char *start= alloca(length + 1);
|
||||||
char *p= (char *)str;
|
my_bool is_date= 0, is_time= 0;
|
||||||
|
|
||||||
if ((p= strchr(str, '-')) && p <= str + length)
|
|
||||||
is_date= 1;
|
|
||||||
if ((p= strchr(str, ':')) && p <= str + length)
|
|
||||||
is_time= 1;
|
|
||||||
if ((p= strchr(str, '.')) && p <= str + length)
|
|
||||||
has_time_frac= 1;
|
|
||||||
|
|
||||||
p= (char *)str;
|
|
||||||
|
|
||||||
memset(tm, 0, sizeof(MYSQL_TIME));
|
memset(tm, 0, sizeof(MYSQL_TIME));
|
||||||
|
if (!start)
|
||||||
|
goto error;
|
||||||
|
tm->time_type= MYSQL_TIMESTAMP_NONE;
|
||||||
|
|
||||||
|
memcpy(start, str, length);
|
||||||
|
start[length]= '\0';
|
||||||
|
|
||||||
|
while (length && isspace(*start)) start++, length--;
|
||||||
|
|
||||||
|
if (!length)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* negativ value? */
|
||||||
|
if (*start == '-')
|
||||||
|
{
|
||||||
|
tm->neg= 1;
|
||||||
|
start++;
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!length)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Determine time type:
|
||||||
|
MYSQL_TIMESTAMP_DATE: [-]YY[YY].MM.DD
|
||||||
|
MYSQL_TIMESTAMP_DATETIME: [-]YY[YY].MM.DD hh:mm:ss.mmmmmm
|
||||||
|
MYSQL_TIMESTAMP_TIME: [-]hh:mm:ss.mmmmmm
|
||||||
|
*/
|
||||||
|
if (strchr(start, '-'))
|
||||||
|
{
|
||||||
|
if (tm->neg)
|
||||||
|
goto error;
|
||||||
|
tm->time_type= MYSQL_TIMESTAMP_DATE;
|
||||||
|
if (sscanf(start, "%d-%d-%d", &tm->year, &tm->month, &tm->day) < 3)
|
||||||
|
goto error;
|
||||||
|
is_date= 1;
|
||||||
|
if (!(start= strchr(start, ' ')))
|
||||||
|
goto check;
|
||||||
|
}
|
||||||
|
if (!strchr(start, ':'))
|
||||||
|
goto check;
|
||||||
|
|
||||||
|
is_time= 1;
|
||||||
|
if (tm->time_type== MYSQL_TIMESTAMP_DATE)
|
||||||
|
tm->time_type= MYSQL_TIMESTAMP_DATETIME;
|
||||||
|
else
|
||||||
|
tm->time_type= MYSQL_TIMESTAMP_TIME;
|
||||||
|
|
||||||
|
if (strchr(start, '.')) /* fractional seconds */
|
||||||
|
{
|
||||||
|
if (sscanf(start, "%d:%d:%d.%ld", &tm->hour, &tm->minute,
|
||||||
|
&tm->second,&tm->second_part) < 4)
|
||||||
|
goto error;
|
||||||
|
} else {
|
||||||
|
if (sscanf(start, "%d:%d:%d", &tm->hour, &tm->minute,
|
||||||
|
&tm->second) < 3)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
check:
|
||||||
|
if (tm->time_type == MYSQL_TIMESTAMP_NONE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (is_date)
|
if (is_date)
|
||||||
{
|
{
|
||||||
sscanf(str, "%d-%d-%d", &tm->year, &tm->month, &tm->day);
|
if (tm->year < 69)
|
||||||
p= strchr(str, ' ');
|
tm->year+= 2000;
|
||||||
if (!p)
|
else if (tm->year < 100)
|
||||||
{
|
tm->year+= 1900;
|
||||||
tm->time_type= MYSQL_TIMESTAMP_DATE;
|
if (tm->day > 31 || tm->month > 12)
|
||||||
return 0;
|
goto error;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_time_frac)
|
|
||||||
{
|
|
||||||
sscanf(p, "%d:%d:%d.%ld", &tm->hour, &tm->minute, &tm->second, &tm->second_part);
|
|
||||||
tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (is_time)
|
if (is_time)
|
||||||
{
|
{
|
||||||
sscanf(p, "%d:%d:%d", &tm->hour, &tm->minute, &tm->second);
|
if (tm->minute > 59 || tm->second > 59)
|
||||||
tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
|
goto error;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
tm->time_type= MYSQL_TIMESTAMP_ERROR;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4654,15 +4654,47 @@ static int test_compress(MYSQL *mysql)
|
|||||||
static int test_codbc138(MYSQL *mysql)
|
static int test_codbc138(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
|
MYSQL_STMT *stmt;
|
||||||
MYSQL_BIND bind[1];
|
MYSQL_BIND bind[1];
|
||||||
MYSQL_TIME tm;
|
MYSQL_TIME tm;
|
||||||
|
int i= 0;
|
||||||
|
|
||||||
rc= mysql_stmt_prepare(stmt, SL("SELECT DATE_ADD('2018-02-01', INTERVAL -188 DAY)"));
|
struct st_time_test {
|
||||||
|
char *statement;
|
||||||
|
MYSQL_TIME tm;
|
||||||
|
} time_test[]= {
|
||||||
|
{"SELECT DATE_ADD('2018-02-01', INTERVAL -188 DAY)",
|
||||||
|
{2017,7,28,0,0,0,0L,0, MYSQL_TIMESTAMP_DATE}
|
||||||
|
},
|
||||||
|
{"SELECT '2001-02-03 11:12:13.123456'",
|
||||||
|
{2001,2,3,11,12,13,123456L,0, MYSQL_TIMESTAMP_DATETIME}
|
||||||
|
},
|
||||||
|
{"SELECT '-11:12:13'",
|
||||||
|
{0,0,0,11,12,13,0,1, MYSQL_TIMESTAMP_TIME}
|
||||||
|
},
|
||||||
|
{"SELECT ' '",
|
||||||
|
{0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR}
|
||||||
|
},
|
||||||
|
{"SELECT '1--'",
|
||||||
|
{1,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR}
|
||||||
|
},
|
||||||
|
{"SELECT '-2001-01-01'",
|
||||||
|
{1,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR}
|
||||||
|
},
|
||||||
|
{"SELECT '-11:00'",
|
||||||
|
{1,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_ERROR}
|
||||||
|
},
|
||||||
|
{NULL, {0}}
|
||||||
|
};
|
||||||
|
|
||||||
|
while (time_test[i].statement)
|
||||||
|
{
|
||||||
|
stmt= mysql_stmt_init(mysql);
|
||||||
|
rc= mysql_stmt_prepare(stmt, SL(time_test[i].statement));
|
||||||
check_stmt_rc(rc, stmt);
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_stmt_rc(rc, stmt);
|
check_stmt_rc(rc, stmt);
|
||||||
|
rc= mysql_stmt_store_result(stmt);
|
||||||
|
|
||||||
memset(bind, 0, sizeof(MYSQL_BIND));
|
memset(bind, 0, sizeof(MYSQL_BIND));
|
||||||
bind[0].buffer_type= MYSQL_TYPE_DATETIME;
|
bind[0].buffer_type= MYSQL_TYPE_DATETIME;
|
||||||
@@ -4671,22 +4703,19 @@ static int test_codbc138(MYSQL *mysql)
|
|||||||
|
|
||||||
rc= mysql_stmt_bind_result(stmt, bind);
|
rc= mysql_stmt_bind_result(stmt, bind);
|
||||||
check_stmt_rc(rc, stmt);
|
check_stmt_rc(rc, stmt);
|
||||||
|
|
||||||
rc= mysql_stmt_fetch(stmt);
|
rc= mysql_stmt_fetch(stmt);
|
||||||
check_stmt_rc(rc, stmt);
|
check_stmt_rc(rc, stmt);
|
||||||
|
diag("test: %s %d %d", time_test[i].statement, tm.time_type, time_test[i].tm.time_type);
|
||||||
if (tm.year != 2017 && tm.day != 28 && tm.month != 7)
|
if (time_test[i].tm.time_type == MYSQL_TIMESTAMP_ERROR)
|
||||||
{
|
{
|
||||||
diag("Error: Expected 2017-07-02");
|
FAIL_UNLESS(tm.time_type == MYSQL_TIMESTAMP_ERROR, "MYSQL_TIMESTAMP_ERROR expected");
|
||||||
return FAIL;
|
|
||||||
}
|
}
|
||||||
if (tm.minute | tm.second || tm.second_part)
|
else
|
||||||
{
|
FAIL_UNLESS(memcmp(&tm, &time_test[i].tm, sizeof(MYSQL_TIME)) == 0, "time_in != time_out");
|
||||||
diag("Error: minute, second or second_part is not zero");
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4776,4 +4805,3 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
return(exit_status());
|
return(exit_status());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user