diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | luaejdb/luabson.c | 151 | ||||
-rwxr-xr-x | tcejdb/configure | 18 | ||||
-rw-r--r-- | tcejdb/configure.ac | 2 | ||||
-rw-r--r-- | tcejdb/tcutil.h | 2 |
5 files changed, 154 insertions, 20 deletions
@@ -96,5 +96,4 @@ tcejdb/debian/*.debhelper /python3-ejdb_*.deb -luaejdb/Makefile luaejdb/test/testdb* diff --git a/luaejdb/luabson.c b/luaejdb/luabson.c index 09c1f7b..8a37595 100644 --- a/luaejdb/luabson.c +++ b/luaejdb/luabson.c @@ -2,6 +2,7 @@ #include "luabson.h" #include <lualib.h> #include <lauxlib.h> +#include <math.h> static void lua_push_bson_value(lua_State *L, bson_iterator *it); static void lua_push_bson_table(lua_State *L, bson_iterator *it); @@ -126,38 +127,172 @@ int lua_from_bson(lua_State *L) { bson_iterator it; bson_iterator_from_buffer(&it, bsdata); lua_push_bson_table(L, &it); - return 0; + return 1; } int lua_to_bson(lua_State *L) { + luaL_checktype(L, lua_gettop(L), LUA_TTABLE); bson bs; bson_init_as_query(&bs); lua_to_bson_impl(L, lua_gettop(L), &bs); - if (bs.err) { + if (bs.err || bson_finish(&bs)) { lua_pushstring(L, bson_first_errormsg(&bs)); + bson_destroy(&bs); return lua_error(L); } lua_pushlstring(L, bson_data(&bs), bson_size(&bs)); + bson_destroy(&bs); return 1; } -static void lua_append_bson(lua_State *L, const char *key, int vpos, bson *bs, int tref) { +static void lua_val_to_bson(lua_State *L, const char *key, int vpos, bson *bs, int tref) { int vtype = lua_type(L, vpos); - + char nbuf[TCNUMBUFSIZ]; + switch (vtype) { + case LUA_TTABLE: + { + if (vpos < 0) vpos = lua_gettop(L) + vpos + 1; + lua_checkstack(L, 3); + int bsontype_found = luaL_getmetafield(L, vpos, "__bsontype"); + if (!bsontype_found) { + //check if registry tbl contains traversed tbl + lua_rawgeti(L, LUA_REGISTRYINDEX, tref); + lua_pushvalue(L, vpos); + lua_rawget(L, -2); + if (lua_toboolean(L, -1)) { //already traversed + lua_pop(L, 2); + break; + } + //setup traversed state + lua_pop(L, 1); + lua_pushvalue(L, vpos); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + lua_pop(L, 1); + + bool array = true; + int len = 0; + for (lua_pushnil(L); lua_next(L, vpos); lua_pop(L, 1)) { + ++len; + if ((lua_type(L, -2) != LUA_TNUMBER) || (lua_tointeger(L, -2) != len)) { + lua_pop(L, 2); + array = false; + break; + } + } + if (array) { + bson_append_start_array(bs, key); + for (int i = 0; i < len; i++) { + lua_rawgeti(L, vpos, i + 1); + bson_numstrn(nbuf, TCNUMBUFSIZ, (int64_t) i); + lua_val_to_bson(L, nbuf, -1, bs, tref); + lua_pop(L, 1); + } + bson_append_finish_array(bs); + } else { + for (lua_pushnil(L); lua_next(L, vpos); lua_pop(L, 1)) { + int ktype = lua_type(L, -2); + if (ktype == LUA_TNUMBER) { + char key[TCNUMBUFSIZ]; + bson_numstrn(key, TCNUMBUFSIZ, (int64_t) lua_tointeger(L, -2)); + lua_val_to_bson(L, key, -1, bs, tref); + } else if (ktype == LUA_TSTRING) { + lua_val_to_bson(L, lua_tostring(L, -2), -1, bs, tref); + } + } + } + } else { + int bson_type = lua_tointeger(L, -1); + lua_pop(L, 1); //pop metafield __bsontype + lua_rawgeti(L, -1, 1); //get first value + switch (bson_type) { + case BSON_OID: + { + const char* boid = lua_tostring(L, -1); + if (boid && strlen(boid) == 24) { + bson_oid_t oid; + bson_oid_from_string(&oid, boid); + bson_append_oid(bs, key, &oid); + } + break; + } + case BSON_DATE: + bson_append_date(bs, key, (bson_date_t) lua_tonumber(L, -1)); + break; + case BSON_REGEX: + { + const char* regex = lua_tostring(L, -1); + lua_rawgeti(L, -2, 2); // re opts + const char* options = lua_tostring(L, -1); + lua_pop(L, 1); + if (regex && options) { + bson_append_regex(bs, key, regex, options); + } + break; + } + case BSON_BINDATA: + { + size_t len; + const char* cbuf = lua_tolstring(L, -1, &len); + bson_append_binary(bs, key, BSON_BIN_BINARY, cbuf, len); + break; + } + case BSON_NULL: + bson_append_null(bs, key); + break; + case BSON_UNDEFINED: + bson_append_undefined(bs, key); + break; + default: + break; + } + } + break; + } + case LUA_TNIL: + bson_append_null(bs, key); + break; + case LUA_TNUMBER: + { + lua_Number numval = lua_tonumber(L, vpos); + if (numval == floor(numval)) { + int64_t iv = (int64_t) numval; + if (-(1LL << 31) <= iv && iv <= (1LL << 31)) { + bson_append_int(bs, key, iv); + } else { + bson_append_long(bs, key, iv); + } + } + break; + } + case LUA_TBOOLEAN: + bson_append_bool(bs, key, lua_toboolean(L, vpos)); + break; + + case LUA_TSTRING: + bson_append_string(bs, key, lua_tostring(L, vpos)); + break; + } } static void lua_to_bson_impl(lua_State *L, int tpos, bson *bs) { - lua_newtable(L); + lua_newtable(L); //traverse state table int tref = luaL_ref(L, LUA_REGISTRYINDEX); for (lua_pushnil(L); lua_next(L, tpos); lua_pop(L, 1)) { int ktype = lua_type(L, -2); if (ktype == LUA_TNUMBER) { char key[TCNUMBUFSIZ]; bson_numstrn(key, TCNUMBUFSIZ, (int64_t) lua_tonumber(L, -2)); - key[TCNUMBUFSIZ - 1] = '\0'; - lua_append_bson(L, key, -1, bs, tref); + lua_val_to_bson(L, key, -1, bs, tref); } else if (ktype == LUA_TSTRING) { - lua_append_bson(L, lua_tostring(L, -2), -1, bs, tref); + const char* key = lua_tostring(L, -2); + if (lua_type(L, -1) == LUA_TSTRING && !strcmp("_id", key)) { //root level OID as string + //pack OID as type table + lua_pushvalue(L, -1); //dup oid on stack + lua_push_bsontype_table(L, BSON_OID); //push type table + lua_rawseti(L, -2, 1); //pop oid val + } + lua_val_to_bson(L, key, -1, bs, tref); } } lua_unref(L, tref); diff --git a/tcejdb/configure b/tcejdb/configure index 29b53d9..1c652e5 100755 --- a/tcejdb/configure +++ b/tcejdb/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for tcejdb 1.0.65. +# Generated by GNU Autoconf 2.69 for tcejdb 1.0.66. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tcejdb' PACKAGE_TARNAME='tcejdb' -PACKAGE_VERSION='1.0.65' -PACKAGE_STRING='tcejdb 1.0.65' +PACKAGE_VERSION='1.0.66' +PACKAGE_STRING='tcejdb 1.0.66' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1258,7 +1258,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures tcejdb 1.0.65 to adapt to many kinds of systems. +\`configure' configures tcejdb 1.0.66 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1319,7 +1319,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of tcejdb 1.0.65:";; + short | recursive ) echo "Configuration of tcejdb 1.0.66:";; esac cat <<\_ACEOF @@ -1426,7 +1426,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -tcejdb configure 1.0.65 +tcejdb configure 1.0.66 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1724,7 +1724,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by tcejdb $as_me 1.0.65, which was +It was created by tcejdb $as_me 1.0.66, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4893,7 +4893,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by tcejdb $as_me 1.0.65, which was +This file was extended by tcejdb $as_me 1.0.66, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4946,7 +4946,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -tcejdb config.status 1.0.65 +tcejdb config.status 1.0.66 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/tcejdb/configure.ac b/tcejdb/configure.ac index 6983dba..29a270e 100644 --- a/tcejdb/configure.ac +++ b/tcejdb/configure.ac @@ -11,7 +11,7 @@ test -n "$CPPFLAGS" && MYCPPFLAGS="$CPPFLAGS $MYCPPFLAGS" test -n "$LDFLAGS" && MYLDFLAGS="$LDFLAGS $MYLDFLAGS" # Package name -AC_INIT(tcejdb, 1.0.65) +AC_INIT(tcejdb, 1.0.66) # Package information MYLIBVER=9 diff --git a/tcejdb/tcutil.h b/tcejdb/tcutil.h index 6c01ab0..b35ac05 100644 --- a/tcejdb/tcutil.h +++ b/tcejdb/tcutil.h @@ -3719,7 +3719,7 @@ typedef unsigned char TCBITMAP; /* type of a bit map object */ #include <stdio.h> -#define _TC_VERSION "1.0.65" +#define _TC_VERSION "1.0.66" #define _TC_LIBVER 911 #define _TC_FORMATVER "1.0" |