1 /************************************************************************************
2 Copyright (C) 2017 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
20 /* ODBC C->SQL and SQL->C type conversion functions */
21
22 #include <ma_odbc.h>
23
24 /* Borrowed from C/C and adapted */
MADB_Str2Ts(const char * Str,size_t Length,MYSQL_TIME * Tm,BOOL Interval,MADB_Error * Error,BOOL * isTime)25 SQLRETURN MADB_Str2Ts(const char *Str, size_t Length, MYSQL_TIME *Tm, BOOL Interval, MADB_Error *Error, BOOL *isTime)
26 {
27 char *localCopy= MADB_ALLOC(Length + 1), *Start= localCopy, *Frac, *End= Start + Length;
28 my_bool isDate= 0;
29
30 if (Start == NULL)
31 {
32 return MADB_SetError(Error, MADB_ERR_HY001, NULL, 0);
33 }
34
35 memset(Tm, 0, sizeof(MYSQL_TIME));
36 memcpy(Start, Str, Length);
37 Start[Length]= '\0';
38
39 while (Length && isspace(*Start)) ++Start, --Length;
40
41 if (Length == 0)
42 {
43 goto end;//MADB_SetError(Error, MADB_ERR_22008, NULL, 0);
44 }
45
46 /* Determine time type:
47 MYSQL_TIMESTAMP_DATE: [-]YY[YY].MM.DD
48 MYSQL_TIMESTAMP_DATETIME: [-]YY[YY].MM.DD hh:mm:ss.mmmmmm
49 MYSQL_TIMESTAMP_TIME: [-]hh:mm:ss.mmmmmm
50 */
51 if (strchr(Start, '-'))
52 {
53 if (sscanf(Start, "%d-%u-%u", &Tm->year, &Tm->month, &Tm->day) < 3)
54 {
55 return MADB_SetError(Error, MADB_ERR_22008, NULL, 0);
56 }
57 isDate= 1;
58 if (!(Start= strchr(Start, ' ')))
59 {
60 goto check;
61 }
62 }
63 if (!strchr(Start, ':'))
64 {
65 goto check;
66 }
67
68 if (isDate == 0)
69 {
70 *isTime= 1;
71 }
72
73 if ((Frac= strchr(Start, '.')) != NULL) /* fractional seconds */
74 {
75 size_t FracMulIdx= End - (Frac + 1) - 1/*to get index array index */;
76 /* ODBC - nano-seconds */
77 if (sscanf(Start, "%d:%u:%u.%6lu", &Tm->hour, &Tm->minute,
78 &Tm->second, &Tm->second_part) < 4)
79 {
80 return MADB_SetError(Error, MADB_ERR_22008, NULL, 0);
81 }
82 /* 9 digits up to nano-seconds, and -1 since comparing with arr idx */
83 if (FracMulIdx < 6 - 1)
84 {
85 static unsigned long Mul[]= {100000, 10000, 1000, 100, 10};
86 Tm->second_part*= Mul[FracMulIdx];
87 }
88 }
89 else
90 {
91 if (sscanf(Start, "%d:%u:%u", &Tm->hour, &Tm->minute,
92 &Tm->second) < 3)
93 {
94 return MADB_SetError(Error, MADB_ERR_22008, NULL, 0);
95 }
96 }
97
98 check:
99 if (Interval == FALSE)
100 {
101 if (isDate)
102 {
103 if (Tm->year > 0)
104 {
105 if (Tm->year < 70)
106 {
107 Tm->year+= 2000;
108 }
109 else if (Tm->year < 100)
110 {
111 Tm->year+= 1900;
112 }
113 }
114 }
115 }
116
117 end:
118 MADB_FREE(localCopy);
119 return SQL_SUCCESS;
120 }
121
122 /* {{{ MADB_ConversionSupported */
MADB_ConversionSupported(MADB_DescRecord * From,MADB_DescRecord * To)123 BOOL MADB_ConversionSupported(MADB_DescRecord *From, MADB_DescRecord *To)
124 {
125 switch (From->ConciseType)
126 {
127 case SQL_C_TIMESTAMP:
128 case SQL_C_TYPE_TIMESTAMP:
129 case SQL_C_TIME:
130 case SQL_C_TYPE_TIME:
131 case SQL_C_DATE:
132 case SQL_C_TYPE_DATE:
133
134 if (To->Type == SQL_INTERVAL)
135 {
136 return FALSE;
137 }
138
139 }
140 return TRUE;
141 }
142 /* }}} */
143
144 /* {{{ MADB_ConvertCharToBit */
MADB_ConvertCharToBit(MADB_Stmt * Stmt,char * src)145 char MADB_ConvertCharToBit(MADB_Stmt *Stmt, char *src)
146 {
147 char *EndPtr= NULL;
148 float asNumber= strtof(src, &EndPtr);
149
150 if (asNumber < 0 || asNumber > 1)
151 {
152 /* 22003 */
153 }
154 else if (asNumber != 0 && asNumber != 1)
155 {
156 /* 22001 */
157 }
158 else if (EndPtr != NULL && *EndPtr != '\0')
159 {
160 /* 22018. TODO: check if condition is correct */
161 }
162
163 return asNumber != 0 ? '\1' : '\0';
164 }
165 /* }}} */
166
167 /* {{{ MADB_ConvertNumericToChar */
MADB_ConvertNumericToChar(SQL_NUMERIC_STRUCT * Numeric,char * Buffer,int * ErrorCode)168 size_t MADB_ConvertNumericToChar(SQL_NUMERIC_STRUCT *Numeric, char *Buffer, int *ErrorCode)
169 {
170 const double DenominatorTable[]= {1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0/*9*/,
171 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 100000000000000.0, 1000000000000000.0/*15*/,
172 10000000000000000.0, 100000000000000000.0, 1000000000000000000.0, 10000000000000000000.0, 1e+20 /*20*/, 1e+21,
173 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38 };
174 unsigned long long Numerator= 0;
175 double Denominator;
176 int Scale= 0;
177 unsigned long long ByteDenominator= 1;
178 int i;
179 char* p;
180 size_t Length;
181
182 Buffer[0]= 0;
183 *ErrorCode= 0;
184
185 Scale+= (Numeric->scale < 0) ? -Numeric->scale : Numeric->scale;
186
187 for (i= 0; i < SQL_MAX_NUMERIC_LEN; ++i)
188 {
189 if (i > 7 && Numeric->val[i] != '\0')
190 {
191 *ErrorCode = MADB_ERR_22003;
192 return 0;
193 }
194 Numerator += Numeric->val[i] * ByteDenominator;
195 ByteDenominator <<= 8;
196 }
197
198 if (Numeric->scale > 0)
199 {
200 Denominator = DenominatorTable[Scale];// pow(10, Scale);
201 char tmp[10 /*1 sign + 1 % + 1 dot + 3 scale + 1f + 1\0 */];
202 _snprintf(tmp, sizeof(tmp), "%s%%.%df", Numeric->sign ? "" : "-", Numeric->scale);
203 _snprintf(Buffer, MADB_CHARSIZE_FOR_NUMERIC, tmp, Numerator / Denominator);
204 }
205 else
206 {
207 _snprintf(Buffer, MADB_CHARSIZE_FOR_NUMERIC, "%s%llu", Numeric->sign ? "" : "-", Numerator);
208 /* Checking Truncation for negative/zero scale before adding 0 */
209 Length= strlen(Buffer) - (Numeric->sign ? 0 : 1);
210 if (Length > Numeric->precision)
211 {
212 *ErrorCode = MADB_ERR_22003;
213 goto end;
214 }
215 for (i= 0; i < Scale; ++i)
216 {
217 strcat(Buffer, "0");
218 }
219 }
220
221 if (Buffer[0] == '-')
222 {
223 ++Buffer;
224 }
225
226 Length= strlen(Buffer);
227 /* Truncation checks:
228 1st ensure, that the digits before decimal point will fit */
229 if ((p= strchr(Buffer, '.')))
230 {
231 if (Numeric->precision != 0 && (p - Buffer) > Numeric->precision)
232 {
233 *ErrorCode= MADB_ERR_22003;
234 Length= Numeric->precision;
235 Buffer[Numeric->precision]= 0;
236 goto end;
237 }
238
239 /* If scale >= precision, we still can have no truncation */
240 if (Length > (unsigned int)(Numeric->precision + 1)/*dot*/ && Scale < Numeric->precision)
241 {
242 *ErrorCode= MADB_ERR_01S07;
243 Length = Numeric->precision + 1/*dot*/;
244 Buffer[Length]= 0;
245 goto end;
246 }
247 }
248
249 end:
250 /* check if last char is decimal point */
251 if (Length > 0 && Buffer[Length - 1] == '.')
252 {
253 Buffer[Length - 1]= 0;
254 }
255 if (Numeric->sign == 0)
256 {
257 ++Length;
258 }
259 return Length;
260 }
261 /* }}} */
262
263 /* {{{ MADB_ConvertNullValue */
MADB_ConvertNullValue(MADB_Stmt * Stmt,MYSQL_BIND * MaBind)264 SQLRETURN MADB_ConvertNullValue(MADB_Stmt *Stmt, MYSQL_BIND *MaBind)
265 {
266 MaBind->buffer_type= MYSQL_TYPE_NULL;
267 MaBind->buffer_length= 0;
268
269 return SQL_SUCCESS;
270 }
271 /* }}} */
272
273 /* {{{ MADB_ProcessIndicator */
274 /* Returns TRUE if indicator contains some special value, and thus no further type conversion is needed */
MADB_ProcessIndicator(MADB_Stmt * Stmt,SQLLEN Indicator,char * DefaultValue,MYSQL_BIND * MaBind)275 BOOL MADB_ProcessIndicator(MADB_Stmt *Stmt, SQLLEN Indicator, char * DefaultValue, MYSQL_BIND *MaBind)
276 {
277 switch (Indicator)
278 {
279 case SQL_COLUMN_IGNORE:
280 if (DefaultValue == NULL)
281 {
282 MADB_ConvertNullValue(Stmt, MaBind);
283 }
284 else
285 {
286 MaBind->buffer= DefaultValue;
287 MaBind->buffer_length= (unsigned long)strlen(DefaultValue);
288 MaBind->buffer_type= MYSQL_TYPE_STRING;
289 }
290 return TRUE;
291 case SQL_NULL_DATA:
292 MADB_ConvertNullValue(Stmt, MaBind);
293 return TRUE;
294 }
295
296 return FALSE;
297 }
298 /* }}} */
299
300 /* {{{ MADB_CalculateLength */
MADB_CalculateLength(MADB_Stmt * Stmt,SQLLEN * OctetLengthPtr,MADB_DescRecord * CRec,void * DataPtr)301 SQLLEN MADB_CalculateLength(MADB_Stmt *Stmt, SQLLEN *OctetLengthPtr, MADB_DescRecord *CRec, void* DataPtr)
302 {
303 /* If no OctetLengthPtr was specified, or OctetLengthPtr is SQL_NTS character
304 are considered to be NULL binary data are null terminated */
305 if (!OctetLengthPtr || *OctetLengthPtr == SQL_NTS)
306 {
307 /* Meaning of Buffer Length is not quite clear in specs. Thus we treat in the way, that does not break
308 (old) testcases. i.e. we neglect its value if Length Ptr is specified */
309 SQLLEN BufferLen= OctetLengthPtr ? -1 : CRec->OctetLength;
310
311 switch (CRec->ConciseType)
312 {
313 case SQL_C_WCHAR:
314 /* CRec->OctetLength eq 0 means not 0-length buffer, but that this value is not specified. Thus -1, for SqlwcsLen
315 and SafeStrlen that means buffer len is not specified */
316 return SqlwcsLen((SQLWCHAR *)DataPtr, BufferLen/sizeof(SQLWCHAR) - test(BufferLen == 0)) * sizeof(SQLWCHAR);
317 break;
318 case SQL_C_BINARY:
319 case SQL_VARBINARY:
320 case SQL_LONGVARBINARY:
321 case SQL_C_CHAR:
322 return SafeStrlen((SQLCHAR *)DataPtr, BufferLen != 0 ? BufferLen : -1);
323 }
324 }
325 else
326 {
327 return *OctetLengthPtr;
328 }
329
330 return CRec->OctetLength;
331 }
332 /* }}} */
333
334 /* {{{ MADB_GetBufferForSqlValue */
MADB_GetBufferForSqlValue(MADB_Stmt * Stmt,MADB_DescRecord * CRec,size_t Size)335 void* MADB_GetBufferForSqlValue(MADB_Stmt *Stmt, MADB_DescRecord *CRec, size_t Size)
336 {
337 if (Stmt->RebindParams || CRec->InternalBuffer == NULL)
338 {
339 MADB_FREE(CRec->InternalBuffer);
340 CRec->InternalBuffer= MADB_CALLOC(Size);
341 if (CRec->InternalBuffer == NULL)
342 {
343 MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
344 return NULL;
345 }
346 }
347
348 return (void *)CRec->InternalBuffer;
349 }
350 /* }}} */
351
352 /* {{{ MADB_Wchar2Sql */
MADB_Wchar2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)353 SQLRETURN MADB_Wchar2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
354 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
355 {
356 SQLULEN mbLength=0;
357
358 MADB_FREE(CRec->InternalBuffer);
359
360 /* conn cs ? */
361 CRec->InternalBuffer= MADB_ConvertFromWChar((SQLWCHAR *)DataPtr, (SQLINTEGER)(Length / sizeof(SQLWCHAR)),
362 &mbLength, &Stmt->Connection->Charset, NULL);
363
364 if (CRec->InternalBuffer == NULL)
365 {
366 return MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
367 }
368
369 *LengthPtr= (unsigned long)mbLength;
370 *Buffer= CRec->InternalBuffer;
371
372 MaBind->buffer_type= MYSQL_TYPE_STRING;
373
374 return SQL_SUCCESS;
375 }
376 /* }}} */
377
378 /* {{{ MADB_Char2Sql */
MADB_Char2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)379 SQLRETURN MADB_Char2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
380 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
381 {
382 switch (SqlRec->Type)
383 {
384 case SQL_BIT:
385 if (*Buffer == NULL)
386 {
387 CRec->InternalBuffer= (char *)MADB_GetBufferForSqlValue(Stmt, CRec, MaBind->buffer_length);
388
389 if (CRec->InternalBuffer == NULL)
390 {
391 return Stmt->Error.ReturnValue;
392 }
393 *Buffer= CRec->InternalBuffer;
394 }
395
396 *LengthPtr= 1;
397 **(char**)Buffer= MADB_ConvertCharToBit(Stmt, DataPtr);
398 MaBind->buffer_type= MYSQL_TYPE_TINY;
399 break;
400 case SQL_DATETIME:
401 {
402 MYSQL_TIME Tm;
403 SQL_TIMESTAMP_STRUCT Ts;
404 BOOL isTime;
405
406 /* Enforcing constraints on date/time values */
407 RETURN_ERROR_OR_CONTINUE(MADB_Str2Ts(DataPtr, Length, &Tm, FALSE, &Stmt->Error, &isTime));
408 MADB_CopyMadbTimeToOdbcTs(&Tm, &Ts);
409 RETURN_ERROR_OR_CONTINUE(MADB_TsConversionIsPossible(&Ts, SqlRec->ConciseType, &Stmt->Error, MADB_ERR_22018, isTime));
410 /* To stay on the safe side - still sending as string in the default branch */
411 }
412 default:
413 /* Bulk shouldn't get here, thus logic for single paramset execution */
414 *LengthPtr= (unsigned long)Length;
415 *Buffer= DataPtr;
416 MaBind->buffer_type= MYSQL_TYPE_STRING;
417 }
418
419 return SQL_SUCCESS;
420 }
421 /* }}} */
422
423 /* {{{ MADB_Numeric2Sql */
MADB_Numeric2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)424 SQLRETURN MADB_Numeric2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
425 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
426 {
427 SQL_NUMERIC_STRUCT *p;
428 int ErrorCode= 0;
429
430 /* We might need to preserve this pointer to be able to later release the memory */
431 CRec->InternalBuffer= (char *)MADB_GetBufferForSqlValue(Stmt, CRec, MADB_CHARSIZE_FOR_NUMERIC);
432
433 if (CRec->InternalBuffer == NULL)
434 {
435 return Stmt->Error.ReturnValue;
436 }
437
438 p= (SQL_NUMERIC_STRUCT *)DataPtr;
439 p->scale= (SQLSCHAR)SqlRec->Scale;
440 p->precision= (SQLSCHAR)SqlRec->Precision;
441
442 *LengthPtr= (unsigned long)MADB_ConvertNumericToChar((SQL_NUMERIC_STRUCT *)p, CRec->InternalBuffer, &ErrorCode);;
443 *Buffer= CRec->InternalBuffer;
444
445 MaBind->buffer_type= MYSQL_TYPE_STRING;
446
447 if (ErrorCode)
448 {
449 /*TODO: I guess this parameters row should be skipped */
450 return MADB_SetError(&Stmt->Error, ErrorCode, NULL, 0);
451 }
452
453 return SQL_SUCCESS;
454 }
455 /* }}} */
456
457 /* {{{ MADB_TsConversionIsPossible */
MADB_TsConversionIsPossible(SQL_TIMESTAMP_STRUCT * ts,SQLSMALLINT SqlType,MADB_Error * Error,enum enum_madb_error SqlState,int isTime)458 SQLRETURN MADB_TsConversionIsPossible(SQL_TIMESTAMP_STRUCT *ts, SQLSMALLINT SqlType, MADB_Error *Error, enum enum_madb_error SqlState, int isTime)
459 {
460 /* I think instead of MADB_ERR_22008 there should be also SqlState */
461 switch (SqlType)
462 {
463 case SQL_TIME:
464 case SQL_TYPE_TIME:
465 if (ts->fraction)
466 {
467 return MADB_SetError(Error, MADB_ERR_22008, NULL, 0);
468 }
469 break;
470 case SQL_DATE:
471 case SQL_TYPE_DATE:
472 if (ts->hour + ts->minute + ts->second + ts->fraction)
473 {
474 return MADB_SetError(Error, MADB_ERR_22008, NULL, 0);
475 }
476 default:
477 /* This only would be good for SQL_TYPE_TIME. If C type is time(isTime!=0), and SQL type is timestamp, date fields may be NULL - driver should set them to current date */
478 if ((isTime == 0 && ts->year == 0) || ts->month == 0 || ts->day == 0)
479 {
480 return MADB_SetError(Error, SqlState, NULL, 0);
481 }
482 }
483 return SQL_SUCCESS;
484 }
485 /* }}} */
486
487 /* {{{ MADB_Timestamp2Sql */
MADB_Timestamp2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)488 SQLRETURN MADB_Timestamp2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
489 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
490 {
491 MYSQL_TIME *tm= NULL;
492 SQL_TIMESTAMP_STRUCT *ts= (SQL_TIMESTAMP_STRUCT *)DataPtr;
493
494 RETURN_ERROR_OR_CONTINUE(MADB_TsConversionIsPossible(ts, SqlRec->ConciseType, &Stmt->Error, MADB_ERR_22007, 0));
495
496 if (*Buffer == NULL)
497 {
498 tm= (MYSQL_TIME*)MADB_GetBufferForSqlValue(Stmt, CRec, sizeof(MYSQL_TIME));
499 if (tm == NULL)
500 {
501 /* Error is set in function responsible for allocation */
502 return Stmt->Error.ReturnValue;
503 }
504 *Buffer= tm;
505 }
506 else
507 {
508 tm= *Buffer;
509 }
510
511
512 /* Default types. Not quite clear if time_type has any effect */
513 tm->time_type= MYSQL_TIMESTAMP_DATETIME;
514 MaBind->buffer_type= MYSQL_TYPE_TIMESTAMP;
515
516 switch (SqlRec->ConciseType) {
517 case SQL_TYPE_DATE:
518 if (ts->hour + ts->minute + ts->second + ts->fraction != 0)
519 {
520 return MADB_SetError(&Stmt->Error, MADB_ERR_22008, "Time fields are nonzero", 0);
521 }
522
523 MaBind->buffer_type= MYSQL_TYPE_DATE;
524 tm->time_type= MYSQL_TIMESTAMP_DATE;
525 tm->year= ts->year;
526 tm->month= ts->month;
527 tm->day= ts->day;
528 break;
529 case SQL_TYPE_TIME:
530 if (ts->fraction != 0)
531 {
532 return MADB_SetError(&Stmt->Error, MADB_ERR_22008, "Fractional seconds fields are nonzero", 0);
533 }
534
535 if (!VALID_TIME(ts))
536 {
537 return MADB_SetError(&Stmt->Error, MADB_ERR_22007, "Invalid time", 0);
538 }
539 MaBind->buffer_type= MYSQL_TYPE_TIME;
540 tm->time_type= MYSQL_TIMESTAMP_TIME;
541 tm->hour= ts->hour;
542 tm->minute= ts->minute;
543 tm->second= ts->second;
544 break;
545 default:
546 MADB_CopyOdbcTsToMadbTime(ts, tm);
547 }
548
549 *LengthPtr= sizeof(MYSQL_TIME);
550
551 return SQL_SUCCESS;
552 }
553 /* }}} */
554
555 /* {{{ MADB_Time2Sql */
MADB_Time2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)556 SQLRETURN MADB_Time2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
557 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
558 {
559 MYSQL_TIME *tm= NULL;
560 SQL_TIME_STRUCT *ts= (SQL_TIME_STRUCT *)DataPtr;
561
562 if ((SqlRec->ConciseType == SQL_TYPE_TIME || SqlRec->ConciseType == SQL_TYPE_TIMESTAMP ||
563 SqlRec->ConciseType == SQL_TIME || SqlRec->ConciseType == SQL_TIMESTAMP || SqlRec->ConciseType == SQL_DATETIME) &&
564 !VALID_TIME(ts))
565 {
566 return MADB_SetError(&Stmt->Error, MADB_ERR_22007, NULL, 0);
567 }
568
569 if (*Buffer == NULL)
570 {
571 tm= (MYSQL_TIME*)MADB_GetBufferForSqlValue(Stmt, CRec, sizeof(MYSQL_TIME));
572 if (tm == NULL)
573 {
574 /* Error is set in function responsible for allocation */
575 return Stmt->Error.ReturnValue;
576 }
577 *Buffer= tm;
578 }
579 else
580 {
581 tm= *Buffer;
582 }
583
584 if(SqlRec->ConciseType == SQL_TYPE_TIMESTAMP ||
585 SqlRec->ConciseType == SQL_TIMESTAMP || SqlRec->ConciseType == SQL_DATETIME)
586 {
587 time_t sec_time;
588 struct tm * cur_tm;
589
590 sec_time= time(NULL);
591 cur_tm= localtime(&sec_time);
592
593 tm->year= 1900 + cur_tm->tm_year;
594 tm->month= cur_tm->tm_mon + 1;
595 tm->day= cur_tm->tm_mday;
596 tm->second_part= 0;
597
598 tm->time_type= MYSQL_TIMESTAMP_DATETIME;
599 MaBind->buffer_type= MYSQL_TYPE_TIMESTAMP;
600 }
601 else
602 {
603 tm->year= 0;
604 tm->month= 0;
605 tm->day= 0;
606
607 tm->time_type = MYSQL_TIMESTAMP_TIME;
608 MaBind->buffer_type= MYSQL_TYPE_TIME;
609 }
610
611 tm->hour= ts->hour;
612 tm->minute= ts->minute;
613 tm->second= ts->second;
614
615 tm->second_part= 0;
616
617 *LengthPtr= sizeof(MYSQL_TIME);
618
619 return SQL_SUCCESS;
620 }
621 /* }}} */
622
623 /* {{{ MADB_IntervalHtoMS2Sql */
MADB_IntervalHtoMS2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)624 SQLRETURN MADB_IntervalHtoMS2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
625 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
626 {
627 MYSQL_TIME *tm= NULL;
628 SQL_INTERVAL_STRUCT *is= (SQL_INTERVAL_STRUCT *)DataPtr;
629
630 if (*Buffer == NULL)
631 {
632 tm= (MYSQL_TIME*)MADB_GetBufferForSqlValue(Stmt, CRec, sizeof(MYSQL_TIME));
633 if (tm == NULL)
634 {
635 /* Error is set in function responsible for allocation */
636 return Stmt->Error.ReturnValue;
637 }
638 *Buffer= tm;
639 }
640 else
641 {
642 tm= *Buffer;
643 }
644
645 tm->hour= is->intval.day_second.hour;
646 tm->minute= is->intval.day_second.minute;
647 tm->second= CRec->ConciseType == SQL_C_INTERVAL_HOUR_TO_SECOND ? is->intval.day_second.second : 0;
648
649 tm->second_part= 0;
650
651 tm->time_type= MYSQL_TIMESTAMP_TIME;
652 MaBind->buffer_type= MYSQL_TYPE_TIME;
653 *LengthPtr= sizeof(MYSQL_TIME);
654
655 return SQL_SUCCESS;
656 }
657 /* }}} */
658
659 /* {{{ MADB_Date2Sql */
MADB_Date2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)660 SQLRETURN MADB_Date2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
661 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
662 {
663 MYSQL_TIME *tm= NULL, **BuffPtr= (MYSQL_TIME**)Buffer;
664 SQL_DATE_STRUCT *ts= (SQL_DATE_STRUCT *)DataPtr;
665
666 if (*BuffPtr == NULL)
667 {
668 tm= (MYSQL_TIME*)MADB_GetBufferForSqlValue(Stmt, CRec, sizeof(MYSQL_TIME));
669 if (tm == NULL)
670 {
671 /* Error is set in function responsible for allocation */
672 return Stmt->Error.ReturnValue;
673 }
674 *BuffPtr= tm;
675 }
676 else
677 {
678 tm= *BuffPtr;
679 }
680
681 tm->year= ts->year;
682 tm->month= ts->month;
683 tm->day= ts->day;
684
685 tm->hour= tm->minute= tm->second= tm->second_part= 0;
686 tm->time_type= MYSQL_TIMESTAMP_DATE;
687
688 MaBind->buffer_type= MYSQL_TYPE_DATE;
689 *LengthPtr= sizeof(MYSQL_TIME);
690
691 return SQL_SUCCESS;
692 }
693 /* }}} */
694
695 /* {{{ MADB_ConvertC2Sql */
MADB_ConvertC2Sql(MADB_Stmt * Stmt,MADB_DescRecord * CRec,void * DataPtr,SQLLEN Length,MADB_DescRecord * SqlRec,MYSQL_BIND * MaBind,void ** Buffer,unsigned long * LengthPtr)696 SQLRETURN MADB_ConvertC2Sql(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void* DataPtr, SQLLEN Length,
697 MADB_DescRecord *SqlRec, MYSQL_BIND *MaBind, void **Buffer, unsigned long *LengthPtr)
698 {
699 if (Buffer == NULL)
700 {
701 MaBind->buffer= NULL;
702 Buffer= &MaBind->buffer;
703 }
704 if (LengthPtr == NULL)
705 {
706 LengthPtr= &MaBind->buffer_length;
707 }
708 /* Switch to fill BIND structures based on C and SQL type */
709 switch (CRec->ConciseType)
710 {
711 case WCHAR_TYPES:
712 RETURN_ERROR_OR_CONTINUE(MADB_Wchar2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
713 break;
714 case CHAR_BINARY_TYPES:
715 RETURN_ERROR_OR_CONTINUE(MADB_Char2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
716 break;
717 case SQL_C_NUMERIC:
718 RETURN_ERROR_OR_CONTINUE(MADB_Numeric2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
719 break;
720 case SQL_C_TIMESTAMP:
721 case SQL_TYPE_TIMESTAMP:
722 RETURN_ERROR_OR_CONTINUE(MADB_Timestamp2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
723 break;
724 case SQL_C_TIME:
725 case SQL_C_TYPE_TIME:
726 RETURN_ERROR_OR_CONTINUE(MADB_Time2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
727 break;
728 case SQL_C_INTERVAL_HOUR_TO_MINUTE:
729 case SQL_C_INTERVAL_HOUR_TO_SECOND:
730 RETURN_ERROR_OR_CONTINUE(MADB_IntervalHtoMS2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
731 break;
732 case SQL_C_DATE:
733 case SQL_TYPE_DATE:
734 RETURN_ERROR_OR_CONTINUE(MADB_Date2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, Buffer, LengthPtr));
735 break;
736 default:
737 /* memset(MaBind, 0, sizeof(MYSQL_BIND));
738 MaBind->buffer_length= 0; */
739 MaBind->buffer_type= 0;
740 MaBind->is_unsigned= 0;
741
742 *LengthPtr= (unsigned long)Length;
743 MaBind->buffer_type= MADB_GetMaDBTypeAndLength(CRec->ConciseType,
744 &MaBind->is_unsigned, &MaBind->buffer_length);
745
746 if (!CRec->OctetLength)
747 {
748 CRec->OctetLength= MaBind->buffer_length;
749 }
750 *Buffer= DataPtr;
751 } /* End of switch (CRec->ConsiseType) */
752 /* We need it in case SQL_SUCCESS_WITH_INFO was set, we can't just return SQL_SUCCESS */
753 return Stmt->Error.ReturnValue;
754 }
755 /* }}} */
756
757 /* {{{ MADB_C2SQL */
758 /* Main entrance function for C type to SQL type conversion*/
MADB_C2SQL(MADB_Stmt * Stmt,MADB_DescRecord * CRec,MADB_DescRecord * SqlRec,SQLULEN ParamSetIdx,MYSQL_BIND * MaBind)759 SQLRETURN MADB_C2SQL(MADB_Stmt* Stmt, MADB_DescRecord *CRec, MADB_DescRecord *SqlRec, SQLULEN ParamSetIdx, MYSQL_BIND *MaBind)
760 {
761 SQLLEN *IndicatorPtr= NULL;
762 SQLLEN *OctetLengthPtr= NULL;
763 void *DataPtr= NULL;
764 SQLLEN Length= 0;
765
766 IndicatorPtr= (SQLLEN *)GetBindOffset(Stmt->Apd, CRec, CRec->IndicatorPtr, ParamSetIdx, sizeof(SQLLEN));
767 OctetLengthPtr= (SQLLEN *)GetBindOffset(Stmt->Apd, CRec, CRec->OctetLengthPtr, ParamSetIdx, sizeof(SQLLEN));
768
769 if (PARAM_IS_DAE(OctetLengthPtr))
770 {
771 if (!DAE_DONE(Stmt))
772 {
773 return SQL_NEED_DATA;
774 }
775 else
776 {
777 MaBind->buffer_type= MADB_GetMaDBTypeAndLength(CRec->ConciseType, &MaBind->is_unsigned, &MaBind->buffer_length);
778 /* I guess we can leave w/out this. Keeping it so far for safety */
779 MaBind->long_data_used= '\1';
780 return SQL_SUCCESS;
781 }
782 } /* -- End of DAE parameter processing -- */
783
784 if (IndicatorPtr && MADB_ProcessIndicator(Stmt, *IndicatorPtr, CRec->DefaultValue, MaBind))
785 {
786 return SQL_SUCCESS;
787 }
788
789 /* -- Special cases are done, i.e. not a DAE etc, general case -- */
790
791 DataPtr= GetBindOffset(Stmt->Apd, CRec, CRec->DataPtr, ParamSetIdx, CRec->OctetLength);
792
793 /* If indicator wasn't NULL_DATA, but data pointer is still NULL, we convert NULL value */
794 if (!DataPtr)
795 {
796 return MADB_ConvertNullValue(Stmt, MaBind);
797 }
798
799 Length= MADB_CalculateLength(Stmt, OctetLengthPtr, CRec, DataPtr);
800
801 RETURN_ERROR_OR_CONTINUE(MADB_ConvertC2Sql(Stmt, CRec, DataPtr, Length, SqlRec, MaBind, NULL, NULL));
802 /* We need it in case SUCCESS_WITH_INFO was set */
803 return Stmt->Error.ReturnValue;
804 }
805 /* }}} */
806