/*
This file is part of GNUnet
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
GNUnet 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 3, or (at your option) any later version.
GNUnet 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
GNUnet; see the file COPYING. If not, If not, see
*/
/**
* @file pq/pq.c
* @brief helper functions for libpq (PostGres) interactions
* @author Sree Harsha Totakura
* @author Florian Dold
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_pq_lib.h"
/**
* Execute a prepared statement.
*
* @param db_conn database connection
* @param name name of the prepared statement
* @param params parameters to the statement
* @return postgres result
*/
PGresult *
GNUNET_PQ_exec_prepared (PGconn *db_conn,
const char *name,
const struct GNUNET_PQ_QueryParam *params)
{
unsigned int len;
unsigned int i;
/* count the number of parameters */
len = 0;
for (i=0;0 != params[i].num_params;i++)
len += params[i].num_params;
/* new scope to allow stack allocation without alloca */
{
/* Scratch buffer for temporary storage */
void *scratch[len];
/* Parameter array we are building for the query */
void *param_values[len];
int param_lengths[len];
int param_formats[len];
unsigned int off;
/* How many entries in the scratch buffer are in use? */
unsigned int soff;
PGresult *res;
int ret;
off = 0;
soff = 0;
for (i=0;0 != params[i].num_params;i++)
{
const struct GNUNET_PQ_QueryParam *x = ¶ms[i];
ret = x->conv (x->conv_cls,
x->data,
x->size,
¶m_values[off],
¶m_lengths[off],
¶m_formats[off],
x->num_params,
&scratch[soff],
len - soff);
if (ret < 0)
{
for (off = 0; off < soff; off++)
GNUNET_free (scratch[off]);
return NULL;
}
soff += ret;
off += x->num_params;
}
GNUNET_assert (off == len);
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
"pq",
"Executing prepared SQL statement `%s'\n",
name);
res = PQexecPrepared (db_conn,
name,
len,
(const char **) param_values,
param_lengths,
param_formats,
1);
for (off = 0; off < soff; off++)
GNUNET_free (scratch[off]);
return res;
}
}
/**
* Free all memory that was allocated in @a rs during
* #GNUNET_PQ_extract_result().
*
* @param rs reult specification to clean up
*/
void
GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs)
{
unsigned int i;
for (i=0; NULL != rs[i].conv; i++)
if (NULL != rs[i].cleaner)
rs[i].cleaner (rs[i].cls,
rs[i].dst);
}
/**
* Extract results from a query result according to the given
* specification.
*
* @param result result to process
* @param[in,out] rs result specification to extract for
* @param row row from the result to extract
* @return
* #GNUNET_YES if all results could be extracted
* #GNUNET_SYSERR if a result was invalid (non-existing field)
*/
int
GNUNET_PQ_extract_result (PGresult *result,
struct GNUNET_PQ_ResultSpec *rs,
int row)
{
unsigned int i;
int ret;
for (i=0; NULL != rs[i].conv; i++)
{
struct GNUNET_PQ_ResultSpec *spec;
spec = &rs[i];
ret = spec->conv (spec->cls,
result,
row,
spec->fname,
&spec->dst_size,
spec->dst);
if (GNUNET_OK != ret)
{
GNUNET_PQ_cleanup_result (rs);
return GNUNET_SYSERR;
}
if (NULL != spec->result_size)
*spec->result_size = spec->dst_size;
}
return GNUNET_OK;
}
/* end of pq/pq.c */