Updated license
[anna.git] / include / anna / dbms / Statement.hpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_dbms_Statement_hpp
38 #define anna_dbms_Statement_hpp
39
40 #include <vector>
41
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>
46
47 #include <anna/dbms/DatabaseException.hpp>
48 #include <anna/dbms/ResultCode.hpp>
49
50 namespace anna {
51
52 namespace xml {
53 class Node;
54 }
55
56 namespace dbms {
57
58 class Database;
59 class Connection;
60 class InputBind;
61 class OutputBind;
62 class Data;
63
64 /**
65    Clase que facilita la ejecucion de sentencias SQL.
66
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.
70 */
71 class Statement : public Mutex {
72 public:
73   typedef std::vector <InputBind*>::iterator input_iterator;
74   typedef std::vector <OutputBind*>::iterator output_iterator;
75
76   /**
77      Destructor.
78   */
79   virtual ~Statement();
80
81   /**
82      Devuelve el nombre logico de esta sentencia.
83      \return El nombre logico de esta sentencia.
84   */
85   const std::string& getName() const throw() { return a_name; }
86
87   /**
88      Devuelve la expresion SQL recibida en el constructor.
89      \return La expresion SQL recibida en el constructor.
90   */
91   const std::string& getExpression() const throw() { return a_expression; }
92
93   /**
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.
99   */
100   bool isCritical() const throw() { return a_isCritical; }
101
102   /**
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.
105   */
106   Database& getDatabase() const throw() { return a_database; }
107
108   /**
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.
113
114      Por ejemplo la sentencia:
115
116      \code
117      update tabla1 set xx = :unavariable where yy = :otravariable;
118      \endcode
119
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.
122
123      \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
124      de la columna.
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.
127   */
128   void bindInput(const char* name, Data& data) throw();
129
130   /**
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.
135
136      Por ejemplo la sentencia:
137
138      \code
139      select xx, yy from tabla1 where zz = :unavariable;
140      \endcode
141
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.
144
145      \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
146      de la columna.
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.
149
150      \return La instancia del dbms::OutputBind asociado al dato. nos permite
151      grabar el contenido de los tipos de datos BLOB.
152
153      \warning Solo las sentencias SQL del tipo \em select usan las variables de salida.
154   */
155   const dbms::OutputBind* bindOutput(const char* name, Data& data) throw();
156
157   /**
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.
160   */
161   void setRequiresCommit(const bool requiresCommit) throw() { a_requiresCommit = requiresCommit; }
162
163   /**
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
168   */
169   bool requiresCommit() const throw() { return (a_requiresCommit == true) || (a_outputBinds.empty() == true); }
170
171   /**
172      Devuelve el iterador que apunta a la primera variable de entrada.
173      \return el iterador que apunta a la primera variable de entrada.
174   */
175   input_iterator input_begin() throw() { return a_inputBinds.begin(); }
176
177   /**
178      Devuelve el iterador que apunta a la primera variable de entrada.
179      \return el iterador que apunta a la primera variable de entrada.
180   */
181   input_iterator input_end() throw() { return a_inputBinds.end(); }
182
183   /**
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.
186   */
187   int input_size() const throw() { return a_inputBinds.size(); }
188
189   /**
190      Devuelve el iterador que apunta a la primera variable de salida.
191      \return el iterador que apunta a la primera variable de salida.
192   */
193   output_iterator output_begin() throw() { return a_outputBinds.begin(); }
194
195   /**
196      Devuelve el iterador que apunta a la primera variable de salida.
197      \return el iterador que apunta a la primera variable de salida.
198   */
199   output_iterator output_end() throw() { return a_outputBinds.end(); }
200
201   /**
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.
204   */
205   int output_size() const throw() { return a_outputBinds.size(); }
206
207   /**
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.
211   */
212   virtual xml::Node* asXML(xml::Node* parent) const throw();
213
214   /**
215      Devuelve una cadena con la informacion referente a esta instancia.
216      @return Una cadena con la informacion referente a esta instancia.
217   */
218   virtual std::string asString() const throw();
219
220   /**
221      Transfiere la informacion de una fila de la sentencia SQL de seleccion a las
222      variables de salida asociadas a la sentencia.
223
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.
226   */
227   virtual bool fetch() throw(RuntimeException, DatabaseException) = 0;
228
229   /**
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.
232   */
233   static Data& input(input_iterator& ii) throw();
234
235   /**
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.
238   */
239   static Data& output(output_iterator& ii) throw();
240
241 protected:
242   /**
243      Contructor.
244
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.
251   */
252   Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
253     a_database(database),
254     a_name(name),
255     a_expression(expression),
256     a_prepared(false),
257     a_isCritical(isCritical),
258     a_measureTiming("Timing", "us"),
259     a_requiresCommit(false) {
260   }
261
262   /**
263      Contructor.
264
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
271      sean de seleccion.
272   */
273   Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
274     a_database(database),
275     a_name(name),
276     a_expression(expression),
277     a_prepared(false),
278     a_isCritical(isCritical),
279     a_measureTiming("Timing", "us"),
280     a_requiresCommit(false) {
281   }
282
283   /**
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.
286   */
287   static InputBind* inputBind(input_iterator& ii) throw() { return *ii; }
288
289   /**
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.
292   */
293   static OutputBind* outputBind(output_iterator& ii) throw() { return *ii; }
294
295 private:
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 */
301   bool a_prepared;
302   const bool a_isCritical;
303   Average <Microsecond> a_measureTiming;
304   bool a_requiresCommit;
305
306   Statement(const Statement&);
307   void measureTiming(const Microsecond & init, const Microsecond & end) throw() { a_measureTiming += (end - init); }
308
309   virtual void prepare(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
310   virtual ResultCode execute(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
311
312   friend class Connection;
313   friend class Database;
314 };
315
316 }
317 }
318
319 #endif