implemented davql order by

Fri, 02 Oct 2015 13:18:17 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 02 Oct 2015 13:18:17 +0200
changeset 139
c6424aebcf5e
parent 138
6a3248e22d58
child 140
0a06bed068a1

implemented davql order by

dav/main.c file | annotate | diff | comparison | revisions
libidav/davqlexec.c file | annotate | diff | comparison | revisions
libidav/davqlexec.h file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/resource.h file | annotate | diff | comparison | revisions
--- a/dav/main.c	Thu Jul 09 17:22:55 2015 +0200
+++ b/dav/main.c	Fri Oct 02 13:18:17 2015 +0200
@@ -375,7 +375,7 @@
     while(ret != 0) {
         ls = dav_query(
                 sn,
-                "select `idav:crypto-name`,`idav:crypto-key` from %s with depth = %d where lastmodified > %t",
+                "select `idav:crypto-name`,`idav:crypto-key` from %s with depth = %d where lastmodified > %t order by iscollection desc, name",
                 path,
                 depth,
                 t);
--- a/libidav/davqlexec.c	Thu Jul 09 17:22:55 2015 +0200
+++ b/libidav/davqlexec.c	Fri Oct 02 13:18:17 2015 +0200
@@ -370,6 +370,58 @@
         return result;
     }
     
+    // compile order criterion
+    UcxList *ordercr = NULL;
+    UCX_FOREACH(elm, st->orderby) {
+        DavQLOrderCriterion *oc = elm->data;
+        DavQLExpression *column = oc->column;
+        //printf("%.*s %s\n", column->srctext.length, column->srctext.ptr, oc->descending ? "desc" : "asc");
+        if(column->type == DAVQL_IDENTIFIER) {
+            // TODO: remove code duplication (add_cmd)
+            davqlresprop_t resprop;
+            sstr_t propertyname = sstrchr(column->srctext, ':');
+            if(propertyname.length > 0) {
+                char *ns;
+                char *name;
+                dav_get_property_namespace_str(
+                        sn->context,
+                        sstrdup_a(mp->allocator, column->srctext).ptr,
+                        &ns,
+                        &name);
+                if(ns && name) {
+                    DavOrderCriterion *cr = ucx_mempool_malloc(mp, sizeof(DavOrderCriterion));
+                    cr->type = 1;
+                    cr->column.property = dav_property_key_a(mp->allocator, ns, name);
+                    cr->descending = oc->descending;
+                    ordercr = ucx_list_append_a(mp->allocator, ordercr, cr);
+                } else {
+                    // error
+                    // TODO: cleanup
+                    return result;
+                }
+            } else if(dav_identifier2resprop(column->srctext, &resprop)) {
+                DavOrderCriterion *cr = ucx_mempool_malloc(mp, sizeof(DavOrderCriterion));
+                cr->type = 0;
+                cr->column.resprop = resprop;
+                cr->descending = oc->descending;
+                ordercr = ucx_list_append_a(mp->allocator, ordercr, cr);
+            } else {
+                // error
+                // TODO: cleanup
+                return result;
+            }
+            
+        } else if(column->type == DAVQL_NUMBER) {
+            // TODO: implement
+            fprintf(stderr, "order by number not supported\n");
+            return result;
+        } else {
+            // something is broken
+            // TODO: cleanup
+            return result;
+        }
+    }
+    
     DavResource *selroot = dav_resource_new(sn, path.ptr);
     
     UcxList *stack = NULL; // stack with DavResource* elements
