storage_pgsql.c
来自「这是一个完全开放的」· C语言 代码 · 共 639 行 · 第 1/2 页
C
639 行
/* * jabberd - Jabber Open Source Server * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA *//** @file sm/storage_pgsql.c * @brief postgresql storage module * @author Robert Norris * $Date: 2004/11/13 16:08:33 $ * $Revision: 1.18.2.6 $ */#include "sm.h"#ifdef STORAGE_PGSQL#include <libpq-fe.h>/** internal structure, holds our data */typedef struct drvdata_st { PGconn *conn; char *prefix; xht filters; int txn;} *drvdata_t;#define FALLBACK_BLOCKSIZE (4096)/** internal: do and return the math and ensure it gets realloc'd */static size_t _st_pgsql_realloc(void **oblocks, size_t len) { void *nblocks; size_t nlen; static size_t block_size = 0; if (block_size == 0) {#ifdef HAVE_GETPAGESIZE block_size = getpagesize();#elif defined(_SC_PAGESIZE) block_size = sysconf(_SC_PAGESIZE);#elif defined(_SC_PAGE_SIZE) block_size = sysconf(_SC_PAGE_SIZE); #else block_size = FALLBACK_BLOCKSIZE;#endif } /* round up to standard block sizes */ nlen = (((len-1)/block_size)+1)*block_size; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen;}/** this is the safety check used to make sure there's always enough mem */#define PGSQL_SAFE(blocks, size, len) if((size) >= len) len = _st_pgsql_realloc((void**)&(blocks),(size + 1));static void _st_pgsql_convert_filter_recursive(st_driver_t drv, st_filter_t f, char **buf, int *buflen, int *nbuf) { drvdata_t data = (drvdata_t) drv->private; st_filter_t scan; int vlen; char *cval; switch(f->type) { case st_filter_type_PAIR: /* do sql escaping for apostrophes */ cval = (char *) malloc(sizeof(char) * ((strlen(f->val) * 2) + 1)); vlen = PQescapeString(cval, f->val, strlen(f->val)); PGSQL_SAFE((*buf), *buflen + 12 + vlen - strlen(f->val), *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( \"%s\" = \'%s\' ) ", f->key, f->val); free(cval); break; case st_filter_type_AND: PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_pgsql_convert_filter_recursive(drv, scan, buf, buflen, nbuf); if(scan->next != NULL) { PGSQL_SAFE((*buf), *buflen + 4, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "AND "); } } PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_OR: PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( "); for(scan = f->sub; scan != NULL; scan = scan->next) { _st_pgsql_convert_filter_recursive(drv, scan, buf, buflen, nbuf); if(scan->next != NULL) { PGSQL_SAFE((*buf), *buflen + 3, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "OR "); } } PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; case st_filter_type_NOT: PGSQL_SAFE((*buf), *buflen + 6, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), "( NOT "); _st_pgsql_convert_filter_recursive(drv, f->sub, buf, buflen, nbuf); PGSQL_SAFE((*buf), *buflen + 2, *buflen); *nbuf += sprintf(&((*buf)[*nbuf]), ") "); return; }}static char *_st_pgsql_convert_filter(st_driver_t drv, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; char *buf = NULL, *sbuf = NULL, *cfilter; int buflen = 0, nbuf = 0, fbuf; st_filter_t f; PGSQL_SAFE(buf, 24 + strlen(owner), buflen); nbuf = sprintf(buf, "\"collection-owner\" = '%s'", owner); sbuf = xhash_get(data->filters, filter); if(sbuf != NULL) { PGSQL_SAFE(buf, buflen + strlen(sbuf) + 7, buflen); nbuf += sprintf(&buf[nbuf], " AND %s", sbuf); return buf; } cfilter = pstrdup(xhash_pool(data->filters), filter); f = storage_filter(filter); if(f == NULL) return buf; PGSQL_SAFE(buf, buflen + 5, buflen); nbuf += sprintf(&buf[nbuf], " AND "); fbuf = nbuf; _st_pgsql_convert_filter_recursive(drv, f, &buf, &buflen, &nbuf); xhash_put(data->filters, cfilter, pstrdup(xhash_pool(data->filters), &buf[fbuf])); pool_free(f->p); return buf;}static st_ret_t _st_pgsql_add_type(st_driver_t drv, const char *type) { return st_SUCCESS;}static st_ret_t _st_pgsql_put_guts(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; char *left = NULL, *right = NULL; int lleft = 0, lright = 0, nleft, nright; os_object_t o; char *key, *cval = NULL; void *val; int vlen; os_type_t ot; char *xml; int xlen; PGresult *res; char tbuf[128]; if(os_count(os) == 0) return st_SUCCESS; if(data->prefix != NULL) { snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); type = tbuf; } if(os_iter_first(os)) do { PGSQL_SAFE(left, strlen(type) + 55, lleft); nleft = sprintf(left, "INSERT INTO \"%s\" ( \"collection-owner\", \"object-sequence\"", type); PGSQL_SAFE(right, strlen(owner) + 43, lright); nright = sprintf(right, " ) VALUES ( '%s', nextval('object-sequence')", owner); o = os_iter_object(os); if(os_object_iter_first(o)) do { os_object_iter_get(o, &key, &val, &ot); switch(ot) { case os_type_BOOLEAN: cval = val ? strdup("t") : strdup("f"); vlen = 1; break; case os_type_INTEGER: cval = (char *) malloc(sizeof(char) * 20); sprintf(cval, "%d", (int) val); vlen = strlen(cval); break; case os_type_STRING: cval = (char *) malloc(sizeof(char) * ((strlen((char *) val) * 2) + 1)); vlen = PQescapeString(cval, (char *) val, strlen((char *) val)); break; /* !!! might not be a good idea to mark nads this way */ case os_type_NAD: nad_print((nad_t) val, 0, &xml, &xlen); cval = (char *) malloc(sizeof(char) * ((xlen * 2) + 4)); vlen = PQescapeString(&cval[3], xml, xlen) + 3; strncpy(cval, "NAD", 3); break; } log_debug(ZONE, "key %s val %s", key, cval); PGSQL_SAFE(left, lleft + strlen(key) + 4, lleft); nleft += sprintf(&left[nleft], ", \"%s\"", key); PGSQL_SAFE(right, lright + strlen(cval) + 4, lright); nright += sprintf(&right[nright], ", '%s'", cval); free(cval); } while(os_object_iter_next(o)); PGSQL_SAFE(left, lleft + strlen(right) + 3, lleft); sprintf(&left[nleft], "%s );", right); log_debug(ZONE, "prepared sql: %s", left); res = PQexec(data->conn, left); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->sm->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, left); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->sm->log, LOG_ERR, "pgsql: sql insert failed: %s", PQresultErrorMessage(res)); free(left); free(right); PQclear(res); return st_FAILED; } PQclear(res); } while(os_iter_next(os)); free(left); free(right); return st_SUCCESS;}static st_ret_t _st_pgsql_put(st_driver_t drv, const char *type, const char *owner, os_t os) { drvdata_t data = (drvdata_t) drv->private; PGresult *res; if(os_count(os) == 0) return st_SUCCESS; if(data->txn) { res = PQexec(data->conn, "BEGIN;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->sm->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "BEGIN;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->sm->log, LOG_ERR, "pgsql: sql transaction begin failed: %s", PQresultErrorMessage(res)); PQclear(res); return st_FAILED; } PQclear(res); res = PQexec(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); if(PQresultStatus(res) != PGRES_COMMAND_OK && PQstatus(data->conn) != CONNECTION_OK) { log_write(drv->st->sm->log, LOG_ERR, "pgsql: lost connection to database, attempting reconnect"); PQclear(res); PQreset(data->conn); res = PQexec(data->conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); } if(PQresultStatus(res) != PGRES_COMMAND_OK) { log_write(drv->st->sm->log, LOG_ERR, "pgsql: sql transaction setup failed: %s", PQresultErrorMessage(res)); PQclear(res); PQclear(PQexec(data->conn, "ROLLBACK;")); return st_FAILED;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?