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 : * SQLGetDiagField()
25 : * ODBC 3.0 API function
26 : * CLI Compliance: ISO 92
27 : **********************************************************************/
28 :
29 : #include "ODBCGlobal.h"
30 : #include "ODBCEnv.h"
31 : #include "ODBCDbc.h"
32 : #include "ODBCStmt.h"
33 : #include "ODBCError.h"
34 : #include "ODBCUtil.h"
35 :
36 : #define copyDiagString(str, buf, len, lenp) \
37 : do { \
38 : size_t _l; \
39 : if (len < 0) \
40 : return SQL_ERROR; \
41 : _l = strcpy_len((char *) buf, str, len); \
42 : if (lenp) \
43 : *lenp = (SQLSMALLINT) _l; \
44 : if (buf == NULL || _l >= (size_t) len) \
45 : return SQL_SUCCESS_WITH_INFO; \
46 : } while (0)
47 :
48 : static SQLRETURN
49 0 : MNDBGetDiagField(SQLSMALLINT HandleType,
50 : SQLHANDLE Handle,
51 : SQLSMALLINT RecNumber,
52 : SQLSMALLINT DiagIdentifier,
53 : SQLPOINTER DiagInfoPtr,
54 : SQLSMALLINT BufferLength,
55 : SQLSMALLINT *StringLengthPtr)
56 : {
57 0 : ODBCError *err;
58 0 : ODBCDbc *dbc = NULL;
59 :
60 : /* input & output parameters validity checks */
61 :
62 0 : switch (HandleType) {
63 0 : case SQL_HANDLE_ENV:
64 : /* Check if this struct is still valid/alive */
65 0 : if (!isValidEnv((ODBCEnv *) Handle))
66 : return SQL_INVALID_HANDLE;
67 0 : err = getEnvError((ODBCEnv *) Handle);
68 0 : break;
69 0 : case SQL_HANDLE_DBC:
70 : /* Check if this struct is still valid/alive */
71 0 : dbc = (ODBCDbc *) Handle;
72 0 : if (!isValidDbc(dbc))
73 : return SQL_INVALID_HANDLE;
74 0 : err = getDbcError(dbc);
75 0 : break;
76 0 : case SQL_HANDLE_STMT:
77 : /* Check if this struct is still valid/alive */
78 0 : if (!isValidStmt((ODBCStmt *) Handle))
79 : return SQL_INVALID_HANDLE;
80 0 : err = getStmtError((ODBCStmt *) Handle);
81 0 : dbc = ((ODBCStmt *) Handle)->Dbc;
82 0 : break;
83 0 : case SQL_HANDLE_DESC:
84 : /* Check if this struct is still valid/alive */
85 0 : if (!isValidDesc((ODBCDesc *) Handle))
86 : return SQL_INVALID_HANDLE;
87 0 : err = getDescError((ODBCDesc *) Handle);
88 0 : dbc = ((ODBCDesc *) Handle)->Dbc;
89 0 : break;
90 : default:
91 : return SQL_INVALID_HANDLE;
92 : }
93 :
94 : /* header fields */
95 0 : switch (DiagIdentifier) {
96 0 : case SQL_DIAG_CURSOR_ROW_COUNT: /* SQLLEN */
97 0 : if (HandleType != SQL_HANDLE_STMT)
98 : return SQL_ERROR;
99 0 : *(SQLLEN *) DiagInfoPtr = (SQLLEN) ((ODBCStmt *) Handle)->rowSetSize;
100 0 : return SQL_SUCCESS;
101 0 : case SQL_DIAG_DYNAMIC_FUNCTION: /* SQLCHAR* */
102 0 : if (HandleType != SQL_HANDLE_STMT)
103 : return SQL_ERROR;
104 0 : copyDiagString("", DiagInfoPtr, BufferLength, StringLengthPtr);
105 : return SQL_SUCCESS;
106 0 : case SQL_DIAG_DYNAMIC_FUNCTION_CODE: /* SQLINTEGER */
107 0 : if (HandleType != SQL_HANDLE_STMT)
108 : return SQL_ERROR;
109 0 : *(SQLINTEGER *) DiagInfoPtr = SQL_DIAG_UNKNOWN_STATEMENT;
110 0 : return SQL_SUCCESS;
111 0 : case SQL_DIAG_NUMBER: /* SQLINTEGER */
112 0 : *(SQLINTEGER *) DiagInfoPtr = getErrorRecCount(err);
113 0 : return SQL_SUCCESS;
114 0 : case SQL_DIAG_RETURNCODE: /* SQLRETURN */
115 0 : *(SQLRETURN *) DiagInfoPtr = SQL_SUCCESS;
116 0 : return SQL_SUCCESS;
117 0 : case SQL_DIAG_ROW_COUNT: /* SQLLEN */
118 0 : if (HandleType != SQL_HANDLE_STMT || ((ODBCStmt *) Handle)->State < EXECUTED0)
119 : return SQL_ERROR;
120 0 : *(SQLLEN *) DiagInfoPtr = (SQLLEN) ((ODBCStmt *) Handle)->rowcount;
121 0 : return SQL_SUCCESS;
122 : }
123 :
124 : /* record fields */
125 0 : if (RecNumber <= 0)
126 : return SQL_ERROR;
127 :
128 0 : err = getErrorRec(err, RecNumber);
129 0 : if (err == NULL)
130 : return SQL_NO_DATA;
131 :
132 0 : switch (DiagIdentifier) {
133 0 : case SQL_DIAG_CLASS_ORIGIN:{ /* SQLCHAR* */
134 0 : char *msg = strncmp(getSqlState(err), "IM", 2) == 0 ? "ODBC 3.0" : "ISO 9075";
135 :
136 0 : copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
137 : return SQL_SUCCESS;
138 : }
139 0 : case SQL_DIAG_COLUMN_NUMBER: /* SQLINTEGER */
140 0 : if (HandleType != SQL_HANDLE_STMT)
141 : return SQL_ERROR;
142 0 : *(SQLINTEGER *) DiagInfoPtr = SQL_COLUMN_NUMBER_UNKNOWN;
143 0 : return SQL_SUCCESS;
144 0 : case SQL_DIAG_CONNECTION_NAME:{ /* SQLCHAR* */
145 0 : char *msg = "MonetDB ODBC/Mapi";
146 :
147 0 : copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
148 : return SQL_SUCCESS;
149 : }
150 0 : case SQL_DIAG_MESSAGE_TEXT:{ /* SQLCHAR* */
151 0 : char *msg = getMessage(err);
152 :
153 : /* first write the error message prefix text:
154 : * [MonetDB][ODBC driver VERSION][DSN]
155 : * this is required by the ODBC spec:
156 : * https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/diagnostic-messages
157 : * and used to determine where the error originated
158 : */
159 0 : SQLSMALLINT msgLen;
160 0 : if (dbc && dbc->dsn)
161 0 : msgLen = (SQLSMALLINT) strconcat_len((char *) DiagInfoPtr, BufferLength, ODBCErrorMsgPrefix, "[", dbc->dsn, "]", msg, NULL);
162 : else
163 0 : msgLen = (SQLSMALLINT) strconcat_len((char *) DiagInfoPtr, BufferLength, ODBCErrorMsgPrefix, msg, NULL);
164 0 : if (StringLengthPtr)
165 0 : *StringLengthPtr = msgLen;
166 0 : if (DiagInfoPtr == NULL || msgLen >= BufferLength)
167 : return SQL_SUCCESS_WITH_INFO;
168 : return SQL_SUCCESS;
169 : }
170 0 : case SQL_DIAG_NATIVE: /* SQLINTEGER */
171 0 : *(SQLINTEGER *) DiagInfoPtr = getNativeErrorCode(err);
172 0 : return SQL_SUCCESS;
173 0 : case SQL_DIAG_ROW_NUMBER: /* SQLLEN */
174 0 : if (HandleType != SQL_HANDLE_STMT)
175 : return SQL_ERROR;
176 0 : *(SQLLEN *) DiagInfoPtr = SQL_ROW_NUMBER_UNKNOWN;
177 0 : return SQL_SUCCESS;
178 0 : case SQL_DIAG_SERVER_NAME:{ /* SQLCHAR* */
179 0 : char *msg = dbc && dbc->Connected && dbc->dsn ? dbc->dsn : "";
180 :
181 0 : copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
182 : return SQL_SUCCESS;
183 : }
184 0 : case SQL_DIAG_SQLSTATE:{ /* SQLCHAR* */
185 0 : char *msg = getSqlState(err);
186 :
187 0 : copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
188 : return SQL_SUCCESS;
189 : }
190 0 : case SQL_DIAG_SUBCLASS_ORIGIN:{ /* SQLCHAR* */
191 0 : char *state = getSqlState(err);
192 0 : char *msg;
193 :
194 0 : if (('0' <= state[0] && state[0] <= '4') ||
195 : ('A' <= state[0] && state[0] <= 'H'))
196 : msg = "ISO 9075"; /* defined by standard */
197 : else
198 0 : msg = "ODBC 3.0"; /* effectively just "IM" */
199 :
200 0 : copyDiagString(msg, DiagInfoPtr, BufferLength, StringLengthPtr);
201 : return SQL_SUCCESS;
202 : }
203 : }
204 :
205 : /* Currently no Diagnostic Fields are supported.
206 : Hence we always return NO_DATA */
207 : return SQL_NO_DATA;
208 : }
209 :
210 : #ifdef ODBCDEBUG
211 : static char *
212 0 : translateDiagIdentifier(SQLSMALLINT DiagIdentifier)
213 : {
214 0 : static char unknown[32];
215 :
216 0 : switch (DiagIdentifier) {
217 : case SQL_DIAG_CLASS_ORIGIN:
218 : return "SQL_DIAG_CLASS_ORIGIN";
219 0 : case SQL_DIAG_COLUMN_NUMBER:
220 0 : return "SQL_DIAG_COLUMN_NUMBER";
221 0 : case SQL_DIAG_CONNECTION_NAME:
222 0 : return "SQL_DIAG_CONNECTION_NAME";
223 0 : case SQL_DIAG_CURSOR_ROW_COUNT:
224 0 : return "SQL_DIAG_CURSOR_ROW_COUNT";
225 0 : case SQL_DIAG_DYNAMIC_FUNCTION:
226 0 : return "SQL_DIAG_DYNAMIC_FUNCTION";
227 0 : case SQL_DIAG_DYNAMIC_FUNCTION_CODE:
228 0 : return "SQL_DIAG_DYNAMIC_FUNCTION_CODE";
229 0 : case SQL_DIAG_MESSAGE_TEXT:
230 0 : return "SQL_DIAG_MESSAGE_TEXT";
231 0 : case SQL_DIAG_NATIVE:
232 0 : return "SQL_DIAG_NATIVE";
233 0 : case SQL_DIAG_NUMBER:
234 0 : return "SQL_DIAG_NUMBER";
235 0 : case SQL_DIAG_RETURNCODE:
236 0 : return "SQL_DIAG_RETURNCODE";
237 0 : case SQL_DIAG_ROW_COUNT:
238 0 : return "SQL_DIAG_ROW_COUNT";
239 0 : case SQL_DIAG_ROW_NUMBER:
240 0 : return "SQL_DIAG_ROW_NUMBER";
241 0 : case SQL_DIAG_SERVER_NAME:
242 0 : return "SQL_DIAG_SERVER_NAME";
243 0 : case SQL_DIAG_SQLSTATE:
244 0 : return "SQL_DIAG_SQLSTATE";
245 0 : case SQL_DIAG_SUBCLASS_ORIGIN:
246 0 : return "SQL_DIAG_SUBCLASS_ORIGIN";
247 0 : default:
248 0 : snprintf(unknown, sizeof(unknown), "unknown (%d)",
249 : (int) DiagIdentifier);
250 0 : return unknown;
251 : }
252 : }
253 : #endif
254 :
255 : SQLRETURN SQL_API
256 : SQLGetDiagField(SQLSMALLINT HandleType,
257 : SQLHANDLE Handle,
258 : SQLSMALLINT RecNumber,
259 : SQLSMALLINT DiagIdentifier,
260 : SQLPOINTER DiagInfoPtr,
261 : SQLSMALLINT BufferLength,
262 : SQLSMALLINT *StringLengthPtr)
263 : {
264 : #ifdef ODBCDEBUG
265 0 : ODBCLOG("SQLGetDiagField %s %p %d %s %p %d %p\n",
266 : HandleType == SQL_HANDLE_ENV ? "Env" : HandleType == SQL_HANDLE_DBC ? "Dbc" : HandleType == SQL_HANDLE_STMT ? "Stmt" : "Desc",
267 : Handle, (int) RecNumber,
268 : translateDiagIdentifier(DiagIdentifier),
269 : DiagInfoPtr,
270 : (int) BufferLength, StringLengthPtr);
271 : #endif
272 :
273 0 : return MNDBGetDiagField(HandleType,
274 : Handle,
275 : RecNumber,
276 : DiagIdentifier,
277 : DiagInfoPtr,
278 : BufferLength,
279 : StringLengthPtr);
280 : }
281 :
282 : SQLRETURN SQL_API
283 : SQLGetDiagFieldA(SQLSMALLINT HandleType,
284 : SQLHANDLE Handle,
285 : SQLSMALLINT RecNumber,
286 : SQLSMALLINT DiagIdentifier,
287 : SQLPOINTER DiagInfoPtr,
288 : SQLSMALLINT BufferLength,
289 : SQLSMALLINT *StringLengthPtr)
290 : {
291 0 : return SQLGetDiagField(HandleType,
292 : Handle,
293 : RecNumber,
294 : DiagIdentifier,
295 : DiagInfoPtr,
296 : BufferLength,
297 : StringLengthPtr);
298 : }
299 :
300 : SQLRETURN SQL_API
301 : SQLGetDiagFieldW(SQLSMALLINT HandleType,
302 : SQLHANDLE Handle,
303 : SQLSMALLINT RecNumber,
304 : SQLSMALLINT DiagIdentifier,
305 : SQLPOINTER DiagInfoPtr,
306 : SQLSMALLINT BufferLength,
307 : SQLSMALLINT *StringLengthPtr)
308 : {
309 0 : SQLRETURN rc;
310 0 : SQLPOINTER ptr = NULL;
311 0 : SQLSMALLINT n;
312 :
313 : #ifdef ODBCDEBUG
314 0 : ODBCLOG("SQLGetDiagFieldW %s %p %d %s %p %d %p\n",
315 : HandleType == SQL_HANDLE_ENV ? "Env" : HandleType == SQL_HANDLE_DBC ? "Dbc" : HandleType == SQL_HANDLE_STMT ? "Stmt" : "Desc",
316 : Handle, (int) RecNumber,
317 : translateDiagIdentifier(DiagIdentifier),
318 : DiagInfoPtr,
319 : (int) BufferLength, StringLengthPtr);
320 : #endif
321 :
322 0 : switch (DiagIdentifier) {
323 : /* all string attributes */
324 0 : case SQL_DIAG_DYNAMIC_FUNCTION:
325 : case SQL_DIAG_CLASS_ORIGIN:
326 : case SQL_DIAG_CONNECTION_NAME:
327 : case SQL_DIAG_MESSAGE_TEXT:
328 : case SQL_DIAG_SERVER_NAME:
329 : case SQL_DIAG_SQLSTATE:
330 : case SQL_DIAG_SUBCLASS_ORIGIN:
331 0 : rc = MNDBGetDiagField(HandleType, Handle, RecNumber,
332 : DiagIdentifier, NULL, 0, &n);
333 0 : if (!SQL_SUCCEEDED(rc))
334 : return rc;
335 0 : n++; /* account for NUL byte */
336 0 : ptr = (SQLPOINTER) malloc(n);
337 0 : break;
338 0 : default:
339 0 : n = BufferLength;
340 0 : ptr = DiagInfoPtr;
341 0 : break;
342 : }
343 :
344 0 : rc = MNDBGetDiagField(HandleType, Handle, RecNumber,
345 : DiagIdentifier, ptr, n, &n);
346 : #ifdef ODBCDEBUG
347 0 : if (ptr != DiagInfoPtr)
348 0 : ODBCLOG("SQLGetDiagFieldW: %s\n", (char *) ptr);
349 : #endif
350 :
351 0 : if (ptr != DiagInfoPtr) {
352 0 : if (SQL_SUCCEEDED(rc)) {
353 0 : const char *e = ODBCutf82wchar(ptr, n, DiagInfoPtr,
354 : BufferLength / 2, &n,
355 : NULL);
356 :
357 0 : if (e)
358 0 : rc = SQL_ERROR;
359 0 : if (StringLengthPtr)
360 0 : *StringLengthPtr = n * 2;
361 : }
362 0 : free(ptr);
363 : }
364 :
365 : return rc;
366 : }
|