1 // Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License, version 2.0, as
5 // published by the Free Software Foundation.
6 //
7 // This program is also distributed with certain software (including
8 // but not limited to OpenSSL) that is licensed under separate terms,
9 // as designated in a particular file or component or in included license
10 // documentation. The authors of MySQL hereby grant you an
11 // additional permission to link the program and your derivative works
12 // with the separately licensed software that they have included with
13 // MySQL.
14 //
15 // Without limiting anything contained in the foregoing, this file,
16 // which is part of MySQL Connector/ODBC, is also subject to the
17 // Universal FOSS Exception, version 1.0, a copy of which can be found at
18 // http://oss.oracle.com/licenses/universal-foss-exception.
19 //
20 // This program is distributed in the hope that it will be useful, but
21 // WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 // See the GNU General Public License, version 2.0, for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with this program; if not, write to the Free Software Foundation, Inc.,
27 // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
29 /**
30 @file desc.c
31 @brief Functions for handling descriptors.
32 */
33
34 /***************************************************************************
35 * The following ODBC APIs are implemented in this file: *
36 * SQLSetDescField (ISO 92) *
37 * SQLGetDescField (ISO 92) *
38 * SQLCopyDesc (ISO 92) *
39 ****************************************************************************/
40
41 #include "driver.h"
42
43 /* Utility macros for defining descriptor fields */
44 #define HDR_FLD(field, perm, type) \
45 static desc_field HDR_##field= \
46 {(perm), (type), DESC_HDR, offsetof(DESC, field)}
47 /* parens around field in offsetof() confuse GCC */
48
49 #define REC_FLD(field, perm, type) \
50 static desc_field REC_##field= \
51 {(perm), (type), DESC_REC, offsetof(DESCREC, field)}
52
53
54 /*
55 * Allocate a new descriptor.
56 * Should be used to allocate 'implicit' descriptors on the statement
57 * or 'explicit' user-requested descriptors.
58 */
desc_alloc(STMT * stmt,SQLSMALLINT alloc_type,desc_ref_type ref_type,desc_desc_type desc_type)59 DESC *desc_alloc(STMT *stmt, SQLSMALLINT alloc_type,
60 desc_ref_type ref_type, desc_desc_type desc_type)
61 {
62 DESC *desc= (DESC *)myodbc_malloc(sizeof(DESC), MYF(MY_ZEROFILL));
63 if (!desc)
64 return NULL;
65 /*
66 We let the dynamic array handle the memory for the whole DESCREC,
67 but in desc_get_rec we manually get a pointer to it. This avoids
68 having to call set_dynamic after modifying the DESCREC.
69 */
70 if (myodbc_init_dynamic_array(&desc->records, sizeof(DESCREC), 0, 0))
71 {
72 x_free((char *)desc);
73 return NULL;
74 }
75
76 if (myodbc_init_dynamic_array(&desc->bookmark, sizeof(DESCREC), 0, 0))
77 {
78 delete_dynamic(&desc->records);
79 x_free((char *)desc);
80 return NULL;
81 }
82
83 desc->desc_type= desc_type;
84 desc->alloc_type= alloc_type;
85 desc->ref_type= ref_type;
86 desc->stmt= stmt;
87 /* spec-defined defaults/initialization */
88 desc->array_size= 1;
89 desc->array_status_ptr= NULL;
90 desc->bind_offset_ptr= NULL;
91 desc->bind_type= SQL_BIND_BY_COLUMN;
92 desc->count= 0;
93 desc->bookmark_count= 0;
94 desc->rows_processed_ptr= NULL;
95 desc->exp.stmts= NULL;
96 return desc;
97 }
98
99
100 /*
101 Free a descriptor.
102 */
desc_free(DESC * desc)103 void desc_free(DESC *desc)
104 {
105 assert(desc);
106 if (IS_APD(desc))
107 desc_free_paramdata(desc);
108 delete_dynamic(&desc->records);
109 delete_dynamic(&desc->bookmark);
110 x_free(desc);
111 }
112
113
114 /*
115 Free any memory allocated for SQLPutData(). This is only useful
116 for APDs.
117 */
desc_free_paramdata(DESC * desc)118 void desc_free_paramdata(DESC *desc)
119 {
120 SQLLEN i;
121 for (i= 0; i < desc->count; ++i)
122 {
123 DESCREC *aprec= desc_get_rec(desc, i, FALSE);
124 assert(aprec);
125 if (aprec->par.alloced)
126 {
127 aprec->par.alloced= FALSE;
128 x_free(aprec->par.value);
129 }
130 }
131 }
132
133
134 /*
135 * Initialize APD
136 */
desc_rec_init_apd(DESCREC * rec)137 void desc_rec_init_apd(DESCREC *rec)
138 {
139 memset(rec, 0, sizeof(DESCREC));
140 /* ODBC defaults */
141 rec->concise_type= SQL_C_DEFAULT;
142 rec->data_ptr= NULL;
143 rec->indicator_ptr= NULL;
144 rec->octet_length_ptr= NULL;
145 rec->type= SQL_C_DEFAULT;
146
147 /* internal */
148 rec->par.alloced= FALSE;
149 rec->par.value= NULL;
150 }
151
152
153 /*
154 * Initialize IPD
155 */
desc_rec_init_ipd(DESCREC * rec)156 void desc_rec_init_ipd(DESCREC *rec)
157 {
158 memset(rec, 0, sizeof(DESCREC));
159 /* ODBC defaults */
160 rec->fixed_prec_scale= SQL_TRUE;
161 rec->local_type_name= (SQLCHAR *)"";
162 rec->nullable= SQL_NULLABLE;
163 rec->parameter_type= SQL_PARAM_INPUT;
164 rec->type_name= (SQLCHAR *)"VARCHAR";
165 rec->is_unsigned= SQL_FALSE;
166
167 /* driver defaults */
168 rec->name= (SQLCHAR *)"";
169 }
170
171
172 /*
173 * Initialize ARD
174 */
desc_rec_init_ard(DESCREC * rec)175 void desc_rec_init_ard(DESCREC *rec)
176 {
177 memset(rec, 0, sizeof(DESCREC));
178 /* ODBC defaults */
179 rec->concise_type= SQL_C_DEFAULT;
180 rec->data_ptr= NULL;
181 rec->indicator_ptr= NULL;
182 rec->octet_length_ptr= NULL;
183 rec->type= SQL_C_DEFAULT;
184 }
185
186
187 /*
188 * Initialize IRD
189 */
desc_rec_init_ird(DESCREC * rec)190 void desc_rec_init_ird(DESCREC *rec)
191 {
192 memset(rec, 0, sizeof(DESCREC));
193 /* ODBC defaults */
194 /* driver defaults */
195 rec->auto_unique_value= SQL_FALSE;
196 rec->case_sensitive= SQL_TRUE;
197 rec->concise_type= SQL_VARCHAR;
198 rec->display_size= 100;/*?*/
199 rec->fixed_prec_scale= SQL_TRUE;
200 rec->length= 100;/*?*/
201 rec->nullable= SQL_NULLABLE_UNKNOWN;
202 rec->type= SQL_VARCHAR;
203 rec->type_name= (SQLCHAR *)"VARCHAR";
204 rec->unnamed= SQL_UNNAMED;
205 rec->is_unsigned= SQL_FALSE;
206 }
207
208
209 /*
210 * Get a record from the descriptor.
211 *
212 * @param desc Descriptor
213 * @param recnum 0-based record number
214 * @param expand Whether to expand the descriptor to include the given
215 * recnum.
216 * @return The requested record of NULL if it doesn't exist
217 * (and isn't created).
218 */
desc_get_rec(DESC * desc,int recnum,my_bool expand)219 DESCREC *desc_get_rec(DESC *desc, int recnum, my_bool expand)
220 {
221 DESCREC *rec= NULL;
222 int i;
223
224 if (recnum == -1 && desc->stmt->stmt_options.bookmarks == SQL_UB_VARIABLE)
225 {
226 if (expand)
227 {
228 if (!desc->bookmark_count)
229 {
230 rec= (DESCREC *)alloc_dynamic(&desc->bookmark);
231 if (!rec)
232 return NULL;
233
234 memset(rec, 0, sizeof(DESCREC));
235 ++desc->bookmark_count;
236
237 /* record initialization */
238 if (IS_APD(desc))
239 desc_rec_init_apd(rec);
240 else if (IS_IPD(desc))
241 desc_rec_init_ipd(rec);
242 else if (IS_ARD(desc))
243 desc_rec_init_ard(rec);
244 else if (IS_IRD(desc))
245 desc_rec_init_ird(rec);
246 }
247 }
248
249 rec= (DESCREC *)desc->bookmark.buffer;
250 }
251 else if (recnum < 0)
252 {
253 set_stmt_error(desc->stmt, "07009", "Invalid descriptor index", MYERR_07009);
254 return NULL;
255 }
256 else
257 {
258 assert(recnum >= 0);
259 /* expand if needed */
260 if (expand)
261 {
262 for (i= desc->count; expand && i <= recnum; ++i)
263 {
264 /* we might have used records lying around from before if
265 * SQLFreeStmt() was called with SQL_UNBIND or SQL_FREE_PARAMS
266 */
267 if ((uint)i < desc->records.elements)
268 {
269 rec= ((DESCREC *)desc->records.buffer) + recnum;
270 }
271 else
272 {
273 rec= (DESCREC *)alloc_dynamic(&desc->records);
274 if (!rec)
275 return NULL;
276 }
277 memset(rec, 0, sizeof(DESCREC));
278 ++desc->count;
279
280 /* record initialization */
281 if (IS_APD(desc))
282 desc_rec_init_apd(rec);
283 else if (IS_IPD(desc))
284 desc_rec_init_ipd(rec);
285 else if (IS_ARD(desc))
286 desc_rec_init_ard(rec);
287 else if (IS_IRD(desc))
288 desc_rec_init_ird(rec);
289 }
290 }
291 if (recnum < desc->count)
292 rec= ((DESCREC *)desc->records.buffer) + recnum;
293 }
294
295 if (expand)
296 assert(rec);
297 return rec;
298 }
299
300
301 /*
302 * Disassociate a statement from an explicitly allocated
303 * descriptor.
304 *
305 * @param desc The descriptor
306 * @param stmt The statement
307 */
desc_remove_stmt(DESC * desc,STMT * stmt)308 void desc_remove_stmt(DESC *desc, STMT *stmt)
309 {
310 LIST *lstmt;
311
312 if (desc->alloc_type != SQL_DESC_ALLOC_USER)
313 return;
314
315 for (lstmt= desc->exp.stmts; lstmt; lstmt= lstmt->next)
316 {
317 if (lstmt->data == stmt)
318 {
319 desc->exp.stmts= list_delete(desc->exp.stmts, lstmt);
320 /* Free only if it was the last element */
321 //if(!lstmt->next && !lstmt->prev)
322 {
323 x_free(lstmt);
324 }
325 return;
326 }
327 }
328
329 assert(!"Statement was not associated with descriptor");
330 }
331
332
333 /*
334 * Check with the given descriptor contains any data-at-exec
335 * records. Return the record number or -1 if none are found.
336 */
desc_find_dae_rec(DESC * desc)337 int desc_find_dae_rec(DESC *desc)
338 {
339 int i;
340 DESCREC *rec;
341 SQLLEN *octet_length_ptr;
342 for (i= 0; i < desc->count; ++i)
343 {
344 rec= desc_get_rec(desc, i, FALSE);
345 assert(rec);
346 octet_length_ptr= (SQLLEN*)ptr_offset_adjust(rec->octet_length_ptr,
347 desc->bind_offset_ptr,
348 desc->bind_type,
349 sizeof(SQLLEN), /*row*/0);
350 if (IS_DATA_AT_EXEC(octet_length_ptr))
351 return i;
352 }
353 return -1;
354 }
355
356
357 /*
358 * Check with the given descriptor contains any output streams
359 * @param recnum[in,out] - pointer to 0-based record number to begin search from
360 and to store found record number
361 * @param res_col_num[in,out] - pointer to 0-based column number in output parameters resultset
362 * Returns the found record or NULL.
363 */
desc_find_outstream_rec(STMT * stmt,uint * recnum,uint * res_col_num)364 DESCREC * desc_find_outstream_rec(STMT *stmt, uint *recnum, uint *res_col_num)
365 {
366 int i, start= recnum != NULL ? *recnum + 1 : 0;
367 DESCREC *rec;
368 uint column= *res_col_num;
369
370 /* No streams in iODBC */
371 #ifndef USE_IODBC
372 for (i= start; i < stmt->ipd->count; ++i)
373 {
374 rec= desc_get_rec(stmt->ipd, i, FALSE);
375 assert(rec);
376
377 if (rec->parameter_type == SQL_PARAM_INPUT_OUTPUT_STREAM
378 || rec->parameter_type == SQL_PARAM_OUTPUT_STREAM)
379 {
380 if (recnum != NULL)
381 {
382 *recnum= i;
383 }
384 *res_col_num= ++column;
385 /* Valuable information is in apd */
386 return desc_get_rec(stmt->apd, i, FALSE);
387 }
388 else if (rec->parameter_type == SQL_PARAM_INPUT_OUTPUT
389 || rec->parameter_type == SQL_PARAM_OUTPUT)
390 {
391 ++column;
392 }
393 }
394 #endif
395
396 return NULL;
397 }
398
399
400 /*
401 * Apply the actual value to the descriptor field.
402 *
403 * @param dest Pointer to descriptor field to be set.
404 * @param dest_type Type of descriptor field (same type constants as buflen).
405 * @param src Value to be set.
406 * @param buflen Length of value (as specified by SQLSetDescField).
407 */
408 static void
apply_desc_val(void * dest,SQLSMALLINT dest_type,void * src,SQLINTEGER buflen)409 apply_desc_val(void *dest, SQLSMALLINT dest_type, void *src, SQLINTEGER buflen)
410 {
411 switch (buflen)
412 {
413 case SQL_IS_SMALLINT:
414 case SQL_IS_INTEGER:
415 case SQL_IS_LEN:
416 if (dest_type == SQL_IS_SMALLINT)
417 *(SQLSMALLINT *)dest= (SQLSMALLINT)((SQLLEN)src);
418 else if (dest_type == SQL_IS_USMALLINT)
419 *(SQLUSMALLINT *)dest = (SQLUSMALLINT)((SQLLEN)src);
420 else if (dest_type == SQL_IS_INTEGER)
421 *(SQLINTEGER *)dest = (SQLINTEGER)((SQLLEN)src);
422 else if (dest_type == SQL_IS_UINTEGER)
423 *(SQLUINTEGER *)dest = (SQLUINTEGER)((SQLLEN)src);
424 else if (dest_type == SQL_IS_LEN)
425 *(SQLLEN *)dest = (SQLLEN)src;
426 else if (dest_type == SQL_IS_ULEN)
427 *(SQLULEN *)dest = (SQLULEN)src;
428 break;
429
430 case SQL_IS_USMALLINT:
431 case SQL_IS_UINTEGER:
432 case SQL_IS_ULEN:
433 if (dest_type == SQL_IS_SMALLINT)
434 *(SQLSMALLINT *)dest = (SQLSMALLINT)((SQLULEN)src);
435 else if (dest_type == SQL_IS_USMALLINT)
436 *(SQLUSMALLINT *)dest = (SQLUSMALLINT)((SQLULEN)src);
437 else if (dest_type == SQL_IS_INTEGER)
438 *(SQLINTEGER *)dest = (SQLINTEGER)((SQLULEN)src);
439 else if (dest_type == SQL_IS_UINTEGER)
440 *(SQLUINTEGER *)dest = (SQLUINTEGER)((SQLULEN)src);
441 else if (dest_type == SQL_IS_LEN)
442 *(SQLLEN *)dest= (SQLULEN)src;
443 else if (dest_type == SQL_IS_ULEN)
444 *(SQLULEN *)dest= (SQLULEN)src;
445 break;
446
447 case SQL_IS_POINTER:
448 *(SQLPOINTER *)dest= src;
449 break;
450
451 default:
452 /* TODO it's an actual data length */
453 /* free/malloc to the field and copy it */
454 /* TODO .. check for 22001 - String data, right truncated
455 * The FieldIdentifier argument was SQL_DESC_NAME,
456 * and the BufferLength argument was a value larger
457 * than SQL_MAX_IDENTIFIER_LEN.
458 */
459 break;
460 }
461 }
462
463
464 /*
465 * Get a descriptor field based on the constant.
466 */
467 static desc_field *
getfield(SQLSMALLINT fldid)468 getfield(SQLSMALLINT fldid)
469 {
470 /* all field descriptions are immutable */
471 /* See: SQLSetDescField() documentation
472 * http://msdn2.microsoft.com/en-us/library/ms713560.aspx */
473 HDR_FLD(alloc_type , P_RI|P_RA , SQL_IS_SMALLINT);
474 HDR_FLD(array_size , P_RA|P_WA , SQL_IS_ULEN );
475 HDR_FLD(array_status_ptr , P_RI|P_WI|P_RA|P_WA, SQL_IS_POINTER );
476 HDR_FLD(bind_offset_ptr , P_RA|P_WA , SQL_IS_POINTER );
477 HDR_FLD(bind_type , P_RA|P_WA , SQL_IS_INTEGER );
478 HDR_FLD(count , P_RI|P_WI|P_RA|P_WA, SQL_IS_LEN );
479 HDR_FLD(rows_processed_ptr, P_RI|P_WI , SQL_IS_POINTER );
480
481 REC_FLD(auto_unique_value, PR_RIR , SQL_IS_INTEGER);
482 REC_FLD(base_column_name , PR_RIR , SQL_IS_POINTER);
483 REC_FLD(base_table_name , PR_RIR , SQL_IS_POINTER);
484 REC_FLD(case_sensitive , PR_RIR|PR_RIP , SQL_IS_INTEGER);
485 REC_FLD(catalog_name , PR_RIR , SQL_IS_POINTER);
486 REC_FLD(concise_type , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_SMALLINT);
487 REC_FLD(data_ptr , PR_WAR|PR_WAP , SQL_IS_POINTER);
488 REC_FLD(display_size , PR_RIR , SQL_IS_LEN);
489 REC_FLD(fixed_prec_scale , PR_RIR|PR_RIP , SQL_IS_SMALLINT);
490 REC_FLD(indicator_ptr , PR_WAR|PR_WAP , SQL_IS_POINTER);
491 REC_FLD(label , PR_RIR , SQL_IS_POINTER);
492 REC_FLD(length , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_ULEN);
493 REC_FLD(literal_prefix , PR_RIR , SQL_IS_POINTER);
494 REC_FLD(literal_suffix , PR_RIR , SQL_IS_POINTER);
495 REC_FLD(local_type_name , PR_RIR|PR_RIP , SQL_IS_POINTER);
496 REC_FLD(name , PR_RIR|PR_WIP , SQL_IS_POINTER);
497 REC_FLD(nullable , PR_RIR|PR_RIP , SQL_IS_SMALLINT);
498 REC_FLD(num_prec_radix , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_INTEGER);
499 REC_FLD(octet_length , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_LEN);
500 REC_FLD(octet_length_ptr , PR_WAR|PR_WAP , SQL_IS_POINTER);
501 REC_FLD(parameter_type , PR_WIP , SQL_IS_SMALLINT);
502 REC_FLD(precision , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_SMALLINT);
503 REC_FLD(rowver , PR_RIR|PR_RIP , SQL_IS_SMALLINT);
504 REC_FLD(scale , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_SMALLINT);
505 REC_FLD(schema_name , PR_RIR , SQL_IS_POINTER);
506 REC_FLD(searchable , PR_RIR , SQL_IS_SMALLINT);
507 REC_FLD(table_name , PR_RIR , SQL_IS_POINTER);
508 REC_FLD(type , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_SMALLINT);
509 REC_FLD(type_name , PR_RIR|PR_RIP , SQL_IS_POINTER);
510 REC_FLD(unnamed , PR_RIR|PR_WIP , SQL_IS_SMALLINT);
511 REC_FLD(is_unsigned , PR_RIR|PR_RIP , SQL_IS_SMALLINT);
512 REC_FLD(updatable , PR_RIR , SQL_IS_SMALLINT);
513 REC_FLD(datetime_interval_code , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_SMALLINT);
514 REC_FLD(datetime_interval_precision , PR_WAR|PR_WAP|PR_RIR|PR_WIP, SQL_IS_INTEGER);
515
516 /* match 'field' names above */
517 switch(fldid)
518 {
519 case SQL_DESC_ALLOC_TYPE:
520 return &HDR_alloc_type;
521 case SQL_DESC_ARRAY_SIZE:
522 return &HDR_array_size;
523 case SQL_DESC_ARRAY_STATUS_PTR:
524 return &HDR_array_status_ptr;
525 case SQL_DESC_BIND_OFFSET_PTR:
526 return &HDR_bind_offset_ptr;
527 case SQL_DESC_BIND_TYPE:
528 return &HDR_bind_type;
529 case SQL_DESC_COUNT:
530 return &HDR_count;
531 case SQL_DESC_ROWS_PROCESSED_PTR:
532 return &HDR_rows_processed_ptr;
533
534 case SQL_DESC_AUTO_UNIQUE_VALUE:
535 return &REC_auto_unique_value;
536 case SQL_DESC_BASE_COLUMN_NAME:
537 return &REC_base_column_name;
538 case SQL_DESC_BASE_TABLE_NAME:
539 return &REC_base_table_name;
540 case SQL_DESC_CASE_SENSITIVE:
541 return &REC_case_sensitive;
542 case SQL_DESC_CATALOG_NAME:
543 return &REC_catalog_name;
544 case SQL_DESC_CONCISE_TYPE:
545 return &REC_concise_type;
546 case SQL_DESC_DATA_PTR:
547 return &REC_data_ptr;
548 case SQL_DESC_DISPLAY_SIZE:
549 return &REC_display_size;
550 case SQL_DESC_FIXED_PREC_SCALE:
551 return &REC_fixed_prec_scale;
552 case SQL_DESC_INDICATOR_PTR:
553 return &REC_indicator_ptr;
554 case SQL_DESC_LABEL:
555 return &REC_label;
556 case SQL_DESC_LENGTH:
557 return &REC_length;
558 case SQL_DESC_LITERAL_PREFIX:
559 return &REC_literal_prefix;
560 case SQL_DESC_LITERAL_SUFFIX:
561 return &REC_literal_suffix;
562 case SQL_DESC_LOCAL_TYPE_NAME:
563 return &REC_local_type_name;
564 case SQL_DESC_NAME:
565 return &REC_name;
566 case SQL_DESC_NULLABLE:
567 return &REC_nullable;
568 case SQL_DESC_NUM_PREC_RADIX:
569 return &REC_num_prec_radix;
570 case SQL_DESC_OCTET_LENGTH:
571 return &REC_octet_length;
572 case SQL_DESC_OCTET_LENGTH_PTR:
573 return &REC_octet_length_ptr;
574 case SQL_DESC_PARAMETER_TYPE:
575 return &REC_parameter_type;
576 case SQL_DESC_PRECISION:
577 return &REC_precision;
578 case SQL_DESC_ROWVER:
579 return &REC_rowver;
580 case SQL_DESC_SCALE:
581 return &REC_scale;
582 case SQL_DESC_SCHEMA_NAME:
583 return &REC_schema_name;
584 case SQL_DESC_SEARCHABLE:
585 return &REC_searchable;
586 case SQL_DESC_TABLE_NAME:
587 return &REC_table_name;
588 case SQL_DESC_TYPE:
589 return &REC_type;
590 case SQL_DESC_TYPE_NAME:
591 return &REC_type_name;
592 case SQL_DESC_UNNAMED:
593 return &REC_unnamed;
594 case SQL_DESC_UNSIGNED:
595 return &REC_is_unsigned;
596 case SQL_DESC_UPDATABLE:
597 return &REC_updatable;
598 case SQL_DESC_DATETIME_INTERVAL_CODE:
599 return &REC_datetime_interval_code;
600 case SQL_DESC_DATETIME_INTERVAL_PRECISION:
601 return &REC_datetime_interval_precision;
602 }
603 return NULL;
604 }
605
606
607 /*
608 @type : ODBC 3.0 API
609 @purpose : Get a field of a descriptor.
610 */
611 SQLRETURN
MySQLGetDescField(SQLHDESC hdesc,SQLSMALLINT recnum,SQLSMALLINT fldid,SQLPOINTER valptr,SQLINTEGER buflen,SQLINTEGER * outlen)612 MySQLGetDescField(SQLHDESC hdesc, SQLSMALLINT recnum, SQLSMALLINT fldid,
613 SQLPOINTER valptr, SQLINTEGER buflen, SQLINTEGER *outlen)
614 {
615 desc_field *fld= getfield(fldid);
616 DESC *desc= (DESC *)hdesc;
617 void *src_struct;
618 void *src;
619
620 if (desc == NULL)
621 {
622 return SQL_INVALID_HANDLE;
623 }
624
625 CLEAR_DESC_ERROR(desc);
626
627 if (IS_IRD(desc) && desc->stmt->state < ST_PREPARED)
628 /* TODO if it's prepared is the IRD still ok to access?
629 * or must we pre-execute it */
630 return set_desc_error(desc, "HY007",
631 "Associated statement is not prepared",
632 MYERR_S1007);
633
634 if ((fld == NULL) ||
635 /* header permissions check */
636 (fld->loc == DESC_HDR &&
637 (desc->ref_type == DESC_APP && (~fld->perms & P_RA)) ||
638 (desc->ref_type == DESC_IMP && (~fld->perms & P_RI))))
639 {
640 return set_desc_error(desc, "HY091",
641 "Invalid descriptor field identifier",
642 MYERR_S1091);
643 }
644 else if (fld->loc == DESC_REC)
645 {
646 int perms= 0; /* needed perms to access */
647
648 if (desc->ref_type == DESC_APP)
649 perms= P_RA;
650 else if (desc->ref_type == DESC_IMP)
651 perms= P_RI;
652
653 if (desc->desc_type == DESC_PARAM)
654 perms= P_PAR(perms);
655 else if (desc->desc_type == DESC_ROW)
656 perms= P_ROW(perms);
657
658 if ((~fld->perms & perms) == perms)
659 return set_desc_error(desc, "HY091",
660 "Invalid descriptor field identifier",
661 MYERR_S1091);
662 }
663
664 /* get the src struct */
665 if (fld->loc == DESC_HDR)
666 src_struct= desc;
667 else
668 {
669 if (recnum < 1 || recnum > desc->count)
670 return set_desc_error(desc, "07009",
671 "Invalid descriptor index",
672 MYERR_07009);
673 src_struct= desc_get_rec(desc, recnum - 1, FALSE);
674 assert(src_struct);
675 }
676
677 src= ((char *)src_struct) + fld->offset;
678
679 /* TODO checks when strings? */
680 if ((fld->data_type == SQL_IS_POINTER && buflen != SQL_IS_POINTER) ||
681 (fld->data_type != SQL_IS_POINTER && buflen == SQL_IS_POINTER))
682 return set_desc_error(desc, "HY015",
683 "Invalid parameter type",
684 MYERR_S1015);
685
686 switch (buflen)
687 {
688 case SQL_IS_SMALLINT:
689 if (fld->data_type == SQL_IS_SMALLINT)
690 *(SQLSMALLINT *)valptr= *(SQLSMALLINT *)src;
691 else if (fld->data_type == SQL_IS_USMALLINT)
692 *(SQLSMALLINT *)valptr= *(SQLUSMALLINT *)src;
693 else if (fld->data_type == SQL_IS_INTEGER)
694 *(SQLSMALLINT *)valptr= *(SQLINTEGER *)src;
695 else if (fld->data_type == SQL_IS_UINTEGER)
696 *(SQLSMALLINT *)valptr= *(SQLUINTEGER *)src;
697 else if (fld->data_type == SQL_IS_LEN)
698 *(SQLSMALLINT *)valptr= *(SQLLEN *)src;
699 else if (fld->data_type == SQL_IS_ULEN)
700 *(SQLSMALLINT *)valptr= *(SQLULEN *)src;
701 break;
702
703 case SQL_IS_USMALLINT:
704 if (fld->data_type == SQL_IS_SMALLINT)
705 *(SQLUSMALLINT *)valptr= *(SQLSMALLINT *)src;
706 else if (fld->data_type == SQL_IS_USMALLINT)
707 *(SQLUSMALLINT *)valptr= *(SQLUSMALLINT *)src;
708 else if (fld->data_type == SQL_IS_INTEGER)
709 *(SQLUSMALLINT *)valptr= *(SQLINTEGER *)src;
710 else if (fld->data_type == SQL_IS_UINTEGER)
711 *(SQLUSMALLINT *)valptr= *(SQLUINTEGER *)src;
712 else if (fld->data_type == SQL_IS_LEN)
713 *(SQLUSMALLINT *)valptr= *(SQLLEN *)src;
714 else if (fld->data_type == SQL_IS_ULEN)
715 *(SQLUSMALLINT *)valptr= *(SQLULEN *)src;
716 break;
717
718 case SQL_IS_INTEGER:
719 if (fld->data_type == SQL_IS_SMALLINT)
720 *(SQLINTEGER *)valptr= *(SQLSMALLINT *)src;
721 else if (fld->data_type == SQL_IS_USMALLINT)
722 *(SQLINTEGER *)valptr= *(SQLUSMALLINT *)src;
723 else if (fld->data_type == SQL_IS_INTEGER)
724 *(SQLINTEGER *)valptr= *(SQLINTEGER *)src;
725 else if (fld->data_type == SQL_IS_UINTEGER)
726 *(SQLINTEGER *)valptr= *(SQLUINTEGER *)src;
727 else if (fld->data_type == SQL_IS_LEN)
728 *(SQLINTEGER *)valptr= *(SQLLEN *)src;
729 else if (fld->data_type == SQL_IS_ULEN)
730 *(SQLINTEGER *)valptr= *(SQLULEN *)src;
731 break;
732
733 case SQL_IS_UINTEGER:
734 if (fld->data_type == SQL_IS_SMALLINT)
735 *(SQLUINTEGER *)valptr= *(SQLSMALLINT *)src;
736 else if (fld->data_type == SQL_IS_USMALLINT)
737 *(SQLUINTEGER *)valptr= *(SQLUSMALLINT *)src;
738 else if (fld->data_type == SQL_IS_INTEGER)
739 *(SQLUINTEGER *)valptr= *(SQLINTEGER *)src;
740 else if (fld->data_type == SQL_IS_UINTEGER)
741 *(SQLUINTEGER *)valptr= *(SQLUINTEGER *)src;
742 else if (fld->data_type == SQL_IS_LEN)
743 *(SQLUINTEGER *)valptr= *(SQLLEN *)src;
744 else if (fld->data_type == SQL_IS_ULEN)
745 *(SQLUINTEGER *)valptr= *(SQLULEN *)src;
746 break;
747
748 case SQL_IS_LEN:
749 if (fld->data_type == SQL_IS_SMALLINT)
750 *(SQLLEN *)valptr= *(SQLSMALLINT *)src;
751 else if (fld->data_type == SQL_IS_USMALLINT)
752 *(SQLLEN *)valptr= *(SQLUSMALLINT *)src;
753 else if (fld->data_type == SQL_IS_INTEGER)
754 *(SQLLEN *)valptr= *(SQLINTEGER *)src;
755 else if (fld->data_type == SQL_IS_UINTEGER)
756 *(SQLLEN *)valptr= *(SQLUINTEGER *)src;
757 else if (fld->data_type == SQL_IS_LEN)
758 *(SQLLEN *)valptr= *(SQLLEN *)src;
759 else if (fld->data_type == SQL_IS_ULEN)
760 *(SQLLEN *)valptr= *(SQLULEN *)src;
761 break;
762
763 case SQL_IS_ULEN:
764 if (fld->data_type == SQL_IS_SMALLINT)
765 *(SQLULEN *)valptr= *(SQLSMALLINT *)src;
766 else if (fld->data_type == SQL_IS_USMALLINT)
767 *(SQLULEN *)valptr= *(SQLUSMALLINT *)src;
768 else if (fld->data_type == SQL_IS_INTEGER)
769 *(SQLULEN *)valptr= *(SQLINTEGER *)src;
770 else if (fld->data_type == SQL_IS_UINTEGER)
771 *(SQLULEN *)valptr= *(SQLUINTEGER *)src;
772 else if (fld->data_type == SQL_IS_LEN)
773 *(SQLULEN *)valptr= *(SQLLEN *)src;
774 else if (fld->data_type == SQL_IS_ULEN)
775 *(SQLULEN *)valptr= *(SQLULEN *)src;
776 break;
777
778 case SQL_IS_POINTER:
779 *(SQLPOINTER *)valptr= *(SQLPOINTER *)src;
780 break;
781
782 default:
783 /* TODO it's an actual data length */
784 /* free/malloc to the field and copy it, etc, etc */
785 break;
786 }
787
788 return SQL_SUCCESS;
789 }
790
791
792 /*
793 @type : ODBC 3.0 API
794 @purpose : Set a field of a descriptor.
795 */
796 SQLRETURN
MySQLSetDescField(SQLHDESC hdesc,SQLSMALLINT recnum,SQLSMALLINT fldid,SQLPOINTER val,SQLINTEGER buflen)797 MySQLSetDescField(SQLHDESC hdesc, SQLSMALLINT recnum, SQLSMALLINT fldid,
798 SQLPOINTER val, SQLINTEGER buflen)
799 {
800 desc_field *fld= getfield(fldid);
801 DESC *desc= (DESC *)hdesc;
802 void *dest_struct;
803 void *dest;
804
805 if (desc == NULL)
806 {
807 return SQL_INVALID_HANDLE;
808 }
809
810 CLEAR_DESC_ERROR(desc);
811
812 /* check for invalid IRD modification */
813 if (IS_IRD(desc))
814 {
815 switch (fldid)
816 {
817 case SQL_DESC_ARRAY_STATUS_PTR:
818 case SQL_DESC_ROWS_PROCESSED_PTR:
819 break;
820 default:
821 return set_desc_error(desc, "HY016",
822 "Cannot modify an implementation row descriptor",
823 MYERR_S1016);
824 }
825 }
826
827 if ((fld == NULL) ||
828 /* header permissions check */
829 (fld->loc == DESC_HDR &&
830 ((desc->ref_type == DESC_APP && (~fld->perms & P_WA)) ||
831 (desc->ref_type == DESC_IMP && (~fld->perms & P_WI)))))
832 {
833 return set_desc_error(desc, "HY091",
834 "Invalid descriptor field identifier",
835 MYERR_S1091);
836 }
837 else if (fld->loc == DESC_REC)
838 {
839 int perms= 0; /* needed perms to access */
840
841 if (desc->ref_type == DESC_APP)
842 perms= P_WA;
843 else if (desc->ref_type == DESC_IMP)
844 perms= P_WI;
845
846 if (desc->desc_type == DESC_PARAM)
847 perms= P_PAR(perms);
848 else if (desc->desc_type == DESC_ROW)
849 perms= P_ROW(perms);
850
851 if ((~fld->perms & perms) == perms)
852 return set_desc_error(desc, "HY091",
853 "Invalid descriptor field identifier",
854 MYERR_S1091);
855 }
856
857 /* get the dest struct */
858 if (fld->loc == DESC_HDR)
859 dest_struct= desc;
860 else
861 {
862 if (recnum < 1 && desc->stmt->stmt_options.bookmarks == SQL_UB_OFF)
863 return set_desc_error(desc, "07009",
864 "Invalid descriptor index",
865 MYERR_07009);
866 else
867 dest_struct= desc_get_rec(desc, recnum - 1, TRUE);
868 }
869
870 dest= ((char *)dest_struct) + fld->offset;
871
872 /* some applications and even MSDN examples don't give a correct constant */
873 if (buflen == 0)
874 buflen= fld->data_type;
875
876 /* TODO checks when strings? */
877 if ((fld->data_type == SQL_IS_POINTER && buflen != SQL_IS_POINTER) ||
878 (fld->data_type != SQL_IS_POINTER && buflen == SQL_IS_POINTER))
879 return set_desc_error(desc, "HY015",
880 "Invalid parameter type",
881 MYERR_S1015);
882
883 /* per-field checks/functionality */
884 switch (fldid)
885 {
886 case SQL_DESC_COUNT:
887 /* we just force the descriptor record count to expand */
888 (void)desc_get_rec(desc, (size_t)val - 1, TRUE);
889 break;
890 case SQL_DESC_NAME:
891 /* We don't support named parameters, values stay as initialized */
892 return set_desc_error(desc, "01S01",
893 "Option value changed",
894 MYERR_01S02);
895 case SQL_DESC_UNNAMED:
896 if ((size_t)val == SQL_NAMED)
897 return set_desc_error(desc, "HY092",
898 "Invalid attribute/option identifier",
899 MYERR_S1092);
900 }
901
902 /* We have to unbind the value if not setting a buffer */
903 switch (fldid)
904 {
905 case SQL_DESC_DATA_PTR:
906 case SQL_DESC_OCTET_LENGTH_PTR:
907 case SQL_DESC_INDICATOR_PTR:
908 break;
909 default:
910 if (fld->loc == DESC_REC)
911 {
912 DESCREC *rec= (DESCREC *) dest_struct;
913 rec->data_ptr= NULL;
914 }
915 }
916
917 apply_desc_val(dest, fld->data_type, val, buflen);
918
919 /* post-set responsibilities */
920 /*http://msdn.microsoft.com/en-us/library/ms710963%28v=vs.85%29.aspx
921 "ParameterType Argument" sectiosn - basically IPD has to be heres as well with same rules
922 C and SQL types match. Thus we can use same function for calculation of type and dti code.
923 */
924 if ((IS_ARD(desc) || IS_APD(desc) || IS_IPD(desc)) && fld->loc == DESC_REC)
925 {
926 DESCREC *rec= (DESCREC *) dest_struct;
927 switch (fldid)
928 {
929 case SQL_DESC_TYPE:
930 rec->concise_type= rec->type;
931 rec->datetime_interval_code= 0;
932 break;
933 case SQL_DESC_CONCISE_TYPE:
934 rec->type= get_type_from_concise_type(rec->concise_type);
935 rec->datetime_interval_code=
936 get_dticode_from_concise_type(rec->concise_type);
937 break;
938 case SQL_DESC_DATETIME_INTERVAL_CODE: /* TODO validation for this value? */
939 /* SQL_DESC_TYPE has to have already been set */
940 if (rec->type == SQL_DATETIME)
941 rec->concise_type=
942 get_concise_type_from_datetime_code(rec->datetime_interval_code);
943 else
944 rec->concise_type=
945 get_concise_type_from_interval_code(rec->datetime_interval_code);
946 break;
947 }
948
949 switch (fldid)
950 {
951 case SQL_DESC_TYPE:
952 case SQL_DESC_CONCISE_TYPE:
953 /* setup type specific defaults (TODO others besides SQL_C_NUMERIC)? */
954 if (IS_ARD(desc) && rec->type == SQL_C_NUMERIC)
955 {
956 rec->precision= 38;
957 rec->scale= 0;
958 }
959 }
960 }
961
962 /*
963 Set "real_param_done" for parameters if all fields needed to bind
964 a parameter are set.
965 */
966 if (IS_APD(desc) && val != NULL && fld->loc == DESC_REC)
967 {
968 DESCREC *rec= (DESCREC *) dest_struct;
969 switch (fldid)
970 {
971 case SQL_DESC_DATA_PTR:
972 case SQL_DESC_OCTET_LENGTH_PTR:
973 case SQL_DESC_INDICATOR_PTR:
974 rec->par.real_param_done= TRUE;
975 break;
976 }
977 }
978
979 return SQL_SUCCESS;
980 }
981
982
983 /*
984 @type : ODBC 3.0 API
985 @purpose : Copy descriptor information from one descriptor to another.
986 Errors are placed in the TargetDescHandle.
987 */
MySQLCopyDesc(SQLHDESC SourceDescHandle,SQLHDESC TargetDescHandle)988 SQLRETURN MySQLCopyDesc(SQLHDESC SourceDescHandle, SQLHDESC TargetDescHandle)
989 {
990 DESC *src= (DESC *)SourceDescHandle;
991 DESC *dest= (DESC *)TargetDescHandle;
992
993 CLEAR_DESC_ERROR(dest);
994
995 if (IS_IRD(dest))
996 return set_desc_error(dest, "HY016",
997 "Cannot modify an implementation row descriptor",
998 MYERR_S1016);
999
1000 if (IS_IRD(src) && src->stmt->state < ST_PREPARED)
1001 return set_desc_error(dest, "HY007",
1002 "Associated statement is not prepared",
1003 MYERR_S1007);
1004
1005 /* copy the records */
1006 delete_dynamic(&dest->records);
1007 if (myodbc_init_dynamic_array(&dest->records, sizeof(DESCREC),
1008 src->records.max_element,
1009 src->records.alloc_increment))
1010 {
1011 return set_desc_error(dest, "HY001",
1012 "Memory allocation error",
1013 MYERR_S1001);
1014 }
1015 memcpy(dest->records.buffer, src->records.buffer,
1016 src->records.max_element * src->records.size_of_element);
1017
1018 /* copy all fields */
1019 dest->array_size= src->array_size;
1020 dest->array_status_ptr= src->array_status_ptr;
1021 dest->bind_offset_ptr= src->bind_offset_ptr;
1022 dest->bind_type= src->bind_type;
1023 dest->count= src->count;
1024 dest->rows_processed_ptr= src->rows_processed_ptr;
1025 memcpy(&dest->error, &src->error, sizeof(MYERROR));
1026
1027 /* TODO consistency check on target, if needed (apd) */
1028
1029 return SQL_SUCCESS;
1030 }
1031
1032
1033 /*
1034 * Call SQLGetDescField in the "context" of a statement. This will copy
1035 * any error from the descriptor to the statement.
1036 */
1037 SQLRETURN
stmt_SQLGetDescField(STMT * stmt,DESC * desc,SQLSMALLINT recnum,SQLSMALLINT fldid,SQLPOINTER valptr,SQLINTEGER buflen,SQLINTEGER * outlen)1038 stmt_SQLGetDescField(STMT *stmt, DESC *desc, SQLSMALLINT recnum,
1039 SQLSMALLINT fldid, SQLPOINTER valptr,
1040 SQLINTEGER buflen, SQLINTEGER *outlen)
1041 {
1042 SQLRETURN rc;
1043 if ((rc= MySQLGetDescField((SQLHANDLE)desc, recnum, fldid,
1044 valptr, buflen, outlen)) != SQL_SUCCESS)
1045 memcpy(&stmt->error, &desc->error, sizeof(MYERROR));
1046 return rc;
1047 }
1048
1049
1050 /*
1051 * Call SQLSetDescField in the "context" of a statement. This will copy
1052 * any error from the descriptor to the statement.
1053 */
1054 SQLRETURN
stmt_SQLSetDescField(STMT * stmt,DESC * desc,SQLSMALLINT recnum,SQLSMALLINT fldid,SQLPOINTER val,SQLINTEGER buflen)1055 stmt_SQLSetDescField(STMT *stmt, DESC *desc, SQLSMALLINT recnum,
1056 SQLSMALLINT fldid, SQLPOINTER val, SQLINTEGER buflen)
1057 {
1058 SQLRETURN rc;
1059 if ((rc= MySQLSetDescField((SQLHANDLE)desc, recnum, fldid,
1060 val, buflen)) != SQL_SUCCESS)
1061 memcpy(&stmt->error, &desc->error, sizeof(MYERROR));
1062 return rc;
1063 }
1064
1065
1066 /*
1067 * Call SQLCopyDesc in the "context" of a statement. This will copy
1068 * any error from the descriptor to the statement.
1069 */
stmt_SQLCopyDesc(STMT * stmt,DESC * src,DESC * dest)1070 SQLRETURN stmt_SQLCopyDesc(STMT *stmt, DESC *src, DESC *dest)
1071 {
1072 SQLRETURN rc;
1073 if ((rc= MySQLCopyDesc((SQLHANDLE)src, (SQLHANDLE)dest)) != SQL_SUCCESS)
1074 memcpy(&stmt->error, &dest->error, sizeof(MYERROR));
1075 return rc;
1076 }
1077
1078
1079 SQLRETURN SQL_API
SQLCopyDesc(SQLHDESC SourceDescHandle,SQLHDESC TargetDescHandle)1080 SQLCopyDesc(SQLHDESC SourceDescHandle, SQLHDESC TargetDescHandle)
1081 {
1082 CHECK_HANDLE(SourceDescHandle);
1083 CHECK_HANDLE(TargetDescHandle);
1084
1085 return MySQLCopyDesc(SourceDescHandle, TargetDescHandle);
1086 }
1087
1088