From b8ef65a87937dfac76c9ba76914f42c5e00b6326 Mon Sep 17 00:00:00 2001 From: Anton Adamansky Date: Wed, 29 Apr 2015 12:50:31 +0600 Subject: [PATCH] Fix: $rename can operate on nested json objects #107 --- Changelog | 2 ++ src/bson/bson.c | 84 +++++++++++++++++++++++++++++++++++++++++----- src/bson/bson.h | 41 ++++++++++++++++------ src/ejdb/ejdb.c | 66 ++++++++++++++---------------------- src/ejdb/ejdb.h | 78 +++++++++++++++++++++--------------------- src/ejdb/tests/ejdbtest2.c | 55 ++++++++++++++++++++++++++++++ 6 files changed, 228 insertions(+), 98 deletions(-) diff --git a/Changelog b/Changelog index f5a8369..2ab202b 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,8 @@ ejdb (1.2.8) UNRELEASED; urgency=low * Fix: Problem with the bson2json conversion dealing with doubles #135 + * $push and $pushAll operations are implemented. #130 + * Fix: $rename can operate on nested json objects #107 -- Anton Adamansky Mon, 27 Apr 2015 21:30:11 +0600 diff --git a/src/bson/bson.c b/src/bson/bson.c index 28d7cf5..7d22a7e 100644 --- a/src/bson/bson.c +++ b/src/bson/bson.c @@ -1500,8 +1500,12 @@ typedef struct { int matched; //number of matched merge fields } _BSONMERGE3CTX; -static bson_visitor_cmd_t _bson_merge3_visitor(const char *ipath, int ipathlen, const char *key, int keylen, - const bson_iterator *it, bool after, void *op) { +static bson_visitor_cmd_t _bson_merge_fieldpaths_visitor( + const char *ipath, int ipathlen, + const char *key, int keylen, + const bson_iterator *it, + bool after, void *op) { + _BSONMERGE3CTX *ctx = op; assert(ctx && ctx->bsout && ctx->mfields && ipath && key && it && op); const void *buf; @@ -1571,7 +1575,7 @@ static bson_visitor_cmd_t _bson_merge3_visitor(const char *ipath, int ipathlen, //merge with fpath support -int bson_merge3(const void *bsdata1, const void *bsdata2, bson *out) { +int bson_merge_fieldpaths(const void *bsdata1, const void *bsdata2, bson *out) { assert(bsdata1 && bsdata2 && out); bson_iterator it1, it2; bson_type bt; @@ -1592,7 +1596,7 @@ int bson_merge3(const void *bsdata1, const void *bsdata2, bson *out) { off_t it2off = (it2.cur - it2start); tcmapput(mfields, key, strlen(key), &it2off, sizeof (it2off)); } - bson_visit_fields(&it1, 0, _bson_merge3_visitor, &ctx); + bson_visit_fields(&it1, 0, _bson_merge_fieldpaths_visitor, &ctx); assert(ctx.nstack == 0); if (TCMAPRNUM(mfields) == 0) { //all merge fields applied tcmapdel(mfields); @@ -1651,7 +1655,9 @@ int bson_merge(const bson *b1, const bson *b2, bson_bool_t overwrite, bson *out) int bson_merge_recursive2(const void *b1data, const void *b2data, bson_bool_t overwrite, bson *out) { bson_iterator it1, it2; bson_type bt1, bt2; - + if (out->finished) { + return BSON_ERROR; + } BSON_ITERATOR_FROM_BUFFER(&it1, b1data); BSON_ITERATOR_FROM_BUFFER(&it2, b2data); //Append all fields in B1 merging with fields in B2 (for nested objects & arrays) @@ -1719,8 +1725,12 @@ typedef struct { } _BSONSTRIPVISITORCTX; /* Discard excluded fields from BSON */ -static bson_visitor_cmd_t _bsonstripvisitor_exclude(const char *ipath, int ipathlen, const char *key, int keylen, - const bson_iterator *it, bool after, void *op) { +static bson_visitor_cmd_t _bsonstripvisitor_exclude( + const char *ipath, int ipathlen, + const char *key, int keylen, + const bson_iterator *it, + bool after, void *op) { + _BSONSTRIPVISITORCTX *ictx = op; assert(ictx); BSONSTRIPCTX *sctx = ictx->sctx; @@ -1769,6 +1779,21 @@ static bson_visitor_cmd_t _bsonstripvisitor_exclude(const char *ipath, int ipath return (BSON_VCMD_SKIP_NESTED | BSON_VCMD_SKIP_AFTER); } } else { + if (sctx->collector) { + const char *k = NULL; + char cpath[BSON_MAX_FPATH_LEN + 1]; + assert(ipathlen <= BSON_MAX_FPATH_LEN && !sctx->collector->finished); + if (sctx->fkfields) { + k = tcmapget(sctx->fkfields, ipath, ipathlen, &bufsz); + } + if (!k) { + memcpy(cpath, ipath, ipathlen); + cpath[ipathlen] = '\0'; + k = cpath; + } + bson_iterator cit = *it; + bson_append_field_from_iterator2(k, &cit, sctx->collector); + } if (!after && ictx->astack > 0 && bson_isnumstr(key, keylen)) { bson_append_undefined(sctx->bsout, key); } @@ -1778,8 +1803,11 @@ static bson_visitor_cmd_t _bsonstripvisitor_exclude(const char *ipath, int ipath } /* Accept only included fields into BSON */ -static bson_visitor_cmd_t _bsonstripvisitor_include(const char *ipath, int ipathlen, const char *key, int keylen, +static bson_visitor_cmd_t _bsonstripvisitor_include( + const char *ipath, int ipathlen, + const char *key, int keylen, const bson_iterator *it, bool after, void *op) { + _BSONSTRIPVISITORCTX *ictx = op; assert(ictx); BSONSTRIPCTX *sctx = ictx->sctx; @@ -1892,6 +1920,46 @@ int bson_strip2(BSONSTRIPCTX *sctx) { return bson_finish(sctx->bsout); } +int bson_rename(TCMAP *fields, const void *bsbuf, bson *bsout, int *rencnt) { + *rencnt = 0; + if (TCMAPRNUM(fields) == 0) { + return BSON_OK; //nothing to rename + } + + int rv; + bson res, collector; + bson_init(&res); + bson_init(&collector); + + BSONSTRIPCTX sctx = { + .ifields = fields, + .imode = false, + .bsbuf = bsbuf, + .bsout = &res, + .collector = &collector, + .fkfields = fields + }; + if ((rv = bson_strip2(&sctx)) != BSON_OK) { + goto finish; + } + if ((rv = bson_finish(&res)) != BSON_OK) { + goto finish; + } + if ((rv = bson_finish(&collector)) != BSON_OK) { + goto finish; + } + if ((rv = bson_merge_fieldpaths(bson_data(&res), + bson_data(&collector), + bsout)) != BSON_OK) { + goto finish; + } + *rencnt = sctx.matched; +finish: + bson_destroy(&res); + bson_destroy(&collector); + return rv; +} + int bson_inplace_set_bool(bson_iterator *pos, bson_bool_t val) { assert(pos); bson_type bt = BSON_ITERATOR_TYPE(pos); diff --git a/src/bson/bson.h b/src/bson/bson.h index 26947e2..37fe385 100644 --- a/src/bson/bson.h +++ b/src/bson/bson.h @@ -234,8 +234,15 @@ typedef enum { BSON_VCMD_SKIP_NESTED = 1 << 1, BSON_VCMD_SKIP_AFTER = 1 << 2 } bson_visitor_cmd_t; -typedef bson_visitor_cmd_t(*BSONVISITOR)(const char *ipath, int ipathlen, const char *key, int keylen, const bson_iterator *it, bool after, void *op); -EJDB_EXPORT void bson_visit_fields(bson_iterator *it, bson_traverse_flags_t flags, BSONVISITOR visitor, void *op); + +typedef bson_visitor_cmd_t(*BSONVISITOR)(const char *ipath, int ipathlen, + const char *key, int keylen, + const bson_iterator *it, + bool after, void *op); + +EJDB_EXPORT void bson_visit_fields(bson_iterator *it, + bson_traverse_flags_t flags, + BSONVISITOR visitor, void *op); EJDB_EXPORT bson_iterator* bson_iterator_create(void); @@ -1149,19 +1156,20 @@ EJDB_EXPORT int bson_merge_recursive2(const void *b1data, const void *b2data, bs * * @return BSON_OK or BSON_ERROR. */ -EJDB_EXPORT int bson_merge3(const void *bsdata1, const void *bsdata2, bson *out); +EJDB_EXPORT int bson_merge_fieldpaths(const void *bsdata1, const void *bsdata2, bson *out); EJDB_EXPORT int bson_inplace_set_bool(bson_iterator *pos, bson_bool_t val); EJDB_EXPORT int bson_inplace_set_long(bson_iterator *pos, int64_t val); EJDB_EXPORT int bson_inplace_set_double(bson_iterator *pos, double val); typedef struct { - TCMAP *ifields; //Required Map of fieldpaths. Map values are a simple boolean bufs. - bool imode; //Required If true fpaths will be included. Otherwise fpaths will be excluded from bson. - const void *bsbuf; //Required BSON buffer to process. - bson *bsout; //Required Allocated output not finished bson* object. - TCMAP *fkfields; //Optional: Map (fpath => bson key) used to force specific bson keys for selected fpaths. - int matched; //Output: number of matched fieldpaths + TCMAP *ifields; //Required Map of fieldpaths. Map values are a simple boolean bufs. + bool imode; //Required If true fpaths will be included. Otherwise fpaths will be excluded from bson. + const void *bsbuf; //Required BSON buffer to process. + bson *bsout; //Required Allocated output not finished bson* object. + TCMAP *fkfields; //Optional: Map (fpath => bson key) used to force specific bson keys for selected fpaths. + int matched; //Output: number of matched fieldpaths + bson *collector; //Optional: Collector for excluded data (fieldpath -> excluded value) } BSONSTRIPCTX; /** @@ -1171,13 +1179,26 @@ typedef struct { * @param ifields Map of fieldpaths. Map values are a simple boolean bufs. * @param imode If true fpaths will be included. Otherwise fpaths will be excluded from bson. * @param bsbuf BSON buffer to process. - * @param bsout Allocated output not finished bson* object + * @param bsout Allocated and not finished output bson* object * @param matched[out] Number of matched include/exclude fieldpaths. * @return BSON error code */ EJDB_EXPORT int bson_strip(TCMAP *ifields, bool imode, const void *bsbuf, bson *bsout, int *matched); EJDB_EXPORT int bson_strip2(BSONSTRIPCTX *sctx); +/** + * @brief Rename a fields specified by `fields` rename mapping. + * + * This operation unsets both all and new fieldpaths and then sets + * new fieldpath values. + * + * @param fields Rename mapping old `fieldpath` to new `fieldpath`. + * @param bsbuf BSON buffer to process. + * @param bsout Allocated and not finished output bson* object + * @param rencnt A number of fieldpaths actually renamed. + */ +EJDB_EXPORT int bson_rename(TCMAP *fields, const void *bsbuf, bson *bsout, int *rencnt); + /** * Compares field path primitive values of two BSONs diff --git a/src/ejdb/ejdb.c b/src/ejdb/ejdb.c index d4639a1..e168b5e 100644 --- a/src/ejdb/ejdb.c +++ b/src/ejdb/ejdb.c @@ -2979,7 +2979,7 @@ static bool _qryupdate(_QRYCTX *ctx, void *bsbuf, int bsbufsz) { } } - if (renameqf) { //todo rename nested fields! + if (renameqf) { char *inbuf = (bsout.finished) ? bsout.data : bsbuf; if (bsout.finished) { //reinit `bsout`, `inbuf` already points to `bsout.data` and will be freed later @@ -2988,47 +2988,31 @@ static bool _qryupdate(_QRYCTX *ctx, void *bsbuf, int bsbufsz) { assert(bsout.data == NULL); bson_init_size(&bsout, bsbufsz); } - TCMAP *efields = NULL; bson *updobj = _qfgetupdateobj(renameqf); - BSON_ITERATOR_INIT(&it, updobj); - while (rv && (bt = bson_iterator_next(&it)) != BSON_EOO) { - if (bt != BSON_STRING) { - continue; - } - const char *ofpath = BSON_ITERATOR_KEY(&it); - const char *nfpath = bson_iterator_string(&it); - bt2 = bson_find_from_buffer(&it2, inbuf, ofpath); - if (bt2 == BSON_EOO) { - continue; - } - if (bson_append_field_from_iterator2(nfpath, &it2, &bsout) != BSON_OK) { - rv = false; - _ejdbsetecode(coll->jb, JBEQUPDFAILED, __FILE__, __LINE__, __func__); - break; - } - update++; - if (!efields) { - efields = tcmapnew2(TCMAPTINYBNUM); + TCMAP *rfields = tcmapnew2(TCMAPTINYBNUM); + BSON_ITERATOR_INIT(&it, updobj); + while ((bt = bson_iterator_next(&it)) != BSON_EOO) { + if (bt != BSON_STRING) { + continue; } - tcmapputkeep(efields, ofpath, strlen(ofpath), "", 0); - tcmapputkeep(efields, nfpath, strlen(nfpath), "", 0); - } - - BSON_ITERATOR_FROM_BUFFER(&it, inbuf); - while (rv && (bt = bson_iterator_next(&it)) != BSON_EOO) { - const char *fpath = BSON_ITERATOR_KEY(&it); - if (efields && tcmapget2(efields, fpath)) { - continue; - } - if (bson_append_field_from_iterator(&it, &bsout) != BSON_OK) { - rv = false; - _ejdbsetecode(coll->jb, JBEQUPDFAILED, __FILE__, __LINE__, __func__); - break; - } - } - if (efields) { - tcmapdel(efields); + const char *nfpath = bson_iterator_string(&it); + int nlen = bson_iterator_string_len(&it); + if (nlen == 0) { + continue; + } + tcmapputkeep(rfields, + BSON_ITERATOR_KEY(&it), strlen(BSON_ITERATOR_KEY(&it)), + nfpath, nlen); + } + int rencnt; + if (bson_rename(rfields, inbuf, &bsout, &rencnt) != BSON_OK) { + rv = false; + _ejdbsetecode(coll->jb, JBEQUPDFAILED, __FILE__, __LINE__, __func__); + } + if (rencnt > 0) { + update++; } + tcmapdel(rfields); bson_finish(&bsout); if (inbuf != bsbuf) { TCFREE(inbuf); @@ -3049,7 +3033,7 @@ static bool _qryupdate(_QRYCTX *ctx, void *bsbuf, int bsbufsz) { assert(bsout.data == NULL); bson_init_size(&bsout, bsbufsz); } - int matched = 0; + int matched; bson *updobj = _qfgetupdateobj(unsetqf); TCMAP *ifields = tcmapnew2(TCMAPTINYBNUM); BSON_ITERATOR_INIT(&it, updobj); @@ -3087,7 +3071,7 @@ static bool _qryupdate(_QRYCTX *ctx, void *bsbuf, int bsbufsz) { assert(bsout.data == NULL); bson_init_size(&bsout, bsbufsz); } - int err = bson_merge3(bsbuf, bson_data(updobj), &bsout); + int err = bson_merge_fieldpaths(bsbuf, bson_data(updobj), &bsout); if (err) { rv = false; _ejdbsetecode(coll->jb, JBEQUPDFAILED, __FILE__, __LINE__, __func__); diff --git a/src/ejdb/ejdb.h b/src/ejdb/ejdb.h index cc87b7a..f61150d 100644 --- a/src/ejdb/ejdb.h +++ b/src/ejdb/ejdb.h @@ -36,11 +36,11 @@ typedef struct EJCOLL EJCOLL; struct EJQ; /**< EJDB query. */ typedef struct EJQ EJQ; -typedef struct { /**< EJDB collection tuning options. */ - bool large; /**< Large collection. It can be larger than 2GB. Default false */ - bool compressed; /**< Collection records will be compressed with DEFLATE compression. Default: false */ - int64_t records; /**< Expected records number in the collection. Default: 128K */ - int cachedrecords; /**< Maximum number of records cached in memory. Default: 0 */ +typedef struct { /**< EJDB collection tuning options. */ + bool large; /**< Large collection. It can be larger than 2GB. Default false */ + bool compressed; /**< Collection records will be compressed with DEFLATE compression. Default: false */ + int64_t records; /**< Expected records number in the collection. Default: 128K */ + int cachedrecords; /**< Maximum number of records cached in memory. Default: 0 */ } EJCOLLOPTS; @@ -49,51 +49,51 @@ typedef TCLIST* EJQRESULT; /**< EJDB query result */ #define JBMAXCOLNAMELEN 128 enum { /** Error codes */ - JBEINVALIDCOLNAME = 9000, /**< Invalid collection name. */ - JBEINVALIDBSON = 9001, /**< Invalid bson object. */ - JBEINVALIDBSONPK = 9002, /**< Invalid bson object id. */ + JBEINVALIDCOLNAME = 9000, /**< Invalid collection name. */ + JBEINVALIDBSON = 9001, /**< Invalid bson object. */ + JBEINVALIDBSONPK = 9002, /**< Invalid bson object id. */ JBEQINVALIDQCONTROL = 9003, /**< Invalid query control field starting with '$'. */ - JBEQINOPNOTARRAY = 9004, /**< $strand, $stror, $in, $nin, $bt keys requires not empty array value. */ - JBEMETANVALID = 9005, /**< Inconsistent database metadata. */ - JBEFPATHINVALID = 9006, /**< Invalid field path value. */ - JBEQINVALIDQRX = 9007, /**< Invalid query regexp value. */ - JBEQRSSORTING = 9008, /**< Result set sorting error. */ - JBEQERROR = 9009, /**< Query generic error. */ - JBEQUPDFAILED = 9010, /**< Updating failed. */ - JBEQONEEMATCH = 9011, /**< Only one $elemMatch allowed in the fieldpath. */ - JBEQINCEXCL = 9012, /**< $fields hint cannot mix include and exclude fields */ - JBEQACTKEY = 9013, /**< action key in $do block can only be one of: $join, $slice */ - JBEMAXNUMCOLS = 9014, /**< Exceeded the maximum number of collections per database */ - JBEEI = 9015, /**< EJDB export/import error */ - JBEEJSONPARSE = 9016, /**< JSON parsing failed */ - JBETOOBIGBSON = 9017, /**< BSON size is too big */ - JBEINVALIDCMD = 9018 /**< Invalid ejdb command specified */ + JBEQINOPNOTARRAY = 9004, /**< $strand, $stror, $in, $nin, $bt keys requires not empty array value. */ + JBEMETANVALID = 9005, /**< Inconsistent database metadata. */ + JBEFPATHINVALID = 9006, /**< Invalid field path value. */ + JBEQINVALIDQRX = 9007, /**< Invalid query regexp value. */ + JBEQRSSORTING = 9008, /**< Result set sorting error. */ + JBEQERROR = 9009, /**< Query generic error. */ + JBEQUPDFAILED = 9010, /**< Updating failed. */ + JBEQONEEMATCH = 9011, /**< Only one $elemMatch allowed in the fieldpath. */ + JBEQINCEXCL = 9012, /**< $fields hint cannot mix include and exclude fields */ + JBEQACTKEY = 9013, /**< action key in $do block can only be one of: $join, $slice */ + JBEMAXNUMCOLS = 9014, /**< Exceeded the maximum number of collections per database */ + JBEEI = 9015, /**< EJDB export/import error */ + JBEEJSONPARSE = 9016, /**< JSON parsing failed */ + JBETOOBIGBSON = 9017, /**< BSON size is too big */ + JBEINVALIDCMD = 9018 /**< Invalid ejdb command specified */ }; enum { /** Database open modes */ - JBOREADER = 1u << 0, /**< Open as a reader. */ - JBOWRITER = 1u << 1, /**< Open as a writer. */ - JBOCREAT = 1u << 2, /**< Create if db file not exists. */ - JBOTRUNC = 1u << 3, /**< Truncate db on open. */ - JBONOLCK = 1u << 4, /**< Open without locking. */ - JBOLCKNB = 1u << 5, /**< Lock without blocking. */ - JBOTSYNC = 1u << 6 /**< Synchronize every transaction. */ + JBOREADER = 1u << 0, /**< Open as a reader. */ + JBOWRITER = 1u << 1, /**< Open as a writer. */ + JBOCREAT = 1u << 2, /**< Create if db file not exists. */ + JBOTRUNC = 1u << 3, /**< Truncate db on open. */ + JBONOLCK = 1u << 4, /**< Open without locking. */ + JBOLCKNB = 1u << 5, /**< Lock without blocking. */ + JBOTSYNC = 1u << 6 /**< Synchronize every transaction. */ }; enum { /** Index modes, index types. */ - JBIDXDROP = 1u << 0, /**< Drop index. */ + JBIDXDROP = 1u << 0, /**< Drop index. */ JBIDXDROPALL = 1u << 1, /**< Drop index for all types. */ - JBIDXOP = 1u << 2, /**< Optimize indexes. */ - JBIDXREBLD = 1u << 3, /**< Rebuild index. */ - JBIDXNUM = 1u << 4, /**< Number index. */ - JBIDXSTR = 1u << 5, /**< String index.*/ - JBIDXARR = 1u << 6, /**< Array token index. */ - JBIDXISTR = 1u << 7 /**< Case insensitive string index */ + JBIDXOP = 1u << 2, /**< Optimize indexes. */ + JBIDXREBLD = 1u << 3, /**< Rebuild index. */ + JBIDXNUM = 1u << 4, /**< Number index. */ + JBIDXSTR = 1u << 5, /**< String index.*/ + JBIDXARR = 1u << 6, /**< Array token index. */ + JBIDXISTR = 1u << 7 /**< Case insensitive string index */ }; enum { /*< Query search mode flags in ejdbqryexecute() */ - JBQRYCOUNT = 1u, /*< Query only count(*) */ - JBQRYFINDONE = 1u << 1 /*< Fetch first record only */ + JBQRYCOUNT = 1u, /*< Query only count(*) */ + JBQRYFINDONE = 1u << 1 /*< Fetch first record only */ }; /** diff --git a/src/ejdb/tests/ejdbtest2.c b/src/ejdb/tests/ejdbtest2.c index f8f3d98..5eb94f6 100644 --- a/src/ejdb/tests/ejdbtest2.c +++ b/src/ejdb/tests/ejdbtest2.c @@ -4091,6 +4091,60 @@ void testPushAll(void) { ejdbquerydel(q1); } +void testRename2(void) { + EJCOLL *coll = ejdbcreatecoll(jb, "ticket123", NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(coll); + bson bsq1; + bson_init_as_query(&bsq1); + bson_append_start_object(&bsq1, "$rename"); + bson_append_string(&bsq1, "abc.g", "abc.f"); + bson_append_finish_object(&bsq1); + bson_finish(&bsq1); + CU_ASSERT_FALSE_FATAL(bsq1.err); + + EJQ *q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + uint32_t count = 0; + TCXSTR *log = tcxstrnew(); + ejdbqryexecute(coll, q1, &count, JBQRYCOUNT, log); + + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES")); + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS COUNT: 1")); + CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "RS SIZE: 0")); + + //fprintf(stderr, "%s", TCXSTRPTR(log)); + bson_destroy(&bsq1); + tcxstrdel(log); + ejdbquerydel(q1); + + //check updated data + bson_init_as_query(&bsq1); + bson_finish(&bsq1); + CU_ASSERT_FALSE_FATAL(bsq1.err); + + q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(q1); + log = tcxstrnew(); + TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log); + + CU_ASSERT_EQUAL(TCLISTNUM(q1res), 1); + //fprintf(stderr, "\n\n%s", TCXSTRPTR(log)); + + for (int i = 0; i < TCLISTNUM(q1res); ++i) { + CU_ASSERT_FALSE(bson_compare_string("g", TCLISTVALPTR(q1res, i), "abc.de.0")); + CU_ASSERT_FALSE(bson_compare_string("f", TCLISTVALPTR(q1res, i), "abc.f.0")); + CU_ASSERT_FALSE(bson_compare_string("f", TCLISTVALPTR(q1res, i), "abc.f.1")); + CU_ASSERT_FALSE(bson_compare_string("h", TCLISTVALPTR(q1res, i), "abc.f.2")); + CU_ASSERT_FALSE(bson_compare_string("h", TCLISTVALPTR(q1res, i), "abc.f.3")); + CU_ASSERT_FALSE(bson_compare_long(11, TCLISTVALPTR(q1res, i), "abc.f.4")); + } + + bson_destroy(&bsq1); + tclistdel(q1res); + tcxstrdel(log); + ejdbquerydel(q1); +} + void testPull(void) { EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL); @@ -6008,6 +6062,7 @@ int main() { (NULL == CU_add_test(pSuite, "testTicket123", testTicket123)) || (NULL == CU_add_test(pSuite, "testPush", testPush)) || (NULL == CU_add_test(pSuite, "testPushAll", testPushAll)) || + (NULL == CU_add_test(pSuite, "testRename2", testRename2)) || (NULL == CU_add_test(pSuite, "testPull", testPull)) || (NULL == CU_add_test(pSuite, "testFindInComplexArray", testFindInComplexArray)) || (NULL == CU_add_test(pSuite, "testElemMatch", testElemMatch)) || -- 2.7.4