diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml index 1537a32feedaaf0ea3ecddc1ab33805532664900..e326717c030071caaf4c4136b8e9982ed5a40b01 100644 --- a/doc/user/stored-procedures.xml +++ b/doc/user/stored-procedures.xml @@ -726,6 +726,31 @@ localhost> lua box.select_reverse_range(4, 1, 2, '1') integer, and stores the integer in the resulting string, low byte first, </member> + <member><code>n</code> — converts Lua + variable to a 2-byte + integer, and stores the integer in the resulting + string, big endian, + </member> + <member><code>N</code> — converts Lua + variable to a 4-byte + integer, and stores the integer in the resulting + string, big endian, + </member> + <member><code>Q</code> — converts Lua + variable to a 8-byte + integer, and stores the integer in the resulting + string, big endian, + </member> + <member><code>f</code> — converts Lua + variable to a 4-byte + float, and stores the float in the resulting + string, + </member> + <member><code>d</code> — converts Lua + variable to a 8-byte + double, and stores the double in the resulting + string, + </member> <member><code>w</code> — converts Lua integer to a BER-encoded integer, </member> diff --git a/src/box/box_lua.cc b/src/box/box_lua.cc index 4848f8fbbb28197df66a2d8b23455c9fbfd6071a..7672b80bb16626aed6c8f05ee81fb63918115be0 100644 --- a/src/box/box_lua.cc +++ b/src/box/box_lua.cc @@ -42,6 +42,7 @@ extern "C" { #include <lj_ctype.h> #include <lj_cdata.h> #include <lj_cconv.h> +#include <endian.h> } /* extern "C" */ #include "pickle.h" @@ -1477,6 +1478,11 @@ lbox_pack(struct lua_State *L) luaL_buffinit(L, &b); struct lua_field field; + double dbl; + float flt; + uint16_t u16; + uint32_t u32; + uint64_t u64; while (*format) { if (i > nargs) luaL_error(L, "box.pack: argument count does not match " @@ -1497,6 +1503,13 @@ lbox_pack(struct lua_State *L) luaL_error(L, "box.pack: expected 16-bit int"); luaL_addlstring(&b, field.data, sizeof(uint16_t)); break; + case 'n': + /* signed and unsigned 16-bit big endian integers */ + if (field.type != NUM || field.u32 > UINT16_MAX) + luaL_error(L, "box.pack: expected 16-bit int"); + u16 = htobe16( (uint16_t) field.u32 ); + luaL_addlstring(&b, (char *)&u16, sizeof(u16)); + break; case 'I': case 'i': /* signed and unsigned 32-bit integers */ @@ -1504,6 +1517,13 @@ lbox_pack(struct lua_State *L) luaL_error(L, "box.pack: expected 32-bit int"); luaL_addlstring(&b, field.data, sizeof(uint32_t)); break; + case 'N': + /* signed and unsigned 32-bit big endian integers */ + if (field.type != NUM) + luaL_error(L, "box.pack: expected 32-bit int"); + u32 = htobe32( field.u32 ); + luaL_addlstring(&b, (char *)&u32, sizeof(uint32_t)); + break; case 'L': case 'l': /* signed and unsigned 64-bit integers */ @@ -1511,12 +1531,34 @@ lbox_pack(struct lua_State *L) luaL_addlstring(&b, field.data, field.len); } else if (field.type == NUM) { /* extend 32-bit value to 64-bit */ - uint64_t val = field.u32; - luaL_addlstring(&b, (char *)&val, sizeof(val)); + u64 = field.u32; + luaL_addlstring(&b, (char *)&u64, sizeof(u64)); } else { luaL_error(L, "box.pack: expected 64-bit int"); } break; + case 'Q': + case 'q': + /* signed and unsigned 64-bit integers */ + if (field.type == NUM64) { + u64 = *(uint64_t*) field.data; + } else if (field.type == NUM) { + /* extend 32-bit value to 64-bit */ + u64 = field.u32; + } else { + luaL_error(L, "box.pack: expected 64-bit int"); + } + u64 = htobe64(u64); + luaL_addlstring(&b, (char *)&u64, sizeof(u64)); + break; + case 'd': + dbl = (double) lua_tonumber(L, i); + luaL_addlstring(&b, (char *) &dbl, sizeof(dbl)); + break; + case 'f': + flt = (float) lua_tonumber(L, i); + luaL_addlstring(&b, (char *) &flt, sizeof(flt)); + break; case 'w': /* Perl 'pack' BER-encoded integer */ if (field.type != NUM) @@ -1618,6 +1660,8 @@ lbox_unpack(struct lua_State *L) uint8_t u8buf; uint16_t u16buf; uint32_t u32buf; + double dbl; + float flt; #define CHECK_SIZE(cur) if (unlikely((cur) >= end)) { \ luaL_error(L, "box.unpack('%c'): got %d bytes (expected: %d+)", \ @@ -1637,17 +1681,46 @@ lbox_unpack(struct lua_State *L) lua_pushnumber(L, u16buf); s += 2; break; + case 'n': + CHECK_SIZE(s + 1); + u16buf = be16toh(*(uint16_t *) s); + lua_pushnumber(L, u16buf); + s += 2; + break; case 'i': CHECK_SIZE(s + 3); u32buf = *(uint32_t *) s; lua_pushnumber(L, u32buf); s += 4; break; + case 'N': + CHECK_SIZE(s + 3); + u32buf = be32toh(*(uint32_t *) s); + lua_pushnumber(L, u32buf); + s += 4; + break; case 'l': CHECK_SIZE(s + 7); luaL_pushnumber64(L, *(uint64_t*) s); s += 8; break; + case 'q': + CHECK_SIZE(s + 7); + luaL_pushnumber64(L, be64toh(*(uint64_t*) s)); + s += 8; + break; + case 'd': + CHECK_SIZE(s + 7); + dbl = *(double *) s; + lua_pushnumber(L, dbl); + s += 8; + break; + case 'f': + CHECK_SIZE(s + 3); + flt = *(float *) s; + lua_pushnumber(L, flt); + s += 4; + break; case 'w': /* pick_varint32 throws exception on error. */ u32buf = pick_varint32(&s, end);