#9
authoradam <anton@adamansky.com>
Mon, 19 Nov 2012 09:37:33 +0000 (16:37 +0700)
committeradam <anton@adamansky.com>
Mon, 19 Nov 2012 09:37:33 +0000 (16:37 +0700)
tcejdb/bson.c
tcejdb/ejdb.c
tcejdb/ejdb_private.h
tcejdb/tcutil.c
tcejdb/tcutil.h
tcejdb/testejdb/Makefile
tcejdb/testejdb/t2.c

index 2249be6..a1b1317 100644 (file)
@@ -1364,7 +1364,7 @@ EJDB_EXPORT int bson_compare_fpaths(const void *bsdata1, const void *bsdata2, co
     } else if (t1 == BSON_OID && t2 == BSON_OID) {
         return memcmp(bson_iterator_oid(&it1), bson_iterator_oid(&it2), sizeof (bson_oid_t));
     }
-    return 0;
+    return (t1 - t2);
 }
 
 EJDB_EXPORT int bson_compare(const void *bsdata1, const void *bsdata2, const char* fpath, int fplen) {
index e96d96f..bca4bfe 100644 (file)
@@ -3,7 +3,6 @@
 
 
 #include <regex.h>
-#include <tcejdb/bson.h>
 #include "ejdb_private.h"
 #include "ejdbutl.h"
 
@@ -135,6 +134,7 @@ EJDB_EXPORT EJDB* ejdbnew(void) {
     TCMALLOC(jb, sizeof (*jb));
     _ejdbclear(jb);
     jb->metadb = tctdbnew();
+    tctdbsetcache(jb->metadb, 1024, 0, 0);
 #ifdef _DEBUG
     tchdbsetdbgfd(jb->metadb->hdb, fileno(stderr));
 #endif
@@ -1546,7 +1546,7 @@ static bool _qryupdate(EJCOLL *jcoll, const EJQ *ejq, void *bsbuf, int bsbufsz)
     bson_iterator it;
     TCMAP *qobjmap = ejq->qobjmap;
     TCTDB *tdb = jcoll->tdb;
-    TCMAP *rowm = tcmapnew2(64);
+    TCMAP *rowm = tcmapnew2(TCMAPTINYBNUM);
 
     bson src;
     bson_create_from_buffer2(&src, bsbuf, bsbufsz);
@@ -1572,6 +1572,11 @@ static bool _qryupdate(EJCOLL *jcoll, const EJQ *ejq, void *bsbuf, int bsbufsz)
         }
     }
     bson_finish(&bsout);
+    if (bsout.err) {
+        rv = false;
+        _ejdbsetecode(jcoll->jb, JBEINVALIDBSON, __FILE__, __LINE__, __func__);
+        goto finish;
+    }
 
     //fetch oid
     bt = bson_find(&it, &src, JDBIDKEYNAME);
