/*
  This file is part of TALER
  Copyright (C) 2014-2024 Taler Systems SA

  TALER 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.

  TALER 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
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file pg.c
 * @brief Low-level (statement-level) Postgres database access for the auditor
 * @author Christian Grothoff
 * @author Gabor X Toth
 */
struct TALER_AUDITORDB_PostgresContext;
#define GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE \
        struct TALER_AUDITORDB_PostgresContext
#include "taler/taler_pq_lib.h"
#include <pthread.h>
#include "auditordb_lib.h"
#include "pg_helper.h"


/**
 * Function called each time we connect or reconnect to the
 * database. Gives the application a chance to run some
 * per-connection initialization logic.
 *
 * @param pg database conntext in the auditor
 * @param pq database connection handle
 */
static void
reconnect_cb (struct TALER_AUDITORDB_PostgresContext *pg,
              struct GNUNET_PQ_Context *pq)
{
  struct GNUNET_PQ_ExecuteStatement es[] = {
    GNUNET_PQ_make_try_execute ("SET search_path TO auditor;"),
    GNUNET_PQ_EXECUTE_STATEMENT_END
  };

  if (GNUNET_OK !=
      GNUNET_PQ_exec_statements (pq,
                                 es))
  {
    GNUNET_break (0);
    return;
  }
  pg->prep_gen++;
}


/**
 * Connect to the db if the connection does not exist yet.
 *
 * @param[in,out] pg the database state
 * @return #GNUNET_OK on success
 */
static enum GNUNET_GenericReturnValue
setup_connection (struct TALER_AUDITORDB_PostgresContext *pg)
{
  struct GNUNET_PQ_Context *db_conn;

  if (NULL != pg->conn)
    return GNUNET_OK;
  db_conn = GNUNET_PQ_init (pg->cfg,
                            "auditordb-postgres",
                            &reconnect_cb,
                            pg);
  if (NULL == db_conn)
    return GNUNET_SYSERR;
  if (0 == pg->prep_gen)
  {
    GNUNET_PQ_disconnect (db_conn);
    return GNUNET_SYSERR;
  }
  pg->conn = db_conn;
  return GNUNET_OK;
}


struct TALER_AUDITORDB_PostgresContext *
TALER_AUDITORDB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  struct TALER_AUDITORDB_PostgresContext *pg;

  pg = GNUNET_new (struct TALER_AUDITORDB_PostgresContext);
  pg->cfg = cfg;
  if (GNUNET_OK !=
      TALER_config_get_currency (cfg,
                                 "exchange",
                                 &pg->currency))
  {
    GNUNET_free (pg);
    return NULL;
  }
  if (GNUNET_OK !=
      setup_connection (pg))
  {
    TALER_AUDITORDB_disconnect (pg);
    return NULL;
  }
  return pg;
}


void
TALER_AUDITORDB_disconnect (struct TALER_AUDITORDB_PostgresContext *pg)
{
  if (NULL == pg)
    return;
  if (NULL != pg->conn)
    GNUNET_PQ_disconnect (pg->conn);
  GNUNET_free (pg->currency);
  GNUNET_free (pg);
}


/* end of plugin_auditordb_postgres.c */
