Merge branch '2.0' into 2.1-merge-2.0

This commit is contained in:
Markus Mäkelä
2017-05-14 10:25:12 +03:00
6 changed files with 296 additions and 102 deletions

View File

@ -25,6 +25,10 @@
#include <strings.h>
#include <math.h>
#include <maxscale/protocol/mysql.h>
static uint64_t unpack_bytes(uint8_t *ptr, size_t bytes);
/**
* @brief Convert a table column type to a string
*
@ -216,6 +220,35 @@ static void unpack_year(uint8_t *ptr, struct tm *dest)
dest->tm_year = *ptr;
}
/** Base-10 logarithm values */
int64_t log_10_values[] =
{
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000
};
/**
* If the TABLE_COL_TYPE_DATETIME type field is declared as a datetime with
* extra precision, the packed length is shorter than 8 bytes.
*/
size_t datetime_sizes[] =
{
5, // DATETIME(0)
6, // DATETIME(1)
6, // DATETIME(2)
7, // DATETIME(3)
7, // DATETIME(4)
7, // DATETIME(5)
8 // DATETIME(6)
};
/**
* @brief Unpack a DATETIME
*
@ -224,21 +257,52 @@ static void unpack_year(uint8_t *ptr, struct tm *dest)
* @param val Value read from the binary log
* @param dest Pointer where the unpacked value is stored
*/
static void unpack_datetime(uint8_t *ptr, struct tm *dest)
static void unpack_datetime(uint8_t *ptr, int length, struct tm *dest)
{
uint64_t val = 0;
memcpy(&val, ptr, sizeof(val));
uint32_t second = val - ((val / 100) * 100);
val /= 100;
uint32_t minute = val - ((val / 100) * 100);
val /= 100;
uint32_t hour = val - ((val / 100) * 100);
val /= 100;
uint32_t day = val - ((val / 100) * 100);
val /= 100;
uint32_t month = val - ((val / 100) * 100);
val /= 100;
uint32_t year = val;
int64_t val = 0;
uint32_t second, minute, hour, day, month, year;
if (length == -1)
{
val = gw_mysql_get_byte8(ptr);
second = val - ((val / 100) * 100);
val /= 100;
minute = val - ((val / 100) * 100);
val /= 100;
hour = val - ((val / 100) * 100);
val /= 100;
day = val - ((val / 100) * 100);
val /= 100;
month = val - ((val / 100) * 100);
val /= 100;
year = val;
}
else
{
// TODO: Figure out why DATETIME(0) doesn't work like it others do
val = unpack_bytes(ptr, datetime_sizes[length]);
val *= log_10_values[6 - length];
if (val < 0)
{
val = -val;
}
int subsecond = val % 1000000;
val /= 1000000;
second = val % 60;
val /= 60;
minute = val % 60;
val /= 60;
hour = val % 24;
val /= 24;
day = val % 32;
val /= 32;
month = val % 13;
val /= 13;
year = val;
}
memset(dest, 0, sizeof(struct tm));
dest->tm_year = year - 1900;
@ -391,14 +455,13 @@ size_t unpack_bit(uint8_t *ptr, uint8_t *null_mask, uint32_t col_count,
return metadata[1];
}
/**
* @brief Get the length of a temporal field
* @param type Field type
* @param decimals How many decimals the field has
* @return Number of bytes the temporal value takes
*/
static size_t temporal_field_size(uint8_t type, uint8_t decimals)
static size_t temporal_field_size(uint8_t type, uint8_t decimals, int length)
{
switch (type)
{
@ -412,8 +475,8 @@ static size_t temporal_field_size(uint8_t type, uint8_t decimals)
case TABLE_COL_TYPE_TIME2:
return 3 + ((decimals + 1) / 2);
case TABLE_COL_TYPE_DATETIME:
return 8;
case TABLE_COL_TYPE_DATETIME:
return length < 0 || length > 6 ? 8 : datetime_sizes[length];
case TABLE_COL_TYPE_TIMESTAMP:
return 4;
@ -441,40 +504,40 @@ static size_t temporal_field_size(uint8_t type, uint8_t decimals)
* @param val Extracted packed value
* @param tm Pointer where the unpacked temporal value is stored
*/
size_t unpack_temporal_value(uint8_t type, uint8_t *ptr, uint8_t *metadata, struct tm *tm)
size_t unpack_temporal_value(uint8_t type, uint8_t *ptr, uint8_t *metadata, int length, struct tm *tm)
{
switch (type)
{
case TABLE_COL_TYPE_YEAR:
unpack_year(ptr, tm);
break;
case TABLE_COL_TYPE_YEAR:
unpack_year(ptr, tm);
break;
case TABLE_COL_TYPE_DATETIME:
unpack_datetime(ptr, tm);
break;
case TABLE_COL_TYPE_DATETIME:
unpack_datetime(ptr, length, tm);
break;
case TABLE_COL_TYPE_DATETIME2:
unpack_datetime2(ptr, *metadata, tm);
break;
case TABLE_COL_TYPE_DATETIME2:
unpack_datetime2(ptr, *metadata, tm);
break;
case TABLE_COL_TYPE_TIME:
unpack_time(ptr, tm);
break;
case TABLE_COL_TYPE_TIME:
unpack_time(ptr, tm);
break;
case TABLE_COL_TYPE_DATE:
unpack_date(ptr, tm);
break;
case TABLE_COL_TYPE_DATE:
unpack_date(ptr, tm);
break;
case TABLE_COL_TYPE_TIMESTAMP:
case TABLE_COL_TYPE_TIMESTAMP2:
unpack_timestamp(ptr, *metadata, tm);
break;
case TABLE_COL_TYPE_TIMESTAMP:
case TABLE_COL_TYPE_TIMESTAMP2:
unpack_timestamp(ptr, *metadata, tm);
break;
default:
ss_dassert(false);
break;
default:
ss_dassert(false);
break;
}
return temporal_field_size(type, *metadata);
return temporal_field_size(type, *metadata, length);
}
void format_temporal_value(char *str, size_t size, uint8_t type, struct tm *tm)