# HG changeset patch # User Olaf Wintermann # Date 1443784697 -7200 # Node ID c6424aebcf5ef468eb67500b7b18fae8f82bcd53 # Parent 6a3248e22d586329605e115e46ec2f4b33602f17 implemented davql order by diff -r 6a3248e22d58 -r c6424aebcf5e dav/main.c --- 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); diff -r 6a3248e22d58 -r c6424aebcf5e libidav/davqlexec.c --- 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: { diff -r 6a3248e22d58 -r c6424aebcf5e libidav/davqlexec.h --- 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); diff -r 6a3248e22d58 -r c6424aebcf5e libidav/resource.c --- 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; diff -r 6a3248e22d58 -r c6424aebcf5e libidav/resource.h --- 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 }