src/server/plugins/postgresql/webdav.c

changeset 415
d938228c382e
parent 402
712aca08da7f
child 479
2a42ba73ecdd
--- a/src/server/plugins/postgresql/webdav.c	Wed Nov 02 19:19:01 2022 +0100
+++ b/src/server/plugins/postgresql/webdav.c	Sun Nov 06 15:53:32 2022 +0100
@@ -35,8 +35,9 @@
 
 #include "../../daemon/http.h" // etag
 
-#include <ucx/buffer.h>
-#include <ucx/utils.h>
+#include <cx/buffer.h>
+#include <cx/utils.h>
+#include <cx/printf.h>
 #include <libxml/tree.h>
 
 
@@ -238,14 +239,14 @@
  * adds str to the buffer
  * some characters will be escaped: \,{}
  */
-static void buf_addstr_escaped(UcxBuffer *buf, const char *str) {
+static void buf_addstr_escaped(CxBuffer *buf, const char *str) {
     size_t len = strlen(str);
     for(size_t i=0;i<len;i++) {
         char c = str[i];
         if(c == '{' || c == '}' || c == ',' || c == '\\') {
-            ucx_buffer_putc(buf, '\\');
+            cxBufferPut(buf, '\\');
         }
-        ucx_buffer_putc(buf, c);
+        cxBufferPut(buf, c);
     }
 }
 
@@ -257,23 +258,23 @@
  * 
  * returns 0 on success, 1 otherwise
  */
-int pg_create_property_param_arrays(WebdavPList *plist, UcxBuffer *xmlns, UcxBuffer *pname) {
-    ucx_buffer_putc(xmlns, '{');
-    ucx_buffer_putc(pname, '{');
+int pg_create_property_param_arrays(WebdavPList *plist, CxBuffer *xmlns, CxBuffer *pname) {
+    cxBufferPut(xmlns, '{');
+    cxBufferPut(pname, '{');
     while(plist) {
         WebdavProperty *property = plist->property;
         if(property && property->namespace && property->namespace->href && property->name) {
             buf_addstr_escaped(xmlns, (const char*)property->namespace->href);
             buf_addstr_escaped(pname, (const char*)property->name);
             if(plist->next) {
-                ucx_buffer_putc(xmlns, ',');
-                ucx_buffer_putc(pname, ',');
+                cxBufferPut(xmlns, ',');
+                cxBufferPut(pname, ',');
             }
         }
         plist = plist->next;
     }
-    int r1 = ucx_buffer_write("}\0", 2, 1, xmlns) == 0;
-    int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0;
+    int r1 = cxBufferWrite("}\0", 2, 1, xmlns) == 0;
+    int r2 = cxBufferWrite("}\0", 2, 1, pname) == 0;
     return r1+r2 != 0;
 }
 
@@ -295,7 +296,7 @@
         WSBool iscollection,
         PgPropfindExtCol *ext,
         size_t numext,
-        UcxBuffer *sql)
+        CxBuffer *sql)
 {
     PgWebdavBackend *pgdav = rq->dav->instance;
     PgRepository *repo = pgdav->repository;
@@ -318,47 +319,47 @@
     
     // CTE
     if(depth == -1) {
-        ucx_buffer_puts(sql, sql_propfind_cte_recursive);
+        cxBufferPutString(sql, sql_propfind_cte_recursive);
     }
     
     // select
-    ucx_buffer_puts(sql, sql_propfind_select);
+    cxBufferPutString(sql, sql_propfind_select);
     
     // ppath
     switch(depth) {
-        case 0: ucx_buffer_puts(sql, sql_propfind_ppath_depth0); break;
-        case 1: ucx_buffer_puts(sql, sql_propfind_ppath_depth1); break;
-        case -1: ucx_buffer_puts(sql, sql_propfind_ppath_depth_infinity); break;
+        case 0: cxBufferPutString(sql, sql_propfind_ppath_depth0); break;
+        case 1: cxBufferPutString(sql, sql_propfind_ppath_depth1); break;
+        case -1: cxBufferPutString(sql, sql_propfind_ppath_depth_infinity); break;
     }
     
     // cols
-    ucx_buffer_puts(sql, sql_propfind_cols);
+    cxBufferPutString(sql, sql_propfind_cols);
     
     // ext_cols
     if(ext) { 
         if(rq->allprop) {
             for(int i=0;i<repo->ntables;i++) {
-                ucx_bprintf(sql, ",x%d.*\n", i);
+                cx_bprintf(sql, ",x%d.*\n", i);
             }
         } else {
             for(int i=0;i<numext;i++) {
                 PgPropfindExtCol e = ext[i];
-                ucx_bprintf(sql, ",x%d.%s\n", e.ext->tableindex, e.ext->column);
+                cx_bprintf(sql, ",x%d.%s\n", e.ext->tableindex, e.ext->column);
             }
         }
     }
     
     // from
-    ucx_buffer_puts(sql, depth == -1 ? sql_propfind_from_cte : sql_propfind_from_table);
+    cxBufferPutString(sql, depth == -1 ? sql_propfind_from_cte : sql_propfind_from_table);
     
     // prop join
-    ucx_buffer_puts(sql, rq->allprop ? sql_propfind_propjoin_allprop : sql_propfind_propjoin_plist);
+    cxBufferPutString(sql, rq->allprop ? sql_propfind_propjoin_allprop : sql_propfind_propjoin_plist);
     
     // ext_join
     if(ext) {
         if(rq->allprop) {
             for(int i=0;i<repo->ntables;i++) {
-                ucx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[i].table, i, i);
+                cx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[i].table, i, i);
             }
         } else {
             int tab = -1;
@@ -366,7 +367,7 @@
                 PgPropfindExtCol e = ext[i];
                 if(e.ext->tableindex != tab) {
                     tab = e.ext->tableindex;
-                    ucx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[tab].table, tab, tab);
+                    cx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[tab].table, tab, tab);
                 }
             }
         }
