Skip to content

Commit

Permalink
Add support for length encoded datetime strings:
Browse files Browse the repository at this point in the history
In some cases server doesn't send date values with field type MYSQL_TYPE_STRING, but as length encoded string with type MYSQL_TYPE_VAR_STRING.
  • Loading branch information
9EOR9 committed May 22, 2018
1 parent 2861c15 commit 7d0d7f2
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 30 deletions.
75 changes: 45 additions & 30 deletions libmariadb/my_stmt_codec.c
Expand Up @@ -186,48 +186,63 @@ double my_atod(const char *number, const char *end, int *error)
return val;
}

static int ma_atoi(char *buffer, int length)
{
char digits[MAX_INT_WIDTH + 1];
if (length > MAX_INT_WIDTH)
return 0;
strncpy(digits, buffer, length);
digits[length]= 0;
return atoi(digits);
}

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;
my_bool is_date= 0, is_time= 0;
char *p= (char *)str;

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));

if (is_date)
{
sscanf(str, "%d-%d-%d", &tm->year, &tm->month, &tm->day);
p= strchr(str, ' ');
if (!p)
{
tm->time_type= MYSQL_TIMESTAMP_DATE;
return 0;
}
}
if (has_time_frac)
/* date: YYYY-MM-DD */
if (memchr(p, '-', length))
{
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 (length < 10)
return 1;
tm->year= ma_atoi(p, 4);
tm->month= ma_atoi(p + 5, 2);
tm->day= ma_atoi(p + 8, 2);
tm->time_type= MYSQL_TIMESTAMP_DATE;
is_date= 1;
p+= 10;
}
if (is_time)

/* time: HH:MM:SS */
if (memchr(p, ':', length - (p - str)))
{
sscanf(p, "%d:%d:%d", &tm->hour, &tm->minute, &tm->second);
tm->time_type= (is_date) ? MYSQL_TIMESTAMP_DATETIME : MYSQL_TIMESTAMP_TIME;
return 0;
if (is_date)
{
p++;
tm->time_type= MYSQL_TIMESTAMP_DATETIME;
}
else
tm->time_type= MYSQL_TIMESTAMP_TIME;
is_time= 1;

if (length - (p - str) < 8)
return 1;

tm->hour= ma_atoi(p,2);
tm->minute= ma_atoi(p + 3, 2);
tm->second= ma_atoi(p + 6, 2);

if (!(p= memchr(p, '.', length - (p - str))))
return 0;
p++;
tm->second_part= ma_atoi(p, length - (p - str));
}
return 1;
return test(!is_date && !is_time);
}


static void convert_from_string(MYSQL_BIND *r_param, char *buffer, size_t len)
{
int error= 0;
Expand Down
2 changes: 2 additions & 0 deletions unittest/libmariadb/my_test.h
Expand Up @@ -50,6 +50,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */

#define SL(a) (a), strlen(a)

#define check_mysql_rc(rc, mysql) \
if (rc)\
{\
Expand Down
42 changes: 42 additions & 0 deletions unittest/libmariadb/ps_bugs.c
Expand Up @@ -4492,7 +4492,49 @@ static int test_conc205(MYSQL *mysql)
return OK;
}

static int test_codbc138(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt= mysql_stmt_init(mysql);
MYSQL_BIND bind[1];
MYSQL_TIME tm;

rc= mysql_stmt_prepare(stmt, SL("SELECT DATE_ADD('2018-02-01', INTERVAL -188 DAY)"));
check_stmt_rc(rc, stmt);

rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);

rc= mysql_stmt_store_result(stmt);

memset(bind, 0, sizeof(MYSQL_BIND));
bind[0].buffer_type= MYSQL_TYPE_DATETIME;
bind[0].buffer= &tm;
bind[0].buffer_length= sizeof(MYSQL_TIME);

rc= mysql_stmt_bind_result(stmt, bind);
check_stmt_rc(rc, stmt);

rc= mysql_stmt_fetch(stmt);
check_stmt_rc(rc, stmt);

if (tm.year != 2017 && tm.day != 28 && tm.month != 7)
{
diag("Error: Expected 2017-07-02");
return FAIL;
}
if (tm.minute | tm.second || tm.second_part)
{
diag("Error: minute, second or second_part is not zero");
return FAIL;
}

mysql_stmt_close(stmt);
return OK;
}

struct my_tests_st my_tests[] = {
{"test_codbc138", test_codbc138, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc205", test_conc205, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc198", test_conc198, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
{"test_conc194", test_conc194, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
Expand Down

0 comments on commit 7d0d7f2

Please sign in to comment.