1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
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 the copyright holder 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 #include <mysql/mysql.h>
39 #include <anna/config/defines.hpp>
40 #include <anna/core/tracing/Logger.hpp>
41 #include <anna/core/DataBlock.hpp>
43 #include <anna/dbms/Float.hpp>
44 #include <anna/dbms/ShortBlock.hpp>
45 #include <anna/dbms/LongBlock.hpp>
46 #include <anna/dbms/String.hpp>
47 #include <anna/dbms/Date.hpp>
48 #include <anna/dbms/TimeStamp.hpp>
50 #include <anna/dbms.mysql/mysql.hpp>
55 OutputBind::OutputBind(const char* name, dbms::Data& data) :
56 dbms::OutputBind(name, data),
58 a_blob = (data.getType() == Data::Type::LongBlock) ? new Blob : NULL;
61 OutputBind::~OutputBind() {
66 * El dato de LONG BLOB se recoge según cuenta:
67 * http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html.
69 void OutputBind::prepare(anna::dbms::Statement* dbmsStmt, anna::dbms::Connection*, const int pos)
70 throw(RuntimeException) {
71 st_mysql_bind* bind = static_cast <dbms::mysql::Statement*>(dbmsStmt)->getBindResults() + pos;
72 Data& data = anna::dbms::Bind::getData();
73 BaseBind::setupBind(*bind, data);
75 if(data.getType() == Data::Type::LongBlock) {
76 dbms::mysql::Statement* myStmt = static_cast <dbms::mysql::Statement*>(dbmsStmt);
77 a_blob->stmt = *myStmt;
78 a_blob->binds = myStmt->getBindResults();
80 bind->buffer_type = MYSQL_TYPE_BLOB;
82 bind->buffer_length = 0;
83 bind->length = &a_length;
88 * Transfiere la información del los MYSQL_BIND del API C de MySQL a las
89 * estructuras dbms::Data de nuestro programa C++.
91 void OutputBind::decode() const
92 throw(RuntimeException) {
93 OutputBind* _this = const_cast <OutputBind*>(this);
95 Data& data = _this->getData();
96 data.setNull(a_nullIndicator == true);
98 switch(data.getType()) {
99 case Data::Type::String:
100 str = (char*) data.getBuffer();
102 if(data.isNull() == true)
105 dbms::String::strip(str);
108 case Data::Type::Float:
110 if(data.isNull() == true)
111 static_cast <dbms::Float&>(data) = 0.0;
114 case Data::Type::Date:
115 case Data::Type::TimeStamp:
116 _this->decodeDate(data);
118 case Data::Type::LongBlock:
121 _this->decodeLongBlob(data);
122 } catch(dbms::DatabaseException& edb) {
123 throw RuntimeException(edb);
130 void OutputBind::do_write(const dbms::LongBlock&) const
131 throw(RuntimeException, dbms::DatabaseException) {
135 * El m�todo BaseBind::setupBind asocia� el contenido de la variable
136 * a_time al buffer de salida de la sentencia SQL, as� que el contenido
137 * de la columna est� contenido ah�. S�lo tendremos que copiar dichos
138 * contenidos en la variable C++ de nuestro entorno.
140 void OutputBind::decodeDate(dbms::Data& data)
142 if(data.isNull() == true)
145 Date& date = static_cast <Date&>(data);
146 date.setYear(a_time->year);
147 date.setMonth(a_time->month);
148 date.setDay(a_time->day);
149 date.setHour(a_time->hour);
150 date.setMinute(a_time->minute);
151 date.setSecond(a_time->second);
153 if(data.getType() == Data::Type::TimeStamp)
154 static_cast <dbms::TimeStamp&>(data).setFractionalSecond(a_time->second_part);
158 * Según http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
160 * Recoge el contenido total de BLOB en partes que va componiendo sobre el
161 * DataBlock final asociado al anna::dbms::LongBlock sobre el que trabaja el
164 void OutputBind::decodeLongBlob(dbms::Data& data) const
165 throw(RuntimeException, dbms::DatabaseException) {
166 const int bufferSize = a_blob->buffer.getMaxSize();
167 const int pos = a_blob->pos;
168 st_mysql_bind& bind = a_blob->binds [a_blob->pos];
169 DataBlock& target = static_cast <dbms::LongBlock&>(data).getValue();
170 const int maxloop = *bind.length / bufferSize;
171 const int remainder = *bind.length % bufferSize;
174 bind.buffer = (void*) a_blob->buffer.getData();
176 for(int iloop = 0; iloop < maxloop; iloop ++) {
177 bind.buffer_length = bufferSize;
178 anna_dbms_mysql_check(
179 mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt
181 target += DataBlock((const char*) bind.buffer, bind.buffer_length, false);
182 offset += bufferSize;
186 bind.buffer_length = remainder;
187 anna_dbms_mysql_check(
188 mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt
190 target += DataBlock((const char*) bind.buffer, remainder, false);
194 OutputBind::Blob::Blob() :
196 buffer.allocate(64 * 1024);