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

Generated by: LCOV version 1.14