bd2455918f5cb9e7721e2360910bd038854a778a
[anna.git] / Statement.hpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #ifndef anna_dbms_Statement_hpp
10 #define anna_dbms_Statement_hpp
11
12 #include <vector>
13
14 #include <anna/core/RuntimeException.hpp>
15 #include <anna/core/mt/Mutex.hpp>
16 #include <anna/core/util/Average.hpp>
17 #include <anna/core/util/Microsecond.hpp>
18
19 #include <anna/dbms/DatabaseException.hpp>
20 #include <anna/dbms/ResultCode.hpp>
21
22 namespace anna {
23
24 namespace xml {
25 class Node;
26 }
27
28 namespace dbms {
29
30 class Database;
31 class Connection;
32 class InputBind;
33 class OutputBind;
34 class Data;
35
36 /**
37    Clase que facilita la ejecucion de sentencias SQL.
38
39    Para obtener la instancia de un comando para una determinada base de datos habra que instanciar
40    dicha base de datos e invocar al metodo Database::createStatement. Independientemente del tipo de comando
41    particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement.
42 */
43 class Statement : public Mutex {
44 public:
45   typedef std::vector <InputBind*>::iterator input_iterator;
46   typedef std::vector <OutputBind*>::iterator output_iterator;
47
48   /**
49      Destructor.
50   */
51   virtual ~Statement();
52
53   /**
54      Devuelve el nombre logico de esta sentencia.
55      \return El nombre logico de esta sentencia.
56   */
57   const std::string& getName() const { return a_name; }
58
59   /**
60      Devuelve la expresion SQL recibida en el constructor.
61      \return La expresion SQL recibida en el constructor.
62   */
63   const std::string& getExpression() const { return a_expression; }
64
65   /**
66      Devuelve el indicador de criticidad, si vale \em true indica que si la ejecucion de esta sentencia
67      falla al desbloquear la conexion con la que ejecutamos esta sentencia se invocara a
68      Connection::rollback, en otro caso  aunque falle se invocara a Connection::commit.
69      Solo aplicara en sentencias que no sean de seleccion.
70      \return El indicador de criticidad de esta sentencia.
71   */
72   bool isCritical() const { return a_isCritical; }
73
74   /**
75      Devuelve la instancia de la base de datos asociada a esta sentencia.
76      \return La instancia de la base de datos asociada a la sentencia.
77   */
78   Database& getDatabase() const { return a_database; }
79
80   /**
81      Establece el parametro de entrada de la sentencia SQL.Cada una de las variables de entrada indicadas
82      en esta sentencia SQL deberia tener un parametro de entrada asociado. La correspondencia entre esta
83      variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
84      de definicion del parametro.
85
86      Por ejemplo la sentencia:
87
88      \code
89      update tabla1 set xx = :unavariable where yy = :otravariable;
90      \endcode
91
92      Cada una de las variables \em unavariable y \em otravariable debera tener asociado una variable de entrada.
93      Primero debemos indicaremos la correspondiente a \em unavariable y luego la correspondiente a \em otravariable.
94
95      \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
96      de la columna.
97      \param data Variable que deseamos asociar como variable de entrada. La correspondencia entre esta
98      y la sentencia SQL vendra dada por el orden de declaracion.
99   */
100   void bindInput(const char* name, Data& data) ;
101
102   /**
103      Establece el parametro de salida de la sentencia SQL.Cada una de las variables de salida indicadas
104      en esta sentencia SQL deberia tener un parametro de salida asociado. La correspondencia entre esta
105      variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
106      de definicion del parametro.
107
108      Por ejemplo la sentencia:
109
110      \code
111      select xx, yy from tabla1 where zz = :unavariable;
112      \endcode
113
114      Cada una de las variables \em xx e \em yy debera tener asociado una variable de salida.
115       Ademas la variable \em unavaraible debera tener asociada una variable de entrada.
116
117      \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
118      de la columna.
119      \param data Variable que deseamos asociar como variable de salida. La correspondencia entre esta
120      y la sentencia SQL vendra dada por el orden de declaracion.
121
122      \return La instancia del dbms::OutputBind asociado al dato. nos permite
123      grabar el contenido de los tipos de datos BLOB.
124
125      \warning Solo las sentencias SQL del tipo \em select usan las variables de salida.
126   */
127   const dbms::OutputBind* bindOutput(const char* name, Data& data) ;
128
129   /**
130      Establece el valor del indicador que activa/desactiva la necesidad de invocar al
131      \em commit y/o \em rollback despues de ejecutar esta sentencia.
132   */
133   void setRequiresCommit(const bool requiresCommit) { a_requiresCommit = requiresCommit; }
134
135   /**
136      Devuelve \em true si la sentencia requiere la invocacion a \em commit o \em rollback
137      tras su ejecucion. Puede devolver \em true por tratarse de una sentencia que no tiene variables
138      de salida (insert, update o delete) o bien porque se haya activado el indicador correspondiente
139      mediante la llamada #setRequiresCommit
140   */
141   bool requiresCommit() const { return (a_requiresCommit == true) || (a_outputBinds.empty() == true); }
142
143   /**
144      Devuelve el iterador que apunta a la primera variable de entrada.
145      \return el iterador que apunta a la primera variable de entrada.
146   */
147   input_iterator input_begin() { return a_inputBinds.begin(); }
148
149   /**
150      Devuelve el iterador que apunta a la primera variable de entrada.
151      \return el iterador que apunta a la primera variable de entrada.
152   */
153   input_iterator input_end() { return a_inputBinds.end(); }
154
155   /**
156      Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
157      \return el numero de variables de entrada asociado a esta sentencia SQL.
158   */
159   int input_size() const { return a_inputBinds.size(); }
160
161   /**
162      Devuelve el iterador que apunta a la primera variable de salida.
163      \return el iterador que apunta a la primera variable de salida.
164   */
165   output_iterator output_begin() { return a_outputBinds.begin(); }
166
167   /**
168      Devuelve el iterador que apunta a la primera variable de salida.
169      \return el iterador que apunta a la primera variable de salida.
170   */
171   output_iterator output_end() { return a_outputBinds.end(); }
172
173   /**
174      Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
175      \return el numero de variables de entrada asociado a esta sentencia SQL.
176   */
177   int output_size() const { return a_outputBinds.size(); }
178
179   /**
180      Devuelve un documento XML con la informacion referente a esta instancia.
181      \param parent Nodo XML del que debe colgar la informacion.
182      @return un documento XML con la informacion referente a esta instancia.
183   */
184   virtual xml::Node* asXML(xml::Node* parent) const ;
185
186   /**
187      Devuelve una cadena con la informacion referente a esta instancia.
188      @return Una cadena con la informacion referente a esta instancia.
189   */
190   virtual std::string asString() const ;
191
192   /**
193      Transfiere la informacion de una fila de la sentencia SQL de seleccion a las
194      variables de salida asociadas a la sentencia.
195
196      \return \em true si el registro ha sido transferido a las variables de salida o \em false si habiamos llegado
197      al ultimo registro de la seleccion.
198   */
199   virtual bool fetch() noexcept(false) = 0;
200
201   /**
202      Devuelve la variable de entrada apuntada por el iterador recibido como parametro.
203      \return la variable de entrada apuntada por el iterador recibido como parametro.
204   */
205   static Data& input(input_iterator& ii) ;
206
207   /**
208      Devuelve la variable de salida apuntada por el iterador recibido como parametro.
209      \return la variable de salida apuntada por el iterador recibido como parametro.
210   */
211   static Data& output(output_iterator& ii) ;
212
213 protected:
214   /**
215      Contructor.
216
217      \param database Base de datos sobre la que se define la sentencia.
218      \param name Nombre logico de la sentencia.
219      \param expression Sentencia SQL asociada a esta clase.
220      \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
221      la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
222      aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion.
223   */
224   Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
225     a_database(database),
226     a_name(name),
227     a_expression(expression),
228     a_prepared(false),
229     a_isCritical(isCritical),
230     a_measureTiming("Timing", "us"),
231     a_requiresCommit(false) {
232   }
233
234   /**
235      Contructor.
236
237      \param database Base de datos sobre la que se define la sentencia.
238      \param name Nombre logico de la sentencia.
239      \param expression Sentencia SQL asociada a esta clase.
240      \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
241      la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
242      aunque falle se invocara a Connection::commit. Solo aplicara en cuenta en sentencias que no
243      sean de seleccion.
244   */
245   Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
246     a_database(database),
247     a_name(name),
248     a_expression(expression),
249     a_prepared(false),
250     a_isCritical(isCritical),
251     a_measureTiming("Timing", "us"),
252     a_requiresCommit(false) {
253   }
254
255   /**
256      Devuelve la referencia de entrada apuntada por el iterador recibido como parametro.
257      \return la referencia de entrada apuntada por el iterador recibido como parametro.
258   */
259   static InputBind* inputBind(input_iterator& ii) { return *ii; }
260
261   /**
262      Devuelve la referencia de salida apuntada por el iterador recibido como parametro.
263      \return la referencia de salida apuntada por el iterador recibido como parametro.
264   */
265   static OutputBind* outputBind(output_iterator& ii) { return *ii; }
266
267 private:
268   Database& a_database;
269   const std::string a_name;
270   std::string a_expression;
271   std::vector <InputBind*> a_inputBinds;  /**< Lista de variables de entrada */
272   std::vector <OutputBind*> a_outputBinds; /**< Lista de variables de salida */
273   bool a_prepared;
274   const bool a_isCritical;
275   Average <Microsecond> a_measureTiming;
276   bool a_requiresCommit;
277
278   Statement(const Statement&);
279   void measureTiming(const Microsecond & init, const Microsecond & end) { a_measureTiming += (end - init); }
280
281   virtual void prepare(Connection* connection) noexcept(false) = 0;
282   virtual ResultCode execute(Connection* connection) noexcept(false) = 0;
283
284   friend class Connection;
285   friend class Database;
286 };
287
288 }
289 }
290
291 #endif