src/server/plugins/postgresql/webdav.c

branch
webdav
changeset 315
b608b7aa43a6
parent 314
6b1a6066ee43
child 317
09676b559091
--- a/src/server/plugins/postgresql/webdav.c	Mon Apr 25 22:38:05 2022 +0200
+++ b/src/server/plugins/postgresql/webdav.c	Tue Apr 26 14:33:58 2022 +0200
@@ -31,6 +31,7 @@
 
 #include "../../util/util.h"
 
+#include <ucx/buffer.h>
 #include <libxml/tree.h>
 
 static WebdavBackend pg_webdav_backend = {
@@ -88,9 +89,11 @@
     p.pname,\n\
     p.pvalue\n\
 from Resource r\n\
-left join Property p on r.resource_id = p.resource_id\n\
-inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
-   on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
+left join (\n\
+    select p.* from Property p\
+    inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
+       on p.xmlns = n.xmlns and p.pname = n.pname\n\
+) p on r.resource_id = p.resource_id\n\
 where r.resource_id = $1;";
 
 // propfind with depth = 1
@@ -113,7 +116,7 @@
 from Resource r\n\
 left join Property p on r.resource_id = p.resource_id\n\
 where r.resource_id = $1 or r.parent_id = $1\n\
-order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;";
+order by case when r.resource_id = $1 then 0 else 1 end, nodename, resource_id;";
 
 
 // propfind with depth = 1 for specific properties
@@ -134,11 +137,13 @@
     p.pname,\n\
     p.pvalue\n\
 from Resource r\n\
-left join Property p on r.resource_id = p.resource_id\n\
-inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
-   on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
+left join (\n\
+    select p.* from Property p\
+    inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
+       on p.xmlns = n.xmlns and p.pname = n.pname\n\
+) p on r.resource_id = p.resource_id\n\
 where r.resource_id = $1 or r.parent_id = $1\n\
-order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;";
+order by case when r.resource_id = $1 then 0 else 1 end, nodename, resource_id;";
 
 // recursive propfind
 // params: $1: resource_id
@@ -194,7 +199,7 @@
     )\n\
 select\n\
     case when r.resource_id = $1 then $2\n\
-         else $2 || '/' || r.ppath\n\
+         else $2 || r.ppath\n\
     end as ppath,\n\
     r.resource_id,\n\
     r.parent_id,\n\
@@ -207,9 +212,11 @@
     p.pname,\n\
     p.pvalue\n\
 from resolvepath r\n\
-left join Property p on r.resource_id = p.resource_id\n\
-inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\
-   on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\
+left join (\n\
+    select p.* from Property p\
+    inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\
+       on p.xmlns = n.xmlns and p.pname = n.pname\n\
+) p on r.resource_id = p.resource_id\n\
 order by replace(ppath, '/', chr(1)), resource_id;";
 
 WebdavBackend* pg_webdav_create(Session *sn, Request *rq, pblock *pb) {
@@ -254,6 +261,49 @@
     return NULL;
 }
 
+/*
+ * adds str to the buffer
+ * some characters will be escaped: \,{}
+ */
+static void buf_addstr_escaped(UcxBuffer *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, '\\');
+        }
+        ucx_buffer_putc(buf, c);
+    }
+}
+
+/*
+ * convert a property list to two pg array parameter strings
+ * array format: {elm1,elm2,elm3}
+ * xmlns: buffer for the xmlns array
+ * pname: buffer for the property name array
+ * 
+ * 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, '{');
+    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, ',');
+            }
+        }
+        plist = plist->next;
+    }
+    int r1 = ucx_buffer_write("}\0", 2, 1, xmlns) == 0;
+    int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0;
+    return r1+r2 != 0;
+}
+
 
 int pg_dav_propfind_init(
         WebdavPropfindRequest *rq,
@@ -312,12 +362,38 @@
     }
     href_param[href_len] = '\0';
     
+    // if allprop is false, create array pair for xmlns/property names
+    UcxBuffer *xmlns_buf = NULL;
+    UcxBuffer *pname_buf = NULL;
+    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) {
+            return 1;
+        }
+        pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND);
+        if(!pname_buf) {
+            ucx_buffer_free(xmlns_buf);
+            return 1;
+        }
+        if(pg_create_property_param_arrays(rq->properties, xmlns_buf, pname_buf)) {
+            ucx_buffer_free(xmlns_buf);
+            ucx_buffer_free(pname_buf);
+            return 1;
+        }
+        xmlns_param = xmlns_buf->space;
+        pname_param = pname_buf->space;
+        nparam = 4;
+    }
     
-    const char* params[2] = { resource_id_str, href_param };
+    const char* params[4] = { resource_id_str, href_param, xmlns_param, pname_param };
     PGresult *result = PQexecParams(
             pgdav->connection,
-            sql_propfind_allprop_recursive,
-            2,     // number of parameters
+            query,
+            nparam,     // number of parameters
             NULL,
             params, // parameter value
             NULL,
@@ -325,6 +401,10 @@
             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(nrows < 1) {
         PQclear(result);
         return 1;

mercurial