@@ -2363,7 +2368,7 @@ static void _qrypreprocess(EJCOLL *jcoll, EJQ *ejq, int qflags, EJQF **mqf, TCMA
         if (!(qflags & JBQRYCOUNT)) {
             bt = bson_find(&it, ejq->hints, "$fields"); //Collect required fields
             if (bt == BSON_OBJECT) {
-                TCMAP *fmap = tcmapnew2(64);
+                TCMAP *fmap = tcmapnew2(TCMAPTINYBNUM);
                 static const bool yes = true;
                 bson_iterator_subiterator(&it, &sit);
                 while ((bt = bson_iterator_next(&sit)) != BSON_EOO) {
@@ -2389,9 +2394,11 @@ static void _qrypreprocess(EJCOLL *jcoll, EJQ *ejq, int qflags, EJQF **mqf, TCMA
         EJQF *qf = (EJQF*) tcmapget(qmap, mkey, mkeysz, &mvalsz); //discard const
         assert(mvalsz == sizeof (EJQF));
         assert(qf->fpath);
-
-        if ((qf->tcop == TDBQCSTREQ || qf->tcop == TDBQCSTROREQ) &&
-                !strcmp(JDBIDKEYNAME, qf->fpath)) { //OID PK matching
+        if (qf->flags & (EJCONDSET | EJCONDINC)) { //skip updating qfields
+            continue;
+        }
+        //OID PK matching
+        if ((qf->tcop == TDBQCSTREQ || qf->tcop == TDBQCSTROREQ) && !strcmp(JDBIDKEYNAME, qf->fpath)) {
             qf->flags |= EJFPKMATCHING;
             *mqf = qf;
             break;
@@ -2669,7 +2676,6 @@ static TCLIST* _fetch_bson_str_array(EJDB *jb, bson_iterator *it, bson_type *typ
     bson_type ftype;
     for (int i = 0; (ftype = bson_iterator_next(it)) != BSON_EOO; ++i) {
         switch (ftype) {
-            case BSON_SYMBOL:
             case BSON_STRING:
                 *type = ftype;
                 if (tflags & JBICASE) { //ignore case
@@ -2745,25 +2751,32 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC
             tclistpush2(pathStack, fkey);
             qf.ftype = ftype;
         } else {
-            if (!pqf) { //Require parent query object
-                ret = JBEQERROR;
-                break;
-            }
-            qf = *pqf;
-            if (!strcmp("$not", fkey)) {
-                qf.negate = !qf.negate;
-            } else if (!strcmp("$gt", fkey)) {
-                qf.flags |= EJCOMPGT;
-            } else if (!strcmp("$gte", fkey)) {
-                qf.flags |= EJCOMPGTE;
-            } else if (!strcmp("$lt", fkey)) {
-                qf.flags |= EJCOMPLT;
-            } else if (!strcmp("$lte", fkey)) {
-                qf.flags |= EJCOMPLTE;
-            } else if (!strcmp("$begin", fkey)) {
-                qf.flags |= EJCONDSTARTWITH;
-            } else if (!strcmp("$icase", fkey)) {
-                qf.flags |= EJCONDICASE;
+            if (!strcmp("$set", fkey) || !strcmp("$inc", fkey)) {
+                if (pqf) { //Top level ops
+                    ret = JBEQERROR;
+                    break;
+                }
+            } else {
+                if (!pqf) { //Require parent query object
+                    ret = JBEQERROR;
+                    break;
+                }
+                qf = *pqf;
+                if (!strcmp("$not", fkey)) {
+                    qf.negate = !qf.negate;
+                } else if (!strcmp("$gt", fkey)) {
+                    qf.flags |= EJCOMPGT;
+                } else if (!strcmp("$gte", fkey)) {
+                    qf.flags |= EJCOMPGTE;
+                } else if (!strcmp("$lt", fkey)) {
+                    qf.flags |= EJCOMPLT;
+                } else if (!strcmp("$lte", fkey)) {
+                    qf.flags |= EJCOMPLTE;
+                } else if (!strcmp("$begin", fkey)) {
+                    qf.flags |= EJCONDSTARTWITH;
+                } else if (!strcmp("$icase", fkey)) {
+                    qf.flags |= EJCONDICASE;
+                }
             }
         }
 
@@ -2827,7 +2840,7 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC
             case BSON_OBJECT:
             {
                 if (isckey) {
-                    if (!strcmp("$set", fkey)) {
+                    if (pqf == NULL && !strcmp("$set", fkey)) { //top level set OP
                         qf.flags |= EJCONDSET;
                         qf.q->flags |= EJQUPDATING;
                     } else if (!strcmp("$inc", fkey)) {
@@ -2845,6 +2858,14 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC
                             bson_append_field_from_iterator(&sit, qf.updateobj);
                         }
                         bson_finish(qf.updateobj);
+                        if (qf.updateobj->err) {
+                            ret = JBEQERROR;
+                        }
+                        qf.fpath = strdup(fkey);
+                        qf.fpathsz = strlen(qf.fpath);
+                        qf.tcop = TDBQTRUE;
+                        qf.flags |= EJFEXCLUDED;
+                        tcmapputkeep(qmap, qf.fpath, qf.fpathsz, &qf, sizeof (qf));
                         break;
                     }
                 }
@@ -2866,8 +2887,6 @@ static int _parse_qobj_impl(EJDB *jb, EJQ *q, bson_iterator *it, TCMAP *qmap, TC
                 tcmapputkeep(qmap, qf.fpath, qf.fpathsz, &qf, sizeof (qf));
                 break;
             }
-
-            case BSON_SYMBOL:
             case BSON_STRING:
             {
                 assert(!qf.fpath && !qf.expr);
@@ -3275,8 +3294,8 @@ static bool _updatebsonidx(EJCOLL *jcoll, const bson_oid_t *oid, const bson *bs,
             continue;
         }
         if (imap == NULL) {
-            imap = tcmapnew2(16);
-            rimap = tcmapnew2(16);
+            imap = tcmapnew2(TCMAPTINYBNUM);
+            rimap = tcmapnew2(TCMAPTINYBNUM);
         }
         for (int i = 4; i <= 7; ++i) { /* JBIDXNUM, JBIDXSTR, JBIDXARR, JBIDXISTR */
             bool rm = false;
index 4fd52cd..885afaa 100644 (file)
@@ -22,7 +22,6 @@ EJDB_EXTERN_C_START
 
 #define BSON_IS_IDXSUPPORTED_TYPE(atype) (atype == BSON_STRING || \
                                           atype == BSON_INT || atype == BSON_LONG || atype == BSON_DOUBLE || \
-                                          atype == BSON_SYMBOL || \
                                           atype == BSON_ARRAY)
 
 struct EJDB {
index 779b933..7cf309b 100644 (file)
@@ -960,7 +960,6 @@ void tclistprintf(TCLIST *list, const char *format, ...){
 #define TCMAPZMMINSIZ  131072            // minimum memory size to use nullified region
 #define TCMAPCSUNIT    52                // small allocation unit size of map concatenation
 #define TCMAPCBUNIT    252               // big allocation unit size of map concatenation
-#define TCMAPTINYBNUM  31                // bucket number of a tiny map
 
 /* get the first hash value */
 #define TCMAPHASH1(TC_res, TC_kbuf, TC_ksiz)                            \
index 68f64bd..a9d4970 100644 (file)
@@ -578,6 +578,7 @@ void tclistprintf(TCLIST *list, const char *format, ...);
  * hash map
  *************************************************************************************************/
 
+#define TCMAPTINYBNUM  31                // bucket number of a tiny map
 
 typedef struct _TCMAPREC {               /* type of structure for an element of a map */
   int32_t ksiz;                          /* size of the region of the key */
index 90f2184..f4473e0 100644 (file)
@@ -12,9 +12,11 @@ TESTS = t1 t2 t3
 check : all check-t1 check-t2 check-t3;
 
 check-valgrind :
-       rm -rf *.vlog
        make RUNCMD="valgrind --tool=memcheck --leak-check=full --error-exitcode=1" check
 
+check-valgrind-t2 :
+       make RUNCMD="valgrind --tool=memcheck --leak-check=full --error-exitcode=1" check-t2
+
 check-t1 :
        $(RUNENV) $(RUNCMD) ./t1
 
index 39c72ea..c546952 100644 (file)
@@ -2714,10 +2714,10 @@ void testTicket8() { //https://github.com/Softmotions/ejdb/issues/8
     TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
     //fprintf(stderr, "%s", TCXSTRPTR(log));
 
-//    for (int i = 0; i < TCLISTNUM(q1res); ++i) {
-//        void *bsdata = TCLISTVALPTR(q1res, i);
-//        bson_print_raw(stderr, bsdata, 0);
-//    }
+    //    for (int i = 0; i < TCLISTNUM(q1res); ++i) {
+    //        void *bsdata = TCLISTVALPTR(q1res, i);
+    //        bson_print_raw(stderr, bsdata, 0);
+    //    }
 
     bson_type bt;
     bson_iterator it;
@@ -2732,23 +2732,23 @@ void testTicket8() { //https://github.com/Softmotions/ejdb/issues/8
             bt = bson_find_fieldpath_value("_id", &it);
             CU_ASSERT_TRUE(bt == BSON_OID);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("address", &it);
+            bt = bson_find_fieldpath_value("address", &it);
             CU_ASSERT_TRUE(bt == BSON_OBJECT);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("address.city", &it);
+            bt = bson_find_fieldpath_value("address.city", &it);
             CU_ASSERT_TRUE(bt == BSON_STRING);
             CU_ASSERT_FALSE(strcmp("Novosibirsk", bson_iterator_string(&it)));
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("address.zip", &it);
+            bt = bson_find_fieldpath_value("address.zip", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("age", &it);
+            bt = bson_find_fieldpath_value("age", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("name", &it);
+            bt = bson_find_fieldpath_value("name", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("labels", &it);
+            bt = bson_find_fieldpath_value("labels", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
         } else if (!bson_compare_string("444-123-333", TCLISTVALPTR(q1res, i), "phone")) {
             ++ccount;
@@ -2756,23 +2756,23 @@ void testTicket8() { //https://github.com/Softmotions/ejdb/issues/8
             bt = bson_find_fieldpath_value("_id", &it);
             CU_ASSERT_TRUE(bt == BSON_OID);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("address", &it);
+            bt = bson_find_fieldpath_value("address", &it);
             CU_ASSERT_TRUE(bt == BSON_OBJECT);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("address.city", &it);
+            bt = bson_find_fieldpath_value("address.city", &it);
             CU_ASSERT_TRUE(bt == BSON_STRING);
             CU_ASSERT_FALSE(strcmp("Novosibirsk", bson_iterator_string(&it)));
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("address.zip", &it);
+            bt = bson_find_fieldpath_value("address.zip", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("age", &it);
+            bt = bson_find_fieldpath_value("age", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("name", &it);
+            bt = bson_find_fieldpath_value("name", &it);
             CU_ASSERT_TRUE(bt == BSON_EOO);
             bson_iterator_from_buffer(&it, bsdata);
-            bt =  bson_find_fieldpath_value("labels", &it);
+            bt = bson_find_fieldpath_value("labels", &it);
             CU_ASSERT_TRUE(bt == BSON_ARRAY);
             CU_ASSERT_FALSE(bson_compare_string("red", bsdata, "labels.0"));
             CU_ASSERT_FALSE(bson_compare_string("green", bsdata, "labels.1"));
@@ -2785,6 +2785,76 @@ void testTicket8() { //https://github.com/Softmotions/ejdb/issues/8
     tclistdel(q1res);
     tcxstrdel(log);
     ejdbquerydel(q1);
+}
+
+void testUpdate1() { //https://github.com/Softmotions/ejdb/issues/9
+
+    EJCOLL *coll = ejdbcreatecoll(jb, "contacts", NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(coll);
+
+    bson_iterator it;
+
+    //q: {name : 'John Travolta', $set : {'labels' : ['black', 'blue'], 'age' : 58}}
+    bson bsq1;
+    bson_init_as_query(&bsq1);
+    bson_append_string(&bsq1, "name", "John Travolta");
+    bson_append_start_object(&bsq1, "$set");
+    bson_append_start_array(&bsq1, "labels");
+    bson_append_string(&bsq1, "0", "black");
+    bson_append_string(&bsq1, "1", "blue");
+    bson_append_finish_array(&bsq1);
+    bson_append_int(&bsq1, "age", 58);
+    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();
+    TCLIST *q1res = ejdbqryexecute(coll, q1, &count, 0, log);
+    //fprintf(stderr, "%s", TCXSTRPTR(log));
+    CU_ASSERT_EQUAL(1, count);
+    CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: YES"));
+
+    for (int i = 0; i < TCLISTNUM(q1res); ++i) {
+        CU_ASSERT_TRUE(!bson_compare_string("John Travolta", TCLISTVALPTR(q1res, i), "name"));
+        bson_iterator_from_buffer(&it, TCLISTVALPTR(q1res, i));
+        CU_ASSERT_TRUE(bson_find_from_buffer(&it, TCLISTVALPTR(q1res, i), "age") == BSON_EOO);
+    }
+
+    bson_destroy(&bsq1);
+    tclistdel(q1res);
+    tcxstrdel(log);
+    ejdbquerydel(q1);
+
+    //q2: {name : 'John Travolta', age: 58}
+    bson_init_as_query(&bsq1);
+    bson_append_string(&bsq1, "name", "John Travolta");
+    bson_append_int(&bsq1, "age", 58);
+    bson_append_finish_object(&bsq1);
+    bson_finish(&bsq1);
+    CU_ASSERT_FALSE_FATAL(bsq1.err);
+
+    q1 = ejdbcreatequery(jb, &bsq1, NULL, 0, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(q1);
+    count = 0;
+    log = tcxstrnew();
+    q1res = ejdbqryexecute(coll, q1, &count, 0, log);
+    //fprintf(stderr, "%s", TCXSTRPTR(log));
+    CU_ASSERT_PTR_NOT_NULL(strstr(TCXSTRPTR(log), "UPDATING MODE: NO"));
+
+    for (int i = 0; i < TCLISTNUM(q1res); ++i) {
+        CU_ASSERT_FALSE(bson_compare_long(58, TCLISTVALPTR(q1res, i), "age"));
+        CU_ASSERT_FALSE(bson_compare_string("black", TCLISTVALPTR(q1res, i), "labels.0"));
+        CU_ASSERT_FALSE(bson_compare_string("blue", TCLISTVALPTR(q1res, i), "labels.1"));
+    }
+    bson_destroy(&bsq1);
+    tclistdel(q1res);
+    tcxstrdel(log);
+    ejdbquerydel(q1);
+
+    
 
 
 }
@@ -2839,7 +2909,8 @@ int main() {
             (NULL == CU_add_test(pSuite, "testEmptyFieldIndex", testEmptyFieldIndex)) ||
             (NULL == CU_add_test(pSuite, "testICaseIndex", testICaseIndex)) ||
             (NULL == CU_add_test(pSuite, "testTicket7", testTicket7)) ||
-            (NULL == CU_add_test(pSuite, "testTicket8", testTicket8))
+            (NULL == CU_add_test(pSuite, "testTicket8", testTicket8)) ||
+            (NULL == CU_add_test(pSuite, "testUpdate1", testUpdate1))
             ) {
         CU_cleanup_registry();
         return CU_get_error();