#define SQL_RESOURCE_DELETE_CHILDREN "delete from resources where parent_id = ? ;"
+// unused
#define SQL_RESOURCE_DELETE_ALL \
"with recursive cte as ( " \
" select resource_id, parent_id, nodename from resources where resource_id = ? " \
if(!q->exec(q)) {
err = dbuResultAsValue(q->getResult(q), ¬ebooks_id);
if(!err) {
- DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, notebooks_id);
+ DBUResult *result = dbuSqlExecQueryParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, notebooks_id);
int64_t unused;
err = dbuResultAsInt64(result, &unused);
}
if(!q->exec(q)) {
err = dbuResultAsValue(q->getResult(q), &mynotes_id);
if(!err) {
- DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, mynotes_id);
+ DBUResult *result = dbuSqlExecQueryParamInt64(connection, NULL, SQL_NOTEBOOK_NEW, mynotes_id);
int64_t unused;
err = dbuResultAsInt64(result, &unused);
}
} CountJob;
static int qthr_collection_get_size(CountJob *job) {
- DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_NOTEBOOK_COUNT_CHILDREN, job->id1);
+ DBUResult *result = dbuSqlExecQueryParamInt64(connection, NULL, SQL_NOTEBOOK_COUNT_CHILDREN, job->id1);
if(!result) {
job->error = 1;
return 0;
static int qthr_delete_collection(ExecJob *job) {
if(job->flag == NOTESTORE_COLLECTION_DELETE_ALL) {
- DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_RESOURCE_DELETE_ALL, job->id1);
- if(!result) {
+ if(dbuSqlExecParamInt64(connection, SQL_RESOURCE_DELETE, job->id1)) {
job->error = 3;
return 0;
}
- int ok = dbuResultIsOk(result);
- dbuResultFree(result);
- if(!ok) {
- job->error = 4;
- return 0;
- }
} else {
// only delete the resource when there are no children
int64_t nchildren = note_store_count_children(job->id1);
return 0;
}
- DBUResult *result = dbuSqlExecParamInt64(connection, NULL, SQL_RESOURCE_DELETE, job->id1);
- if(!result) {
- job->error = 5;
- }
- int ok = dbuResultIsOk(result);
- dbuResultFree(result);
- if(!ok) {
- job->error = 6;
+ if(dbuSqlExecParamInt64(connection, SQL_RESOURCE_DELETE, job->id1)) {
+ job->error = 3;
}
}
int nsql = sizeof(sql) / sizeof(char*);
for(int i=0;i<nsql;i++) {
- if(dbuConnectionExec(connection, sql[i])) {
+ if(dbuSqlExec(connection, sql[i])) {
fprintf(stderr, "sqlite error: query failed\n%s\n", sql[i]);
return 1;
}
int ret = note_store_create_default("testhost", "testuser");
CX_TEST_ASSERT(ret == 0);
- DBUResult *result = dbuSqlExec(conn, NULL,
+ DBUResult *result = dbuSqlExecQuery(conn, NULL,
"select r.repository_id, c.resource_id from user_settings u "
"inner join repositories r on u.default_repository_id = r.repository_id "
"inner join resources c on u.default_collection_id = c.resource_id "
free(field->name.ptr);
field->name = name ? cx_strdup(cx_str(name)) : (cxmutstr){NULL,0};
cxMapPut(cls->obj_fields, foreign_cls->name, field);
+ cxMapPut(cls->fields, name, field);
}
#include "db.h"
#include "dbutils/db.h"
-int dbuConnectionExec(DBUConnection *conn, const char *sql) {
- DBUQuery *q = conn->createQuery(conn, NULL);
- int err = 1;
- if(!dbuQuerySetSQL(q, sql)) {
- err = dbuQueryExec(q);
- }
- dbuQueryFree(q);
- return err;
-}
-
int dbuConnectionIsActive(DBUConnection *conn) {
return conn->isActive ? conn->isActive(conn) : 1;
}
return q;
}
-DBUResult* dbuSqlExec(DBUConnection *conn, const CxAllocator *a, const char *sql) {
+DBUResult* dbuSqlExecQuery(DBUConnection *conn, const CxAllocator *a, const char *sql) {
DBUQuery *q = dbuQueryCreate(conn, a, sql);
if(!q) {
return NULL;
return result;
}
-DBUResult* dbuSqlExecParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param) {
+DBUResult* dbuSqlExecQueryParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param) {
DBUQuery *q = execInt64ParamQuery(conn, sql, param);
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
return r;
}
-DBUResult* dbuSqlExecParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param) {
+DBUResult* dbuSqlExecQueryParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param) {
DBUQuery *q = execInt64ParamQuery(conn, sql, param);
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
return r;
}
-DBUResult* dbuSqlExecParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param) {
+DBUResult* dbuSqlExecQueryParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param) {
DBUQuery *q = execInt64ParamQuery(conn, sql, param);
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
return r;
}
-DBUResult* dbuSqlExecParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param) {
+DBUResult* dbuSqlExecQueryParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint64_t param) {
DBUQuery *q = execInt64ParamQuery(conn, sql, param);
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
return r;
}
-DBUResult* dbuSqlExecParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param) {
+DBUResult* dbuSqlExecQueryParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param) {
DBUQuery *q = execStringParamQuery(conn, sql, cx_str(param));
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
return r;
}
-DBUResult* dbuSqlExecParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param) {
+DBUResult* dbuSqlExecQueryParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param) {
DBUQuery *q = execStringParamQuery(conn, sql, param);
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
return r;
}
-DBUResult* dbuSqlExecParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param) {
+DBUResult* dbuSqlExecQueryParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param) {
DBUQuery *q = execStringParamQuery(conn, sql, cx_strcast(param));
if(!q) return NULL;
DBUResult *r = dbuQueryGetResult(q);
dbuObjectBuilderDestroy(builder);
return list;
}
+
+int dbuSqlExec(DBUConnection *conn, const char *sql) {
+ DBUResult *result = dbuSqlExecQuery(conn, NULL, sql);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamInt32(DBUConnection *conn, const char *sql, int32_t param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamInt64(DBUConnection *conn, const char *sql, int64_t param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamUInt32(DBUConnection *conn, const char *sql, uint32_t param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamUInt64(DBUConnection *conn, const char *sql, uint64_t param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamString(DBUConnection *conn, const char *sql, const char *param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamCxString(DBUConnection *conn, const char *sql, cxstring param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
+
+int dbuSqlExecParamCxMutStr(DBUConnection *conn, const char *sql, cxmutstr param) {
+ DBUResult *result = dbuSqlExecQueryParam(conn, NULL, sql, param);
+ if(!result) {
+ return 1;
+ }
+ int ret = dbuResultIsOk(result);
+ dbuResultFree(result);
+ return !ret;
+}
int rowIndex;
};
-int dbuConnectionExec(DBUConnection *conn, const char *sql);
int dbuConnectionIsActive(DBUConnection *conn);
void dbuConnectionFree(DBUConnection *conn);
DBUQuery* dbuConnectionQuery(DBUConnection *conn, const CxAllocator *a);
// TODO: implement
int dbuObjectBuilderAddSubquery(DBUObjectBuilder *builder, DBUClass *type, DBUQuery *subquery);
-#define dbuSqlExecParam(conn, a, sql, param) \
+#define dbuSqlExecQueryParam(conn, a, sql, param) \
_Generic(param, \
- int32_t : dbuSqlExecParamInt32, \
- int64_t : dbuSqlExecParamInt64, \
- uint32_t : dbuSqlExecParamUInt32, \
- uint64_t : dbuSqlExecParamUInt64, \
- char* : dbuSqlExecParamString, \
- const char*: dbuSqlExecParamString, \
- cxstring : dbuSqlExecParamCxString, \
- cxmutstr : dbuSqlExecParamCxMutStr)(conn, a, sql, param)
-
-DBUResult* dbuSqlExec(DBUConnection *conn, const CxAllocator *a, const char *sql);
-DBUResult* dbuSqlExecParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param);
-DBUResult* dbuSqlExecParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param);
-DBUResult* dbuSqlExecParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param);
-DBUResult* dbuSqlExecParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param);
-DBUResult* dbuSqlExecParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param);
-DBUResult* dbuSqlExecParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param);
-DBUResult* dbuSqlExecParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param);
-
-
+ int32_t : dbuSqlExecQueryParamInt32, \
+ int64_t : dbuSqlExecQueryParamInt64, \
+ uint32_t : dbuSqlExecQueryParamUInt32, \
+ uint64_t : dbuSqlExecQueryParamUInt64, \
+ char* : dbuSqlExecQueryParamString, \
+ const char*: dbuSqlExecQueryParamString, \
+ cxstring : dbuSqlExecQueryParamCxString, \
+ cxmutstr : dbuSqlExecQueryParamCxMutStr)(conn, a, sql, param)
+
+DBUResult* dbuSqlExecQuery(DBUConnection *conn, const CxAllocator *a, const char *sql);
+DBUResult* dbuSqlExecQueryParamInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, int32_t param);
+DBUResult* dbuSqlExecQueryParamInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, int64_t param);
+DBUResult* dbuSqlExecQueryParamUInt32(DBUConnection *conn, const CxAllocator *a, const char *sql, uint32_t param);
+DBUResult* dbuSqlExecQueryParamUInt64(DBUConnection *conn, const CxAllocator *a, const char *sql, uint64_t param);
+DBUResult* dbuSqlExecQueryParamString(DBUConnection *conn, const CxAllocator *a, const char *sql, const char *param);
+DBUResult* dbuSqlExecQueryParamCxString(DBUConnection *conn, const CxAllocator *a, const char *sql, cxstring param);
+DBUResult* dbuSqlExecQueryParamCxMutStr(DBUConnection *conn, const CxAllocator *a, const char *sql, cxmutstr param);
int dbuSimpleGetInt64WithIntParam(DBUConnection *conn, const char *sql, int64_t param, int64_t *result);
int dbuSimpleGetInt64WithStringParam(DBUConnection *conn, const char *sql, cxstring param, int64_t *result);
CxList* dbuSimpleGetListWithIntParam(DBUConnection *conn, const char *sql, int64_t param, const CxAllocator *a, DBUClass *type);
CxList* dbuSimpleGetListWithStringParam(DBUConnection *conn, const char *sql, cxstring param, const CxAllocator *a, DBUClass *type);
+#define dbuSqlExecParam(conn, sql, param) \
+ _Generic(param, \
+ int32_t : dbuSqlExecParamInt32, \
+ int64_t : dbuSqlExecParamInt64, \
+ uint32_t : dbuSqlExecParamUInt32, \
+ uint64_t : dbuSqlExecParamUInt64, \
+ char* : dbuSqlExecParamString, \
+ const char*: dbuSqlExecParamString, \
+ cxstring : dbuSqlExecParamCxString, \
+ cxmutstr : dbuSqlExecParamCxMutStr)(conn, sql, param)
+
+int dbuSqlExec(DBUConnection *conn, const char *sql);
+int dbuSqlExecParamInt32(DBUConnection *conn, const char *sql, int32_t param);
+int dbuSqlExecParamInt64(DBUConnection *conn, const char *sql, int64_t param);
+int dbuSqlExecParamUInt32(DBUConnection *conn, const char *sql, uint32_t param);
+int dbuSqlExecParamUInt64(DBUConnection *conn, const char *sql, uint64_t param);
+int dbuSqlExecParamString(DBUConnection *conn, const char *sql, const char *param);
+int dbuSqlExecParamCxString(DBUConnection *conn, const char *sql, cxstring param);
+int dbuSqlExecParamCxMutStr(DBUConnection *conn, const char *sql, cxmutstr param);
+
#ifdef __cplusplus
}
#endif
struct DBUObjectResult {
void *userdata1;
void *userdata2;
+ DBUClass *type;
int int1;
int int2;
DBUObject (*create)(DBUObjectResult *result, DBUClass *type, const CxAllocator *a);
CxJsonValue* dbuObjectToJson2(DBUClass *type, void *obj, const CxAllocator *a, bool setNull, bool forceString);
+void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value);
+CxList* dbuJsonToList(DBUClass *type, const CxAllocator *a, CxJsonValue *value);
+
#ifdef __cplusplus
}
}
static int linkedlist_add(DBUObjectResult *result, DBUObject parent, DBUClass *type, void *obj, CxList *fk, const CxAllocator *a) {
DBUOffsetField *field = result->userdata1;
- DBUClass *cls = result->userdata2;
+ DBUClass *cls = result->type;
CxList **list = (CxList**)(parent+field->offset);
if(!*list) {
*list = cxLinkedListCreate(a, CX_STORE_POINTERS);
memset(field, 0, sizeof(DBUOffsetField));
field->offset = offset;
field->def.def = 0;
+ field->field.builder.type = foreign_cls;
field->field.builder.userdata1 = field;
field->field.builder.userdata2 = foreign_cls;
field->field.builder.create = linkedlist_create_obj;
field->field.builder.add = linkedlist_add;
field->field.toList = cxlist_tolist;
// TODO: can we pass name to dbuClassAddObjField?
- dbuClassAddObjField(cls, NULL, (DBUField*)field, foreign_cls);
+ dbuClassAddObjField(cls, name, (DBUField*)field, foreign_cls);
field->field.name = name ? cx_strdup(cx_str(name)) : (cxmutstr){NULL,0};
//dbuClassAddParentObjField(foreign_cls, name, cls, (DBUField*)field);
}
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdio.h>
+
#include "json.h"
+/* ---------------- Obj to JSON serialization functions ---------------------*/
+
CxJsonValue* dbuObjectToJson(DBUClass *type, void *obj, const CxAllocator *a) {
return dbuObjectToJson2(type, obj, a, false, false);
}
return value;
}
+
+
+/* --------------- Json to Obj deserialization functions --------------------*/
+
+static void* jsonToObj(DBUClass *type, const CxAllocator *a, CxJsonValue *value, int depth, int *error) {
+ if(!cxJsonIsObject(value)) {
+ *error = 1;
+ return NULL;
+ }
+ if(depth > DBU_JSON_MAX_DEPTH) {
+ *error = 2;
+ return NULL;
+ }
+ if(!a) {
+ a = cxDefaultAllocator;
+ }
+
+ void *obj = cxMalloc(a, type->obj_size);
+ if(obj) {
+ memset(obj, 0, type->obj_size);
+ } else {
+ *error = 3;
+ return NULL;
+ }
+
+ char buf[64];
+ int len = 0;
+
+ CxMapIterator i = cxMapIterator(value->object);
+ cx_foreach(CxMapEntry *, entry, i) {
+ DBUField *field = cxMapGet(type->fields, entry->key);
+ if(!field) {
+ field = cxMapGet(type->obj_fields, entry->key);
+ if(!field) {
+ continue;
+ }
+ }
+
+ len = 0;
+
+ CxJsonValue *child = entry->value;
+ switch(child->type) {
+ case CX_JSON_LITERAL: {
+ if(child->literal == CX_JSON_NULL) {
+ if(field->initObjValue) {
+ field->initObjValue(field, a, obj, NULL);
+ }
+ break;
+ } else {
+ int b = child->literal == CX_JSON_TRUE;
+ if(field->initIntValue) {
+ field->initIntValue(field, a, obj, b);
+ continue;
+ } else {
+ len = snprintf(buf, 64, "%d", b);
+ }
+ }
+ break;
+ }
+ case CX_JSON_INTEGER: {
+ if(field->initIntValue) {
+ field->initIntValue(field, a, obj, child->integer);
+ } else {
+ len = snprintf(buf, 64, "%" PRId64, child->integer);
+ }
+ break;
+ }
+ case CX_JSON_NUMBER: {
+ if(field->initDoubleValue) {
+ field->initDoubleValue(field, a, obj, child->number);
+ } else {
+ len = snprintf(buf, 64, "%f", child->number);
+ }
+ break;
+ }
+ case CX_JSON_STRING: {
+ cxmutstr str = child->string;
+ if(field->initValue(field, a, obj, str.ptr, str.length)) {
+ *error = 3;
+ free(obj); // TODO: improve obj cleanup
+ return NULL;
+ }
+ break;
+ }
+ case CX_JSON_OBJECT: {
+ if(field->objType && field->initObjValue) {
+ void *child_obj = jsonToObj(field->objType, a, child, depth+1, error);
+ if(child_obj) {
+ field->initObjValue(field, a, obj, child_obj);
+ } else {
+ free(obj); // TODO: improve obj cleanup
+ return NULL;
+ }
+ }
+ break;
+ }
+ case CX_JSON_ARRAY: {
+ if(field->builder.add) {
+ for(int i=0;i<child->array.size;i++) {
+ CxJsonValue *elm = child->array.data[i];
+ void *elm_obj = NULL;
+ bool add_elm = false;
+ if(cxJsonIsObject(elm)) {
+ elm_obj = jsonToObj(field->builder.type, a, elm, depth+1, error);
+ if(!elm_obj) {
+ free(obj); // TODO: improve obj cleanup
+ return NULL;
+ }
+ add_elm = true;
+
+ } else if(cxJsonIsLiteral(elm) && elm->literal == CX_JSON_NULL) {
+ add_elm = true;
+ }
+
+ if(add_elm) {
+ if(field->builder.add(&field->builder, obj, field->builder.type, elm_obj, NULL, a)) {
+ free(obj); // TODO: improve obj cleanup
+ free(elm_obj);
+ *error = 3;
+ return NULL;
+ }
+ }
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+
+ if(len > 0) {
+ if(field->initValue(field, a, obj, buf, len)) {
+ // TODO: completely cleanup obj
+ free(obj);
+ *error = 3;
+ return NULL;
+ }
+ }
+ }
+
+ *error = 0;
+ return obj;
+}
+
+void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value) {
+ int error;
+ return jsonToObj(type, a, value, 0, &error);
+}
+
+static CxList* jsonToArray(DBUClass *type, const CxAllocator *a, CxJsonValue *value, size_t elmSize, int *error) {
+ if(!cxJsonIsArray(value)) {
+ *error = 1;
+ return NULL;
+ }
+
+ CxList *list = cxArrayListCreate(a, elmSize, value->array.size);
+ if(!list) {
+ *error = 3;
+ }
+
+ for(size_t i=0;i<value->array.size;i++) {
+ CxJsonValue *elm = value->array.data[i];
+ void *elm_obj = NULL;
+ if(cxJsonIsObject(elm)) {
+ elm_obj = jsonToObj(type, a, elm, 1, error);
+ if(!elm_obj) {
+ cxListFree(list);
+ return NULL;
+ }
+ }
+ if(cxListAdd(list, elm_obj)) {
+ *error = 3;
+ cxListFree(list);
+ return NULL;
+ }
+ }
+
+ return list;
+}
+
+CxList* dbuJsonToList(DBUClass *type, const CxAllocator *a, CxJsonValue *value) {
+ int error;
+ return jsonToArray(type, a, value, CX_STORE_POINTERS, &error);
+}
extern "C" {
#endif
-
+#define DBU_JSON_MAX_DEPTH 512
#ifdef __cplusplus
}
// TODO: the class needs a obj destructor func, because we need to be able
// to destroy partialy created lists
- DBUObjectResult result = {
+ DBUObjectResult result = {
+ .type = builder->resultType,
.userdata1 = result_list,
.userdata2 = malloc(builder->resultType->obj_size),
.int1 = builder->resultType->obj_size,
DBUClass *cls = type;
// execute sql
+ if(!query) {
+ return 1;
+ }
+
if(query->exec(query)) {
query->free(query);
return 1;
// list of all classes returned by the result
// used when dense == true, to check, if a new result row contains
// the same objects (primary keys haven't changed)
- size_t result_types_capacity = 16;
- size_t result_types_size = 0;
CX_ARRAY(DBUResultType, result_types);
cx_array_init(result_types, 16);
DBUResultType mainResult = { .cls = cls };
cx_array_add(result_types, mainResult);
+ // analyse columns: create a column-field mapping
for(int i=0;i<numcols;i++) {
cxstring fieldname = cx_str(result->fieldName(result, i));
DBUField *field = NULL;
}
if(remaining.length > 2) {
field = cxMapGet(fcls->fields, cx_strsubs(remaining, 2));
+ // make sure the field is a normal field and not an obj/list field
+ if(!field->initValue) {
+ field = NULL;
+ }
}
field_mapping[i].cls = fcls;
field_class = fcls;
}
} else {
field = cxMapGet(field_class->fields, fieldname);
+ if(field && !field->initValue) {
+ field = NULL;
+ }
}
if(field) {
CxList *fklist = cxArrayListCreate(NULL, sizeof(DBUFK), 4);
fklist->collection.simple_destructor = (cx_destructor_func)dbufkelm_free;
- // get result
+ // get result
int err = 0;
while(result->hasData(result)) {
// create main result obj
int skip_fields = 0;
int cls_index = 0;
if(dense) {
+ // if the primary key in this row is the same as in the previous
+ // row, we don't create a new obj for this row, but reuse the
+ // previous obj ptr.
cxstring text = result->getText(result, main_pk_index);
cxmutstr prev_pk = result_types.data[0].prev_key;
- if(prev_pk.ptr && !cx_strcmp(text, cx_strcast(prev_pk))) {
+ if(prev_pk.ptr && !cx_strcmp(text, prev_pk)) {
obj = result_types.data[0].prev_obj;
addobj = false;
- if(1 < result_types_size) {
+ if(1 < result_types.size) {
skip_fields = result_types.data[1].pk_col;
}
}
if(dense) {
// check if this object was already added
- if(cls_index < result_types_size) {
+ if(cls_index < result_types.size) {
cxstring text = result->getText(result, result_types.data[cls_index].pk_col);
cxmutstr prev_pk = result_types.data[cls_index].prev_key;
if(prev_pk.ptr && !cx_strcmp(text, cx_strcast(prev_pk))) {
//printf("already added -> skip\n");
- if(cls_index+1 < result_types_size) {
+ if(cls_index+1 < result_types.size) {
i = result_types.data[cls_index+1].pk_col-1; // -1 because i++ by loop
//printf("next col %d\n", i);
continue;
//printf("list field\n");
DBUField *parent_field = NULL;
- for(int c=0;c<result_types_size;c++) {
+ for(int c=0;c<result_types.size;c++) {
DBUResultType parentType = result_types.data[c];
DBUField *f = cxMapGet(parentType.cls->obj_fields, field.cls->name);
if(f && f->builder.create) {
cxListClear(fklist);
if(dense) {
- for(int i=0;i<result_types_size;i++) {
+ for(int i=0;i<result_types.size;i++) {
cxstring text = result->getText(result, result_types.data[i].pk_col);
free(result_types.data[i].prev_key.ptr);
result_types.data[i].prev_key = cx_strdup(text);
cxListFree(fklist);
- for(int i=0;i<result_types_size;i++) {
+ for(int i=0;i<result_types.size;i++) {
free(result_types.data[i].prev_key.ptr);
}
free(result_types.data);
DBUConnection *conn = dbuSQLiteConnectionFromDB(db, true);
if(!conn) {
sqlite3_close(db);
+ } else {
+ if(dbuSqlExec(conn, "PRAGMA foreign_keys = ON;")) {
+ dbuConnectionFree(conn);
+ return NULL;
+ }
}
+
return conn;
}