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