prepare for dense queries

Mon, 16 Dec 2024 18:38:11 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 16 Dec 2024 18:38:11 +0100
changeset 9
5785a693834c
parent 8
bd08116b8af4
child 10
80f9d007cb52

prepare for dense queries

dbutils/dbutils/db.h file | annotate | diff | comparison | revisions
dbutils/object.c file | annotate | diff | comparison | revisions
dbutils/object.h file | annotate | diff | comparison | revisions
--- a/dbutils/dbutils/db.h	Sat Dec 14 17:03:31 2024 +0100
+++ b/dbutils/dbutils/db.h	Mon Dec 16 18:38:11 2024 +0100
@@ -111,16 +111,17 @@
 
 
 DBUObjectBuilder* dbuObjectBuilder(DBUClass *type, DBUQuery *query, const CxAllocator *a);
-int dbuObjectBuilderAddSubquery(DBUObjectBuilder *builder, DBUClass *type, DBUQuery *subquery);
+void dbuObjectBuilderSetDenseResult(DBUObjectBuilder *builder, bool dense);
 int dbuObjectBuilderAddAdditionalQuery(DBUObjectBuilder *builder, DBUClass *type, DBUQuery *query);
 CxList* dbuObjectBuilderGetList(DBUObjectBuilder *builder);
 CxList* dbuObjectBuilderGetValueList(DBUObjectBuilder *builder);
 int dbuObjectBuilderGetArray(DBUObjectBuilder *builder, void **array, size_t *size);
 void dbuObjectBuilderDestroy(DBUObjectBuilder *builder);
 
+// TODO: implement
+int dbuObjectBuilderAddSubquery(DBUObjectBuilder *builder, DBUClass *type, DBUQuery *subquery);
 
-// TODO: remove
-CxList* dbuQuerySingleType(DBUContext *ctx, DBUQuery *query, const char *type);
+
 
 #ifdef __cplusplus
 }
--- a/dbutils/object.c	Sat Dec 14 17:03:31 2024 +0100
+++ b/dbutils/object.c	Mon Dec 16 18:38:11 2024 +0100
@@ -69,6 +69,10 @@
     return builder;
 }
 
+void dbuObjectBuilderSetDenseResult(DBUObjectBuilder *builder, bool dense) {
+    builder->denseResult = dense;
+}
+
 int dbuObjectBuilderAddSubquery(DBUObjectBuilder *builder, DBUClass *type, DBUQuery *subquery) {
     return cxMapPut(builder->subQueries, type->name, subquery);
 }
@@ -185,14 +189,14 @@
 }
 
 int dbuObjectExec(DBUObjectBuilder *builder, DBUObjectResult *objresult) {
-    if(cxListSize(builder->additionalQueries) > 0) {
+    if(cxListSize(builder->additionalQueries) > 0 || builder->denseResult) {
         builder->cache = cxHashMapCreateSimple(sizeof(DBUBuilderObjCache));
         if(!builder->cache) {
             return 1;
         }
     }
     
-    int ret = dbuObjectExecuteQuery(builder, builder->mainQuery, builder->resultType, objresult);
+    int ret = dbuObjectExecuteQuery(builder, builder->mainQuery, builder->resultType, objresult, builder->denseResult);
     if(!ret) {
         CxIterator i = cxListIterator(builder->additionalQueries);
         cx_foreach(DBUBuilderQuery *, q, i) {
@@ -204,7 +208,7 @@
                 .add = add_to_parent
             };
             
-            ret = dbuObjectExecuteQuery(builder, q->query, q->type, &result);
+            ret = dbuObjectExecuteQuery(builder, q->query, q->type, &result, false);
             if(ret) {
                 break;
             }
@@ -222,7 +226,7 @@
     free(elm->cache_key);
 }
 
-int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult) {
+int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult, bool dense) {
     DBUClass *cls = type;
     
     // TODO: execute additional queries
@@ -250,6 +254,9 @@
     bool is_main = true;
     DBUClass *field_class = cls;
     
+    int main_pk_index = -1;
+    int end_main_fields = numcols;
+    
     for(int i=0;i<numcols;i++) {
         cxstring fieldname = cx_str(result->fieldName(result, i));
         DBUField *field = NULL;
@@ -287,9 +294,21 @@
             mapping.type = result->fieldType(result, i);
             mapping.is_main = is_main;
             field_mapping[i] = mapping;
+            
+            if(field == cls->primary_key) {
+                main_pk_index = i;
+            }
+            
+            if(end_main_fields == numcols && field_class != cls) {
+                end_main_fields = i;
+            }
         }
     }
     
+    if(main_pk_index < 0) {
+        dense = false;
+    }
+    
     const CxAllocator *a = builder->allocator;
     
     CxList *fklist = cxArrayListCreateSimple(sizeof(DBUFK), 4);
@@ -300,7 +319,28 @@
     while(result->hasData(result)) {
         
         // create main result obj
-        void *obj = objresult->create(objresult, cls, a);
+        bool addobj = true;
+        void *obj = NULL;
+        int skip_fields = 0;
+        if(dense) {
+            cxstring text = result->getText(result, main_pk_index);
+            cxmutstr cache_key = cx_asprintf("%.*s::%.*s",
+                    (int)cls->name.length, cls->name.ptr,
+                    (int)text.length, text.ptr);
+            if(!cache_key.ptr) {
+                err = 1;
+                break;
+            }
+            DBUBuilderObjCache *cached_obj = cxMapGet(builder->cache, cache_key);
+            free(cache_key.ptr);
+            if(cached_obj && cached_obj->class == cls) {
+                obj = cached_obj->obj;
+                addobj = false;
+                skip_fields = end_main_fields;
+            }
+        }
+            
+        obj = objresult->create(objresult, cls, a);
         if(!obj) {
             break;
         }
@@ -312,7 +352,7 @@
         void *current_obj = obj;
         void *child_obj = NULL;
         DBUClass *current_cls = cls;
-        for(int i=0;i<numcols;i++) {
+        for(int i=skip_fields;i<numcols;i++) {
             DBUFieldMapping field = field_mapping[i];
             int isnull = result->isNull(result, i);
             
@@ -385,7 +425,9 @@
             break;
         }
         
-        objresult->add(objresult, NULL, cls, obj, fklist, a);
+        if(addobj) {
+            objresult->add(objresult, NULL, cls, obj, fklist, a);
+        }
         
         cxListClear(fklist);
         
--- a/dbutils/object.h	Sat Dec 14 17:03:31 2024 +0100
+++ b/dbutils/object.h	Mon Dec 16 18:38:11 2024 +0100
@@ -100,6 +100,12 @@
      * 
      */
     CxMap *cache;
+    
+    /*
+     * if true, the main result does not contain duplicated entries
+     * with the same primary key
+     */
+    bool denseResult;
 };
 
 typedef struct DBUFK {
@@ -109,7 +115,7 @@
 
 int dbuObjectExec(DBUObjectBuilder *builder, DBUObjectResult *objresult);
 
-int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult);
+int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass *type, DBUObjectResult *objresult, bool dense);
 
 #ifdef __cplusplus
 }

mercurial