diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Changelog | 18 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | cmake/Modules/Win32LIBTools.cmake | 2 | ||||
-rw-r--r-- | nejdb/README.md | 2 | ||||
-rwxr-xr-x | release.sh | 21 | ||||
-rw-r--r-- | src/CMakeLists.txt | 67 | ||||
-rw-r--r-- | src/bson/bson.c | 152 | ||||
-rw-r--r-- | src/bson/bson.h | 67 | ||||
-rw-r--r-- | src/bson/tests/CMakeLists.txt | 14 | ||||
-rw-r--r-- | src/bson/tests/bsontest.c | 183 | ||||
-rw-r--r-- | src/ejdb/tests/ejdbtest2.c | 136 | ||||
-rw-r--r-- | src/tchdb/tchdb.c | 22 | ||||
-rw-r--r-- | src/tcutil/win32/platform.h | 1 |
14 files changed, 628 insertions, 60 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ff23dc4..5d6c68d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ endif(POLICY CMP0042) if (CMAKE_SIZEOF_VOID_P MATCHES 8) set(PROJECT_ARCH "x86_64") + add_definitions("-D_FILE_OFFSET_BITS=64") else(CMAKE_SIZEOF_VOID_P MATCHES 8) set(PROJECT_ARCH "x86") endif(CMAKE_SIZEOF_VOID_P MATCHES 8) @@ -1,4 +1,18 @@ -ejdb (1.2.8) UNRELEASED; urgency=low +ejdb (1.2.10) testing; urgency=medium + + * Fix: Uninitialized Memory Conditional fixe #155 + * Fix: $set fails to create nested keys if supplied with a non existent topmost key #148 + + -- Anton Adamansky <adamansky@gmail.com> Fri, 24 Jul 2015 17:21:38 +0600 + +ejdb (1.2.9) testing; urgency=low + + * Fix: Builds shared lib when -DBUILD_SHARED_LIBS:BOOL=OFF #143 + * Fix: Not able to store data above 2GB on windows #149 + + -- Anton Adamansky <adam@dev-main.weblab.nsu.ru> Fri, 10 Jul 2015 14:30:07 +0600 + +ejdb (1.2.8) testing; urgency=low * Fix: Problem with the bson2json conversion dealing with doubles #135 * $push and $pushAll operations are implemented. #130 @@ -7,7 +21,7 @@ ejdb (1.2.8) UNRELEASED; urgency=low * Source code style fixes * A data format version info now stored in the database meta header #139 - -- Anton Adamansky <adamansky@gmail.com> Mon, 27 Apr 2015 21:30:11 +0600 + -- Anton Adamansky <adamansky@gmail.com> Mon, 01 Jun 2015 13:07:17 +0600 ejdb (1.2.7) testing; urgency=low @@ -3,6 +3,8 @@ Embedded JSON Database engine C library (libejdb) ================================================= +[![Join the chat at https://gitter.im/Softmotions/ejdb](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Softmotions/ejdb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + **See http://ejdb.org** It aims to be a fast [MongoDB](http://mongodb.org)-like library diff --git a/cmake/Modules/Win32LIBTools.cmake b/cmake/Modules/Win32LIBTools.cmake index 0dcf437..d218364 100644 --- a/cmake/Modules/Win32LIBTools.cmake +++ b/cmake/Modules/Win32LIBTools.cmake @@ -15,7 +15,7 @@ if (NOT WINTOOLS_WGET_EXEC) endif() set(WINTOOLS_DIR ${CMAKE_BINARY_DIR}/WINTOOLS) -set(WINTOOLS_DL_ROOT "https://dl.dropboxusercontent.com/u/4709222/windev") +set(WINTOOLS_DL_ROOT "http://softmotions.com/windev") if (NOT EXISTS ${WINTOOLS_DIR}) file(MAKE_DIRECTORY ${WINTOOLS_DIR}) diff --git a/nejdb/README.md b/nejdb/README.md new file mode 100644 index 0000000..ce68cea --- /dev/null +++ b/nejdb/README.md @@ -0,0 +1,2 @@ + +# See [EJDB C# Driver](https://github.com/Softmotions/ejdb-csharp) diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..f447e12 --- /dev/null +++ b/release.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e +set -x + +cd `readlink -f "$0" | xargs dirname` +git pull +dch --distribution testing --no-force-save-on-release --release "" -c ./Changelog +VERSION=`dpkg-parsechangelog -l./Changelog -SVersion` +TAG="v${VERSION}" +CHANGESET=`dpkg-parsechangelog -l./Changelog -SChanges | sed '/^ejdb.*/d' | sed '/^\s*$/d'` +git add ./Changelog + +if ! git diff-index --quiet HEAD --; then + git commit -m"${TAG} landed" + git push origin master +fi + +echo "${CHANGESET}" | git tag -f -a -F - "${TAG}" +git push -f --tags + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5702d88..0f9f9f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,12 +34,15 @@ foreach(MODULE IN LISTS MODULES) list(APPEND PUB_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/${MODULE}.h) endforeach(MODULE) -add_library(ejdb SHARED ${ALL_SRC}) if (NOT BUILD_SHARED_LIBS) add_definitions(-DEJDB_NODLL) + add_library(ejdb STATIC ${ALL_SRC}) + add_library(ejdb_p ALIAS ejdb) +else() + add_library(ejdb SHARED ${ALL_SRC}) + add_library(ejdb_p STATIC ${ALL_SRC}) endif() -add_library(ejdb_p STATIC ${ALL_SRC}) find_package(Threads REQUIRED CMAKE_THREAD_PREFER_PTHREAD) if (CMAKE_USE_WIN32_THREADS_INIT) @@ -142,7 +145,9 @@ list(REMOVE_DUPLICATES EJDB_INCLUDE_DIRS) include_directories(${EJDB_INCLUDE_DIRS}) target_link_libraries(ejdb ${EJDB_LLIBRARIES}) -target_link_libraries(ejdb_p ${EJDB_LLIBRARIES}) +if (BUILD_SHARED_LIBS) + target_link_libraries(ejdb_p ${EJDB_LLIBRARIES}) +endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -fsigned-char -pedantic -Wfatal-errors -Wno-unknown-pragmas") if (NOT WIN32) ## todo review @@ -177,10 +182,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/myconf.h.in ${EJDB_GENERATED_DIR}/myc file(GLOB EJDB_GENERATED_HDRS ${EJDB_GENERATED_DIR}/*.h) list(APPEND ALL_HDRS ${EJDB_GENERATED_HDRS}) -if (NOT APPLE AND NOT BUILD_FRAMEWORK) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libejdb.pc.in ${EJDB_GENERATED_DIR}/libejdb.pc @ONLY) - install(FILES ${EJDB_GENERATED_DIR}/libejdb.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -endif(NOT APPLE AND NOT BUILD_FRAMEWORK) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libejdb.pc.in ${EJDB_GENERATED_DIR}/libejdb.pc @ONLY) +install(FILES ${EJDB_GENERATED_DIR}/libejdb.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) foreach(MODULE IN LISTS MODULES) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}/CMakeLists.txt) @@ -197,13 +200,7 @@ endforeach(MODULE) list(APPEND PUB_HDRS ${EJDB_GENERATED_DIR}/basedefs.h ${CMAKE_CURRENT_SOURCE_DIR}/ejdb/ejdb_private.h) - -set_target_properties(ejdb PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - PUBLIC_HEADER "${PUB_HDRS}" - DEFINE_SYMBOL EJDB_API_EXPORTS) -if (WIN32) +if (WIN32 AND BUILD_SHARED_LIBS) add_dependencies(ejdb wintools_init) set_target_properties(ejdb PROPERTIES LINK_FLAGS "-Wl,--output-def,libejdb.def") add_w32_importlib(ejdb libejdb ${CMAKE_CURRENT_BINARY_DIR}) @@ -214,10 +211,26 @@ if (WIN32) DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() +if (BUILD_SHARED_LIBS) + +set_target_properties(ejdb PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + PUBLIC_HEADER "${PUB_HDRS}" + DEFINE_SYMBOL EJDB_API_EXPORTS) + set_target_properties(ejdb_p PROPERTIES VERSION ${PROJECT_VERSION} COMPILE_FLAGS "-DEJDB_NODLL" OUTPUT_NAME ejdb-${PROJECT_VERSION_MAJOR}) +else() + +set_target_properties(ejdb PROPERTIES + VERSION ${PROJECT_VERSION} + PUBLIC_HEADER "${PUB_HDRS}" + COMPILE_FLAGS "-DEJDB_NODLL" + OUTPUT_NAME ejdb-${PROJECT_VERSION_MAJOR}) +endif() install(TARGETS ejdb EXPORT ejdb-exports @@ -230,13 +243,15 @@ install(TARGETS ejdb install(EXPORT ejdb-exports DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}) -install(TARGETS ejdb_p - EXPORT ejdb-static-exports - FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) +if (BUILD_SHARED_LIBS) + install(TARGETS ejdb_p + EXPORT ejdb-static-exports + FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) +endif() install(FILES ${CMAKE_SOURCE_DIR}/LICENSE @@ -251,10 +266,14 @@ install(FILES if (CMAKE_VERSION VERSION_GREATER 3.0) export(EXPORT ejdb-exports) - export(EXPORT ejdb-static-exports) + if (BUILD_SHARED_LIBS) + export(EXPORT ejdb-static-exports) + endif() else() - export(TARGETS ejdb FILE ejdb-exports.cmake) - export(TARGETS ejdb_p FILE ejdb-static-exports.cmake) + export(TARGETS ejdb FILE ejdb-exports.cmake) + if (BUILD_SHARED_LIBS) + export(TARGETS ejdb_p FILE ejdb-static-exports.cmake) + endif() endif() diff --git a/src/bson/bson.c b/src/bson/bson.c index 0d3c01e..64069e2 100644 --- a/src/bson/bson.c +++ b/src/bson/bson.c @@ -1397,7 +1397,7 @@ static void bson_append_fpath_from_iterator(const char *fpath, const bson_iterat memcpy(key, fp, keylen); key[keylen] = '\0'; rp++; - fplen -= keylen; + fplen -= keylen + 1; if (fplen <= 0) { //last part of fp bson_append_field_from_iterator2(key, from, into); while (nl-- > 0) { @@ -1623,6 +1623,19 @@ int bson_merge_fieldpaths(const void *bsdata1, const void *bsdata2, bson *out) { } } tcmapdel(mfields); + + if (!out->err) { + // check duplicate paths + bson_finish(out); + if (bson_check_duplicate_keys(out)) { + bson bstmp; + bson_copy(&bstmp, out); + bson_destroy(out); + bson_init(out); + bson_fix_duplicate_keys(&bstmp, out); + bson_destroy(&bstmp); + } + } return out->err; } @@ -1726,6 +1739,143 @@ int bson_merge_recursive(const bson *b1, const bson *b2, bson_bool_t overwrite, return bson_merge_recursive2(bson_data(b1), bson_data(b2), overwrite, out); } +static bson_bool_t _bson_check_duplicate_keys(bson_iterator *it) { + bson_iterator it2; + bson_type bt, bt2; + while ((bt = bson_iterator_next(it)) != BSON_EOO) { + BSON_ITERATOR_CLONE(it, &it2); + while((bt2 = bson_iterator_next(&it2)) != BSON_EOO) { + if (!strcmp(BSON_ITERATOR_KEY(it), BSON_ITERATOR_KEY(&it2))) { + return true; + } + } + if (bt == BSON_OBJECT || bt == BSON_ARRAY) { + BSON_ITERATOR_SUBITERATOR(it, &it2); + if (_bson_check_duplicate_keys(&it2)) { + return true; + } + } + } + + return false; +} + +bson_bool_t bson_check_duplicate_keys(const bson *bs) { + bson_iterator it; + BSON_ITERATOR_INIT(&it, bs); + return _bson_check_duplicate_keys(&it); +} + +static void _bson_fix_duplicate_keys(bson_iterator *it, bson *bso) { + bson_iterator it2; + bson_type bt, bt2; + + TCMAP *keys = tcmapnew(); + while((bt = bson_iterator_next(it)) != BSON_EOO) { + if (NULL != tcmapget2(keys, BSON_ITERATOR_KEY(it))) { + continue; + } + tcmapput2(keys, BSON_ITERATOR_KEY(it), BSON_ITERATOR_KEY(it)); + + TCLIST *dups = tclistnew(); + off_t itoff = 0; + tclistpush(dups, &itoff, sizeof(itoff)); + + BSON_ITERATOR_CLONE(it, &it2); + while((bt2 = bson_iterator_next(&it2)) != BSON_EOO) { + if (!strcmp(BSON_ITERATOR_KEY(it), BSON_ITERATOR_KEY(&it2))) { + bt2 = BSON_ITERATOR_TYPE(&it2); + if (bt != bt2 || (bt != BSON_OBJECT && bt != BSON_ARRAY)) { + tclistclear(dups); + bt = bt2; + } + itoff = it2.cur - it->cur; + tclistpush(dups, &itoff, sizeof(itoff)); + } + } + + const char *buf; + int bufsz; + + buf = tclistval(dups, TCLISTNUM(dups) - 1, &bufsz); + memcpy(&itoff, buf, sizeof(itoff)); + it2.cur = it->cur + itoff; + it2.first = itoff == 0 ? it->first : 0; + + bt2 = BSON_ITERATOR_TYPE(&it2); + if (bt2 == BSON_OBJECT) { + bson bst; + bson_init(&bst); + int j = -1; + while(++j < TCLISTNUM(dups)) { + buf = tclistval(dups, j, &bufsz); + memcpy(&itoff, buf, sizeof(itoff)); + it2.cur = it->cur + itoff; + it2.first = itoff == 0 ? it->first : 0; + + bson_iterator sit; + BSON_ITERATOR_SUBITERATOR(&it2, &sit); + while(bson_iterator_next(&sit) != BSON_EOO){ + bson_append_field_from_iterator(&sit, &bst); + } + } + bson_finish(&bst); + + bson_append_start_object(bso, BSON_ITERATOR_KEY(it)); + BSON_ITERATOR_INIT(&it2, &bst); + _bson_fix_duplicate_keys(&it2, bso); + bson_append_finish_object(bso); + bson_destroy(&bst); + } else if (bt2 == BSON_ARRAY) { + char ibuf[TCNUMBUFSIZ]; + memset(ibuf, '\0', TCNUMBUFSIZ); + + bson_append_start_array(bso, BSON_ITERATOR_KEY(it)); + int ind = 0; + int j = -1; + while(++j < TCLISTNUM(dups)) { + buf = tclistval(dups, TCLISTNUM(dups) - 1, &bufsz); + memcpy(&itoff, buf, sizeof(itoff)); + it2.cur = it->cur + itoff; + it2.first = itoff == 0 ? it->first : 0; + + bson_iterator sit, sit2; + bson_type sbt; + BSON_ITERATOR_SUBITERATOR(&it2, &sit); + while((sbt = bson_iterator_next(&sit)) != BSON_EOO) { + bson_numstrn(ibuf, TCNUMBUFSIZ, ind++); + if (sbt == BSON_OBJECT) { + bson_append_start_object(bso, ibuf); + BSON_ITERATOR_SUBITERATOR(&sit, &sit2); + _bson_fix_duplicate_keys(&sit2, bso); + bson_append_finish_object(bso); + } else if(sbt == BSON_ARRAY) { + bson_append_start_array(bso, ibuf); + BSON_ITERATOR_SUBITERATOR(&sit, &sit2); + _bson_fix_duplicate_keys(&sit2, bso); + bson_append_finish_array(bso); + } else { + bson_append_field_from_iterator2(ibuf, &sit, bso); + } + } + } + bson_append_finish_array(bso); + } else { + bson_append_field_from_iterator(&it2, bso); + } + tclistdel(dups); + } + tcmapdel(keys); +} + +void bson_fix_duplicate_keys(const bson *bsi, bson *bso) { + bson_iterator it; + + BSON_ITERATOR_INIT(&it, bsi); + _bson_fix_duplicate_keys(&it, bso); +} + + typedef struct { int nstack; //nested object stack pos int matched; //number of matched include fields diff --git a/src/bson/bson.h b/src/bson/bson.h index f7403f7..662af64 100644 --- a/src/bson/bson.h +++ b/src/bson/bson.h @@ -148,6 +148,9 @@ EJDB_EXPORT const char* bson_first_errormsg(bson *bson); (_bs_I)->cur = (_bs)->data + 4; \ (_bs_I)->first = 1; +#define BSON_ITERATOR_CLONE(_bs_I_S, _bs_I_T) \ + (_bs_I_T)->cur = (_bs_I_S)->cur; \ + (_bs_I_T)->first = (_bs_I_S)->first; /* -------------------------------- READING @@ -1008,6 +1011,70 @@ EJDB_EXPORT int bson_append_finish_object(bson *b); */ EJDB_EXPORT int bson_append_finish_array(bson *b); +EJDB_EXPORT int bson_merge_recursive(const bson *b1, const bson *b2, bson_bool_t overwrite, bson *out); + +/** + * Check duplicate keys + * @return true if bson contains duplicate keys + */ +EJDB_EXPORT bson_bool_t bson_check_duplicate_keys(const bson *bs); + +/** + * Remove duplicate keys from bson: + * - merge objects and arrays with same key: + * { a : { b : "value 1" }, a : { c : "value 2" } } -> { a : { b : "value 1", c : "value 2" } } + * - keep last value for non object and non array values + * { a : "value 1", a : "value 2" } -> { a : "value 2" } + * + * Example: + * { + * a : { + * b : 1, + * c : "c" + * }, + * b : NULL, + * c : [ + * { + * a : 1, + * b : 2, + * a : 0 + * }, + * { + * a : 0, + * b : 1, + * c : 3 + * } + * ], + * a : { + * d : 0, + * c : 1 + * } + * } + * + * => + * + * { + * a : { + * b : 1, + * c : 1, + * d : 0 + * }, + * b : NULL, + * c : [ + * { + * a : 0, + * b : 2 + * }, + * { + * a : 0, + b : 1, + c : 3 + * } + * ] + * } + */ +EJDB_EXPORT void bson_fix_duplicate_keys(const bson *bsi, bson *bso); + EJDB_EXPORT void bson_numstr(char *str, int64_t i); EJDB_EXPORT int bson_numstrn(char *str, int maxbuf, int64_t i); diff --git a/src/bson/tests/CMakeLists.txt b/src/bson/tests/CMakeLists.txt new file mode 100644 index 0000000..2096305 --- /dev/null +++ b/src/bson/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +link_libraries(ejdb_p ${CUNIT_LIBRARIES}) +include_directories(${CUNIT_INCLUDE_DIRS}) + +set(TEST_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${TEST_DATA_DIR}) + +add_executable(bsontest bsontest.c) +set_target_properties(bsontest + PROPERTIES + COMPILE_FLAGS "-DEJDB_STATIC") +add_test(NAME bsontest + WORKING_DIRECTORY ${TEST_DATA_DIR} + COMMAND ${TEST_TOOL_CMD} $<TARGET_FILE:bsontest>) + diff --git a/src/bson/tests/bsontest.c b/src/bson/tests/bsontest.c new file mode 100644 index 0000000..935c3da --- /dev/null +++ b/src/bson/tests/bsontest.c @@ -0,0 +1,183 @@ +#include "myconf.h" +#include "bson.h" +#include "CUnit/Basic.h" + + +/* + * CUnit Test Suite + */ + +int init_suite(void) { + return 0; +} + +int clean_suite(void) { + return 0; +} + +void testCheckDuplicates(void) { + bson bs, bs2; + bson_iterator it; + bson_type bt; + + bson_init(&bs); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "b", 2); + bson_append_null(&bs, "c"); + bson_append_start_object(&bs, "d"); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "e", 0); + bson_append_int(&bs, "d", 1); + bson_append_finish_object(&bs); + bson_finish(&bs); + CU_ASSERT_FALSE_FATAL(bs.err); + + CU_ASSERT_FALSE(bson_check_duplicate_keys(&bs)); + + bson_destroy(&bs); + + bson_init(&bs); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "b", 2); + bson_append_null(&bs, "c"); + bson_append_start_object(&bs, "d"); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "e", 0); + bson_append_int(&bs, "e", 1); + bson_append_finish_object(&bs); + bson_finish(&bs); + CU_ASSERT_FALSE_FATAL(bs.err); + + CU_ASSERT_TRUE(bson_check_duplicate_keys(&bs)); + + bson_init(&bs2); + bson_fix_duplicate_keys(&bs, &bs2); + bson_finish(&bs2); + + CU_ASSERT_FALSE(bson_check_duplicate_keys(&bs2)); + BSON_ITERATOR_INIT(&it, &bs2); + bt = bson_find_fieldpath_value("d.e", &it); + CU_ASSERT_TRUE(BSON_IS_NUM_TYPE(bt)); + CU_ASSERT_EQUAL(bson_iterator_int(&it), 1); + + bson_destroy(&bs2); + + bson_init(&bs); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "b", 2); + bson_append_null(&bs, "c"); + bson_append_start_object(&bs, "d"); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "e", 0); + bson_append_int(&bs, "d", 1); + bson_append_finish_object(&bs); + bson_append_start_array(&bs, "f"); + bson_append_start_object(&bs, "0"); + bson_append_string(&bs, "a", "a"); + bson_append_string(&bs, "b", "b"); + bson_append_int(&bs, "c", 1); + bson_append_finish_object(&bs); + bson_append_start_object(&bs, "1"); + bson_append_string(&bs, "a", "a"); + bson_append_string(&bs, "b", "b"); + bson_append_int(&bs, "c", 1); + bson_append_finish_object(&bs); + bson_append_finish_array(&bs); + bson_finish(&bs); + CU_ASSERT_FALSE_FATAL(bs.err); + + CU_ASSERT_FALSE(bson_check_duplicate_keys(&bs)); + + bson_init(&bs); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "b", 2); + bson_append_null(&bs, "c"); + bson_append_start_object(&bs, "d"); + bson_append_string(&bs, "a", "a"); + bson_append_int(&bs, "e", 0); + bson_append_int(&bs, "d", 1); + bson_append_start_object(&bs, "q"); + bson_append_int(&bs, "w", 0); + bson_append_finish_object(&bs); + bson_append_finish_object(&bs); + bson_append_start_array(&bs, "f"); + bson_append_start_object(&bs, "0"); + bson_append_string(&bs, "a", "a"); + bson_append_string(&bs, "b", "b"); + bson_append_int(&bs, "a", 1); + bson_append_finish_object(&bs); + bson_append_start_object(&bs, "1"); + bson_append_string(&bs, "a", "a"); + bson_append_string(&bs, "b", "b"); + bson_append_int(&bs, "c", 1); + bson_append_finish_object(&bs); + bson_append_finish_array(&bs); + bson_append_start_object(&bs, "a"); + bson_append_finish_object(&bs); + bson_append_start_object(&bs, "d"); + bson_append_start_object(&bs, "q"); + bson_append_int(&bs, "e", 1); + bson_append_finish_object(&bs); + bson_append_finish_object(&bs); + bson_finish(&bs); + CU_ASSERT_FALSE_FATAL(bs.err); + + CU_ASSERT_TRUE(bson_check_duplicate_keys(&bs)); + + bson_init(&bs2); + bson_fix_duplicate_keys(&bs, &bs2); + bson_finish(&bs2); + + CU_ASSERT_FALSE(bson_check_duplicate_keys(&bs2)); + BSON_ITERATOR_INIT(&it, &bs2); + bt = bson_find_fieldpath_value("f.0.a", &it); + CU_ASSERT_TRUE(BSON_IS_NUM_TYPE(bt)); + CU_ASSERT_EQUAL(bson_iterator_int(&it), 1); + BSON_ITERATOR_INIT(&it, &bs2); + bt = bson_find_fieldpath_value("f.1.a", &it); + CU_ASSERT_TRUE(BSON_IS_STRING_TYPE(bt)); + CU_ASSERT_FALSE(strcmp(bson_iterator_string(&it), "a")); + + BSON_ITERATOR_INIT(&it, &bs2); + bt = bson_find_fieldpath_value("a", &it); + CU_ASSERT_EQUAL(bt, BSON_OBJECT); + + BSON_ITERATOR_INIT(&it, &bs2); + bt = bson_find_fieldpath_value("d.q.w", &it); + CU_ASSERT_TRUE(BSON_IS_NUM_TYPE(bt)); + CU_ASSERT_EQUAL(bson_iterator_int(&it), 0); + BSON_ITERATOR_INIT(&it, &bs2); + bt = bson_find_fieldpath_value("d.q.e", &it); + CU_ASSERT_TRUE(BSON_IS_NUM_TYPE(bt)); + CU_ASSERT_EQUAL(bson_iterator_int(&it), 1); +} + +int main() { + setlocale(LC_ALL, "en_US.UTF-8"); + CU_pSuite pSuite = NULL; + + /* Initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + /* Add a suite to the registry */ + pSuite = CU_add_suite("bsontest", init_suite, clean_suite); + if (NULL == pSuite) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Add the tests to the suite */ + if ((NULL == CU_add_test(pSuite, "testCheckDuplicates", testCheckDuplicates)) + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + int ret = CU_get_error() || CU_get_number_of_failures(); + CU_cleanup_registry(); + return ret; +} diff --git a/src/ejdb/tests/ejdbtest2.c b/src/ejdb/tests/ejdbtest2.c index 5cbbb36..1924732 100644 --- a/src/ejdb/tests/ejdbtest2.c +++ b/src/ejdb/tests/ejdbtest2.c @@ -6030,29 +6030,122 @@ void testTicket117(void) { tcxstrdel(log); } -void testTicket142() -{ - EJCOLL *coll = ejdbcreatecoll(jb, "ticket142", NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(coll); +void testTicket148(void) { + EJCOLL *coll = ejdbcreatecoll(jb, "ticket148", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); - bson b; - bson_oid_t oid; + bson bs; + bson_oid_t oid; - bson_init(&b); - bson_append_int(&b, "id", 18); - bson_append_symbol(&b, "sym", "eighteen"); - bson_finish(&b); - CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid); - bson_destroy(&b); + bson_init(&bs); + bson_finish(&bs); + CU_ASSERT_FALSE_FATAL(bs.err); + CU_ASSERT_TRUE_FATAL(ejdbsavebson(coll, &bs, &oid)); + bson_destroy(&bs); - /* Verify that id=18 contain record with symbol */ - bson bsq; + bson bsq; bson_init_as_query(&bsq); - bson_append_int(&bsq, "id", 18); - bson_finish(&bsq); - CU_ASSERT_FALSE_FATAL(bsq.err); + bson_append_start_object(&bsq, "$set"); + bson_append_int(&bsq, "info.name.par.age", 40); + bson_append_int(&bsq, "info.name.mot.age", 35); + bson_append_finish_object(&bsq); + bson_finish(&bsq); + CU_ASSERT_FALSE_FATAL(bsq.err); + + uint32_t count = ejdbupdate(coll, &bsq, 0, 0, 0, 0); + bson_destroy(&bsq); + CU_ASSERT_EQUAL(count, 1); + + bson_init_as_query(&bsq); + bson_finish(&bsq); + EJQ *q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL); + bson_destroy(&bsq); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, NULL); + CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1); + + void *bsdata = TCLISTVALPTR(q1res, 0); + CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata); + + bson_iterator it, sit; + bson_type bt; + BSON_ITERATOR_FROM_BUFFER(&it, bsdata); + while((bt = bson_iterator_next(&it)) != BSON_EOO) { + if (bt == BSON_OID) { + continue; + } + break; + } + CU_ASSERT_EQUAL(bt, BSON_OBJECT); + CU_ASSERT_FALSE(strcmp(BSON_ITERATOR_KEY(&it), "info")); + + BSON_ITERATOR_SUBITERATOR(&it, &sit); + bt = bson_iterator_next(&sit); + CU_ASSERT_EQUAL(bt, BSON_OBJECT); + CU_ASSERT_FALSE(strcmp(BSON_ITERATOR_KEY(&sit), "name")); + + BSON_ITERATOR_SUBITERATOR(&sit, &sit); + bt = bson_iterator_next(&sit); + CU_ASSERT_EQUAL(bt, BSON_OBJECT); + CU_ASSERT_FALSE(strcmp(BSON_ITERATOR_KEY(&sit) , "par") && strcmp(BSON_ITERATOR_KEY(&sit) , "mot")); + bt = bson_iterator_next(&sit); + CU_ASSERT_EQUAL(bt, BSON_OBJECT); + CU_ASSERT_FALSE(strcmp(BSON_ITERATOR_KEY(&sit) , "par") && strcmp(BSON_ITERATOR_KEY(&sit) , "mot")); + + BSON_ITERATOR_FROM_BUFFER(&it, bsdata); + bt = bson_find_fieldpath_value("info.name.par.age", &it); + CU_ASSERT_TRUE(BSON_IS_NUM_TYPE(bt)); + CU_ASSERT_EQUAL(bson_iterator_int(&it), 40); + BSON_ITERATOR_FROM_BUFFER(&it, bsdata); + bt = bson_find_fieldpath_value("info.name.mot.age", &it); + CU_ASSERT_TRUE(BSON_IS_NUM_TYPE(bt)); + CU_ASSERT_EQUAL(bson_iterator_int(&it), 35); + ejdbquerydel(q1); + tclistdel(q1res); +} + +void testTicket156(void) { + EJCOLL *coll = ejdbcreatecoll(jb, "ticket156", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); + + bson b; + bson_oid_t oid; + + bson_init(&b); + bson_append_int(&b, "id", 18); + bson_append_symbol(&b, "sym", "eighteen"); + bson_finish(&b); + CU_ASSERT_TRUE(ejdbsavebson(coll, &b, &oid)); + bson_destroy(&b); + + /* Verify that id=18 contain record with symbol */ + bson bsq; + bson_init_as_query(&bsq); + bson_append_int(&bsq, "id", 18); + bson_finish(&bsq); + CU_ASSERT_FALSE_FATAL(bsq.err); + + EJQ *q1 = ejdbcreatequery(jb, &bsq, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + uint32_t count; + TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, NULL); + CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1); + + void *bsdata = TCLISTVALPTR(q1res, 0); + CU_ASSERT_PTR_NOT_NULL_FATAL(bsdata); + + bson_iterator it; + bson_type bt; + BSON_ITERATOR_FROM_BUFFER(&it, bsdata); + bt = bson_find_fieldpath_value("sym", &it); + CU_ASSERT_EQUAL_FATAL(bt, BSON_SYMBOL); + CU_ASSERT_FALSE(strcmp(bson_iterator_string(&it), "eighteen")); + + bson_destroy(&bsq); + ejdbquerydel(q1); + tclistdel(q1res); } int main() { @@ -6146,10 +6239,11 @@ int main() { (NULL == CU_add_test(pSuite, "testTicket101", testTicket101)) || (NULL == CU_add_test(pSuite, "testTicket110", testTicket110)) || (NULL == CU_add_test(pSuite, "testDistinct", testDistinct)) || - (NULL == CU_add_test(pSuite, "testSlice", testSlice)) || - (NULL == CU_add_test(pSuite, "testTicket117", testTicket117)) || - (NULL == CU_add_test(pSuite, "testTicket142", testTicket142)) || - (NULL == CU_add_test(pSuite, "testMetaInfo", testMetaInfo)) + (NULL == CU_add_test(pSuite, "testSlice", testSlice)) || + (NULL == CU_add_test(pSuite, "testTicket117", testTicket117)) || + (NULL == CU_add_test(pSuite, "testMetaInfo", testMetaInfo)) || + (NULL == CU_add_test(pSuite, "testTicket148", testTicket148)) || + (NULL == CU_add_test(pSuite, "testTicket156", testTicket156)) ) { CU_cleanup_registry(); return CU_get_error(); diff --git a/src/tchdb/tchdb.c b/src/tchdb/tchdb.c index 8ea46fb..45dee6a 100644 --- a/src/tchdb/tchdb.c +++ b/src/tchdb/tchdb.c @@ -45,11 +45,11 @@ #define HDBDEFFPOW 10 // default free block pool power #define HDBMAXFPOW 20 // maximum free block pool power -#ifdef _WIN32 -#define HDBDEFXMSIZ _maxof(off_t) // default size of the extra mapped memory -#else +//#ifdef _WIN32 +//#define HDBDEFXMSIZ _maxof(off_t) // default size of the extra mapped memory +//#else #define HDBDEFXMSIZ (64LL<<20) // default size of the extra mapped memory -#endif +//#endif #define HDBXFSIZINC 1048576 // 1MB increment of extra file size #define HDBMINRUNIT 48 // minimum record reading unit #define HDBMAXHSIZ 32 // maximum record header size @@ -359,10 +359,6 @@ bool tchdbsetcache(TCHDB *hdb, int32_t rcnum) { /* Set the size of the extra mapped memory of a hash database object. */ bool tchdbsetxmsiz(TCHDB *hdb, int64_t xmsiz) { -#if defined (_WIN32) - //fprintf(stderr, "\ntchdbsetxmsiz does not takes effect on windows platform\n"); - return true; -#else assert(hdb); if (!INVALIDHANDLE(hdb->fd)) { tchdbsetecode(hdb, TCEINVALID, __FILE__, __LINE__, __func__); @@ -370,7 +366,6 @@ bool tchdbsetxmsiz(TCHDB *hdb, int64_t xmsiz) { } hdb->xmsiz = (xmsiz > 0) ? tcpagealign(xmsiz) : 0; return true; -#endif } /* Set the unit step number of auto defragmentation of a hash database object. */ @@ -5645,7 +5640,7 @@ static bool tchdbftruncate2(TCHDB *hdb, off_t length, int opts) { } #else bool err = false; - LARGE_INTEGER size; + LARGE_INTEGER size, msize; //MSDN: Applications should test for files with a length of 0 (zero) and reject those files. size.QuadPart = (hdb->omode & HDBOWRITER) ? tcpagealign((length == 0) ? 1 : length) : length; if (hdb->map && @@ -5656,11 +5651,13 @@ static bool tchdbftruncate2(TCHDB *hdb, off_t length, int opts) { if (!(opts & HDBOPTNOSMLOCK) && !HDBLOCKSMEMPTR2(hdb, true)) { return false; } + if ((hdb->omode & HDBOWRITER) && size.QuadPart > xfsiz && !(opts & HDBTRALLOWSHRINK)) { off_t o1 = tcpagealign((_maxof(off_t) - (off_t) size.QuadPart < HDBXFSIZINC) ? size.QuadPart : size.QuadPart + HDBXFSIZINC); off_t o2 = tcpagealign((((uint64_t) size.QuadPart) * 3) >> 1); size.QuadPart = MAX(o1, o2); } + msize = size; if (hdb->map) { FlushViewOfFile((LPCVOID) hdb->map, 0); if (!UnmapViewOfFile((LPCVOID) hdb->map) || !CloseHandle(hdb->w32hmap)) { @@ -5678,9 +5675,12 @@ static bool tchdbftruncate2(TCHDB *hdb, off_t length, int opts) { goto finish; } } + if (msize.QuadPart > hdb->xmsiz) { + msize.QuadPart = hdb->xmsiz; + } hdb->w32hmap = CreateFileMapping(hdb->fd, NULL, ((hdb->omode & HDBOWRITER) ? PAGE_READWRITE : PAGE_READONLY), - size.HighPart, size.LowPart, NULL); + msize.HighPart, msize.LowPart, NULL); if (INVALIDHANDLE(hdb->w32hmap)) { tchdbsetecode(hdb, TCEMMAP, __FILE__, __LINE__, __func__); err = true; diff --git a/src/tcutil/win32/platform.h b/src/tcutil/win32/platform.h index a111070..a037e21 100644 --- a/src/tcutil/win32/platform.h +++ b/src/tcutil/win32/platform.h @@ -46,6 +46,7 @@ ssize_t win_pwrite(HANDLE fd, const void *buf, size_t count, off_t offset); ssize_t win_pread(HANDLE fd, void *buf, size_t size, off_t off); #define mkdir(a, b) _mkdir(a) +#undef fstat #define fstat win_fstat #define lstat stat #define sysconf_SC_CLK_TCK 64 |