/*
   This file is part of TALER
   Copyright (C) 2023 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_helper.h
 * @brief shared internal definitions for postgres DB plugin
 * @author Christian Grothoff
 */
#ifndef PG_HELPER_H
#define PG_HELPER_H

#include <gnunet/gnunet_db_lib.h>

/**
 * Type of the "cls" argument given to each of the functions in
 * our API.
 */
struct PostgresClosure
{

  /**
   * Postgres connection handle.
   */
  struct GNUNET_PQ_Context *conn;

  /**
   * Directory with SQL statements to run to create tables.
   */
  char *sql_dir;

  /**
   * Underlying configuration.
   */
  const struct GNUNET_CONFIGURATION_Handle *cfg;

  /**
   * Name of the currently active transaction, NULL if none is active.
   */
  const char *transaction_name;

  /**
   * How many times have we connected to the DB.
   */
  uint64_t prep_gen;

};


/**
 * Prepares SQL statement @a sql under @a name for
 * connection @a pg once.
 * Returns with #GNUNET_DB_STATUS_HARD_ERROR on failure.
 *
 * @param pg a `struct PostgresClosure`
 * @param name name to prepare the statement under
 * @param sql actual SQL text
 */
#define PREPARE(pg,name,sql)                      \
  do {                                            \
    static unsigned long long gen;                \
                                                  \
    if (gen < pg->prep_gen)                       \
    {                                             \
      struct GNUNET_PQ_PreparedStatement ps[] = { \
        GNUNET_PQ_make_prepare (name, sql),       \
        GNUNET_PQ_PREPARED_STATEMENT_END          \
      };                                          \
                                                  \
      if (GNUNET_OK !=                            \
          GNUNET_PQ_prepare_statements (pg->conn, \
                                        ps))      \
      {                                           \
        GNUNET_break (0);                         \
        return GNUNET_DB_STATUS_HARD_ERROR;       \
      }                                           \
      gen = pg->prep_gen;                         \
    }                                             \
  } while (0)


/**
 * Check that the database connection is still up
 * and automatically reconnects unless we are
 * already inside of a transaction.
 *
 * @param pg connection to check
 */
void
check_connection (struct PostgresClosure *pg);


/**
 * Do a pre-flight check that we are not in an uncommitted transaction.
 * If we are, die.
 * Does not return anything, as we will continue regardless of the outcome.
 *
 * @param cls the `struct PostgresClosure` with the plugin-specific state
 */
void
postgres_preflight (void *cls);

/**
 * Start a transaction.
 *
 * @param cls the `struct PostgresClosure` with the plugin-specific state
 * @param name unique name identifying the transaction (for debugging),
 *             must point to a constant
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TMH_PG_start (void *cls,
              const char *name);


/**
 * Start a transaction in 'read committed' mode.
 *
 * @param cls the `struct PostgresClosure` with the plugin-specific state
 * @param name unique name identifying the transaction (for debugging),
 *             must point to a constant
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TMH_PG_start_read_committed (void *cls,
                             const char *name);

/**
 * Roll back the current transaction of a database connection.
 *
 * @param cls the `struct PostgresClosure` with the plugin-specific state
 */
void
TMH_PG_rollback (void *cls);


/**
 * Commit the current transaction of a database connection.
 *
 * @param cls the `struct PostgresClosure` with the plugin-specific state
 * @return transaction status code
 */
enum GNUNET_DB_QueryStatus
TMH_PG_commit (void *cls);


#endif
