/* * Copyright (C) 2007 Tildeslash Ltd. All rights reserved. * * 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. * * There are special exceptions to the terms and conditions of the GPL * as it is applied to this software. View the full text of the exception * in the file EXCEPTIONS accompanying this software distribution. * * 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, MA 02111-1307 USA */ #include "Config.h" #include #include #include #include #include "Util.h" #include "ResultSet.h" #include "PostgresqlResultSet.h" #include "PreparedStatementStrategy.h" #include "PostgresqlPreparedStatement.h" /** * Implementation of the PreparedStatement/Strategy interface for postgresql. * * @version \$Id: PostgresqlPreparedStatement.c,v 1.6 2007/02/11 11:18:55 hauk Exp $ * @file */ /* ----------------------------------------------------------- Definitions */ const struct prepop postgresqlprepops= { "postgresql", PostgresqlPreparedStatement_free, PostgresqlPreparedStatement_setString, PostgresqlPreparedStatement_setInt, PostgresqlPreparedStatement_setLLong, PostgresqlPreparedStatement_setDouble, PostgresqlPreparedStatement_setBlob, PostgresqlPreparedStatement_execute, PostgresqlPreparedStatement_executeQuery }; #define T IPreparedStatement_T struct T { int maxRows; int lastError; char *stmt; PGconn *db; PGresult *res; int paramCount; char **paramValues; int *paramLengths; int *paramFormats; }; #ifndef net_buffer_length #define net_buffer_length 4096 #endif #define TEST_INDEX \ int i; assert(P); i= parameterIndex - 1; if(P->paramCount <= 0 || \ i < 0 || i > P->paramCount) return FALSE; extern const struct rsetop postgresqlrsetops; /* ----------------------------------------------------- Protected methods */ #ifdef PACKAGE_PROTECTED #pragma GCC visibility push(hidden) #endif T PostgresqlPreparedStatement_new(PGconn *db, int maxRows, char *stmt, int prm) { T P; assert(stmt); NEW(P); P->maxRows = maxRows; P->lastError = PGRES_COMMAND_OK; P->stmt = stmt; P->db = db; P->res = NULL; P->paramCount = prm; if(P->paramCount) { P->paramValues = CALLOC(prm, sizeof(char *)); P->paramLengths = CALLOC(prm, sizeof(int)); P->paramFormats = CALLOC(prm, sizeof(int)); } return P; } void PostgresqlPreparedStatement_free(T *P) { char stmt[STRLEN]; assert(P && *P); /* NOTE: there is no C API function for explicit statement * deallocation (postgres-8.1.x) - the DEALLOCATE statement * has to be used. The postgres documentation mentiones such * function as a possible future extension */ snprintf(stmt, STRLEN, "DEALLOCATE %s;", (*P)->stmt); PQclear(PQexec((*P)->db, stmt)); PQclear((*P)->res); FREE((*P)->stmt); if((*P)->paramCount) { int i; for(i = 0; i < (*P)->paramCount; i++) { if((*P)->paramFormats[i] == 0) { FREE((*P)->paramValues[i]); } } FREE((*P)->paramValues); FREE((*P)->paramLengths); FREE((*P)->paramFormats); } FREE(*P); } int PostgresqlPreparedStatement_setString(T P, int parameterIndex, const char *x) { TEST_INDEX FREE(P->paramValues[i]); P->paramValues[i] = Util_strdup(x); P->paramLengths[i] = strlen(P->paramValues[i]); P->paramFormats[i] = 0; return TRUE; } int PostgresqlPreparedStatement_setInt(T P, int parameterIndex, int x) { TEST_INDEX FREE(P->paramValues[i]); P->paramValues[i] = Util_getString("%d", x); P->paramLengths[i] = strlen(P->paramValues[i]); P->paramFormats[i] = 0; return TRUE; } int PostgresqlPreparedStatement_setLLong(T P, int parameterIndex, long long int x) { TEST_INDEX FREE(P->paramValues[i]); P->paramValues[i] = Util_getString("%lld", x); P->paramLengths[i] = strlen(P->paramValues[i]); P->paramFormats[i] = 0; return TRUE; } int PostgresqlPreparedStatement_setDouble(T P, int parameterIndex, double x) { TEST_INDEX FREE(P->paramValues[i]); P->paramValues[i] = Util_getString("%lf", x); P->paramLengths[i] = strlen(P->paramValues[i]); P->paramFormats[i] = 0; return TRUE; } int PostgresqlPreparedStatement_setBlob(T P, int parameterIndex, const void *x, int size) { TEST_INDEX if(x==NULL) { P->paramValues[i] = NULL; P->paramLengths[i] = 0; } else { P->paramValues[i] = (char *)x; P->paramLengths[i] = size; } P->paramFormats[i] = 1; return TRUE; } int PostgresqlPreparedStatement_execute(T P) { assert(P); PQclear(P->res); P->res = PQexecPrepared(P->db, P->stmt, P->paramCount, (const char **)P->paramValues, P->paramLengths, P->paramFormats, 0); P->lastError= PQresultStatus(P->res); return(P->lastError == PGRES_COMMAND_OK); } ResultSet_T PostgresqlPreparedStatement_executeQuery(T P) { assert(P); PQclear(P->res); P->res = PQexecPrepared(P->db, P->stmt, P->paramCount, (const char **)P->paramValues, P->paramLengths, P->paramFormats, 0); P->lastError= PQresultStatus(P->res); if(P->lastError == PGRES_TUPLES_OK) { return ResultSet_new(PostgresqlResultSet_new(P->res, P->maxRows, TRUE), (Rop_T)&postgresqlrsetops); } return NULL; } #ifdef PACKAGE_PROTECTED #pragma GCC visibility pop #endif