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 : #include "ODBCGlobal.h"
14 : #include "ODBCStmt.h"
15 :
16 : #define ODBC_DESC_MAGIC_NR 21845 /* for internal sanity check only */
17 :
18 : /*
19 : * Creates a new allocated ODBCDesc object and initializes it.
20 : *
21 : * Precondition: valid ODBCDbc object
22 : * Postcondition: returns a new ODBCDesc object
23 : */
24 : ODBCDesc *
25 52 : newODBCDesc(ODBCDbc *dbc)
26 : {
27 52 : ODBCDesc *desc;
28 :
29 52 : assert(dbc);
30 :
31 52 : desc = (ODBCDesc *) malloc(sizeof(ODBCDesc));
32 52 : if (desc == NULL) {
33 : /* Memory allocation error */
34 0 : addDbcError(dbc, "HY001", NULL, 0);
35 0 : return NULL;
36 : }
37 :
38 52 : *desc = (ODBCDesc) {
39 : .Dbc = dbc,
40 : .sql_desc_alloc_type = SQL_DESC_ALLOC_USER,
41 : .sql_desc_array_size = 1,
42 : .sql_desc_bind_type = SQL_BIND_TYPE_DEFAULT,
43 : .Type = ODBC_DESC_MAGIC_NR, /* set it valid */
44 : };
45 52 : return desc;
46 : }
47 :
48 :
49 : /*
50 : * Check if the descriptor handle is valid.
51 : * Note: this function is used internally by the driver to assert legal
52 : * and save usage of the handle and prevent crashes as much as possible.
53 : *
54 : * Precondition: none
55 : * Postcondition: returns 1 if it is a valid statement handle,
56 : * returns 0 if is invalid and thus an unusable handle.
57 : */
58 : int
59 52 : isValidDesc(ODBCDesc *desc)
60 : {
61 : #ifdef ODBCDEBUG
62 52 : if (!(desc && desc->Type == ODBC_DESC_MAGIC_NR))
63 0 : ODBCLOG("desc %pnot a valid descriptor handle\n", desc);
64 : #endif
65 52 : return desc && desc->Type == ODBC_DESC_MAGIC_NR;
66 : }
67 :
68 : /*
69 : * Creates and adds an error msg object to the end of the error list of
70 : * this ODBCDesc struct.
71 : * When the errMsg is NULL and the SQLState is an ISO SQLState the
72 : * standard ISO message text for the SQLState is used as message.
73 : *
74 : * Precondition: desc must be valid. SQLState and errMsg may be NULL.
75 : */
76 : void
77 0 : addDescError(ODBCDesc *desc, const char *SQLState, const char *errMsg, int nativeErrCode)
78 : {
79 0 : ODBCError *error = NULL;
80 :
81 : #ifdef ODBCDEBUG
82 0 : ODBCLOG("addDescError %p %s %s %d\n", desc, SQLState, errMsg ? errMsg : getStandardSQLStateMsg(SQLState), nativeErrCode);
83 : #endif
84 0 : assert(isValidDesc(desc));
85 :
86 0 : error = newODBCError(SQLState, errMsg, nativeErrCode);
87 0 : appendODBCError(&desc->Error, error);
88 0 : }
89 :
90 : /*
91 : * Extracts an error object from the error list of this ODBCDesc struct.
92 : * The error object itself is removed from the error list.
93 : * The caller is now responsible for freeing the error object memory.
94 : *
95 : * Precondition: desc and error must be valid
96 : * Postcondition: returns a ODBCError object or null when no error is available.
97 : */
98 : ODBCError *
99 0 : getDescError(ODBCDesc *desc)
100 : {
101 0 : assert(isValidDesc(desc));
102 0 : return desc->Error;
103 : }
104 :
105 : static void
106 994 : cleanODBCDescRec(ODBCDesc *desc, ODBCDescRec *rec)
107 : {
108 994 : if (rec->sql_desc_base_column_name)
109 90 : free(rec->sql_desc_base_column_name);
110 994 : if (rec->sql_desc_base_table_name)
111 92 : free(rec->sql_desc_base_table_name);
112 994 : if (rec->sql_desc_catalog_name)
113 0 : free(rec->sql_desc_catalog_name);
114 994 : if (rec->sql_desc_label)
115 915 : free(rec->sql_desc_label);
116 994 : if (rec->sql_desc_literal_prefix)
117 0 : free(rec->sql_desc_literal_prefix);
118 994 : if (rec->sql_desc_literal_suffix)
119 0 : free(rec->sql_desc_literal_suffix);
120 994 : if (rec->sql_desc_local_type_name)
121 0 : free(rec->sql_desc_local_type_name);
122 994 : if (rec->sql_desc_name)
123 915 : free(rec->sql_desc_name);
124 994 : if (rec->sql_desc_schema_name)
125 915 : free(rec->sql_desc_schema_name);
126 994 : if (rec->sql_desc_table_name)
127 915 : free(rec->sql_desc_table_name);
128 994 : if (rec->sql_desc_type_name)
129 922 : free(rec->sql_desc_type_name);
130 994 : *rec = (ODBCDescRec) {0};
131 994 : if (desc) {
132 2 : if (isAD(desc)) {
133 0 : rec->sql_desc_concise_type = SQL_C_DEFAULT;
134 0 : rec->sql_desc_type = SQL_C_DEFAULT;
135 2 : } else if (isIPD(desc)) {
136 2 : rec->sql_desc_parameter_type = SQL_PARAM_INPUT;
137 2 : rec->sql_desc_nullable = SQL_NULLABLE;
138 : }
139 : }
140 994 : }
141 :
142 : void
143 2521 : setODBCDescRecCount(ODBCDesc *desc, int count)
144 : {
145 2521 : assert(count >= 0);
146 2521 : assert(desc->sql_desc_count >= 0);
147 :
148 2521 : if (count == desc->sql_desc_count)
149 : return;
150 235 : if (count < desc->sql_desc_count) {
151 109 : int i;
152 :
153 1101 : for (i = count + 1; i <= desc->sql_desc_count; i++)
154 992 : cleanODBCDescRec(NULL, &desc->descRec[i]);
155 : }
156 235 : if (count == 0) {
157 106 : assert(desc->descRec != NULL);
158 106 : free(desc->descRec);
159 106 : desc->descRec = NULL;
160 129 : } else if (desc->descRec == NULL) {
161 106 : assert(desc->sql_desc_count == 0);
162 106 : desc->descRec = malloc((count + 1) * sizeof(*desc->descRec));
163 : } else {
164 23 : ODBCDescRec *p;
165 23 : assert(desc->sql_desc_count > 0);
166 23 : p = realloc(desc->descRec, (count + 1) * sizeof(*desc->descRec));
167 23 : if (p == NULL)
168 : return; /* TODO: error handling */
169 23 : desc->descRec = p;
170 : }
171 235 : if (count > desc->sql_desc_count) {
172 126 : int i;
173 :
174 126 : memset(desc->descRec + desc->sql_desc_count + 1, 0, (count - desc->sql_desc_count) * sizeof(*desc->descRec));
175 126 : if (isAD(desc)) {
176 57 : for (i = desc->sql_desc_count + 1; i <= count; i++) {
177 36 : desc->descRec[i].sql_desc_concise_type = SQL_C_DEFAULT;
178 36 : desc->descRec[i].sql_desc_type = SQL_C_DEFAULT;
179 : }
180 105 : } else if (isIPD(desc)) {
181 45 : for (i = desc->sql_desc_count + 1; i <= count; i++) {
182 34 : desc->descRec[i].sql_desc_parameter_type = SQL_PARAM_INPUT;
183 34 : desc->descRec[i].sql_desc_nullable = SQL_NULLABLE;
184 : }
185 : }
186 : }
187 235 : desc->sql_desc_count = count;
188 : }
189 :
190 : /*
191 : * Destroys the ODBCDesc object including its own managed data.
192 : *
193 : * Precondition: desc must be valid.
194 : * Postcondition: desc is completely destroyed, desc handle is become invalid.
195 : */
196 : void
197 52 : destroyODBCDesc(ODBCDesc *desc)
198 : {
199 52 : assert(isValidDesc(desc));
200 :
201 52 : desc->Type = 0;
202 52 : deleteODBCErrorList(&desc->Error);
203 52 : setODBCDescRecCount(desc, 0);
204 52 : free(desc);
205 52 : }
206 :
207 : ODBCDescRec *
208 18 : addODBCDescRec(ODBCDesc *desc, SQLSMALLINT recno)
209 : {
210 18 : assert(desc);
211 18 : assert(recno > 0);
212 :
213 18 : if (desc->sql_desc_count < recno)
214 16 : setODBCDescRecCount(desc, recno);
215 : else {
216 2 : assert(desc->descRec != NULL);
217 2 : cleanODBCDescRec(desc, &desc->descRec[recno]);
218 : }
219 :
220 18 : return &desc->descRec[recno];
221 : }
222 :
223 : /* Return either the column size or display size for a column or parameter. */
224 : SQLULEN
225 2118 : ODBCLength(ODBCDescRec *rec, int lengthtype)
226 : {
227 2118 : switch (rec->sql_desc_concise_type) {
228 0 : case SQL_CHAR:
229 : case SQL_VARCHAR:
230 : case SQL_LONGVARCHAR:
231 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
232 0 : return rec->sql_desc_length * 4;
233 : else
234 0 : return rec->sql_desc_length;
235 535 : case SQL_WCHAR:
236 : case SQL_WVARCHAR:
237 : case SQL_WLONGVARCHAR:
238 : case SQL_BINARY:
239 : case SQL_VARBINARY:
240 : case SQL_LONGVARBINARY:
241 535 : return rec->sql_desc_length;
242 8 : case SQL_DECIMAL:
243 : case SQL_NUMERIC:
244 12 : return rec->sql_desc_length + (lengthtype == SQL_DESC_LENGTH ? 0 : 2);
245 : case SQL_BIT:
246 : return 1;
247 48 : case SQL_TINYINT:
248 48 : switch (lengthtype) {
249 : case SQL_DESC_LENGTH:
250 : return 3;
251 12 : case SQL_DESC_DISPLAY_SIZE:
252 12 : return 3 + !rec->sql_desc_unsigned;
253 : case SQL_DESC_OCTET_LENGTH:
254 : return (int) sizeof(char);
255 : }
256 : break;
257 1001 : case SQL_SMALLINT:
258 1001 : switch (lengthtype) {
259 : case SQL_DESC_LENGTH:
260 : return 5;
261 260 : case SQL_DESC_DISPLAY_SIZE:
262 260 : return 5 + !rec->sql_desc_unsigned;
263 : case SQL_DESC_OCTET_LENGTH:
264 : return (int) sizeof(short);
265 : }
266 : break;
267 460 : case SQL_INTEGER:
268 460 : switch (lengthtype) {
269 : case SQL_DESC_LENGTH:
270 : return 10;
271 116 : case SQL_DESC_DISPLAY_SIZE:
272 116 : return 10 + !rec->sql_desc_unsigned;
273 : case SQL_DESC_OCTET_LENGTH:
274 : return (int) sizeof(int);
275 : }
276 : break;
277 4 : case SQL_BIGINT:
278 4 : switch (lengthtype) {
279 2 : case SQL_DESC_LENGTH:
280 2 : return 19 + (rec->sql_desc_unsigned != 0);
281 : case SQL_DESC_DISPLAY_SIZE:
282 : case SQL_DESC_OCTET_LENGTH:
283 : return 20;
284 : }
285 : break;
286 0 : case SQL_HUGEINT:
287 0 : switch (lengthtype) {
288 0 : case SQL_DESC_LENGTH:
289 0 : return 39 + (rec->sql_desc_unsigned != 0);
290 : case SQL_DESC_DISPLAY_SIZE:
291 : case SQL_DESC_OCTET_LENGTH:
292 : return 40;
293 : }
294 : break;
295 0 : case SQL_REAL:
296 0 : switch (lengthtype) {
297 : case SQL_DESC_LENGTH:
298 : return 7;
299 0 : case SQL_DESC_DISPLAY_SIZE:
300 : /* sign, 7 digits, decimal point, E, sign, 2 digits */
301 0 : return 14;
302 : case SQL_DESC_OCTET_LENGTH:
303 : return (int) sizeof(float);
304 : }
305 : break;
306 15 : case SQL_FLOAT:
307 : case SQL_DOUBLE:
308 15 : switch (lengthtype) {
309 : case SQL_DESC_LENGTH:
310 : return 15;
311 5 : case SQL_DESC_DISPLAY_SIZE:
312 : /* sign, 15 digits, decimal point, E, sign, 3 digits */
313 5 : return 24;
314 5 : case SQL_DESC_OCTET_LENGTH:
315 5 : return (int) sizeof(double);
316 : }
317 : break;
318 15 : case SQL_TYPE_DATE:
319 15 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
320 : return (int) sizeof(SQL_DATE_STRUCT);
321 : else {
322 : /* strlen("yyyy-mm-dd") */
323 : return 10;
324 : }
325 15 : case SQL_TYPE_TIME:
326 15 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
327 : return (int) sizeof(SQL_TIME_STRUCT);
328 : else {
329 : /* strlen("hh:mm:ss.fff") */
330 10 : return 12;
331 : }
332 0 : case SQL_TYPE_TIMESTAMP:
333 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
334 : return (int) sizeof(SQL_TIMESTAMP_STRUCT);
335 : else {
336 : /* strlen("yyyy-mm-dd hh:mm:ss.fff") */
337 0 : return 23;
338 : }
339 0 : case SQL_INTERVAL_SECOND:
340 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
341 : return (int) sizeof(SQL_INTERVAL_STRUCT);
342 : /* strlen("INTERVAL -'sss[.fff]' SECOND(p,q)") */
343 0 : return 11 + 13 +
344 0 : (rec->sql_desc_datetime_interval_precision > 10) +
345 0 : (rec->sql_desc_precision > 10) +
346 0 : rec->sql_desc_datetime_interval_precision +
347 : (rec->sql_desc_precision > 0 ?
348 0 : rec->sql_desc_precision + 1 :
349 : 0);
350 0 : case SQL_INTERVAL_DAY_TO_SECOND:
351 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
352 : return (int) sizeof(SQL_INTERVAL_STRUCT);
353 : /* strlen("INTERVAL -'ddd hh:mm:ss[.fff]' DAY(p) TO SECOND(q)") */
354 0 : return 11 + 21 +
355 0 : (rec->sql_desc_datetime_interval_precision > 10) +
356 0 : (rec->sql_desc_precision > 10) +
357 0 : rec->sql_desc_datetime_interval_precision +
358 0 : 9 +
359 : (rec->sql_desc_precision > 0 ?
360 0 : rec->sql_desc_precision + 1 :
361 : 0);
362 0 : case SQL_INTERVAL_HOUR_TO_SECOND:
363 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
364 : return (int) sizeof(SQL_INTERVAL_STRUCT);
365 : /* strlen("INTERVAL -'hhh:mm:ss[.fff]' HOUR(p) TO SECOND(q)") */
366 0 : return 11 + 22 +
367 0 : (rec->sql_desc_datetime_interval_precision > 10) +
368 0 : (rec->sql_desc_precision > 10) +
369 0 : rec->sql_desc_datetime_interval_precision +
370 0 : 6 +
371 : (rec->sql_desc_precision > 0 ?
372 0 : rec->sql_desc_precision + 1 :
373 : 0);
374 0 : case SQL_INTERVAL_MINUTE_TO_SECOND:
375 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
376 : return (int) sizeof(SQL_INTERVAL_STRUCT);
377 : /* strlen("INTERVAL -'mmm:ss[.fff]' MINUTE(p) TO SECOND(q)") */
378 0 : return 11 + 24 +
379 0 : (rec->sql_desc_datetime_interval_precision > 10) +
380 0 : (rec->sql_desc_precision > 10) +
381 0 : rec->sql_desc_datetime_interval_precision +
382 0 : 3 +
383 : (rec->sql_desc_precision > 0 ?
384 0 : rec->sql_desc_precision + 1 :
385 : 0);
386 0 : case SQL_INTERVAL_YEAR:
387 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
388 : return (int) sizeof(SQL_INTERVAL_STRUCT);
389 : /* strlen("INTERVAL -'yyy' YEAR(p)") */
390 0 : return 11 + 9 +
391 0 : (rec->sql_desc_datetime_interval_precision > 10) +
392 : rec->sql_desc_datetime_interval_precision;
393 0 : case SQL_INTERVAL_MONTH:
394 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
395 : return (int) sizeof(SQL_INTERVAL_STRUCT);
396 : /* strlen("INTERVAL -'yyy' MONTH(p)") */
397 0 : return 11 + 10 +
398 0 : (rec->sql_desc_datetime_interval_precision > 10) +
399 : rec->sql_desc_datetime_interval_precision;
400 0 : case SQL_INTERVAL_DAY:
401 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
402 : return (int) sizeof(SQL_INTERVAL_STRUCT);
403 : /* strlen("INTERVAL -'yyy' DAY(p)") */
404 0 : return 11 + 8 +
405 0 : (rec->sql_desc_datetime_interval_precision > 10) +
406 : rec->sql_desc_datetime_interval_precision;
407 0 : case SQL_INTERVAL_HOUR:
408 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
409 : return (int) sizeof(SQL_INTERVAL_STRUCT);
410 : /* strlen("INTERVAL -'yyy' HOUR(p)") */
411 0 : return 11 + 9 +
412 0 : (rec->sql_desc_datetime_interval_precision > 10) +
413 : rec->sql_desc_datetime_interval_precision;
414 0 : case SQL_INTERVAL_MINUTE:
415 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
416 : return (int) sizeof(SQL_INTERVAL_STRUCT);
417 : /* strlen("INTERVAL -'yyy' MINUTE(p)") */
418 0 : return 11 + 11 +
419 0 : (rec->sql_desc_datetime_interval_precision > 10) +
420 : rec->sql_desc_datetime_interval_precision;
421 0 : case SQL_INTERVAL_YEAR_TO_MONTH:
422 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
423 : return (int) sizeof(SQL_INTERVAL_STRUCT);
424 : /* strlen("INTERVAL -'yyy' YEAR(p) TO MONTH") */
425 0 : return 11 + 18 +
426 0 : (rec->sql_desc_datetime_interval_precision > 10) +
427 0 : rec->sql_desc_datetime_interval_precision +
428 : 3;
429 0 : case SQL_INTERVAL_DAY_TO_HOUR:
430 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
431 : return (int) sizeof(SQL_INTERVAL_STRUCT);
432 : /* strlen("INTERVAL -'yyy' DAY(p) TO HOUR") */
433 0 : return 11 + 16 +
434 0 : (rec->sql_desc_datetime_interval_precision > 10) +
435 0 : rec->sql_desc_datetime_interval_precision +
436 : 3;
437 0 : case SQL_INTERVAL_HOUR_TO_MINUTE:
438 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
439 : return (int) sizeof(SQL_INTERVAL_STRUCT);
440 : /* strlen("INTERVAL -'yyy' HOUR(p) TO MINUTE") */
441 0 : return 11 + 19 +
442 0 : (rec->sql_desc_datetime_interval_precision > 10) +
443 0 : rec->sql_desc_datetime_interval_precision +
444 : 3;
445 0 : case SQL_INTERVAL_DAY_TO_MINUTE:
446 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
447 : return (int) sizeof(SQL_INTERVAL_STRUCT);
448 : /* strlen("INTERVAL -'yyy' DAY(p) TO MINUTE") */
449 0 : return 11 + 18 +
450 0 : (rec->sql_desc_datetime_interval_precision > 10) +
451 0 : rec->sql_desc_datetime_interval_precision +
452 : 6;
453 0 : case SQL_GUID:
454 0 : if (lengthtype == SQL_DESC_OCTET_LENGTH)
455 0 : return 16; /* sizeof(SQLGUID) */
456 : /* strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee") */
457 : return 36;
458 : default:
459 : break;
460 : }
461 0 : return SQL_NO_TOTAL;
462 : }
|