--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Statement_hpp
+#define anna_dbms_Statement_hpp
+
+#include <vector>
+
+#include <anna/core/RuntimeException.hpp>
+#include <anna/core/mt/Mutex.hpp>
+#include <anna/core/util/Average.hpp>
+#include <anna/core/util/Microsecond.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+#include <anna/dbms/ResultCode.hpp>
+
+namespace anna {
+
+namespace xml {
+class Node;
+}
+
+namespace dbms {
+
+class Database;
+class Connection;
+class InputBind;
+class OutputBind;
+class Data;
+
+/**
+ Clase que facilita la ejecucion de sentencias SQL.
+
+ Para obtener la instancia de un comando para una determinada base de datos habra que instanciar
+ dicha base de datos e invocar al metodo Database::createStatement. Independientemente del tipo de comando
+ particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement.
+*/
+class Statement : public Mutex {
+public:
+ typedef std::vector <InputBind*>::iterator input_iterator;
+ typedef std::vector <OutputBind*>::iterator output_iterator;
+
+ /**
+ Destructor.
+ */
+ virtual ~Statement();
+
+ /**
+ Devuelve el nombre logico de esta sentencia.
+ \return El nombre logico de esta sentencia.
+ */
+ const std::string& getName() const throw() { return a_name; }
+
+ /**
+ Devuelve la expresion SQL recibida en el constructor.
+ \return La expresion SQL recibida en el constructor.
+ */
+ const std::string& getExpression() const throw() { return a_expression; }
+
+ /**
+ Devuelve el indicador de criticidad, si vale \em true indica que si la ejecucion de esta sentencia
+ falla al desbloquear la conexion con la que ejecutamos esta sentencia se invocara a
+ Connection::rollback, en otro caso aunque falle se invocara a Connection::commit.
+ Solo aplicara en sentencias que no sean de seleccion.
+ \return El indicador de criticidad de esta sentencia.
+ */
+ bool isCritical() const throw() { return a_isCritical; }
+
+ /**
+ Devuelve la instancia de la base de datos asociada a esta sentencia.
+ \return La instancia de la base de datos asociada a la sentencia.
+ */
+ Database& getDatabase() const throw() { return a_database; }
+
+ /**
+ Establece el parametro de entrada de la sentencia SQL.Cada una de las variables de entrada indicadas
+ en esta sentencia SQL deberia tener un parametro de entrada asociado. La correspondencia entre esta
+ variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
+ de definicion del parametro.
+
+ Por ejemplo la sentencia:
+
+ \code
+ update tabla1 set xx = :unavariable where yy = :otravariable;
+ \endcode
+
+ Cada una de las variables \em unavariable y \em otravariable debera tener asociado una variable de entrada.
+ Primero debemos indicaremos la correspondiente a \em unavariable y luego la correspondiente a \em otravariable.
+
+ \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
+ de la columna.
+ \param data Variable que deseamos asociar como variable de entrada. La correspondencia entre esta
+ y la sentencia SQL vendra dada por el orden de declaracion.
+ */
+ void bindInput(const char* name, Data& data) throw();
+
+ /**
+ Establece el parametro de salida de la sentencia SQL.Cada una de las variables de salida indicadas
+ en esta sentencia SQL deberia tener un parametro de salida asociado. La correspondencia entre esta
+ variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
+ de definicion del parametro.
+
+ Por ejemplo la sentencia:
+
+ \code
+ select xx, yy from tabla1 where zz = :unavariable;
+ \endcode
+
+ Cada una de las variables \em xx e \em yy debera tener asociado una variable de salida.
+ Ademas la variable \em unavaraible debera tener asociada una variable de entrada.
+
+ \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
+ de la columna.
+ \param data Variable que deseamos asociar como variable de salida. La correspondencia entre esta
+ y la sentencia SQL vendra dada por el orden de declaracion.
+
+ \return La instancia del dbms::OutputBind asociado al dato. nos permite
+ grabar el contenido de los tipos de datos BLOB.
+
+ \warning Solo las sentencias SQL del tipo \em select usan las variables de salida.
+ */
+ const dbms::OutputBind* bindOutput(const char* name, Data& data) throw();
+
+ /**
+ Establece el valor del indicador que activa/desactiva la necesidad de invocar al
+ \em commit y/o \em rollback despues de ejecutar esta sentencia.
+ */
+ void setRequiresCommit(const bool requiresCommit) throw() { a_requiresCommit = requiresCommit; }
+
+ /**
+ Devuelve \em true si la sentencia requiere la invocacion a \em commit o \em rollback
+ tras su ejecucion. Puede devolver \em true por tratarse de una sentencia que no tiene variables
+ de salida (insert, update o delete) o bien porque se haya activado el indicador correspondiente
+ mediante la llamada #setRequiresCommit
+ */
+ bool requiresCommit() const throw() { return (a_requiresCommit == true) || (a_outputBinds.empty() == true); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de entrada.
+ \return el iterador que apunta a la primera variable de entrada.
+ */
+ input_iterator input_begin() throw() { return a_inputBinds.begin(); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de entrada.
+ \return el iterador que apunta a la primera variable de entrada.
+ */
+ input_iterator input_end() throw() { return a_inputBinds.end(); }
+
+ /**
+ Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
+ \return el numero de variables de entrada asociado a esta sentencia SQL.
+ */
+ int input_size() const throw() { return a_inputBinds.size(); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de salida.
+ \return el iterador que apunta a la primera variable de salida.
+ */
+ output_iterator output_begin() throw() { return a_outputBinds.begin(); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de salida.
+ \return el iterador que apunta a la primera variable de salida.
+ */
+ output_iterator output_end() throw() { return a_outputBinds.end(); }
+
+ /**
+ Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
+ \return el numero de variables de entrada asociado a esta sentencia SQL.
+ */
+ int output_size() const throw() { return a_outputBinds.size(); }
+
+ /**
+ Devuelve un documento XML con la informacion referente a esta instancia.
+ \param parent Nodo XML del que debe colgar la informacion.
+ @return un documento XML con la informacion referente a esta instancia.
+ */
+ virtual xml::Node* asXML(xml::Node* parent) const throw();
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+ /**
+ Transfiere la informacion de una fila de la sentencia SQL de seleccion a las
+ variables de salida asociadas a la sentencia.
+
+ \return \em true si el registro ha sido transferido a las variables de salida o \em false si habiamos llegado
+ al ultimo registro de la seleccion.
+ */
+ virtual bool fetch() throw(RuntimeException, DatabaseException) = 0;
+
+ /**
+ Devuelve la variable de entrada apuntada por el iterador recibido como parametro.
+ \return la variable de entrada apuntada por el iterador recibido como parametro.
+ */
+ static Data& input(input_iterator& ii) throw();
+
+ /**
+ Devuelve la variable de salida apuntada por el iterador recibido como parametro.
+ \return la variable de salida apuntada por el iterador recibido como parametro.
+ */
+ static Data& output(output_iterator& ii) throw();
+
+protected:
+ /**
+ Contructor.
+
+ \param database Base de datos sobre la que se define la sentencia.
+ \param name Nombre logico de la sentencia.
+ \param expression Sentencia SQL asociada a esta clase.
+ \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
+ la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
+ aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion.
+ */
+ Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
+ a_database(database),
+ a_name(name),
+ a_expression(expression),
+ a_prepared(false),
+ a_isCritical(isCritical),
+ a_measureTiming("Timing", "us"),
+ a_requiresCommit(false) {
+ }
+
+ /**
+ Contructor.
+
+ \param database Base de datos sobre la que se define la sentencia.
+ \param name Nombre logico de la sentencia.
+ \param expression Sentencia SQL asociada a esta clase.
+ \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
+ la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
+ aunque falle se invocara a Connection::commit. Solo aplicara en cuenta en sentencias que no
+ sean de seleccion.
+ */
+ Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
+ a_database(database),
+ a_name(name),
+ a_expression(expression),
+ a_prepared(false),
+ a_isCritical(isCritical),
+ a_measureTiming("Timing", "us"),
+ a_requiresCommit(false) {
+ }
+
+ /**
+ Devuelve la referencia de entrada apuntada por el iterador recibido como parametro.
+ \return la referencia de entrada apuntada por el iterador recibido como parametro.
+ */
+ static InputBind* inputBind(input_iterator& ii) throw() { return *ii; }
+
+ /**
+ Devuelve la referencia de salida apuntada por el iterador recibido como parametro.
+ \return la referencia de salida apuntada por el iterador recibido como parametro.
+ */
+ static OutputBind* outputBind(output_iterator& ii) throw() { return *ii; }
+
+private:
+ Database& a_database;
+ const std::string a_name;
+ std::string a_expression;
+ std::vector <InputBind*> a_inputBinds; /**< Lista de variables de entrada */
+ std::vector <OutputBind*> a_outputBinds; /**< Lista de variables de salida */
+ bool a_prepared;
+ const bool a_isCritical;
+ Average <Microsecond> a_measureTiming;
+ bool a_requiresCommit;
+
+ Statement(const Statement&);
+ void measureTiming(const Microsecond & init, const Microsecond & end) throw() { a_measureTiming += (end - init); }
+
+ virtual void prepare(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
+ virtual ResultCode execute(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
+
+ friend class Connection;
+ friend class Database;
+};
+
+}
+}
+
+#endif