@@ -453,7 +505,8 @@
                     if(!dav_exec_expr(where, child, &where_result)) {
                         if(where_result.data.integer != 0) {
                             if(!reset_properties(sn, &result, child, cfieldlist)) {
-                                resource_add_child(root, child);
+                                //resource_add_child(root, child);
+                                resource_add_ordered_child(root, child, ordercr);
                                 if(child->iscollection &&
                                     (depth < 0 || depth > sr->depth+1))
                                 {
@@ -504,6 +557,29 @@
     return count;
 }
 
+int dav_identifier2resprop(sstr_t src, davqlresprop_t *prop) {
+    if(!sstrcmp(src, S("name"))) {
+        *prop = DAVQL_RES_NAME;
+    } else if(!sstrcmp(src, S("path"))) {
+        *prop = DAVQL_RES_PATH;
+    } else if(!sstrcmp(src, S("href"))) {
+        *prop = DAVQL_RES_HREF;
+    } else if(!sstrcmp(src, S("contentlength"))) {
+        *prop = DAVQL_RES_CONTENTLENGTH;
+    } else if(!sstrcmp(src, S("contenttype"))) {
+        *prop = DAVQL_RES_CONTENTTYPE;
+    } else if(!sstrcmp(src, S("creationdate"))) {
+        *prop = DAVQL_RES_CREATIONDATE;
+    } else if(!sstrcmp(src, S("lastmodified"))) {
+        *prop = DAVQL_RES_LASTMODIFIED;
+    } else if(!sstrcmp(src, S("iscollection"))) {
+        *prop = DAVQL_RES_ISCOLLECTION;
+    } else {
+        return 0;
+    }
+    return 1;
+}
+
 static int add_cmd(DavContext *ctx, UcxAllocator *a, UcxBuffer *bcode, DavQLExpression *expr, va_list ap) {
     if(!expr) {
         return 0;
@@ -565,31 +641,17 @@
                     // error
                     return -1;
                 }
-            } else if(!sstrcmp(src, S("name"))) {
-                cmd.data.resprop = DAVQL_RES_NAME;
-            } else if(!sstrcmp(src, S("path"))) {
-                cmd.data.resprop = DAVQL_RES_PATH;
-            } else if(!sstrcmp(src, S("href"))) {
-                cmd.data.resprop = DAVQL_RES_HREF;
-            } else if(!sstrcmp(src, S("contentlength"))) {
-                cmd.data.resprop = DAVQL_RES_CONTENTLENGTH;
-            } else if(!sstrcmp(src, S("contenttype"))) {
-                cmd.data.resprop = DAVQL_RES_CONTENTTYPE;
-            } else if(!sstrcmp(src, S("creationdate"))) {
-                cmd.data.resprop = DAVQL_RES_CREATIONDATE;
-            } else if(!sstrcmp(src, S("lastmodified"))) {
-                cmd.data.resprop = DAVQL_RES_LASTMODIFIED;
-            } else if(!sstrcmp(src, S("iscollection"))) {
-                cmd.data.resprop = DAVQL_RES_ISCOLLECTION;
-            } else if(!sstrcmp(src, S("true"))) {
-                cmd.type = DAVQL_CMD_INT;
-                cmd.data.integer = 1;
-            } else if(!sstrcmp(src, S("false"))) {
-                cmd.type = DAVQL_CMD_INT;
-                cmd.data.integer = 0;
-            } else {
-                // error, unknown identifier
-                return -1;
+            } else if(!dav_identifier2resprop(src, &cmd.data.resprop)) {
+                if(!sstrcmp(src, S("true"))) {
+                    cmd.type = DAVQL_CMD_INT;
+                    cmd.data.integer = 1;
+                } else if(!sstrcmp(src, S("false"))) {
+                    cmd.type = DAVQL_CMD_INT;
+                    cmd.data.integer = 0;
+                } else {
+                    // error, unknown identifier
+                    return -1;
+                }
             }
             ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode);
             break;
@@ -847,7 +909,7 @@
                 break;
             }
             case DAVQL_CMD_RES_IDENTIFIER: {
-                char *rid[8] = {"name", "path", "href", "contentlength", "contenttype", "creationdate", "lastmodified", "iscollection"};
+                //char *rid[8] = {"name", "path", "href", "contentlength", "contenttype", "creationdate", "lastmodified", "iscollection"};
                 //printf("resprop %s\n", rid[cmd.data.resprop]);
                 switch(cmd.data.resprop) {
                     case DAVQL_RES_NAME: {
--- a/libidav/davqlexec.h	Thu Jul 09 17:22:55 2015 +0200
+++ b/libidav/davqlexec.h	Fri Oct 02 13:18:17 2015 +0200
@@ -56,7 +56,7 @@
     DAVQL_CMD_TIMESTAMP,
     DAVQL_CMD_RES_IDENTIFIER,
     DAVQL_CMD_PROP_IDENTIFIER,
-    DAVQL_CMD_OP_UNARY_ADD,
+    //DAVQL_CMD_OP_UNARY_ADD,
     DAVQL_CMD_OP_UNARY_SUB,
     DAVQL_CMD_OP_UNARY_NEG,
     DAVQL_CMD_OP_BINARY_ADD,
@@ -124,6 +124,15 @@
     char *name;
     UcxBuffer *code;
 } DavCompiledField;
+
+typedef struct DavOrderCriterion {
+    int type; // 0: resprop, 1: property
+    union DavQLColumn {
+        davqlresprop_t resprop;
+        UcxKey property;
+    } column;
+    _Bool descending;
+} DavOrderCriterion;
     
 DavResult dav_statement_exec(DavSession *sn, DavQLStatement *st, ...);
 DavResult dav_statement_execv(DavSession *sn, DavQLStatement *st, va_list ap);
@@ -133,6 +142,8 @@
 
 DavResult dav_exec_select(DavSession *sn, DavQLStatement *st, va_list ap);
 
+int dav_identifier2resprop(sstr_t src, davqlresprop_t *prop);
+
 UcxBuffer* dav_compile_expr(DavContext *ctx, UcxAllocator *a, DavQLExpression *lexpr, va_list ap);
 
 int dav_exec_expr(UcxBuffer *bcode, DavResource *res, DavQLStackObj *result);
--- a/libidav/resource.c	Thu Jul 09 17:22:55 2015 +0200
+++ b/libidav/resource.c	Fri Oct 02 13:18:17 2015 +0200
@@ -39,6 +39,7 @@
 #include "ucx/utils.h"
 
 #include "resource.h"
+#include "davqlexec.h"
 
 #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
 
@@ -236,18 +237,26 @@
 
 char* resource_get_property(DavResource *res, char *ns, char *name) {
     UcxKey key = dav_property_key(ns, name);
-    DavResourceData *data = (DavResourceData*)res->data;
-    char *property = ucx_map_get(data->properties, key);
+    char *property = resource_get_property_k(res, key);
     free(key.data);
     return property;
 }
 
+char* resource_get_property_k(DavResource *res, UcxKey key) {
+    DavResourceData *data = (DavResourceData*)res->data;
+    return ucx_map_get(data->properties, key);
+}
+
 UcxKey dav_property_key(char *ns, char *name) {
+    return dav_property_key_a(ucx_default_allocator(), ns, name);
+}
+
+UcxKey dav_property_key_a(UcxAllocator *a, char *ns, char *name) {
     sstr_t ns_str = sstr(ns);
     sstr_t name_str = sstr(name);
     
     sstr_t key;
-    key = sstrcat(4, ns_str, S("\0"), name_str, S("\0"));
+    key = sstrcat_a(a, 4, ns_str, S("\0"), name_str, S("\0"));
     
     return ucx_key(key.ptr, key.length);
 }
@@ -271,6 +280,111 @@
     child->parent = parent;
 }
 
+static int resource_cmp(DavResource *res1, DavResource *res2, DavOrderCriterion *cr) {
+    if(!(res1 && res2)) {
+        return 0;
+    }
+    
+    int ret;
+    if(cr->type == 0) {
+        switch(cr->column.resprop) {
+            case DAVQL_RES_NAME: {
+                ret = strcmp(res1->name, res2->name);
+                break;
+            }
+            case DAVQL_RES_PATH: {
+                ret = strcmp(res1->path, res2->path);
+                break;
+            }
+            case DAVQL_RES_HREF: {
+                ret = strcmp(res1->href, res2->href);
+                break;
+            }
+            case DAVQL_RES_CONTENTLENGTH: {
+                int c = res1->contentlength == res2->contentlength;
+                ret = c ? 0 : (res1->contentlength < res2->contentlength?-1:1);
+                break;
+            }
+            case DAVQL_RES_CONTENTTYPE: {
+                ret = strcmp(res1->contenttype, res2->contenttype);
+                break;
+            }
+            case DAVQL_RES_CREATIONDATE: {
+                int c = res1->creationdate == res2->creationdate;
+                ret = c ? 0 : (res1->creationdate < res2->creationdate?-1:1);
+                break;
+            }
+            case DAVQL_RES_LASTMODIFIED: {
+                int c = res1->lastmodified == res2->lastmodified;
+                ret = c ? 0 : (res1->lastmodified < res2->lastmodified?-1:1);
+                break;
+            }
+            case DAVQL_RES_ISCOLLECTION: {
+                int c = res1->iscollection == res2->iscollection;
+                ret = c ? 0 : (res1->iscollection < res2->iscollection?-1:1);
+                break;
+            }
+            default: ret = 0;
+        }
+    } else if(cr->type == 1) {
+        char *value1 = resource_get_property_k(res1, cr->column.property);
+        char *value2 = resource_get_property_k(res2, cr->column.property);
+        if(!value1) {
+            ret = value2 ? -1 : 0;
+        } else if(!value2) {
+            ret = value1 ? 1 : 0;
+        } else {
+            ret = strcmp(value1, value2);
+        }
+    } else {
+        return 0;
+    }
+    
+    return cr->descending ? -ret : ret;
+}
+
+void resource_add_ordered_child(DavResource *parent, DavResource *child, UcxList *ordercr) {
+    if(!ordercr) {
+        resource_add_child(parent, child);
+        return;
+    }
+    
+    child->parent = parent;
+    
+    if(!parent->children) {
+        child->next = NULL;
+        child->prev = NULL;
+        parent->children = child;
+    } else {
+        DavResource *resource = parent->children;
+        while(resource) {
+            int r = 0;
+            UCX_FOREACH(elm, ordercr) {
+                DavOrderCriterion *cr = elm->data;
+                r = resource_cmp(child, resource, cr);
+                if(r != 0) {
+                    break;
+                }
+            }
+            
+            if(r < 0 || !resource->next) {
+                // insert child before resource
+                child->prev = resource->prev;
+                child->next = resource;
+                if(resource->prev) {
+                    resource->prev->next = child;
+                } else {
+                    parent->children = child;
+                }
+                resource->prev = child;
+                break;
+            } else {
+                resource = resource->next;
+            }
+        }
+    }
+}
+
 char* dav_get_property(DavResource *res, char *name) {
     char *pns;
     char *pname;
--- a/libidav/resource.h	Thu Jul 09 17:22:55 2015 +0200
+++ b/libidav/resource.h	Fri Oct 02 13:18:17 2015 +0200
@@ -67,9 +67,12 @@
 DavResourceData* resource_data_new(DavSession *sn);
 void resource_add_property(DavResource *res, char *ns, char *name, char *val);
 char* resource_get_property(DavResource *res, char *ns, char *name);
+char* resource_get_property_k(DavResource *res, UcxKey key);
 void resource_add_child(DavResource *parent, DavResource *child);
+void resource_add_ordered_child(DavResource *parent, DavResource *child, UcxList *ordercr);
+int resource_add_crypto_info(DavSession *sn, char *href, char *name);
 
-int resource_add_crypto_info(DavSession *sn, char *href, char *name);
+UcxKey dav_property_key_a(UcxAllocator *a, char *ns, char *name);
 
 #ifdef	__cplusplus
 }

mercurial