📄 apr_dbd_pgsql.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include "apu.h"#if APU_HAVE_PGSQL#include "apu_config.h"#include <ctype.h>#include <stdlib.h>#ifdef HAVE_LIBPQ_FE_H#include <libpq-fe.h>#elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H)#include <postgresql/libpq-fe.h>#endif#include "apr_strings.h"#include "apr_time.h"#include "apr_buckets.h"#include "apr_dbd_internal.h"struct apr_dbd_transaction_t { int mode; int errnum; apr_dbd_t *handle;};struct apr_dbd_t { PGconn *conn; apr_dbd_transaction_t *trans;};struct apr_dbd_results_t { int random; PGconn *handle; PGresult *res; size_t ntuples; size_t sz; size_t index; apr_pool_t *pool;};struct apr_dbd_row_t { int n; apr_dbd_results_t *res;};struct apr_dbd_prepared_t { const char *name; int prepared; int nargs; int nvals; apr_dbd_type_e *types;};#define dbd_pgsql_is_success(x) (((x) == PGRES_EMPTY_QUERY) \ || ((x) == PGRES_COMMAND_OK) \ || ((x) == PGRES_TUPLES_OK))static apr_status_t clear_result(void *data){ PQclear(data); return APR_SUCCESS;}static int dbd_pgsql_select(apr_pool_t *pool, apr_dbd_t *sql, apr_dbd_results_t **results, const char *query, int seek){ PGresult *res; int ret; if ( sql->trans && sql->trans->errnum ) { return sql->trans->errnum; } if (seek) { /* synchronous query */ if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } res = PQexec(sql->conn, query); if (res) { ret = PQresultStatus(res); if (dbd_pgsql_is_success(ret)) { ret = 0; } else { PQclear(res); } } else { ret = PGRES_FATAL_ERROR; } if (ret != 0) { if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } else if (TXN_NOTICE_ERRORS(sql->trans)){ sql->trans->errnum = ret; } return ret; } else { if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "RELEASE SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } } if (!*results) { *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); } (*results)->res = res; (*results)->ntuples = PQntuples(res); (*results)->sz = PQnfields(res); (*results)->random = seek; (*results)->pool = pool; apr_pool_cleanup_register(pool, res, clear_result, apr_pool_cleanup_null); } else { if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } if (PQsendQuery(sql->conn, query) == 0) { if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } else if (TXN_NOTICE_ERRORS(sql->trans)){ sql->trans->errnum = 1; } return 1; } else { if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "RELEASE SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } } if (*results == NULL) { *results = apr_pcalloc(pool, sizeof(apr_dbd_results_t)); } (*results)->random = seek; (*results)->handle = sql->conn; (*results)->pool = pool; } return 0;}static const char *dbd_pgsql_get_name(const apr_dbd_results_t *res, int n){ return (res->res ? PQfname(res->res, n) : NULL);}static int dbd_pgsql_get_row(apr_pool_t *pool, apr_dbd_results_t *res, apr_dbd_row_t **rowp, int rownum){ apr_dbd_row_t *row = *rowp; int sequential = ((rownum >= 0) && res->random) ? 0 : 1; if (row == NULL) { row = apr_palloc(pool, sizeof(apr_dbd_row_t)); *rowp = row; row->res = res; if ( sequential ) { row->n = 0; } else { if (rownum > 0) { row->n = --rownum; } else { return -1; /* invalid row */ } } } else { if ( sequential ) { ++row->n; } else { if (rownum > 0) { row->n = --rownum; } else { return -1; /* invalid row */ } } } if (res->random) { if ((row->n >= 0) && (size_t)row->n >= res->ntuples) { *rowp = NULL; apr_pool_cleanup_run(pool, res->res, clear_result); res->res = NULL; return -1; } } else { if ((row->n >= 0) && (size_t)row->n >= res->ntuples) { /* no data; we have to fetch some */ row->n -= res->ntuples; if (res->res != NULL) { PQclear(res->res); } res->res = PQgetResult(res->handle); if (res->res) { res->ntuples = PQntuples(res->res); while (res->ntuples == 0) { /* if we got an empty result, clear it, wait a mo, try * again */ PQclear(res->res); apr_sleep(100000); /* 0.1 secs */ res->res = PQgetResult(res->handle); if (res->res) { res->ntuples = PQntuples(res->res); } else { return -1; } } if (res->sz == 0) { res->sz = PQnfields(res->res); } } else { return -1; } } } return 0;}static const char *dbd_pgsql_get_entry(const apr_dbd_row_t *row, int n){ return PQgetvalue(row->res->res, row->n, n);}static apr_status_t dbd_pgsql_datum_get(const apr_dbd_row_t *row, int n, apr_dbd_type_e type, void *data){ if (PQgetisnull(row->res->res, row->n, n)) { return APR_ENOENT; } switch (type) { case APR_DBD_TYPE_TINY: *(char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_UTINY: *(unsigned char*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_SHORT: *(short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_USHORT: *(unsigned short*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_INT: *(int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_UINT: *(unsigned int*)data = atoi(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_LONG: *(long*)data = atol(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_ULONG: *(unsigned long*)data = atol(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_LONGLONG: *(apr_int64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_ULONGLONG: *(apr_uint64_t*)data = apr_atoi64(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_FLOAT: *(float*)data = (float)atof(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_DOUBLE: *(double*)data = atof(PQgetvalue(row->res->res, row->n, n)); break; case APR_DBD_TYPE_STRING: case APR_DBD_TYPE_TEXT: case APR_DBD_TYPE_TIME: case APR_DBD_TYPE_DATE: case APR_DBD_TYPE_DATETIME: case APR_DBD_TYPE_TIMESTAMP: case APR_DBD_TYPE_ZTIMESTAMP: *(char**)data = PQgetvalue(row->res->res, row->n, n); break; case APR_DBD_TYPE_BLOB: case APR_DBD_TYPE_CLOB: { apr_bucket *e; apr_bucket_brigade *b = (apr_bucket_brigade*)data; e = apr_bucket_pool_create(PQgetvalue(row->res->res, row->n, n), PQgetlength(row->res->res, row->n, n), row->res->pool, b->bucket_alloc); APR_BRIGADE_INSERT_TAIL(b, e); } break; case APR_DBD_TYPE_NULL: *(void**)data = NULL; break; default: return APR_EGENERAL; } return APR_SUCCESS;}static const char *dbd_pgsql_error(apr_dbd_t *sql, int n){ return PQerrorMessage(sql->conn);}static int dbd_pgsql_query(apr_dbd_t *sql, int *nrows, const char *query){ PGresult *res; int ret; if (sql->trans && sql->trans->errnum) { return sql->trans->errnum; } if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { return sql->trans->errnum = PGRES_FATAL_ERROR; } } res = PQexec(sql->conn, query); if (res) { ret = PQresultStatus(res); if (dbd_pgsql_is_success(ret)) { /* ugh, making 0 return-success doesn't fit */ ret = 0; } *nrows = atoi(PQcmdTuples(res)); PQclear(res); } else { ret = PGRES_FATAL_ERROR; } if (ret != 0){ if (TXN_IGNORE_ERRORS(sql->trans)) { PGresult *res = PQexec(sql->conn, "ROLLBACK TO SAVEPOINT APR_DBD_TXN_SP"); if (res) { ret = PQresultStatus(res); PQclear(res); if (!dbd_pgsql_is_success(ret)) { sql->trans->errnum = ret; return PGRES_FATAL_ERROR; } } else { sql->trans->errnum = ret; return PGRES_FATAL_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -