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
40 #include <anna/config/defines.hpp>
41 #include <anna/core/tracing/Logger.hpp>
42 #include <anna/core/DataBlock.hpp>
44 #include <anna/dbms/Float.hpp>
45 #include <anna/dbms/ShortBlock.hpp>
46 #include <anna/dbms/LongBlock.hpp>
47 #include <anna/dbms/String.hpp>
48 #include <anna/dbms/Date.hpp>
49 #include <anna/dbms/TimeStamp.hpp>
51 #include <anna/dbms.oracle/oracle.hpp>
56 OutputBind::OutputBind(const char* name, dbms::Data& data) :
57 dbms::OutputBind(name, data),
62 OutputBind::~OutputBind() {
65 void OutputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos)
66 throw(dbms::DatabaseException) {
67 if(a_ociDefine != NULL)
70 Database& database(static_cast <Database&>(dbmsStatement->getDatabase()));
71 OCIError* error = database.getErrorHandler();
72 Statement* statement(static_cast <Statement*>(dbmsStatement));
73 dbms::Data& data = anna::dbms::Bind::getData();
74 oci_param ociparam = getOCIParam(database, static_cast <oracle::Connection*>(connection), data);
76 if(data.isNulleable() == false) {
77 anna_dbms_oracle_check(
79 *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type,
80 0, ociparam.length, 0, OCI_DEFAULT
85 anna_dbms_oracle_check(
87 *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type,
88 &a_nullIndicator, ociparam.length, 0, OCI_DEFAULT
95 std::string msg("anna::dbms::oracle::OutputBind::prepare | ");
97 msg += " | Sentence: ";
98 msg += statement->getName();
99 msg += " | Position: ";
100 msg += functions::asString(pos);
101 Logger::debug(msg, ANNA_FILE_LOCATION)
105 //-------------------------------------------------------------------------------
106 // Transfiere la informacin obtenida desde Oracle. Todos los comprobados en �te
107 // m�odo son parametros que modificados al ejecuta la sentencia Oracle debido cmo
108 // hemos invocamo al m�odo OCIDefineByPos
110 // Todo esto se podr� haber hecho en la anna::dbms::DataBlock pero exigir�
111 // definir una clase distinta para cada RDBMS. Creo que los Binds particulares de
112 // cada base de datos se ocupen toda la complejidad de convertir los datos.
114 // (1) Truco para fijar el contenido y la longitud actual.
115 //-------------------------------------------------------------------------------
116 void OutputBind::decode() const
117 throw(RuntimeException) {
118 OutputBind* _this = const_cast <OutputBind*>(this);
120 Data& data = _this->getData();
121 data.setNull(a_nullIndicator < 0);
123 switch(data.getType()) {
124 case Data::Type::String:
125 str = (char*) data.getBuffer();
127 if(data.isNull() == true)
130 dbms::String::strip(str);
133 case Data::Type::Float:
136 case Data::Type::ShortBlock:
137 decodeShortBlock(data);
139 case Data::Type::LongBlock:
140 decodeLongBlock(data);
142 case Data::Type::Date:
143 case Data::Type::TimeStamp:
147 } catch(DatabaseException& edb) {
148 throw RuntimeException(edb);
155 void OutputBind::decodeFloat(dbms::Data& data) const
156 throw(RuntimeException) {
157 dbms::Float& _float = static_cast <dbms::Float&>(data);
159 if(data.isNull() == true) {
164 char* _data = (char*) a_ofb->getData();
165 const char decimalPoint = oracle::Database::getDecimalPoint();
167 if(decimalPoint != 0) {
168 char* point = anna_strchr(_data, decimalPoint);
174 sscanf(_data, _float.getFormat(), (float*) _float.getBuffer());
177 void OutputBind::decodeShortBlock(dbms::Data& data) const
178 throw(RuntimeException) {
179 const anna::DataBlock& constdbms(static_cast <dbms::ShortBlock&>(data).getValue());
180 anna::DataBlock& dataBlock(const_cast <anna::DataBlock&>(constdbms));
182 if(data.isNull() == true) {
187 const char* src = a_ofb->getData();
189 char* dest = (char*) dataBlock.getData();
195 for(int i = 1; i < a_length; i += 2, j ++) {
196 hex = asByte(src [i - 1]) << 4;
197 hex |= asByte(src [i]);
202 dataBlock.allocate(j); // (1)
205 //--------------------------------------------------------------------------------------------
206 // (1) Offset = 1 => primer caracter.
207 //--------------------------------------------------------------------------------------------
208 void OutputBind::decodeLongBlock(dbms::Data& data) const
209 throw(RuntimeException) {
210 const anna::DataBlock& constdbms(static_cast <dbms::LongBlock&>(data).getValue());
211 anna::DataBlock& dataBlock(const_cast <anna::DataBlock&>(constdbms));
214 if(data.isNull() == true)
222 ub4 offset = 1; // (1)
225 buffer = (ub1*) a_ofb->getData();
226 maxLength = a_ofb->getSize();
230 ret = OCILobRead(a_blob.context, a_blob.error, a_blob.handle, &length, offset, buffer, maxLength, 0, 0, 0, SQLCS_IMPLICIT);
234 dataBlock += anna::DataBlock((const char*) buffer, length, false);
238 dataBlock += anna::DataBlock((const char*) buffer, length, false);
242 throw dbms::DatabaseException(oracle::ResultCode(ret, a_blob.error), ANNA_FILE_LOCATION);
244 } while(stop == false);
245 } catch(dbms::DatabaseException& edbms) {
246 throw RuntimeException(edbms);
250 void OutputBind::do_write(const dbms::LongBlock& data) const
251 throw(RuntimeException, dbms::DatabaseException) {
252 const anna::DataBlock& dataBlock = data.getValue();
254 if(a_blob.handle == NULL) {
255 string msg("anna::dbms::oracle::OutputBind::do_write | ");
256 msg += data.asString();
257 msg += " | BLOB must be loaded before modification";
258 throw RuntimeException(msg, ANNA_FILE_LOCATION);
261 ub1* buffer = (ub1*) dataBlock.getData();
262 ub4 length = dataBlock.getSize();
263 anna_dbms_oracle_check(
264 OCILobWrite(a_blob.context, a_blob.error, a_blob.handle, &length, (ub4) 1, buffer, length, OCI_ONE_PIECE, 0, 0, 0, SQLCS_IMPLICIT),
269 void OutputBind::decodeDate(dbms::Data& data) const
270 throw(RuntimeException, dbms::DatabaseException) {
271 if(data.isNull() == true)
274 Date& date = static_cast <Date&>(data);
277 anna_dbms_oracle_check(
278 OCIDateTimeGetDate(a_datetime.env, a_datetime.error, a_datetime.handle, &year, &month, &day),
282 date.setMonth(month);
286 sword status = OCIDateTimeGetTime(a_datetime.env, a_datetime.error, a_datetime.handle, &hour, &min, &sec, &fsec);
288 if(status == OCI_SUCCESS) {
293 if(data.getType() == Data::Type::TimeStamp)
294 static_cast <dbms::TimeStamp&>(data).setFractionalSecond(fsec / 1000);
300 if(data.getType() == Data::Type::TimeStamp)
301 static_cast <dbms::TimeStamp&>(data).setFractionalSecond(0);