/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/prepared_statement.hxx
 *
 *   DESCRIPTION
 *      Helper classes for defining and executing prepared statements
 *   See the connection_base hierarchy for more about prepared statements
 *
 * Copyright (c) 2006-2011, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#ifndef PQXX_H_PREPARED_STATEMENT
#define PQXX_H_PREPARED_STATEMENT

#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#include "pqxx/internal/statement_parameters.hxx"


namespace pqxx
{
class binarystring;
class connection_base;
class transaction_base;
class result;


/// Dedicated namespace for helper types related to prepared statements
namespace prepare
{
/** \defgroup prepared Prepared statements
 *
 * Prepared statements are SQL queries that you define once and then invoke
 * as many times as you like, typically with varying parameters.  It's basically
 * a function that you can define ad hoc.
 *
 * If you have an SQL statement that you're going to execute many times in
 * quick succession, it may be more efficient to prepare it once and reuse it.
 * This saves the database backend the effort of parsing complex SQL and
 * figuring out an efficient execution plan.  Another nice side effect is that
 * you don't need to worry about escaping parameters.
 *
 * You create a prepared statement by preparing it on the connection, passing an
 * identifier and its SQL text.  The identifier is the name by which the
 * prepared statement will be known; it should consist of letters, digits, and
 * underscores only and start with a letter.  The name is case-sensitive.
 *
 * @code
 * void prepare_my_statement(pqxx::connection_base &c)
 * {
 *   c.prepare("my_statement", "SELECT * FROM Employee WHERE name = 'Xavier'");
 * }
 * @endcode
 *
 * Once you've done this, you'll be able to call @c my_statement from any
 * transaction you execute on the same connection.  You start an invocation by
 * looking up your statement using a member function called @c "prepared".  (The
 * definition used a different member function, called @c "prepare" ).
 *
 * @code
 * pqxx::result execute_my_statement(pqxx::transaction_base &t)
 * {
 *   return t.prepared("my_statement").exec();
 * }
 * @endcode
 *
 * Did I mention that prepared statements can have parameters?  The query text
 * can contain $@c 1, @c $2 etc. as placeholders for parameter values that you
 * will provide when you invoke the prepared satement.
 *
 * @code
 * void prepare_find(pqxx::connection_base &c)
 * {
 *   // Prepare a statement called "find" that looks for employees with a given
 *   // name (parameter 1) whose salary exceeds a given number (parameter 2).
 *   c.prepare(
 *   	"find",
 *   	"SELECT * FROM Employee WHERE name = $1 AND salary > $2");
 * }
 * @endcode
 *
 * How do you pass those parameters?  C++ has no good way to let you pass an
 * unlimited, variable number of arguments to a function call, and the compiler
 * does not know how many you are going to pass.  There's a trick for that: you
 * can treat the value you get back from @c prepared as a function, which you
 * call to pass a parameter.  What you get back from that call is the same
 * again, so you can call it again to pass another parameter and so on.
 *
 * Once you've passed all parameters in this way, you invoke the statement with
 * the parameters by calling @c exec on the invocation.
 *
 * This example looks up the prepared statement "find," passes @c name and
 * @c min_salary as parameters, and invokes the statement with those values:
 *
 * @code
 * pqxx::result execute_find(
 *   pqxx::transaction_base &t, std::string name, int min_salary)
 * {
 *   return t.prepared("find")(name)(min_salary).exec();
 * }
 * @endcode
 *
 * @warning There are cases where prepared statements are actually slower than
 * plain SQL.  Sometimes the backend can produce a better execution plan when it
 * knows the parameter values.  For example, say you've got a web application
 * and you're querying for users with status "inactive" who have email addresses
 * in a given domain name X.  If X is a very popular provider, the best way to
 * plan the query may be to list the inactive users first and then filter for
 * the email addresses you're looking for.  But in other cases, it may be much
 * faster to find matching email addresses first and then see which of their
 * owners are "inactive."  A prepared statement must be planned to fit either
 * case, but a direct query can be optimized based on table statistics, partial
 * indexes, etc.
 */

/// Helper class for passing parameters to, and executing, prepared statements
class PQXX_LIBEXPORT invocation : internal::statement_parameters
{
public:
  invocation(transaction_base &, const PGSTD::string &statement);

  /// Execute!
  result exec() const;

  /// Has a statement of this name been defined?
  bool exists() const;

  /// Pass null parameter.
  invocation &operator()() { add_param(); return *this; }

  /// Pass parameter value.
  /**
   * @param v parameter value; will be represented as a string internally.
   */
  template<typename T> invocation &operator()(const T &v)
	{ add_param(v, true); return *this; }

  /// Pass binary parameter value for a BYTEA field.
  /**
   * @param v binary string; will be passed on directly in binary form.
   */
  invocation &operator()(const binarystring &v)
	{ add_binary_param(v, true); return *this; }

  /// Pass parameter value.
  /**
   * @param v parameter value (will be represented as a string internally).
   * @param nonnull replaces value with null if set to false.
   */
  template<typename T> invocation &operator()(const T &v, bool nonnull)
	{ add_param(v, nonnull); return *this; }

  /// Pass binary parameter value for a BYTEA field.
  /**
   * @param v binary string; will be passed on directly in binary form.
   * @param nonnull determines whether to pass a real value, or NULL.
   */
  invocation &operator()(const binarystring &v, bool nonnull)
	{ add_binary_param(v, nonnull); return *this; }

  /// Pass C-style parameter string, or null if pointer is null.
  /**
   * This version is for passing C-style strings; it's a template, so any
   * pointer type that @c to_string accepts will do.
   *
   * @warning Be very careful with the special constant @c NULL!  Since @c NULL
   * in C++ is an @c int, not a pointer, a value of @c NULL would cause the
   * wrong version of this template to be invoked.  To all intents and purposes
   * it would look like you were trying to pass a regular zero as an integer
   * value, instead of a null string.  This is not a problem with pointer
   * variables that may happen to be @c NULL, since in that case the value's
   * type is not subject to any confusion.  So if you know at compile time that
   * you want to pass a null value, use the zero-argument version of this
   * operator; if you don't want to do that, at least add a second argument of
   * @c false to make clear that you want a null, not a zero.
   *
   * @param v parameter value (will be represented as a C++ string internally)
   * @param nonnull replaces value with null if set to @c false
   */
  template<typename T> invocation &operator()(T *v, bool nonnull=true)
	{ add_param(v, nonnull); return *this; }

  /// Pass C-style string parameter, or null if pointer is null.
  /** This duplicates the pointer-to-template-argument-type version of the
   * operator, but helps compilers with less advanced template implementations
   * disambiguate calls where C-style strings are passed.
   */
  invocation &operator()(const char *v, bool nonnull=true)
	{ add_param(v, nonnull); return *this; }

private:
  /// Not allowed
  invocation &operator=(const invocation &);

  transaction_base &m_home;
  const PGSTD::string m_statement;
  PGSTD::vector<PGSTD::string> m_values;
  PGSTD::vector<bool> m_nonnull;

  invocation &setparam(const PGSTD::string &, bool nonnull);
};


namespace internal
{
/// Internal representation of a prepared statement definition
struct PQXX_LIBEXPORT prepared_def
{
  /// Text of prepared query
  PGSTD::string definition;
  /// Has this prepared statement been prepared in the current session?
  bool registered;

  prepared_def();
  explicit prepared_def(const PGSTD::string &);
};

} // namespace pqxx::prepare::internal
} // namespace pqxx::prepare
} // namespace pqxx

#include "pqxx/compiler-internal-post.hxx"

#endif

