Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * This code was created by Peter Harvey (mostly during Christmas 98/99).
15 : * This code is LGPL. Please ensure that this message remains in future
16 : * distributions and uses of this code (thats about all I get out of it).
17 : * - Peter Harvey pharvey@codebydesign.com
18 : *
19 : * This file has been modified for the MonetDB project. See the file
20 : * Copyright in this directory for more information.
21 : */
22 :
23 : /**********************************************
24 : * ODBCStmt.c
25 : *
26 : * Description:
27 : * This file contains the functions which operate on
28 : * ODBC statement structures/objects (see ODBCStmt.h).
29 : *
30 : * Author: Martin van Dinther, Sjoerd Mullender
31 : * Date : 30 aug 2002
32 : *
33 : **********************************************/
34 :
35 : #include "ODBCGlobal.h"
36 : #include "ODBCStmt.h"
37 :
38 : #define ODBC_STMT_MAGIC_NR 5461 /* for internal sanity check only */
39 :
40 :
41 : /*
42 : * Creates a new allocated ODBCStmt object and initializes it.
43 : *
44 : * Precondition: none
45 : * Postcondition: returns a new ODBCStmt object
46 : */
47 : ODBCStmt *
48 13 : newODBCStmt(ODBCDbc *dbc)
49 : {
50 13 : ODBCStmt *stmt = (ODBCStmt *) malloc(sizeof(ODBCStmt));
51 :
52 13 : assert(dbc);
53 13 : assert(dbc->mid);
54 :
55 13 : if (stmt == NULL) {
56 : /* Memory allocation error */
57 0 : addDbcError(dbc, "HY001", NULL, 0);
58 0 : return NULL;
59 : }
60 :
61 26 : *stmt = (ODBCStmt) {
62 : .Dbc = dbc,
63 : .Error = NULL,
64 : .RetrievedErrors = 0,
65 :
66 : .State = INITED,
67 13 : .hdl = mapi_new_handle(dbc->mid),
68 : .currentRow = 0,
69 : .startRow = 0,
70 : .rowSetSize = 0,
71 : .queryid = -1,
72 : .nparams = 0,
73 : .querytype = -1,
74 : .rowcount = 0,
75 :
76 13 : .qtimeout = dbc->qtimeout, /* inherit query timeout */
77 :
78 : .cursorType = SQL_CURSOR_FORWARD_ONLY,
79 : .cursorScrollable = SQL_NONSCROLLABLE,
80 : .retrieveData = SQL_RD_ON,
81 : .noScan = SQL_NOSCAN_OFF,
82 :
83 13 : .AutoApplRowDescr = newODBCDesc(dbc),
84 13 : .AutoApplParamDescr = newODBCDesc(dbc),
85 13 : .ImplRowDescr = newODBCDesc(dbc),
86 13 : .ImplParamDescr = newODBCDesc(dbc),
87 :
88 : .Type = ODBC_STMT_MAGIC_NR, /* set it valid */
89 : };
90 :
91 13 : if (stmt->hdl == NULL) {
92 : /* Memory allocation error */
93 0 : addDbcError(dbc, "HY001", NULL, 0);
94 0 : destroyODBCStmt(stmt);
95 0 : return NULL;
96 : }
97 13 : if (stmt->AutoApplRowDescr == NULL || stmt->AutoApplParamDescr == NULL ||
98 13 : stmt->ImplRowDescr == NULL || stmt->ImplParamDescr == NULL) {
99 0 : destroyODBCStmt(stmt);
100 0 : return NULL;
101 : }
102 :
103 13 : stmt->AutoApplRowDescr->sql_desc_alloc_type = SQL_DESC_ALLOC_AUTO;
104 13 : stmt->AutoApplParamDescr->sql_desc_alloc_type = SQL_DESC_ALLOC_AUTO;
105 13 : stmt->ImplRowDescr->sql_desc_alloc_type = SQL_DESC_ALLOC_AUTO;
106 13 : stmt->ImplParamDescr->sql_desc_alloc_type = SQL_DESC_ALLOC_AUTO;
107 13 : stmt->ImplRowDescr->Stmt = stmt;
108 13 : stmt->ImplParamDescr->Stmt = stmt;
109 13 : stmt->ApplRowDescr = stmt->AutoApplRowDescr;
110 13 : stmt->ApplParamDescr = stmt->AutoApplParamDescr;
111 :
112 : /* add this stmt to the administrative linked stmt list */
113 13 : stmt->next = dbc->FirstStmt,
114 13 : dbc->FirstStmt = stmt;
115 :
116 13 : return stmt;
117 : }
118 :
119 :
120 : /*
121 : * Check if the statement handle is valid.
122 : * Note: this function is used internally by the driver to assert legal
123 : * and save usage of the handle and prevent crashes as much as possible.
124 : *
125 : * Precondition: none
126 : * Postcondition: returns 1 if it is a valid statement handle,
127 : * returns 0 if is invalid and thus an unusable handle.
128 : */
129 : int
130 13361 : isValidStmt(ODBCStmt *stmt)
131 : {
132 : #ifdef ODBCDEBUG
133 13361 : if (!(stmt &&stmt->Type == ODBC_STMT_MAGIC_NR))
134 0 : ODBCLOG("stmt %p not a valid statement handle\n", stmt);
135 : #endif
136 13361 : return stmt &&stmt->Type == ODBC_STMT_MAGIC_NR;
137 : }
138 :
139 :
140 : /*
141 : * Creates and adds an error msg object to the end of the error list of
142 : * this ODBCStmt struct.
143 : * When the errMsg is NULL and the SQLState is an ISO SQLState the
144 : * standard ISO message text for the SQLState is used as message.
145 : *
146 : * Precondition: stmt must be valid. SQLState and errMsg may be NULL.
147 : */
148 : void
149 60 : addStmtError(ODBCStmt *stmt, const char *SQLState, const char *errMsg, int nativeErrCode)
150 : {
151 60 : ODBCError *error = NULL;
152 :
153 : #ifdef ODBCDEBUG
154 60 : ODBCLOG("addStmtError %p %s %s %d\n", stmt, SQLState, errMsg ? errMsg : getStandardSQLStateMsg(SQLState), nativeErrCode);
155 : #endif
156 60 : assert(isValidStmt(stmt));
157 :
158 60 : error = newODBCError(SQLState, errMsg, nativeErrCode);
159 60 : appendODBCError(&stmt->Error, error);
160 60 : }
161 :
162 :
163 : /*
164 : * Extracts an error object from the error list of this ODBCStmt struct.
165 : * The error object itself is removed from the error list.
166 : * The caller is now responsible for freeing the error object memory.
167 : *
168 : * Precondition: stmt and error must be valid
169 : * Postcondition: returns a ODBCError object or null when no error is available.
170 : */
171 : ODBCError *
172 47 : getStmtError(ODBCStmt *stmt)
173 : {
174 47 : assert(isValidStmt(stmt));
175 47 : return stmt->Error;
176 : }
177 :
178 :
179 :
180 : /*
181 : * Destroys the ODBCStmt object including its own managed data.
182 : *
183 : * Precondition: stmt must be valid.
184 : * Postcondition: stmt is completely destroyed, stmt handle is invalid.
185 : */
186 : void
187 13 : destroyODBCStmt(ODBCStmt *stmt)
188 : {
189 13 : ODBCStmt **stmtp;
190 :
191 13 : assert(isValidStmt(stmt));
192 :
193 : /* first set this object to invalid */
194 13 : stmt->Type = 0;
195 :
196 : /* remove this stmt from the dbc */
197 13 : assert(stmt->Dbc);
198 :
199 : /* search for stmt in linked list */
200 13 : stmtp = &stmt->Dbc->FirstStmt;
201 :
202 14 : while (*stmtp && *stmtp != stmt)
203 1 : stmtp = &(*stmtp)->next;
204 : /* stmtp points to location in list where stmt is found, or
205 : * *stmtp is NULL in case it wasn't there (presumably not added
206 : * yet) */
207 :
208 13 : if (*stmtp) {
209 : /* now remove it from the linked list */
210 13 : *stmtp = stmt->next;
211 : }
212 :
213 : /* cleanup own managed data */
214 13 : deleteODBCErrorList(&stmt->Error);
215 :
216 13 : destroyODBCDesc(stmt->ImplParamDescr);
217 13 : destroyODBCDesc(stmt->ImplRowDescr);
218 13 : destroyODBCDesc(stmt->AutoApplParamDescr);
219 13 : destroyODBCDesc(stmt->AutoApplRowDescr);
220 :
221 13 : if (stmt->hdl)
222 13 : mapi_close_handle(stmt->hdl);
223 :
224 13 : free(stmt);
225 13 : }
|