src/server/plugins/postgresql/config.c

Thu, 11 Aug 2022 20:51:39 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 11 Aug 2022 20:51:39 +0200
branch
webdav
changeset 372
1d2538a1ba8f
parent 366
47bc686fafe4
child 373
f78a585e1a2f
permissions
-rw-r--r--

add config option for pg root node lookup

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2022 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "../../util/util.h"

static const char *sql_get_repository_root = "select resource_id from Resource where parent_id is NULL and nodename = $1 ;";


// Uses a PGconn to lookup the resource id of the specified root node
// if the lookup succeeds, the resource id is written to rootid
// in case of an error, an error message will be logged
// returns: 0 success, 1 error
static int pg_lookup_root(ResourceData *res, scstr_t rootnode, int64_t *rootid) {
    PGconn *connection = res->data;
    
    PGresult *result = PQexecParams(
            connection,
            sql_get_repository_root,
            1,     // number of parameters
            NULL,
            &rootnode.ptr, // parameter value
            NULL,
            NULL,
            0);    // 0: result in text format
    
    if(!result) {
        log_ereport(LOG_FAILURE, "pg: root lookup failed: %s", PQerrorMessage(connection));
        return 1;
    }
    
    int ret = 0;
    
    int nrows = PQntuples(result);
    if(nrows == 1) {
        char *resource_id_str = PQgetvalue(result, 0, 0);
        if(resource_id_str) {
            if(!util_strtoint(resource_id_str, rootid)) {
                log_ereport(LOG_FAILURE, "pg: unexpected result for column resource_id", rootnode.ptr);
                ret = 1;
            }
        }
    } else {
        log_ereport(LOG_FAILURE, "pg: cannot find root resource '%s'", rootnode.ptr);
        ret = 1;
    }
    PQclear(result);
    
    return ret;
}

PgRepository* pg_init_repo(ServerConfiguration *cfg, pool_handle_t *pool, WSConfigNode *config) {
    UcxAllocator a = util_pool_allocator(pool);
    
    ConfigNode *pg = serverconfig_get_node(config, CONFIG_NODE_OBJECT, SC("Postgresql"));
    if(!pg) {
        log_ereport(LOG_MISCONFIG, "pg_init_repo: missing postgresql config object");
        return NULL;
    }
    
    scstr_t cfg_respool = serverconfig_directive_value(pg, SC("ResourcePool"));
    scstr_t cfg_rootid = serverconfig_directive_value(pg, SC("RootId"));
    scstr_t cfg_rootnode = serverconfig_directive_value(pg, SC("RootNode"));
    scstr_t cfg_dav = serverconfig_directive_value(pg, SC("PGDavConfig"));
    
    // minimum requirement is a resource pool
    if(cfg_respool.length == 0) {
        return NULL;
    }
    
    // check rootid
    int64_t root_id = 1;
    if(cfg_rootid.length > 0) {
        if(!util_strtoint(cfg_rootid.ptr, &root_id)) {
            log_ereport(LOG_MISCONFIG, "pg_init_repo: RootId parameter is not an integer: %s", cfg_rootid.ptr);
            return NULL;
        }
    }
    
    // warn if RootId and RootNode are specified
    if(cfg_rootid.length > 0 && cfg_rootnode.length > 0) {
        log_ereport(LOG_WARN, "log_init_repo: RootId and RootNode specified, RootNode ignored");
    } else if(cfg_rootnode.length > 0) {
        // check root node
        
        // resolve rootnode
        // therefore we first need to get a connection from the resourcepool
        ResourceData *res = resourcepool_cfg_lookup(cfg, cfg_respool.ptr, 0);
        if(!res) {
            log_ereport(LOG_MISCONFIG, "pg_init_repo: resource lookup failed");
            return NULL;
        }
        // do lookup, if successful, root_id will be set
        int lookup_err = pg_lookup_root(res, cfg_rootnode, &root_id);
        // we don't need the connection anymore
        resourcepool_free(NULL, NULL, res);
        if(lookup_err) {
            // no logging required, pg_lookup_root will log the error
            return NULL;
        }
    }
    
    PgRepository *repo = pool_malloc(pool, sizeof(PgRepository));
    ZERO(repo, sizeof(PgRepository));
    
    repo->resourcepool = sstrdup_a(&a, cfg_respool);
    
    return repo;
}

mercurial