fix that NULL as __tabname did not work as table separator in queries

Wed, 31 Dec 2025 15:40:44 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 31 Dec 2025 15:40:44 +0100
changeset 35
16731869cc05
parent 34
0d2291e77d32
child 36
93753b036d9f

fix that NULL as __tabname did not work as table separator in queries

dbutils/object.c file | annotate | diff | comparison | revisions
test/database.c file | annotate | diff | comparison | revisions
--- a/dbutils/object.c	Tue Dec 30 21:07:45 2025 +0100
+++ b/dbutils/object.c	Wed Dec 31 15:40:44 2025 +0100
@@ -341,7 +341,7 @@
     // collect all foreign keys per row
     CxList *fklist = cxArrayListCreate(NULL, sizeof(DBUFK), 4);
     fklist->collection.simple_destructor = (cx_destructor_func)dbufkelm_free;
-    
+      
      // get result
     int err = 0;
     while(result->hasData(result)) {       
@@ -377,6 +377,7 @@
         }
         
         void *current_obj = obj;
+        void *parent_obj = obj;
         void *child_obj = NULL;
         DBUClass *current_cls = cls;
         for(int i=skip_fields;i<numcols;i++) {
@@ -404,10 +405,21 @@
                     }
                 }
                 
-                current_cls = field.cls;
                 if(field.field) {
                     // check if an object of this class can be added to the main obj
                     DBUField *obj_field = cxMapGet(cls->obj_fields, field.cls->name);
+                    if(!obj_field) {
+                        // priority 2: can this class be added to the current class?
+                        obj_field = cxMapGet(current_cls->obj_fields, field.cls->name);
+                        if(obj_field) {
+                            parent_obj = current_obj;
+                        }
+                    } else {
+                        parent_obj = obj;
+                    }
+                    
+                    current_cls = field.cls;
+                    
                     if(obj_field && obj_field->initObjValue) {
                         //printf("create child obj [%s]\n", field.cls->name.ptr);
                         child_obj = objresult->create(objresult, field.cls, a);
@@ -421,7 +433,7 @@
                             field.cls->init(child_obj, a); // TODO: check return
                         }
 
-                        obj_field->initObjValue(obj_field, a, obj, child_obj);
+                        obj_field->initObjValue(obj_field, a, parent_obj, child_obj);
                     } else {
                         //printf("list field\n");
                         
@@ -454,6 +466,7 @@
                 } else {
                     cxstring text = result->getText(result, i);
                     //printf("getText(%d) = %s\n", i, text.ptr);
+                    //printf("init obj: [%d] %p   {%s}\n", i, current_obj, text.ptr);
                     field.field->initValue(field.field, a, current_obj, text.ptr, text.length);
                     
                     // if obj caching is enabled and the current field contains
--- a/test/database.c	Tue Dec 30 21:07:45 2025 +0100
+++ b/test/database.c	Wed Dec 31 15:40:44 2025 +0100
@@ -310,45 +310,6 @@
         CX_TEST_ASSERT(!cx_strcmp(p1->address->city, "city 18"));
         
         dbuObjectBuilderDestroy(builder);
-        
-        const char *sql2 = "select p.*, "
-                           "a.address_id as [__address__address_id], a.street, a.zip, a.city, "
-                           "c.country_id as [__country__country_id], c.name "
-                           "from Person p inner join Address a on p.address_id = a.address_id inner join Country c on a.country_id = c.country_id "
-                           "order by p.person_id;";
-        DBUQuery *query2 = dbuQueryCreate(conn, mp->allocator, sql2);
-        DBUObjectBuilder *builder2 = dbuObjectBuilder(person, query2, mp->allocator);
-        CxList *persons2 = dbuObjectBuilderGetList(builder2);
-        
-        CX_TEST_ASSERT(persons2);
-        CX_TEST_ASSERT(cxListSize(persons2) == 2);
-        
-        p0 = cxListAt(persons2, 0);
-        p1 = cxListAt(persons2, 1);
-        CX_TEST_ASSERT(p0);
-        CX_TEST_ASSERT(p1);
-        CX_TEST_ASSERT(!cx_strcmp(p0->name, "alice"));
-        CX_TEST_ASSERT(!cx_strcmp(p1->name, "bob"));
-        CX_TEST_ASSERT(!cx_strcmp(p0->email, "alice@example.com"));
-        CX_TEST_ASSERT(!cx_strcmp(p1->email, "bob@example.com"));
-        CX_TEST_ASSERT(p0->age == 30);
-        CX_TEST_ASSERT(p1->age == 25);
-        CX_TEST_ASSERT(p0->iscustomer == 0);
-        CX_TEST_ASSERT(p1->iscustomer == 1);
-        CX_TEST_ASSERT(p0->hash == 123456789);
-        CX_TEST_ASSERT(p1->hash == 987654321);
-        
-        CX_TEST_ASSERT(p0->address != NULL);
-        CX_TEST_ASSERT(p1->address != NULL);
-        
-        CX_TEST_ASSERT(!cx_strcmp(p0->address->street, "street 1"));
-        CX_TEST_ASSERT(!cx_strcmp(p1->address->street, "street 2"));
-        CX_TEST_ASSERT(!cx_strcmp(p0->address->zip, "12343"));
-        CX_TEST_ASSERT(!cx_strcmp(p1->address->zip, "23456"));
-        CX_TEST_ASSERT(!cx_strcmp(p0->address->city, "city 17"));
-        CX_TEST_ASSERT(!cx_strcmp(p1->address->city, "city 18"));
-        
-        dbuObjectBuilderDestroy(builder2);
     }
     
     cxMempoolFree(mp);
@@ -395,6 +356,11 @@
         CX_TEST_ASSERT(!cx_strcmp(p0->address->city, "city 17"));
         CX_TEST_ASSERT(!cx_strcmp(p1->address->city, "city 18"));
         
+        CX_TEST_ASSERT(p0->address->country);
+        CX_TEST_ASSERT(p1->address->country);
+        CX_TEST_ASSERT(!cx_strcmp(p0->address->country->name, "Germany"));
+        CX_TEST_ASSERT(!cx_strcmp(p1->address->country->name, "Germany"));
+        
         dbuObjectBuilderDestroy(builder);
     }
     

mercurial