diff -r eab579b8c80d -r 96e53bd94958 src/server/plugins/postgresql/vfs.c --- a/src/server/plugins/postgresql/vfs.c Thu Feb 03 18:03:27 2022 +0100 +++ b/src/server/plugins/postgresql/vfs.c Fri Feb 04 18:12:23 2022 +0100 @@ -112,6 +112,14 @@ // params: $1: resource_id static const char *sql_get_resource = "select resource_id, nodename, iscollection, lastmodified, creationdate, contentlength from Resource where resource_id = $1;"; +// Create resource +// params: $1: parent_id +// $2: node name +static const char *sql_create_resource = + "insert into Resource (parent_id, nodename, iscollection, lastmodified, creationdate, contentlength, resoid) values\n\ + ($1, $2, false, now(), now(), 0, lo_creat(-1))\n\ + returning resource_id, resoid, lastmodified, creationdate;"; + VFS* pg_vfs_create(Session *sn, Request *rq, pblock *pb) { // resourcepool is required char *resource_pool = pblock_findval("resourcepool", pb); @@ -270,6 +278,100 @@ } } +int pg_create_file( + VFSContext *ctx, + PgVFS *pg, + const char *path, + int64_t *new_resource_id, + int64_t *res_parent_id, + Oid *oid, + const char **resource_name, + struct stat *s) +{ + char *parent_path = util_parent_path(path); + if(!parent_path) return 1; + + const char *nodename = util_resource_name(path); + + // resolve the parent path + // if the parent path can't be resolved, we are done + const char *resname; + int64_t resource_id, parent_id; + resource_id = -1; + parent_id = -1; + WSBool iscollection; + Oid unused_oid = 0; + + int err = pg_resolve_path(ctx, parent_path, &parent_id, &resource_id, &unused_oid, &resname, &iscollection, NULL); + FREE(parent_path); + if(err) { + return 1; + } + + // parent path exists, check if it is a collection + if(!iscollection) { + return 1; + } + + // create new Resource + char resid_str[32]; + snprintf(resid_str, 32, "%" PRId64, resource_id); // convert parent resource_id to string + + const char* params[2] = { resid_str, nodename }; + PGresult *result = PQexecParams( + pg->connection, + sql_create_resource, + 2, // number of parameters + NULL, + params, // parameter value + NULL, + NULL, + 0); // 0: result in text format + + if(!result) return 1; + + int ret = 1; + if(PQntuples(result) == 1) { + // sql insert succesful + ret = 0; + + char *id_str = PQgetvalue(result, 0, 0); + char *oid_str = PQgetvalue(result, 0, 1); + char *lastmodified = PQgetvalue(result, 0, 2); + char *creationdate = PQgetvalue(result, 0, 3); + + if(new_resource_id) { + if(!id_str || !util_strtoint(id_str, new_resource_id)) { + ret = 1; // shouldn't happen + log_ereport(LOG_FAILURE, "Postgresql VFS: sql_create_resource: Could not convert resource_id to int"); + } + } + if(res_parent_id) { + // resource_id is still the id of the parent from previous pg_resolve_path call + *res_parent_id = resource_id; + } + if(oid) { + int64_t i; + if(!oid_str || !util_strtoint(oid_str, &i)) { + ret = 1; // shouldn't happen + log_ereport(LOG_FAILURE, "Postgresql VFS: sql_create_resource: Could not convert oid to int"); + } else { + *oid = i; + } + } + if(resource_name) { + *resource_name = nodename; + } + if(s) { + pg_set_stat(s, 0, lastmodified, creationdate, NULL); + } + } + + PQclear(result); + + return ret; +} + /* -------------------------- VFS functions -------------------------- */ SYS_FILE pg_vfs_open(VFSContext *ctx, const char *path, int oflags) { @@ -284,7 +386,14 @@ struct stat s; Oid oid = 0; if(pg_resolve_path(ctx, path, &parent_id, &resource_id, &oid, &resname, &iscollection, &s)) { - return NULL; + if((oflags & O_CREAT) == O_CREAT) { + if(pg_create_file(ctx, pg, path, &resource_id, &parent_id, &oid, &resname, &s)) { + return NULL; + } + iscollection = 0; + } else { + return NULL; + } } VFSFile *file = pool_malloc(ctx->pool, sizeof(VFSFile));