From e1961ba59053bbe2bd368a018e892bd8b709acf6 Mon Sep 17 00:00:00 2001 From: Timur Safin Date: Sat, 3 Jul 2021 02:22:52 +0300 Subject: [PATCH] box, datetime: add messagepack support for datetime Serialize datetime_t as newly introduced MP_EXT type. It saves 1 required integer field and upto 2 optional unsigned fields in very compact fashion. - secs is required field; - but nsec, offset are both optional; * json, yaml serialization formats, lua output mode supported; Part of #5941 Part of #5946 --- src/box/field_def.c | 34 ++++--- src/box/field_def.h | 1 + src/box/lua/serialize_lua.c | 7 +- src/box/msgpack.c | 7 +- src/box/tuple_compare.cc | 20 ++++ src/exports.h | 2 + src/lib/core/CMakeLists.txt | 3 +- src/lib/core/datetime.c | 161 ++++++++++++++++++++++++++++++ src/lib/core/datetime.h | 41 +++++++- src/lib/core/mp_extension_types.h | 1 + src/lib/mpstream/mpstream.c | 11 ++ src/lib/mpstream/mpstream.h | 4 + src/lua/msgpack.c | 12 +++ src/lua/msgpackffi.lua | 8 ++ src/lua/serializer.c | 4 + src/lua/serializer.h | 2 + src/lua/utils.c | 1 - test/unit/datetime.c | 1 - third_party/lua-cjson/lua_cjson.c | 8 ++ third_party/lua-yaml/lyaml.cc | 6 +- 20 files changed, 312 insertions(+), 22 deletions(-) diff --git a/src/box/field_def.c b/src/box/field_def.c index 51acb80259aa..33606a52daba 100644 --- a/src/box/field_def.c +++ b/src/box/field_def.c @@ -67,11 +67,12 @@ const uint32_t field_mp_type[] = { /* [FIELD_TYPE_VARBINARY] = */ 1U << MP_BIN, /* [FIELD_TYPE_SCALAR] = */ (1U << MP_UINT) | (1U << MP_INT) | (1U << MP_FLOAT) | (1U << MP_DOUBLE) | (1U << MP_STR) | - (1U << MP_BIN) | (1U << MP_BOOL), + (1U << MP_BIN) | (1U << MP_BOOL) | (1U << MP_DATETIME), /* [FIELD_TYPE_DECIMAL] = */ 0, /* only MP_DECIMAL is supported */ /* [FIELD_TYPE_UUID] = */ 0, /* only MP_UUID is supported */ /* [FIELD_TYPE_ARRAY] = */ 1U << MP_ARRAY, /* [FIELD_TYPE_MAP] = */ (1U << MP_MAP), + /* [FIELD_TYPE_DATETIME] = */ 0, /* only MP_DATETIME is supported */ }; const uint32_t field_ext_type[] = { @@ -88,6 +89,7 @@ const uint32_t field_ext_type[] = { /* [FIELD_TYPE_UUID] = */ 1U << MP_UUID, /* [FIELD_TYPE_ARRAY] = */ 0, /* [FIELD_TYPE_MAP] = */ 0, + /* [FIELD_TYPE_DATETIME] = */ 1U << MP_DATETIME, }; const char *field_type_strs[] = { @@ -104,6 +106,7 @@ const char *field_type_strs[] = { /* [FIELD_TYPE_UUID] = */ "uuid", /* [FIELD_TYPE_ARRAY] = */ "array", /* [FIELD_TYPE_MAP] = */ "map", + /* [FIELD_TYPE_DATETIME] = */ "datetime", }; const char *on_conflict_action_strs[] = { @@ -128,20 +131,21 @@ field_type_by_name_wrapper(const char *str, uint32_t len) * values can be stored in the j type. */ static const bool field_type_compatibility[] = { - /* ANY UNSIGNED STRING NUMBER DOUBLE INTEGER BOOLEAN VARBINARY SCALAR DECIMAL UUID ARRAY MAP */ -/* ANY */ true, false, false, false, false, false, false, false, false, false, false, false, false, -/* UNSIGNED */ true, true, false, true, false, true, false, false, true, false, false, false, false, -/* STRING */ true, false, true, false, false, false, false, false, true, false, false, false, false, -/* NUMBER */ true, false, false, true, false, false, false, false, true, false, false, false, false, -/* DOUBLE */ true, false, false, true, true, false, false, false, true, false, false, false, false, -/* INTEGER */ true, false, false, true, false, true, false, false, true, false, false, false, false, -/* BOOLEAN */ true, false, false, false, false, false, true, false, true, false, false, false, false, -/* VARBINARY*/ true, false, false, false, false, false, false, true, true, false, false, false, false, -/* SCALAR */ true, false, false, false, false, false, false, false, true, false, false, false, false, -/* DECIMAL */ true, false, false, true, false, false, false, false, true, true, false, false, false, -/* UUID */ true, false, false, false, false, false, false, false, false, false, true, false, false, -/* ARRAY */ true, false, false, false, false, false, false, false, false, false, false, true, false, -/* MAP */ true, false, false, false, false, false, false, false, false, false, false, false, true, + /* ANY UNSIGNED STRING NUMBER DOUBLE INTEGER BOOLEAN VARBINARY SCALAR DECIMAL UUID ARRAY MAP DATETIME */ +/* ANY */ true, false, false, false, false, false, false, false, false, false, false, false, false, false, +/* UNSIGNED */ true, true, false, true, false, true, false, false, true, false, false, false, false, false, +/* STRING */ true, false, true, false, false, false, false, false, true, false, false, false, false, false, +/* NUMBER */ true, false, false, true, false, false, false, false, true, false, false, false, false, false, +/* DOUBLE */ true, false, false, true, true, false, false, false, true, false, false, false, false, false, +/* INTEGER */ true, false, false, true, false, true, false, false, true, false, false, false, false, false, +/* BOOLEAN */ true, false, false, false, false, false, true, false, true, false, false, false, false, false, +/* VARBINARY*/ true, false, false, false, false, false, false, true, true, false, false, false, false, false, +/* SCALAR */ true, false, false, false, false, false, false, false, true, false, false, false, false, false, +/* DECIMAL */ true, false, false, true, false, false, false, false, true, true, false, false, false, false, +/* UUID */ true, false, false, false, false, false, false, false, false, false, true, false, false, false, +/* ARRAY */ true, false, false, false, false, false, false, false, false, false, false, true, false, false, +/* MAP */ true, false, false, false, false, false, false, false, false, false, false, false, true, false, +/* DATETIME */ true, false, false, false, false, false, false, false, false, false, false, false, false, true, }; bool diff --git a/src/box/field_def.h b/src/box/field_def.h index c5cfe5e86ab8..120b2a93de61 100644 --- a/src/box/field_def.h +++ b/src/box/field_def.h @@ -63,6 +63,7 @@ enum field_type { FIELD_TYPE_UUID, FIELD_TYPE_ARRAY, FIELD_TYPE_MAP, + FIELD_TYPE_DATETIME, field_type_MAX }; diff --git a/src/box/lua/serialize_lua.c b/src/box/lua/serialize_lua.c index 7144305cfaa0..5cfa6f5e0f1a 100644 --- a/src/box/lua/serialize_lua.c +++ b/src/box/lua/serialize_lua.c @@ -768,7 +768,7 @@ static int dump_node(struct lua_dumper *d, struct node *nd, int indent) { struct luaL_field *field = &nd->field; - char buf[FPCONV_G_FMT_BUFSIZE]; + char buf[FPCONV_G_FMT_BUFSIZE + 8]; int ltype = lua_type(d->L, -1); const char *str = NULL; size_t len = 0; @@ -861,6 +861,11 @@ dump_node(struct lua_dumper *d, struct node *nd, int indent) str = tt_uuid_str(field->uuidval); len = UUID_STR_LEN; break; + case MP_DATETIME: + nd->mask |= NODE_QUOTE; + str = buf; + len = datetime_to_string(field->dateval, buf, sizeof buf); + break; default: d->err = EINVAL; snprintf(d->err_msg, sizeof(d->err_msg), diff --git a/src/box/msgpack.c b/src/box/msgpack.c index 1723dea4ca3e..e53af548c565 100644 --- a/src/box/msgpack.c +++ b/src/box/msgpack.c @@ -1,5 +1,5 @@ /* - * Copyright 2020, Tarantool AUTHORS, please see AUTHORS file. + * Copyright 2020-2021, Tarantool AUTHORS, please see AUTHORS file. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -35,6 +35,7 @@ #include "mp_decimal.h" #include "uuid/mp_uuid.h" #include "mp_error.h" +#include "datetime.h" static int msgpack_fprint_ext(FILE *file, const char **data, int depth) @@ -47,6 +48,8 @@ msgpack_fprint_ext(FILE *file, const char **data, int depth) return mp_fprint_decimal(file, data, len); case MP_UUID: return mp_fprint_uuid(file, data, len); + case MP_DATETIME: + return mp_fprint_datetime(file, data, len); case MP_ERROR: return mp_fprint_error(file, data, depth); default: @@ -65,6 +68,8 @@ msgpack_snprint_ext(char *buf, int size, const char **data, int depth) return mp_snprint_decimal(buf, size, data, len); case MP_UUID: return mp_snprint_uuid(buf, size, data, len); + case MP_DATETIME: + return mp_snprint_datetime(buf, size, data, len); case MP_ERROR: return mp_snprint_error(buf, size, data, depth); default: diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc index 98938fb39aa6..48c833643c03 100644 --- a/src/box/tuple_compare.cc +++ b/src/box/tuple_compare.cc @@ -36,6 +36,7 @@ #include "lib/core/decimal.h" #include "lib/core/mp_decimal.h" #include "uuid/mp_uuid.h" +#include "core/datetime.h" #include "lib/core/mp_extension_types.h" /* {{{ tuple_compare */ @@ -76,6 +77,7 @@ enum mp_class { MP_CLASS_STR, MP_CLASS_BIN, MP_CLASS_UUID, + MP_CLASS_DATETIME, MP_CLASS_ARRAY, MP_CLASS_MAP, mp_class_max, @@ -99,6 +101,8 @@ static enum mp_class mp_ext_classes[] = { /* .MP_UNKNOWN_EXTENSION = */ mp_class_max, /* unsupported */ /* .MP_DECIMAL = */ MP_CLASS_NUMBER, /* .MP_UUID = */ MP_CLASS_UUID, + /* .MP_ERROR = */ mp_class_max, + /* .MP_DATETIME = */ MP_CLASS_DATETIME, }; static enum mp_class @@ -390,6 +394,19 @@ mp_compare_uuid(const char *field_a, const char *field_b) return memcmp(field_a + 2, field_b + 2, UUID_PACKED_LEN); } +static int +mp_compare_datetime(const char *lhs, const char *rhs) +{ + datetime_t lhs_dt, rhs_dt; + datetime_t *ret; + ret = mp_decode_datetime(&lhs, &lhs_dt); + assert(ret != NULL); + ret = mp_decode_datetime(&rhs, &rhs_dt); + assert(ret != NULL); + (void)ret; + return datetime_compare(&lhs_dt, &rhs_dt); +} + typedef int (*mp_compare_f)(const char *, const char *); static mp_compare_f mp_class_comparators[] = { /* .MP_CLASS_NIL = */ NULL, @@ -398,6 +415,7 @@ static mp_compare_f mp_class_comparators[] = { /* .MP_CLASS_STR = */ mp_compare_str, /* .MP_CLASS_BIN = */ mp_compare_bin, /* .MP_CLASS_UUID = */ mp_compare_uuid, + /* .MP_CLASS_DATETIME=*/ mp_compare_datetime, /* .MP_CLASS_ARRAY = */ NULL, /* .MP_CLASS_MAP = */ NULL, }; @@ -478,6 +496,8 @@ tuple_compare_field(const char *field_a, const char *field_b, return mp_compare_decimal(field_a, field_b); case FIELD_TYPE_UUID: return mp_compare_uuid(field_a, field_b); + case FIELD_TYPE_DATETIME: + return mp_compare_datetime(field_a, field_b); default: unreachable(); return 0; diff --git a/src/exports.h b/src/exports.h index 1a03db63616b..586444b65100 100644 --- a/src/exports.h +++ b/src/exports.h @@ -531,6 +531,8 @@ EXPORT(uri_format) EXPORT(uri_parse) EXPORT(uuid_nil) EXPORT(uuid_unpack) +EXPORT(datetime_unpack) +EXPORT(datetime_pack) EXPORT(dt_from_rdn) EXPORT(dt_from_yd) EXPORT(dt_from_ymd) diff --git a/src/lib/core/CMakeLists.txt b/src/lib/core/CMakeLists.txt index 8bc776b82f4b..c3e68c36feb9 100644 --- a/src/lib/core/CMakeLists.txt +++ b/src/lib/core/CMakeLists.txt @@ -44,7 +44,8 @@ add_library(core STATIC ${core_sources}) target_link_libraries(core salad small uri decNumber bit ${LIBEV_LIBRARIES} ${LIBEIO_LIBRARIES} ${LIBCORO_LIBRARIES} - ${MSGPUCK_LIBRARIES} ${ICU_LIBRARIES}) + ${MSGPUCK_LIBRARIES} ${ICU_LIBRARIES} + ${LIBCDT_LIBRARIES}) if (ENABLE_BACKTRACE AND NOT TARGET_OS_DARWIN) target_link_libraries(core gcc_s ${UNWIND_LIBRARIES}) diff --git a/src/lib/core/datetime.c b/src/lib/core/datetime.c index 65f813a70240..26ba8a7023c2 100755 --- a/src/lib/core/datetime.c +++ b/src/lib/core/datetime.c @@ -33,6 +33,132 @@ #include "trivia/util.h" #include "datetime.h" +#include "msgpuck.h" +#include "mp_extension_types.h" + +/* + Datetime MessagePack serialization schema is MP_EXT (0xC7 for 1 byte length) + extension, which creates container of 1 to 3 integers. + + +----+---+-----------+====~~~~~~~====+-----~~~~~~~~-------+....~~~~~~~....+ + |0xC7| 4 |len (uint8)| seconds (int) | nanoseconds (uint) | offset (uint) | + +----+---+-----------+====~~~~~~~====+-----~~~~~~~~-------+....~~~~~~~....+ + + MessagePack extension MP_EXT (0xC7), after 1-byte length, contains: + + - signed integer seconds part (required). Depending on the value of + seconds it may be from 1 to 8 bytes positive or negative integer number; + + - [optional] fraction time in nanoseconds as unsigned integer. + If this value is 0 then it's not saved (unless there is offset field, + as below); + + - [optional] timzeone offset in minutes as unsigned integer. + If this field is 0 then it's not saved. + */ + +static inline uint32_t +mp_sizeof_Xint(int64_t n) +{ + return n < 0 ? mp_sizeof_int(n) : mp_sizeof_uint(n); +} + +static inline char * +mp_encode_Xint(char *data, int64_t v) +{ + return v < 0 ? mp_encode_int(data, v) : mp_encode_uint(data, v); +} + +static inline int64_t +mp_decode_Xint(const char **data) +{ + switch (mp_typeof(**data)) { + case MP_UINT: + return (int64_t)mp_decode_uint(data); + case MP_INT: + return mp_decode_int(data); + default: + mp_unreachable(); + } + return 0; +} + +uint32_t +mp_sizeof_datetime(const struct datetime_t *date) +{ + uint32_t sz = mp_sizeof_Xint(date->secs); + + // even if nanosecs == 0 we need to output anything + // if we have non-null tz offset + if (date->nsec != 0 || date->offset != 0) + sz += mp_sizeof_Xint(date->nsec); + if (date->offset) + sz += mp_sizeof_Xint(date->offset); + + return sz; +} + +struct datetime_t * +datetime_unpack(const char **data, uint32_t len, struct datetime_t *date) +{ + const char * svp = *data; + + memset(date, 0, sizeof(*date)); + + date->secs = mp_decode_Xint(data); + + len -= *data - svp; + if (len <= 0) + return date; + + svp = *data; + date->secs = mp_decode_Xint(data); + len -= *data - svp; + + if (len <= 0) + return date; + + date->offset = mp_decode_Xint(data); + + return date; +} + +struct datetime_t * +mp_decode_datetime(const char **data, struct datetime_t *date) +{ + if (mp_typeof(**data) != MP_EXT) + return NULL; + + int8_t type; + uint32_t len = mp_decode_extl(data, &type); + + if (type != MP_DATETIME || len == 0) { + return NULL; + } + return datetime_unpack(data, len, date); +} + +char * +datetime_pack(char *data, const struct datetime_t *date) +{ + data = mp_encode_Xint(data, date->secs); + if (date->nsec != 0 || date->offset != 0) + data = mp_encode_Xint(data, date->nsec); + if (date->offset) + data = mp_encode_Xint(data, date->offset); + + return data; +} + +char * +mp_encode_datetime(char *data, const struct datetime_t *date) +{ + uint32_t len = mp_sizeof_datetime(date); + + data = mp_encode_extl(data, MP_DATETIME, len); + + return datetime_pack(data, date); +} int datetime_to_string(const struct datetime_t * date, char *buf, uint32_t len) @@ -83,3 +209,38 @@ datetime_to_string(const struct datetime_t * date, char *buf, uint32_t len) } return (buf - src); } + +int +mp_snprint_datetime(char *buf, int size, const char **data, uint32_t len) +{ + struct datetime_t date = {0}; + + if (datetime_unpack(data, len, &date) == NULL) + return -1; + + return datetime_to_string(&date, buf, size); +} + +int +mp_fprint_datetime(FILE *file, const char **data, uint32_t len) +{ + struct datetime_t date; + + if (datetime_unpack(data, len, &date) == NULL) + return -1; + + char buf[48]; + datetime_to_string(&date, buf, sizeof buf); + + return fprintf(file, "%s", buf); +} + +int datetime_compare(const struct datetime_t *lhs, const struct datetime_t *rhs) +{ + int result = COMPARE_RESULT(lhs->secs, rhs->secs); + if (result != 0) + return result; + + return COMPARE_RESULT(lhs->nsec, rhs->nsec); +} + diff --git a/src/lib/core/datetime.h b/src/lib/core/datetime.h index fdaff2d27676..6e78d8ddbc2d 100644 --- a/src/lib/core/datetime.h +++ b/src/lib/core/datetime.h @@ -30,9 +30,10 @@ * SUCH DAMAGE. */ -#include +#include #include #include +#include #if defined(__cplusplus) extern "C" { @@ -60,6 +61,38 @@ struct datetime_interval_t { int32_t nsec; ///< nanoseconds delta }; +int +datetime_compare(const struct datetime_t * lhs, + const struct datetime_t * rhs); + + +struct datetime_t * +datetime_unpack(const char **data, uint32_t len, struct datetime_t *date); + +/** + * Pack datetime_t data to the MessagePack buffer. + */ +char * +datetime_pack(char *data, const struct datetime_t *date); + +/** + * Calculate size of MessagePack buffer for datetime_t data. + */ +uint32_t +mp_sizeof_datetime(const struct datetime_t *date); + +/** + * Decode data from MessagePack buffer to datetime_t structure. + */ +struct datetime_t * +mp_decode_datetime(const char **data, struct datetime_t *date); + +/** + * Encode datetime_t structure to the MessagePack buffer. + */ +char * +mp_encode_datetime(char *data, const struct datetime_t *date); + /** * Convert datetime to string using default format * @param date source datetime value @@ -69,6 +102,12 @@ struct datetime_interval_t { int datetime_to_string(const struct datetime_t * date, char *buf, uint32_t len); +int +mp_snprint_datetime(char *buf, int size, const char **data, uint32_t len); + +int +mp_fprint_datetime(FILE *file, const char **data, uint32_t len); + #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/src/lib/core/mp_extension_types.h b/src/lib/core/mp_extension_types.h index e3ff9f5d0781..3b7eaee7cb5a 100644 --- a/src/lib/core/mp_extension_types.h +++ b/src/lib/core/mp_extension_types.h @@ -44,6 +44,7 @@ enum mp_extension_type { MP_DECIMAL = 1, MP_UUID = 2, MP_ERROR = 3, + MP_DATETIME = 4, mp_extension_type_MAX, }; diff --git a/src/lib/mpstream/mpstream.c b/src/lib/mpstream/mpstream.c index 70ca2988966d..1077e3b19f26 100644 --- a/src/lib/mpstream/mpstream.c +++ b/src/lib/mpstream/mpstream.c @@ -35,6 +35,7 @@ #include "msgpuck.h" #include "mp_decimal.h" #include "uuid/mp_uuid.h" +#include "core/datetime.h" void mpstream_reserve_slow(struct mpstream *stream, size_t size) @@ -208,6 +209,16 @@ mpstream_encode_uuid(struct mpstream *stream, const struct tt_uuid *uuid) mpstream_advance(stream, pos - data); } +void +mpstream_encode_datetime(struct mpstream *stream, const struct datetime_t *val) +{ + char *data = mpstream_reserve(stream, mp_sizeof_datetime(val)); + if (data == NULL) + return; + char *pos = mp_encode_datetime(data, val); + mpstream_advance(stream, pos - data); +} + void mpstream_memcpy(struct mpstream *stream, const void *src, uint32_t n) { diff --git a/src/lib/mpstream/mpstream.h b/src/lib/mpstream/mpstream.h index a60add1437c1..540e9a6665a9 100644 --- a/src/lib/mpstream/mpstream.h +++ b/src/lib/mpstream/mpstream.h @@ -39,6 +39,7 @@ extern "C" { #endif /* defined(__cplusplus) */ struct tt_uuid; +struct datetime_t; /** * Ask the allocator to reserve at least size bytes. It can reserve @@ -145,6 +146,9 @@ mpstream_encode_decimal(struct mpstream *stream, const decimal_t *val); void mpstream_encode_uuid(struct mpstream *stream, const struct tt_uuid *uuid); +void +mpstream_encode_datetime(struct mpstream *stream, const struct datetime_t *dt); + /** Copies n bytes from memory area src to stream. */ void mpstream_memcpy(struct mpstream *stream, const void *src, uint32_t n); diff --git a/src/lua/msgpack.c b/src/lua/msgpack.c index b6ecf2b1e377..0a4ba8129d48 100644 --- a/src/lua/msgpack.c +++ b/src/lua/msgpack.c @@ -46,6 +46,7 @@ #include "lib/core/decimal.h" /* decimal_unpack() */ #include "lib/uuid/mp_uuid.h" /* mp_decode_uuid() */ #include "lib/core/mp_extension_types.h" +#include "datetime.h" #include "cord_buf.h" #include @@ -200,6 +201,9 @@ luamp_encode_r(struct lua_State *L, struct luaL_serializer *cfg, break; case MP_ERROR: return luamp_encode_extension(L, top, stream); + case MP_DATETIME: + mpstream_encode_datetime(stream, field->dateval); + break; default: /* Run trigger if type can't be encoded */ type = luamp_encode_extension(L, top, stream); @@ -333,6 +337,14 @@ luamp_decode(struct lua_State *L, struct luaL_serializer *cfg, goto ext_decode_err; return; } + case MP_DATETIME: + { + struct datetime_t * date = luaL_pushdatetime(L); + date = datetime_unpack(data, len, date); + if (date == NULL) + goto ext_decode_err; + return; + } default: /* reset data to the extension header */ *data = svp; diff --git a/src/lua/msgpackffi.lua b/src/lua/msgpackffi.lua index 1d54f11b8988..271be857a498 100644 --- a/src/lua/msgpackffi.lua +++ b/src/lua/msgpackffi.lua @@ -36,6 +36,8 @@ decimal_t * decimal_unpack(const char **data, uint32_t len, decimal_t *dec); struct tt_uuid * uuid_unpack(const char **data, uint32_t len, struct tt_uuid *uuid); +struct datetime_t * +datetime_unpack(const char **data, uint32_t len, struct datetime_t *date); ]]) local strict_alignment = (jit.arch == 'arm') @@ -513,6 +515,12 @@ local ext_decoder = { builtin.uuid_unpack(data, len, uuid) return uuid end, + -- MP_DATETIME + [4] = function(data, len) + local dt = ffi.new("struct datetime_t") + builtin.datetime_unpack(data, len, dt) + return dt + end, } local function decode_ext(data) diff --git a/src/lua/serializer.c b/src/lua/serializer.c index 8db6746a3dce..c27e62c62368 100644 --- a/src/lua/serializer.c +++ b/src/lua/serializer.c @@ -41,6 +41,7 @@ #include "lib/core/mp_extension_types.h" #include "lua/error.h" +#include "datetime.h" #include "trivia/util.h" #include "diag.h" #include "serializer_opts.h" @@ -544,6 +545,9 @@ luaL_tofield(struct lua_State *L, struct luaL_serializer *cfg, opts != NULL && opts->error_marshaling_enabled) { field->ext_type = MP_ERROR; + } else if (cd->ctypeid == CTID_DATETIME) { + field->ext_type = MP_DATETIME; + field->dateval = (struct datetime_t*) cdata; } else { field->ext_type = MP_UNKNOWN_EXTENSION; } diff --git a/src/lua/serializer.h b/src/lua/serializer.h index 0a0501a742de..52e51d279a25 100644 --- a/src/lua/serializer.h +++ b/src/lua/serializer.h @@ -52,6 +52,7 @@ extern "C" { #include #include "trigger.h" +#include "lib/core/datetime.h" #include "lib/core/decimal.h" /* decimal_t */ #include "lib/core/mp_extension_types.h" #include "lua/error.h" @@ -223,6 +224,7 @@ struct luaL_field { uint32_t size; decimal_t *decval; struct tt_uuid *uuidval; + struct datetime_t *dateval; }; enum mp_type type; /* subtypes of MP_EXT */ diff --git a/src/lua/utils.c b/src/lua/utils.c index 6aeb18cfe842..a959ed9ddb7e 100644 --- a/src/lua/utils.c +++ b/src/lua/utils.c @@ -241,7 +241,6 @@ luaL_setcdatagc(struct lua_State *L, int idx) lua_pop(L, 1); } - /** * A helper to register a single type metatable. */ diff --git a/test/unit/datetime.c b/test/unit/datetime.c index b6f568c0338d..226b6fadb07d 100644 --- a/test/unit/datetime.c +++ b/test/unit/datetime.c @@ -139,7 +139,6 @@ parse_datetime(const char *str, size_t len, int64_t *sp, int32_t *np, // avoid introducing external datetime.h dependency // - just copy paste it for today #define SECS_PER_DAY 86400 -#define NANOS_PER_SEC 1000000000 #define DT_EPOCH_1970_OFFSET 719163 diff --git a/third_party/lua-cjson/lua_cjson.c b/third_party/lua-cjson/lua_cjson.c index 5123b9a748e8..d5ddc4ea0039 100644 --- a/third_party/lua-cjson/lua_cjson.c +++ b/third_party/lua-cjson/lua_cjson.c @@ -52,6 +52,7 @@ #include "mp_extension_types.h" /* MP_DECIMAL, MP_UUID */ #include "tt_static.h" #include "uuid/tt_uuid.h" /* tt_uuid_to_string(), UUID_STR_LEN */ +#include "core/datetime.h" #include "cord_buf.h" typedef enum { @@ -426,6 +427,13 @@ static void json_append_data(lua_State *l, struct luaL_serializer *cfg, case MP_UUID: return json_append_string(cfg, json, tt_uuid_str(field.uuidval), UUID_STR_LEN); + + case MP_DATETIME: + { + char buf[128]; + size_t sz = datetime_to_string(field.dateval, buf, sizeof buf); + return json_append_string(cfg, json, buf, sz); + } default: assert(false); } diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc index 5469e9f4f4bc..b76a45dfbc1c 100644 --- a/third_party/lua-yaml/lyaml.cc +++ b/third_party/lua-yaml/lyaml.cc @@ -617,7 +617,7 @@ static int dump_node(struct lua_yaml_dumper *dumper) yaml_event_t ev; yaml_scalar_style_t style = YAML_PLAIN_SCALAR_STYLE; int is_binary = 0; - char buf[FPCONV_G_FMT_BUFSIZE]; + char buf[FPCONV_G_FMT_BUFSIZE + 8]; // FIXME - need extra space for datetime struct luaL_field field; bool unused; (void) unused; @@ -707,6 +707,10 @@ static int dump_node(struct lua_yaml_dumper *dumper) str = tt_uuid_str(field.uuidval); len = UUID_STR_LEN; break; + case MP_DATETIME: + len = datetime_to_string(field.dateval, buf, sizeof buf); + str = buf; + break; default: assert(0); /* checked by luaL_checkfield() */ }