Merge branch '2.0' into 2.1-merge-2.0
This commit is contained in:
@ -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)
|
||||
|
Reference in New Issue
Block a user