UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2022 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "resource.h" 30 31 static ResourceType pg_resource_type = { 32 (resource_pool_init_func)pg_resourcepool_init, 33 (resource_pool_destroy_func)pg_resourcepool_destroy, 34 (resource_pool_createresource_func)pg_resourcepool_createresource, 35 (resource_pool_freeresource_func)pg_resourcepool_freeresource, 36 (resource_pool_prepare_func)pg_resourcepool_prepare, 37 (resource_pool_finish_func)pg_resourcepool_finish, 38 (resource_pool_getresourcedata_func)pg_resourcepool_getresourcedata 39 }; 40 41 ResourceType* pg_get_resource_type(void) { 42 return &pg_resource_type; 43 } 44 45 void * pg_resourcepool_init(pool_handle_t *pool, const char *rpname, pblock *pb) { 46 char *connection = pblock_findval("Connection", pb); 47 if(!connection) { 48 log_ereport(LOG_MISCONFIG, "Resource pool %s: Missing Connection parameter", rpname); 49 return NULL; 50 } 51 52 // test connection 53 PGconn *test_connection = PQconnectdb(connection); 54 // pg_check_connections logs errors, so we don't really need to handle 55 // any error here 56 pg_check_connection(LOG_WARN, rpname, test_connection); 57 if(test_connection) PQfinish(test_connection); 58 59 PgResourcePool *pg = pool_malloc(pool, sizeof(PgResourcePool)); 60 if(!pg) { 61 return NULL; 62 } 63 pg->pool = pool; 64 pg->name = rpname; 65 pg->connection = connection; 66 67 return pg; 68 69 } 70 71 int pg_check_connection(int loglevel, const char *rpname, PGconn *connection) { 72 if(!connection) { 73 log_ereport(loglevel, "Resource pool %s: Cannot create PQ connection", rpname); 74 return 1; 75 } 76 if(PQstatus(connection) != CONNECTION_OK) { 77 char *err = PQerrorMessage(connection); 78 int errlen = 0; 79 if(err) { 80 errlen = strlen(err); 81 if(errlen > 0 && err[errlen-1] == '\n') { 82 errlen--; 83 } 84 } 85 log_ereport(loglevel, "Resource pool %s: Failed to connect to database: %.*s", rpname, errlen, err); 86 return 1; 87 } 88 return 0; 89 } 90 91 92 void pg_resourcepool_destroy(PgResourcePool *pg) { 93 // unused 94 } 95 96 void * pg_resourcepool_createresource(PgResourcePool *pg) { 97 PGconn *connection = PQconnectdb(pg->connection); 98 if(pg_check_connection(LOG_FAILURE, pg->name, connection)) { 99 return NULL; 100 } 101 102 PgResource *res = pool_malloc(pg->pool, sizeof(PgResource)); 103 if(!res) { 104 PQfinish(connection); 105 log_ereport(LOG_CATASTROPHE, "pg_resourcepool_createresource: OOM"); 106 return NULL; 107 } 108 res->connection = connection; 109 110 return res; 111 } 112 113 void pg_resourcepool_freeresource(PgResourcePool *pg, PgResource *res) { 114 if(res->connection) { 115 PQfinish(res->connection); 116 } 117 pool_free(pg->pool, res); 118 } 119 120 int pg_resourcepool_prepare(PgResourcePool *pg, PgResource *res) { 121 PGresult *result = PQexec(res->connection, "BEGIN"); 122 PQclear(result); // TODO: handle error 123 return 0; 124 } 125 126 int pg_resourcepool_finish(PgResourcePool *pg, PgResource *res) { 127 PGresult *result = PQexec(res->connection, "COMMIT"); 128 if(PQresultStatus(result) != PGRES_COMMAND_OK) { 129 log_ereport(LOG_FAILURE, "pg_dav_proppatch_finish: COMMIT failed failed: %s", PQerrorMessage(res->connection)); 130 } 131 PQclear(result); 132 return 0; 133 } 134 135 void * pg_resourcepool_getresourcedata(PgResource *res) { 136 return res->connection; 137 } 138