diff -r 8c37028f5024 -r 4bccc18820e8 libidav/davqlexec.c --- a/libidav/davqlexec.c Sat Jun 06 10:46:29 2015 +0200 +++ b/libidav/davqlexec.c Tue Jul 07 20:47:02 2015 +0200 @@ -31,10 +31,12 @@ #include #include +#include #include "davqlexec.h" #include "utils.h" #include "methods.h" #include "session.h" +#include "resource.h" DavResult* dav_statement_exec(DavSession *sn, DavQLStatement *st, ...) { va_list ap; @@ -128,22 +130,228 @@ return sstrdup_a(a, sstrn(buf->space, buf->size)); } +static int fl_add_properties(DavSession *sn, UcxMempool *mp, UcxMap *map, DavQLExpression *expression) { + if(!expression) { + return 0; + } + + if(expression->type == DAVQL_IDENTIFIER) { + DavProperty *property = ucx_mempool_malloc(mp, sizeof(DavProperty)); + + char *name; + DavNamespace *ns = dav_get_property_namespace( + sn->context, + sstrdup_a(mp->allocator, expression->srctext).ptr, + &name); + if(!ns) { + return -1; + } + + property->ns = ns; + property->name = name; + property->value = NULL; + + ucx_map_sstr_put(map, expression->srctext, property); + } + + if(expression->left) { + if(fl_add_properties(sn, mp, map, expression->left)) { + return -1; + } + } + if(expression->right) { + if(fl_add_properties(sn, mp, map, expression->right)) { + return -1; + } + } + + return 0; +} + +static UcxBuffer* fieldlist2propfindrequest(DavSession *sn, UcxMempool *mp, UcxList *fields, int *isallprop) { + UcxMap *properties = ucx_map_new(32); + *isallprop = 0; + + UCX_FOREACH(elm, fields) { + DavQLField *field = elm->data; + if(!sstrcmp(field->name, S("*"))) { + ucx_map_free(properties); + *isallprop = 1; + return create_allprop_propfind_request(); + } else if(!sstrcmp(field->name, S("-"))) { + ucx_map_free(properties); + return create_basic_propfind_request(); + } else { + if(fl_add_properties(sn, mp, properties, field->expr)) { + // TODO: set error + return NULL; + } + } + } + + UcxMapIterator i = ucx_map_iterator(properties); + UcxKey key; + DavProperty *value; + UcxList *list = NULL; + UCX_MAP_FOREACH(key, value, i) { + list = ucx_list_append(list, value); + } + + UcxBuffer *reqbuf = create_propfind_request(sn, list); + ucx_list_free(list); + return reqbuf; +} + +static int reset_properties(DavSession *sn, DavResult *result, DavResource *res, UcxList *fields) { + UcxMap *new_properties = ucx_map_new_a(sn->mp->allocator, 32); + DavResourceData *data = (DavResourceData*)res->data; + + // add basic properties + char *value; + + UcxKey cl_key = dav_property_key("DAV:", "getcontentlength"); + value = ucx_map_get(data->properties, cl_key); + if(value) { + ucx_map_put(new_properties, cl_key, value); + } + + UcxKey cd_key = dav_property_key("DAV:", "creationdate"); + value = ucx_map_get(data->properties, cd_key); + if(value) { + ucx_map_put(new_properties, cd_key, value); + } + + UcxKey lm_key = dav_property_key("DAV:", "getlastmodified"); + value = ucx_map_get(data->properties, lm_key); + if(value) { + ucx_map_put(new_properties, lm_key, value); + } + + UcxKey ct_key = dav_property_key("DAV:", "getcontenttype"); + value = ucx_map_get(data->properties, ct_key); + if(value) { + ucx_map_put(new_properties, ct_key, value); + } + + UcxKey rt_key = dav_property_key("DAV:", "resourcetype"); + value = ucx_map_get(data->properties, rt_key); + if(value) { + ucx_map_put(new_properties, rt_key, value); + } + + UcxKey cn_key = dav_property_key("DAV:", "crypto-name"); + value = ucx_map_get(data->properties, cn_key); + if(value) { + ucx_map_put(new_properties, cn_key, value); + } + + UcxKey ck_key = dav_property_key("DAV:", "crypto-key"); + value = ucx_map_get(data->properties, ck_key); + if(value) { + ucx_map_put(new_properties, ck_key, value); + } + + // add properties from field list + UCX_FOREACH(elm, fields) { + DavCompiledField *field = elm->data; + DavQLStackObj field_result; + if(!dav_exec_expr(field->code, res, &field_result)) { + sstr_t str; + if(field_result.type == 0) { + str = ucx_asprintf( + sn->mp->allocator, + "%d", + field_result.data.integer); + } else { + str = sstrdup_a(sn->mp->allocator, sstrn( + field_result.data.string, + field_result.length)); + } + if(str.ptr) { + UcxKey key = dav_property_key(field->ns, field->name); + ucx_map_put(new_properties, key, str.ptr); + } + } else { + // TODO: error + resource_free_properties(sn, new_properties); + return -1; + } + } + + ucx_map_remove(data->properties, cl_key); + ucx_map_remove(data->properties, cd_key); + ucx_map_remove(data->properties, lm_key); + ucx_map_remove(data->properties, ct_key); + ucx_map_remove(data->properties, rt_key); + ucx_map_remove(data->properties, cn_key); + ucx_map_remove(data->properties, ck_key); + + resource_free_properties(sn, data->properties); + data->properties = new_properties; + + return 0; +} + /* * execute a davql select statement */ DavResult dav_exec_select(DavSession *sn, DavQLStatement *st, char* path, va_list ap) { UcxMempool *mp = ucx_mempool_new(128); + DavResult result; + result.result = NULL; + result.status = 1; - // TODO: get property list - UcxBuffer *rqbuf = create_allprop_propfind_request(); + int isallprop; + UcxBuffer *rqbuf = fieldlist2propfindrequest(sn, mp, st->fields, &isallprop); + if(!rqbuf) { + ucx_mempool_destroy(mp); + return result; + } + + // compile field list + UcxList *cfieldlist = NULL; + UCX_FOREACH(elm, st->fields) { + DavQLField *field = elm->data; + if(sstrcmp(field->name, S("*")) && sstrcmp(field->name, S("-"))) { + // compile field expression + UcxBuffer *code = dav_compile_expr( + sn->context, + mp->allocator, + field->expr, + ap); + if(!code) { + // TODO: set error string + return result; + } + DavCompiledField *cfield = ucx_mempool_malloc( + mp, + sizeof(DavCompiledField)); + + char *ns; + char *name; + dav_get_property_namespace_str( + sn->context, + sstrdup_a(mp->allocator, field->name).ptr, + &ns, + &name); + if(!ns || !name) { + // TODO: set error string + return result; + } + cfield->ns = ns; + cfield->name = name; + cfield->code = code; + cfieldlist = ucx_list_append_a(mp->allocator, cfieldlist, cfield); + } + } UcxBuffer *where = dav_compile_expr(sn->context, mp->allocator, st->where, ap); + if(!where) { + ucx_mempool_destroy(mp); + return result; + } DavResource *selroot = dav_resource_new(sn, path); - DavResult result; - result.result = selroot; - result.status = 0; - UcxList *stack = NULL; // stack with DavResource* elements // initialize the stack with the requested resource @@ -181,7 +389,7 @@ } // the propfind multistatus response contains responses - // for the requsted resource and all childs + // for the requested resource and all childs // determine if the response is a child or not if(hrefeq(sn, root->href, response.href)) { // response is the currently requested resource @@ -199,7 +407,10 @@ DavQLStackObj where_result; if(!dav_exec_expr(where, root, &where_result)) { if(where_result.data.integer != 0) { - continue; + if(!reset_properties(sn, &result, root, cfieldlist)) { + continue; + } + result.status = -1; } } else { result.status = -1; @@ -217,16 +428,20 @@ DavQLStackObj where_result; if(!dav_exec_expr(where, child, &where_result)) { if(where_result.data.integer != 0) { - resource_add_child(root, child); - if(child->iscollection && - (st->depth < 0 || st->depth > sr->depth+1)) - { - DavQLRes *rs = ucx_mempool_malloc( - mp, - sizeof(DavQLRes)); - rs->resource = child; - rs->depth = sr->depth + 1; - stack = ucx_list_prepend(stack, rs); + if(!reset_properties(sn, &result, child, cfieldlist)) { + resource_add_child(root, child); + if(child->iscollection && + (st->depth < 0 || st->depth > sr->depth+1)) + { + DavQLRes *rs = ucx_mempool_malloc( + mp, + sizeof(DavQLRes)); + rs->resource = child; + rs->depth = sr->depth + 1; + stack = ucx_list_prepend(stack, rs); + } + } else { + dav_resource_free(child); } } else { dav_resource_free(child); @@ -249,6 +464,7 @@ ucx_mempool_destroy(mp); result.result = selroot; + result.status = 0; return result; } @@ -314,7 +530,7 @@ cmd.type = DAVQL_CMD_PROP_IDENTIFIER; char *ns; char *name; - dav_get_property_namespace( + dav_get_property_namespace_str( ctx, sstrdup_a(a, src).ptr, &ns, @@ -788,18 +1004,38 @@ } case DAVQL_CMD_OP_LOGICAL_AND: { printf("land\n"); + DavQLStackObj obj2 = DAVQL_POP(); + DavQLStackObj obj1 = DAVQL_POP(); + int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0); + int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0); + DAVQL_PUSH_INT(v1 && v2); break; } case DAVQL_CMD_OP_LOGICAL_OR_L: { printf("or_l %d\n", cmd.data.integer); + DavQLStackObj obj1 = DAVQL_POP(); + if((obj1.type == 0 && obj1.data.integer) || (obj1.type == 1 && obj1.data.string)) { + DAVQL_PUSH_INT(1); + i += cmd.data.integer; // jump, skip right subtree of 'or' + } break; } case DAVQL_CMD_OP_LOGICAL_OR: { printf("or\n"); + DavQLStackObj obj2 = DAVQL_POP(); + DavQLStackObj obj1 = DAVQL_POP(); + int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0); + int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0); + DAVQL_PUSH_INT(v1 || v2); break; } case DAVQL_CMD_OP_LOGICAL_XOR: { printf("lxor\n"); + DavQLStackObj obj2 = DAVQL_POP(); + DavQLStackObj obj1 = DAVQL_POP(); + int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0); + int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0); + DAVQL_PUSH_INT(!v1 != !v2); break; } case DAVQL_CMD_OP_EQ: { @@ -892,132 +1128,3 @@ return ret; } - - -void print_bytecode(UcxBuffer *bcode) { - bcode->pos = 0; - DavQLCmd cmd; - while(ucx_buffer_read(&cmd, sizeof(DavQLCmd), 1, bcode) == 1) { - switch(cmd.type) { - case DAVQL_CMD_INT: { - printf("int %lld\n", cmd.data.integer); - break; - } - case DAVQL_CMD_STRING: { - printf("string \"%.*s\"\n", cmd.data.string.length, cmd.data.string.ptr); - break; - } - case DAVQL_CMD_TIMESTAMP: { - printf("timestamp %d\n", cmd.data.timestamp); - break; - } - case DAVQL_CMD_RES_IDENTIFIER: { - char *rid[8] = {"name", "path", "href", "contentlength", "contenttype", "creationdate", "lastmodified", "iscollection"}; - printf("resprop %s\n", rid[cmd.data.resprop]); - break; - } - case DAVQL_CMD_PROP_IDENTIFIER: { - printf("property %s:%s\n", cmd.data.property.ns, cmd.data.property.name); - break; - } - case DAVQL_CMD_OP_UNARY_ADD: { - printf("uadd\n"); - break; - } - case DAVQL_CMD_OP_UNARY_SUB: { - printf("usub\n"); - break; - } - case DAVQL_CMD_OP_UNARY_NEG: { - printf("uneg\n"); - break; - } - case DAVQL_CMD_OP_BINARY_ADD: { - printf("add\n"); - break; - } - case DAVQL_CMD_OP_BINARY_SUB: { - printf("sub\n"); - break; - } - case DAVQL_CMD_OP_BINARY_MUL: { - printf("mul\n"); - break; - } - case DAVQL_CMD_OP_BINARY_DIV: { - printf("div\n"); - break; - } - case DAVQL_CMD_OP_BINARY_AND: { - printf("and\n"); - break; - } - case DAVQL_CMD_OP_BINARY_OR: { - printf("or\n"); - break; - } - case DAVQL_CMD_OP_BINARY_XOR: { - printf("xor\n"); - break; - } - case DAVQL_CMD_OP_LOGICAL_NOT: { - printf("not\n"); - break; - } - case DAVQL_CMD_OP_LOGICAL_AND: { - printf("land\n"); - break; - } - case DAVQL_CMD_OP_LOGICAL_OR_L: { - printf("or_l %d\n", cmd.data.integer); - break; - } - case DAVQL_CMD_OP_LOGICAL_OR: { - printf("or\n"); - break; - } - case DAVQL_CMD_OP_LOGICAL_XOR: { - printf("lxor\n"); - break; - } - case DAVQL_CMD_OP_EQ: { - printf("eq\n"); - break; - } - case DAVQL_CMD_OP_NEQ: { - printf("neq\n"); - break; - } - case DAVQL_CMD_OP_LT: { - printf("lt\n"); - break; - } - case DAVQL_CMD_OP_GT: { - printf("gt\n"); - break; - } - case DAVQL_CMD_OP_LE: { - printf("le\n"); - break; - } - case DAVQL_CMD_OP_GE: { - printf("ge\n"); - break; - } - case DAVQL_CMD_OP_LIKE: { - printf("like\n"); - break; - } - case DAVQL_CMD_OP_UNLIKE: { - printf("unlike\n"); - break; - } - case DAVQL_CMD_CALL: { - printf("call %x\n", cmd.data.func); - break; - } - } - } - printf("\n"); -} -