summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--Changelog18
-rw-r--r--README.md2
-rw-r--r--cmake/Modules/Win32LIBTools.cmake2
-rw-r--r--nejdb/README.md2
-rwxr-xr-xrelease.sh21
-rw-r--r--src/CMakeLists.txt67
-rw-r--r--src/bson/bson.c152
-rw-r--r--src/bson/bson.h67
-rw-r--r--src/bson/tests/CMakeLists.txt14
-rw-r--r--src/bson/tests/bsontest.c183
-rw-r--r--src/ejdb/tests/ejdbtest2.c136
-rw-r--r--src/tchdb/tchdb.c22
-rw-r--r--src/tcutil/win32/platform.h1
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)
diff --git a/Changelog b/Changelog
index 23ed824..b69eaf2 100644
--- a/Changelog
+++ b/Changelog
@@ -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
diff --git a/README.md b/README.md
index 2fc2f23..40ffc44 100644
--- a/README.md
+++ b/README.md
@@ -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