1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251876Speter * contributor license agreements. See the NOTICE file distributed with 3251876Speter * this work for additional information regarding copyright ownership. 4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251876Speter * (the "License"); you may not use this file except in compliance with 6251876Speter * the License. You may obtain a copy of the License at 7251876Speter * 8251876Speter * http://www.apache.org/licenses/LICENSE-2.0 9251876Speter * 10251876Speter * Unless required by applicable law or agreed to in writing, software 11251876Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251876Speter * See the License for the specific language governing permissions and 14251876Speter * limitations under the License. 15251876Speter */ 16251876Speter 17251876Speter#include "apu.h" 18251876Speter 19251876Speter#if APU_HAVE_PGSQL 20251876Speter 21251876Speter#include "apu_config.h" 22251876Speter 23251876Speter#include <ctype.h> 24251876Speter#include <stdlib.h> 25251876Speter 26251876Speter#ifdef HAVE_LIBPQ_FE_H 27251876Speter#include <libpq-fe.h> 28251876Speter#elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H) 29251876Speter#include <postgresql/libpq-fe.h> 30251876Speter#endif 31251876Speter 32251876Speter#include "apr_strings.h" 33251876Speter#include "apr_time.h" 34251876Speter#include "apr_buckets.h" 35251876Speter 36251876Speter#include "apr_dbd_internal.h" 37251876Speter 38251876Speterstruct apr_dbd_transaction_t { 39251876Speter int mode; 40251876Speter int errnum; 41251876Speter apr_dbd_t *handle; 42251876Speter}; 43251876Speter 44251876Speterstruct apr_dbd_t { 45251876Speter PGconn *conn; 46251876Speter apr_dbd_transaction_t *trans; 47251876Speter}; 48251876Speter 49251876Speterstruct apr_dbd_results_t { 50251876Speter int random; 51251876Speter PGconn *handle; 52251876Speter PGresult *res; 53251876Speter size_t ntuples; 54251876Speter size_t sz; 55251876Speter size_t index; 56251876Speter apr_pool_t *pool; 57251876Speter}; 58251876Speter 59251876Speterstruct apr_dbd_row_t { 60251876Speter int n; 61251876Speter apr_dbd_results_t *res; 62251876Speter}; 63251876Speter 64251876Speterstruct apr_dbd_prepared_t { 65251876Speter const char *name; 66251876Speter int prepared; 67251876Speter int nargs; 68251876Speter int nvals; 69251876Speter apr_dbd_type_e *types; 70251876Speter}; 71251876Speter 72251876Speter#define dbd_pgsql_is_success(x) (((x) == PGRES_EMPTY_QUERY) \ 73251876Speter || ((x) == PGRES_COMMAND_OK) \ 74251876Speter || ((x) == PGRES_TUPLES_OK)) 75251876Speter 76251876Speterstatic apr_status_t clear_result(void *data) 77251876Speter{ 78251876Speter PQclear(data); 79251876Speter return APR_SUCCESS; 80251876Speter} 81251876Speter 82251876Speterstatic int dbd_pgsql_select(apr_pool_t *pool, apr_dbd_t *sql, 83251876Speter apr_dbd_results_t **results, 84251876Speter const char *query, int seek) 85251876Speter{ 86251876Speter PGresult *res; 87251876Speter int ret; 88251876Speter if ( sql->trans && sql->trans->errnum ) { 89251876Speter return sql->trans->errnum; 90251876Speter } 91251876Speter if (seek) { /* synchronous query */ 92251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 93251876Speter PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); 94251876Speter if (res) { 95251876Speter int ret = PQresultStatus(res); 96251876Speter PQclear(res); 97251876Speter if (!dbd_pgsql_is_success(ret)) { 98251876Speter sql->trans->errnum = ret; 99251876Speter return PGRES_FATAL_ERROR; 100251876Speter } 101251876Speter } else { 102251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 103251876Speter } 104251876Speter } 105251876Speter res = PQexec(sql->conn, query); 106251876Speter if (res) { 107251876Speter ret = PQresultStatus(res); 108251876Speter if (dbd_pgsql_is_success(ret)) { 109251876Speter ret = 0; 110251876Speter } else { 111251876Speter PQclear(res); 112251876Speter } 113251876Speter } else { 114251876Speter ret = PGRES_FATAL_ERROR; 115251876Speter } 116251876Speter if (ret != 0) { 117251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 118251876Speter PGresult *res = PQexec(sql->conn, 119251876Speter "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); 120251876Speter if (res) { 121251876Speter int ret = PQresultStatus(res); 122251876Speter PQclear(res); 123251876Speter if (!dbd_pgsql_is_success(ret)) { 124251876Speter sql->trans->errnum = ret; 125251876Speter return PGRES_FATAL_ERROR; 126251876Speter } 127251876Speter } else { 128251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 129251876Speter } 130251876Speter } else if (TXN_NOTICE_ERRORS(sql->trans)){ 131251876Speter sql->trans->errnum = ret; 132251876Speter } 133251876Speter return ret; 134251876Speter } else { 135251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 136251876Speter PGresult *res = PQexec(sql->conn, 137251876Speter "RELEASE SAVEPOINT APR_DBD_TXN_SP"); 138251876Speter if (res) { 139251876Speter int ret = PQresultStatus(res); 140251876Speter PQclear(res); 141251876Speter if (!dbd_pgsql_is_success(ret)) { 142251876Speter sql->trans->errnum = ret; 143251876Speter return PGRES_FATAL_ERROR; 144251876Speter } 145251876Speter } else { 146251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 147251876Speter } 148251876Speter } 149251876Speter } 150251876Speter if (!*results) { 151251876Speter *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); 152251876Speter } 153251876Speter (*results)->res = res; 154251876Speter (*results)->ntuples = PQntuples(res); 155251876Speter (*results)->sz = PQnfields(res); 156251876Speter (*results)->random = seek; 157251876Speter (*results)->pool = pool; 158251876Speter apr_pool_cleanup_register(pool, res, clear_result, 159251876Speter apr_pool_cleanup_null); 160251876Speter } 161251876Speter else { 162251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 163251876Speter PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); 164251876Speter if (res) { 165251876Speter int ret = PQresultStatus(res); 166251876Speter PQclear(res); 167251876Speter if (!dbd_pgsql_is_success(ret)) { 168251876Speter sql->trans->errnum = ret; 169251876Speter return PGRES_FATAL_ERROR; 170251876Speter } 171251876Speter } else { 172251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 173251876Speter } 174251876Speter } 175251876Speter if (PQsendQuery(sql->conn, query) == 0) { 176251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 177251876Speter PGresult *res = PQexec(sql->conn, 178251876Speter "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); 179251876Speter if (res) { 180251876Speter int ret = PQresultStatus(res); 181251876Speter PQclear(res); 182251876Speter if (!dbd_pgsql_is_success(ret)) { 183251876Speter sql->trans->errnum = ret; 184251876Speter return PGRES_FATAL_ERROR; 185251876Speter } 186251876Speter } else { 187251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 188251876Speter } 189251876Speter } else if (TXN_NOTICE_ERRORS(sql->trans)){ 190251876Speter sql->trans->errnum = 1; 191251876Speter } 192251876Speter return 1; 193251876Speter } else { 194251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 195251876Speter PGresult *res = PQexec(sql->conn, 196251876Speter "RELEASE SAVEPOINT APR_DBD_TXN_SP"); 197251876Speter if (res) { 198251876Speter int ret = PQresultStatus(res); 199251876Speter PQclear(res); 200251876Speter if (!dbd_pgsql_is_success(ret)) { 201251876Speter sql->trans->errnum = ret; 202251876Speter return PGRES_FATAL_ERROR; 203251876Speter } 204251876Speter } else { 205251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 206251876Speter } 207251876Speter } 208251876Speter } 209251876Speter if (*results == NULL) { 210251876Speter *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); 211251876Speter } 212251876Speter (*results)->random = seek; 213251876Speter (*results)->handle = sql->conn; 214251876Speter (*results)->pool = pool; 215251876Speter } 216251876Speter return 0; 217251876Speter} 218251876Speter 219251876Speterstatic const char *dbd_pgsql_get_name(const apr_dbd_results_t *res, int n) 220251876Speter{ 221251876Speter if (res->res) { 222251876Speter if ((n>=0) && (PQnfields(res->res) > n)) { 223251876Speter return PQfname(res->res,n); 224251876Speter } 225251876Speter } 226251876Speter return NULL; 227251876Speter} 228251876Speter 229251876Speterstatic int dbd_pgsql_get_row(apr_pool_t *pool, apr_dbd_results_t *res, 230251876Speter apr_dbd_row_t **rowp, int rownum) 231251876Speter{ 232251876Speter apr_dbd_row_t *row = *rowp; 233251876Speter int sequential = ((rownum >= 0) && res->random) ? 0 : 1; 234251876Speter 235251876Speter if (row == NULL) { 236251876Speter row = apr_palloc(pool, sizeof(apr_dbd_row_t)); 237251876Speter *rowp = row; 238251876Speter row->res = res; 239251876Speter if ( sequential ) { 240251876Speter row->n = 0; 241251876Speter } 242251876Speter else { 243251876Speter if (rownum > 0) { 244251876Speter row->n = --rownum; 245251876Speter } 246251876Speter else { 247251876Speter return -1; /* invalid row */ 248251876Speter } 249251876Speter } 250251876Speter } 251251876Speter else { 252251876Speter if ( sequential ) { 253251876Speter ++row->n; 254251876Speter } 255251876Speter else { 256251876Speter if (rownum > 0) { 257251876Speter row->n = --rownum; 258251876Speter } 259251876Speter else { 260251876Speter return -1; /* invalid row */ 261251876Speter } 262251876Speter } 263251876Speter } 264251876Speter 265251876Speter if (res->random) { 266251876Speter if ((row->n >= 0) && (size_t)row->n >= res->ntuples) { 267251876Speter *rowp = NULL; 268253734Speter apr_pool_cleanup_run(res->pool, res->res, clear_result); 269251876Speter res->res = NULL; 270251876Speter return -1; 271251876Speter } 272251876Speter } 273251876Speter else { 274251876Speter if ((row->n >= 0) && (size_t)row->n >= res->ntuples) { 275251876Speter /* no data; we have to fetch some */ 276251876Speter row->n -= res->ntuples; 277251876Speter if (res->res != NULL) { 278251876Speter PQclear(res->res); 279251876Speter } 280251876Speter res->res = PQgetResult(res->handle); 281251876Speter if (res->res) { 282251876Speter res->ntuples = PQntuples(res->res); 283251876Speter while (res->ntuples == 0) { 284251876Speter /* if we got an empty result, clear it, wait a mo, try 285251876Speter * again */ 286251876Speter PQclear(res->res); 287251876Speter apr_sleep(100000); /* 0.1 secs */ 288251876Speter res->res = PQgetResult(res->handle); 289251876Speter if (res->res) { 290251876Speter res->ntuples = PQntuples(res->res); 291251876Speter } 292251876Speter else { 293251876Speter return -1; 294251876Speter } 295251876Speter } 296251876Speter if (res->sz == 0) { 297251876Speter res->sz = PQnfields(res->res); 298251876Speter } 299251876Speter } 300251876Speter else { 301251876Speter return -1; 302251876Speter } 303251876Speter } 304251876Speter } 305251876Speter return 0; 306251876Speter} 307251876Speter 308251876Speterstatic const char *dbd_pgsql_get_entry(const apr_dbd_row_t *row, int n) 309251876Speter{ 310251876Speter return PQgetvalue(row->res->res, row->n, n); 311251876Speter} 312251876Speter 313251876Speterstatic apr_status_t dbd_pgsql_datum_get(const apr_dbd_row_t *row, int n, 314251876Speter apr_dbd_type_e type, void *data) 315251876Speter{ 316251876Speter if (PQgetisnull(row->res->res, row->n, n)) { 317251876Speter return APR_ENOENT; 318251876Speter } 319251876Speter 320251876Speter switch (type) { 321251876Speter case APR_DBD_TYPE_TINY: 322251876Speter *(char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); 323251876Speter break; 324251876Speter case APR_DBD_TYPE_UTINY: 325251876Speter *(unsigned char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); 326251876Speter break; 327251876Speter case APR_DBD_TYPE_SHORT: 328251876Speter *(short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); 329251876Speter break; 330251876Speter case APR_DBD_TYPE_USHORT: 331251876Speter *(unsigned short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); 332251876Speter break; 333251876Speter case APR_DBD_TYPE_INT: 334251876Speter *(int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); 335251876Speter break; 336251876Speter case APR_DBD_TYPE_UINT: 337251876Speter *(unsigned int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); 338251876Speter break; 339251876Speter case APR_DBD_TYPE_LONG: 340251876Speter *(long*)data = atol(PQgetvalue(row->res->res, row->n, n)); 341251876Speter break; 342251876Speter case APR_DBD_TYPE_ULONG: 343251876Speter *(unsigned long*)data = atol(PQgetvalue(row->res->res, row->n, n)); 344251876Speter break; 345251876Speter case APR_DBD_TYPE_LONGLONG: 346251876Speter *(apr_int64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); 347251876Speter break; 348251876Speter case APR_DBD_TYPE_ULONGLONG: 349251876Speter *(apr_uint64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); 350251876Speter break; 351251876Speter case APR_DBD_TYPE_FLOAT: 352251876Speter *(float*)data = (float)atof(PQgetvalue(row->res->res, row->n, n)); 353251876Speter break; 354251876Speter case APR_DBD_TYPE_DOUBLE: 355251876Speter *(double*)data = atof(PQgetvalue(row->res->res, row->n, n)); 356251876Speter break; 357251876Speter case APR_DBD_TYPE_STRING: 358251876Speter case APR_DBD_TYPE_TEXT: 359251876Speter case APR_DBD_TYPE_TIME: 360251876Speter case APR_DBD_TYPE_DATE: 361251876Speter case APR_DBD_TYPE_DATETIME: 362251876Speter case APR_DBD_TYPE_TIMESTAMP: 363251876Speter case APR_DBD_TYPE_ZTIMESTAMP: 364251876Speter *(char**)data = PQgetvalue(row->res->res, row->n, n); 365251876Speter break; 366251876Speter case APR_DBD_TYPE_BLOB: 367251876Speter case APR_DBD_TYPE_CLOB: 368251876Speter { 369251876Speter apr_bucket *e; 370251876Speter apr_bucket_brigade *b = (apr_bucket_brigade*)data; 371251876Speter 372251876Speter e = apr_bucket_pool_create(PQgetvalue(row->res->res, row->n, n), 373251876Speter PQgetlength(row->res->res, row->n, n), 374251876Speter row->res->pool, b->bucket_alloc); 375251876Speter APR_BRIGADE_INSERT_TAIL(b, e); 376251876Speter } 377251876Speter break; 378251876Speter case APR_DBD_TYPE_NULL: 379251876Speter *(void**)data = NULL; 380251876Speter break; 381251876Speter default: 382251876Speter return APR_EGENERAL; 383251876Speter } 384251876Speter 385251876Speter return APR_SUCCESS; 386251876Speter} 387251876Speter 388251876Speterstatic const char *dbd_pgsql_error(apr_dbd_t *sql, int n) 389251876Speter{ 390251876Speter return PQerrorMessage(sql->conn); 391251876Speter} 392251876Speter 393251876Speterstatic int dbd_pgsql_query(apr_dbd_t *sql, int *nrows, const char *query) 394251876Speter{ 395251876Speter PGresult *res; 396251876Speter int ret; 397251876Speter if (sql->trans && sql->trans->errnum) { 398251876Speter return sql->trans->errnum; 399251876Speter } 400251876Speter 401251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 402251876Speter PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); 403251876Speter if (res) { 404251876Speter int ret = PQresultStatus(res); 405251876Speter PQclear(res); 406251876Speter if (!dbd_pgsql_is_success(ret)) { 407251876Speter sql->trans->errnum = ret; 408251876Speter return PGRES_FATAL_ERROR; 409251876Speter } 410251876Speter } else { 411251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 412251876Speter } 413251876Speter } 414251876Speter 415251876Speter res = PQexec(sql->conn, query); 416251876Speter if (res) { 417251876Speter ret = PQresultStatus(res); 418251876Speter if (dbd_pgsql_is_success(ret)) { 419251876Speter /* ugh, making 0 return-success doesn't fit */ 420251876Speter ret = 0; 421251876Speter } 422251876Speter *nrows = atoi(PQcmdTuples(res)); 423251876Speter PQclear(res); 424251876Speter } 425251876Speter else { 426251876Speter ret = PGRES_FATAL_ERROR; 427251876Speter } 428251876Speter 429251876Speter if (ret != 0){ 430251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 431251876Speter PGresult *res = PQexec(sql->conn, 432251876Speter "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); 433251876Speter if (res) { 434251876Speter int ret = PQresultStatus(res); 435251876Speter PQclear(res); 436251876Speter if (!dbd_pgsql_is_success(ret)) { 437251876Speter sql->trans->errnum = ret; 438251876Speter return PGRES_FATAL_ERROR; 439251876Speter } 440251876Speter } else { 441251876Speter sql->trans->errnum = ret; 442251876Speter return PGRES_FATAL_ERROR; 443251876Speter } 444251876Speter } else if (TXN_NOTICE_ERRORS(sql->trans)){ 445251876Speter sql->trans->errnum = ret; 446251876Speter } 447251876Speter } else { 448251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 449251876Speter PGresult *res = PQexec(sql->conn, 450251876Speter "RELEASE SAVEPOINT APR_DBD_TXN_SP"); 451251876Speter if (res) { 452251876Speter int ret = PQresultStatus(res); 453251876Speter PQclear(res); 454251876Speter if (!dbd_pgsql_is_success(ret)) { 455251876Speter sql->trans->errnum = ret; 456251876Speter return PGRES_FATAL_ERROR; 457251876Speter } 458251876Speter } else { 459251876Speter sql->trans->errnum = ret; 460251876Speter return PGRES_FATAL_ERROR; 461251876Speter } 462251876Speter } 463251876Speter } 464251876Speter 465251876Speter return ret; 466251876Speter} 467251876Speter 468251876Speterstatic const char *dbd_pgsql_escape(apr_pool_t *pool, const char *arg, 469251876Speter apr_dbd_t *sql) 470251876Speter{ 471251876Speter size_t len = strlen(arg); 472251876Speter char *ret = apr_palloc(pool, 2*len + 2); 473253734Speter PQescapeStringConn(sql->conn, ret, arg, len, NULL); 474251876Speter return ret; 475251876Speter} 476251876Speter 477251876Speterstatic int dbd_pgsql_prepare(apr_pool_t *pool, apr_dbd_t *sql, 478251876Speter const char *query, const char *label, 479251876Speter int nargs, int nvals, apr_dbd_type_e *types, 480251876Speter apr_dbd_prepared_t **statement) 481251876Speter{ 482251876Speter char *sqlcmd; 483251876Speter char *sqlptr; 484251876Speter size_t length, qlen; 485251876Speter int i = 0; 486251876Speter const char **args; 487251876Speter size_t alen; 488251876Speter int ret; 489251876Speter PGresult *res; 490251876Speter 491251876Speter if (!*statement) { 492251876Speter *statement = apr_palloc(pool, sizeof(apr_dbd_prepared_t)); 493251876Speter } 494251876Speter (*statement)->nargs = nargs; 495251876Speter (*statement)->nvals = nvals; 496251876Speter (*statement)->types = types; 497251876Speter 498251876Speter args = apr_palloc(pool, nargs * sizeof(*args)); 499251876Speter 500251876Speter qlen = strlen(query); 501251876Speter length = qlen + 1; 502251876Speter 503251876Speter for (i = 0; i < nargs; i++) { 504251876Speter switch (types[i]) { 505251876Speter case APR_DBD_TYPE_TINY: 506251876Speter case APR_DBD_TYPE_UTINY: 507251876Speter case APR_DBD_TYPE_SHORT: 508251876Speter case APR_DBD_TYPE_USHORT: 509251876Speter args[i] = "smallint"; 510251876Speter break; 511251876Speter case APR_DBD_TYPE_INT: 512251876Speter case APR_DBD_TYPE_UINT: 513251876Speter args[i] = "integer"; 514251876Speter break; 515251876Speter case APR_DBD_TYPE_LONG: 516251876Speter case APR_DBD_TYPE_ULONG: 517251876Speter case APR_DBD_TYPE_LONGLONG: 518251876Speter case APR_DBD_TYPE_ULONGLONG: 519251876Speter args[i] = "bigint"; 520251876Speter break; 521251876Speter case APR_DBD_TYPE_FLOAT: 522251876Speter args[i] = "real"; 523251876Speter break; 524251876Speter case APR_DBD_TYPE_DOUBLE: 525251876Speter args[i] = "double precision"; 526251876Speter break; 527251876Speter case APR_DBD_TYPE_TEXT: 528251876Speter args[i] = "text"; 529251876Speter break; 530251876Speter case APR_DBD_TYPE_TIME: 531251876Speter args[i] = "time"; 532251876Speter break; 533251876Speter case APR_DBD_TYPE_DATE: 534251876Speter args[i] = "date"; 535251876Speter break; 536251876Speter case APR_DBD_TYPE_DATETIME: 537251876Speter case APR_DBD_TYPE_TIMESTAMP: 538251876Speter args[i] = "timestamp"; 539251876Speter break; 540251876Speter case APR_DBD_TYPE_ZTIMESTAMP: 541251876Speter args[i] = "timestamp with time zone"; 542251876Speter break; 543251876Speter case APR_DBD_TYPE_BLOB: 544251876Speter case APR_DBD_TYPE_CLOB: 545251876Speter args[i] = "bytea"; 546251876Speter break; 547251876Speter case APR_DBD_TYPE_NULL: 548251876Speter args[i] = "varchar"; /* XXX Eh? */ 549251876Speter break; 550251876Speter default: 551251876Speter args[i] = "varchar"; 552251876Speter break; 553251876Speter } 554251876Speter length += 1 + strlen(args[i]); 555251876Speter } 556251876Speter 557251876Speter if (!label) { 558251876Speter /* don't really prepare; use in execParams instead */ 559251876Speter (*statement)->prepared = 0; 560251876Speter (*statement)->name = apr_pstrdup(pool, query); 561251876Speter return 0; 562251876Speter } 563251876Speter (*statement)->name = apr_pstrdup(pool, label); 564251876Speter 565251876Speter /* length of SQL query that prepares this statement */ 566251876Speter length = 8 + strlen(label) + 2 + 4 + length + 1; 567251876Speter sqlcmd = apr_palloc(pool, length); 568251876Speter sqlptr = sqlcmd; 569251876Speter memcpy(sqlptr, "PREPARE ", 8); 570251876Speter sqlptr += 8; 571251876Speter length = strlen(label); 572251876Speter memcpy(sqlptr, label, length); 573251876Speter sqlptr += length; 574251876Speter if (nargs > 0) { 575251876Speter memcpy(sqlptr, " (",2); 576251876Speter sqlptr += 2; 577251876Speter for (i=0; i < nargs; ++i) { 578251876Speter alen = strlen(args[i]); 579251876Speter memcpy(sqlptr, args[i], alen); 580251876Speter sqlptr += alen; 581251876Speter *sqlptr++ = ','; 582251876Speter } 583251876Speter sqlptr[-1] = ')'; 584251876Speter } 585251876Speter memcpy(sqlptr, " AS ", 4); 586251876Speter sqlptr += 4; 587251876Speter memcpy(sqlptr, query, qlen); 588251876Speter sqlptr += qlen; 589251876Speter *sqlptr = 0; 590251876Speter 591251876Speter res = PQexec(sql->conn, sqlcmd); 592251876Speter if ( res ) { 593251876Speter ret = PQresultStatus(res); 594251876Speter if (dbd_pgsql_is_success(ret)) { 595251876Speter ret = 0; 596251876Speter } 597251876Speter /* Hmmm, do we do this here or register it on the pool? */ 598251876Speter PQclear(res); 599251876Speter } 600251876Speter else { 601251876Speter ret = PGRES_FATAL_ERROR; 602251876Speter } 603251876Speter (*statement)->prepared = 1; 604251876Speter 605251876Speter return ret; 606251876Speter} 607251876Speter 608251876Speterstatic int dbd_pgsql_pquery_internal(apr_pool_t *pool, apr_dbd_t *sql, 609251876Speter int *nrows, apr_dbd_prepared_t *statement, 610251876Speter const char **values, 611251876Speter const int *len, const int *fmt) 612251876Speter{ 613251876Speter int ret; 614251876Speter PGresult *res; 615251876Speter 616251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 617251876Speter PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); 618251876Speter if (res) { 619251876Speter int ret = PQresultStatus(res); 620251876Speter PQclear(res); 621251876Speter if (!dbd_pgsql_is_success(ret)) { 622251876Speter sql->trans->errnum = ret; 623251876Speter return PGRES_FATAL_ERROR; 624251876Speter } 625251876Speter } else { 626251876Speter return sql->trans->errnum = PGRES_FATAL_ERROR; 627251876Speter } 628251876Speter } 629251876Speter 630251876Speter if (statement->prepared) { 631251876Speter res = PQexecPrepared(sql->conn, statement->name, statement->nargs, 632251876Speter values, len, fmt, 0); 633251876Speter } 634251876Speter else { 635251876Speter res = PQexecParams(sql->conn, statement->name, statement->nargs, 0, 636251876Speter values, len, fmt, 0); 637251876Speter } 638251876Speter if (res) { 639251876Speter ret = PQresultStatus(res); 640251876Speter if (dbd_pgsql_is_success(ret)) { 641251876Speter ret = 0; 642251876Speter } 643251876Speter *nrows = atoi(PQcmdTuples(res)); 644251876Speter PQclear(res); 645251876Speter } 646251876Speter else { 647251876Speter ret = PGRES_FATAL_ERROR; 648251876Speter } 649251876Speter 650251876Speter if (ret != 0){ 651251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 652251876Speter PGresult *res = PQexec(sql->conn, 653251876Speter "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); 654251876Speter if (res) { 655251876Speter int ret = PQresultStatus(res); 656251876Speter PQclear(res); 657251876Speter if (!dbd_pgsql_is_success(ret)) { 658251876Speter sql->trans->errnum = ret; 659251876Speter return PGRES_FATAL_ERROR; 660251876Speter } 661251876Speter } else { 662251876Speter sql->trans->errnum = ret; 663251876Speter return PGRES_FATAL_ERROR; 664251876Speter } 665251876Speter } else if (TXN_NOTICE_ERRORS(sql->trans)){ 666251876Speter sql->trans->errnum = ret; 667251876Speter } 668251876Speter } else { 669251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 670251876Speter PGresult *res = PQexec(sql->conn, 671251876Speter "RELEASE SAVEPOINT APR_DBD_TXN_SP"); 672251876Speter if (res) { 673251876Speter int ret = PQresultStatus(res); 674251876Speter PQclear(res); 675251876Speter if (!dbd_pgsql_is_success(ret)) { 676251876Speter sql->trans->errnum = ret; 677251876Speter return PGRES_FATAL_ERROR; 678251876Speter } 679251876Speter } else { 680251876Speter sql->trans->errnum = ret; 681251876Speter return PGRES_FATAL_ERROR; 682251876Speter } 683251876Speter } 684251876Speter } 685251876Speter 686251876Speter return ret; 687251876Speter} 688251876Speter 689251876Speterstatic void dbd_pgsql_bind(apr_dbd_prepared_t *statement, 690251876Speter const char **values, 691251876Speter const char **val, int *len, int *fmt) 692251876Speter{ 693251876Speter int i, j; 694251876Speter 695251876Speter for (i = 0, j = 0; i < statement->nargs; i++, j++) { 696251876Speter if (values[j] == NULL) { 697251876Speter val[i] = NULL; 698251876Speter } 699251876Speter else { 700251876Speter switch (statement->types[i]) { 701251876Speter case APR_DBD_TYPE_BLOB: 702251876Speter case APR_DBD_TYPE_CLOB: 703251876Speter val[i] = (char *)values[j]; 704251876Speter len[i] = atoi(values[++j]); 705251876Speter fmt[i] = 1; 706251876Speter 707251876Speter /* skip table and column */ 708251876Speter j += 2; 709251876Speter break; 710251876Speter default: 711251876Speter val[i] = values[j]; 712251876Speter break; 713251876Speter } 714251876Speter } 715251876Speter } 716251876Speter 717251876Speter return; 718251876Speter} 719251876Speter 720251876Speterstatic int dbd_pgsql_pquery(apr_pool_t *pool, apr_dbd_t *sql, 721251876Speter int *nrows, apr_dbd_prepared_t *statement, 722251876Speter const char **values) 723251876Speter{ 724251876Speter int *len, *fmt; 725251876Speter const char **val; 726251876Speter 727251876Speter if (sql->trans && sql->trans->errnum) { 728251876Speter return sql->trans->errnum; 729251876Speter } 730251876Speter 731251876Speter val = apr_palloc(pool, sizeof(*val) * statement->nargs); 732251876Speter len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); 733251876Speter fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); 734251876Speter 735251876Speter dbd_pgsql_bind(statement, values, val, len, fmt); 736251876Speter 737251876Speter return dbd_pgsql_pquery_internal(pool, sql, nrows, statement, 738251876Speter val, len, fmt); 739251876Speter} 740251876Speter 741251876Speterstatic int dbd_pgsql_pvquery(apr_pool_t *pool, apr_dbd_t *sql, 742251876Speter int *nrows, apr_dbd_prepared_t *statement, 743251876Speter va_list args) 744251876Speter{ 745251876Speter const char **values; 746251876Speter int i; 747251876Speter 748251876Speter if (sql->trans && sql->trans->errnum) { 749251876Speter return sql->trans->errnum; 750251876Speter } 751251876Speter 752251876Speter values = apr_palloc(pool, sizeof(*values) * statement->nvals); 753251876Speter 754251876Speter for (i = 0; i < statement->nvals; i++) { 755251876Speter values[i] = va_arg(args, const char*); 756251876Speter } 757251876Speter 758251876Speter return dbd_pgsql_pquery(pool, sql, nrows, statement, values); 759251876Speter} 760251876Speter 761251876Speterstatic int dbd_pgsql_pselect_internal(apr_pool_t *pool, apr_dbd_t *sql, 762251876Speter apr_dbd_results_t **results, 763251876Speter apr_dbd_prepared_t *statement, 764251876Speter int seek, const char **values, 765251876Speter const int *len, const int *fmt) 766251876Speter{ 767251876Speter PGresult *res; 768251876Speter int rv; 769251876Speter int ret = 0; 770251876Speter 771251876Speter if (seek) { /* synchronous query */ 772251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 773251876Speter PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); 774251876Speter if (res) { 775251876Speter int ret = PQresultStatus(res); 776251876Speter PQclear(res); 777251876Speter if (!dbd_pgsql_is_success(ret)) { 778251876Speter sql->trans->errnum = ret; 779251876Speter return PGRES_FATAL_ERROR; 780251876Speter } 781251876Speter } else { 782251876Speter sql->trans->errnum = ret; 783251876Speter return PGRES_FATAL_ERROR; 784251876Speter } 785251876Speter } 786251876Speter if (statement->prepared) { 787251876Speter res = PQexecPrepared(sql->conn, statement->name, statement->nargs, 788251876Speter values, len, fmt, 0); 789251876Speter } 790251876Speter else { 791251876Speter res = PQexecParams(sql->conn, statement->name, statement->nargs, 0, 792251876Speter values, len, fmt, 0); 793251876Speter } 794251876Speter if (res) { 795251876Speter ret = PQresultStatus(res); 796251876Speter if (dbd_pgsql_is_success(ret)) { 797251876Speter ret = 0; 798251876Speter } 799251876Speter else { 800251876Speter PQclear(res); 801251876Speter } 802251876Speter } 803251876Speter else { 804251876Speter ret = PGRES_FATAL_ERROR; 805251876Speter } 806251876Speter if (ret != 0) { 807251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 808251876Speter PGresult *res = PQexec(sql->conn, 809251876Speter "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); 810251876Speter if (res) { 811251876Speter int ret = PQresultStatus(res); 812251876Speter PQclear(res); 813251876Speter if (!dbd_pgsql_is_success(ret)) { 814251876Speter sql->trans->errnum = ret; 815251876Speter return PGRES_FATAL_ERROR; 816251876Speter } 817251876Speter } else { 818251876Speter sql->trans->errnum = ret; 819251876Speter return PGRES_FATAL_ERROR; 820251876Speter } 821251876Speter } else if (TXN_NOTICE_ERRORS(sql->trans)){ 822251876Speter sql->trans->errnum = ret; 823251876Speter } 824251876Speter return ret; 825251876Speter } else { 826251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 827251876Speter PGresult *res = PQexec(sql->conn, 828251876Speter "RELEASE SAVEPOINT APR_DBD_TXN_SP"); 829251876Speter if (res) { 830251876Speter int ret = PQresultStatus(res); 831251876Speter PQclear(res); 832251876Speter if (!dbd_pgsql_is_success(ret)) { 833251876Speter sql->trans->errnum = ret; 834251876Speter return PGRES_FATAL_ERROR; 835251876Speter } 836251876Speter } else { 837251876Speter sql->trans->errnum = ret; 838251876Speter return PGRES_FATAL_ERROR; 839251876Speter } 840251876Speter } 841251876Speter } 842251876Speter if (!*results) { 843251876Speter *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); 844251876Speter } 845251876Speter (*results)->res = res; 846251876Speter (*results)->ntuples = PQntuples(res); 847251876Speter (*results)->sz = PQnfields(res); 848251876Speter (*results)->random = seek; 849251876Speter (*results)->pool = pool; 850251876Speter apr_pool_cleanup_register(pool, res, clear_result, 851251876Speter apr_pool_cleanup_null); 852251876Speter } 853251876Speter else { 854251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 855251876Speter PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); 856251876Speter if (res) { 857251876Speter int ret = PQresultStatus(res); 858251876Speter PQclear(res); 859251876Speter if (!dbd_pgsql_is_success(ret)) { 860251876Speter sql->trans->errnum = ret; 861251876Speter return PGRES_FATAL_ERROR; 862251876Speter } 863251876Speter } else { 864251876Speter sql->trans->errnum = ret; 865251876Speter return PGRES_FATAL_ERROR; 866251876Speter } 867251876Speter } 868251876Speter if (statement->prepared) { 869251876Speter rv = PQsendQueryPrepared(sql->conn, statement->name, 870251876Speter statement->nargs, values, len, fmt, 0); 871251876Speter } 872251876Speter else { 873251876Speter rv = PQsendQueryParams(sql->conn, statement->name, 874251876Speter statement->nargs, 0, values, len, fmt, 0); 875251876Speter } 876251876Speter if (rv == 0) { 877251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 878251876Speter PGresult *res = PQexec(sql->conn, 879251876Speter "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); 880251876Speter if (res) { 881251876Speter int ret = PQresultStatus(res); 882251876Speter PQclear(res); 883251876Speter if (!dbd_pgsql_is_success(ret)) { 884251876Speter sql->trans->errnum = ret; 885251876Speter return PGRES_FATAL_ERROR; 886251876Speter } 887251876Speter } else { 888251876Speter sql->trans->errnum = ret; 889251876Speter return PGRES_FATAL_ERROR; 890251876Speter } 891251876Speter } else if (TXN_NOTICE_ERRORS(sql->trans)){ 892251876Speter sql->trans->errnum = 1; 893251876Speter } 894251876Speter return 1; 895251876Speter } else { 896251876Speter if (TXN_IGNORE_ERRORS(sql->trans)) { 897251876Speter PGresult *res = PQexec(sql->conn, 898251876Speter "RELEASE SAVEPOINT APR_DBD_TXN_SP"); 899251876Speter if (res) { 900251876Speter int ret = PQresultStatus(res); 901251876Speter PQclear(res); 902251876Speter if (!dbd_pgsql_is_success(ret)) { 903251876Speter sql->trans->errnum = ret; 904251876Speter return PGRES_FATAL_ERROR; 905251876Speter } 906251876Speter } else { 907251876Speter sql->trans->errnum = ret; 908251876Speter return PGRES_FATAL_ERROR; 909251876Speter } 910251876Speter } 911251876Speter } 912251876Speter if (!*results) { 913251876Speter *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); 914251876Speter } 915251876Speter (*results)->random = seek; 916251876Speter (*results)->handle = sql->conn; 917251876Speter (*results)->pool = pool; 918251876Speter } 919251876Speter 920251876Speter return ret; 921251876Speter} 922251876Speter 923251876Speterstatic int dbd_pgsql_pselect(apr_pool_t *pool, apr_dbd_t *sql, 924251876Speter apr_dbd_results_t **results, 925251876Speter apr_dbd_prepared_t *statement, 926251876Speter int seek, const char **values) 927251876Speter{ 928251876Speter int *len, *fmt; 929251876Speter const char **val; 930251876Speter 931251876Speter if (sql->trans && sql->trans->errnum) { 932251876Speter return sql->trans->errnum; 933251876Speter } 934251876Speter 935251876Speter val = apr_palloc(pool, sizeof(*val) * statement->nargs); 936251876Speter len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); 937251876Speter fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); 938251876Speter 939251876Speter dbd_pgsql_bind(statement, values, val, len, fmt); 940251876Speter 941251876Speter return dbd_pgsql_pselect_internal(pool, sql, results, statement, 942251876Speter seek, val, len, fmt); 943251876Speter} 944251876Speter 945251876Speterstatic int dbd_pgsql_pvselect(apr_pool_t *pool, apr_dbd_t *sql, 946251876Speter apr_dbd_results_t **results, 947251876Speter apr_dbd_prepared_t *statement, 948251876Speter int seek, va_list args) 949251876Speter{ 950251876Speter const char **values; 951251876Speter int i; 952251876Speter 953251876Speter if (sql->trans && sql->trans->errnum) { 954251876Speter return sql->trans->errnum; 955251876Speter } 956251876Speter 957251876Speter values = apr_palloc(pool, sizeof(*values) * statement->nvals); 958251876Speter 959251876Speter for (i = 0; i < statement->nvals; i++) { 960251876Speter values[i] = va_arg(args, const char*); 961251876Speter } 962251876Speter 963251876Speter return dbd_pgsql_pselect(pool, sql, results, statement, seek, values); 964251876Speter} 965251876Speter 966251876Speterstatic void dbd_pgsql_bbind(apr_pool_t *pool, apr_dbd_prepared_t * statement, 967251876Speter const void **values, 968251876Speter const char **val, int *len, int *fmt) 969251876Speter{ 970251876Speter int i, j; 971251876Speter apr_dbd_type_e type; 972251876Speter 973251876Speter for (i = 0, j = 0; i < statement->nargs; i++, j++) { 974251876Speter type = (values[j] == NULL ? APR_DBD_TYPE_NULL : statement->types[i]); 975251876Speter 976251876Speter switch (type) { 977251876Speter case APR_DBD_TYPE_TINY: 978251876Speter val[i] = apr_itoa(pool, *(char*)values[j]); 979251876Speter break; 980251876Speter case APR_DBD_TYPE_UTINY: 981251876Speter val[i] = apr_itoa(pool, *(unsigned char*)values[j]); 982251876Speter break; 983251876Speter case APR_DBD_TYPE_SHORT: 984251876Speter val[i] = apr_itoa(pool, *(short*)values[j]); 985251876Speter break; 986251876Speter case APR_DBD_TYPE_USHORT: 987251876Speter val[i] = apr_itoa(pool, *(unsigned short*)values[j]); 988251876Speter break; 989251876Speter case APR_DBD_TYPE_INT: 990251876Speter val[i] = apr_itoa(pool, *(int*)values[j]); 991251876Speter break; 992251876Speter case APR_DBD_TYPE_UINT: 993251876Speter val[i] = apr_itoa(pool, *(unsigned int*)values[j]); 994251876Speter break; 995251876Speter case APR_DBD_TYPE_LONG: 996251876Speter val[i] = apr_ltoa(pool, *(long*)values[j]); 997251876Speter break; 998251876Speter case APR_DBD_TYPE_ULONG: 999251876Speter val[i] = apr_ltoa(pool, *(unsigned long*)values[j]); 1000251876Speter break; 1001251876Speter case APR_DBD_TYPE_LONGLONG: 1002251876Speter val[i] = apr_psprintf(pool, "%" APR_INT64_T_FMT, 1003251876Speter *(apr_int64_t*)values[j]); 1004251876Speter break; 1005251876Speter case APR_DBD_TYPE_ULONGLONG: 1006251876Speter val[i] = apr_psprintf(pool, "%" APR_UINT64_T_FMT, 1007251876Speter *(apr_uint64_t*)values[j]); 1008251876Speter break; 1009251876Speter case APR_DBD_TYPE_FLOAT: 1010251876Speter val[i] = apr_psprintf(pool, "%f", *(float*)values[j]); 1011251876Speter break; 1012251876Speter case APR_DBD_TYPE_DOUBLE: 1013251876Speter val[i] = apr_psprintf(pool, "%lf", *(double*)values[j]); 1014251876Speter break; 1015251876Speter case APR_DBD_TYPE_STRING: 1016251876Speter case APR_DBD_TYPE_TEXT: 1017251876Speter case APR_DBD_TYPE_TIME: 1018251876Speter case APR_DBD_TYPE_DATE: 1019251876Speter case APR_DBD_TYPE_DATETIME: 1020251876Speter case APR_DBD_TYPE_TIMESTAMP: 1021251876Speter case APR_DBD_TYPE_ZTIMESTAMP: 1022251876Speter val[i] = values[j]; 1023251876Speter break; 1024251876Speter case APR_DBD_TYPE_BLOB: 1025251876Speter case APR_DBD_TYPE_CLOB: 1026251876Speter val[i] = (char*)values[j]; 1027251876Speter len[i] = *(apr_size_t*)values[++j]; 1028251876Speter fmt[i] = 1; 1029251876Speter 1030251876Speter /* skip table and column */ 1031251876Speter j += 2; 1032251876Speter break; 1033251876Speter case APR_DBD_TYPE_NULL: 1034251876Speter default: 1035251876Speter val[i] = NULL; 1036251876Speter break; 1037251876Speter } 1038251876Speter } 1039251876Speter 1040251876Speter return; 1041251876Speter} 1042251876Speter 1043251876Speterstatic int dbd_pgsql_pbquery(apr_pool_t * pool, apr_dbd_t * sql, 1044251876Speter int *nrows, apr_dbd_prepared_t * statement, 1045251876Speter const void **values) 1046251876Speter{ 1047251876Speter int *len, *fmt; 1048251876Speter const char **val; 1049251876Speter 1050251876Speter if (sql->trans && sql->trans->errnum) { 1051251876Speter return sql->trans->errnum; 1052251876Speter } 1053251876Speter 1054251876Speter val = apr_palloc(pool, sizeof(*val) * statement->nargs); 1055251876Speter len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); 1056251876Speter fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); 1057251876Speter 1058251876Speter dbd_pgsql_bbind(pool, statement, values, val, len, fmt); 1059251876Speter 1060251876Speter return dbd_pgsql_pquery_internal(pool, sql, nrows, statement, 1061251876Speter val, len, fmt); 1062251876Speter} 1063251876Speter 1064251876Speterstatic int dbd_pgsql_pvbquery(apr_pool_t * pool, apr_dbd_t * sql, 1065251876Speter int *nrows, apr_dbd_prepared_t * statement, 1066251876Speter va_list args) 1067251876Speter{ 1068251876Speter const void **values; 1069251876Speter int i; 1070251876Speter 1071251876Speter if (sql->trans && sql->trans->errnum) { 1072251876Speter return sql->trans->errnum; 1073251876Speter } 1074251876Speter 1075251876Speter values = apr_palloc(pool, sizeof(*values) * statement->nvals); 1076251876Speter 1077251876Speter for (i = 0; i < statement->nvals; i++) { 1078251876Speter values[i] = va_arg(args, const void*); 1079251876Speter } 1080251876Speter 1081251876Speter return dbd_pgsql_pbquery(pool, sql, nrows, statement, values); 1082251876Speter} 1083251876Speter 1084251876Speterstatic int dbd_pgsql_pbselect(apr_pool_t * pool, apr_dbd_t * sql, 1085251876Speter apr_dbd_results_t ** results, 1086251876Speter apr_dbd_prepared_t * statement, 1087251876Speter int seek, const void **values) 1088251876Speter{ 1089251876Speter int *len, *fmt; 1090251876Speter const char **val; 1091251876Speter 1092251876Speter if (sql->trans && sql->trans->errnum) { 1093251876Speter return sql->trans->errnum; 1094251876Speter } 1095251876Speter 1096251876Speter val = apr_palloc(pool, sizeof(*val) * statement->nargs); 1097251876Speter len = apr_pcalloc(pool, sizeof(*len) * statement->nargs); 1098251876Speter fmt = apr_pcalloc(pool, sizeof(*fmt) * statement->nargs); 1099251876Speter 1100251876Speter dbd_pgsql_bbind(pool, statement, values, val, len, fmt); 1101251876Speter 1102251876Speter return dbd_pgsql_pselect_internal(pool, sql, results, statement, 1103251876Speter seek, val, len, fmt); 1104251876Speter} 1105251876Speter 1106251876Speterstatic int dbd_pgsql_pvbselect(apr_pool_t * pool, apr_dbd_t * sql, 1107251876Speter apr_dbd_results_t ** results, 1108251876Speter apr_dbd_prepared_t * statement, int seek, 1109251876Speter va_list args) 1110251876Speter{ 1111251876Speter const void **values; 1112251876Speter int i; 1113251876Speter 1114251876Speter if (sql->trans && sql->trans->errnum) { 1115251876Speter return sql->trans->errnum; 1116251876Speter } 1117251876Speter 1118251876Speter values = apr_palloc(pool, sizeof(*values) * statement->nvals); 1119251876Speter 1120251876Speter for (i = 0; i < statement->nvals; i++) { 1121251876Speter values[i] = va_arg(args, const void*); 1122251876Speter } 1123251876Speter 1124251876Speter return dbd_pgsql_pbselect(pool, sql, results, statement, seek, values); 1125251876Speter} 1126251876Speter 1127251876Speterstatic int dbd_pgsql_start_transaction(apr_pool_t *pool, apr_dbd_t *handle, 1128251876Speter apr_dbd_transaction_t **trans) 1129251876Speter{ 1130251876Speter int ret = 0; 1131251876Speter PGresult *res; 1132251876Speter 1133251876Speter /* XXX handle recursive transactions here */ 1134251876Speter 1135251876Speter res = PQexec(handle->conn, "BEGIN TRANSACTION"); 1136251876Speter if (res) { 1137251876Speter ret = PQresultStatus(res); 1138251876Speter if (dbd_pgsql_is_success(ret)) { 1139251876Speter ret = 0; 1140251876Speter if (!*trans) { 1141251876Speter *trans = apr_pcalloc(pool, sizeof(apr_dbd_transaction_t)); 1142251876Speter } 1143251876Speter } 1144251876Speter PQclear(res); 1145251876Speter (*trans)->handle = handle; 1146251876Speter handle->trans = *trans; 1147251876Speter } 1148251876Speter else { 1149251876Speter ret = PGRES_FATAL_ERROR; 1150251876Speter } 1151251876Speter return ret; 1152251876Speter} 1153251876Speter 1154251876Speterstatic int dbd_pgsql_end_transaction(apr_dbd_transaction_t *trans) 1155251876Speter{ 1156251876Speter PGresult *res; 1157251876Speter int ret = -1; /* no transaction is an error cond */ 1158251876Speter if (trans) { 1159251876Speter /* rollback on error or explicit rollback request */ 1160251876Speter if (trans->errnum || TXN_DO_ROLLBACK(trans)) { 1161251876Speter trans->errnum = 0; 1162251876Speter res = PQexec(trans->handle->conn, "ROLLBACK"); 1163251876Speter } 1164251876Speter else { 1165251876Speter res = PQexec(trans->handle->conn, "COMMIT"); 1166251876Speter } 1167251876Speter if (res) { 1168251876Speter ret = PQresultStatus(res); 1169251876Speter if (dbd_pgsql_is_success(ret)) { 1170251876Speter ret = 0; 1171251876Speter } 1172251876Speter PQclear(res); 1173251876Speter } 1174251876Speter else { 1175251876Speter ret = PGRES_FATAL_ERROR; 1176251876Speter } 1177251876Speter trans->handle->trans = NULL; 1178251876Speter } 1179251876Speter return ret; 1180251876Speter} 1181251876Speter 1182251876Speterstatic int dbd_pgsql_transaction_mode_get(apr_dbd_transaction_t *trans) 1183251876Speter{ 1184251876Speter if (!trans) 1185251876Speter return APR_DBD_TRANSACTION_COMMIT; 1186251876Speter 1187251876Speter return trans->mode; 1188251876Speter} 1189251876Speter 1190251876Speterstatic int dbd_pgsql_transaction_mode_set(apr_dbd_transaction_t *trans, 1191251876Speter int mode) 1192251876Speter{ 1193251876Speter if (!trans) 1194251876Speter return APR_DBD_TRANSACTION_COMMIT; 1195251876Speter 1196251876Speter return trans->mode = (mode & TXN_MODE_BITS); 1197251876Speter} 1198251876Speter 1199251876Speterstatic void null_notice_receiver(void *arg, const PGresult *res) 1200251876Speter{ 1201251876Speter /* nothing */ 1202251876Speter} 1203251876Speter 1204251876Speterstatic void null_notice_processor(void *arg, const char *message) 1205251876Speter{ 1206251876Speter /* nothing */ 1207251876Speter} 1208251876Speter 1209251876Speterstatic apr_dbd_t *dbd_pgsql_open(apr_pool_t *pool, const char *params, 1210251876Speter const char **error) 1211251876Speter{ 1212251876Speter apr_dbd_t *sql; 1213251876Speter 1214251876Speter PGconn *conn = PQconnectdb(params); 1215251876Speter 1216251876Speter /* if there's an error in the connect string or something we get 1217251876Speter * back a * bogus connection object, and things like PQreset are 1218251876Speter * liable to segfault, so just close it out now. it would be nice 1219251876Speter * if we could give an indication of why we failed to connect... */ 1220251876Speter if (PQstatus(conn) != CONNECTION_OK) { 1221251876Speter if (error) { 1222251876Speter *error = apr_pstrdup(pool, PQerrorMessage(conn)); 1223251876Speter } 1224251876Speter PQfinish(conn); 1225251876Speter return NULL; 1226251876Speter } 1227251876Speter 1228251876Speter PQsetNoticeReceiver(conn, null_notice_receiver, NULL); 1229251876Speter PQsetNoticeProcessor(conn, null_notice_processor, NULL); 1230251876Speter 1231251876Speter sql = apr_pcalloc (pool, sizeof (*sql)); 1232251876Speter 1233251876Speter sql->conn = conn; 1234251876Speter 1235251876Speter return sql; 1236251876Speter} 1237251876Speter 1238251876Speterstatic apr_status_t dbd_pgsql_close(apr_dbd_t *handle) 1239251876Speter{ 1240251876Speter PQfinish(handle->conn); 1241251876Speter return APR_SUCCESS; 1242251876Speter} 1243251876Speter 1244251876Speterstatic apr_status_t dbd_pgsql_check_conn(apr_pool_t *pool, 1245251876Speter apr_dbd_t *handle) 1246251876Speter{ 1247251876Speter if (PQstatus(handle->conn) != CONNECTION_OK) { 1248251876Speter PQreset(handle->conn); 1249251876Speter if (PQstatus(handle->conn) != CONNECTION_OK) { 1250251876Speter return APR_EGENERAL; 1251251876Speter } 1252251876Speter } 1253251876Speter return APR_SUCCESS; 1254251876Speter} 1255251876Speter 1256251876Speterstatic int dbd_pgsql_select_db(apr_pool_t *pool, apr_dbd_t *handle, 1257251876Speter const char *name) 1258251876Speter{ 1259251876Speter return APR_ENOTIMPL; 1260251876Speter} 1261251876Speter 1262251876Speterstatic void *dbd_pgsql_native(apr_dbd_t *handle) 1263251876Speter{ 1264251876Speter return handle->conn; 1265251876Speter} 1266251876Speter 1267251876Speterstatic int dbd_pgsql_num_cols(apr_dbd_results_t* res) 1268251876Speter{ 1269251876Speter return res->sz; 1270251876Speter} 1271251876Speter 1272251876Speterstatic int dbd_pgsql_num_tuples(apr_dbd_results_t* res) 1273251876Speter{ 1274251876Speter if (res->random) { 1275251876Speter return res->ntuples; 1276251876Speter } 1277251876Speter else { 1278251876Speter return -1; 1279251876Speter } 1280251876Speter} 1281251876Speter 1282251876SpeterAPU_MODULE_DECLARE_DATA const apr_dbd_driver_t apr_dbd_pgsql_driver = { 1283251876Speter "pgsql", 1284251876Speter NULL, 1285251876Speter dbd_pgsql_native, 1286251876Speter dbd_pgsql_open, 1287251876Speter dbd_pgsql_check_conn, 1288251876Speter dbd_pgsql_close, 1289251876Speter dbd_pgsql_select_db, 1290251876Speter dbd_pgsql_start_transaction, 1291251876Speter dbd_pgsql_end_transaction, 1292251876Speter dbd_pgsql_query, 1293251876Speter dbd_pgsql_select, 1294251876Speter dbd_pgsql_num_cols, 1295251876Speter dbd_pgsql_num_tuples, 1296251876Speter dbd_pgsql_get_row, 1297251876Speter dbd_pgsql_get_entry, 1298251876Speter dbd_pgsql_error, 1299251876Speter dbd_pgsql_escape, 1300251876Speter dbd_pgsql_prepare, 1301251876Speter dbd_pgsql_pvquery, 1302251876Speter dbd_pgsql_pvselect, 1303251876Speter dbd_pgsql_pquery, 1304251876Speter dbd_pgsql_pselect, 1305251876Speter dbd_pgsql_get_name, 1306251876Speter dbd_pgsql_transaction_mode_get, 1307251876Speter dbd_pgsql_transaction_mode_set, 1308251876Speter "$%d", 1309251876Speter dbd_pgsql_pvbquery, 1310251876Speter dbd_pgsql_pvbselect, 1311251876Speter dbd_pgsql_pbquery, 1312251876Speter dbd_pgsql_pbselect, 1313251876Speter dbd_pgsql_datum_get 1314251876Speter}; 1315251876Speter#endif 1316