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