First commit
[anna.git] / source / dbms.oracle / Statement.cpp
1 // ANNA - Anna is Not 'N' 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 #include <oci.h>
38
39 #include <anna/config/defines.hpp>
40 #include <anna/core/tracing/TraceMethod.hpp>
41
42 #include <anna/dbms.oracle/oracle.hpp>
43
44 using namespace std;
45 using namespace anna;
46
47 dbms::oracle::Statement::~Statement() {
48   if(a_ociStmt)
49     OCIHandleFree(a_ociStmt, OCI_HTYPE_STMT);
50 }
51
52 void dbms::oracle::Statement::prepare(dbms::Connection* dbmsConnection)
53 throw(RuntimeException, dbms::DatabaseException) {
54   LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Statement", "prepare", ANNA_FILE_LOCATION));
55   Connection* connection(static_cast <Connection*>(dbmsConnection));
56   Database& dbms(static_cast <Database&>(connection->getDatabase()));
57   a_ociError = dbms.getErrorHandler();
58
59   if(a_ociStmt != NULL) {
60     anna_dbms_oracle_check(OCIHandleFree(a_ociStmt, OCI_HTYPE_STMT), a_ociError);
61     a_ociStmt = NULL;
62   }
63
64   const char* expression = dbms::oracle::Statement::getExpression().c_str();
65
66   anna_dbms_oracle_check(OCIHandleAlloc(dbms, (void**) &a_ociStmt, OCI_HTYPE_STMT, 0, 0), a_ociError);
67
68   anna_dbms_oracle_check(
69     OCIStmtPrepare(a_ociStmt, a_ociError, (text*) expression, anna_strlen(expression), OCI_NTV_SYNTAX, OCI_DEFAULT),
70     a_ociError
71   );
72
73   int pos = 1;
74
75   for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++)
76     inputBind(ii)->prepare(this, dbmsConnection, pos ++);
77
78   pos = 1;
79
80   for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++)
81     outputBind(oo)->prepare(this, dbmsConnection, pos ++);
82 }
83
84 dbms::ResultCode dbms::oracle::Statement::execute(dbms::Connection* dbmsConnection)
85 throw(RuntimeException, dbms::DatabaseException) {
86   Connection* connection(static_cast <Connection*>(dbmsConnection));
87
88   for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) {
89     inputBind(ii)->code();
90     LOGDEBUG(
91       string msg("anna::dbms::oracle::Statement::InputBind: ");
92       msg += inputBind(ii)->asString();
93       Logger::debug(msg, ANNA_FILE_LOCATION);
94     );
95   }
96
97   const sword status = OCIStmtExecute(*connection, a_ociStmt, a_ociError, 1, 0, NULL, NULL, OCI_DEFAULT);
98
99   a_firstFetch = false;
100
101   ResultCode result(status, a_ociError);
102
103   if(result.successful() == true && result.notFound() == false) {
104     for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) {
105       outputBind(oo)->decode();
106       LOGDEBUG(
107         string msg("anna::dbms::oracle::Statement::OutputBind: ");
108         msg += outputBind(oo)->asString();
109         Logger::debug(msg, ANNA_FILE_LOCATION);
110       );
111     }
112
113     a_firstFetch = true;
114   }
115
116   return result;
117 }
118
119 //-------------------------------------------------------------------------------------------------
120 // (1) Si es una consulta de seleccin, entonces, nada m� ejecutar la sentencia el primer registro
121 //     encontrado ya est�cargado en las variables de salida, para obtener los siguientes hay que invocar
122 //     a fetch. Vamos a hacer este esquema m� gen�ico de forma que siempre habr�que invocar a
123 //     'fetch' para obtener los datos, pero en Oracle, la primera llamada no har�nada.
124 //-------------------------------------------------------------------------------------------------
125 bool dbms::oracle::Statement::fetch()
126 throw(RuntimeException, dbms::DatabaseException) {
127   bool result;
128
129   if(a_firstFetch == true) {    // (1)
130     a_firstFetch = false;
131     result = true;
132   } else {
133     ResultCode resultCode(OCIStmtFetch(a_ociStmt, a_ociError, 1, OCI_FETCH_NEXT, OCI_DEFAULT), a_ociError);
134     result = resultCode.successful();
135
136     if(result == false && resultCode.notFound() == false)
137       Logger::write(Logger::Error, asString(), resultCode.asString(), ANNA_FILE_LOCATION);
138
139     if(result == true) {
140       for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) {
141         outputBind(oo)->decode();
142         LOGDEBUG(Logger::write(Logger::Debug, outputBind(oo)->asString(), ANNA_FILE_LOCATION));
143       }
144     }
145   }
146
147   LOGDEBUG(
148     string msg("anna::dbms::oracle::Statement::fetch | Result: ");
149     msg += functions::asString(result);
150     Logger::debug(msg, ANNA_FILE_LOCATION);
151   );
152   return result;
153 }
154
155
156