summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Adamansky <adamansky@gmail.com>2015-04-29 12:50:31 +0600
committerAnton Adamansky <adamansky@gmail.com>2015-04-29 12:50:31 +0600
commitb8ef65a87937dfac76c9ba76914f42c5e00b6326 (patch)
treebabf37b2742c99199916bf37b7287437b7b89496
parent0478ea61300762aaf66f3b158dfb6ab63e87cb69 (diff)
downloadejdb-b8ef65a87937dfac76c9ba76914f42c5e00b6326.tar.gz
ejdb-b8ef65a87937dfac76c9ba76914f42c5e00b6326.tar.bz2
ejdb-b8ef65a87937dfac76c9ba76914f42c5e00b6326.zip
Fix: $rename can operate on nested json objects #107
-rw-r--r--Changelog2
-rw-r--r--src/bson/bson.c84
-rw-r--r--src/bson/bson.h41
-rw-r--r--src/ejdb/ejdb.c66
-rw-r--r--src/ejdb/ejdb.h78
-rw-r--r--src/ejdb/tests/ejdbtest2.c55
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 <adamansky@gmail.com> 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)) ||