Normalize xml processing
[anna.git] / source / dbms.mysql / Statement.cpp
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 #include <mysql/mysql.h>
10
11 #include <anna/config/defines.hpp>
12 #include <anna/core/tracing/TraceMethod.hpp>
13
14 #include <anna/dbms.mysql/mysql.hpp>
15
16 using namespace std;
17 using namespace anna;
18
19 dbms::mysql::Statement::~Statement() {
20   if(a_mysqlStmt) {
21     try {
22       anna_dbms_mysql_check(mysql_stmt_close(a_mysqlStmt), a_mysqlStmt);
23     } catch(DatabaseException& edb) {
24       edb.trace();
25     }
26   }
27
28   delete [] a_params;
29   delete [] a_results;
30 }
31
32 /**
33  * Según el ejemplo de: http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
34  *
35  */
36 void dbms::mysql::Statement::prepare(dbms::Connection* dbmsConnection)
37 throw(RuntimeException, dbms::DatabaseException) {
38   LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Statement", "prepare", ANNA_FILE_LOCATION));
39   Connection* connection(static_cast <Connection*>(dbmsConnection));
40   //Database& dbms(static_cast <Database&>(connection->getDatabase()));
41   LOGDEBUG(
42     string msg("anna::dbms::mysql::Statement::prepare | ");
43     msg += asString();
44     Logger::debug(msg, ANNA_FILE_LOCATION);
45   );
46
47   /*
48    * Libera la información establecida anteriormente. Las sentencias se pueden reusar.
49    */
50   if(a_mysqlStmt != NULL) {
51     anna_dbms_mysql_check(mysql_stmt_reset(a_mysqlStmt), a_mysqlStmt);
52     delete [] a_params;
53     delete [] a_results;
54     a_params = a_results = NULL;
55   } else if((a_mysqlStmt = mysql_stmt_init(*connection)) == NULL) {
56     string msg(asString());
57     msg += " | Insufficient memory";
58     throw RuntimeException(msg, ANNA_FILE_LOCATION);
59   }
60
61   const char* expression = dbms::Statement::getExpression().c_str();
62
63   anna_dbms_mysql_check(mysql_stmt_prepare(a_mysqlStmt, expression, anna_strlen(expression)), a_mysqlStmt);
64
65   const int paramCount = mysql_stmt_param_count(a_mysqlStmt);
66
67   const int inputSize = dbms::Statement::input_size();
68
69   const int outputSize = dbms::Statement::output_size();
70
71   /*
72    * Verifica que el número de parámetros de entrada de la sentencia coincida con el número de parámetros
73    * indicados por el programador.
74    */
75   if(paramCount != inputSize) {
76     string msg(asString());
77     msg += " | Wrong input parameters";
78     throw RuntimeException(msg, ANNA_FILE_LOCATION);
79   }
80
81   /*
82    * Verifica que el número de parámetros de salida de la sentencia coincida con el número de parámetros
83    * indicados por el programador. Si no tiene parámetros de salida (INSERT) => no debe tener parámetros
84    * indicados por el programador.
85    */
86   MYSQL_RES* metaResult = mysql_stmt_result_metadata(a_mysqlStmt);
87
88   try {
89     if(metaResult == NULL) {
90       if(outputSize != 0) {
91         string msg(asString());
92         msg += " | Wrong output parameters";
93         throw RuntimeException(msg, ANNA_FILE_LOCATION);
94       }
95     } else if(mysql_num_fields(metaResult) != outputSize) {
96       string msg(asString());
97       msg += " | Wrong output parameters";
98       throw RuntimeException(msg, ANNA_FILE_LOCATION);
99     }
100   } catch(RuntimeException&) {
101     mysql_free_result(metaResult);
102     throw;
103   }
104
105   /*
106    * Define las estructuras requeridas para asociar las columasn MySQL con las áreas de memoria C++
107    */
108   int pos;
109
110   if((a_params = create(inputSize, "input")) != NULL) {
111     pos = 0;
112
113     for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++)
114       inputBind(ii)->prepare(this, dbmsConnection, pos ++);
115
116     anna_dbms_mysql_check(mysql_stmt_bind_param(a_mysqlStmt, a_params), a_mysqlStmt);
117   }
118
119   if((a_results = create(outputSize, "output")) != NULL) {
120     pos = 0;
121
122     for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++)
123       outputBind(oo)->prepare(this, dbmsConnection, pos ++);
124
125     anna_dbms_mysql_check(mysql_stmt_bind_result(a_mysqlStmt, a_results), a_mysqlStmt);
126   }
127 }
128
129 dbms::ResultCode dbms::mysql::Statement::execute(dbms::Connection* dbmsConnection)
130 throw(RuntimeException, dbms::DatabaseException) {
131   //Connection* connection(static_cast <Connection*>(dbmsConnection));
132
133   for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) {
134     inputBind(ii)->code();
135     LOGDEBUG(
136       string msg("anna::dbms::mysql::Statement::InputBind: ");
137       msg += inputBind(ii)->asString();
138       Logger::debug(msg, ANNA_FILE_LOCATION);
139     );
140   }
141
142   anna_dbms_mysql_check(mysql_stmt_execute(a_mysqlStmt), a_mysqlStmt)
143   ResultCode result(a_mysqlStmt);
144   return result;
145 }
146
147 /*
148  * Según la información de http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
149  */
150 bool dbms::mysql::Statement::fetch()
151 throw(RuntimeException, dbms::DatabaseException) {
152   bool result = false;
153
154   switch(mysql_stmt_fetch(a_mysqlStmt)) {
155   case 0:
156     result = true;
157
158     for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) {
159       outputBind(oo)->decode();
160       LOGDEBUG(Logger::write(Logger::Debug, outputBind(oo)->asString(), ANNA_FILE_LOCATION));
161     }
162
163     break;
164   case 1:
165     throw DatabaseException(ResultCode(a_mysqlStmt), ANNA_FILE_LOCATION);
166   default:
167     result = false;
168     break;
169   }
170
171   LOGDEBUG(
172     string msg("anna::dbms::mysql::Statement::fetch | Result: ");
173     msg += functions::asString(result);
174     Logger::debug(msg, ANNA_FILE_LOCATION);
175   );
176   return result;
177 }
178
179 st_mysql_bind* dbms::mysql::Statement::create(const int size, const char* whatis)
180 throw(RuntimeException) {
181   st_mysql_bind* result = NULL;
182
183   if(size > 0) {
184     if((result = new st_mysql_bind [size]) == NULL) {
185       string msg(asString());
186       msg += anna::functions::asString("Insufficient memory to create %d parameters of %s", size, whatis);
187       throw RuntimeException(msg, ANNA_FILE_LOCATION);
188     }
189   }
190
191   return result;
192 }