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