1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_dbms_Statement_hpp
38 #define anna_dbms_Statement_hpp
42 #include <anna/core/RuntimeException.hpp>
43 #include <anna/core/mt/Mutex.hpp>
44 #include <anna/core/util/Average.hpp>
45 #include <anna/core/util/Microsecond.hpp>
47 #include <anna/dbms/DatabaseException.hpp>
48 #include <anna/dbms/ResultCode.hpp>
65 Clase que facilita la ejecucion de sentencias SQL.
67 Para obtener la instancia de un comando para una determinada base de datos habra que instanciar
68 dicha base de datos e invocar al metodo Database::createStatement. Independientemente del tipo de comando
69 particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement.
71 class Statement : public Mutex {
73 typedef std::vector <InputBind*>::iterator input_iterator;
74 typedef std::vector <OutputBind*>::iterator output_iterator;
82 Devuelve el nombre logico de esta sentencia.
83 \return El nombre logico de esta sentencia.
85 const std::string& getName() const throw() { return a_name; }
88 Devuelve la expresion SQL recibida en el constructor.
89 \return La expresion SQL recibida en el constructor.
91 const std::string& getExpression() const throw() { return a_expression; }
94 Devuelve el indicador de criticidad, si vale \em true indica que si la ejecucion de esta sentencia
95 falla al desbloquear la conexion con la que ejecutamos esta sentencia se invocara a
96 Connection::rollback, en otro caso aunque falle se invocara a Connection::commit.
97 Solo aplicara en sentencias que no sean de seleccion.
98 \return El indicador de criticidad de esta sentencia.
100 bool isCritical() const throw() { return a_isCritical; }
103 Devuelve la instancia de la base de datos asociada a esta sentencia.
104 \return La instancia de la base de datos asociada a la sentencia.
106 Database& getDatabase() const throw() { return a_database; }
109 Establece el parametro de entrada de la sentencia SQL.Cada una de las variables de entrada indicadas
110 en esta sentencia SQL deberia tener un parametro de entrada asociado. La correspondencia entre esta
111 variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
112 de definicion del parametro.
114 Por ejemplo la sentencia:
117 update tabla1 set xx = :unavariable where yy = :otravariable;
120 Cada una de las variables \em unavariable y \em otravariable debera tener asociado una variable de entrada.
121 Primero debemos indicaremos la correspondiente a \em unavariable y luego la correspondiente a \em otravariable.
123 \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
125 \param data Variable que deseamos asociar como variable de entrada. La correspondencia entre esta
126 y la sentencia SQL vendra dada por el orden de declaracion.
128 void bindInput(const char* name, Data& data) throw();
131 Establece el parametro de salida de la sentencia SQL.Cada una de las variables de salida indicadas
132 en esta sentencia SQL deberia tener un parametro de salida asociado. La correspondencia entre esta
133 variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
134 de definicion del parametro.
136 Por ejemplo la sentencia:
139 select xx, yy from tabla1 where zz = :unavariable;
142 Cada una de las variables \em xx e \em yy debera tener asociado una variable de salida.
143 Ademas la variable \em unavaraible debera tener asociada una variable de entrada.
145 \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
147 \param data Variable que deseamos asociar como variable de salida. La correspondencia entre esta
148 y la sentencia SQL vendra dada por el orden de declaracion.
150 \return La instancia del dbms::OutputBind asociado al dato. nos permite
151 grabar el contenido de los tipos de datos BLOB.
153 \warning Solo las sentencias SQL del tipo \em select usan las variables de salida.
155 const dbms::OutputBind* bindOutput(const char* name, Data& data) throw();
158 Establece el valor del indicador que activa/desactiva la necesidad de invocar al
159 \em commit y/o \em rollback despues de ejecutar esta sentencia.
161 void setRequiresCommit(const bool requiresCommit) throw() { a_requiresCommit = requiresCommit; }
164 Devuelve \em true si la sentencia requiere la invocacion a \em commit o \em rollback
165 tras su ejecucion. Puede devolver \em true por tratarse de una sentencia que no tiene variables
166 de salida (insert, update o delete) o bien porque se haya activado el indicador correspondiente
167 mediante la llamada #setRequiresCommit
169 bool requiresCommit() const throw() { return (a_requiresCommit == true) || (a_outputBinds.empty() == true); }
172 Devuelve el iterador que apunta a la primera variable de entrada.
173 \return el iterador que apunta a la primera variable de entrada.
175 input_iterator input_begin() throw() { return a_inputBinds.begin(); }
178 Devuelve el iterador que apunta a la primera variable de entrada.
179 \return el iterador que apunta a la primera variable de entrada.
181 input_iterator input_end() throw() { return a_inputBinds.end(); }
184 Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
185 \return el numero de variables de entrada asociado a esta sentencia SQL.
187 int input_size() const throw() { return a_inputBinds.size(); }
190 Devuelve el iterador que apunta a la primera variable de salida.
191 \return el iterador que apunta a la primera variable de salida.
193 output_iterator output_begin() throw() { return a_outputBinds.begin(); }
196 Devuelve el iterador que apunta a la primera variable de salida.
197 \return el iterador que apunta a la primera variable de salida.
199 output_iterator output_end() throw() { return a_outputBinds.end(); }
202 Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
203 \return el numero de variables de entrada asociado a esta sentencia SQL.
205 int output_size() const throw() { return a_outputBinds.size(); }
208 Devuelve un documento XML con la informacion referente a esta instancia.
209 \param parent Nodo XML del que debe colgar la informacion.
210 @return un documento XML con la informacion referente a esta instancia.
212 virtual xml::Node* asXML(xml::Node* parent) const throw();
215 Devuelve una cadena con la informacion referente a esta instancia.
216 @return Una cadena con la informacion referente a esta instancia.
218 virtual std::string asString() const throw();
221 Transfiere la informacion de una fila de la sentencia SQL de seleccion a las
222 variables de salida asociadas a la sentencia.
224 \return \em true si el registro ha sido transferido a las variables de salida o \em false si habiamos llegado
225 al ultimo registro de la seleccion.
227 virtual bool fetch() throw(RuntimeException, DatabaseException) = 0;
230 Devuelve la variable de entrada apuntada por el iterador recibido como parametro.
231 \return la variable de entrada apuntada por el iterador recibido como parametro.
233 static Data& input(input_iterator& ii) throw();
236 Devuelve la variable de salida apuntada por el iterador recibido como parametro.
237 \return la variable de salida apuntada por el iterador recibido como parametro.
239 static Data& output(output_iterator& ii) throw();
245 \param database Base de datos sobre la que se define la sentencia.
246 \param name Nombre logico de la sentencia.
247 \param expression Sentencia SQL asociada a esta clase.
248 \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
249 la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
250 aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion.
252 Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
253 a_database(database),
255 a_expression(expression),
257 a_isCritical(isCritical),
258 a_measureTiming("Timing", "us"),
259 a_requiresCommit(false) {
265 \param database Base de datos sobre la que se define la sentencia.
266 \param name Nombre logico de la sentencia.
267 \param expression Sentencia SQL asociada a esta clase.
268 \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
269 la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
270 aunque falle se invocara a Connection::commit. Solo aplicara en cuenta en sentencias que no
273 Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
274 a_database(database),
276 a_expression(expression),
278 a_isCritical(isCritical),
279 a_measureTiming("Timing", "us"),
280 a_requiresCommit(false) {
284 Devuelve la referencia de entrada apuntada por el iterador recibido como parametro.
285 \return la referencia de entrada apuntada por el iterador recibido como parametro.
287 static InputBind* inputBind(input_iterator& ii) throw() { return *ii; }
290 Devuelve la referencia de salida apuntada por el iterador recibido como parametro.
291 \return la referencia de salida apuntada por el iterador recibido como parametro.
293 static OutputBind* outputBind(output_iterator& ii) throw() { return *ii; }
296 Database& a_database;
297 const std::string a_name;
298 std::string a_expression;
299 std::vector <InputBind*> a_inputBinds; /**< Lista de variables de entrada */
300 std::vector <OutputBind*> a_outputBinds; /**< Lista de variables de salida */
302 const bool a_isCritical;
303 Average <Microsecond> a_measureTiming;
304 bool a_requiresCommit;
306 Statement(const Statement&);
307 void measureTiming(const Microsecond & init, const Microsecond & end) throw() { a_measureTiming += (end - init); }
309 virtual void prepare(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
310 virtual ResultCode execute(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
312 friend class Connection;
313 friend class Database;