2010-09-16 17:11:46 +02:00
|
|
|
/*
|
|
|
|
* =====================================================================================
|
|
|
|
*
|
|
|
|
* Filename: postgresql.c
|
|
|
|
*
|
|
|
|
* Description: Interface to a PostgreSQL database
|
|
|
|
*
|
|
|
|
* Version: 0.1
|
|
|
|
* Created: 16/09/2010 00:23:34
|
|
|
|
* Revision: none
|
|
|
|
* Compiler: gcc
|
|
|
|
*
|
|
|
|
* Author: BlackLight (http://0x00.ath.cx), <blacklight@autistici.org>
|
|
|
|
* Licence: GNU GPL v.3
|
|
|
|
* Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE!
|
|
|
|
*
|
|
|
|
* =====================================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spp_ai.h"
|
|
|
|
#ifdef HAVE_LIBPQ
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
#include "db.h"
|
|
|
|
|
2010-09-16 17:11:46 +02:00
|
|
|
#include <alloca.h>
|
|
|
|
#include <postgresql/libpq-fe.h>
|
|
|
|
|
|
|
|
/** \defgroup postgresql Module for the interface with a PostgreSQL DBMS
|
|
|
|
* @{ */
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
/***************************/
|
|
|
|
/* Database descriptors */
|
|
|
|
PRIVATE PGconn *db = NULL;
|
|
|
|
PRIVATE PGconn *outdb = NULL;
|
|
|
|
/***************************/
|
2010-09-16 17:11:46 +02:00
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
/*************************************************************/
|
|
|
|
/* Private functions (operating on the database descriptors) */
|
|
|
|
|
|
|
|
PRIVATE BOOL
|
|
|
|
__postgresql_is_init ( PGconn *__DB )
|
|
|
|
{
|
|
|
|
return ( __DB != NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
PRIVATE void*
|
|
|
|
__postgresql_do_init ( PGconn **__DB, BOOL is_out )
|
2010-09-16 17:11:46 +02:00
|
|
|
{
|
|
|
|
char *conninfo = NULL;
|
|
|
|
int conninfo_max_length =
|
2010-10-01 19:32:34 +02:00
|
|
|
( is_out ?
|
|
|
|
((config->outdbhost) ? strlen ( config->outdbhost ) : 0) +
|
|
|
|
((config->outdbuser) ? strlen ( config->outdbuser ) : 0) +
|
|
|
|
((config->outdbpass) ? strlen ( config->outdbpass ) : 0) +
|
|
|
|
((config->outdbname) ? strlen ( config->outdbname ) : 0) :
|
|
|
|
|
|
|
|
((config->dbhost) ? strlen ( config->dbhost ) : 0) +
|
|
|
|
((config->dbuser) ? strlen ( config->dbuser ) : 0) +
|
|
|
|
((config->dbpass) ? strlen ( config->dbpass ) : 0) +
|
|
|
|
((config->dbname) ? strlen ( config->dbname ) : 0)) + 100;
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
if ( __postgresql_is_init ( *__DB ))
|
2010-10-01 19:32:34 +02:00
|
|
|
return (void*) *__DB;
|
|
|
|
|
2010-09-16 17:11:46 +02:00
|
|
|
if ( !( conninfo = (char*) alloca ( conninfo_max_length )))
|
2010-10-03 04:18:43 +02:00
|
|
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
2010-09-16 17:11:46 +02:00
|
|
|
|
|
|
|
memset ( conninfo, 0, conninfo_max_length );
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
if ( is_out )
|
|
|
|
{
|
|
|
|
snprintf ( conninfo, conninfo_max_length, "dbname=%s", config->outdbname );
|
|
|
|
|
|
|
|
if ( config->outdbuser )
|
2010-10-05 04:01:35 +02:00
|
|
|
{
|
|
|
|
if ( strlen ( config->outdbuser ) != 0 )
|
|
|
|
{
|
|
|
|
sprintf ( conninfo, "%s user=%s", conninfo, config->outdbuser );
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 19:32:34 +02:00
|
|
|
|
|
|
|
if ( config->outdbpass )
|
2010-10-05 04:01:35 +02:00
|
|
|
{
|
|
|
|
if ( strlen ( config->outdbpass ) != 0 )
|
|
|
|
{
|
|
|
|
sprintf ( conninfo, "%s password=%s", conninfo, config->outdbpass );
|
|
|
|
}
|
|
|
|
}
|
2010-09-16 17:11:46 +02:00
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
if ( config->outdbhost )
|
2010-10-05 04:01:35 +02:00
|
|
|
{
|
|
|
|
if ( strlen ( config->outdbhost ) != 0 )
|
|
|
|
{
|
|
|
|
sprintf ( conninfo, "%s hostaddr=%s", conninfo, config->outdbhost );
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 19:32:34 +02:00
|
|
|
} else {
|
|
|
|
snprintf ( conninfo, conninfo_max_length, "dbname=%s", config->dbname );
|
2010-09-16 17:11:46 +02:00
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
if ( config->dbuser )
|
2010-10-05 04:01:35 +02:00
|
|
|
{
|
|
|
|
if ( strlen ( config->dbuser ) != 0 )
|
|
|
|
{
|
|
|
|
sprintf ( conninfo, "%s user=%s", conninfo, config->dbuser );
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 19:32:34 +02:00
|
|
|
|
|
|
|
if ( config->dbpass )
|
2010-10-05 04:01:35 +02:00
|
|
|
{
|
|
|
|
if ( strlen ( config->dbpass ) != 0 )
|
|
|
|
{
|
|
|
|
sprintf ( conninfo, "%s password=%s", conninfo, config->dbpass );
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 19:32:34 +02:00
|
|
|
|
|
|
|
if ( config->dbhost )
|
2010-10-05 04:01:35 +02:00
|
|
|
{
|
|
|
|
if ( strlen ( config->dbhost ) != 0 )
|
|
|
|
{
|
|
|
|
sprintf ( conninfo, "%s hostaddr=%s", conninfo, config->dbhost );
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 19:32:34 +02:00
|
|
|
}
|
2010-09-16 17:11:46 +02:00
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
if ( PQstatus ( *__DB = PQconnectdb ( conninfo )) != CONNECTION_OK )
|
2010-09-16 17:11:46 +02:00
|
|
|
return NULL;
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
return (void*) *__DB;
|
2010-09-16 17:11:46 +02:00
|
|
|
}
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
PRIVATE PSQL_result*
|
|
|
|
__postgresql_do_query ( PGconn *__DB, const char *query )
|
2010-09-16 17:11:46 +02:00
|
|
|
{
|
|
|
|
int i, j, ntuples, nfields;
|
|
|
|
PSQL_result *res = NULL;
|
|
|
|
|
|
|
|
if ( !( res = (PSQL_result*) malloc ( sizeof ( PSQL_result ))))
|
2010-10-03 04:18:43 +02:00
|
|
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
2010-09-16 17:11:46 +02:00
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
if ( PQresultStatus ( res->res = PQexec( __DB, query )) != PGRES_TUPLES_OK )
|
2010-09-16 17:11:46 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ntuples = PQntuples ( res->res );
|
|
|
|
res->index = 0;
|
|
|
|
res->rows = NULL;
|
|
|
|
|
|
|
|
if ( !( res->rows = ( char*** ) malloc ( ntuples * sizeof ( char** ))))
|
2010-10-03 04:18:43 +02:00
|
|
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
2010-09-16 17:11:46 +02:00
|
|
|
|
|
|
|
for ( i=0; i < ntuples; i++ )
|
|
|
|
{
|
|
|
|
nfields = PQnfields ( res->res );
|
|
|
|
|
|
|
|
if ( !( res->rows[i] = ( char** ) malloc ( nfields * sizeof ( char* ))))
|
2010-10-03 04:18:43 +02:00
|
|
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
2010-09-16 17:11:46 +02:00
|
|
|
|
|
|
|
for ( j=0; j < nfields; j++ )
|
|
|
|
{
|
|
|
|
res->rows[i][j] = PQgetvalue ( res->res, i, j );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
PRIVATE void
|
|
|
|
__postgresql_do_close ( PGconn **__DB )
|
|
|
|
{
|
|
|
|
if ( *__DB )
|
|
|
|
PQfinish ( *__DB );
|
|
|
|
|
|
|
|
*__DB = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* End of private functions */
|
|
|
|
/****************************/
|
|
|
|
|
|
|
|
/********************/
|
|
|
|
/* Public functions */
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
postgresql_is_init ()
|
|
|
|
{
|
|
|
|
return __postgresql_is_init ( db );
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
postgresql_do_init ()
|
|
|
|
{
|
|
|
|
return __postgresql_do_init ( &db, false );
|
|
|
|
}
|
|
|
|
|
|
|
|
PSQL_result*
|
|
|
|
postgresql_do_query ( const char *query )
|
|
|
|
{
|
|
|
|
return __postgresql_do_query ( db, query );
|
|
|
|
}
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
unsigned long
|
|
|
|
postgresql_do_escape_string ( char **to, const char *from, unsigned long length )
|
|
|
|
{
|
|
|
|
size_t out_len = 0;
|
2010-11-23 18:42:20 +01:00
|
|
|
|
|
|
|
if ( !from )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ( strlen ( from ) == 0 )
|
|
|
|
return 0;
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
*to = (char*) PQescapeByteaConn ( db, (const unsigned char* ) from, (size_t) length, &out_len );
|
|
|
|
return (unsigned long) out_len;
|
|
|
|
}
|
|
|
|
|
2010-09-16 17:11:46 +02:00
|
|
|
void
|
|
|
|
postgresql_do_close ()
|
|
|
|
{
|
2010-10-01 19:32:34 +02:00
|
|
|
__postgresql_do_close ( &db );
|
|
|
|
}
|
2010-09-16 17:11:46 +02:00
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
/* Output database functions */
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
postgresql_is_out_init ()
|
|
|
|
{
|
|
|
|
return __postgresql_is_init ( outdb );
|
2010-09-16 17:11:46 +02:00
|
|
|
}
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
void*
|
|
|
|
postgresql_do_out_init ()
|
|
|
|
{
|
|
|
|
return __postgresql_do_init ( &outdb, true );
|
|
|
|
}
|
|
|
|
|
|
|
|
PSQL_result*
|
|
|
|
postgresql_do_out_query ( const char *query )
|
|
|
|
{
|
|
|
|
return __postgresql_do_query ( outdb, query );
|
|
|
|
}
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
unsigned long
|
|
|
|
postgresql_do_out_escape_string ( char **to, const char *from, unsigned long length )
|
|
|
|
{
|
|
|
|
size_t out_len = 0;
|
2010-11-23 18:42:20 +01:00
|
|
|
|
|
|
|
if ( !from )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ( strlen ( from ) == 0 )
|
|
|
|
return 0;
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
*to = (char*) PQescapeByteaConn ( outdb, (const unsigned char* ) from, (size_t) length, &out_len );
|
|
|
|
return (unsigned long) out_len;
|
|
|
|
}
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
void
|
|
|
|
postgresql_do_out_close ()
|
|
|
|
{
|
|
|
|
__postgresql_do_close ( &outdb );
|
|
|
|
}
|
|
|
|
|
2010-10-04 17:48:07 +02:00
|
|
|
/* Functions working on result sets */
|
|
|
|
|
|
|
|
int
|
|
|
|
postgresql_num_rows ( PSQL_result *res )
|
|
|
|
{
|
|
|
|
return PQntuples ( res->res );
|
|
|
|
}
|
|
|
|
|
|
|
|
char**
|
|
|
|
postgresql_fetch_row ( PSQL_result *res )
|
|
|
|
{
|
|
|
|
if ( (res->index++) >= PQntuples ( res->res ))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return res->rows[ res->index - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
postgresql_free_result ( PSQL_result *res )
|
|
|
|
{
|
|
|
|
int i, ntuples;
|
|
|
|
|
|
|
|
if ( res )
|
|
|
|
{
|
|
|
|
ntuples = PQntuples ( res->res );
|
|
|
|
|
|
|
|
for ( i=0; i < ntuples; i++ )
|
|
|
|
free ( res->rows[i] );
|
|
|
|
free ( res->rows );
|
|
|
|
|
|
|
|
PQclear ( res->res );
|
|
|
|
free ( res );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-01 19:32:34 +02:00
|
|
|
/* End of public functions */
|
|
|
|
/***************************/
|
|
|
|
|
2010-09-16 17:11:46 +02:00
|
|
|
/* @} */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|