LCOV - code coverage report
Current view: top level - clients/odbc/driver - ODBCConvert.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 619 2318 26.7 %
Date: 2025-03-26 20:06:40 Functions: 9 13 69.2 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024, 2025 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "ODBCGlobal.h"
      14             : #include "ODBCStmt.h"
      15             : #include "ODBCUtil.h"
      16             : #include <time.h>
      17             : #ifdef HAVE_STRINGS_H
      18             : #include <strings.h>              /* for strncasecmp */
      19             : #endif
      20             : #include <float.h>                /* for FLT_MAX */
      21             : 
      22             : #ifdef HAVE_HGE
      23             : #define MAXBIGNUM10     (((uhge) UINT64_C(0x1999999999999999) << 64) | ((uhge) UINT64_C(0x9999999999999999)))
      24             : #define MAXBIGNUMLAST   '5'
      25             : #else
      26             : #define MAXBIGNUM10     (UINT64_MAX / 10)
      27             : #define MAXBIGNUMLAST   ('0' + (int) (UINT64_MAX % 10))
      28             : #endif
      29             : 
      30             : #define space(c)        ((c) == ' ' || (c) == '\t')
      31             : 
      32             : typedef struct {
      33             :         uint8_t precision;      /* total number of digits */
      34             :         int8_t scale;           /* how far to shift decimal point (>
      35             :                                  * 0: shift left, i.e. number has
      36             :                                  * fraction; < 0: shift right,
      37             :                                  * i.e. multiply with power of 10) */
      38             :         uint8_t sign;           /* 1 pos, 0 neg */
      39             : #ifdef HAVE_HGE
      40             :         uhge val;               /* the value (128 bits) */
      41             : #else
      42             :         uint64_t val;           /* the value (64 bits) */
      43             : #endif
      44             : } bignum_t;
      45             : 
      46             : /* Parse a number and store in a bignum_t.
      47             :  * 1 is returned if all is well;
      48             :  * 2 is returned if there is loss of precision (i.e. overflow of the value);
      49             :  * 0 is returned if the string is not a number, or if scale doesn't fit.
      50             :  */
      51             : static int
      52        5255 : parseint(const char *data, bignum_t *nval)
      53             : {
      54        5255 :         int fraction = 0;       /* inside the fractional part */
      55        5255 :         int scale = 0;
      56        5255 :         int overflow = 0;
      57             : 
      58        5255 :         nval->val = 0;
      59        5255 :         nval->precision = 0;
      60        5255 :         scale = 0;
      61        5255 :         while (space(*data))
      62           0 :                 data++;
      63        5255 :         if (*data == '-') {
      64         564 :                 nval->sign = 0;
      65         564 :                 data++;
      66             :         } else {
      67        4691 :                 nval->sign = 1;
      68        4691 :                 if (*data == '+')
      69           0 :                         data++;
      70             :         }
      71       17598 :         while (*data && *data != 'e' && *data != 'E' && !space(*data)) {
      72       12343 :                 if (*data == '.')
      73             :                         fraction = 1;
      74       12303 :                 else if (isdigit((unsigned char) *data)) {
      75       12303 :                         if (overflow ||
      76       12303 :                             nval->val > MAXBIGNUM10 ||
      77           0 :                             (nval->val == MAXBIGNUM10 &&
      78             :                              *data > MAXBIGNUMLAST)) {
      79           0 :                                 overflow = 1;
      80           0 :                                 if (!fraction)
      81           0 :                                         scale--;
      82             :                         } else {
      83       12303 :                                 nval->precision++;
      84       12303 :                                 if (fraction)
      85         149 :                                         scale++;
      86       12303 :                                 nval->val *= 10;
      87       12303 :                                 nval->val += *data - '0';
      88             :                         }
      89             :                 } else
      90             :                         return 0;
      91       12343 :                 data++;
      92             :         }
      93        5255 :         if (*data == 'e' || *data == 'E') {
      94           0 :                 char *p;
      95           0 :                 long i;
      96             : 
      97           0 :                 i = strtol(data, &p, 10);
      98           0 :                 if (p == data || *p)
      99           0 :                         return 0;
     100           0 :                 scale -= i;
     101             :                 /* normalize scale */
     102           0 :                 while (scale > 0 && nval->val % 10 == 0) {
     103           0 :                         scale--;
     104           0 :                         nval->val /= 10;
     105             :                 }
     106           0 :                 while (scale < 0 && nval->val <= MAXBIGNUM10) {
     107           0 :                         scale++;
     108           0 :                         nval->val *= 10;
     109             :                 }
     110             :         }
     111        5255 :         if (scale < -128 || scale > 127)
     112             :                 return 0;
     113        5255 :         nval->scale = scale;
     114        5255 :         while (space(*data))
     115           0 :                 data++;
     116        5255 :         if (*data)
     117             :                 return 0;
     118        5255 :         return 1 + overflow;
     119             : }
     120             : 
     121             : static int
     122          32 : parsesecondinterval(bignum_t *nval, SQL_INTERVAL_STRUCT *ival, int type)
     123             : {
     124          32 :         unsigned int f = 1;
     125          32 :         int ivalscale = 0;
     126             : 
     127             :         /* convert value to second */
     128          32 :         switch (type) {
     129           0 :         case SQL_INTERVAL_DAY:  /* SQL_C_INTERVAL_DAY */
     130           0 :                 nval->val *= 24;
     131             :                 /* fall through */
     132           0 :         case SQL_INTERVAL_HOUR: /* SQL_C_INTERVAL_HOUR */
     133             :         case SQL_INTERVAL_DAY_TO_HOUR: /* SQL_C_INTERVAL_DAY_TO_HOUR */
     134           0 :                 nval->val *= 60;
     135             :                 /* fall through */
     136           0 :         case SQL_INTERVAL_MINUTE: /* SQL_C_INTERVAL_MINUTE */
     137             :         case SQL_INTERVAL_HOUR_TO_MINUTE: /* SQL_C_INTERVAL_HOUR_TO_MINUTE */
     138             :         case SQL_INTERVAL_DAY_TO_MINUTE: /* SQL_C_INTERVAL_DAY_TO_MINUTE */
     139           0 :                 nval->val *= 60;
     140             :                 /* fall through */
     141             :         case SQL_INTERVAL_SECOND: /* SQL_C_INTERVAL_SECOND */
     142             :         case SQL_INTERVAL_MINUTE_TO_SECOND: /* SQL_C_INTERVAL_MINUTE_TO_SECOND */
     143             :         case SQL_INTERVAL_HOUR_TO_SECOND: /* SQL_C_INTERVAL_HOUR_TO_SECOND */
     144             :         case SQL_INTERVAL_DAY_TO_SECOND: /* SQL_C_INTERVAL_DAY_TO_SECOND */
     145          32 :                 break;
     146             :         default:
     147           0 :                 assert(0);
     148             :         }
     149          32 :         ival->intval.day_second.fraction = 0;
     150         128 :         while (nval->scale > 0) {
     151          96 :                 if (f < 1000000000) {
     152          96 :                         ivalscale++;
     153          96 :                         ival->intval.day_second.fraction += (SQLUINTEGER) ((nval->val % 10) * f);
     154          96 :                         f *= 10;
     155             :                 }
     156          96 :                 nval->val /= 10;
     157          96 :                 nval->scale--;
     158             :         }
     159          32 :         ival->interval_type = SQL_IS_DAY_TO_SECOND;
     160          32 :         ival->interval_sign = !nval->sign;
     161          32 :         ival->intval.day_second.second = (SQLUINTEGER) (nval->val % 60);
     162          32 :         nval->val /= 60;
     163          32 :         ival->intval.day_second.minute = (SQLUINTEGER) (nval->val % 60);
     164          32 :         nval->val /= 60;
     165          32 :         ival->intval.day_second.hour = (SQLUINTEGER) (nval->val % 24);
     166          32 :         nval->val /= 24;
     167          32 :         ival->intval.day_second.day = (SQLUINTEGER) nval->val;
     168          32 :         return ivalscale;
     169             : }
     170             : 
     171             : static void
     172           9 : parsemonthinterval(bignum_t *nval, SQL_INTERVAL_STRUCT *ival, int type)
     173             : {
     174             :         /* convert value to months */
     175           9 :         switch (type) {
     176           0 :         case SQL_INTERVAL_YEAR: /* SQL_C_INTERVAL_YEAR */
     177           0 :                 nval->val *= 12;
     178             :         case SQL_INTERVAL_YEAR_TO_MONTH: /* SQL_C_INTERVAL_YEAR_TO_MONTH */
     179             :         case SQL_INTERVAL_MONTH: /* SQL_C_INTERVAL_MONTH */
     180             :                 break;
     181             :         default:
     182           0 :                 assert(0);
     183             :         }
     184             :         /* ignore fraction */
     185           9 :         while (nval->scale > 0) {
     186           0 :                 nval->scale--;
     187           0 :                 nval->val /= 10;
     188             :         }
     189           9 :         ival->interval_type = SQL_IS_YEAR_TO_MONTH;
     190           9 :         ival->interval_sign = !nval->sign;
     191           9 :         ival->intval.year_month.year = (SQLUINTEGER) (nval->val / 12);
     192           9 :         ival->intval.year_month.month = (SQLUINTEGER) (nval->val % 12);
     193           9 : }
     194             : 
     195             : static short monthlengths[] = {
     196             :         0,                      /* dummy */
     197             :         31,                     /* Jan */
     198             :         29,                     /* Feb */
     199             :         31,                     /* Mar */
     200             :         30,                     /* Apr */
     201             :         31,                     /* May */
     202             :         30,                     /* Jun */
     203             :         31,                     /* Jul */
     204             :         31,                     /* Aug */
     205             :         30,                     /* Sep */
     206             :         31,                     /* Oct */
     207             :         30,                     /* Nov */
     208             :         31,                     /* Dec */
     209             : };
     210             : 
     211             : #define isLeap(y)       ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
     212             : 
     213             : static int
     214        2003 : parsedate(const char *data, DATE_STRUCT *dval)
     215             : {
     216        2003 :         int n;
     217             : 
     218        2003 :         *dval = (DATE_STRUCT) {0};
     219        2003 :         while (space(*data))
     220           0 :                 data++;
     221        2003 :         if (sscanf(data, "{d '%hd-%hu-%hu'}%n",
     222        2003 :                    &dval->year, &dval->month, &dval->day, &n) < 3 &&
     223        2003 :             sscanf(data, "%hd-%hu-%hu%n",
     224             :                    &dval->year, &dval->month, &dval->day, &n) < 3)
     225             :                 return 0;
     226        2003 :         if (dval->month == 0 || dval->month > 12 ||
     227        2003 :             dval->day == 0 || dval->day > monthlengths[dval->month] ||
     228         169 :             (dval->month == 2 && !isLeap(dval->year) && dval->day == 29))
     229             :                 return 0;
     230        2003 :         data += n;
     231        2003 :         while (space(*data))
     232           0 :                 data++;
     233        2003 :         if (*data)
     234             :                 return 0;
     235             :         return 1;
     236             : }
     237             : 
     238             : static int
     239        2003 : parsetime(const char *data, TIME_STRUCT *tval)
     240             : {
     241        2003 :         int n;
     242        2003 :         int braces;
     243             : 
     244        2003 :         *tval = (TIME_STRUCT) {0};
     245        2003 :         while (space(*data))
     246           0 :                 data++;
     247        2003 :         if (sscanf(data, "{t '%hu:%hu:%hu%n",
     248        2003 :                    &tval->hour, &tval->minute, &tval->second, &n) < 3 &&
     249        2003 :             sscanf(data, "%hu:%hu:%hu%n",
     250             :                    &tval->hour, &tval->minute, &tval->second, &n) < 3)
     251             :                 return 0;
     252             :         /* seconds can go up to 61(!) because of leap seconds */
     253        2003 :         if (tval->hour > 23 || tval->minute > 59 || tval->second > 61)
     254             :                 return 0;
     255        2003 :         braces = *data == '{';
     256        2003 :         data += n;
     257        2003 :         n = 1;                  /* tentative return value */
     258        2003 :         if (*data == '.') {
     259           0 :                 while (*++data && isdigit((unsigned char) *data))
     260             :                         ;
     261           0 :                 n = 2;          /* indicate loss of precision */
     262             :         }
     263        2003 :         if (*data == '+' || *data == '-') {
     264             :                 /* time zone (which we ignore) */
     265           0 :                 short tzhour, tzmin;
     266           0 :                 int i;
     267             : 
     268           0 :                 if (sscanf(data, "%hd:%hd%n", &tzhour, &tzmin, &i) < 2)
     269           0 :                         return 0;
     270           0 :                 data += i;
     271           0 :                 tzmin = tzhour < 0 ? tzhour * 60 - tzmin : tzhour * 60 + tzmin;
     272           0 :                 (void) tzhour;
     273           0 :                 (void) tzmin;
     274             :         }
     275        2003 :         if (braces && *data++ != '\'' && *data++ != '}')
     276             :                 return 0;
     277        2003 :         while (space(*data))
     278           0 :                 data++;
     279        2003 :         if (*data)
     280             :                 return 0;
     281        2003 :         return n;
     282             : }
     283             : 
     284             : static int
     285           3 : parsetimestamp(const char *data, TIMESTAMP_STRUCT *tsval)
     286             : {
     287           3 :         int n;
     288           3 :         int braces;
     289             : 
     290           3 :         *tsval = (TIMESTAMP_STRUCT) {0};
     291           3 :         while (space(*data))
     292           0 :                 data++;
     293           3 :         if (sscanf(data, "{TS '%hd-%hu-%hu %hu:%hu:%hu%n",
     294             :                    &tsval->year, &tsval->month, &tsval->day,
     295           3 :                    &tsval->hour, &tsval->minute, &tsval->second, &n) < 6 &&
     296           3 :             sscanf(data, "%hd-%hu-%hu %hu:%hu:%hu%n",
     297             :                    &tsval->year, &tsval->month, &tsval->day,
     298             :                    &tsval->hour, &tsval->minute, &tsval->second, &n) < 6)
     299             :                 return 0;
     300           3 :         if (tsval->month == 0 || tsval->month > 12 ||
     301           3 :             tsval->day == 0 || tsval->day > monthlengths[tsval->month] ||
     302           1 :             (tsval->month == 2 && !isLeap(tsval->year) && tsval->day == 29) ||
     303           3 :             tsval->hour > 23 || tsval->minute > 59 || tsval->second > 61)
     304             :                 return 0;
     305           3 :         braces = *data == '{';
     306           3 :         tsval->fraction = 0;
     307           3 :         data += n;
     308           3 :         n = 1000000000;
     309           3 :         if (*data == '.') {
     310          21 :                 while (*++data && isdigit((unsigned char) *data)) {
     311          18 :                         n /= 10;
     312          18 :                         tsval->fraction += (*data - '0') * n;
     313             :                 }
     314             :         }
     315           3 :         if (*data == '+' || *data == '-') {
     316             :                 /* time zone (which we ignore) */
     317           0 :                 short tzhour, tzmin;
     318           0 :                 int i;
     319             : 
     320           0 :                 if (sscanf(data, "%hd:%hd%n", &tzhour, &tzmin, &i) < 2)
     321           0 :                         return 0;
     322           0 :                 data += i;
     323           0 :                 tzmin = tzhour < 0 ? tzhour * 60 - tzmin : tzhour * 60 + tzmin;
     324           0 :                 (void) tzhour;
     325           0 :                 (void) tzmin;
     326             :         }
     327           3 :         if (braces && *data++ != '\'' && *data++ != '}')
     328             :                 return 0;
     329           3 :         while (space(*data))
     330           0 :                 data++;
     331           3 :         if (*data)
     332             :                 return 0;
     333           3 :         if (n == 0)
     334           0 :                 return 2;       /* fractional digits truncated */
     335             :         return 1;
     336             : }
     337             : 
     338             : static int
     339        2006 : parsedouble(const char *data, double *fval)
     340             : {
     341        2006 :         char *p;
     342             : 
     343        2006 :         while (space(*data))
     344           0 :                 data++;
     345        2006 :         errno = 0;
     346        2006 :         *fval = strtod(data, &p);
     347        2006 :         if (p == NULL || p == data || errno == ERANGE)
     348             :                 return 0;
     349        2006 :         while (space(*p))
     350           0 :                 p++;
     351        2006 :         if (*p)
     352             :                 return 0;
     353             :         return 1;
     354             : }
     355             : 
     356             : static SQLSMALLINT
     357           0 : ODBCDefaultType(ODBCDescRec *rec)
     358             : {
     359           0 :         switch (rec->sql_desc_concise_type) {
     360             :         case SQL_CHAR:
     361             :         case SQL_VARCHAR:
     362             :         case SQL_LONGVARCHAR:
     363             :         case SQL_DECIMAL:
     364             :         case SQL_NUMERIC:
     365             :         case SQL_GUID:
     366             :                 return SQL_C_CHAR;
     367           0 :         case SQL_WCHAR:
     368             :         case SQL_WVARCHAR:
     369             :         case SQL_WLONGVARCHAR:
     370           0 :                 return SQL_C_WCHAR;
     371           0 :         case SQL_BIT:
     372           0 :                 return SQL_C_BIT;
     373           0 :         case SQL_TINYINT:
     374           0 :                 return rec->sql_desc_unsigned ? SQL_C_UTINYINT : SQL_C_STINYINT;
     375           0 :         case SQL_SMALLINT:
     376           0 :                 return rec->sql_desc_unsigned ? SQL_C_USHORT : SQL_C_SSHORT;
     377           0 :         case SQL_INTEGER:
     378           0 :                 return rec->sql_desc_unsigned ? SQL_C_ULONG : SQL_C_SLONG;
     379           0 :         case SQL_BIGINT:
     380           0 :                 return rec->sql_desc_unsigned ? SQL_C_UBIGINT : SQL_C_SBIGINT;
     381           0 :         case SQL_HUGEINT:       /* for now, try to treat as BIGINT */
     382           0 :                 return rec->sql_desc_unsigned ? SQL_C_UBIGINT : SQL_C_SBIGINT;
     383           0 :         case SQL_REAL:
     384           0 :                 return SQL_C_FLOAT;
     385           0 :         case SQL_FLOAT:
     386             :         case SQL_DOUBLE:
     387           0 :                 return SQL_C_DOUBLE;
     388           0 :         case SQL_BINARY:
     389             :         case SQL_VARBINARY:
     390             :         case SQL_LONGVARBINARY:
     391           0 :                 return SQL_C_BINARY;
     392           0 :         case SQL_TYPE_DATE:
     393           0 :                 return SQL_C_TYPE_DATE;
     394           0 :         case SQL_TYPE_TIME:
     395           0 :                 return SQL_C_TYPE_TIME;
     396           0 :         case SQL_TYPE_TIMESTAMP:
     397           0 :                 return SQL_C_TYPE_TIMESTAMP;
     398           0 :         case SQL_INTERVAL_YEAR:
     399           0 :                 return SQL_C_INTERVAL_YEAR;
     400           0 :         case SQL_INTERVAL_MONTH:
     401           0 :                 return SQL_C_INTERVAL_MONTH;
     402           0 :         case SQL_INTERVAL_YEAR_TO_MONTH:
     403           0 :                 return SQL_C_INTERVAL_YEAR_TO_MONTH;
     404           0 :         case SQL_INTERVAL_DAY:
     405           0 :                 return SQL_C_INTERVAL_DAY;
     406           0 :         case SQL_INTERVAL_HOUR:
     407           0 :                 return SQL_C_INTERVAL_HOUR;
     408           0 :         case SQL_INTERVAL_MINUTE:
     409           0 :                 return SQL_C_INTERVAL_MINUTE;
     410           0 :         case SQL_INTERVAL_SECOND:
     411           0 :                 return SQL_C_INTERVAL_SECOND;
     412           0 :         case SQL_INTERVAL_DAY_TO_HOUR:
     413           0 :                 return SQL_C_INTERVAL_DAY_TO_HOUR;
     414           0 :         case SQL_INTERVAL_DAY_TO_MINUTE:
     415           0 :                 return SQL_C_INTERVAL_DAY_TO_MINUTE;
     416           0 :         case SQL_INTERVAL_DAY_TO_SECOND:
     417           0 :                 return SQL_C_INTERVAL_DAY_TO_SECOND;
     418           0 :         case SQL_INTERVAL_HOUR_TO_MINUTE:
     419           0 :                 return SQL_C_INTERVAL_HOUR_TO_MINUTE;
     420           0 :         case SQL_INTERVAL_HOUR_TO_SECOND:
     421           0 :                 return SQL_C_INTERVAL_HOUR_TO_SECOND;
     422           0 :         case SQL_INTERVAL_MINUTE_TO_SECOND:
     423           0 :                 return SQL_C_INTERVAL_MINUTE_TO_SECOND;
     424             :         }
     425           0 :         return 0;
     426             : }
     427             : 
     428             : static SQLRETURN
     429           0 : parseoptionalbracketednumber(char **svalp,
     430             :                              SQLLEN *slenp,
     431             :                              int *val1p,
     432             :                              int *val2p)
     433             : {
     434           0 :         char *sval = *svalp;
     435           0 :         SQLLEN slen = *slenp;
     436           0 :         char *eptr;
     437           0 :         long val;
     438             : 
     439           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     440           0 :                 slen--;
     441           0 :                 sval++;
     442             :         }
     443           0 :         if (slen == 0 || *sval != '(') {
     444             :                 /* don't touch *valp, it contains the default */
     445             :                 return SQL_SUCCESS;
     446             :         }
     447           0 :         slen--;
     448           0 :         sval++;
     449           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     450           0 :                 slen--;
     451           0 :                 sval++;
     452             :         }
     453             :         /* make sure there is a closing parenthesis in the string:
     454             :          * this makes the calls to strtol safe */
     455             :         {
     456           0 :                 SQLLEN i;
     457             : 
     458           0 :                 for (eptr = sval, i = slen; i > 0 && *eptr != ')'; i--, eptr++)
     459             :                         ;
     460           0 :                 if (i == 0)
     461             :                         return SQL_ERROR;
     462             :         }
     463           0 :         if (slen > 0 && (*sval == '+' || *sval == '-'))
     464             :                 return SQL_ERROR;
     465           0 :         val = strtol(sval, &eptr, 10);
     466           0 :         if (eptr == sval)
     467             :                 return SQL_ERROR;
     468           0 :         slen -= (int) (eptr - sval);
     469           0 :         sval = eptr;
     470           0 :         *val1p = (int) val;
     471           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     472           0 :                 slen--;
     473           0 :                 sval++;
     474             :         }
     475           0 :         if (val2p != NULL && slen > 0 && *sval == ',') {
     476           0 :                 slen--;
     477           0 :                 sval++;
     478           0 :                 while (slen > 0 && isspace((unsigned char) *sval)) {
     479           0 :                         slen--;
     480           0 :                         sval++;
     481             :                 }
     482           0 :                 if (slen > 0 && (*sval == '+' || *sval == '-'))
     483             :                         return SQL_ERROR;
     484           0 :                 val = strtol(sval, &eptr, 10);
     485           0 :                 if (eptr == sval)
     486             :                         return SQL_ERROR;
     487           0 :                 slen -= (int) (eptr - sval);
     488           0 :                 sval = eptr;
     489           0 :                 *val2p = (int) val;
     490             :         }
     491             : 
     492           0 :         if (slen == 0 || *sval != ')')
     493             :                 return SQL_ERROR;
     494           0 :         slen--;
     495           0 :         sval++;
     496           0 :         *svalp = sval;
     497           0 :         *slenp = slen;
     498           0 :         return SQL_SUCCESS;
     499             : }
     500             : 
     501             : static SQLRETURN
     502           0 : parsemonthintervalstring(char **svalp,
     503             :                          SQLLEN *slenp,
     504             :                          SQL_INTERVAL_STRUCT *ival)
     505             : {
     506           0 :         char *sval = *svalp;
     507           0 :         SQLLEN slen = slenp ? *slenp : (SQLLEN) strlen(sval);
     508           0 :         char *eptr;
     509           0 :         long val1 = -1, val2 = -1;
     510           0 :         SQLLEN leadingprecision;
     511             : 
     512           0 :         *ival = (SQL_INTERVAL_STRUCT) {
     513             :                 .interval_type = SQL_IS_YEAR, /* anything will do */
     514             :         };
     515           0 :         if (slen < 8 || strncasecmp(sval, "interval", 8) != 0)
     516             :                 return SQL_ERROR;
     517           0 :         sval += 8;
     518           0 :         slen -= 8;
     519           0 :         if (slen == 0 || !isspace((unsigned char) *sval))
     520             :                 return SQL_ERROR;
     521           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     522           0 :                 slen--;
     523           0 :                 sval++;
     524             :         }
     525           0 :         if (slen > 0 && *sval == '-') {
     526           0 :                 slen--;
     527           0 :                 sval++;
     528           0 :                 ival->interval_sign = SQL_TRUE;
     529             :         } else
     530             :                 ival->interval_sign = SQL_FALSE;
     531           0 :         if (slen == 0 || *sval != '\'')
     532             :                 return SQL_ERROR;
     533           0 :         slen--;
     534           0 :         sval++;
     535             :         /* make sure there is another quote in the string: this makes
     536             :          * the calls to strtol safe */
     537           0 :         for (eptr = sval, leadingprecision = slen;
     538           0 :              leadingprecision > 0 && *eptr != '\'';
     539           0 :              leadingprecision--, eptr++)
     540             :                 ;
     541           0 :         if (leadingprecision == 0)
     542             :                 return SQL_ERROR;
     543           0 :         if (*sval == '+' || *sval == '-')
     544             :                 return SQL_ERROR;
     545           0 :         val1 = strtol(sval, &eptr, 10);
     546           0 :         if (eptr == sval)
     547             :                 return SQL_ERROR;
     548           0 :         leadingprecision = (SQLLEN) (eptr - sval);
     549           0 :         slen -= leadingprecision;
     550           0 :         sval = eptr;
     551           0 :         while (isspace((unsigned char) *sval)) {
     552           0 :                 slen--;
     553           0 :                 sval++;
     554             :         }
     555           0 :         if (*sval == '-') {
     556           0 :                 slen--;
     557           0 :                 sval++;
     558           0 :                 while (isspace((unsigned char) *sval)) {
     559           0 :                         slen--;
     560           0 :                         sval++;
     561             :                 }
     562           0 :                 if (*sval == '+' || *sval == '-')
     563             :                         return SQL_ERROR;
     564           0 :                 val2 = strtol(sval, &eptr, 10);
     565           0 :                 if (eptr == sval)
     566             :                         return SQL_ERROR;
     567           0 :                 if (eptr - sval > 2)
     568             :                         return SQL_ERROR;
     569           0 :                 slen -= (int) (eptr - sval);
     570           0 :                 sval = eptr;
     571           0 :                 while (isspace((unsigned char) *sval)) {
     572           0 :                         slen--;
     573           0 :                         sval++;
     574             :                 }
     575           0 :                 if (val2 >= 12)
     576             :                         return SQL_ERROR;
     577             :         }
     578           0 :         if (*sval != '\'')
     579             :                 return SQL_ERROR;
     580           0 :         slen--;
     581           0 :         sval++;
     582           0 :         if (slen == 0 || !isspace((unsigned char) *sval))
     583             :                 return SQL_ERROR;
     584           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     585           0 :                 slen--;
     586           0 :                 sval++;
     587             :         }
     588           0 :         if (slen >= 4 && strncasecmp(sval, "year", 4) == 0) {
     589           0 :                 int p = 2;
     590             : 
     591           0 :                 slen -= 4;
     592           0 :                 sval += 4;
     593           0 :                 if (parseoptionalbracketednumber(&sval, &slen, &p, NULL) == SQL_ERROR)
     594           0 :                         return SQL_ERROR;
     595           0 :                 if (leadingprecision > p)
     596             :                         return SQL_ERROR;
     597           0 :                 ival->intval.year_month.year = val1;
     598           0 :                 if (val2 == -1) {
     599           0 :                         ival->interval_type = SQL_IS_YEAR;
     600           0 :                         ival->intval.year_month.month = 0;
     601             :                 } else {
     602           0 :                         ival->interval_type = SQL_IS_YEAR_TO_MONTH;
     603           0 :                         ival->intval.year_month.month = val2;
     604             :                 }
     605           0 :                 if (slen > 0 && isspace((unsigned char) *sval)) {
     606           0 :                         while (slen > 0 && isspace((unsigned char) *sval)) {
     607           0 :                                 slen--;
     608           0 :                                 sval++;
     609             :                         }
     610           0 :                         if (slen > 2 && strncasecmp(sval, "to", 2) == 0) {
     611           0 :                                 slen -= 2;
     612           0 :                                 sval += 2;
     613           0 :                                 if (val2 == -1)
     614             :                                         return SQL_ERROR;
     615           0 :                                 if (slen == 0 || !isspace((unsigned char) *sval))
     616             :                                         return SQL_ERROR;
     617           0 :                                 while (slen > 0 && isspace((unsigned char) *sval)) {
     618           0 :                                         slen--;
     619           0 :                                         sval++;
     620             :                                 }
     621           0 :                                 if (slen >= 5 && strncasecmp(sval, "month", 5) == 0) {
     622           0 :                                         slen -= 5;
     623           0 :                                         sval += 5;
     624           0 :                                         while (slen > 0 && isspace((unsigned char) *sval)) {
     625           0 :                                                 slen--;
     626           0 :                                                 sval++;
     627             :                                         }
     628             :                                 } else
     629             :                                         return SQL_ERROR;
     630             :                         }
     631             :                 }
     632           0 :                 if (slen > 0)
     633             :                         return SQL_ERROR;
     634           0 :         } else if (slen >= 5 && strncasecmp(sval, "month", 5) == 0) {
     635           0 :                 int p = 2;
     636             : 
     637           0 :                 slen -= 5;
     638           0 :                 sval += 5;
     639           0 :                 if (parseoptionalbracketednumber(&sval, &slen, &p, NULL) == SQL_ERROR)
     640           0 :                         return SQL_ERROR;
     641           0 :                 if (leadingprecision > p)
     642             :                         return SQL_ERROR;
     643           0 :                 while (slen > 0 && isspace((unsigned char) *sval)) {
     644           0 :                         slen--;
     645           0 :                         sval++;
     646             :                 }
     647           0 :                 if (slen != 0)
     648             :                         return SQL_ERROR;
     649           0 :                 ival->interval_type = SQL_IS_MONTH;
     650           0 :                 ival->intval.year_month.year = val1 / 12;
     651           0 :                 ival->intval.year_month.month = val1 % 12;
     652             :         } else
     653             :                 return SQL_ERROR;
     654             : 
     655             :         return SQL_SUCCESS;
     656             : }
     657             : 
     658             : static SQLRETURN
     659           0 : parsesecondintervalstring(char **svalp,
     660             :                           SQLLEN *slenp,
     661             :                           SQL_INTERVAL_STRUCT *ival,
     662             :                           int *secprecp)
     663             : {
     664           0 :         char *sval = *svalp;
     665           0 :         SQLLEN slen = slenp ? *slenp : (SQLLEN) strlen(sval);
     666           0 :         char *eptr;
     667           0 :         SQLLEN leadingprecision;
     668           0 :         int secondprecision = 0;
     669           0 :         unsigned v1, v2, v3, v4;
     670           0 :         int n;
     671             : 
     672           0 :         *ival = (SQL_INTERVAL_STRUCT) {
     673             :                 .interval_type = SQL_IS_YEAR, /* anything will do */
     674             :         };
     675           0 :         if (slen < 8 || strncasecmp(sval, "interval", 8) != 0)
     676             :                 return SQL_ERROR;
     677           0 :         sval += 8;
     678           0 :         slen -= 8;
     679           0 :         if (slen == 0 || !isspace((unsigned char) *sval))
     680             :                 return SQL_ERROR;
     681           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     682           0 :                 slen--;
     683           0 :                 sval++;
     684             :         }
     685           0 :         if (slen > 0 && *sval == '-') {
     686           0 :                 slen--;
     687           0 :                 sval++;
     688           0 :                 ival->interval_sign = SQL_TRUE;
     689             :         } else
     690             :                 ival->interval_sign = SQL_FALSE;
     691           0 :         if (slen == 0 || *sval != '\'')
     692             :                 return SQL_ERROR;
     693           0 :         slen--;
     694           0 :         sval++;
     695             :         /* make sure there is another quote in the string: this makes
     696             :          * the calls to sscanf safe */
     697           0 :         for (eptr = sval, leadingprecision = slen;
     698           0 :              leadingprecision > 0 && *eptr != '\'';
     699           0 :              leadingprecision--, eptr++)
     700             :                 ;
     701           0 :         if (leadingprecision == 0)
     702             :                 return SQL_ERROR;
     703           0 :         if (*sval == '+' || *sval == '-')
     704             :                 return SQL_ERROR;
     705             :         /* note that the first bit is a bogus comparison (sval does
     706             :          * not start with '-', so is not negative) but this keeps the
     707             :          * compiler happy */
     708           0 :         if (strtol(sval, &eptr, 10) < 0 || /* we parse the actual value again later */
     709           0 :             eptr == sval)
     710             :                 return SQL_ERROR;
     711           0 :         leadingprecision = (int) (eptr - sval);
     712             : 
     713           0 :         ival->interval_type = (SQLINTERVAL)0; /* unknown as yet */
     714           0 :         ival->intval.day_second.day = 0;
     715           0 :         ival->intval.day_second.hour = 0;
     716           0 :         ival->intval.day_second.minute = 0;
     717           0 :         ival->intval.day_second.second = 0;
     718           0 :         ival->intval.day_second.fraction = 0;
     719           0 :         if (sscanf(sval, "%u %2u:%2u:%2u%n", &v1, &v2, &v3, &v4, &n) >= 4) {
     720           0 :                 ival->interval_type = SQL_IS_DAY_TO_SECOND;
     721           0 :                 if (v2 >= 24 || v3 >= 60 || v4 >= 60)
     722             :                         return SQL_ERROR;
     723           0 :                 ival->intval.day_second.day = v1;
     724           0 :                 ival->intval.day_second.hour = v2;
     725           0 :                 ival->intval.day_second.minute = v3;
     726           0 :                 ival->intval.day_second.second = v4;
     727           0 :                 sval += n;
     728           0 :                 slen -= n;
     729           0 :         } else if (sscanf(sval, "%u %2u:%2u%n", &v1, &v2, &v3, &n) >= 3) {
     730           0 :                 ival->interval_type = SQL_IS_DAY_TO_MINUTE;
     731           0 :                 if (v2 >= 24 || v3 >= 60)
     732             :                         return SQL_ERROR;
     733           0 :                 ival->intval.day_second.day = v1;
     734           0 :                 ival->intval.day_second.hour = v2;
     735           0 :                 ival->intval.day_second.minute = v3;
     736           0 :                 sval += n;
     737           0 :                 slen -= n;
     738           0 :         } else if (sscanf(sval, "%u %2u%n", &v1, &v2, &n) >= 2) {
     739           0 :                 ival->interval_type = SQL_IS_DAY_TO_HOUR;
     740           0 :                 if (v2 >= 60)
     741             :                         return SQL_ERROR;
     742           0 :                 ival->intval.day_second.day = v1;
     743           0 :                 ival->intval.day_second.hour = v2;
     744           0 :                 sval += n;
     745           0 :                 slen -= n;
     746           0 :         } else if (sscanf(sval, "%u:%2u:%2u%n", &v1, &v2, &v3, &n) >= 3) {
     747           0 :                 ival->interval_type = SQL_IS_HOUR_TO_SECOND;
     748           0 :                 if (v2 >= 60 || v3 >= 60)
     749             :                         return SQL_ERROR;
     750           0 :                 ival->intval.day_second.day = v1 / 24;
     751           0 :                 ival->intval.day_second.hour = v1 % 24;
     752           0 :                 ival->intval.day_second.minute = v2;
     753           0 :                 ival->intval.day_second.second = v3;
     754           0 :                 sval += n;
     755           0 :                 slen -= n;
     756           0 :         } else if (sscanf(sval, "%u:%2u%n", &v1, &v2, &n) >= 2) {
     757           0 :                 sval += n;
     758           0 :                 slen -= n;
     759           0 :                 if (*sval == '.') {
     760           0 :                         ival->interval_type = SQL_IS_MINUTE_TO_SECOND;
     761           0 :                         if (v2 >= 60)
     762             :                                 return SQL_ERROR;
     763           0 :                         ival->intval.day_second.day = v1 / (24 * 60);
     764           0 :                         ival->intval.day_second.hour = (v1 / 60) % 24;
     765           0 :                         ival->intval.day_second.minute = v1 % 60;
     766           0 :                         ival->intval.day_second.second = v2;
     767             :                 }
     768           0 :                 n = 2;  /* two valid values */
     769           0 :         } else if (sscanf(sval, "%u%n", &v1, &n) >= 1) {
     770           0 :                 sval += n;
     771           0 :                 slen -= n;
     772           0 :                 if (*sval == '.') {
     773           0 :                         ival->interval_type = SQL_IS_SECOND;
     774           0 :                         ival->intval.day_second.day = v1 / (24 * 60 * 60);
     775           0 :                         ival->intval.day_second.hour = (v1 / (60 * 60)) % 24;
     776           0 :                         ival->intval.day_second.minute = (v1 / 60) % 60;
     777           0 :                         ival->intval.day_second.second = v1 % 60;
     778             :                 }
     779           0 :                 n = 1;  /* one valid value */
     780             :         }
     781           0 :         if (*sval == '.') {
     782           0 :                 if (ival->interval_type != SQL_IS_SECOND &&
     783           0 :                     ival->interval_type != SQL_IS_MINUTE_TO_SECOND &&
     784           0 :                     ival->interval_type != SQL_IS_HOUR_TO_SECOND &&
     785             :                     ival->interval_type != SQL_IS_DAY_TO_SECOND)
     786             :                         return SQL_ERROR;
     787           0 :                 sval++;
     788           0 :                 slen--;
     789           0 :                 secondprecision = 0;
     790           0 :                 while (isdigit((unsigned char) *sval)) {
     791           0 :                         if (secondprecision < 9) {
     792           0 :                                 secondprecision++;
     793           0 :                                 ival->intval.day_second.fraction *= 10;
     794           0 :                                 ival->intval.day_second.fraction += *sval - '0';
     795             :                         }
     796           0 :                         sval++;
     797           0 :                         slen--;
     798             :                 }
     799             :         }
     800           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     801           0 :                 slen--;
     802           0 :                 sval++;
     803             :         }
     804           0 :         if (*sval != '\'')
     805             :                 return SQL_ERROR;
     806           0 :         slen--;
     807           0 :         sval++;
     808           0 :         if (slen == 0 || !isspace((unsigned char) *sval))
     809             :                 return SQL_ERROR;
     810           0 :         while (slen > 0 && isspace((unsigned char) *sval)) {
     811           0 :                 slen--;
     812           0 :                 sval++;
     813             :         }
     814             : 
     815           0 :         if (slen >= 3 && strncasecmp(sval, "day", 3) == 0) {
     816           0 :                 sval += 3;
     817           0 :                 slen -= 3;
     818           0 :                 if (ival->interval_type == 0 && n == 1) {
     819           0 :                         ival->interval_type = SQL_IS_DAY;
     820           0 :                         ival->intval.day_second.day = v1;
     821             :                 }
     822           0 :                 if (ival->interval_type != SQL_IS_DAY &&
     823           0 :                     ival->interval_type != SQL_IS_DAY_TO_HOUR &&
     824           0 :                     ival->interval_type != SQL_IS_DAY_TO_MINUTE &&
     825             :                     ival->interval_type != SQL_IS_DAY_TO_SECOND)
     826             :                         return SQL_ERROR;
     827           0 :         } else if (slen >= 4 && strncasecmp(sval, "hour", 4) == 0) {
     828           0 :                 slen -= 4;
     829           0 :                 sval += 4;
     830           0 :                 if (ival->interval_type == 0) {
     831           0 :                         if (n == 1) {
     832           0 :                                 ival->interval_type = SQL_IS_HOUR;
     833           0 :                                 ival->intval.day_second.day = v1 / 24;
     834           0 :                                 ival->intval.day_second.hour = v1 % 24;
     835             :                         } else {
     836           0 :                                 assert(n == 2);
     837           0 :                                 ival->interval_type = SQL_IS_HOUR_TO_MINUTE;
     838           0 :                                 if (v2 >= 60)
     839             :                                         return SQL_ERROR;
     840           0 :                                 ival->intval.day_second.day = v1 / 24;
     841           0 :                                 ival->intval.day_second.hour = v1 % 24;
     842           0 :                                 ival->intval.day_second.minute = v2;
     843             :                         }
     844             :                 }
     845           0 :                 if (ival->interval_type != SQL_IS_HOUR &&
     846           0 :                     ival->interval_type != SQL_IS_HOUR_TO_MINUTE &&
     847             :                     ival->interval_type != SQL_IS_HOUR_TO_SECOND)
     848             :                         return SQL_ERROR;
     849           0 :         } else if (slen >= 6 && strncasecmp(sval, "minute", 6) == 0) {
     850           0 :                 slen -= 6;
     851           0 :                 sval += 6;
     852           0 :                 if (ival->interval_type == 0) {
     853           0 :                         if (n == 1) {
     854           0 :                                 ival->interval_type = SQL_IS_MINUTE;
     855           0 :                                 ival->intval.day_second.day = v1 / (24 * 60);
     856           0 :                                 ival->intval.day_second.hour = (v1 / 60) % 24;
     857           0 :                                 ival->intval.day_second.minute = v1 % 60;
     858             :                         } else {
     859           0 :                                 assert(n == 2);
     860           0 :                                 ival->interval_type = SQL_IS_MINUTE_TO_SECOND;
     861           0 :                                 if (v2 >= 60)
     862             :                                         return SQL_ERROR;
     863           0 :                                 ival->intval.day_second.day = v1 / (24 * 60);
     864           0 :                                 ival->intval.day_second.hour = (v1 / 60) % 24;
     865           0 :                                 ival->intval.day_second.minute = v1 % 60;
     866           0 :                                 ival->intval.day_second.second = v2;
     867             :                         }
     868             :                 }
     869           0 :                 if (ival->interval_type != SQL_IS_MINUTE &&
     870             :                     ival->interval_type != SQL_IS_MINUTE_TO_SECOND)
     871             :                         return SQL_ERROR;
     872           0 :         } else if (slen >= 6 && strncasecmp(sval, "second", 6) == 0) {
     873           0 :                 slen -= 6;
     874           0 :                 sval += 6;
     875           0 :                 if (ival->interval_type == 0) {
     876           0 :                         if (n == 1) {
     877           0 :                                 ival->interval_type = SQL_IS_SECOND;
     878           0 :                                 ival->intval.day_second.day = v1 / (24 * 60 * 60);
     879           0 :                                 ival->intval.day_second.hour = (v1 / (60 * 60)) % 24;
     880           0 :                                 ival->intval.day_second.minute = (v1 / 60) % 60;
     881           0 :                                 ival->intval.day_second.second = v1 % 60;
     882             :                         }
     883             :                 }
     884           0 :                 if (ival->interval_type != SQL_IS_SECOND)
     885             :                         return SQL_ERROR;
     886             :         }
     887             :         {
     888           0 :                 int p = 2;
     889           0 :                 int q = 6;
     890             : 
     891           0 :                 if (parseoptionalbracketednumber(&sval, &slen, &p, ival->interval_type == SQL_IS_SECOND ? &q : NULL) == SQL_ERROR)
     892           0 :                         return SQL_ERROR;
     893           0 :                 if (leadingprecision > p)
     894             :                         return SQL_ERROR;
     895           0 :                 if (ival->interval_type == SQL_IS_SECOND && secondprecision > q)
     896             :                         return SQL_ERROR;
     897             :         }
     898           0 :         if (slen > 0 && isspace((unsigned char) *sval)) {
     899           0 :                 while (slen > 0 && isspace((unsigned char) *sval)) {
     900           0 :                         slen--;
     901           0 :                         sval++;
     902             :                 }
     903           0 :                 if (slen > 2 && strncasecmp(sval, "to", 2) == 0) {
     904           0 :                         slen -= 2;
     905           0 :                         sval += 2;
     906           0 :                         if (slen == 0 || !isspace((unsigned char) *sval))
     907             :                                 return SQL_ERROR;
     908           0 :                         while (slen > 0 && isspace((unsigned char) *sval)) {
     909           0 :                                 slen--;
     910           0 :                                 sval++;
     911             :                         }
     912           0 :                         if (slen >= 4 && strncasecmp(sval, "hour", 4) == 0) {
     913           0 :                                 slen -= 4;
     914           0 :                                 sval += 4;
     915           0 :                                 if (ival->interval_type != SQL_IS_DAY_TO_HOUR)
     916             :                                         return SQL_ERROR;
     917           0 :                         } else if (slen >= 6 && strncasecmp(sval, "minute", 6) == 0) {
     918           0 :                                 slen -= 6;
     919           0 :                                 sval += 6;
     920           0 :                                 if (ival->interval_type != SQL_IS_DAY_TO_MINUTE &&
     921             :                                     ival->interval_type != SQL_IS_HOUR_TO_MINUTE)
     922             :                                         return SQL_ERROR;
     923           0 :                         } else if (slen >= 6 && strncasecmp(sval, "second", 6) == 0) {
     924           0 :                                 int p = 6;
     925             : 
     926           0 :                                 slen -= 6;
     927           0 :                                 sval += 6;
     928           0 :                                 if (ival->interval_type != SQL_IS_DAY_TO_SECOND &&
     929           0 :                                     ival->interval_type != SQL_IS_HOUR_TO_SECOND &&
     930             :                                     ival->interval_type != SQL_IS_MINUTE_TO_SECOND)
     931           0 :                                         return SQL_ERROR;
     932           0 :                                 while (slen > 0 && isspace((unsigned char) *sval)) {
     933           0 :                                         slen--;
     934           0 :                                         sval++;
     935             :                                 }
     936           0 :                                 if (parseoptionalbracketednumber(&sval, &slen, &p, NULL) == SQL_ERROR)
     937             :                                         return SQL_ERROR;
     938           0 :                                 if (p < secondprecision)
     939             :                                         return SQL_ERROR;
     940             :                         } else
     941             :                                 return SQL_ERROR;
     942           0 :                         while (slen > 0 && isspace((unsigned char) *sval)) {
     943           0 :                                 slen--;
     944           0 :                                 sval++;
     945             :                         }
     946             :                 }
     947             :         }
     948           0 :         if (slen > 0)
     949             :                 return SQL_ERROR;
     950           0 :         *secprecp = secondprecision;
     951           0 :         return SQL_SUCCESS;
     952             : }
     953             : 
     954             : SQLRETURN
     955       16573 : ODBCFetch(ODBCStmt *stmt,
     956             :           SQLUSMALLINT col,
     957             :           SQLSMALLINT type,
     958             :           SQLPOINTER ptr,
     959             :           SQLLEN buflen,
     960             :           SQLLEN *lenp,
     961             :           SQLLEN *nullp,
     962             :           SQLSMALLINT precision,
     963             :           SQLSMALLINT scale,
     964             :           SQLINTEGER datetime_interval_precision,
     965             :           SQLLEN offset,
     966             :           SQLULEN row)
     967             : {
     968       16573 :         char *data;
     969       16573 :         size_t datalen;
     970       16573 :         SQLSMALLINT sql_type;
     971       16573 :         SQLUINTEGER maxdatetimeval;
     972       16573 :         ODBCDesc *ard, *ird;
     973       16573 :         ODBCDescRec *irdrec, *ardrec;
     974       16573 :         SQLINTEGER bind_type;
     975             : 
     976             :         /* various interpretations of the input data */
     977       16573 :         bignum_t nval;
     978       16573 :         SQL_INTERVAL_STRUCT ival;
     979       16573 :         int ivalprec = 0;       /* interval second precision */
     980       16573 :         int i;
     981       16573 :         DATE_STRUCT dval;
     982       16573 :         TIME_STRUCT tval;
     983       16573 :         TIMESTAMP_STRUCT tsval;
     984       16573 :         double fval = 0;
     985             : 
     986             :         /* staging variables for output data */
     987       16573 :         SQL_NUMERIC_STRUCT nmval;
     988       16573 :         SQL_INTERVAL_STRUCT ivval;
     989             : 
     990       16573 :         assert(ptr != NULL);
     991             : 
     992       16573 :         ird = stmt->ImplRowDescr;
     993       16573 :         ard = stmt->ApplRowDescr;
     994             : 
     995       16573 :         if (col == 0 || col > ird->sql_desc_count) {
     996             :                 /* Invalid descriptor index */
     997           0 :                 addStmtError(stmt, "07009", NULL, 0);
     998           0 :                 return SQL_ERROR;
     999             :         }
    1000       16573 :         bind_type = ard->sql_desc_bind_type;
    1001       16573 :         irdrec = &ird->descRec[col];
    1002       16573 :         ardrec = col <= ard->sql_desc_count ? &ard->descRec[col] : NULL;
    1003       16573 :         sql_type = irdrec->sql_desc_concise_type;
    1004             : 
    1005       16573 :         if (offset > 0)
    1006           0 :                 ptr = (SQLPOINTER) ((char *) ptr + offset);
    1007             : 
    1008       16573 :         if (lenp)
    1009        6559 :                 lenp = (SQLLEN *) ((char *) lenp + offset + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(*lenp) : bind_type));
    1010       16573 :         if (nullp)
    1011        6559 :                 nullp = (SQLLEN *) ((char *) nullp + offset + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(*nullp) : bind_type));
    1012             : 
    1013             :         /* translate default type */
    1014             :         /* note, type can't be SQL_ARD_TYPE since when this function
    1015             :          * is called from SQLFetch, type is already the ARD concise
    1016             :          * type, and when it is called from SQLGetData, it has already
    1017             :          * been translated */
    1018             : 
    1019       16573 :         if (type == SQL_C_DEFAULT)
    1020           0 :                 type = ODBCDefaultType(irdrec);
    1021             : 
    1022       16573 :         if (precision == UNAFFECTED ||
    1023       16573 :             scale == UNAFFECTED ||
    1024             :             datetime_interval_precision == UNAFFECTED) {
    1025        6563 :                 if (ardrec) {
    1026           0 :                         if (precision == UNAFFECTED)
    1027           0 :                                 precision = ardrec->sql_desc_precision;
    1028           0 :                         if (scale == UNAFFECTED)
    1029           0 :                                 scale = ardrec->sql_desc_scale;
    1030           0 :                         if (datetime_interval_precision == UNAFFECTED)
    1031           0 :                                 datetime_interval_precision = ardrec->sql_desc_datetime_interval_precision;
    1032             :                 } else {
    1033        6563 :                         if (precision == UNAFFECTED)
    1034        6563 :                                 precision = type == SQL_C_NUMERIC ? 10 : 6;
    1035        6563 :                         if (scale == UNAFFECTED)
    1036        6563 :                                 scale = 0;
    1037        6563 :                         if (datetime_interval_precision == UNAFFECTED)
    1038        6563 :                                 datetime_interval_precision = 2;
    1039             :                 }
    1040             :         }
    1041       16573 :         i = datetime_interval_precision;
    1042       16573 :         maxdatetimeval = 1;
    1043       29699 :         while (i-- > 0)
    1044       13126 :                 maxdatetimeval *= 10;
    1045             : 
    1046       16573 :         data = mapi_fetch_field(stmt->hdl, col - 1);
    1047       16573 :         if (mapi_error(stmt->Dbc->mid)) {
    1048             :                 /* General error */
    1049           0 :                 addStmtError(stmt, "HY000", mapi_error_str(stmt->Dbc->mid), 0);
    1050           0 :                 return SQL_ERROR;
    1051             :         }
    1052       16573 :         if (nullp)
    1053        6559 :                 *nullp = SQL_NULL_DATA;
    1054       16573 :         if (lenp)
    1055        6559 :                 *lenp = SQL_NULL_DATA;
    1056       16573 :         if (data == NULL) {
    1057        1233 :                 if (nullp == NULL) {
    1058             :                         /* Indicator variable required but not supplied */
    1059           0 :                         addStmtError(stmt, "22002", NULL, 0);
    1060           0 :                         return SQL_ERROR;
    1061             :                 }
    1062             :                 return SQL_SUCCESS;
    1063             :         }
    1064       15340 :         datalen = mapi_fetch_field_len(stmt->hdl, col - 1);
    1065             : 
    1066             :         /* first convert to internal (binary) format */
    1067             : 
    1068             :         /* see SQLExecute.c for possible types */
    1069       15340 :         switch (sql_type) {
    1070        5255 :         case SQL_DECIMAL:
    1071             :         case SQL_NUMERIC:
    1072             :         case SQL_TINYINT:
    1073             :         case SQL_SMALLINT:
    1074             :         case SQL_INTEGER:
    1075             :         case SQL_BIGINT:
    1076             :         case SQL_HUGEINT:
    1077             :         case SQL_INTERVAL_YEAR:
    1078             :         case SQL_INTERVAL_YEAR_TO_MONTH:
    1079             :         case SQL_INTERVAL_MONTH:
    1080             :         case SQL_INTERVAL_DAY:
    1081             :         case SQL_INTERVAL_DAY_TO_HOUR:
    1082             :         case SQL_INTERVAL_DAY_TO_MINUTE:
    1083             :         case SQL_INTERVAL_DAY_TO_SECOND:
    1084             :         case SQL_INTERVAL_HOUR:
    1085             :         case SQL_INTERVAL_HOUR_TO_MINUTE:
    1086             :         case SQL_INTERVAL_HOUR_TO_SECOND:
    1087             :         case SQL_INTERVAL_MINUTE:
    1088             :         case SQL_INTERVAL_MINUTE_TO_SECOND:
    1089             :         case SQL_INTERVAL_SECOND:
    1090        5255 :                 switch (parseint(data, &nval)) {
    1091           0 :                 case 0:
    1092             :                         /* shouldn't happen: getting here means SQL
    1093             :                          * server told us a value was of a certain
    1094             :                          * type, but in reality it wasn't. */
    1095             :                         /* Invalid character value for cast specification */
    1096           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1097           0 :                         return SQL_ERROR;
    1098           0 :                 case 2:
    1099             :                         /* hugeint that doesn't fit into a bigint */
    1100             :                         /* Numeric value out of range */
    1101           0 :                         addStmtError(stmt, "22003", NULL, 0);
    1102           0 :                         return SQL_ERROR;
    1103             :                 }
    1104             : 
    1105             :                 /* interval types are transferred as ints but need to
    1106             :                  * be converted to the internal interval formats */
    1107        5255 :                 switch (sql_type) {
    1108           9 :                 case SQL_INTERVAL_YEAR:
    1109             :                 case SQL_INTERVAL_YEAR_TO_MONTH:
    1110             :                 case SQL_INTERVAL_MONTH:
    1111           9 :                         parsemonthinterval(&nval, &ival, SQL_INTERVAL_MONTH);
    1112           9 :                         break;
    1113          32 :                 case SQL_INTERVAL_DAY:
    1114             :                 case SQL_INTERVAL_DAY_TO_HOUR:
    1115             :                 case SQL_INTERVAL_DAY_TO_MINUTE:
    1116             :                 case SQL_INTERVAL_DAY_TO_SECOND:
    1117             :                 case SQL_INTERVAL_HOUR:
    1118             :                 case SQL_INTERVAL_HOUR_TO_MINUTE:
    1119             :                 case SQL_INTERVAL_HOUR_TO_SECOND:
    1120             :                 case SQL_INTERVAL_MINUTE:
    1121             :                 case SQL_INTERVAL_MINUTE_TO_SECOND:
    1122             :                 case SQL_INTERVAL_SECOND:
    1123          32 :                         ivalprec = parsesecondinterval(&nval, &ival, SQL_INTERVAL_SECOND);
    1124          32 :                         break;
    1125             :                 default:
    1126             :                         break;
    1127             :                 }
    1128             :                 break;
    1129        2006 :         case SQL_DOUBLE:
    1130             :         case SQL_FLOAT:
    1131             :         case SQL_REAL:
    1132        2006 :                 if (!parsedouble(data, &fval)) {
    1133             :                         /* Invalid character value for cast specification */
    1134           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1135           0 :                         return SQL_ERROR;
    1136             :                 }
    1137             :                 break;
    1138         147 :         case SQL_BIT:
    1139         147 :                 nval.precision = 1;
    1140         147 :                 nval.scale = 0;
    1141         147 :                 nval.sign = 1;
    1142         147 :                 while (datalen != 0 && space(*data)) {
    1143           0 :                         data++;
    1144           0 :                         datalen--;
    1145             :                 }
    1146         147 :                 if (datalen >= 4 && strncasecmp(data, "true", 4) == 0) {
    1147         145 :                         data += 4;
    1148         145 :                         datalen -= 4;
    1149         145 :                         nval.val = 1;
    1150           2 :                 } else if (datalen >= 5 && strncasecmp(data, "false", 5) == 0) {
    1151           2 :                         data += 5;
    1152           2 :                         datalen -= 5;
    1153           2 :                         nval.val = 0;
    1154             :                 } else {
    1155             :                         /* Invalid character value for cast specification */
    1156           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1157           0 :                         return SQL_ERROR;
    1158             :                 }
    1159         147 :                 while (datalen != 0 && space(*data)) {
    1160           0 :                         data++;
    1161           0 :                         datalen--;
    1162             :                 }
    1163         147 :                 if (datalen != 0) {
    1164             :                         /* Invalid character value for cast specification */
    1165           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1166           0 :                         return SQL_ERROR;
    1167             :                 }
    1168             :                 break;
    1169        2003 :         case SQL_TYPE_DATE:
    1170        2003 :                 if (!parsedate(data, &dval)) {
    1171             :                         /* Invalid character value for cast specification */
    1172           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1173           0 :                         return SQL_ERROR;
    1174             :                 }
    1175             :                 break;
    1176        2003 :         case SQL_TYPE_TIME:
    1177        2003 :                 if (!parsetime(data, &tval)) {
    1178             :                         /* Invalid character value for cast specification */
    1179           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1180           0 :                         return SQL_ERROR;
    1181             :                 }
    1182             :                 break;
    1183           3 :         case SQL_TYPE_TIMESTAMP:
    1184           3 :                 if (!parsetimestamp(data, &tsval)) {
    1185             :                         /* Invalid character value for cast specification */
    1186           0 :                         addStmtError(stmt, "22018", NULL, 0);
    1187           0 :                         return SQL_ERROR;
    1188             :                 }
    1189             :                 break;
    1190             :         case SQL_GUID:
    1191             :                 /* nothing special to do here */
    1192             :         default:
    1193             :                 /* any other type can only be converted to SQL_C_CHAR */
    1194             :                 break;
    1195             :         }
    1196             : 
    1197             :         /* then convert to desired format */
    1198             : 
    1199       15340 :         switch (type) {
    1200        6244 :         case SQL_C_CHAR:
    1201             :         case SQL_C_WCHAR:
    1202             :         {
    1203        6244 :                 SQLPOINTER origptr;
    1204        6244 :                 SQLLEN origbuflen;
    1205        6244 :                 SQLLEN *origlenp;
    1206        6244 :                 SQLLEN sz;
    1207             : 
    1208        6244 :                 if (buflen < 0) {
    1209             :                         /* Invalid string or buffer length */
    1210           0 :                         addStmtError(stmt, "HY090", NULL, 0);
    1211           0 :                         return SQL_ERROR;
    1212             :                 }
    1213        6244 :                 if (ardrec && row > 0)
    1214           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? ardrec->sql_desc_octet_length : bind_type));
    1215             : 
    1216             :                 /* if SQL_C_WCHAR is requested, first convert to UTF-8
    1217             :                  * (SQL_C_CHAR), and at the end convert to WCHAR */
    1218        6244 :                 origptr = ptr;
    1219             : 
    1220        6244 :                 origbuflen = buflen;
    1221        6244 :                 origlenp = lenp;
    1222        6244 :                 if (type == SQL_C_WCHAR) {
    1223             :                         /* allocate temporary space */
    1224         391 :                         switch (sql_type) {
    1225         391 :                         case SQL_CHAR:
    1226             :                         case SQL_VARCHAR:
    1227             :                         case SQL_LONGVARCHAR:
    1228             :                         case SQL_WCHAR:
    1229             :                         case SQL_WVARCHAR:
    1230             :                         case SQL_WLONGVARCHAR:
    1231             :                         case SQL_BINARY:
    1232             :                         case SQL_VARBINARY:
    1233             :                         case SQL_LONGVARBINARY:
    1234             :                         case SQL_GUID:
    1235             :                                 /* this is certainly enough for strings */
    1236         391 :                                 buflen = (SQLLEN) datalen + 1;
    1237         391 :                                 ptr = NULL;
    1238         391 :                                 break;
    1239           0 :                         default:
    1240             :                                 /* should be enough for most types */
    1241           0 :                                 buflen = 511;
    1242           0 :                                 ptr = malloc(buflen);
    1243           0 :                                 if (ptr == NULL) {
    1244             :                                         /* Memory allocation error */
    1245           0 :                                         addStmtError(stmt, "HY001", NULL, 0);
    1246           0 :                                         return SQL_ERROR;
    1247             :                                 }
    1248             :                                 break;
    1249             :                         }
    1250             :                         lenp = NULL;
    1251             :                 }
    1252        6244 :                 switch (sql_type) {
    1253           0 :                 case SQL_BINARY:
    1254             :                 case SQL_VARBINARY:
    1255             :                 case SQL_LONGVARBINARY:
    1256           0 :                         if (buflen > 0 && (buflen & 1) == 0) {
    1257             :                                 /* return even number of bytes + NULL
    1258             :                                  * (i.e. buflen must be odd) */
    1259           0 :                                 buflen--;
    1260             :                         }
    1261             :                         /* fall through */
    1262             :                 default:
    1263             :                 case SQL_CHAR:
    1264             :                 case SQL_VARCHAR:
    1265             :                 case SQL_LONGVARCHAR:
    1266             :                 case SQL_WCHAR:
    1267             :                 case SQL_WVARCHAR:
    1268             :                 case SQL_WLONGVARCHAR:
    1269             :                 case SQL_GUID:
    1270        3917 :                         if (irdrec->already_returned < 0)
    1271        3911 :                                 irdrec->already_returned = 0;
    1272           6 :                         else if ((size_t) irdrec->already_returned >= datalen) {
    1273             :                                 /* no more data to return */
    1274           0 :                                 if (type == SQL_C_WCHAR && ptr)
    1275           0 :                                         free(ptr);
    1276           0 :                                 return SQL_NO_DATA;
    1277             :                         }
    1278        3917 :                         data += irdrec->already_returned;
    1279        3917 :                         datalen -= (size_t) irdrec->already_returned;
    1280        3917 :                         if (ptr) {
    1281        7052 :                                 copyString(data, datalen, ptr, buflen, lenp,
    1282             :                                            SQLLEN, addStmtError, stmt,
    1283             :                                            return SQL_ERROR);
    1284             :                         }
    1285        3917 :                         if (datalen < (size_t) buflen)
    1286        3916 :                                 irdrec->already_returned += datalen;
    1287             :                         else
    1288           1 :                                 irdrec->already_returned += buflen - 1;
    1289             :                         break;
    1290        2318 :                 case SQL_TINYINT:
    1291             :                 case SQL_SMALLINT:
    1292             :                 case SQL_INTEGER:
    1293             :                 case SQL_BIGINT:
    1294             :                 case SQL_HUGEINT:
    1295        2318 :                         sz = snprintf((char *) ptr, buflen, "%s", data);
    1296        2318 :                         if (sz < 0 || sz >= buflen) {
    1297             :                                 /* Numeric value out of range */
    1298           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1299             : 
    1300           0 :                                 if (type == SQL_C_WCHAR)
    1301           0 :                                         free(ptr);
    1302           0 :                                 return SQL_ERROR;
    1303             :                         }
    1304        2318 :                         if (lenp)
    1305        2318 :                                 *lenp = sz;
    1306             :                         break;
    1307           9 :                 case SQL_DECIMAL:
    1308             :                 case SQL_NUMERIC:
    1309             :                 case SQL_BIT: {
    1310           9 :                         uint64_t f;
    1311           9 :                         int n;
    1312             : 
    1313           9 :                         data = (char *) ptr;
    1314             : 
    1315          62 :                         for (n = 0, f = 1; n < nval.scale; n++)
    1316          53 :                                 f *= 10;
    1317             : #ifdef HAVE_HGE
    1318           9 :                         uhge v = nval.val / f;
    1319           9 :                         if (v > UINT64_MAX) {
    1320             :                                 /* Numeric value out of range */
    1321           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1322             : 
    1323           0 :                                 if (type == SQL_C_WCHAR)
    1324           0 :                                         free(ptr);
    1325           0 :                                 return SQL_ERROR;
    1326             :                         }
    1327          18 :                         sz = snprintf(data, buflen, "%s%" PRIu64,
    1328           9 :                                       nval.sign ? "" : "-", (uint64_t) v);
    1329             : #else
    1330             :                         sz = snprintf(data, buflen, "%s%" PRIu64,
    1331             :                                       nval.sign ? "" : "-",
    1332             :                                       (uint64_t) (nval.val / f));
    1333             : #endif
    1334           9 :                         if (sz < 0 || sz >= buflen) {
    1335             :                                 /* Numeric value out of range */
    1336           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1337             : 
    1338           0 :                                 if (type == SQL_C_WCHAR)
    1339           0 :                                         free(ptr);
    1340           0 :                                 return SQL_ERROR;
    1341             :                         }
    1342           9 :                         if (lenp)
    1343           9 :                                 *lenp = sz;
    1344           9 :                         if (nval.scale > 0) {
    1345           8 :                                 data += sz;
    1346           8 :                                 buflen -= sz;
    1347           8 :                                 if (lenp)
    1348           8 :                                         *lenp += nval.scale + 1;
    1349           8 :                                 if (buflen > 2)
    1350           8 :                                         sz = (SQLLEN) snprintf(data, buflen, ".%0*" PRIu64, nval.scale, (uint64_t) (nval.val % f));
    1351           8 :                                 if (buflen <= 2 || sz < 0 || sz >= buflen) {
    1352           0 :                                         data[buflen - 1] = 0;
    1353             :                                         /* String data, right-truncated */
    1354           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1355             :                                 }
    1356             :                         }
    1357             :                         break;
    1358             :                 }
    1359           0 :                 case SQL_DOUBLE:
    1360             :                 case SQL_FLOAT:
    1361             :                 case SQL_REAL: {
    1362           0 :                         data = (char *) ptr;
    1363             : 
    1364           0 :                         for (i = 4; i < 18; i++) {
    1365           0 :                                 sz = (SQLLEN) snprintf(data, buflen, "%.*g", i, fval);
    1366           0 :                                 if (sz < 0 || sz >= buflen) {
    1367           0 :                                         data[buflen - 1] = 0;
    1368           0 :                                         if (i == 0) {
    1369             :                                                 /* Numeric value out
    1370             :                                                  * of range */
    1371             :                                                 addStmtError(stmt, "22003", NULL, 0);
    1372             : 
    1373             :                                                 if (type == SQL_C_WCHAR)
    1374             :                                                         free(ptr);
    1375             :                                                 return SQL_ERROR;
    1376             :                                         }
    1377             :                                         /* current precision (i) doesn't fit,
    1378             :                                          * but previous did, so use that */
    1379           0 :                                         snprintf(data, buflen, "%.*g", i - 1, fval);
    1380             :                                         /* max space that would have
    1381             :                                          * been needed */
    1382           0 :                                         sz = (SQLLEN) strlen(data) + 17 - i;
    1383             :                                         /* String data, right-truncated */
    1384           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1385           0 :                                         break;
    1386             :                                 }
    1387           0 :                                 if (fval == strtod(data, NULL))
    1388             :                                         break;
    1389             :                         }
    1390           0 :                         if (lenp)
    1391           0 :                                 *lenp = sz;
    1392             :                         break;
    1393             :                 }
    1394           0 :                 case SQL_TYPE_DATE:
    1395           0 :                         if (buflen < 11) {
    1396             :                                 /* Numeric value out of range */
    1397           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1398             : 
    1399           0 :                                 if (type == SQL_C_WCHAR)
    1400           0 :                                         free(ptr);
    1401           0 :                                 return SQL_ERROR;
    1402             :                         }
    1403           0 :                         data = (char *) ptr;
    1404             : 
    1405           0 :                         sz = snprintf(data, buflen, "%04u-%02u-%02u",
    1406           0 :                                       (unsigned int) dval.year,
    1407           0 :                                       (unsigned int) dval.month,
    1408           0 :                                       (unsigned int) dval.day);
    1409           0 :                         if (sz < 0 || sz >= buflen) {
    1410           0 :                                 data[buflen - 1] = 0;
    1411             :                                 /* String data, right-truncated */
    1412           0 :                                 addStmtError(stmt, "01004", NULL, 0);
    1413             :                         }
    1414           0 :                         if (lenp)
    1415           0 :                                 *lenp = sz;
    1416             :                         break;
    1417           0 :                 case SQL_TYPE_TIME:
    1418           0 :                         if (buflen < 9) {
    1419             :                                 /* Numeric value out of range */
    1420           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1421             : 
    1422           0 :                                 if (type == SQL_C_WCHAR)
    1423           0 :                                         free(ptr);
    1424           0 :                                 return SQL_ERROR;
    1425             :                         }
    1426           0 :                         data = (char *) ptr;
    1427             : 
    1428           0 :                         sz = snprintf(data, buflen, "%02u:%02u:%02u",
    1429           0 :                                       (unsigned int) tval.hour,
    1430           0 :                                       (unsigned int) tval.minute,
    1431           0 :                                       (unsigned int) tval.second);
    1432           0 :                         if (sz < 0 || sz >= buflen) {
    1433           0 :                                 data[buflen - 1] = 0;
    1434             :                                 /* String data, right-truncated */
    1435           0 :                                 addStmtError(stmt, "01004", NULL, 0);
    1436             :                         }
    1437           0 :                         if (lenp)
    1438           0 :                                 *lenp = sz;
    1439             :                         break;
    1440           0 :                 case SQL_TYPE_TIMESTAMP:
    1441           0 :                         data = (char *) ptr;
    1442             : 
    1443           0 :                         sz = snprintf(data, buflen,
    1444             :                                       "%04u-%02u-%02u %02u:%02u:%02u",
    1445           0 :                                       (unsigned int) tsval.year,
    1446           0 :                                       (unsigned int) tsval.month,
    1447           0 :                                       (unsigned int) tsval.day,
    1448           0 :                                       (unsigned int) tsval.hour,
    1449           0 :                                       (unsigned int) tsval.minute,
    1450           0 :                                       (unsigned int) tsval.second);
    1451           0 :                         if (sz < 0 || sz >= buflen) {
    1452             :                                 /* Numeric value out of range */
    1453           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1454             : 
    1455           0 :                                 if (type == SQL_C_WCHAR)
    1456           0 :                                         free(ptr);
    1457           0 :                                 return SQL_ERROR;
    1458             :                         }
    1459           0 :                         if (lenp)
    1460           0 :                                 *lenp = sz;
    1461           0 :                         if (tsval.fraction) {
    1462           0 :                                 int fscale = 9;
    1463             : 
    1464           0 :                                 data += sz;
    1465           0 :                                 buflen += sz;
    1466           0 :                                 while (tsval.fraction % 10 == 0) {
    1467           0 :                                         tsval.fraction /= 10;
    1468           0 :                                         fscale--;
    1469             :                                 }
    1470           0 :                                 if (lenp)
    1471           0 :                                         *lenp += fscale + 1;
    1472           0 :                                 if (buflen > 2)
    1473           0 :                                         sz = snprintf(data, buflen, ".%0*u",
    1474             :                                                       fscale, (unsigned int) tsval.fraction);
    1475           0 :                                 if (buflen <= 2 || sz < 0 || sz >= buflen) {
    1476           0 :                                         data[buflen - 1] = 0;
    1477             :                                         /* String data, right-truncated */
    1478           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1479             :                                 }
    1480             :                         }
    1481             :                         break;
    1482           0 :                 case SQL_INTERVAL_YEAR:
    1483           0 :                         sz = snprintf((char *) ptr, buflen,
    1484             :                                       "INTERVAL %s'%u' YEAR",
    1485           0 :                                       ival.interval_sign ? "-" : "",
    1486           0 :                                       (unsigned int) ival.intval.year_month.year);
    1487             : 
    1488           0 :                         if (sz < 0 || sz >= buflen) {
    1489             :                                 /* Numeric value out of range */
    1490           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1491             : 
    1492           0 :                                 if (type == SQL_C_WCHAR)
    1493           0 :                                         free(ptr);
    1494           0 :                                 return SQL_ERROR;
    1495             :                         }
    1496           0 :                         if (lenp)
    1497           0 :                                 *lenp = sz;
    1498             :                         break;
    1499           0 :                 case SQL_INTERVAL_YEAR_TO_MONTH:
    1500           0 :                         sz = snprintf((char *) ptr, buflen,
    1501             :                                       "INTERVAL %s'%u-%02u' YEAR TO MONTH",
    1502           0 :                                       ival.interval_sign ? "-" : "",
    1503           0 :                                       (unsigned int) ival.intval.year_month.year,
    1504           0 :                                       (unsigned int) ival.intval.year_month.month);
    1505             : 
    1506           0 :                         if (sz < 0 || sz >= buflen) {
    1507             :                                 /* Numeric value out of range */
    1508           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1509             : 
    1510           0 :                                 if (type == SQL_C_WCHAR)
    1511           0 :                                         free(ptr);
    1512           0 :                                 return SQL_ERROR;
    1513             :                         }
    1514           0 :                         if (lenp)
    1515           0 :                                 *lenp = sz;
    1516             :                         break;
    1517           0 :                 case SQL_INTERVAL_MONTH:
    1518           0 :                         sz = snprintf((char *) ptr, buflen,
    1519             :                                       "INTERVAL %s'%u' MONTH",
    1520           0 :                                       ival.interval_sign ? "-" : "",
    1521           0 :                                       (unsigned int) (12 * ival.intval.year_month.year +
    1522           0 :                                                       ival.intval.year_month.month));
    1523             : 
    1524           0 :                         if (sz < 0 || sz >= buflen) {
    1525             :                                 /* Numeric value out of range */
    1526           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1527             : 
    1528           0 :                                 if (type == SQL_C_WCHAR)
    1529           0 :                                         free(ptr);
    1530           0 :                                 return SQL_ERROR;
    1531             :                         }
    1532           0 :                         if (lenp)
    1533           0 :                                 *lenp = sz;
    1534             :                         break;
    1535           0 :                 case SQL_INTERVAL_DAY:
    1536           0 :                         sz = snprintf((char *) ptr, buflen,
    1537             :                                       "INTERVAL %s'%u' DAY",
    1538           0 :                                       ival.interval_sign ? "-" : "",
    1539           0 :                                       (unsigned int) ival.intval.day_second.day);
    1540             : 
    1541           0 :                         if (sz < 0 || sz >= buflen) {
    1542             :                                 /* Numeric value out of range */
    1543           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1544             : 
    1545           0 :                                 if (type == SQL_C_WCHAR)
    1546           0 :                                         free(ptr);
    1547           0 :                                 return SQL_ERROR;
    1548             :                         }
    1549           0 :                         if (lenp)
    1550           0 :                                 *lenp = sz;
    1551             :                         break;
    1552           0 :                 case SQL_INTERVAL_DAY_TO_HOUR:
    1553           0 :                         sz = snprintf((char *) ptr, buflen,
    1554             :                                       "INTERVAL %s'%u %02u' DAY TO HOUR",
    1555           0 :                                       ival.interval_sign ? "-" : "",
    1556           0 :                                       (unsigned int) ival.intval.day_second.day,
    1557           0 :                                       (unsigned int) ival.intval.day_second.hour);
    1558             : 
    1559           0 :                         if (sz < 0 || sz >= buflen) {
    1560             :                                 /* Numeric value out of range */
    1561           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1562             : 
    1563           0 :                                 if (type == SQL_C_WCHAR)
    1564           0 :                                         free(ptr);
    1565           0 :                                 return SQL_ERROR;
    1566             :                         }
    1567           0 :                         if (lenp)
    1568           0 :                                 *lenp = sz;
    1569             :                         break;
    1570           0 :                 case SQL_INTERVAL_DAY_TO_MINUTE:
    1571           0 :                         sz = snprintf((char *) ptr, buflen,
    1572             :                                       "INTERVAL %s'%u %02u:%02u' DAY TO MINUTE",
    1573           0 :                                       ival.interval_sign ? "-" : "",
    1574           0 :                                       (unsigned int) ival.intval.day_second.day,
    1575           0 :                                       (unsigned int) ival.intval.day_second.hour,
    1576           0 :                                       (unsigned int) ival.intval.day_second.minute);
    1577             : 
    1578           0 :                         if (sz < 0 || sz >= buflen) {
    1579             :                                 /* Numeric value out of range */
    1580           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1581             : 
    1582           0 :                                 if (type == SQL_C_WCHAR)
    1583           0 :                                         free(ptr);
    1584           0 :                                 return SQL_ERROR;
    1585             :                         }
    1586           0 :                         if (lenp)
    1587           0 :                                 *lenp = sz;
    1588             :                         break;
    1589           0 :                 case SQL_INTERVAL_DAY_TO_SECOND: {
    1590           0 :                         int w;
    1591             : 
    1592           0 :                         data = (char *) ptr;
    1593             : 
    1594           0 :                         w = 14; /* space needed for "'DAY TO SECOND" */
    1595             : 
    1596           0 :                         sz = snprintf(data, buflen, "INTERVAL %s'%u %02u:%02u:%02u",
    1597           0 :                                       ival.interval_sign ? "-" : "",
    1598           0 :                                       (unsigned int) ival.intval.day_second.day,
    1599           0 :                                       (unsigned int) ival.intval.day_second.hour,
    1600           0 :                                       (unsigned int) ival.intval.day_second.minute,
    1601           0 :                                       (unsigned int) ival.intval.day_second.second);
    1602           0 :                         if (sz < 0 || sz + w >= buflen) {
    1603             :                                 /* Numeric value out of range */
    1604           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1605             : 
    1606           0 :                                 if (type == SQL_C_WCHAR)
    1607           0 :                                         free(ptr);
    1608           0 :                                 return SQL_ERROR;
    1609             :                         }
    1610           0 :                         data += sz;
    1611           0 :                         buflen -= sz;
    1612             : 
    1613           0 :                         if (lenp)
    1614           0 :                                 *lenp = sz;
    1615           0 :                         if (ivalprec > 0) {
    1616           0 :                                 if (lenp)
    1617           0 :                                         *lenp += ivalprec + 1;
    1618           0 :                                 if (buflen > w + 2)
    1619           0 :                                         sz = snprintf(data, buflen, ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    1620           0 :                                 if (buflen <= w + 2 || sz < 0 || sz + w >= buflen) {
    1621           0 :                                         sz = buflen - w - 1;
    1622             :                                         /* String data, right-truncated */
    1623           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1624             :                                 }
    1625           0 :                                 data += sz;
    1626           0 :                                 buflen -= sz;
    1627             :                         }
    1628             :                         /* this should now fit */
    1629           0 :                         sz = snprintf(data, buflen, "' DAY TO SECOND");
    1630           0 :                         if (lenp && sz > 0)
    1631           0 :                                 *lenp += sz;
    1632             :                         break;
    1633             :                 }
    1634           0 :                 case SQL_INTERVAL_HOUR:
    1635           0 :                         sz = snprintf((char *) ptr, buflen,
    1636             :                                       "INTERVAL %s'%u' HOUR",
    1637           0 :                                       ival.interval_sign ? "-" : "",
    1638           0 :                                       (unsigned) (24 * ival.intval.day_second.day +
    1639           0 :                                                   ival.intval.day_second.hour));
    1640             : 
    1641           0 :                         if (sz < 0 || sz >= buflen) {
    1642             :                                 /* Numeric value out of range */
    1643           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1644             : 
    1645           0 :                                 if (type == SQL_C_WCHAR)
    1646           0 :                                         free(ptr);
    1647           0 :                                 return SQL_ERROR;
    1648             :                         }
    1649           0 :                         if (lenp)
    1650           0 :                                 *lenp = sz;
    1651             :                         break;
    1652           0 :                 case SQL_INTERVAL_HOUR_TO_MINUTE:
    1653           0 :                         sz = snprintf((char *) ptr, buflen,
    1654             :                                       "INTERVAL %s'%u:%02u' HOUR TO MINUTE",
    1655           0 :                                       ival.interval_sign ? "-" : "",
    1656           0 :                                       (unsigned) (24 * ival.intval.day_second.day +
    1657           0 :                                                   ival.intval.day_second.hour),
    1658           0 :                                       (unsigned int) ival.intval.day_second.minute);
    1659             : 
    1660           0 :                         if (sz < 0 || sz >= buflen) {
    1661             :                                 /* Numeric value out of range */
    1662           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1663             : 
    1664           0 :                                 if (type == SQL_C_WCHAR)
    1665           0 :                                         free(ptr);
    1666           0 :                                 return SQL_ERROR;
    1667             :                         }
    1668           0 :                         if (lenp)
    1669           0 :                                 *lenp = sz;
    1670             :                         break;
    1671           0 :                 case SQL_INTERVAL_HOUR_TO_SECOND: {
    1672           0 :                         int w;
    1673             : 
    1674           0 :                         data = (char *) ptr;
    1675             : 
    1676           0 :                         w = 15; /* space needed for "'HOUR TO SECOND" */
    1677             : 
    1678           0 :                         sz = snprintf(data, buflen, "INTERVAL %s'%u:%02u:%02u",
    1679           0 :                                       ival.interval_sign ? "-" : "",
    1680           0 :                                       (unsigned) (24 * ival.intval.day_second.day +
    1681           0 :                                                   ival.intval.day_second.hour),
    1682           0 :                                       (unsigned int) ival.intval.day_second.minute,
    1683           0 :                                       (unsigned int) ival.intval.day_second.second);
    1684           0 :                         if (sz < 0 || sz + w >= buflen) {
    1685             :                                 /* Numeric value out of range */
    1686           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1687             : 
    1688           0 :                                 if (type == SQL_C_WCHAR)
    1689           0 :                                         free(ptr);
    1690           0 :                                 return SQL_ERROR;
    1691             :                         }
    1692           0 :                         data += sz;
    1693           0 :                         buflen -= sz;
    1694             : 
    1695           0 :                         if (lenp)
    1696           0 :                                 *lenp = sz;
    1697           0 :                         if (ivalprec > 0) {
    1698           0 :                                 if (lenp)
    1699           0 :                                         *lenp += ivalprec + 1;
    1700           0 :                                 if (buflen > w + 2)
    1701           0 :                                         sz = snprintf(data, buflen, ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    1702           0 :                                 if (buflen <= w + 2 || sz < 0 || sz + w >= buflen) {
    1703           0 :                                         sz = buflen - w - 1;
    1704             :                                         /* String data, right-truncated */
    1705           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1706             :                                 }
    1707           0 :                                 data += sz;
    1708           0 :                                 buflen -= sz;
    1709             :                         }
    1710             :                         /* this should now fit */
    1711           0 :                         sz = snprintf(data, buflen, "' HOUR TO SECOND");
    1712           0 :                         if (lenp && sz > 0)
    1713           0 :                                 *lenp += sz;
    1714             :                         break;
    1715             :                 }
    1716           0 :                 case SQL_INTERVAL_MINUTE:
    1717           0 :                         sz = snprintf((char *) ptr, buflen,
    1718             :                                       "INTERVAL %s'%u' MINUTE",
    1719           0 :                                       ival.interval_sign ? "-" : "",
    1720           0 :                                       (unsigned) (60 * (24 * ival.intval.day_second.day +
    1721           0 :                                                         ival.intval.day_second.hour) +
    1722           0 :                                                   ival.intval.day_second.minute));
    1723             : 
    1724           0 :                         if (sz < 0 || sz >= buflen) {
    1725             :                                 /* Numeric value out of range */
    1726           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1727             : 
    1728           0 :                                 if (type == SQL_C_WCHAR)
    1729           0 :                                         free(ptr);
    1730           0 :                                 return SQL_ERROR;
    1731             :                         }
    1732           0 :                         if (lenp)
    1733           0 :                                 *lenp = sz;
    1734             :                         break;
    1735           0 :                 case SQL_INTERVAL_MINUTE_TO_SECOND: {
    1736           0 :                         int w;
    1737             : 
    1738           0 :                         data = (char *) ptr;
    1739             : 
    1740           0 :                         w = 17; /* space needed for "'MINUTE TO SECOND" */
    1741             : 
    1742           0 :                         sz = snprintf(data, buflen, "INTERVAL %s'%u:%02u",
    1743           0 :                                       ival.interval_sign ? "-" : "",
    1744           0 :                                       (unsigned) (60 * (24 * ival.intval.day_second.day +
    1745           0 :                                                         ival.intval.day_second.hour) +
    1746           0 :                                                   ival.intval.day_second.minute),
    1747           0 :                                       (unsigned int) ival.intval.day_second.second);
    1748           0 :                         if (sz < 0 || sz + w >= buflen) {
    1749             :                                 /* Numeric value out of range */
    1750           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1751             : 
    1752           0 :                                 if (type == SQL_C_WCHAR)
    1753           0 :                                         free(ptr);
    1754           0 :                                 return SQL_ERROR;
    1755             :                         }
    1756           0 :                         data += sz;
    1757           0 :                         buflen -= sz;
    1758             : 
    1759           0 :                         if (lenp)
    1760           0 :                                 *lenp = sz;
    1761           0 :                         if (ivalprec > 0) {
    1762           0 :                                 if (lenp)
    1763           0 :                                         *lenp += ivalprec + 1;
    1764           0 :                                 if (buflen > w + 2)
    1765           0 :                                         sz = snprintf(data, buflen, ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    1766           0 :                                 if (buflen <= w + 2 || sz < 0 || sz + w >= buflen) {
    1767           0 :                                         sz = buflen - w - 1;
    1768             :                                         /* String data, right-truncated */
    1769           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1770             :                                 }
    1771           0 :                                 data += sz;
    1772           0 :                                 buflen -= sz;
    1773             :                         }
    1774             :                         /* this should now fit */
    1775           0 :                         sz = snprintf(data, buflen, "' MINUTE TO SECOND");
    1776           0 :                         if (lenp && sz > 0)
    1777           0 :                                 *lenp += sz;
    1778             :                         break;
    1779             :                 }
    1780           0 :                 case SQL_INTERVAL_SECOND: {
    1781           0 :                         int w;
    1782             : 
    1783           0 :                         data = (char *) ptr;
    1784             : 
    1785           0 :                         w = 7;  /* space needed for "'SECOND" */
    1786             : 
    1787           0 :                         sz = snprintf(data, buflen, "INTERVAL %s'%u",
    1788           0 :                                       ival.interval_sign ? "-" : "",
    1789           0 :                                       (unsigned) (60 * (60 * (24 * ival.intval.day_second.day +
    1790           0 :                                                               ival.intval.day_second.hour) +
    1791           0 :                                                         ival.intval.day_second.minute) +
    1792           0 :                                                   ival.intval.day_second.second));
    1793           0 :                         if (sz < 0 || sz + w >= buflen) {
    1794             :                                 /* Numeric value out of range */
    1795           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1796             : 
    1797           0 :                                 if (type == SQL_C_WCHAR)
    1798           0 :                                         free(ptr);
    1799           0 :                                 return SQL_ERROR;
    1800             :                         }
    1801           0 :                         data += sz;
    1802           0 :                         buflen -= sz;
    1803             : 
    1804           0 :                         if (lenp)
    1805           0 :                                 *lenp = sz;
    1806           0 :                         if (ivalprec > 0) {
    1807           0 :                                 if (lenp)
    1808           0 :                                         *lenp += ivalprec + 1;
    1809           0 :                                 if (buflen > w + 2)
    1810           0 :                                         sz = snprintf(data, buflen, ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    1811           0 :                                 if (buflen <= w + 2 || sz < 0 || sz + w >= buflen) {
    1812           0 :                                         sz = buflen - w - 1;
    1813             :                                         /* String data, right-truncated */
    1814           0 :                                         addStmtError(stmt, "01004", NULL, 0);
    1815             :                                 }
    1816           0 :                                 data += sz;
    1817           0 :                                 buflen -= sz;
    1818             :                         }
    1819             :                         /* this should now fit */
    1820           0 :                         sz = snprintf(data, buflen, "' SECOND");
    1821           0 :                         if (lenp && sz > 0)
    1822           0 :                                 *lenp += sz;
    1823             :                         break;
    1824             :                 }
    1825             :                 }
    1826        6244 :                 if (type == SQL_C_WCHAR) {
    1827         391 :                         SQLSMALLINT n;
    1828         391 :                         size_t i;
    1829             : 
    1830         391 :                         if (ptr) {
    1831           0 :                                 ODBCutf82wchar((SQLCHAR *) ptr, SQL_NTS,
    1832             :                                                (SQLWCHAR *) origptr,
    1833           0 :                                                origbuflen / sizeof(SQLWCHAR),
    1834             :                                                &n, &i);
    1835           0 :                                 free(ptr);
    1836             :                         } else {
    1837         391 :                                 ODBCutf82wchar((SQLCHAR *) data, SQL_NTS,
    1838             :                                                (SQLWCHAR *) origptr,
    1839         391 :                                                origbuflen / sizeof(SQLWCHAR),
    1840             :                                                &n, &i);
    1841             :                         }
    1842             : #ifdef ODBCDEBUG
    1843         391 :                         ODBCLOG("Writing %d bytes to %p\n",
    1844             :                                 (int) (n * sizeof(SQLWCHAR)),
    1845             :                                 origptr);
    1846             : #endif
    1847             : 
    1848         391 :                         if (origlenp)
    1849         391 :                                 *origlenp = n * sizeof(SQLWCHAR); /* # of bytes, not chars */
    1850         391 :                         irdrec->already_returned -= datalen;
    1851         391 :                         irdrec->already_returned += i;
    1852         391 :                         if (i < datalen) {
    1853             :                                 /* String data, right-truncated */
    1854           6 :                                 addStmtError(stmt, "01004", NULL, 0);
    1855             :                         }
    1856             :                 }
    1857             : #ifdef ODBCDEBUG
    1858             :                 else
    1859        5853 :                         ODBCLOG("Writing %zu bytes to %p\n", strlen(ptr), ptr);
    1860             : #endif
    1861       15340 :                 break;
    1862             :         }
    1863           2 :         case SQL_C_BINARY: {
    1864           2 :                 if (buflen < 0) {
    1865             :                         /* Invalid string or buffer length */
    1866           0 :                         addStmtError(stmt, "HY090", NULL, 0);
    1867           0 :                         return SQL_ERROR;
    1868             :                 }
    1869           2 :                 if (ardrec && row > 0)
    1870           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? ardrec->sql_desc_octet_length : bind_type));
    1871             : 
    1872           2 :                 switch (sql_type) {
    1873           0 :                 case SQL_CHAR:
    1874             :                 case SQL_VARCHAR:
    1875             :                 case SQL_WCHAR:
    1876             :                 case SQL_WVARCHAR:
    1877             :                 case SQL_DECIMAL:
    1878             :                 case SQL_NUMERIC:
    1879             :                 case SQL_TINYINT:
    1880             :                 case SQL_SMALLINT:
    1881             :                 case SQL_INTEGER:
    1882             :                 case SQL_BIGINT:
    1883             :                 case SQL_HUGEINT:
    1884             :                 case SQL_REAL:
    1885             :                 case SQL_DOUBLE:
    1886             :                 case SQL_FLOAT:
    1887             :                 case SQL_BIT:
    1888             :                 case SQL_TYPE_DATE:
    1889             :                 case SQL_TYPE_TIME:
    1890             :                 case SQL_TYPE_TIMESTAMP:
    1891             :                 case SQL_INTERVAL_YEAR:
    1892             :                 case SQL_INTERVAL_YEAR_TO_MONTH:
    1893             :                 case SQL_INTERVAL_MONTH:
    1894             :                 case SQL_INTERVAL_DAY:
    1895             :                 case SQL_INTERVAL_DAY_TO_HOUR:
    1896             :                 case SQL_INTERVAL_DAY_TO_MINUTE:
    1897             :                 case SQL_INTERVAL_DAY_TO_SECOND:
    1898             :                 case SQL_INTERVAL_HOUR:
    1899             :                 case SQL_INTERVAL_HOUR_TO_MINUTE:
    1900             :                 case SQL_INTERVAL_HOUR_TO_SECOND:
    1901             :                 case SQL_INTERVAL_MINUTE:
    1902             :                 case SQL_INTERVAL_MINUTE_TO_SECOND:
    1903             :                 case SQL_INTERVAL_SECOND:
    1904             :                 default:
    1905             :                         /* Restricted data type attribute violation */
    1906           0 :                         addStmtError(stmt, "07006", NULL, 0);
    1907           0 :                         return SQL_ERROR;
    1908             :                 case SQL_BINARY:
    1909             :                 case SQL_VARBINARY:
    1910             :                 case SQL_LONGVARBINARY:
    1911           2 :                         break;
    1912             :                 }
    1913           2 :                 if (irdrec->already_returned < 0)
    1914           2 :                         irdrec->already_returned = 0;
    1915           0 :                 else if ((size_t) irdrec->already_returned >= datalen) {
    1916             :                         /* no more data to return */
    1917             :                         return SQL_NO_DATA;
    1918             :                 }
    1919           2 :                 data += irdrec->already_returned;
    1920           2 :                 datalen -= irdrec->already_returned;
    1921             : 
    1922           2 :                 size_t k;
    1923           2 :                 SQLLEN j;
    1924           2 :                 unsigned char *p = ptr;
    1925             : 
    1926          84 :                 for (k = 0, j = 0; k < datalen && j < buflen; k++) {
    1927          82 :                         unsigned int n;
    1928             : 
    1929          82 :                         if (isdigit((unsigned char) data[k]))
    1930          43 :                                 n = data[k] - '0';
    1931          39 :                         else if ('A' <= data[k] && data[k] <= 'F')
    1932          39 :                                 n = data[k] - 'A' + 10;
    1933           0 :                         else if ('a' <= data[k] && data[k] <= 'f')
    1934           0 :                                 n = data[k] - 'a' + 10;
    1935             :                         else {
    1936             :                                 /* should not happen: not a hex character */
    1937             :                                 /* General error */
    1938           0 :                                 addStmtError(stmt, "HY000", "Unexpected data from server", 0);
    1939           0 :                                 if (type == SQL_C_WCHAR)
    1940             :                                         free(ptr);
    1941           0 :                                 return SQL_ERROR;
    1942             :                         }
    1943          82 :                         if (k & 1) {
    1944          41 :                                 p[j] |= n;
    1945          41 :                                 j++;
    1946             :                         } else {
    1947          41 :                                 p[j] = n << 4;
    1948             :                         }
    1949             :                 }
    1950           2 :                 if (k & 1) {
    1951             :                         /* should not happen: uneven length */
    1952             :                         /* General error */
    1953           0 :                         addStmtError(stmt, "HY000", "Unexpected data from server", 0);
    1954           0 :                         if (type == SQL_C_WCHAR)
    1955             :                                 free(ptr);
    1956           0 :                         return SQL_ERROR;
    1957             :                 }
    1958           2 :                 irdrec->already_returned += k;
    1959           2 :                 if (lenp)
    1960           2 :                         *lenp = datalen / 2;
    1961           2 :                 if (k < datalen) {
    1962             :                         /* String data, right-truncated */
    1963           0 :                         addStmtError(stmt, "01004", NULL, 0);
    1964             :                 }
    1965             :                 break;
    1966             :         }
    1967         147 :         case SQL_C_BIT:
    1968         147 :                 if (ardrec && row > 0)
    1969           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(unsigned char) : bind_type));
    1970             : 
    1971         147 :                 if (lenp)
    1972         147 :                         *lenp = 1;
    1973         147 :                 switch (sql_type) {
    1974           0 :                 case SQL_CHAR:
    1975             :                 case SQL_VARCHAR:
    1976             :                 case SQL_WCHAR:
    1977             :                 case SQL_WVARCHAR:
    1978           0 :                         if (!parsedouble(data, &fval)) {
    1979             :                                 /* Invalid character value for cast
    1980             :                                    specification */
    1981           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    1982           0 :                                 return SQL_ERROR;
    1983             :                         }
    1984             :                         /* fall through */
    1985             :                 case SQL_REAL:
    1986             :                 case SQL_DOUBLE:
    1987             :                 case SQL_FLOAT:
    1988           0 :                         if (fval < 0 || fval >= 2) {
    1989             :                                 /* Numeric value out of range */
    1990           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    1991           0 :                                 return SQL_ERROR;
    1992             :                         }
    1993           0 :                         WriteData(ptr, fval >= 1, unsigned char);
    1994             : 
    1995           0 :                         if (fval != 0 && fval != 1) {
    1996             :                                 /* Fractional truncation */
    1997           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    1998             :                         }
    1999             :                         break;
    2000         147 :                 case SQL_DECIMAL:
    2001             :                 case SQL_NUMERIC:
    2002             :                 case SQL_TINYINT:
    2003             :                 case SQL_SMALLINT:
    2004             :                 case SQL_INTEGER:
    2005             :                 case SQL_BIGINT:
    2006             :                 case SQL_HUGEINT:
    2007             :                 case SQL_BIT: {
    2008         147 :                         int truncated = nval.scale > 0;
    2009             : 
    2010         147 :                         while (nval.scale > 0) {
    2011           0 :                                 nval.val /= 10;
    2012           0 :                                 nval.scale--;
    2013             :                         }
    2014             :                         /* -0 is ok, but -1 or -0.5 isn't */
    2015         147 :                         if (nval.val > 1 || (!nval.sign && (nval.val == 1 || truncated))) {
    2016             :                                 /* Numeric value out of range */
    2017           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    2018           0 :                                 return SQL_ERROR;
    2019             :                         }
    2020         147 :                         WriteData(ptr, (unsigned char) nval.val, unsigned char);
    2021             : 
    2022         147 :                         if (truncated) {
    2023             :                                 /* Fractional truncation */
    2024           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2025             :                         }
    2026             :                         break;
    2027             :                 }
    2028           0 :                 default:
    2029             :                         /* Restricted data type attribute violation */
    2030           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2031           0 :                         return SQL_ERROR;
    2032             :                 }
    2033             :                 break;
    2034        2887 :         case SQL_C_STINYINT:
    2035             :         case SQL_C_TINYINT:
    2036             :         case SQL_C_SSHORT:
    2037             :         case SQL_C_SHORT:
    2038             :         case SQL_C_SLONG:
    2039             :         case SQL_C_LONG:
    2040             :         case SQL_C_SBIGINT: {
    2041        2887 :                 uint64_t maxval = 1;
    2042             : 
    2043        2887 :                 switch (type) {
    2044           3 :                 case SQL_C_STINYINT:
    2045             :                 case SQL_C_TINYINT:
    2046           3 :                         maxval <<= 7;
    2047           3 :                         if (lenp)
    2048           3 :                                 *lenp = sizeof(signed char);
    2049           3 :                         if (ardrec && row > 0)
    2050           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(signed char) : bind_type));
    2051             :                         break;
    2052        2013 :                 case SQL_C_SSHORT:
    2053             :                 case SQL_C_SHORT:
    2054        2013 :                         maxval <<= 15;
    2055        2013 :                         if (lenp)
    2056           3 :                                 *lenp = sizeof(short);
    2057        2013 :                         if (ardrec && row > 0)
    2058           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(short) : bind_type));
    2059             :                         break;
    2060         868 :                 case SQL_C_SLONG:
    2061             :                 case SQL_C_LONG:
    2062         868 :                         maxval <<= 31;
    2063         868 :                         if (lenp)
    2064         864 :                                 *lenp = sizeof(int);
    2065         868 :                         if (ardrec && row > 0)
    2066           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(int) : bind_type));
    2067             :                         break;
    2068           3 :                 case SQL_C_SBIGINT:
    2069           3 :                         maxval <<= 63;
    2070           3 :                         if (lenp)
    2071           3 :                                 *lenp = sizeof(SQLBIGINT);
    2072           3 :                         if (ardrec && row > 0)
    2073           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQLBIGINT) : bind_type));
    2074             :                         break;
    2075             :                 }
    2076        2887 :                 switch (sql_type) {
    2077           0 :                 case SQL_CHAR:
    2078             :                 case SQL_VARCHAR:
    2079             :                 case SQL_WCHAR:
    2080             :                 case SQL_WVARCHAR:
    2081             :                 case SQL_DOUBLE:
    2082             :                 case SQL_FLOAT:
    2083             :                 case SQL_REAL:
    2084             :                         /* reparse double and float, parse char */
    2085           0 :                         if (!parseint(data, &nval)) {
    2086             :                                 /* Invalid character value for cast
    2087             :                                  * specification */
    2088           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2089           0 :                                 return SQL_ERROR;
    2090             :                         }
    2091             :                         /* fall through */
    2092             :                 case SQL_DECIMAL:
    2093             :                 case SQL_NUMERIC:
    2094             :                 case SQL_TINYINT:
    2095             :                 case SQL_SMALLINT:
    2096             :                 case SQL_INTEGER:
    2097             :                 case SQL_BIGINT:
    2098             :                 case SQL_HUGEINT:
    2099             :                 case SQL_BIT: {
    2100        2887 :                         int truncated = nval.scale > 0;
    2101             : 
    2102             :                         /* scale is normalized, so if negative, number
    2103             :                          * is too large even for SQLUBIGINT */
    2104        2887 :                         while (nval.scale > 0) {
    2105           0 :                                 nval.val /= 10;
    2106           0 :                                 nval.scale--;
    2107             :                         }
    2108        2887 :                         if (nval.scale < 0 || nval.val > maxval || (nval.val == maxval && nval.sign)) {
    2109             :                                 /* Numeric value out of range */
    2110           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    2111           0 :                                 return SQL_ERROR;
    2112             :                         }
    2113        2887 :                         if (truncated) {
    2114             :                                 /* Fractional truncation */
    2115           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2116             :                         }
    2117             : 
    2118        2887 :                         switch (type) {
    2119           3 :                         case SQL_C_STINYINT:
    2120             :                         case SQL_C_TINYINT:
    2121           3 :                                 WriteData(ptr, nval.sign ? (signed char) nval.val : -(signed char) nval.val, signed char);
    2122           3 :                                 break;
    2123        2013 :                         case SQL_C_SSHORT:
    2124             :                         case SQL_C_SHORT:
    2125        2013 :                                 WriteData(ptr, nval.sign ? (short) nval.val : -(short) nval.val, short);
    2126        2013 :                                 break;
    2127         868 :                         case SQL_C_SLONG:
    2128             :                         case SQL_C_LONG:
    2129         868 :                                 WriteData(ptr, nval.sign ? (int) nval.val : -(int) nval.val, int);
    2130         868 :                                 break;
    2131           3 :                         case SQL_C_SBIGINT:
    2132           3 :                                 WriteData(ptr, nval.sign ? (SQLBIGINT) nval.val : -(SQLBIGINT) nval.val, SQLBIGINT);
    2133           3 :                                 break;
    2134             :                         }
    2135             :                         break;
    2136             :                 }
    2137           0 :                 default:
    2138             :                         /* Restricted data type attribute violation */
    2139           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2140           0 :                         return SQL_ERROR;
    2141             :                 }
    2142             :                 break;
    2143             :         }
    2144           0 :         case SQL_C_UTINYINT:
    2145             :         case SQL_C_USHORT:
    2146             :         case SQL_C_ULONG:
    2147             :         case SQL_C_UBIGINT: {
    2148           0 :                 uint64_t maxval = 1;
    2149             : 
    2150           0 :                 switch (type) {
    2151           0 :                 case SQL_C_UTINYINT:
    2152           0 :                         maxval <<= 8;
    2153           0 :                         if (lenp)
    2154           0 :                                 *lenp = sizeof(unsigned char);
    2155           0 :                         if (ardrec && row > 0)
    2156           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(unsigned char) : bind_type));
    2157             :                         break;
    2158           0 :                 case SQL_C_USHORT:
    2159           0 :                         maxval <<= 16;
    2160           0 :                         if (lenp)
    2161           0 :                                 *lenp = sizeof(unsigned short);
    2162           0 :                         if (ardrec && row > 0)
    2163           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(unsigned short) : bind_type));
    2164             :                         break;
    2165           0 :                 case SQL_C_ULONG:
    2166           0 :                         maxval <<= 32;
    2167           0 :                         if (lenp)
    2168           0 :                                 *lenp = sizeof(unsigned int);
    2169           0 :                         if (ardrec && row > 0)
    2170           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(unsigned int) : bind_type));
    2171             :                         break;
    2172           0 :                 case SQL_C_UBIGINT:
    2173           0 :                         if (lenp)
    2174           0 :                                 *lenp = sizeof(SQLUBIGINT);
    2175           0 :                         if (ardrec && row > 0)
    2176           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQLUBIGINT) : bind_type));
    2177             :                         break;
    2178             :                 }
    2179           0 :                 maxval--;
    2180           0 :                 switch (sql_type) {
    2181           0 :                 case SQL_CHAR:
    2182             :                 case SQL_VARCHAR:
    2183             :                 case SQL_WCHAR:
    2184             :                 case SQL_WVARCHAR:
    2185             :                 case SQL_DOUBLE:
    2186             :                 case SQL_FLOAT:
    2187             :                 case SQL_REAL:
    2188             :                         /* reparse double and float, parse char */
    2189           0 :                         if (!parseint(data, &nval)) {
    2190             :                                 /* Invalid character value for cast
    2191             :                                  * specification */
    2192           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2193           0 :                                 return SQL_ERROR;
    2194             :                         }
    2195             :                         /* fall through */
    2196             :                 case SQL_DECIMAL:
    2197             :                 case SQL_NUMERIC:
    2198             :                 case SQL_TINYINT:
    2199             :                 case SQL_SMALLINT:
    2200             :                 case SQL_INTEGER:
    2201             :                 case SQL_BIGINT:
    2202             :                 case SQL_HUGEINT:
    2203             :                 case SQL_BIT: {
    2204           0 :                         int truncated = nval.scale > 0;
    2205             : 
    2206             :                         /* scale is normalized, so if negative, number
    2207             :                          * is too large even for SQLUBIGINT */
    2208           0 :                         while (nval.scale > 0) {
    2209           0 :                                 nval.val /= 10;
    2210           0 :                                 nval.scale--;
    2211             :                         }
    2212           0 :                         if (nval.scale < 0 || !nval.sign || (maxval != 0 && nval.val >= maxval)) {
    2213             :                                 /* Numeric value out of range */
    2214           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    2215           0 :                                 return SQL_ERROR;
    2216             :                         }
    2217           0 :                         if (truncated) {
    2218             :                                 /* Fractional truncation */
    2219           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2220             :                         }
    2221             : 
    2222           0 :                         switch (type) {
    2223           0 :                         case SQL_C_UTINYINT:
    2224           0 :                                 WriteData(ptr, (unsigned char) nval.val, unsigned char);
    2225           0 :                                 break;
    2226           0 :                         case SQL_C_USHORT:
    2227           0 :                                 WriteData(ptr, (unsigned short) nval.val, unsigned short);
    2228           0 :                                 break;
    2229           0 :                         case SQL_C_ULONG:
    2230           0 :                                 WriteData(ptr, (unsigned int) nval.val, unsigned int);
    2231           0 :                                 break;
    2232           0 :                         case SQL_C_UBIGINT:
    2233           0 :                                 WriteData(ptr, (SQLUBIGINT) nval.val, SQLUBIGINT);
    2234           0 :                                 break;
    2235             :                         }
    2236             :                         break;
    2237             :                 }
    2238           0 :                 default:
    2239             :                         /* Restricted data type attribute violation */
    2240           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2241           0 :                         return SQL_ERROR;
    2242             :                 }
    2243             :                 break;
    2244             :         }
    2245           0 :         case SQL_C_NUMERIC:
    2246           0 :                 if (ardrec && row > 0)
    2247           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQL_NUMERIC_STRUCT) : bind_type));
    2248             : 
    2249           0 :                 switch (sql_type) {
    2250           0 :                 case SQL_CHAR:
    2251             :                 case SQL_VARCHAR:
    2252             :                 case SQL_WCHAR:
    2253             :                 case SQL_WVARCHAR:
    2254             :                 case SQL_DOUBLE:
    2255             :                 case SQL_FLOAT:
    2256             :                 case SQL_REAL:
    2257             :                         /* reparse double and float, parse char */
    2258           0 :                         if (!(i = parseint(data, &nval))) {
    2259             :                                 /* Invalid character value for cast
    2260             :                                  * specification */
    2261           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2262           0 :                                 return SQL_ERROR;
    2263             :                         }
    2264           0 :                         if (i == 2) {
    2265             :                                 /* Fractional truncation */
    2266           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2267             :                         }
    2268             : 
    2269             :                         /* fall through */
    2270             :                 case SQL_DECIMAL:
    2271             :                 case SQL_NUMERIC:
    2272             :                 case SQL_TINYINT:
    2273             :                 case SQL_SMALLINT:
    2274             :                 case SQL_INTEGER:
    2275             :                 case SQL_BIGINT:
    2276             :                 case SQL_HUGEINT:
    2277             :                 case SQL_BIT:
    2278           0 :                         while (nval.precision > precision) {
    2279           0 :                                 nval.val /= 10;
    2280           0 :                                 nval.scale--;
    2281           0 :                                 nval.precision--;
    2282             :                         }
    2283           0 :                         while (nval.scale < scale) {
    2284           0 :                                 nval.val *= 10;
    2285           0 :                                 nval.scale++;
    2286             :                         }
    2287           0 :                         while (nval.scale > scale) {
    2288           0 :                                 nval.val /= 10;
    2289           0 :                                 nval.scale--;
    2290           0 :                                 nval.precision--;
    2291             :                         }
    2292           0 :                         nmval = (SQL_NUMERIC_STRUCT) {
    2293           0 :                                 .precision = nval.precision,
    2294             :                                 .scale = nval.scale,
    2295           0 :                                 .sign = nval.sign,
    2296             :                         };
    2297           0 :                         for (i = 0; i < SQL_MAX_NUMERIC_LEN; i++) {
    2298           0 :                                 nmval.val[i] = (SQLCHAR) (nval.val & 0xFF);
    2299           0 :                                 nval.val >>= 8;
    2300             :                         }
    2301           0 :                         WriteData(ptr, nmval, SQL_NUMERIC_STRUCT);
    2302           0 :                         if (lenp)
    2303           0 :                                 *lenp = sizeof(SQL_NUMERIC_STRUCT);
    2304             :                         break;
    2305           0 :                 default:
    2306             :                         /* Restricted data type attribute violation */
    2307           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2308           0 :                         return SQL_ERROR;
    2309             :                 }
    2310             :                 break;
    2311        2006 :         case SQL_C_FLOAT:
    2312             :         case SQL_C_DOUBLE:
    2313        2006 :                 switch (sql_type) {
    2314           0 :                 case SQL_CHAR:
    2315             :                 case SQL_VARCHAR:
    2316             :                 case SQL_WCHAR:
    2317             :                 case SQL_WVARCHAR:
    2318           0 :                         if (!parsedouble(data, &fval)) {
    2319             :                                 /* Invalid character value for cast
    2320             :                                  * specification */
    2321           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2322           0 :                                 return SQL_ERROR;
    2323             :                         }
    2324             :                         break;
    2325             :                 case SQL_DOUBLE:
    2326             :                 case SQL_FLOAT:
    2327             :                 case SQL_REAL:
    2328             :                         break;
    2329           0 :                 case SQL_DECIMAL:
    2330             :                 case SQL_NUMERIC:
    2331             :                 case SQL_TINYINT:
    2332             :                 case SQL_SMALLINT:
    2333             :                 case SQL_INTEGER:
    2334             :                 case SQL_BIGINT:
    2335             :                 case SQL_HUGEINT:
    2336             :                 case SQL_BIT:
    2337           0 :                         fval = (double) (int64_t) nval.val;
    2338           0 :                         i = 1;
    2339           0 :                         while (nval.scale > 0) {
    2340           0 :                                 nval.scale--;
    2341           0 :                                 i *= 10;
    2342             :                         }
    2343           0 :                         fval /= (double) i;
    2344           0 :                         i = 1;
    2345           0 :                         while (nval.scale < 0) {
    2346           0 :                                 nval.scale++;
    2347           0 :                                 i *= 10;
    2348             :                         }
    2349           0 :                         fval *= (double) i;
    2350           0 :                         if (!nval.sign)
    2351           0 :                                 fval = -fval;
    2352             :                         break;
    2353           0 :                 default:
    2354             :                         /* Restricted data type attribute violation */
    2355           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2356           0 :                         return SQL_ERROR;
    2357             :                 }
    2358        2006 :                 if (type == SQL_C_FLOAT) {
    2359           3 :                         if (ardrec && row > 0)
    2360           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(float) : bind_type));
    2361           3 :                         if (fval < -FLT_MAX || fval > FLT_MAX) {
    2362             :                                 /* Numeric value out of range */
    2363           0 :                                 addStmtError(stmt, "22003", NULL, 0);
    2364           0 :                                 return SQL_ERROR;
    2365             :                         }
    2366           3 :                         WriteData(ptr, (float) fval, float);
    2367           3 :                         if (lenp)
    2368           3 :                                 *lenp = sizeof(float);
    2369             :                 } else {
    2370        2003 :                         if (ardrec && row > 0)
    2371           0 :                                 ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(double) : bind_type));
    2372        2003 :                         WriteData(ptr, fval, double);
    2373             : 
    2374        2003 :                         if (lenp)
    2375           3 :                                 *lenp = sizeof(double);
    2376             :                 }
    2377             :                 break;
    2378        2003 :         case SQL_C_TYPE_DATE:
    2379        2003 :                 if (ardrec && row > 0)
    2380           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(DATE_STRUCT) : bind_type));
    2381             : 
    2382        2003 :                 i = 1;
    2383        2003 :                 switch (sql_type) {
    2384           0 :                 case SQL_CHAR:
    2385             :                 case SQL_VARCHAR:
    2386             :                 case SQL_WCHAR:
    2387             :                 case SQL_WVARCHAR:
    2388           0 :                         i = parsetimestamp(data, &tsval);
    2389             :                         /* fall through */
    2390             :                 case SQL_TYPE_TIMESTAMP:        /* note i==1 unless we fell through */
    2391           0 :                         if (i) {
    2392           0 :                                 if (tsval.hour || tsval.minute || tsval.second || tsval.fraction || i == 2) {
    2393             :                                         /* Fractional truncation */
    2394           0 :                                         addStmtError(stmt, "01S07", NULL, 0);
    2395             :                                 }
    2396           0 :                                 dval = (DATE_STRUCT) {
    2397           0 :                                         .year = tsval.year,
    2398           0 :                                         .month = tsval.month,
    2399           0 :                                         .day = tsval.day,
    2400             :                                 };
    2401           0 :                         } else if (!parsedate(data, &dval)) {
    2402             :                                 /* Invalid character value for cast
    2403             :                                  * specification */
    2404           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2405           0 :                                 return SQL_ERROR;
    2406             :                         }
    2407             :                         /* fall through */
    2408             :                 case SQL_TYPE_DATE:
    2409        2003 :                         WriteData(ptr, dval, DATE_STRUCT);
    2410        2003 :                         break;
    2411           0 :                 default:
    2412             :                         /* Restricted data type attribute violation */
    2413           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2414           0 :                         return SQL_ERROR;
    2415             :                 }
    2416        2003 :                 if (lenp)
    2417           3 :                         *lenp = sizeof(DATE_STRUCT);
    2418             :                 break;
    2419        2003 :         case SQL_C_TYPE_TIME:
    2420        2003 :                 if (ardrec && row > 0)
    2421           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(TIME_STRUCT) : bind_type));
    2422             : 
    2423        2003 :                 i = 1;
    2424        2003 :                 switch (sql_type) {
    2425           0 :                 case SQL_CHAR:
    2426             :                 case SQL_VARCHAR:
    2427             :                 case SQL_WCHAR:
    2428             :                 case SQL_WVARCHAR:
    2429           0 :                         i = parsetimestamp(data, &tsval);
    2430             :                         /* fall through */
    2431             :                 case SQL_TYPE_TIMESTAMP:        /* note i==1 unless we fell through */
    2432           0 :                         if (i) {
    2433           0 :                                 if (tsval.fraction || i == 2) {
    2434             :                                         /* Fractional truncation */
    2435           0 :                                         addStmtError(stmt, "01S07", NULL, 0);
    2436             :                                 }
    2437           0 :                                 tval.hour = tsval.hour;
    2438           0 :                                 tval.minute = tsval.minute;
    2439           0 :                                 tval.second = tsval.second;
    2440           0 :                         } else if (!parsetime(data, &tval)) {
    2441             :                                 /* Invalid character value for cast
    2442             :                                  * specification */
    2443           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2444           0 :                                 return SQL_ERROR;
    2445             :                         }
    2446             :                         /* fall through */
    2447             :                 case SQL_TYPE_TIME:
    2448        2003 :                         WriteData(ptr, tval, TIME_STRUCT);
    2449        2003 :                         break;
    2450           0 :                 default:
    2451             :                         /* Restricted data type attribute violation */
    2452           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2453           0 :                         return SQL_ERROR;
    2454             :                 }
    2455        2003 :                 if (lenp)
    2456           3 :                         *lenp = sizeof(TIME_STRUCT);
    2457             :                 break;
    2458           3 :         case SQL_C_TYPE_TIMESTAMP:
    2459           3 :                 if (ardrec && row > 0)
    2460           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(TIMESTAMP_STRUCT) : bind_type));
    2461             : 
    2462           3 :                 i = 1;
    2463           3 :                 switch (sql_type) {
    2464           0 :                 case SQL_CHAR:
    2465             :                 case SQL_VARCHAR:
    2466             :                 case SQL_WCHAR:
    2467             :                 case SQL_WVARCHAR:
    2468           0 :                         i = parsetimestamp(data, &tsval);
    2469           0 :                         if (i == 0) {
    2470           0 :                                 i = parsetime(data, &tval);
    2471           0 :                                 if (i) {
    2472           0 :                                         struct tm tm;
    2473           0 :                                         time_t t;
    2474             : 
    2475             :                 case SQL_TYPE_TIME:
    2476           0 :                                         (void) time(&t);
    2477           0 :                                         tm = (struct tm) {0};
    2478             : #ifdef HAVE_LOCALTIME_R
    2479           0 :                                         (void) localtime_r(&t, &tm);
    2480             : #else
    2481             :                                         tm = *localtime(&t);
    2482             : #endif
    2483           0 :                                         tsval = (TIMESTAMP_STRUCT) {
    2484           0 :                                                 .year = tm.tm_year + 1900,
    2485           0 :                                                 .month = tm.tm_mon + 1,
    2486           0 :                                                 .day = tm.tm_mday,
    2487           0 :                                                 .hour = tval.hour,
    2488           0 :                                                 .minute = tval.minute,
    2489           0 :                                                 .second = tval.second,
    2490             :                                                 .fraction = 0,
    2491             :                                         };
    2492             :                                 } else {
    2493           0 :                                         i = parsedate(data, &dval);
    2494           0 :                                         if (i) {
    2495             :                 case SQL_TYPE_DATE:
    2496           0 :                                                 tsval = (TIMESTAMP_STRUCT) {
    2497           0 :                                                         .year = dval.year,
    2498           0 :                                                         .month = dval.month,
    2499           0 :                                                         .day = dval.day,
    2500             :                                                         .hour = 0,
    2501             :                                                         .minute = 0,
    2502             :                                                         .second = 0,
    2503             :                                                         .fraction = 0,
    2504             :                                                 };
    2505             :                                         } else {
    2506             :                                                 /* Invalid character
    2507             :                                                  * value for cast
    2508             :                                                  * specification */
    2509           0 :                                                 addStmtError(stmt, "22018", NULL, 0);
    2510           0 :                                                 return SQL_ERROR;
    2511             :                                         }
    2512             :                                 }
    2513             :                         }
    2514             :                         /* fall through */
    2515             :                 case SQL_TYPE_TIMESTAMP:        /* note i==1 unless we fell through */
    2516           3 :                         WriteData(ptr, tsval, TIMESTAMP_STRUCT);
    2517           3 :                         break;
    2518           0 :                 default:
    2519             :                         /* Restricted data type attribute violation */
    2520           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2521           0 :                         return SQL_ERROR;
    2522             :                 }
    2523           3 :                 if (lenp)
    2524           3 :                         *lenp = sizeof(TIMESTAMP_STRUCT);
    2525             :                 break;
    2526           9 :         case SQL_C_INTERVAL_YEAR:
    2527             :         case SQL_C_INTERVAL_MONTH:
    2528             :         case SQL_C_INTERVAL_YEAR_TO_MONTH:
    2529           9 :                 if (ardrec && row > 0)
    2530           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQL_INTERVAL_STRUCT) : bind_type));
    2531             : 
    2532           9 :                 switch (sql_type) {
    2533           0 :                 case SQL_CHAR:
    2534             :                 case SQL_VARCHAR:
    2535             :                 case SQL_WCHAR:
    2536             :                 case SQL_WVARCHAR:
    2537           0 :                         if (parsemonthintervalstring(&data, NULL, &ival) == SQL_ERROR) {
    2538             :                                 /* Invalid character value for cast
    2539             :                                  * specification */
    2540           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2541           0 :                                 return SQL_ERROR;
    2542             :                         }
    2543             :                         break;
    2544           0 :                 case SQL_DECIMAL:
    2545             :                 case SQL_NUMERIC:
    2546             :                 case SQL_TINYINT:
    2547             :                 case SQL_SMALLINT:
    2548             :                 case SQL_INTEGER:
    2549             :                 case SQL_BIGINT:
    2550             :                 case SQL_HUGEINT:
    2551           0 :                         parsemonthinterval(&nval, &ival, type);
    2552           0 :                         break;
    2553             :                 case SQL_INTERVAL_YEAR:
    2554             :                 case SQL_INTERVAL_YEAR_TO_MONTH:
    2555             :                 case SQL_INTERVAL_MONTH:
    2556             :                         break;
    2557           0 :                 default:
    2558             :                         /* Restricted data type attribute violation */
    2559           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2560           0 :                         return SQL_ERROR;
    2561             :                 }
    2562           9 :                 ivval = (SQL_INTERVAL_STRUCT) {
    2563           9 :                         .interval_sign = ival.interval_sign,
    2564             :                         .intval.year_month.year = 0,
    2565             :                         .intval.year_month.month = 0,
    2566             :                 };
    2567           9 :                 switch (type) {
    2568           3 :                 case SQL_C_INTERVAL_YEAR:
    2569           3 :                         ivval.interval_type = SQL_IS_YEAR;
    2570           3 :                         if ((ivval.intval.year_month.year = ival.intval.year_month.year) >= maxdatetimeval) {
    2571             :                                 /* Interval field overflow */
    2572           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2573           0 :                                 return SQL_ERROR;
    2574             :                         }
    2575           3 :                         if (ival.intval.year_month.month) {
    2576             :                                 /* Fractional truncation */
    2577           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2578             :                         }
    2579             :                         break;
    2580           3 :                 case SQL_C_INTERVAL_MONTH:
    2581           3 :                         ivval.interval_type = SQL_IS_MONTH;
    2582           3 :                         if ((ivval.intval.year_month.month = ival.intval.year_month.month + 12 * ival.intval.year_month.year) >= maxdatetimeval) {
    2583             :                                 /* Interval field overflow */
    2584           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2585           0 :                                 return SQL_ERROR;
    2586             :                         }
    2587             :                         break;
    2588           3 :                 case SQL_C_INTERVAL_YEAR_TO_MONTH:
    2589           3 :                         ivval.interval_type = SQL_IS_YEAR_TO_MONTH;
    2590           3 :                         if ((ivval.intval.year_month.year = ival.intval.year_month.year) >= maxdatetimeval) {
    2591             :                                 /* Interval field overflow */
    2592           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2593           0 :                                 return SQL_ERROR;
    2594             :                         }
    2595           3 :                         ivval.intval.year_month.month = ival.intval.year_month.month;
    2596           3 :                         break;
    2597             :                 }
    2598           9 :                 WriteData(ptr, ivval, SQL_INTERVAL_STRUCT);
    2599           9 :                 if (lenp)
    2600           9 :                         *lenp = sizeof(SQL_INTERVAL_STRUCT);
    2601             :                 break;
    2602          32 :         case SQL_C_INTERVAL_DAY:
    2603             :         case SQL_C_INTERVAL_HOUR:
    2604             :         case SQL_C_INTERVAL_MINUTE:
    2605             :         case SQL_C_INTERVAL_SECOND:
    2606             :         case SQL_C_INTERVAL_DAY_TO_HOUR:
    2607             :         case SQL_C_INTERVAL_DAY_TO_MINUTE:
    2608             :         case SQL_C_INTERVAL_DAY_TO_SECOND:
    2609             :         case SQL_C_INTERVAL_HOUR_TO_MINUTE:
    2610             :         case SQL_C_INTERVAL_HOUR_TO_SECOND:
    2611             :         case SQL_C_INTERVAL_MINUTE_TO_SECOND:
    2612          32 :                 if (ardrec && row > 0)
    2613           0 :                         ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQL_INTERVAL_STRUCT) : bind_type));
    2614             : 
    2615          32 :                 switch (sql_type) {
    2616           0 :                 case SQL_CHAR:
    2617             :                 case SQL_VARCHAR:
    2618             :                 case SQL_WCHAR:
    2619             :                 case SQL_WVARCHAR:
    2620           0 :                         if (parsesecondintervalstring(&data, NULL, &ival, &ivalprec) == SQL_ERROR) {
    2621             :                                 /* Invalid character value for cast
    2622             :                                  * specification */
    2623           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    2624           0 :                                 return SQL_ERROR;
    2625             :                         }
    2626             :                         break;
    2627           0 :                 case SQL_DECIMAL:
    2628             :                 case SQL_NUMERIC:
    2629             :                 case SQL_TINYINT:
    2630             :                 case SQL_SMALLINT:
    2631             :                 case SQL_INTEGER:
    2632             :                 case SQL_BIGINT:
    2633             :                 case SQL_HUGEINT:
    2634           0 :                         ivalprec = parsesecondinterval(&nval, &ival, type);
    2635           0 :                         break;
    2636             :                 case SQL_INTERVAL_DAY:
    2637             :                 case SQL_INTERVAL_DAY_TO_HOUR:
    2638             :                 case SQL_INTERVAL_DAY_TO_MINUTE:
    2639             :                 case SQL_INTERVAL_DAY_TO_SECOND:
    2640             :                 case SQL_INTERVAL_HOUR:
    2641             :                 case SQL_INTERVAL_HOUR_TO_MINUTE:
    2642             :                 case SQL_INTERVAL_HOUR_TO_SECOND:
    2643             :                 case SQL_INTERVAL_MINUTE:
    2644             :                 case SQL_INTERVAL_MINUTE_TO_SECOND:
    2645             :                 case SQL_INTERVAL_SECOND:
    2646             :                         break;
    2647           0 :                 default:
    2648             :                         /* Restricted data type attribute violation */
    2649           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2650           0 :                         return SQL_ERROR;
    2651             :                 }
    2652          32 :                 ivval = (SQL_INTERVAL_STRUCT) {
    2653          32 :                         .interval_sign = ival.interval_sign,
    2654             :                         .intval.day_second.day = 0,
    2655             :                         .intval.day_second.hour = 0,
    2656             :                         .intval.day_second.minute = 0,
    2657             :                         .intval.day_second.second = 0,
    2658             :                         .intval.day_second.fraction = 0,
    2659             :                 };
    2660          32 :                 switch (type) {
    2661           5 :                 case SQL_C_INTERVAL_DAY:
    2662           5 :                         ivval.interval_type = SQL_IS_DAY;
    2663           5 :                         if ((ivval.intval.day_second.day = ival.intval.day_second.day) >= maxdatetimeval) {
    2664             :                                 /* Interval field overflow */
    2665           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2666           0 :                                 return SQL_ERROR;
    2667             :                         }
    2668           5 :                         if (ival.intval.day_second.hour || ival.intval.day_second.minute || ival.intval.day_second.second || ival.intval.day_second.fraction) {
    2669             :                                 /* Fractional truncation */
    2670           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2671             :                         }
    2672             :                         break;
    2673           3 :                 case SQL_C_INTERVAL_HOUR:
    2674           3 :                         ivval.interval_type = SQL_IS_HOUR;
    2675           3 :                         if ((ivval.intval.day_second.hour = ival.intval.day_second.hour + 24 * ival.intval.day_second.day) >= maxdatetimeval) {
    2676             :                                 /* Interval field overflow */
    2677           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2678           0 :                                 return SQL_ERROR;
    2679             :                         }
    2680           3 :                         if (ival.intval.day_second.minute || ival.intval.day_second.second || ival.intval.day_second.fraction) {
    2681             :                                 /* Fractional truncation */
    2682           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2683             :                         }
    2684             :                         break;
    2685           3 :                 case SQL_C_INTERVAL_MINUTE:
    2686           3 :                         ivval.interval_type = SQL_IS_MINUTE;
    2687           3 :                         if ((ivval.intval.day_second.minute = ival.intval.day_second.minute + 60 * (ival.intval.day_second.hour + 24 * ival.intval.day_second.day)) >= maxdatetimeval) {
    2688             :                                 /* Interval field overflow */
    2689           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2690           0 :                                 return SQL_ERROR;
    2691             :                         }
    2692           3 :                         if (ival.intval.day_second.second || ival.intval.day_second.fraction) {
    2693             :                                 /* Fractional truncation */
    2694           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2695             :                         }
    2696             :                         break;
    2697           3 :                 case SQL_C_INTERVAL_SECOND:
    2698           3 :                         ivval.interval_type = SQL_IS_SECOND;
    2699           3 :                         if ((ivval.intval.day_second.second = ival.intval.day_second.second + 60 * (ival.intval.day_second.minute + 60 * (ival.intval.day_second.hour + 24 * ival.intval.day_second.day))) >= maxdatetimeval) {
    2700             :                                 /* Interval field overflow */
    2701           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2702           0 :                                 return SQL_ERROR;
    2703             :                         }
    2704           3 :                         ivval.intval.day_second.fraction = ival.intval.day_second.fraction;
    2705           3 :                         break;
    2706           3 :                 case SQL_C_INTERVAL_DAY_TO_HOUR:
    2707           3 :                         ivval.interval_type = SQL_IS_DAY_TO_HOUR;
    2708           3 :                         if ((ivval.intval.day_second.day = ival.intval.day_second.day) >= maxdatetimeval) {
    2709             :                                 /* Interval field overflow */
    2710           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2711           0 :                                 return SQL_ERROR;
    2712             :                         }
    2713           3 :                         ivval.intval.day_second.hour = ival.intval.day_second.hour;
    2714           3 :                         if (ival.intval.day_second.minute || ival.intval.day_second.second || ival.intval.day_second.fraction) {
    2715             :                                 /* Fractional truncation */
    2716           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2717             :                         }
    2718             :                         break;
    2719           3 :                 case SQL_C_INTERVAL_DAY_TO_MINUTE:
    2720           3 :                         ivval.interval_type = SQL_IS_DAY_TO_MINUTE;
    2721           3 :                         if ((ivval.intval.day_second.day = ival.intval.day_second.day) >= maxdatetimeval) {
    2722             :                                 /* Interval field overflow */
    2723           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2724           0 :                                 return SQL_ERROR;
    2725             :                         }
    2726           3 :                         ivval.intval.day_second.hour = ival.intval.day_second.hour;
    2727           3 :                         ivval.intval.day_second.minute = ival.intval.day_second.minute;
    2728           3 :                         if (ival.intval.day_second.second || ival.intval.day_second.fraction) {
    2729             :                                 /* Fractional truncation */
    2730           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2731             :                         }
    2732             :                         break;
    2733           3 :                 case SQL_C_INTERVAL_DAY_TO_SECOND:
    2734           3 :                         ivval.interval_type = SQL_IS_DAY_TO_SECOND;
    2735           3 :                         if ((ivval.intval.day_second.day = ival.intval.day_second.day) >= maxdatetimeval) {
    2736             :                                 /* Interval field overflow */
    2737           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2738           0 :                                 return SQL_ERROR;
    2739             :                         }
    2740           3 :                         ivval.intval.day_second.hour = ival.intval.day_second.hour;
    2741           3 :                         ivval.intval.day_second.minute = ival.intval.day_second.minute;
    2742           3 :                         ivval.intval.day_second.second = ival.intval.day_second.second;
    2743           3 :                         ivval.intval.day_second.fraction = ival.intval.day_second.fraction;
    2744           3 :                         break;
    2745           3 :                 case SQL_C_INTERVAL_HOUR_TO_MINUTE:
    2746           3 :                         ivval.interval_type = SQL_IS_HOUR_TO_MINUTE;
    2747           3 :                         if ((ivval.intval.day_second.hour = ival.intval.day_second.hour + 24 * ival.intval.day_second.day) >= maxdatetimeval) {
    2748             :                                 /* Interval field overflow */
    2749           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2750           0 :                                 return SQL_ERROR;
    2751             :                         }
    2752           3 :                         ivval.intval.day_second.minute = ival.intval.day_second.minute;
    2753           3 :                         if (ival.intval.day_second.second || ival.intval.day_second.fraction) {
    2754             :                                 /* Fractional truncation */
    2755           0 :                                 addStmtError(stmt, "01S07", NULL, 0);
    2756             :                         }
    2757             :                         break;
    2758           3 :                 case SQL_C_INTERVAL_HOUR_TO_SECOND:
    2759           3 :                         ivval.interval_type = SQL_IS_HOUR_TO_SECOND;
    2760           3 :                         if ((ivval.intval.day_second.hour = ival.intval.day_second.hour + 24 * ival.intval.day_second.day) >= maxdatetimeval) {
    2761             :                                 /* Interval field overflow */
    2762           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2763           0 :                                 return SQL_ERROR;
    2764             :                         }
    2765           3 :                         ivval.intval.day_second.minute = ival.intval.day_second.minute;
    2766           3 :                         ivval.intval.day_second.second = ival.intval.day_second.second;
    2767           3 :                         ivval.intval.day_second.fraction = ival.intval.day_second.fraction;
    2768           3 :                         break;
    2769           3 :                 case SQL_C_INTERVAL_MINUTE_TO_SECOND:
    2770           3 :                         ivval.interval_type = SQL_IS_MINUTE_TO_SECOND;
    2771           3 :                         if ((ivval.intval.day_second.minute = ival.intval.day_second.minute + 60 * (ival.intval.day_second.hour + 24 * ival.intval.day_second.day)) >= maxdatetimeval) {
    2772             :                                 /* Interval field overflow */
    2773           0 :                                 addStmtError(stmt, "22015", NULL, 0);
    2774           0 :                                 return SQL_ERROR;
    2775             :                         }
    2776           3 :                         ivval.intval.day_second.second = ival.intval.day_second.second;
    2777           3 :                         ivval.intval.day_second.fraction = ival.intval.day_second.fraction;
    2778           3 :                         break;
    2779             :                 }
    2780          32 :                 if (ivval.intval.day_second.fraction) {
    2781          32 :                         while (ivalprec < precision) {
    2782          24 :                                 ivalprec++;
    2783          24 :                                 ivval.intval.day_second.fraction *= 10;
    2784             :                         }
    2785           8 :                         while (ivalprec > precision) {
    2786           0 :                                 ivalprec--;
    2787           0 :                                 if (stmt->Error == NULL &&
    2788           0 :                                     ivval.intval.day_second.fraction % 10 != 0) {
    2789             :                                         /* Fractional truncation */
    2790           0 :                                         addStmtError(stmt, "01S07", NULL, 0);
    2791             :                                 }
    2792           0 :                                 ivval.intval.day_second.fraction /= 10;
    2793             :                         }
    2794             :                 }
    2795          32 :                 WriteData(ptr, ivval, SQL_INTERVAL_STRUCT);
    2796          32 :                 if (lenp)
    2797          32 :                         *lenp = sizeof(SQL_INTERVAL_STRUCT);
    2798             :                 break;
    2799           4 :         case SQL_C_GUID:
    2800           4 :                 if (datalen != 36) {
    2801             :                         /* Restricted data type attribute violation */
    2802           0 :                         addStmtError(stmt, "07006", NULL, 0);
    2803           0 :                         return SQL_ERROR;
    2804             :                 }
    2805             : #ifdef ODBCDEBUG
    2806           4 :                 ODBCLOG("Writing 16 bytes to %p\n", ptr);
    2807             : #endif
    2808           4 :                 SQLGUID su;
    2809           4 :                 sscanf(data,
    2810             :                        "%8"SCNx32
    2811             :                        "-%4"SCNx16
    2812             :                        "-%4"SCNx16
    2813             :                        "-%2"SCNx8"%2"SCNx8
    2814             :                        "-%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8,
    2815             :                        &su.Data1, &su.Data2, &su.Data3,
    2816             :                        &su.Data4[0], &su.Data4[1],
    2817             :                        &su.Data4[2], &su.Data4[3], &su.Data4[4], &su.Data4[5], &su.Data4[6], &su.Data4[7]);
    2818           4 :                 WriteData(ptr, su, SQLGUID);
    2819           4 :                 if (lenp)
    2820           4 :                         *lenp = sizeof(SQLGUID);
    2821             :                 break;
    2822           0 :         default:
    2823             :                 /* Invalid application buffer type */
    2824           0 :                 addStmtError(stmt, "HY003", NULL, 0);
    2825           0 :                 return SQL_ERROR;
    2826             :         }
    2827       15340 :         return stmt->Error ? SQL_SUCCESS_WITH_INFO : SQL_SUCCESS;
    2828             : }
    2829             : 
    2830             : #define assign(buf,bufpos,buflen,value,stmt)                            \
    2831             :         do {                                                            \
    2832             :                 if (bufpos >= buflen) {                                      \
    2833             :                         char *b = realloc(buf, buflen += 1024);         \
    2834             :                         if (b == NULL) {                                \
    2835             :                                 free(buf);                              \
    2836             :                                 if (ctype == SQL_C_WCHAR && sval)       \
    2837             :                                         free(sval);                     \
    2838             :                                 /* Memory allocation error */           \
    2839             :                                 addStmtError(stmt, "HY001", NULL, 0); \
    2840             :                                 return SQL_ERROR;                       \
    2841             :                         }                                               \
    2842             :                         buf = b;                                        \
    2843             :                 }                                                       \
    2844             :                 buf[bufpos++] = (value);                                \
    2845             :         } while (0)
    2846             : #define assigns(buf,bufpos,buflen,value,stmt)                           \
    2847             :         do {                                                            \
    2848             :                 size_t _len = strlen(value);                            \
    2849             :                 size_t _i;                                              \
    2850             :                 while (bufpos + _len >= buflen) {                    \
    2851             :                         char *b = realloc(buf, buflen += 1024);         \
    2852             :                         if (b == NULL) {                                \
    2853             :                                 free(buf);                              \
    2854             :                                 if (ctype == SQL_C_WCHAR && sval)       \
    2855             :                                         free(sval);                     \
    2856             :                                 /* Memory allocation error */           \
    2857             :                                 addStmtError(stmt, "HY001", NULL, 0); \
    2858             :                                 return SQL_ERROR;                       \
    2859             :                         }                                               \
    2860             :                         buf = b;                                        \
    2861             :                 }                                                       \
    2862             :                 for (_i = 0; _i < _len; _i++)                                \
    2863             :                         buf[bufpos++] = (value)[_i];                    \
    2864             :         } while (0)
    2865             : 
    2866             : SQLRETURN
    2867       10004 : ODBCStore(ODBCStmt *stmt,
    2868             :           SQLUSMALLINT param,
    2869             :           SQLLEN offset,
    2870             :           SQLULEN row,
    2871             :           char **bufp,
    2872             :           size_t *bufposp,
    2873             :           size_t *buflenp,
    2874             :           const char *sep)
    2875             : {
    2876       10004 :         ODBCDescRec *ipdrec, *apdrec;
    2877       10004 :         SQLPOINTER ptr;
    2878       10004 :         SQLLEN *strlen_or_ind_ptr;
    2879       10004 :         SQLINTEGER bind_type;
    2880       10004 :         SQLSMALLINT ctype, sqltype;
    2881       10004 :         char *sval = NULL;
    2882       10004 :         SQLLEN slen = 0;
    2883       10004 :         bignum_t nval;
    2884       10004 :         double fval = 0.0;
    2885       10004 :         DATE_STRUCT dval;
    2886       10004 :         TIME_STRUCT tval;
    2887       10004 :         TIMESTAMP_STRUCT tsval;
    2888       10004 :         int ivalprec = 0;       /* interval second precision */
    2889       10004 :         SQL_INTERVAL_STRUCT ival;
    2890       10004 :         SQLGUID u;
    2891       10004 :         char *buf = *bufp;
    2892       10004 :         size_t bufpos = *bufposp;
    2893       10004 :         size_t buflen = *buflenp;
    2894       10004 :         char data[256];
    2895       10004 :         int i;
    2896             : 
    2897       10004 :         assert(param <= stmt->ImplParamDescr->sql_desc_count);
    2898       10004 :         assert(param <= stmt->ApplParamDescr->sql_desc_count);
    2899       10004 :         ipdrec = stmt->ImplParamDescr->descRec + param;
    2900       10004 :         apdrec = stmt->ApplParamDescr->descRec + param;
    2901             : 
    2902       10004 :         bind_type = stmt->ApplParamDescr->sql_desc_bind_type;
    2903       10004 :         ptr = apdrec->sql_desc_data_ptr;
    2904       10004 :         if (ptr && offset)
    2905           0 :                 ptr = (SQLPOINTER) ((char *) ptr + offset + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQLPOINTER) : bind_type));
    2906       10004 :         strlen_or_ind_ptr = apdrec->sql_desc_indicator_ptr;
    2907       10004 :         if (strlen_or_ind_ptr && offset)
    2908           0 :                 strlen_or_ind_ptr = (SQLLEN *) ((char *) strlen_or_ind_ptr + offset + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQLINTEGER) : bind_type));
    2909       10004 :         if (ptr == NULL &&
    2910           0 :             (strlen_or_ind_ptr == NULL || *strlen_or_ind_ptr != SQL_NULL_DATA)) {
    2911             :                 /* COUNT field incorrect */
    2912           0 :                 addStmtError(stmt, "07002", NULL, 0);
    2913           0 :                 return SQL_ERROR;
    2914             :         }
    2915             : 
    2916       10004 :         ctype = apdrec->sql_desc_concise_type;
    2917       10004 :         sqltype = ipdrec->sql_desc_concise_type;
    2918       10004 :         if (ctype == SQL_C_DEFAULT)
    2919           0 :                 ctype = ODBCDefaultType(ipdrec);
    2920             : 
    2921       10004 :         switch (ctype) {
    2922           0 :         case SQL_C_TINYINT:
    2923           0 :                 ctype = apdrec->sql_desc_unsigned ? SQL_C_UTINYINT : SQL_C_STINYINT;
    2924             :                 break;
    2925           0 :         case SQL_C_SHORT:
    2926           0 :                 ctype = apdrec->sql_desc_unsigned ? SQL_C_USHORT : SQL_C_SSHORT;
    2927             :                 break;
    2928           2 :         case SQL_C_LONG:
    2929           2 :                 ctype = apdrec->sql_desc_unsigned ? SQL_C_ULONG : SQL_C_SLONG;
    2930             :                 break;
    2931             :         default:
    2932             :                 break;
    2933             :         }
    2934             : 
    2935       28010 :         assigns(buf, bufpos, buflen, sep, stmt);
    2936       10004 :         *bufp = buf;
    2937             : 
    2938       10004 :         if (strlen_or_ind_ptr != NULL && *strlen_or_ind_ptr == SQL_NULL_DATA) {
    2939           0 :                 assigns(buf, bufpos, buflen, "NULL", stmt);
    2940           0 :                 *bufp = buf;
    2941           0 :                 *bufposp = bufpos;
    2942           0 :                 *buflenp = buflen;
    2943           0 :                 return SQL_SUCCESS;
    2944             :         }
    2945             : 
    2946       10004 :         strlen_or_ind_ptr = apdrec->sql_desc_octet_length_ptr;
    2947       10004 :         if (strlen_or_ind_ptr && offset)
    2948           0 :                 strlen_or_ind_ptr = (SQLLEN *) ((char *) strlen_or_ind_ptr + offset + row * (bind_type == SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(SQLINTEGER) : bind_type));
    2949             : 
    2950       10004 :         switch (ctype) {
    2951        2000 :         case SQL_C_CHAR:
    2952             :         case SQL_C_BINARY:
    2953        2000 :                 slen = strlen_or_ind_ptr ? *strlen_or_ind_ptr : SQL_NTS;
    2954        2000 :                 sval = (char *) ptr;
    2955        2000 :                 fixODBCstring(sval, slen, SQLLEN, addStmtError, stmt, return SQL_ERROR);
    2956             :                 break;
    2957           2 :         case SQL_C_WCHAR:
    2958           2 :                 slen = strlen_or_ind_ptr ? *strlen_or_ind_ptr : SQL_NTS;
    2959           2 :                 if (slen > 0)
    2960           2 :                         slen /= 2;      /* convert from bytes to characters */
    2961           2 :                 fixWcharIn((SQLWCHAR *) ptr, slen, char, sval, addStmtError, stmt, return SQL_ERROR);
    2962           2 :                 if (sval == NULL) {
    2963           0 :                         sval = strdup("");
    2964           0 :                         if (sval == NULL) {
    2965           0 :                                 addStmtError(stmt, "HY001", NULL, 0);
    2966           0 :                                 return SQL_ERROR;
    2967             :                         }
    2968             :                 }
    2969           2 :                 slen = strlen(sval);
    2970           2 :                 break;
    2971           0 :         case SQL_C_BIT:
    2972           0 :                 nval.precision = 1;
    2973           0 :                 nval.scale = 0;
    2974           0 :                 nval.sign = 1;
    2975           0 :                 nval.val = * (SQLCHAR *) ptr != 0;
    2976           0 :                 break;
    2977           0 :         case SQL_C_STINYINT:
    2978           0 :                 nval.precision = 1;
    2979           0 :                 nval.scale = 0;
    2980           0 :                 if (* (SQLSCHAR *) ptr < 0) {
    2981           0 :                         nval.sign = 0;
    2982           0 :                         nval.val = - * (SQLSCHAR *) ptr;
    2983             :                 } else {
    2984           0 :                         nval.sign = 1;
    2985           0 :                         nval.val = * (SQLSCHAR *) ptr;
    2986             :                 }
    2987             :                 break;
    2988           0 :         case SQL_C_UTINYINT:
    2989           0 :                 nval.precision = 1;
    2990           0 :                 nval.scale = 0;
    2991           0 :                 nval.sign = 1;
    2992           0 :                 nval.val = * (SQLCHAR *) ptr;
    2993           0 :                 break;
    2994        2000 :         case SQL_C_SSHORT:
    2995        2000 :                 nval.precision = 1;
    2996        2000 :                 nval.scale = 0;
    2997        2000 :                 if (* (SQLSMALLINT *) ptr < 0) {
    2998           0 :                         nval.sign = 0;
    2999           0 :                         nval.val = - * (SQLSMALLINT *) ptr;
    3000             :                 } else {
    3001        2000 :                         nval.sign = 1;
    3002        2000 :                         nval.val = * (SQLSMALLINT *) ptr;
    3003             :                 }
    3004             :                 break;
    3005           0 :         case SQL_C_USHORT:
    3006           0 :                 nval.precision = 1;
    3007           0 :                 nval.scale = 0;
    3008           0 :                 nval.sign = 1;
    3009           0 :                 nval.val = * (SQLUSMALLINT *) ptr;
    3010           0 :                 break;
    3011           2 :         case SQL_C_SLONG:
    3012           2 :                 nval.precision = 1;
    3013           2 :                 nval.scale = 0;
    3014           2 :                 if (* (SQLINTEGER *) ptr < 0) {
    3015           0 :                         nval.sign = 0;
    3016           0 :                         nval.val = - * (SQLINTEGER *) ptr;
    3017             :                 } else {
    3018           2 :                         nval.sign = 1;
    3019           2 :                         nval.val = * (SQLINTEGER *) ptr;
    3020             :                 }
    3021             :                 break;
    3022           0 :         case SQL_C_ULONG:
    3023           0 :                 nval.precision = 1;
    3024           0 :                 nval.scale = 0;
    3025           0 :                 nval.sign = 1;
    3026           0 :                 nval.val = * (SQLUINTEGER *) ptr;
    3027           0 :                 break;
    3028           0 :         case SQL_C_SBIGINT:
    3029           0 :                 nval.precision = 1;
    3030           0 :                 nval.scale = 0;
    3031           0 :                 if (* (SQLBIGINT *) ptr < 0) {
    3032           0 :                         nval.sign = 0;
    3033           0 :                         nval.val = - * (SQLBIGINT *) ptr;
    3034             :                 } else {
    3035           0 :                         nval.sign = 1;
    3036           0 :                         nval.val = * (SQLBIGINT *) ptr;
    3037             :                 }
    3038             :                 break;
    3039           0 :         case SQL_C_UBIGINT:
    3040           0 :                 nval.precision = 1;
    3041           0 :                 nval.scale = 0;
    3042           0 :                 nval.sign = 1;
    3043           0 :                 nval.val = * (SQLUBIGINT *) ptr;
    3044           0 :                 break;
    3045           0 :         case SQL_C_NUMERIC:
    3046           0 :                 nval.precision = (uint8_t) apdrec->sql_desc_precision;
    3047           0 :                 nval.scale = (int8_t) apdrec->sql_desc_scale;
    3048           0 :                 nval.sign = ((SQL_NUMERIC_STRUCT *) ptr)->sign;
    3049           0 :                 nval.val = 0;
    3050           0 :                 for (i = 0; i < SQL_MAX_NUMERIC_LEN; i++)
    3051           0 :                         nval.val |= (uint64_t) ((SQL_NUMERIC_STRUCT *) ptr)->val[i] << (i * 8);
    3052             :                 break;
    3053           0 :         case SQL_C_FLOAT:
    3054           0 :                 fval = * (SQLREAL *) ptr;
    3055           0 :                 break;
    3056        2000 :         case SQL_C_DOUBLE:
    3057        2000 :                 fval = * (SQLDOUBLE *) ptr;
    3058        2000 :                 break;
    3059        2000 :         case SQL_C_TYPE_DATE:
    3060        2000 :                 dval = * (SQL_DATE_STRUCT *) ptr;
    3061        2000 :                 break;
    3062        2000 :         case SQL_C_TYPE_TIME:
    3063        2000 :                 tval = * (SQL_TIME_STRUCT *) ptr;
    3064        2000 :                 break;
    3065           0 :         case SQL_C_TYPE_TIMESTAMP:
    3066           0 :                 tsval = * (SQL_TIMESTAMP_STRUCT *) ptr;
    3067           0 :                 break;
    3068           0 :         case SQL_C_INTERVAL_YEAR:
    3069           0 :                 ival.interval_type = SQL_IS_YEAR;
    3070           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3071           0 :                 ival.intval.year_month.year = ((SQL_INTERVAL_STRUCT *) ptr)->intval.year_month.year;
    3072           0 :                 ival.intval.year_month.month = 0;
    3073           0 :                 break;
    3074           0 :         case SQL_C_INTERVAL_MONTH:
    3075           0 :                 ival.interval_type = SQL_IS_MONTH;
    3076           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3077           0 :                 ival.intval.year_month.year = 0;
    3078           0 :                 ival.intval.year_month.month = ((SQL_INTERVAL_STRUCT *) ptr)->intval.year_month.month;
    3079           0 :                 break;
    3080           0 :         case SQL_C_INTERVAL_YEAR_TO_MONTH:
    3081           0 :                 ival.interval_type = SQL_IS_YEAR_TO_MONTH;
    3082           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3083           0 :                 ival.intval.year_month.year = ((SQL_INTERVAL_STRUCT *) ptr)->intval.year_month.year;
    3084           0 :                 ival.intval.year_month.month = ((SQL_INTERVAL_STRUCT *) ptr)->intval.year_month.month;
    3085           0 :                 break;
    3086           0 :         case SQL_C_INTERVAL_DAY:
    3087           0 :                 ival.interval_type = SQL_IS_DAY;
    3088           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3089           0 :                 ival.intval.day_second.day = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.day;
    3090           0 :                 ival.intval.day_second.hour = 0;
    3091           0 :                 ival.intval.day_second.minute = 0;
    3092           0 :                 ival.intval.day_second.second = 0;
    3093           0 :                 ival.intval.day_second.fraction = 0;
    3094           0 :                 break;
    3095           0 :         case SQL_C_INTERVAL_HOUR:
    3096           0 :                 ival.interval_type = SQL_IS_HOUR;
    3097           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3098           0 :                 ival.intval.day_second.day = 0;
    3099           0 :                 ival.intval.day_second.hour = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.hour;
    3100           0 :                 ival.intval.day_second.minute = 0;
    3101           0 :                 ival.intval.day_second.second = 0;
    3102           0 :                 ival.intval.day_second.fraction = 0;
    3103           0 :                 break;
    3104           0 :         case SQL_C_INTERVAL_MINUTE:
    3105           0 :                 ival.interval_type = SQL_IS_MINUTE;
    3106           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3107           0 :                 ival.intval.day_second.day = 0;
    3108           0 :                 ival.intval.day_second.hour = 0;
    3109           0 :                 ival.intval.day_second.minute = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.minute;
    3110           0 :                 ival.intval.day_second.second = 0;
    3111           0 :                 ival.intval.day_second.fraction = 0;
    3112           0 :                 break;
    3113           0 :         case SQL_C_INTERVAL_SECOND:
    3114           0 :                 ival.interval_type = SQL_IS_SECOND;
    3115           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3116           0 :                 ival.intval.day_second.day = 0;
    3117           0 :                 ival.intval.day_second.hour = 0;
    3118           0 :                 ival.intval.day_second.minute = 0;
    3119           0 :                 ival.intval.day_second.second = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.second;
    3120           0 :                 ival.intval.day_second.fraction = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.fraction;
    3121           0 :                 ivalprec = apdrec->sql_desc_precision;
    3122           0 :                 break;
    3123           0 :         case SQL_C_INTERVAL_DAY_TO_HOUR:
    3124           0 :                 ival.interval_type = SQL_IS_DAY_TO_HOUR;
    3125           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3126           0 :                 ival.intval.day_second.day = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.day;
    3127           0 :                 ival.intval.day_second.hour = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.hour;
    3128           0 :                 ival.intval.day_second.minute = 0;
    3129           0 :                 ival.intval.day_second.second = 0;
    3130           0 :                 ival.intval.day_second.fraction = 0;
    3131           0 :                 break;
    3132           0 :         case SQL_C_INTERVAL_DAY_TO_MINUTE:
    3133           0 :                 ival.interval_type = SQL_IS_DAY_TO_MINUTE;
    3134           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3135           0 :                 ival.intval.day_second.day = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.day;
    3136           0 :                 ival.intval.day_second.hour = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.hour;
    3137           0 :                 ival.intval.day_second.minute = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.minute;
    3138           0 :                 ival.intval.day_second.second = 0;
    3139           0 :                 ival.intval.day_second.fraction = 0;
    3140           0 :                 break;
    3141           0 :         case SQL_C_INTERVAL_DAY_TO_SECOND:
    3142           0 :                 ival.interval_type = SQL_IS_DAY_TO_SECOND;
    3143           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3144           0 :                 ival.intval.day_second.day = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.day;
    3145           0 :                 ival.intval.day_second.hour = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.hour;
    3146           0 :                 ival.intval.day_second.minute = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.minute;
    3147           0 :                 ival.intval.day_second.second = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.second;
    3148           0 :                 ival.intval.day_second.fraction = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.fraction;
    3149           0 :                 ivalprec = apdrec->sql_desc_precision;
    3150           0 :                 break;
    3151           0 :         case SQL_C_INTERVAL_HOUR_TO_MINUTE:
    3152           0 :                 ival.interval_type = SQL_IS_HOUR_TO_MINUTE;
    3153           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3154           0 :                 ival.intval.day_second.day = 0;
    3155           0 :                 ival.intval.day_second.hour = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.hour;
    3156           0 :                 ival.intval.day_second.minute = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.minute;
    3157           0 :                 ival.intval.day_second.second = 0;
    3158           0 :                 ival.intval.day_second.fraction = 0;
    3159           0 :                 break;
    3160           0 :         case SQL_C_INTERVAL_HOUR_TO_SECOND:
    3161           0 :                 ival.interval_type = SQL_IS_HOUR_TO_SECOND;
    3162           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3163           0 :                 ival.intval.day_second.day = 0;
    3164           0 :                 ival.intval.day_second.hour = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.hour;
    3165           0 :                 ival.intval.day_second.minute = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.minute;
    3166           0 :                 ival.intval.day_second.second = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.second;
    3167           0 :                 ival.intval.day_second.fraction = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.fraction;
    3168           0 :                 ivalprec = apdrec->sql_desc_precision;
    3169           0 :                 break;
    3170           0 :         case SQL_C_INTERVAL_MINUTE_TO_SECOND:
    3171           0 :                 ival.interval_type = SQL_IS_MINUTE_TO_SECOND;
    3172           0 :                 ival.interval_sign = ((SQL_INTERVAL_STRUCT *) ptr)->interval_sign;
    3173           0 :                 ival.intval.day_second.day = 0;
    3174           0 :                 ival.intval.day_second.hour = 0;
    3175           0 :                 ival.intval.day_second.minute = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.minute;
    3176           0 :                 ival.intval.day_second.second = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.second;
    3177           0 :                 ival.intval.day_second.fraction = ((SQL_INTERVAL_STRUCT *) ptr)->intval.day_second.fraction;
    3178           0 :                 ivalprec = apdrec->sql_desc_precision;
    3179           0 :                 break;
    3180             :         case SQL_C_GUID:
    3181             :                 break;
    3182             :         }
    3183             : 
    3184             :         /* just the types supported by the server */
    3185       10004 :         switch (sqltype) {
    3186        2002 :         case SQL_CHAR:
    3187             :         case SQL_VARCHAR:
    3188             :         case SQL_LONGVARCHAR:
    3189             :         case SQL_WCHAR:
    3190             :         case SQL_WVARCHAR:
    3191             :         case SQL_WLONGVARCHAR:
    3192        2002 :                 assign(buf, bufpos, buflen, 'r', stmt); /* RAW string */
    3193        2002 :                 assign(buf, bufpos, buflen, '\'', stmt);
    3194        2002 :                 switch (ctype) {
    3195             :                 case SQL_C_CHAR:
    3196             :                 case SQL_C_WCHAR:
    3197             :                 case SQL_C_BINARY:
    3198       32901 :                         for (i = 0; i < slen; i++) {
    3199       30899 :                                 unsigned char c = (unsigned char) sval[i];
    3200             : 
    3201       30899 :                                 if (c == 0)
    3202             :                                         break;
    3203       30899 :                                 if (c == '\'')
    3204           0 :                                         assign(buf, bufpos, buflen, '\'', stmt);
    3205       30899 :                                 assign(buf, bufpos, buflen, c, stmt);
    3206             :                         }
    3207             :                         break;
    3208           0 :                 case SQL_C_BIT:
    3209           0 :                         if (nval.val)
    3210           0 :                                 assigns(buf, bufpos, buflen, "true", stmt);
    3211             :                         else
    3212           0 :                                 assigns(buf, bufpos, buflen, "false", stmt);
    3213             :                         break;
    3214             :                 case SQL_C_STINYINT:
    3215             :                 case SQL_C_UTINYINT:
    3216             :                 case SQL_C_SSHORT:
    3217             :                 case SQL_C_USHORT:
    3218             :                 case SQL_C_SLONG:
    3219             :                 case SQL_C_ULONG:
    3220             :                 case SQL_C_SBIGINT:
    3221             :                 case SQL_C_UBIGINT:
    3222             :                 case SQL_C_NUMERIC: {
    3223             :                         int f, n;
    3224             : 
    3225           0 :                         for (n = 0, f = 1; n < nval.scale; n++)
    3226           0 :                                 f *= 10;
    3227           0 :                         snprintf(data, sizeof(data), "%s%" PRIu64, nval.sign ? "" : "-", (uint64_t) (nval.val / f));
    3228           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3229           0 :                         if (nval.scale > 0) {
    3230           0 :                                 snprintf(data, sizeof(data), ".%0*" PRIu64, nval.scale, (uint64_t) (nval.val % f));
    3231           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3232             :                         }
    3233             :                         break;
    3234             :                 }
    3235             :                 case SQL_C_FLOAT:
    3236             :                 case SQL_C_DOUBLE: {
    3237           0 :                         for (i = 0; i < 18; i++) {
    3238           0 :                                 snprintf(data, sizeof(data), "%.*g", i, fval);
    3239           0 :                                 if (fval == strtod(data, NULL))
    3240             :                                         break;
    3241             :                         }
    3242           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3243             :                         break;
    3244             :                 }
    3245           0 :                 case SQL_C_TYPE_DATE:
    3246           0 :                         snprintf(data, sizeof(data), "%04d-%02u-%02u",
    3247           0 :                                  (int) dval.year,
    3248           0 :                                  (unsigned int) dval.month,
    3249           0 :                                  (unsigned int) dval.day);
    3250           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3251             :                         break;
    3252           0 :                 case SQL_C_TYPE_TIME:
    3253           0 :                         snprintf(data, sizeof(data), "%02u:%02u:%02u",
    3254           0 :                                  (unsigned int) tval.hour,
    3255           0 :                                  (unsigned int) tval.minute,
    3256           0 :                                  (unsigned int) tval.second);
    3257           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3258             :                         break;
    3259           0 :                 case SQL_C_TYPE_TIMESTAMP:
    3260           0 :                         snprintf(data, sizeof(data),
    3261             :                                  "%04d-%02u-%02u %02u:%02u:%02u",
    3262           0 :                                  (int) tsval.year,
    3263           0 :                                  (unsigned int) tsval.month,
    3264           0 :                                  (unsigned int) tsval.day,
    3265           0 :                                  (unsigned int) tsval.hour,
    3266           0 :                                  (unsigned int) tsval.minute,
    3267           0 :                                  (unsigned int) tsval.second);
    3268           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3269           0 :                         if (tsval.fraction) {
    3270           0 :                                 snprintf(data, sizeof(data), ".%09u", (unsigned int) tsval.fraction);
    3271             :                                 /* remove trailing zeros */
    3272           0 :                                 for (i = 9; i > 0 && data[i] == '0'; i--)
    3273           0 :                                         data[i] = 0;
    3274           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3275             :                         }
    3276             :                         break;
    3277           0 :                 case SQL_C_INTERVAL_YEAR:
    3278           0 :                         snprintf(data, sizeof(data), "%s%0*u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.year_month.year);
    3279           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3280             :                         break;
    3281           0 :                 case SQL_C_INTERVAL_MONTH:
    3282           0 :                         snprintf(data, sizeof(data), "%s%0*u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.year_month.month);
    3283           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3284             :                         break;
    3285           0 :                 case SQL_C_INTERVAL_YEAR_TO_MONTH:
    3286           0 :                         snprintf(data, sizeof(data), "%s%0*u-%02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.year_month.year, (unsigned int) ival.intval.year_month.month);
    3287           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3288             :                         break;
    3289           0 :                 case SQL_C_INTERVAL_DAY:
    3290           0 :                         snprintf(data, sizeof(data), "%s%0*u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.day);
    3291           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3292             :                         break;
    3293           0 :                 case SQL_C_INTERVAL_HOUR:
    3294           0 :                         snprintf(data, sizeof(data), "%s%0*u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.hour);
    3295           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3296             :                         break;
    3297           0 :                 case SQL_C_INTERVAL_MINUTE:
    3298           0 :                         snprintf(data, sizeof(data), "%s%0*u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.minute);
    3299           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3300             :                         break;
    3301           0 :                 case SQL_C_INTERVAL_SECOND:
    3302           0 :                         snprintf(data, sizeof(data), "%s%0*u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.second);
    3303           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3304             :                         /* if ivalprec > 16, the digits that are used by
    3305             :                          * the server are all 0, so we don't need to
    3306             :                          * write them */
    3307           0 :                         if (ival.intval.day_second.fraction && ivalprec > 0 && ivalprec < 17) {
    3308           0 :                                 snprintf(data, sizeof(data), ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    3309           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3310             :                         }
    3311             :                         break;
    3312           0 :                 case SQL_C_INTERVAL_DAY_TO_HOUR:
    3313           0 :                         snprintf(data, sizeof(data), "%s%0*u %02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.day, (unsigned int) ival.intval.day_second.hour);
    3314           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3315             :                         break;
    3316           0 :                 case SQL_C_INTERVAL_DAY_TO_MINUTE:
    3317           0 :                         snprintf(data, sizeof(data), "%s%0*u %02u:%02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.day, (unsigned int) ival.intval.day_second.hour, (unsigned int) ival.intval.day_second.minute);
    3318           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3319             :                         break;
    3320           0 :                 case SQL_C_INTERVAL_DAY_TO_SECOND:
    3321           0 :                         snprintf(data, sizeof(data), "%s%0*u %02u:%02u:%02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.day, (unsigned int) ival.intval.day_second.hour, (unsigned int) ival.intval.day_second.minute, (unsigned int) ival.intval.day_second.second);
    3322           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3323           0 :                         if (ival.intval.day_second.fraction && ivalprec > 0 && ivalprec < 17) {
    3324           0 :                                 snprintf(data, sizeof(data), ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    3325           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3326             :                         }
    3327             :                         break;
    3328           0 :                 case SQL_C_INTERVAL_HOUR_TO_MINUTE:
    3329           0 :                         snprintf(data, sizeof(data), "%s%0*u:%02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.hour, (unsigned int) ival.intval.day_second.minute);
    3330           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3331             :                         break;
    3332           0 :                 case SQL_C_INTERVAL_HOUR_TO_SECOND:
    3333           0 :                         snprintf(data, sizeof(data), "%s%0*u:%02u:%02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.hour, (unsigned int) ival.intval.day_second.minute, (unsigned int) ival.intval.day_second.second);
    3334           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3335           0 :                         if (ival.intval.day_second.fraction && ivalprec > 0 && ivalprec < 17) {
    3336           0 :                                 snprintf(data, sizeof(data), ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    3337           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3338             :                         }
    3339             :                         break;
    3340           0 :                 case SQL_C_INTERVAL_MINUTE_TO_SECOND:
    3341           0 :                         snprintf(data, sizeof(data), "%s%0*u:%02u", ival.interval_sign ? "-" : "", (int) apdrec->sql_desc_datetime_interval_precision, (unsigned int) ival.intval.day_second.minute, (unsigned int) ival.intval.day_second.second);
    3342           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3343           0 :                         if (ival.intval.day_second.fraction && ivalprec > 0 && ivalprec < 17) {
    3344           0 :                                 snprintf(data, sizeof(data), ".%0*u", ivalprec, (unsigned int) ival.intval.day_second.fraction);
    3345           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3346             :                         }
    3347             :                         break;
    3348           0 :                 case SQL_C_GUID:
    3349           0 :                         u = *(SQLGUID *)ptr;
    3350           0 :                         snprintf(data, sizeof(data),
    3351             :                                  "%08"PRIx32"-%04"PRIx16"-%04"PRIx16
    3352             :                                  "-%02"PRIx8"%02"PRIx8
    3353             :                                  "-%02"PRIx8"%02"PRIx8"%02"PRIx8
    3354             :                                  "%02"PRIx8"%02"PRIx8"%02"PRIx8,
    3355             :                                  u.Data1, u.Data2, u.Data3,
    3356             :                                  u.Data4[0], u.Data4[1],
    3357             :                                  u.Data4[2], u.Data4[3],
    3358             :                                  u.Data4[4], u.Data4[5],
    3359             :                                  u.Data4[6], u.Data4[7]);
    3360           0 :                         break;
    3361             :                 }
    3362        2002 :                 assign(buf, bufpos, buflen, '\'', stmt);
    3363        2002 :                 break;
    3364           0 :         case SQL_BINARY:
    3365             :         case SQL_VARBINARY:
    3366             :         case SQL_LONGVARBINARY:
    3367           0 :                 switch (ctype) {
    3368             :                 case SQL_C_CHAR:
    3369             :                 case SQL_C_BINARY:
    3370           0 :                         assigns(buf, bufpos, buflen, "blob '", stmt);
    3371           0 :                         for (i = 0; i < slen; i++) {
    3372           0 :                                 unsigned char c = (unsigned char) sval[i];
    3373             : 
    3374           0 :                                 assign(buf, bufpos, buflen, "0123456789ABCDEF"[c >> 4], stmt);
    3375           0 :                                 assign(buf, bufpos, buflen, "0123456789ABCDEF"[c & 0xF], stmt);
    3376             :                         }
    3377           0 :                         assign(buf, bufpos, buflen, '\'', stmt);
    3378           0 :                         break;
    3379           0 :                 default:
    3380             :                         /* Restricted data type attribute violation */
    3381           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3382           0 :                         goto failure;
    3383             :                 }
    3384           0 :                 break;
    3385        2000 :         case SQL_TYPE_DATE:
    3386        2000 :                 i = 1;
    3387        2000 :                 switch (ctype) {
    3388           0 :                 case SQL_C_CHAR:
    3389             :                 case SQL_C_WCHAR:
    3390             :                 case SQL_C_BINARY:
    3391           0 :                         i = parsetimestamp(sval, &tsval);
    3392             :                         /* fall through */
    3393             :                 case SQL_C_TYPE_TIMESTAMP:
    3394           0 :                         if (i) {
    3395           0 :                                 if (tsval.hour || tsval.minute || tsval.second || tsval.fraction || i == 2) {
    3396             :                                         /* Datetime field overflow */
    3397           0 :                                         addStmtError(stmt, "22008", NULL, 0);
    3398             :                                 }
    3399           0 :                                 dval = (DATE_STRUCT) {
    3400           0 :                                         .year = tsval.year,
    3401           0 :                                         .month = tsval.month,
    3402           0 :                                         .day = tsval.day,
    3403             :                                 };
    3404           0 :                         } else if (!parsedate(sval, &dval)) {
    3405             :                                 /* Invalid character value for cast
    3406             :                                  * specification */
    3407           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3408           0 :                                 goto failure;
    3409             :                         }
    3410             :                         /* fall through */
    3411             :                 case SQL_C_TYPE_DATE:
    3412        2000 :                         snprintf(data, sizeof(data), "DATE '%u-%02u-%02u'",
    3413        2000 :                                  (unsigned int) dval.year,
    3414        2000 :                                  (unsigned int) dval.month,
    3415        2000 :                                  (unsigned int) dval.day);
    3416       38000 :                         assigns(buf, bufpos, buflen, data, stmt);
    3417             :                         break;
    3418           0 :                 default:
    3419             :                         /* Restricted data type attribute violation */
    3420           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3421           0 :                         goto failure;
    3422             :                 }
    3423             :                 break;
    3424        2000 :         case SQL_TYPE_TIME:
    3425        2000 :                 i = 1;
    3426        2000 :                 switch (ctype) {
    3427           0 :                 case SQL_C_CHAR:
    3428             :                 case SQL_C_WCHAR:
    3429             :                 case SQL_C_BINARY:
    3430           0 :                         i = parsetimestamp(sval, &tsval);
    3431             :                         /* fall through */
    3432             :                 case SQL_C_TYPE_TIMESTAMP:
    3433           0 :                         if (i) {
    3434           0 :                                 if (tsval.fraction || i == 2) {
    3435             :                                         /* Datetime field overflow */
    3436           0 :                                         addStmtError(stmt, "22008", NULL, 0);
    3437             :                                 }
    3438           0 :                                 tval = (TIME_STRUCT) {
    3439           0 :                                         .hour = tsval.hour,
    3440           0 :                                         .minute = tsval.minute,
    3441           0 :                                         .second = tsval.second,
    3442             :                                 };
    3443           0 :                         } else if (!parsetime(sval, &tval)) {
    3444             :                                 /* Invalid character value for cast
    3445             :                                  * specification */
    3446           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3447           0 :                                 goto failure;
    3448             :                         }
    3449             :                         /* fall through */
    3450             :                 case SQL_C_TYPE_TIME:
    3451        2000 :                         snprintf(data, sizeof(data), "TIME '%u:%02u:%02u'",
    3452        2000 :                                  (unsigned int) tval.hour,
    3453        2000 :                                  (unsigned int) tval.minute,
    3454        2000 :                                  (unsigned int) tval.second);
    3455       32000 :                         assigns(buf, bufpos, buflen, data, stmt);
    3456             :                         break;
    3457           0 :                 default:
    3458             :                         /* Restricted data type attribute violation */
    3459           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3460           0 :                         goto failure;
    3461             :                 }
    3462             :                 break;
    3463           0 :         case SQL_TYPE_TIMESTAMP:
    3464           0 :                 switch (ctype) {
    3465           0 :                 case SQL_C_CHAR:
    3466             :                 case SQL_C_WCHAR:
    3467             :                 case SQL_C_BINARY:
    3468           0 :                         i = parsetimestamp(sval, &tsval);
    3469           0 :                         if (i == 0) {
    3470           0 :                                 i = parsetime(sval, &tval);
    3471           0 :                                 if (i) {
    3472           0 :                                         struct tm tm;
    3473           0 :                                         time_t t;
    3474             : 
    3475             :                 case SQL_C_TYPE_TIME:
    3476           0 :                                         (void) time(&t);
    3477           0 :                                         tm = (struct tm) {0};
    3478             : #ifdef HAVE_LOCALTIME_R
    3479           0 :                                         (void) localtime_r(&t, &tm);
    3480             : #else
    3481             :                                         tm = *localtime(&t);
    3482             : #endif
    3483           0 :                                         tsval = (TIMESTAMP_STRUCT) {
    3484           0 :                                                 .year = tm.tm_year + 1900,
    3485           0 :                                                 .month = tm.tm_mon + 1,
    3486           0 :                                                 .day = tm.tm_mday,
    3487           0 :                                                 .hour = tval.hour,
    3488           0 :                                                 .minute = tval.minute,
    3489           0 :                                                 .second = tval.second,
    3490             :                                                 .fraction = 0,
    3491             :                                         };
    3492             :                                 } else {
    3493           0 :                                         i = parsedate(sval, &dval);
    3494           0 :                                         if (i) {
    3495             :                 case SQL_TYPE_DATE:
    3496           0 :                                                 tsval = (TIMESTAMP_STRUCT) {
    3497           0 :                                                         .year = dval.year,
    3498           0 :                                                         .month = dval.month,
    3499           0 :                                                         .day = dval.day,
    3500             :                                                         .hour = 0,
    3501             :                                                         .minute = 0,
    3502             :                                                         .second = 0,
    3503             :                                                         .fraction = 0,
    3504             :                                                 };
    3505             :                                         } else {
    3506             :                                                 /* Invalid character
    3507             :                                                  * value for cast
    3508             :                                                  * specification */
    3509           0 :                                                 addStmtError(stmt, "22018", NULL, 0);
    3510           0 :                                                 goto failure;
    3511             :                                         }
    3512             :                                 }
    3513             :                         }
    3514             :                         /* fall through */
    3515             :                 case SQL_C_TYPE_TIMESTAMP:
    3516           0 :                         snprintf(data, sizeof(data),
    3517             :                                  "TIMESTAMP '%u-%02u-%02u %02u:%02u:%02u",
    3518           0 :                                  (unsigned int) tsval.year,
    3519           0 :                                  (unsigned int) tsval.month,
    3520           0 :                                  (unsigned int) tsval.day,
    3521           0 :                                  (unsigned int) tsval.hour,
    3522           0 :                                  (unsigned int) tsval.minute,
    3523           0 :                                  (unsigned int) tsval.second);
    3524           0 :                         assigns(buf, bufpos, buflen, data, stmt);
    3525           0 :                         if (tsval.fraction) {
    3526           0 :                                 snprintf(data, sizeof(data), ".%09u", (unsigned int) tsval.fraction);
    3527           0 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3528             :                         }
    3529           0 :                         assign(buf, bufpos, buflen, '\'', stmt);
    3530           0 :                         break;
    3531           0 :                 default:
    3532             :                         /* Restricted data type attribute violation */
    3533           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3534           0 :                         goto failure;
    3535             :                 }
    3536           0 :                 break;
    3537           0 :         case SQL_INTERVAL_MONTH:
    3538             :         case SQL_INTERVAL_YEAR:
    3539             :         case SQL_INTERVAL_YEAR_TO_MONTH:
    3540           0 :                 switch (ctype) {
    3541           0 :                 case SQL_C_CHAR:
    3542             :                 case SQL_C_WCHAR:
    3543             :                 case SQL_C_BINARY:
    3544           0 :                         if (parsemonthintervalstring(&sval, &slen, &ival) == SQL_ERROR) {
    3545             :                                 /* Invalid character value for cast
    3546             :                                  * specification */
    3547           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3548           0 :                                 goto failure;
    3549             :                         }
    3550             :                         break;
    3551           0 :                 case SQL_C_BIT:
    3552             :                 case SQL_C_STINYINT:
    3553             :                 case SQL_C_UTINYINT:
    3554             :                 case SQL_C_TINYINT:
    3555             :                 case SQL_C_SSHORT:
    3556             :                 case SQL_C_USHORT:
    3557             :                 case SQL_C_SHORT:
    3558             :                 case SQL_C_SLONG:
    3559             :                 case SQL_C_ULONG:
    3560             :                 case SQL_C_LONG:
    3561             :                 case SQL_C_SBIGINT:
    3562             :                 case SQL_C_UBIGINT:
    3563             :                 case SQL_C_NUMERIC:
    3564           0 :                         parsemonthinterval(&nval, &ival, sqltype);
    3565           0 :                         break;
    3566             :                 case SQL_C_INTERVAL_YEAR:
    3567             :                 case SQL_C_INTERVAL_MONTH:
    3568             :                 case SQL_C_INTERVAL_YEAR_TO_MONTH:
    3569             :                         break;
    3570           0 :                 default:
    3571             :                         /* Restricted data type attribute violation */
    3572           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3573           0 :                         goto failure;
    3574             :                 }
    3575           0 :                 switch (ival.interval_type) {
    3576           0 :                 case SQL_IS_YEAR:
    3577           0 :                         snprintf(data, sizeof(data), "INTERVAL %s'%u' YEAR", ival.interval_sign ? "" : "- ", (unsigned int) ival.intval.year_month.year);
    3578           0 :                         break;
    3579           0 :                 case SQL_IS_MONTH:
    3580           0 :                         snprintf(data, sizeof(data), "INTERVAL %s'%u' MONTH", ival.interval_sign ? "" : "- ", (unsigned int) ival.intval.year_month.month);
    3581           0 :                         break;
    3582           0 :                 case SQL_IS_YEAR_TO_MONTH:
    3583           0 :                         snprintf(data, sizeof(data), "INTERVAL %s'%u-%u' YEAR TO MONTH", ival.interval_sign ? "" : "- ", (unsigned int) ival.intval.year_month.year, (unsigned int) ival.intval.year_month.month);
    3584           0 :                         break;
    3585             :                 default:
    3586             :                         /* cannot happen */
    3587             :                         break;
    3588             :                 }
    3589           0 :                 assigns(buf, bufpos, buflen, data, stmt);
    3590             :                 break;
    3591           0 :         case SQL_INTERVAL_DAY:
    3592             :         case SQL_INTERVAL_HOUR:
    3593             :         case SQL_INTERVAL_MINUTE:
    3594             :         case SQL_INTERVAL_SECOND:
    3595             :         case SQL_INTERVAL_DAY_TO_HOUR:
    3596             :         case SQL_INTERVAL_DAY_TO_MINUTE:
    3597             :         case SQL_INTERVAL_DAY_TO_SECOND:
    3598             :         case SQL_INTERVAL_HOUR_TO_MINUTE:
    3599             :         case SQL_INTERVAL_HOUR_TO_SECOND:
    3600             :         case SQL_INTERVAL_MINUTE_TO_SECOND:
    3601           0 :                 switch (ctype) {
    3602           0 :                 case SQL_C_CHAR:
    3603             :                 case SQL_C_WCHAR:
    3604             :                 case SQL_C_BINARY:
    3605           0 :                         if (parsesecondintervalstring(&sval, &slen, &ival, &ivalprec) == SQL_ERROR) {
    3606             :                                 /* Invalid character value for cast
    3607             :                                  * specification */
    3608           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3609           0 :                                 goto failure;
    3610             :                         }
    3611             :                         break;
    3612           0 :                 case SQL_C_BIT:
    3613             :                 case SQL_C_STINYINT:
    3614             :                 case SQL_C_UTINYINT:
    3615             :                 case SQL_C_TINYINT:
    3616             :                 case SQL_C_SSHORT:
    3617             :                 case SQL_C_USHORT:
    3618             :                 case SQL_C_SHORT:
    3619             :                 case SQL_C_SLONG:
    3620             :                 case SQL_C_ULONG:
    3621             :                 case SQL_C_LONG:
    3622             :                 case SQL_C_SBIGINT:
    3623             :                 case SQL_C_UBIGINT:
    3624             :                 case SQL_C_NUMERIC:
    3625           0 :                         parsesecondinterval(&nval, &ival, sqltype);
    3626           0 :                         break;
    3627             :                 case SQL_C_INTERVAL_DAY:
    3628             :                 case SQL_C_INTERVAL_HOUR:
    3629             :                 case SQL_C_INTERVAL_MINUTE:
    3630             :                 case SQL_C_INTERVAL_SECOND:
    3631             :                 case SQL_C_INTERVAL_DAY_TO_HOUR:
    3632             :                 case SQL_C_INTERVAL_DAY_TO_MINUTE:
    3633             :                 case SQL_C_INTERVAL_DAY_TO_SECOND:
    3634             :                 case SQL_C_INTERVAL_HOUR_TO_MINUTE:
    3635             :                 case SQL_C_INTERVAL_HOUR_TO_SECOND:
    3636             :                 case SQL_C_INTERVAL_MINUTE_TO_SECOND:
    3637             :                         break;
    3638           0 :                 default:
    3639             :                         /* Restricted data type attribute violation */
    3640           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3641           0 :                         goto failure;
    3642             :                 }
    3643           0 :                 snprintf(data, sizeof(data), "INTERVAL %s'%u %u:%u:%u", ival.interval_sign ? "" : "- ", (unsigned int) ival.intval.day_second.day, (unsigned int) ival.intval.day_second.hour, (unsigned int) ival.intval.day_second.minute, (unsigned int) ival.intval.day_second.second);
    3644           0 :                 assigns(buf, bufpos, buflen, data, stmt);
    3645           0 :                 assigns(buf, bufpos, buflen, "' DAY TO SECOND", stmt);
    3646             :                 break;
    3647        2002 :         case SQL_DECIMAL:
    3648             :         case SQL_NUMERIC:
    3649             :         case SQL_SMALLINT:
    3650             :         case SQL_INTEGER:
    3651             :         case SQL_BIGINT:
    3652             :         case SQL_HUGEINT:
    3653             :         case SQL_BIT:
    3654             :                 /* first convert to nval (if not already done) */
    3655        2002 :                 switch (ctype) {
    3656             :                 case SQL_C_FLOAT:
    3657             :                 case SQL_C_DOUBLE:
    3658           0 :                         for (i = 0; i < 18; i++) {
    3659           0 :                                 snprintf(data, sizeof(data), "%.*g", i, fval);
    3660           0 :                                 if (fval == strtod(data, NULL))
    3661             :                                         break;
    3662             :                         }
    3663           0 :                         sval = data;
    3664             :                         /* fall through */
    3665           0 :                 case SQL_C_CHAR:
    3666             :                 case SQL_C_WCHAR:
    3667             :                 case SQL_C_BINARY:
    3668             :                         /* parse character data, reparse floating
    3669             :                          * point number */
    3670           0 :                         if (!parseint(sval, &nval)) {
    3671             :                                 /* Invalid character value for cast
    3672             :                                  * specification */
    3673           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3674           0 :                                 goto failure;
    3675             :                         }
    3676             :                         /* fall through */
    3677             :                 case SQL_C_BIT:
    3678             :                 case SQL_C_STINYINT:
    3679             :                 case SQL_C_UTINYINT:
    3680             :                 case SQL_C_TINYINT:
    3681             :                 case SQL_C_SSHORT:
    3682             :                 case SQL_C_USHORT:
    3683             :                 case SQL_C_SHORT:
    3684             :                 case SQL_C_SLONG:
    3685             :                 case SQL_C_ULONG:
    3686             :                 case SQL_C_LONG:
    3687             :                 case SQL_C_SBIGINT:
    3688             :                 case SQL_C_UBIGINT:
    3689             :                 case SQL_C_NUMERIC:
    3690             :                         break;
    3691           0 :                 case SQL_C_INTERVAL_YEAR:
    3692           0 :                         nval.precision = 0;
    3693           0 :                         nval.scale = 0;
    3694           0 :                         nval.sign = !ival.interval_sign;
    3695           0 :                         nval.val = ival.intval.year_month.year;
    3696           0 :                         break;
    3697           0 :                 case SQL_C_INTERVAL_MONTH:
    3698           0 :                         nval.precision = 0;
    3699           0 :                         nval.scale = 0;
    3700           0 :                         nval.sign = !ival.interval_sign;
    3701           0 :                         nval.val = 12 * ival.intval.year_month.year + ival.intval.year_month.month;
    3702           0 :                         break;
    3703           0 :                 case SQL_C_INTERVAL_DAY:
    3704           0 :                         nval.precision = 0;
    3705           0 :                         nval.scale = 0;
    3706           0 :                         nval.sign = !ival.interval_sign;
    3707           0 :                         nval.val = ival.intval.day_second.day;
    3708           0 :                         break;
    3709           0 :                 case SQL_C_INTERVAL_HOUR:
    3710           0 :                         nval.precision = 0;
    3711           0 :                         nval.scale = 0;
    3712           0 :                         nval.sign = !ival.interval_sign;
    3713           0 :                         nval.val = 24 * ival.intval.day_second.day + ival.intval.day_second.hour;
    3714           0 :                         break;
    3715           0 :                 case SQL_C_INTERVAL_MINUTE:
    3716           0 :                         nval.precision = 0;
    3717           0 :                         nval.scale = 0;
    3718           0 :                         nval.sign = !ival.interval_sign;
    3719           0 :                         nval.val = 60 * (24 * ival.intval.day_second.day + ival.intval.day_second.hour) + ival.intval.day_second.minute;
    3720           0 :                         break;
    3721           0 :                 case SQL_C_INTERVAL_SECOND:
    3722           0 :                         nval.precision = 0;
    3723           0 :                         nval.scale = 0;
    3724           0 :                         nval.sign = !ival.interval_sign;
    3725           0 :                         nval.val = 60 * (60 * (24 * ival.intval.day_second.day + ival.intval.day_second.hour) + ival.intval.day_second.minute) + ival.intval.day_second.second;
    3726           0 :                         if (ival.intval.day_second.fraction && ivalprec > 0) {
    3727           0 :                                 for (i = 0; i < ivalprec; i++) {
    3728           0 :                                         nval.val *= 10;
    3729           0 :                                         nval.scale++;
    3730             :                                 }
    3731           0 :                                 nval.val += ival.intval.day_second.fraction;
    3732             :                         }
    3733             :                         break;
    3734           0 :                 default:
    3735             :                         /* Restricted data type attribute violation */
    3736           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3737           0 :                         goto failure;
    3738             :                 }
    3739             :                 /* now store value contained in nval */
    3740             :                 {
    3741        2002 :                         int f = 1;
    3742             : 
    3743        2002 :                         for (i = 0; i < nval.scale; i++)
    3744           0 :                                 f *= 10;
    3745        2002 :                         if (sqltype == SQL_BIT) {
    3746           0 :                                 switch (nval.val / f) {
    3747             :                                 case 0:
    3748           0 :                                         assigns(buf, bufpos, buflen, "false", stmt);
    3749             :                                         break;
    3750             :                                 case 1:
    3751           0 :                                         assigns(buf, bufpos, buflen, "true", stmt);
    3752             :                                         break;
    3753           0 :                                 default:
    3754             :                                         /* Numeric value out of range */
    3755           0 :                                         addStmtError(stmt, "22003", NULL, 0);
    3756           0 :                                         goto failure;
    3757             :                                 }
    3758           0 :                                 if (f > 1 && nval.val % f) {
    3759             :                                         /* String data, right truncation */
    3760           0 :                                         addStmtError(stmt, "22001", NULL, 0);
    3761             :                                 }
    3762             :                         } else {
    3763        2002 :                                 snprintf(data, sizeof(data), "%s%" PRIu64, nval.sign ? "" : "-", (uint64_t) (nval.val / f));
    3764       10896 :                                 assigns(buf, bufpos, buflen, data, stmt);
    3765        2002 :                                 if (nval.scale > 0) {
    3766           0 :                                         switch (sqltype) {
    3767           0 :                                         case SQL_DECIMAL:
    3768             :                                         case SQL_NUMERIC:
    3769           0 :                                                 snprintf(data, sizeof(data), ".%0*" PRIu64, nval.scale, (uint64_t) (nval.val % f));
    3770           0 :                                                 assigns(buf, bufpos, buflen, data, stmt);
    3771             :                                                 break;
    3772           0 :                                         default:
    3773             :                                                 /* Fractional truncation */
    3774           0 :                                                 addStmtError(stmt, "01S07", NULL, 0);
    3775           0 :                                                 break;
    3776             :                                         }
    3777             :                                 } else {
    3778        2002 :                                         for (i = nval.scale; i < 0; i++)
    3779           0 :                                                 assign(buf, bufpos, buflen, '0', stmt);
    3780             :                                 }
    3781             :                         }
    3782             :                 }
    3783             :                 break;
    3784        2000 :         case SQL_REAL:
    3785             :         case SQL_DOUBLE:
    3786             :         case SQL_FLOAT:
    3787        2000 :                 switch (ctype) {
    3788           0 :                 case SQL_C_CHAR:
    3789             :                 case SQL_C_WCHAR:
    3790             :                 case SQL_C_BINARY:
    3791           0 :                         if (!parsedouble(sval, &fval)) {
    3792             :                                 /* Invalid character value for cast specification */
    3793           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3794           0 :                                 goto failure;
    3795             :                         }
    3796             :                         break;
    3797           0 :                 case SQL_C_BIT:
    3798             :                 case SQL_C_STINYINT:
    3799             :                 case SQL_C_UTINYINT:
    3800             :                 case SQL_C_TINYINT:
    3801             :                 case SQL_C_SSHORT:
    3802             :                 case SQL_C_USHORT:
    3803             :                 case SQL_C_SHORT:
    3804             :                 case SQL_C_SLONG:
    3805             :                 case SQL_C_ULONG:
    3806             :                 case SQL_C_LONG:
    3807             :                 case SQL_C_SBIGINT:
    3808             :                 case SQL_C_UBIGINT:
    3809             :                 case SQL_C_NUMERIC:
    3810           0 :                         fval = (double) (int64_t) nval.val;
    3811           0 :                         i = 1;
    3812           0 :                         while (nval.scale > 0) {
    3813           0 :                                 nval.scale--;
    3814           0 :                                 i *= 10;
    3815             :                         }
    3816           0 :                         fval /= (double) i;
    3817           0 :                         i = 1;
    3818           0 :                         while (nval.scale < 0) {
    3819           0 :                                 nval.scale++;
    3820           0 :                                 i *= 10;
    3821             :                         }
    3822           0 :                         fval *= (double) i;
    3823           0 :                         if (!nval.sign)
    3824           0 :                                 fval = -fval;
    3825             :                         break;
    3826             :                 case SQL_C_FLOAT:
    3827             :                 case SQL_C_DOUBLE:
    3828             :                         break;
    3829           0 :                 case SQL_C_INTERVAL_YEAR:
    3830           0 :                         fval = (double) ival.intval.year_month.year;
    3831           0 :                         if (ival.interval_sign)
    3832           0 :                                 fval = -fval;
    3833             :                         break;
    3834           0 :                 case SQL_C_INTERVAL_MONTH:
    3835           0 :                         fval = (double) (12 * ival.intval.year_month.year + ival.intval.year_month.month);
    3836           0 :                         if (ival.interval_sign)
    3837           0 :                                 fval = -fval;
    3838             :                         break;
    3839           0 :                 case SQL_C_INTERVAL_DAY:
    3840           0 :                         fval = (double) ival.intval.day_second.day;
    3841           0 :                         if (ival.interval_sign)
    3842           0 :                                 fval = -fval;
    3843             :                         break;
    3844           0 :                 case SQL_C_INTERVAL_HOUR:
    3845           0 :                         fval = (double) (24 * ival.intval.day_second.day + ival.intval.day_second.hour);
    3846           0 :                         if (ival.interval_sign)
    3847           0 :                                 fval = -fval;
    3848             :                         break;
    3849           0 :                 case SQL_C_INTERVAL_MINUTE:
    3850           0 :                         fval = (double) (60 * (24 * ival.intval.day_second.day + ival.intval.day_second.hour) + ival.intval.day_second.minute);
    3851           0 :                         if (ival.interval_sign)
    3852           0 :                                 fval = -fval;
    3853             :                         break;
    3854           0 :                 case SQL_C_INTERVAL_SECOND:
    3855           0 :                         fval = (double) (60 * (60 * (24 * ival.intval.day_second.day + ival.intval.day_second.hour) + ival.intval.day_second.minute) + ival.intval.day_second.second);
    3856           0 :                         if (ival.intval.day_second.fraction && ivalprec > 0) {
    3857             :                                 int f = 1;
    3858             : 
    3859           0 :                                 for (i = 0; i < ivalprec; i++)
    3860           0 :                                         f *= 10;
    3861           0 :                                 fval += ival.intval.day_second.fraction / (double) f;
    3862             :                         }
    3863           0 :                         if (ival.interval_sign)
    3864           0 :                                 fval = -fval;
    3865             :                         break;
    3866           0 :                 default:
    3867             :                         /* Restricted data type attribute violation */
    3868           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3869           0 :                         goto failure;
    3870             :                 }
    3871        6161 :                 for (i = 1; i < 18; i++) {
    3872        6161 :                         snprintf(data, sizeof(data), "%.*e", i, fval);
    3873        6161 :                         if (fval == strtod(data, NULL))
    3874             :                                 break;
    3875             :                 }
    3876       22161 :                 assigns(buf, bufpos, buflen, data, stmt);
    3877             :                 break;
    3878           0 :         case SQL_GUID:
    3879           0 :                 switch (ctype) {
    3880           0 :                 case SQL_C_CHAR:
    3881             :                 case SQL_C_WCHAR:
    3882           0 :                         if (slen != 36) {
    3883             :                                 /* not sure this is the correct error */
    3884             :                                 /* Invalid character value for cast
    3885             :                                  * specification */
    3886           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3887           0 :                                 goto failure;
    3888             :                         }
    3889           0 :                         if (sval[strspn(sval, "0123456789abcdefABCDEF-")] != 0) {
    3890             :                                 /* not sure this is the correct error */
    3891             :                                 /* Invalid character value for cast
    3892             :                                  * specification */
    3893           0 :                                 addStmtError(stmt, "22018", NULL, 0);
    3894           0 :                                 goto failure;
    3895             :                         }
    3896           0 :                         snprintf(data, sizeof(data), "%.36s", sval);
    3897           0 :                         break;
    3898           0 :                 case SQL_C_GUID:
    3899           0 :                         u = *(SQLGUID *)ptr;
    3900           0 :                         snprintf(data, sizeof(data),
    3901             :                                  "UUID '"
    3902             :                                  "%08"PRIx32"-%04"PRIx16"-%04"PRIx16
    3903             :                                  "-%02"PRIx8"%02"PRIx8
    3904             :                                  "-%02"PRIx8"%02"PRIx8"%02"PRIx8
    3905             :                                  "%02"PRIx8"%02"PRIx8"%02"PRIx8
    3906             :                                  "'",
    3907             :                                  u.Data1, u.Data2, u.Data3,
    3908             :                                  u.Data4[0], u.Data4[1],
    3909             :                                  u.Data4[2], u.Data4[3],
    3910             :                                  u.Data4[4], u.Data4[5],
    3911             :                                  u.Data4[6], u.Data4[7]);
    3912           0 :                         break;
    3913           0 :                 default:
    3914             :                         /* Restricted data type attribute violation */
    3915           0 :                         addStmtError(stmt, "07006", NULL, 0);
    3916           0 :                         goto failure;
    3917             :                 }
    3918           0 :                 assigns(buf, bufpos, buflen, data, stmt);
    3919             :                 break;
    3920             :         }
    3921       10004 :         if (ctype == SQL_C_WCHAR)
    3922           2 :                 free(sval);
    3923       10004 :         *bufp = buf;
    3924       10004 :         *bufposp = bufpos;
    3925       10004 :         *buflenp = buflen;
    3926       10004 :         return SQL_SUCCESS;
    3927             : 
    3928           0 :   failure:
    3929           0 :         if (ctype == SQL_C_WCHAR)
    3930           0 :                 free(sval);
    3931             :         return SQL_ERROR;
    3932             : }

Generated by: LCOV version 1.14