1 /************************************************************************************
2    Copyright (C) 2013, 2019 MariaDB Corporation AB
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with this library; if not see <http://www.gnu.org/licenses>
16    or write to the Free Software Foundation, Inc.,
17    51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18 *************************************************************************************/
19 #include <ma_odbc.h>
20 
21 extern Client_Charset utf8;
22 
23 /* To keep the source code smaller we use the following structure to check if a field
24    identifier is valid for a given descriptor type */
25 struct st_ma_desc_fldid MADB_DESC_FLDID[]=
26 {
27   {SQL_DESC_ALLOC_TYPE, {MADB_DESC_READ, MADB_DESC_READ, MADB_DESC_NONE, MADB_DESC_NONE}},
28   {SQL_DESC_ARRAY_SIZE, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_NONE}},
29   {SQL_DESC_ARRAY_STATUS_PTR, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW}},
30   {SQL_DESC_BIND_OFFSET_PTR, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_NONE}},
31   {SQL_DESC_BIND_TYPE, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_NONE}},
32   {SQL_DESC_COUNT, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_READ}},
33   {SQL_DESC_ROWS_PROCESSED_PTR, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_RW, MADB_DESC_RW}},
34   {SQL_DESC_AUTO_UNIQUE_VALUE,  {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
35   {SQL_DESC_BASE_COLUMN_NAME, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
36   {SQL_DESC_BASE_TABLE_NAME, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
37   {SQL_DESC_CASE_SENSITIVE, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
38   {SQL_DESC_CATALOG_NAME, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
39   {SQL_DESC_CONCISE_TYPE, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW}},
40   {SQL_DESC_DATA_PTR, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_NONE}},
41   {SQL_DESC_DATETIME_INTERVAL_CODE, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
42   {SQL_DESC_DATETIME_INTERVAL_PRECISION, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
43   {SQL_DESC_DISPLAY_SIZE, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE}},
44   {SQL_DESC_FIXED_PREC_SCALE, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_RW, MADB_DESC_RW}},
45   {SQL_DESC_INDICATOR_PTR, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_NONE}},
46   {SQL_DESC_LABEL, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE}},
47   {SQL_DESC_LENGTH, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
48   {SQL_DESC_LITERAL_PREFIX, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
49   {SQL_DESC_LITERAL_SUFFIX, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
50   {SQL_DESC_LOCAL_TYPE_NAME, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ, MADB_DESC_READ}},
51   {SQL_DESC_NAME, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_RW, MADB_DESC_READ}},
52   {SQL_DESC_NULLABLE, {MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ, MADB_DESC_READ}},
53   {SQL_DESC_NUM_PREC_RADIX, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
54   {SQL_DESC_OCTET_LENGTH, {MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
55   {SQL_DESC_OCTET_LENGTH_PTR,{MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_NONE, MADB_DESC_NONE}},
56   {SQL_DESC_PARAMETER_TYPE,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_RW, MADB_DESC_NONE}},
57   {SQL_DESC_PRECISION,{MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
58 #if (ODBCVER >= 0x0350)
59   {SQL_DESC_ROWVER,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ, MADB_DESC_READ}},
60 #endif
61   {SQL_DESC_SCALE,{MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
62   {SQL_DESC_SCHEMA_NAME,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
63   {SQL_DESC_SEARCHABLE,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
64   {SQL_DESC_TABLE_NAME,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
65   {SQL_DESC_TYPE,{MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_RW, MADB_DESC_READ}},
66   {SQL_DESC_TYPE_NAME ,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ, MADB_DESC_READ}},
67   {SQL_DESC_UNSIGNED ,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ, MADB_DESC_READ}},
68   {SQL_DESC_UPDATABLE ,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_READ}},
69   {SQL_DESC_UNNAMED ,{MADB_DESC_NONE, MADB_DESC_NONE, MADB_DESC_RW, MADB_DESC_READ}},
70   {0, {0, 0, 0, 0}}
71 };
72 
73 /* {{{ MADB_DescInit */
MADB_DescInit(MADB_Dbc * Dbc,enum enum_madb_desc_type DescType,my_bool isExternal)74 MADB_Desc *MADB_DescInit(MADB_Dbc *Dbc,enum enum_madb_desc_type DescType, my_bool isExternal)
75 {
76   MADB_Desc *Desc;
77 
78   if (!(Desc= (MADB_Desc *)MADB_CALLOC(sizeof(MADB_Desc))))
79     return NULL;
80 
81   Desc->DescType= DescType;
82   MADB_PutErrorPrefix(Dbc, &Desc->Error);
83 
84   if (MADB_InitDynamicArray(&Desc->Records, sizeof(MADB_DescRecord), 0, MADB_DESC_INIT_REC_NUM))
85   {
86     MADB_FREE(Desc);
87     return NULL;
88   }
89   if (isExternal)
90   {
91     if (MADB_InitDynamicArray(&Desc->Stmts, sizeof(MADB_Stmt**), 0, MADB_DESC_INIT_STMT_NUM))
92     {
93       MADB_DescFree(Desc, FALSE);
94       return NULL;
95     }
96     else
97     {
98       Desc->Dbc= Dbc;
99       /* MADB_DescInit call for explicit descriptor is in critical section */
100       Desc->ListItem.data= (void *)Desc;
101       Dbc->Descrs= MADB_ListAdd(Dbc->Descrs, &Desc->ListItem);
102     }
103   }
104   Desc->AppType= isExternal;
105   Desc->Header.ArraySize= 1;
106 
107   return Desc;
108 }
109 /* }}} */
110 
111 /* {{{ MADB_DescFree */
MADB_DescFree(MADB_Desc * Desc,my_bool RecordsOnly)112 SQLRETURN MADB_DescFree(MADB_Desc *Desc, my_bool RecordsOnly)
113 {
114   MADB_DescRecord *Record;
115   unsigned int i;
116 
117   if (!Desc)
118     return SQL_ERROR;
119 
120   /* We need to free internal pointers first */
121   for (i=0; i < Desc->Records.elements; i++)
122   {
123     Record= ((MADB_DescRecord *)Desc->Records.buffer) + i;
124     MADB_FREE(Record->InternalBuffer);
125     MADB_FREE(Record->DefaultValue);
126 
127     if (Desc->DescType == MADB_DESC_IRD)
128     {
129       MADB_FREE(Record->CatalogName);
130       MADB_FREE(Record->BaseCatalogName);
131       MADB_FREE(Record->BaseColumnName);
132       MADB_FREE(Record->BaseTableName);
133       MADB_FREE(Record->ColumnName);
134       MADB_FREE(Record->TableName);
135       MADB_FREE(Record->TypeName);
136     }
137     else if(Desc->DescType == MADB_DESC_IPD)
138     {
139       MADB_FREE(Record->TypeName);
140     }
141   }
142   MADB_DeleteDynamic(&Desc->Records);
143 
144   Desc->Header.Count= 0;
145   if (Desc->AppType)
146   {
147     EnterCriticalSection(&Desc->Dbc->ListsCs);
148     for (i=0; i < Desc->Stmts.elements; i++)
149     {
150       MADB_Stmt **XStmt= ((MADB_Stmt **)Desc->Stmts.buffer) + i;
151       MADB_Stmt *Stmt= *XStmt;
152       switch(Desc->DescType) {
153       case MADB_DESC_ARD:
154         Stmt->Ard=Stmt->IArd;
155         break;
156       case MADB_DESC_APD:
157         Stmt->Apd= Stmt->IApd;
158         break;
159       }
160     }
161     MADB_DeleteDynamic(&Desc->Stmts);
162 
163     Desc->Dbc->Descrs= MADB_ListDelete(Desc->Dbc->Descrs, &Desc->ListItem);
164     LeaveCriticalSection(&Desc->Dbc->ListsCs);
165   }
166 
167   if (!RecordsOnly)
168     MADB_FREE(Desc);
169   return SQL_SUCCESS;
170 }
171 /* }}} */
172 
173 /* {{{ MADB_SetIrdRecord */
174 my_bool
MADB_SetIrdRecord(MADB_Stmt * Stmt,MADB_DescRecord * Record,MYSQL_FIELD * Field)175 MADB_SetIrdRecord(MADB_Stmt *Stmt, MADB_DescRecord *Record, MYSQL_FIELD *Field)
176 {
177   MY_CHARSET_INFO cs;
178   MARIADB_CHARSET_INFO *FieldCs;
179 
180   if (Record == NULL)
181   {
182     return 1;
183   }
184 
185   mariadb_get_infov(Stmt->Connection->mariadb, MARIADB_CONNECTION_MARIADB_CHARSET_INFO, (void*)&cs);
186 
187   MADB_RESET(Record->CatalogName,    Field->db);
188   MADB_RESET(Record->TableName,      Field->table);
189   MADB_RESET(Record->ColumnName,     Field->name);
190   MADB_RESET(Record->BaseTableName,  Field->org_table);
191   MADB_RESET(Record->BaseColumnName, Field->org_name);
192   Record->AutoUniqueValue= (Field->flags & AUTO_INCREMENT_FLAG) ? SQL_TRUE : SQL_FALSE;
193   Record->CaseSensitive=   (Field->flags & BINARY_FLAG) ? SQL_TRUE : SQL_FALSE;
194   Record->Nullable= ( (Field->flags & NOT_NULL_FLAG) &&
195                       !Record->AutoUniqueValue &&
196                       Field->type != MYSQL_TYPE_TIMESTAMP) ? SQL_NO_NULLS : SQL_NULLABLE;
197   Record->Unsigned= (Field->flags & UNSIGNED_FLAG) ? SQL_TRUE : SQL_FALSE;
198   /* We assume it might be updatable if tablename exists */
199   Record->Updateable= (Field->table && Field->table[0]) ? SQL_ATTR_READWRITE_UNKNOWN : SQL_ATTR_READONLY;
200 
201   /*
202       RADIX:
203       If the data type in the SQL_DESC_TYPE field is an approximate numeric data type, this SQLINTEGER field
204       contains a value of 2 because the SQL_DESC_PRECISION field contains the number of bits.
205       If the data type in the SQL_DESC_TYPE field is an exact numeric data type, this field contains a value of 10
206       because the SQL_DESC_PRECISION field contains the number of decimal digits.
207       This field is set to 0 for all non-numeric data types.
208   */
209   switch (Field->type) {
210   case MYSQL_TYPE_DECIMAL:
211   case MYSQL_TYPE_NEWDECIMAL:
212     Record->NumPrecRadix= 10;
213     Record->Scale= Field->decimals;
214     Record->Precision= (SQLSMALLINT)Field->length - test(Record->Unsigned == SQL_FALSE) - test(Record->Scale > 0);
215     if (Record->Precision == 0)
216     {
217       Record->Precision= Record->Scale;
218     }
219     break;
220   case MYSQL_TYPE_FLOAT:
221     Record->NumPrecRadix= 2;
222     Record->Precision= (SQLSMALLINT)Field->length - 2;
223     //Record->Scale= Field->decimals;
224     break;
225   case MYSQL_TYPE_DOUBLE:
226   case MYSQL_TYPE_TINY:
227   case MYSQL_TYPE_SHORT:
228   case MYSQL_TYPE_INT24:
229   case MYSQL_TYPE_LONG:
230   case MYSQL_TYPE_LONGLONG:
231   case MYSQL_TYPE_YEAR:
232     Record->NumPrecRadix= 10;
233     break;
234   case MYSQL_TYPE_TIMESTAMP:
235   case MYSQL_TYPE_TIME:
236   case MYSQL_TYPE_DATETIME:
237     Record->Scale= Field->decimals;
238   default:
239     Record->NumPrecRadix= 0;
240     break;
241   }
242 
243   Record->ConciseType= MapMariadDbToOdbcType(Field);
244   /*
245       TYPE:
246       For the datetime and interval data types, this field returns the verbose data type: SQL_DATETIME or SQL_INTERVAL.
247   */
248   Record->Type= (Record->ConciseType ==  SQL_TYPE_DATE || Record->ConciseType ==  SQL_DATE ||
249                  Record->ConciseType ==  SQL_TYPE_TIME || Record->ConciseType ==  SQL_TIME ||
250                  Record->ConciseType ==  SQL_TYPE_TIMESTAMP || Record->ConciseType == SQL_TIMESTAMP) ?
251                     SQL_DATETIME : Record->ConciseType;
252 
253   switch(Record->ConciseType) {
254   case SQL_TYPE_DATE:
255     Record->DateTimeIntervalCode= SQL_CODE_DATE;
256     break;
257   case SQL_TYPE_TIME:
258     Record->DateTimeIntervalCode= SQL_CODE_TIME;
259     break;
260   case SQL_TYPE_TIMESTAMP:
261     Record->DateTimeIntervalCode= SQL_CODE_TIMESTAMP;
262     break;
263   }
264   /*
265       SEARCHABLE:
266       Columns of type SQL_LONGVARCHAR and SQL_LONGVARBINARY usually return SQL_PRED_CHAR.
267   */
268   Record->Searchable= (Record->ConciseType == SQL_LONGVARCHAR ||
269                        Record->ConciseType == SQL_WLONGVARCHAR ||
270                        Record->ConciseType == SQL_LONGVARBINARY) ? SQL_PRED_CHAR : SQL_SEARCHABLE;
271 
272   Record->DisplaySize= MADB_GetDisplaySize(Field, mariadb_get_charset_by_nr(Field->charsetnr));
273   Record->OctetLength= MADB_GetOctetLength(Field, cs.mbmaxlen);
274   FieldCs= mariadb_get_charset_by_nr(Field->charsetnr);
275   Record->Length= MADB_GetDataSize(Record->ConciseType, Field->length, Record->Unsigned == SQL_TRUE,
276                                    Record->Precision, Record->Scale, FieldCs!= NULL ? FieldCs->char_maxlen : 1);
277 
278   MADB_RESET(Record->TypeName, MADB_GetTypeName(Field));
279 
280   switch(Field->type) {
281   case MYSQL_TYPE_BLOB:
282   case MYSQL_TYPE_LONG_BLOB:
283   case MYSQL_TYPE_MEDIUM_BLOB:
284   case MYSQL_TYPE_STRING:
285   case MYSQL_TYPE_TINY_BLOB:
286   case MYSQL_TYPE_VAR_STRING:
287     if (Field->flags & BINARY_FLAG)
288     {
289       Record->LiteralPrefix= "0x";
290       Record->LiteralSuffix= "";
291       break;
292     }
293     /* else default */
294   case MYSQL_TYPE_DATE:
295   case MYSQL_TYPE_DATETIME:
296   case MYSQL_TYPE_NEWDATE:
297   case MYSQL_TYPE_TIME:
298   case MYSQL_TYPE_TIMESTAMP:
299   case MYSQL_TYPE_YEAR:
300     Record->LiteralPrefix="'";
301     Record->LiteralSuffix= "'";
302     break;
303   default:
304     Record->LiteralPrefix= "";
305     Record->LiteralSuffix= "";
306     break;
307   }
308 
309   return 0;
310 }
311 /* }}} */
312 
313 /* {{{ MADB_DescSetIrdMetadata */
314 my_bool
MADB_DescSetIrdMetadata(MADB_Stmt * Stmt,MYSQL_FIELD * Fields,unsigned int NumFields)315 MADB_DescSetIrdMetadata(MADB_Stmt *Stmt, MYSQL_FIELD *Fields, unsigned int NumFields)
316 {
317   SQLSMALLINT i;
318 
319   /* Perhaps we should call routine that does SQL_CLOSE here */
320   Stmt->Ird->Header.Count= 0;
321 
322   for (i= 0; i < (SQLSMALLINT)NumFields; i++)
323   {
324     if (MADB_SetIrdRecord(Stmt, MADB_DescGetInternalRecord(Stmt->Ird, i, MADB_DESC_WRITE), &Fields[i]))
325     {
326       return 1;
327     }
328   }
329   return 0;
330 }
331 /* }}} */
332 
333 /* {{{ MADB_FixOctetLength */
MADB_FixOctetLength(MADB_DescRecord * Record)334 void MADB_FixOctetLength(MADB_DescRecord *Record)
335 {
336   switch (Record->ConciseType) {
337   case SQL_BIT:
338   case SQL_TINYINT:
339     Record->OctetLength= 1;
340     break;
341   case SQL_SMALLINT:
342     Record->OctetLength= 2;
343     break;
344   case SQL_INTEGER:
345   case SQL_REAL:
346     Record->OctetLength= 4;
347     break;
348   case SQL_BIGINT:
349   case SQL_DOUBLE:
350     Record->OctetLength= 8;
351     break;
352   case SQL_TYPE_DATE:
353     Record->OctetLength= sizeof(SQL_DATE_STRUCT);
354     break;
355   case SQL_TYPE_TIME:
356     Record->OctetLength= sizeof(SQL_TIME_STRUCT);
357     break;
358   case SQL_TYPE_TIMESTAMP:
359     Record->OctetLength= sizeof(SQL_TIMESTAMP_STRUCT);
360     break;
361   default:
362     Record->OctetLength= MIN(MADB_INT_MAX32, Record->OctetLength);
363   }
364 }
365 /* }}} */
366 
367 /* {{{ MADB_FixDisplayLength */
MADB_FixDisplaySize(MADB_DescRecord * Record,const MY_CHARSET_INFO * charset)368 void MADB_FixDisplaySize(MADB_DescRecord *Record, const MY_CHARSET_INFO *charset)
369 {
370   switch (Record->ConciseType) {
371   case SQL_BIT:
372     Record->DisplaySize= 1;
373     break;
374   case SQL_TINYINT:
375     Record->DisplaySize= 4 - test(Record->Unsigned == SQL_TRUE);
376     break;
377   case SQL_SMALLINT:
378     Record->DisplaySize= 6 - test(Record->Unsigned == SQL_TRUE);
379     break;
380   case SQL_INTEGER:
381     Record->DisplaySize= 11 - test(Record->Unsigned == SQL_TRUE);
382     break;
383   case SQL_REAL:
384     Record->DisplaySize= 14;
385     break;
386   case SQL_BIGINT:
387     Record->DisplaySize= 20;
388     break;
389   case SQL_FLOAT:
390   case SQL_DOUBLE:
391     Record->DisplaySize= 24;
392     break;
393   case SQL_DECIMAL:
394   case SQL_NUMERIC:
395     Record->DisplaySize= Record->Precision + 2;
396     break;
397   case SQL_TYPE_DATE:
398     Record->DisplaySize= SQL_DATE_LEN;
399     break;
400   case SQL_TYPE_TIME:
401     Record->DisplaySize= SQL_TIME_LEN + MADB_FRACTIONAL_PART(Record->Scale);
402     break;
403   case SQL_TYPE_TIMESTAMP:
404     Record->DisplaySize= SQL_TIMESTAMP_LEN + MADB_FRACTIONAL_PART(Record->Scale);
405     break;
406   case SQL_BINARY:
407   case SQL_VARBINARY:
408   case SQL_LONGVARBINARY:
409     Record->DisplaySize=Record->OctetLength*2; /* For display in hex */
410     break;
411   case SQL_GUID:
412     Record->DisplaySize= 36;
413     break;
414   default:
415     if (charset == NULL || charset->mbmaxlen < 2/*i.e.0||1*/)
416     {
417       Record->DisplaySize=Record->OctetLength;
418     }
419     else
420     {
421       Record->DisplaySize=Record->OctetLength/charset->mbmaxlen;
422     }
423   }
424 }
425 /* }}} */
426 
427 /* {{{ MADB_FixDataSize - aka Column size */
MADB_FixDataSize(MADB_DescRecord * Record,const MY_CHARSET_INFO * charset)428 void MADB_FixDataSize(MADB_DescRecord *Record, const MY_CHARSET_INFO *charset)
429 {
430   Record->Length= MADB_GetDataSize(Record->ConciseType, Record->OctetLength, Record->Unsigned == TRUE, Record->Precision, Record->Scale, charset->mbmaxlen );
431 }
432 /* }}} */
433 
434 /* {{{ MADB_FixIrdRecord */
435 my_bool
MADB_FixIrdRecord(MADB_Stmt * Stmt,MADB_DescRecord * Record)436 MADB_FixIrdRecord(MADB_Stmt *Stmt, MADB_DescRecord *Record)
437 {
438   MY_CHARSET_INFO cs;
439 
440   if (Record == NULL)
441   {
442     return 1;
443   }
444 
445   MADB_FixOctetLength(Record);
446   /*
447       RADIX:
448       If the data type in the SQL_DESC_TYPE field is an approximate numeric data type, this SQLINTEGER field
449       contains a value of 2 because the SQL_DESC_PRECISION field contains the number of bits.
450       If the data type in the SQL_DESC_TYPE field is an exact numeric data type, this field contains a value of 10
451       because the SQL_DESC_PRECISION field contains the number of decimal digits.
452       This field is set to 0 for all non-numeric data types.
453   */
454   switch (Record->ConciseType) {
455   case SQL_DECIMAL:
456     Record->NumPrecRadix= 10;
457     Record->Precision= (SQLSMALLINT)Record->OctetLength - 2;
458     /*Record->Scale= Fields[i].decimals;*/
459     break;
460   case SQL_REAL:
461     /* Float*/
462     Record->NumPrecRadix= 2;
463     Record->Precision= (SQLSMALLINT)Record->OctetLength - 2;
464     break;
465   case SQL_DOUBLE:
466   case SQL_TINYINT:
467   case SQL_SMALLINT:
468   case SQL_INTEGER:
469   case SQL_BIGINT:
470     Record->NumPrecRadix= 10;
471     break;
472   default:
473     Record->NumPrecRadix= 0;
474     break;
475   }
476   /*
477       TYPE:
478       For the datetime and interval data types, this field returns the verbose data type: SQL_DATETIME or SQL_INTERVAL.
479   */
480   Record->Type= (Record->ConciseType ==  SQL_TYPE_DATE || Record->ConciseType ==  SQL_DATE ||
481                   Record->ConciseType ==  SQL_TYPE_TIME || Record->ConciseType ==  SQL_TIME ||
482                   Record->ConciseType ==  SQL_TYPE_TIMESTAMP || Record->ConciseType == SQL_TIMESTAMP) ?
483                     SQL_DATETIME : Record->ConciseType;
484 
485   switch(Record->ConciseType) {
486   case SQL_TYPE_DATE:
487     Record->DateTimeIntervalCode= SQL_CODE_DATE;
488     break;
489   case SQL_TYPE_TIME:
490     Record->DateTimeIntervalCode= SQL_CODE_TIME;
491     break;
492   case SQL_TYPE_TIMESTAMP:
493     Record->DateTimeIntervalCode= SQL_CODE_TIMESTAMP;
494     break;
495   }
496   /*
497       SEARCHABLE:
498       Columns of type SQL_LONGVARCHAR and SQL_LONGVARBINARY usually return SQL_PRED_CHAR.
499   */
500   Record->Searchable= (Record->ConciseType == SQL_LONGVARCHAR ||
501                         Record->ConciseType == SQL_WLONGVARCHAR ||
502                         Record->ConciseType == SQL_LONGVARBINARY) ? SQL_PRED_CHAR : SQL_SEARCHABLE;
503 
504   mariadb_get_infov(Stmt->Connection->mariadb, MARIADB_CONNECTION_MARIADB_CHARSET_INFO, (void*)&cs);
505 
506   MADB_FixDisplaySize(Record, &cs);
507   MADB_FixDataSize(Record, &cs);
508 
509   switch(Record->ConciseType) {
510   case SQL_BINARY:
511   case SQL_VARBINARY:
512   case SQL_LONGVARBINARY:
513       Record->LiteralPrefix= "0x";
514       Record->LiteralSuffix= "";
515       break;
516   /* else default */
517   case SQL_TYPE_DATE:
518   case SQL_TYPE_TIME:
519   case SQL_TYPE_TIMESTAMP:
520     Record->LiteralPrefix="'";
521     Record->LiteralSuffix= "'";
522     break;
523   default:
524     Record->LiteralPrefix= "";
525     Record->LiteralSuffix= "";
526     break;
527   }
528 
529   return 0;
530 }
531 /* }}} */
532 
533 /* {{{ MADB_FixColumnDataTypes */
534 my_bool
MADB_FixColumnDataTypes(MADB_Stmt * Stmt,MADB_ShortTypeInfo * ColTypesArr)535 MADB_FixColumnDataTypes(MADB_Stmt *Stmt, MADB_ShortTypeInfo *ColTypesArr)
536 {
537   SQLSMALLINT     i;
538   MADB_DescRecord *Record= NULL;
539 
540   if (ColTypesArr == NULL)
541   {
542     return 1;
543   }
544   for (i=0; i < Stmt->Ird->Header.Count; ++i)
545   {
546     if (ColTypesArr[i].SqlType != 0)
547     {
548       Record= MADB_DescGetInternalRecord(Stmt->Ird, i, MADB_DESC_READ);
549 
550       if (Record == NULL)
551       {
552         return 1;
553       }
554       Record->ConciseType= ColTypesArr[i].SqlType;
555       Record->Nullable= ColTypesArr[i].Nullable;
556 
557       Record->Unsigned= ColTypesArr[i].Unsigned != 0 ? SQL_TRUE : SQL_FALSE;
558 
559       if (ColTypesArr[i].OctetLength > 0)
560       {
561         Record->OctetLength= ColTypesArr[i].OctetLength;
562       }
563       if (MADB_FixIrdRecord(Stmt, Record))
564       {
565         return 1;
566       }
567     }
568   }
569 
570   /* If the stmt is re-executed, we should be able to fix columns again */
571   Stmt->ColsTypeFixArr= ColTypesArr;
572   return 0;
573 }
574 /* }}} */
575 
MADB_DescSetRecordDefaults(MADB_Desc * Desc,MADB_DescRecord * Record)576 void MADB_DescSetRecordDefaults(MADB_Desc *Desc, MADB_DescRecord *Record)
577 {
578   memset(Record, 0, sizeof(MADB_DescRecord));
579 
580   switch (Desc->DescType) {
581   case MADB_DESC_APD:
582     Record->ConciseType= Record->Type= SQL_C_DEFAULT;
583     break;
584   case MADB_DESC_ARD:
585     Record->ConciseType= Record->Type= SQL_C_DEFAULT;
586     break;
587   case MADB_DESC_IPD:
588     Record->FixedPrecScale= SQL_FALSE;
589     Record->LocalTypeName= "";
590     Record->Nullable= SQL_NULLABLE;
591     Record->ParameterType= SQL_PARAM_INPUT;
592     MADB_RESET(Record->TypeName, "VARCHAR");
593     Record->Unsigned= SQL_FALSE;
594     Record->ColumnName= "";
595     break;
596   case MADB_DESC_IRD:
597     Record->Nullable= SQL_NULLABLE_UNKNOWN;
598     Record->FixedPrecScale= SQL_FALSE;
599     Record->CaseSensitive= SQL_TRUE;
600     Record->ConciseType= SQL_VARCHAR;
601     Record->AutoUniqueValue= SQL_FALSE;
602     Record->Type= SQL_VARCHAR;
603     MADB_RESET(Record->TypeName, "VARCHAR");
604     Record->Unsigned= SQL_FALSE;
605     break;
606   }
607 }
608 /* }}} */
609 
610 /* {{{ MADB_DescGetInternalRecord */
MADB_DescGetInternalRecord(MADB_Desc * Desc,SQLSMALLINT RecordNumber,SQLSMALLINT Type)611 MADB_DescRecord *MADB_DescGetInternalRecord(MADB_Desc *Desc, SQLSMALLINT RecordNumber, SQLSMALLINT Type)
612 {
613   MADB_DescRecord *DescRecord;
614 
615   if (RecordNumber > (SQLINTEGER)Desc->Records.elements &&
616       Type == MADB_DESC_READ)
617   {
618     MADB_SetError(&Desc->Error, MADB_ERR_07009, NULL, 0);
619     return NULL;
620   }
621 
622   while (RecordNumber >= (SQLINTEGER)Desc->Records.elements)
623   {
624     if (!(DescRecord= (MADB_DescRecord *)MADB_AllocDynamic(&Desc->Records)))
625     {
626       MADB_SetError(&Desc->Error, MADB_ERR_HY001, NULL, 0);
627       return NULL;
628     }
629 
630     MADB_DescSetRecordDefaults(Desc, DescRecord);
631   }
632 
633   if (RecordNumber + 1 > Desc->Header.Count)
634     Desc->Header.Count= (SQLSMALLINT)(RecordNumber + 1);
635 
636   DescRecord= ((MADB_DescRecord *)Desc->Records.buffer) + RecordNumber;
637 
638   return DescRecord;
639 }
640 /* }}} */
641 
642 /* {{{ MADB_DescCheckFldId */
MADB_DeskCheckFldId(MADB_Desc * Desc,SQLSMALLINT FieldIdentifier,SQLSMALLINT mode)643 SQLRETURN MADB_DeskCheckFldId(MADB_Desc *Desc, SQLSMALLINT FieldIdentifier, SQLSMALLINT mode)
644 {
645   int i= 0;
646 
647   while (MADB_DESC_FLDID[i].FieldIdentifier &&
648          MADB_DESC_FLDID[i].FieldIdentifier != FieldIdentifier)
649     ++i;
650 
651   /* End of list = invalid FieldIdentifier */
652   if (!MADB_DESC_FLDID[i].FieldIdentifier ||
653       !(MADB_DESC_FLDID[i].Access[Desc->DescType] & mode)) {
654     MADB_SetError(&Desc->Error, MADB_ERR_HY091, NULL, 0);
655     return SQL_ERROR;
656   }
657   return SQL_SUCCESS;
658 }
659 /* }}} */
660 
661 /* {{{ MADB_DescGetField */
MADB_DescGetField(SQLHDESC DescriptorHandle,SQLSMALLINT RecNumber,SQLSMALLINT FieldIdentifier,SQLPOINTER ValuePtr,SQLINTEGER BufferLength,SQLINTEGER * StringLengthPtr,my_bool isWChar)662 SQLRETURN MADB_DescGetField(SQLHDESC DescriptorHandle,
663                             SQLSMALLINT RecNumber,
664                             SQLSMALLINT FieldIdentifier,
665                             SQLPOINTER ValuePtr,
666                             SQLINTEGER BufferLength,
667                             SQLINTEGER *StringLengthPtr,
668                             my_bool isWChar)
669 {
670   MADB_Desc *Desc= (MADB_Desc *)DescriptorHandle;
671   MADB_DescRecord *DescRecord= NULL;
672   SQLRETURN ret;
673   size_t Length;
674 
675   /* Bookmark */
676   if (RecNumber < 1)
677   {
678     /* todo */
679 
680   }
681 
682   ret= MADB_DeskCheckFldId(Desc, FieldIdentifier, MADB_DESC_READ);
683   if (!SQL_SUCCEEDED(ret))
684     return ret;
685 
686   MADB_CLEAR_ERROR(&Desc->Error);
687 
688   if (RecNumber)
689     if (!(DescRecord= MADB_DescGetInternalRecord(Desc, RecNumber - 1, MADB_DESC_READ)))
690       return SQL_ERROR;
691 
692   switch (FieldIdentifier) {
693   case SQL_DESC_ALLOC_TYPE:
694     *((SQLINTEGER *)ValuePtr)= Desc->Header.AllocType;
695     break;
696   case SQL_DESC_ARRAY_SIZE:
697     *((SQLULEN *)ValuePtr)= Desc->Header.ArraySize;
698     break;
699   case SQL_DESC_ARRAY_STATUS_PTR:
700     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)Desc->Header.ArrayStatusPtr;
701     break;
702   case SQL_DESC_BIND_OFFSET_PTR:
703     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)Desc->Header.BindOffsetPtr;
704     break;
705   case SQL_DESC_BIND_TYPE:
706     *((SQLULEN *)ValuePtr)= Desc->Header.BindType;
707     break;
708   case SQL_DESC_COUNT:
709     *(SQLSMALLINT *)ValuePtr= Desc->Header.Count;
710     break;
711   case SQL_DESC_ROWS_PROCESSED_PTR:
712     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)Desc->Header.RowsProcessedPtr;
713     break;
714   case SQL_DESC_AUTO_UNIQUE_VALUE:
715     *((SQLINTEGER *)ValuePtr)= DescRecord->AutoUniqueValue;
716     break;
717   case SQL_DESC_BASE_COLUMN_NAME:
718     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->BaseColumnName, SQL_NTS, &Desc->Error);
719     if (StringLengthPtr)
720       *StringLengthPtr= (SQLINTEGER)Length;
721     break;
722   case SQL_DESC_BASE_TABLE_NAME:
723     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->BaseTableName, SQL_NTS, &Desc->Error);
724     if (StringLengthPtr)
725       *StringLengthPtr= (SQLINTEGER)Length;
726     break;
727   case SQL_DESC_CASE_SENSITIVE:
728     *((SQLINTEGER *)ValuePtr)= DescRecord->CaseSensitive;
729     break;
730   case SQL_DESC_CATALOG_NAME:
731     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->BaseCatalogName, SQL_NTS, &Desc->Error);
732     if (StringLengthPtr)
733       *StringLengthPtr= (SQLINTEGER)Length;
734     break;
735   case SQL_DESC_CONCISE_TYPE:
736     *((SQLSMALLINT *)ValuePtr)= DescRecord->ConciseType;
737     break;
738   case SQL_DESC_DATA_PTR:
739     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->DataPtr;
740     break;
741   case SQL_DESC_DATETIME_INTERVAL_CODE:
742     *((SQLSMALLINT *)ValuePtr)= DescRecord->DateTimeIntervalCode;
743     break;
744   case SQL_DESC_DATETIME_INTERVAL_PRECISION:
745     *((SQLINTEGER *)ValuePtr)= DescRecord->DateTimeIntervalPrecision;
746     break;
747   case SQL_DESC_FIXED_PREC_SCALE:
748     *((SQLSMALLINT *)ValuePtr)= DescRecord->FixedPrecScale;
749     break;
750   case SQL_DESC_INDICATOR_PTR:
751     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->IndicatorPtr;
752     break;
753   case SQL_DESC_LENGTH:
754    *((SQLINTEGER *)ValuePtr)= DescRecord->DescLength;
755     break;
756   case SQL_DESC_LITERAL_PREFIX:
757     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->LiteralPrefix;
758     break;
759   case SQL_DESC_LITERAL_SUFFIX:
760     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->LiteralSuffix;
761     break;
762   case SQL_DESC_LOCAL_TYPE_NAME:
763     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->LocalTypeName, SQL_NTS, &Desc->Error);
764     if (StringLengthPtr)
765       *StringLengthPtr= (SQLINTEGER)Length;
766     break;
767   case SQL_DESC_NAME:
768     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->BaseColumnName, SQL_NTS, &Desc->Error);
769     if (StringLengthPtr)
770       *StringLengthPtr= (SQLINTEGER)Length;
771     DescRecord->Unnamed= SQL_NAMED;
772     break;
773   case SQL_DESC_NULLABLE:
774     *((SQLINTEGER *)ValuePtr)= DescRecord->Nullable;
775     break;
776   case SQL_DESC_NUM_PREC_RADIX:
777     *((SQLINTEGER *)ValuePtr)= DescRecord->NumPrecRadix;
778     break;
779   case SQL_DESC_OCTET_LENGTH:
780     *((SQLLEN *)ValuePtr)= DescRecord->OctetLength;
781     break;
782   case SQL_DESC_OCTET_LENGTH_PTR:
783     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->OctetLengthPtr;
784     break;
785   case SQL_DESC_PARAMETER_TYPE:
786     *((SQLSMALLINT *)ValuePtr)= DescRecord->ParameterType;
787     break;
788   case SQL_DESC_PRECISION:
789     *((SQLINTEGER *)ValuePtr)= DescRecord->Precision;
790     break;
791 #if (ODBCVER >= 0x0350)
792   case SQL_DESC_ROWVER:
793     *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)(SQLULEN)DescRecord->RowVer;
794     break;
795 #endif
796   case SQL_DESC_SCALE:
797     *((SQLINTEGER *)ValuePtr)= DescRecord->Scale;
798     break;
799   case SQL_DESC_SCHEMA_NAME:
800     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->SchemaName, SQL_NTS, &Desc->Error);
801     if (StringLengthPtr)
802       *StringLengthPtr= (SQLINTEGER)Length;
803     break;
804   case SQL_DESC_SEARCHABLE:
805     *((SQLINTEGER *)ValuePtr)= DescRecord->Searchable;
806     break;
807   case SQL_DESC_TABLE_NAME:
808     Length= MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->TableName, SQL_NTS, &Desc->Error);
809     if (StringLengthPtr)
810       *StringLengthPtr= (SQLINTEGER)Length;
811     break;
812   case SQL_DESC_TYPE:
813     *((SQLINTEGER *)ValuePtr)= DescRecord->Type;
814     break;
815   case SQL_DESC_TYPE_NAME:
816     *StringLengthPtr= (SQLINTEGER)MADB_SetString(isWChar ? &utf8 : 0, ValuePtr, BufferLength, DescRecord->TypeName, SQL_NTS, &Desc->Error);
817      break;
818   case SQL_DESC_UNSIGNED:
819     *((SQLINTEGER *)ValuePtr)= DescRecord->Unsigned;
820     break;
821   case SQL_DESC_UPDATABLE:
822     *((SQLINTEGER *)ValuePtr)= DescRecord->Updateable;
823     break;
824   }
825   return ret;
826 }
827 
828 /* {{{ MADB_DescSetField */
MADB_DescSetField(SQLHDESC DescriptorHandle,SQLSMALLINT RecNumber,SQLSMALLINT FieldIdentifier,SQLPOINTER ValuePtr,SQLINTEGER BufferLength,my_bool isWChar)829 SQLRETURN MADB_DescSetField(SQLHDESC DescriptorHandle,
830                             SQLSMALLINT RecNumber,
831                             SQLSMALLINT FieldIdentifier,
832                             SQLPOINTER ValuePtr,
833                             SQLINTEGER BufferLength,
834                             my_bool isWChar)
835 {
836   MADB_Desc *Desc= (MADB_Desc *)DescriptorHandle;
837   MADB_DescRecord *DescRecord= NULL;
838   SQLRETURN ret;
839   SQL_UNNAMED;
840   ret= MADB_DeskCheckFldId(Desc, FieldIdentifier, MADB_DESC_WRITE);
841 
842   /* Application may set IPD's field SQL_DESC_UNNAMED to SQL_UNNAMED only */
843   if (FieldIdentifier == SQL_DESC_UNNAMED && (SQLSMALLINT)(SQLULEN)ValuePtr == SQL_NAMED)
844   {
845     ret= MADB_SetError(&Desc->Error, MADB_ERR_HY092, NULL, 0);
846   }
847 
848   if (!SQL_SUCCEEDED(ret))
849     return ret;
850 
851   MADB_CLEAR_ERROR(&Desc->Error);
852   switch (FieldIdentifier) {
853   case SQL_DESC_ARRAY_SIZE:
854     Desc->Header.ArraySize= (SQLULEN)ValuePtr;
855     return SQL_SUCCESS;
856   case SQL_DESC_ARRAY_STATUS_PTR:
857     Desc->Header.ArrayStatusPtr= (SQLUSMALLINT *)ValuePtr;
858     return SQL_SUCCESS;
859   case SQL_DESC_BIND_OFFSET_PTR:
860     Desc->Header.BindOffsetPtr= (SQLULEN *)ValuePtr;
861     return SQL_SUCCESS;
862   case SQL_DESC_BIND_TYPE:
863     Desc->Header.BindType= (SQLINTEGER)(SQLLEN)ValuePtr;
864     return SQL_SUCCESS;
865   case SQL_DESC_COUNT:
866     Desc->Header.Count= (SQLSMALLINT)(SQLLEN)ValuePtr;
867     return SQL_SUCCESS;
868   case SQL_DESC_ROWS_PROCESSED_PTR:
869     Desc->Header.RowsProcessedPtr= (SQLULEN *)ValuePtr;
870     return SQL_SUCCESS;
871   }
872 
873   if (RecNumber > 0)
874   {
875     if (!(DescRecord= MADB_DescGetInternalRecord(Desc, RecNumber - 1, MADB_DESC_WRITE)))
876       return SQL_ERROR;
877 
878     switch (FieldIdentifier) {
879     case SQL_DESC_CONCISE_TYPE:
880       DescRecord->ConciseType= (SQLSMALLINT)(SQLLEN)ValuePtr;
881       DescRecord->Type= MADB_GetTypeFromConciseType(DescRecord->ConciseType);
882       if (DescRecord->Type == SQL_INTERVAL)
883       {
884         DescRecord->DateTimeIntervalCode= DescRecord->ConciseType - 100;
885       }
886       break;
887     case SQL_DESC_DATA_PTR:
888       DescRecord->DataPtr= ValuePtr;
889       break;
890     case SQL_DESC_DATETIME_INTERVAL_CODE:
891       DescRecord->DateTimeIntervalCode= (SQLSMALLINT)(SQLLEN)ValuePtr;
892       break;
893     case SQL_DESC_DATETIME_INTERVAL_PRECISION:
894       DescRecord->DateTimeIntervalPrecision= (SQLINTEGER)(SQLLEN)ValuePtr;
895       break;
896     case SQL_DESC_FIXED_PREC_SCALE:
897       DescRecord->FixedPrecScale= (SQLSMALLINT)(SQLLEN)ValuePtr;
898       break;
899     case SQL_DESC_INDICATOR_PTR:
900       DescRecord->IndicatorPtr= (SQLLEN *)ValuePtr;
901       break;
902     case SQL_DESC_LENGTH:
903       DescRecord->DescLength= (SQLINTEGER)(SQLLEN)ValuePtr;
904       break;
905     case SQL_DESC_NUM_PREC_RADIX:
906       DescRecord->NumPrecRadix= (SQLINTEGER)(SQLLEN)ValuePtr;
907       break;
908     case SQL_DESC_OCTET_LENGTH:
909       DescRecord->OctetLength= (SQLLEN)ValuePtr;
910       break;
911     case SQL_DESC_OCTET_LENGTH_PTR:
912       DescRecord->OctetLengthPtr= (SQLLEN *)ValuePtr;
913       break;
914     case SQL_DESC_PARAMETER_TYPE:
915       DescRecord->ParameterType= (SQLSMALLINT)(SQLLEN)ValuePtr;
916       break;
917     case SQL_DESC_PRECISION:
918       DescRecord->Precision= (SQLSMALLINT)(SQLLEN)ValuePtr;
919       break;
920     case SQL_DESC_SCALE:
921       if ((SQLSMALLINT)(SQLLEN)ValuePtr > MADB_MAX_SCALE)
922       {
923         DescRecord->Scale= MADB_MAX_SCALE;
924         ret= MADB_SetError(&Desc->Error, MADB_ERR_01S02, NULL, 0);
925       }
926       else
927       {
928         DescRecord->Scale= (SQLSMALLINT)(SQLLEN)ValuePtr;
929       }
930       break;
931     case SQL_DESC_TYPE:
932       DescRecord->Type= (SQLSMALLINT)(SQLLEN)ValuePtr;
933       DescRecord->ConciseType= DescRecord->Type;
934       break;
935     }
936     /* bug41018 (ma_desc.c):
937      We need to unbind in case parameter doesn't set a buffer or header field */
938     switch (FieldIdentifier)
939     {
940     case SQL_DESC_DATA_PTR:
941     case SQL_DESC_OCTET_LENGTH_PTR:
942     case SQL_DESC_INDICATOR_PTR:
943       break;
944     default:
945       if (Desc->DescType== MADB_DESC_ARD && DescRecord && DescRecord->DataPtr)
946         DescRecord->DataPtr= NULL;
947       break;
948     }
949 
950     /* inUse is only used to check if column/parameter was bound or not. Thus we do not set it for each field, but only for those,
951        that make column/parameter "bound" */
952     if (DescRecord && (DescRecord->DataPtr != NULL || DescRecord->OctetLengthPtr != NULL || DescRecord->IndicatorPtr != NULL))
953       DescRecord->inUse= 1;
954   }
955   return ret;
956 }
957 /* }}} */
958 
959 /* {{{ MADB_DescCopyDesc */
MADB_DescCopyDesc(MADB_Desc * SrcDesc,MADB_Desc * DestDesc)960 SQLRETURN MADB_DescCopyDesc(MADB_Desc *SrcDesc, MADB_Desc *DestDesc)
961 {
962   if (!SrcDesc)
963     return SQL_INVALID_HANDLE;
964 
965   if (DestDesc->DescType == MADB_DESC_IRD)
966   {
967     MADB_SetError(&DestDesc->Error, MADB_ERR_HY016, NULL, 0);
968     return SQL_ERROR;
969   }
970   if (SrcDesc->DescType == MADB_DESC_IRD && !SrcDesc->Header.Count)
971   {
972     MADB_SetError(&DestDesc->Error, MADB_ERR_HY007, NULL, 0);
973     return SQL_ERROR;
974   }
975   /* make sure there aren't old records */
976   MADB_DeleteDynamic(&DestDesc->Records);
977   if (MADB_InitDynamicArray(&DestDesc->Records, sizeof(MADB_DescRecord),
978                             SrcDesc->Records.max_element, SrcDesc->Records.alloc_increment))
979   {
980     MADB_SetError(&DestDesc->Error, MADB_ERR_HY001, NULL, 0);
981     return SQL_ERROR;
982   }
983 
984   memcpy(&DestDesc->Header, &SrcDesc->Header, sizeof(MADB_Header));
985 
986   /* We don't copy AppType from Src to Dest. If we copy internal descriptor to the explicit/external, it stays explicit/external */
987 
988   DestDesc->DescType= SrcDesc->DescType;
989   memcpy(&DestDesc->Error, &SrcDesc->Error, sizeof(MADB_Error));
990 
991   /* Since we never allocate pointers we can just copy content */
992   memcpy(DestDesc->Records.buffer, SrcDesc->Records.buffer,
993          SrcDesc->Records.size_of_element * SrcDesc->Records.max_element);
994   DestDesc->Records.elements= SrcDesc->Records.elements;
995 
996   /* internal buffer needs to be clearead or we will get it freed twice with all nice subsequences */
997   {
998     unsigned int i;
999 
1000     for (i= 0; i < DestDesc->Records.elements; ++i)
1001     {
1002       MADB_DescRecord *Rec= MADB_DescGetInternalRecord(DestDesc, i, MADB_DESC_READ);
1003 
1004       if (Rec != NULL)
1005       {
1006         Rec->InternalBuffer= NULL;
1007       }
1008     }
1009   }
1010 
1011   return SQL_SUCCESS;
1012 }
1013 /* }}} */
1014 
MADB_DescGetRec(MADB_Desc * Desc,SQLSMALLINT RecNumber,SQLCHAR * Name,SQLSMALLINT BufferLength,SQLSMALLINT * StringLengthPtr,SQLSMALLINT * TypePtr,SQLSMALLINT * SubTypePtr,SQLLEN * LengthPtr,SQLSMALLINT * PrecisionPtr,SQLSMALLINT * ScalePtr,SQLSMALLINT * NullablePtr,BOOL isWChar)1015 SQLRETURN MADB_DescGetRec(MADB_Desc *Desc,
1016     SQLSMALLINT RecNumber,
1017     SQLCHAR *Name,
1018     SQLSMALLINT BufferLength,
1019     SQLSMALLINT *StringLengthPtr,
1020     SQLSMALLINT *TypePtr,
1021     SQLSMALLINT *SubTypePtr,
1022     SQLLEN *LengthPtr,
1023     SQLSMALLINT *PrecisionPtr,
1024     SQLSMALLINT *ScalePtr,
1025     SQLSMALLINT *NullablePtr,
1026     BOOL isWChar)
1027 {
1028   MADB_DescRecord *Record;
1029   SQLLEN Length;
1030 
1031   MADB_CLEAR_ERROR(&Desc->Error);
1032 
1033   if (!(Record= MADB_DescGetInternalRecord(Desc, RecNumber, MADB_DESC_READ)))
1034   {
1035     MADB_SetError(&Desc->Error, MADB_ERR_07009, NULL, 0);
1036     return Desc->Error.ReturnValue;
1037   }
1038 
1039   /* SQL_DESC_NAME */
1040   Length= MADB_SetString(isWChar ? &utf8 : 0, Name, BufferLength, Record->BaseColumnName, SQL_NTS, &Desc->Error);
1041   if (StringLengthPtr)
1042     *StringLengthPtr= (SQLSMALLINT)Length;
1043   Record->Unnamed= SQL_NAMED;
1044 
1045   /* SQL_DESC_TYPE */
1046   *(SQLSMALLINT *)TypePtr= (SQLSMALLINT)Record->Type;
1047 
1048   /* SQL_DESC_DATETIME_INTERVAL_CODE */
1049   *(SQLSMALLINT *)SubTypePtr= Record->DateTimeIntervalCode;
1050 
1051   /* SQL_DESC_OCTET_LENGTH */
1052   *(SQLLEN *)LengthPtr= (SQLLEN)Record->OctetLength;
1053 
1054   /* SQL_DESC_PRECISION */
1055   *(SQLSMALLINT *)PrecisionPtr= (SQLSMALLINT)Record->Precision;
1056 
1057   /* SQL_DESC_SCALE */
1058   *(SQLSMALLINT *)ScalePtr= (SQLSMALLINT)Record->Scale;
1059 
1060   /* SQL_DESC_NULLABLE */
1061   *(SQLSMALLINT *)NullablePtr= (SQLSMALLINT)Record->Nullable;
1062 
1063   return SQL_SUCCESS;
1064 }
1065 
1066