@@ -375,20 +376,20 @@
     
     // where
     if(depth == 0) {
-        ucx_buffer_puts(sql, sql_propfind_where_depth0);
+        cxBufferPutString(sql, sql_propfind_where_depth0);
     } else if(depth == 1) {
-        ucx_buffer_puts(sql, sql_propfind_where_depth1);
+        cxBufferPutString(sql, sql_propfind_where_depth1);
     }
     
     // order
     if(depth == 1) {
-        ucx_buffer_puts(sql, sql_propfind_order_depth1);
+        cxBufferPutString(sql, sql_propfind_order_depth1);
     } else if(depth == -1) {
-        ucx_buffer_puts(sql, sql_propfind_order_depth_infinity);
+        cxBufferPutString(sql, sql_propfind_order_depth_infinity);
     }
     
     // end
-    ucx_buffer_puts(sql, ";\0");
+    cxBufferWrite(";\0", 1, 2, sql);
       
     return 0;
 }
@@ -400,6 +401,7 @@
         WebdavPList **outplist)
 {
     PgWebdavBackend *pgdav = rq->dav->instance;
+    CxAllocator *a = pool_allocator(rq->sn->pool);
     
     // first, check if the resource exists
     // if it doesn't exist, we can return immediately
@@ -432,7 +434,7 @@
     // like to use it
     char resource_id_str[32];
     snprintf(resource_id_str, 32, "%" PRId64, resource_id);
-    pblock_nvinsert("resource_id",resource_id_str, rq->rq->vars);
+    pblock_nvinsert("resource_id", resource_id_str, rq->rq->vars);
     
     // create a list of requsted extended properties
     PgPropfindExtCol *ext;
@@ -442,16 +444,15 @@
         ext = NULL;
         numext = 0;
     } else {     
-        numext = pgdav->repository->prop_ext->count;
+        numext = pgdav->repository->prop_ext->size;
         ext = pool_calloc(rq->sn->pool, numext, sizeof(PgPropfindExtCol));
         
         if(rq->allprop) {
             // the map pgdav->repository->prop_ext contains all property extensions
             // we can just convert the map to an array
-            UcxMapIterator i = ucx_map_iterator(pgdav->repository->prop_ext);
-            PgPropertyStoreExt *cfg_ext;
+            CxIterator i = cxMapIteratorValues(pgdav->repository->prop_ext);
             int j = 0;
-            UCX_MAP_FOREACH(key, cfg_ext, i) {
+            cx_foreach(PgPropertyStoreExt *, cfg_ext, i) {
                 PgPropfindExtCol extcol;
                 extcol.ext = cfg_ext;
                 extcol.field_num = -1; // get the field_num after the PQexec
@@ -464,9 +465,9 @@
             while(webdav_plist_iterator_next(&i, &cur)) {
                 WSNamespace *ns = cur->property->namespace;
                 if(ns) {
-                    UcxKey pkey = webdav_property_key((const char*)ns->href, cur->property->name);
-                    PgPropertyStoreExt *cfg_ext = ucx_map_get(pgdav->repository->prop_ext, pkey);
-                    free((void*)pkey.data);
+                    CxHashKey pkey = webdav_property_key((const char*)ns->href, cur->property->name);
+                    PgPropertyStoreExt *cfg_ext = cxMapGet(pgdav->repository->prop_ext, pkey);
+                    free(pkey.data.bytes);
                     if(cfg_ext) {
                         PgPropfindExtCol extcol;
                         extcol.ext = cfg_ext;
@@ -485,11 +486,15 @@
     
     // create sql query
     const char *query = NULL;
-    UcxBuffer *sql = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND);
-    if(pg_create_propfind_query(rq, iscollection, ext, numext, sql)) {
+    CxBuffer sql;
+    if(cxBufferInit(&sql, NULL, 2048, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) {
         return 1;
     }
-    query = sql->space;
+    
+    if(pg_create_propfind_query(rq, iscollection, ext, numext, &sql)) {
+        return 1;
+    }
+    query = sql.space;
     
     // get all resources and properties
     size_t href_len = strlen(href);
@@ -501,32 +506,34 @@
     href_param[href_len] = '\0';
     
     // if allprop is false, create array pair for xmlns/property names
-    UcxBuffer *xmlns_buf = NULL;
-    UcxBuffer *pname_buf = NULL;
+    CxBuffer xmlns_buf;
+    CxBuffer pname_buf;
+    WSBool buf_initialized = FALSE;
     char *xmlns_param = NULL;
     char *pname_param = NULL;
     int nparam = 2;
     if(!rq->allprop) {
         size_t bufsize = rq->propcount < 200 ? 8 + rq->propcount * 32 : 4096;
-        xmlns_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND);
-        if(!xmlns_buf) {
+        if(cxBufferInit(&xmlns_buf, NULL, bufsize, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) {
             return 1;
         }
-        pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND);
-        if(!pname_buf) {
-            ucx_buffer_free(xmlns_buf);
+        if(cxBufferInit(&pname_buf, NULL, bufsize, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) {
+            cxBufferDestroy(&xmlns_buf);
             return 1;
         }
-        if(pg_create_property_param_arrays(*outplist, xmlns_buf, pname_buf)) {
-            ucx_buffer_free(xmlns_buf);
-            ucx_buffer_free(pname_buf);
+        if(pg_create_property_param_arrays(*outplist, &xmlns_buf, &pname_buf)) {
+            cxBufferDestroy(&xmlns_buf);
+            cxBufferDestroy(&pname_buf);
             return 1;
         }
-        xmlns_param = xmlns_buf->space;
-        pname_param = pname_buf->space;
+        buf_initialized = TRUE;
+        xmlns_param = xmlns_buf.space;
+        pname_param = pname_buf.space;
         nparam = 4;
     }
     
+    
+    
     const char* params[4] = { resource_id_str, href_param, xmlns_param, pname_param };
     PGresult *result = PQexecParams(
             pgdav->connection,
@@ -539,9 +546,9 @@
             0);    // 0: result in text format
     int nrows = PQntuples(result);
     pool_free(rq->sn->pool, href_param);
-    if(xmlns_buf) {
-        ucx_buffer_free(xmlns_buf);
-        ucx_buffer_free(pname_buf);
+    if(buf_initialized) {
+        cxBufferDestroy(&xmlns_buf);
+        cxBufferDestroy(&pname_buf);
     }
     if(nrows < 1) {
         // we resolved the path, so the resource exists and nrows should
@@ -899,9 +906,9 @@
 
 
 static PgPropertyStoreExt* pg_proppatch_prop_get_ext(PgWebdavBackend *pgdav, WebdavProperty *property) {
-    UcxKey pkey = webdav_property_key((const char*)property->namespace->href, property->name);
-    PgPropertyStoreExt *ext = ucx_map_get(pgdav->repository->prop_ext, pkey);
-    free((void*)pkey.data);
+    CxHashKey pkey = webdav_property_key((const char*)property->namespace->href, property->name);
+    PgPropertyStoreExt *ext = cxMapGet(pgdav->repository->prop_ext, pkey);
+    free(pkey.data.bytes);
     return ext;
 }
 
@@ -923,14 +930,21 @@
     ext_prop->column = ext;
     ext_prop->property = property;
 
-    UcxAllocator a = util_pool_allocator(pool);
+    CxAllocator *a = pool_allocator(pool);
     proppatch->ext[ext->tableindex].isused = TRUE;
 
-    UcxList **list = proppatch_op == PG_PROPPATCH_EXT_REMOVE
-                        ? &proppatch->ext[ext->tableindex].remove
-                        : &proppatch->ext[ext->tableindex].set;
-    *list = ucx_list_append_a(&a, *list, ext_prop);
-
+    PgProppatchExtProp **list_begin;
+    PgProppatchExtProp **list_end;
+    if(proppatch_op == PG_PROPPATCH_EXT_SET) {
+        list_begin = &proppatch->ext[ext->tableindex].set_begin;
+        list_end = &proppatch->ext[ext->tableindex].set_end;
+    } else {
+        list_begin = &proppatch->ext[ext->tableindex].remove_begin;
+        list_end = &proppatch->ext[ext->tableindex].remove_end;
+    }
+    
+    cx_linked_list_add((void**)list_begin, (void**)list_end, -1, offsetof(PgProppatchExtProp, next), ext_prop);
+    
     proppatch->extensions_used = TRUE;
     
     return 0;
@@ -1053,33 +1067,36 @@
  * 
  * Query: insert into <table> (resource_id, col1, ...) values ($1, $2 ...);
  */
-static UcxBuffer* ext_row_create_insert_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) {
+static CxBuffer* ext_row_create_insert_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) {
     pool_handle_t *pool = request->sn->pool;
     
-    UcxBuffer *sql = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
+    CxBuffer *sql = pool_malloc(pool, sizeof(CxBuffer)); 
     if(!sql) {
         return NULL;
     }
+    if(cxBufferInit(sql, NULL, 1024, pool_allocator(pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) {
+        pool_free(pool, sql);
+        return NULL;
+    }
     
-    size_t pg_nparams = ucx_list_size(ext->set) + 1;
+    size_t pg_nparams = cx_linked_list_size(ext->set_begin, offsetof(PgProppatchExtProp, next)) + 1;
     char** pg_params = pool_calloc(pool, pg_nparams, sizeof(char*));
     if(!pg_params) {
-        ucx_buffer_free(sql);
+        cxBufferDestroy(sql);
+        pool_free(pool, sql);
         return NULL;
     }
     
-    ucx_buffer_puts(sql, "insert into ");
-    ucx_buffer_puts(sql, table->table);
-    ucx_buffer_puts(sql, "(resource_id");
-    UCX_FOREACH(elm, ext->set) {
-        PgProppatchExtProp *prop = elm->data;
-        ucx_bprintf(sql, ",%s", prop->column->name);
+    cxBufferPutString(sql, "insert into ");
+    cxBufferPutString(sql, table->table);
+    cxBufferPutString(sql, "(resource_id");
+    for(PgProppatchExtProp *prop=ext->set_begin;prop;prop=prop->next) {
+        cx_bprintf(sql, ",%s", prop->column->name);
     }
     
-    ucx_buffer_puts(sql, ") values ($1\n");
+    cxBufferPutString(sql, ") values ($1\n");
     int i = 1;
-    UCX_FOREACH(elm, ext->set) {
-        PgProppatchExtProp *prop = elm->data;
+    for(PgProppatchExtProp *prop=ext->set_begin;prop;prop=prop->next) {
         WebdavProperty *property = prop->property;
         // convert the property value to WSXmlData
         // property->vtype == WS_VALUE_XML_NODE should always be true
@@ -1091,15 +1108,15 @@
             if(property_value->namespaces) {
                 // currently only text data is supported
                 pool_free(pool, params);
-                ucx_buffer_free(sql);
+                cxBufferDestroy(sql);
                 return NULL;
             }
         }
         
         pg_params[i] = value_str;
-        ucx_bprintf(sql, ",$%d", ++i);
+        cx_bprintf(sql, ",$%d", ++i);
     }
-    ucx_buffer_puts(sql, ");");
+    cxBufferPutString(sql, ");");
     
     
     //printf("\n\n%.*s\n\n", (int)sql->size, sql->space);
@@ -1122,28 +1139,32 @@
  *        ...
  *        where resource_id = $1 ;
  */
-static UcxBuffer* ext_row_create_update_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) {
+static CxBuffer* ext_row_create_update_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) {
     pool_handle_t *pool = request->sn->pool;
     
-    UcxBuffer *sql = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
+    CxBuffer *sql = pool_malloc(pool, sizeof(CxBuffer)); 
     if(!sql) {
         return NULL;
     }
+    if(cxBufferInit(sql, NULL, 1024, pool_allocator(pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) {
+        pool_free(pool, sql);
+        return NULL;
+    }
     
-    ucx_buffer_puts(sql, "update ");
-    ucx_buffer_puts(sql, table->table);
-    ucx_buffer_puts(sql, " set\n");
+    cxBufferPutString(sql, "update ");
+    cxBufferPutString(sql, table->table);
+    cxBufferPutString(sql, " set\n");
     
-    size_t pg_nparams = ucx_list_size(ext->set) + 1;
+    size_t pg_nparams = cx_linked_list_size(ext->set_begin, offsetof(PgProppatchExtProp, next)) + 1;
     char** pg_params = pool_calloc(pool, pg_nparams, sizeof(char*));
     if(!pg_params) {
-        ucx_buffer_free(sql);
+        cxBufferDestroy(sql);
+        pool_free(pool, sql);
         return NULL;
     }
     
     int i = 1;
-    UCX_FOREACH(elm, ext->set) {
-        PgProppatchExtProp *prop = elm->data;
+    for(PgProppatchExtProp *prop=ext->set_begin;prop;prop=prop->next)  {
         WebdavProperty *property = prop->property;
         // convert the property value to WSXmlData
         // property->vtype == WS_VALUE_XML_NODE should always be true
@@ -1155,23 +1176,22 @@
             if(property_value->namespaces) {
                 // currently only text data is supported
                 pool_free(pool, params);
-                ucx_buffer_free(sql);
+                cxBufferDestroy(sql);
                 return NULL;
             }
         }
         
         pg_params[i] = value_str;
-        ucx_bprintf(sql, " %s = $%d,\n", prop->column->name, ++i);
+        cx_bprintf(sql, " %s = $%d,\n", prop->column->name, ++i);
     }
     
-    UCX_FOREACH(elm, ext->remove) {
-        PgProppatchExtProp *prop = elm->data;
-        ucx_bprintf(sql, " %s = NULL,\n", prop->column->name);
+    for(PgProppatchExtProp *prop=ext->remove_begin;prop;prop=prop->next)  {
+        cx_bprintf(sql, " %s = NULL,\n", prop->column->name);
     }
     
     // check if any write worked
     if(sql->pos == 0) {
-        ucx_buffer_free(sql);
+        cxBufferDestroy(sql);
         pool_free(pool, pg_params);
         return NULL;
     }
@@ -1182,7 +1202,8 @@
         sql->space[sql->pos-2] = ' ';
     }
     
-    ucx_bprintf(sql, "where resource_id =  $1 ;\0");
+    cxBufferPutString(sql, "where resource_id =  $1 ;");
+    cxBufferPut(sql, '\0');
     
     //printf("\n\n%.*s\n\n", (int)sql->size, sql->space);
     //fflush(stdout);
@@ -1203,7 +1224,7 @@
     
     char **params;
     size_t nparam;
-    UcxBuffer *sql = ext_row_create_insert_query(request, ext, table, &params, &nparam);
+    CxBuffer *sql = ext_row_create_insert_query(request, ext, table, &params, &nparam);
     if(!sql) {
         return 1;
     }
@@ -1222,7 +1243,7 @@
             NULL,
             0);    // 0: result in text format
     
-    ucx_buffer_free(sql);
+    cxBufferDestroy(sql);
     
     int ret = 1;
     if(PQresultStatus(result) == PGRES_COMMAND_OK) {
@@ -1252,7 +1273,7 @@
     
     char **params;
     size_t nparam;
-    UcxBuffer *sql = ext_row_create_update_query(request, ext, table, &params, &nparam);
+    CxBuffer *sql = ext_row_create_update_query(request, ext, table, &params, &nparam);
     if(!sql) {
         return 1;
     }
@@ -1271,7 +1292,7 @@
             NULL,
             0);    // 0: result in text format
     
-    ucx_buffer_free(sql);
+    cxBufferDestroy(sql);
     
     int ret = 1;
     if(PQresultStatus(result) == PGRES_COMMAND_OK) {

mercurial