1 /* src/interfaces/ecpg/ecpglib/data.c */
2
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
5
6 #include <math.h>
7
8 #include "ecpgerrno.h"
9 #include "ecpglib.h"
10 #include "ecpglib_extern.h"
11 #include "ecpgtype.h"
12 #include "pgtypes_date.h"
13 #include "pgtypes_interval.h"
14 #include "pgtypes_numeric.h"
15 #include "pgtypes_timestamp.h"
16 #include "sqlca.h"
17
18 /* returns true if character c is a delimiter for the given array type */
19 static bool
array_delimiter(enum ARRAY_TYPE isarray,char c)20 array_delimiter(enum ARRAY_TYPE isarray, char c)
21 {
22 if (isarray == ECPG_ARRAY_ARRAY && c == ',')
23 return true;
24
25 if (isarray == ECPG_ARRAY_VECTOR && c == ' ')
26 return true;
27
28 return false;
29 }
30
31 /* returns true if character c marks the boundary for the given array type */
32 static bool
array_boundary(enum ARRAY_TYPE isarray,char c)33 array_boundary(enum ARRAY_TYPE isarray, char c)
34 {
35 if (isarray == ECPG_ARRAY_ARRAY && c == '}')
36 return true;
37
38 if (isarray == ECPG_ARRAY_VECTOR && c == '\0')
39 return true;
40
41 return false;
42 }
43
44 /* returns true if some garbage is found at the end of the scanned string */
45 static bool
garbage_left(enum ARRAY_TYPE isarray,char ** scan_length,enum COMPAT_MODE compat)46 garbage_left(enum ARRAY_TYPE isarray, char **scan_length, enum COMPAT_MODE compat)
47 {
48 /*
49 * INFORMIX allows for selecting a numeric into an int, the result is
50 * truncated
51 */
52 if (isarray == ECPG_ARRAY_NONE)
53 {
54 if (INFORMIX_MODE(compat) && **scan_length == '.')
55 {
56 /* skip invalid characters */
57 do
58 {
59 (*scan_length)++;
60 } while (isdigit((unsigned char) **scan_length));
61 }
62
63 if (**scan_length != ' ' && **scan_length != '\0')
64 return true;
65 }
66 else if (ECPG_IS_ARRAY(isarray) && !array_delimiter(isarray, **scan_length) && !array_boundary(isarray, **scan_length))
67 return true;
68
69 return false;
70 }
71
72 /* stolen code from src/backend/utils/adt/float.c */
73 #if defined(WIN32) && !defined(NAN)
74 static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
75
76 #define NAN (*(const double *) nan)
77 #endif
78
79 static double
get_float8_infinity(void)80 get_float8_infinity(void)
81 {
82 #ifdef INFINITY
83 return (double) INFINITY;
84 #else
85 return (double) (HUGE_VAL * HUGE_VAL);
86 #endif
87 }
88
89 static double
get_float8_nan(void)90 get_float8_nan(void)
91 {
92 /* (double) NAN doesn't work on some NetBSD/MIPS releases */
93 #if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
94 return (double) NAN;
95 #else
96 return (double) (0.0 / 0.0);
97 #endif
98 }
99
100 static bool
check_special_value(char * ptr,double * retval,char ** endptr)101 check_special_value(char *ptr, double *retval, char **endptr)
102 {
103 if (pg_strncasecmp(ptr, "NaN", 3) == 0)
104 {
105 *retval = get_float8_nan();
106 *endptr = ptr + 3;
107 return true;
108 }
109 else if (pg_strncasecmp(ptr, "Infinity", 8) == 0)
110 {
111 *retval = get_float8_infinity();
112 *endptr = ptr + 8;
113 return true;
114 }
115 else if (pg_strncasecmp(ptr, "-Infinity", 9) == 0)
116 {
117 *retval = -get_float8_infinity();
118 *endptr = ptr + 9;
119 return true;
120 }
121
122 return false;
123 }
124
125 /* imported from src/backend/utils/adt/encode.c */
126
127 unsigned
ecpg_hex_enc_len(unsigned srclen)128 ecpg_hex_enc_len(unsigned srclen)
129 {
130 return srclen << 1;
131 }
132
133 unsigned
ecpg_hex_dec_len(unsigned srclen)134 ecpg_hex_dec_len(unsigned srclen)
135 {
136 return srclen >> 1;
137 }
138
139 static inline char
get_hex(char c)140 get_hex(char c)
141 {
142 static const int8 hexlookup[128] = {
143 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
144 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
145 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
146 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
147 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
148 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
149 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
151 };
152 int res = -1;
153
154 if (c > 0 && c < 127)
155 res = hexlookup[(unsigned char) c];
156
157 return (char) res;
158 }
159
160 static unsigned
hex_decode(const char * src,unsigned len,char * dst)161 hex_decode(const char *src, unsigned len, char *dst)
162 {
163 const char *s,
164 *srcend;
165 char v1,
166 v2,
167 *p;
168
169 srcend = src + len;
170 s = src;
171 p = dst;
172 while (s < srcend)
173 {
174 if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
175 {
176 s++;
177 continue;
178 }
179 v1 = get_hex(*s++) << 4;
180 if (s >= srcend)
181 return -1;
182
183 v2 = get_hex(*s++);
184 *p++ = v1 | v2;
185 }
186
187 return p - dst;
188 }
189
190 unsigned
ecpg_hex_encode(const char * src,unsigned len,char * dst)191 ecpg_hex_encode(const char *src, unsigned len, char *dst)
192 {
193 static const char hextbl[] = "0123456789abcdef";
194 const char *end = src + len;
195
196 while (src < end)
197 {
198 *dst++ = hextbl[(*src >> 4) & 0xF];
199 *dst++ = hextbl[*src & 0xF];
200 src++;
201 }
202 return len * 2;
203 }
204
205 bool
ecpg_get_data(const PGresult * results,int act_tuple,int act_field,int lineno,enum ECPGttype type,enum ECPGttype ind_type,char * var,char * ind,long varcharsize,long offset,long ind_offset,enum ARRAY_TYPE isarray,enum COMPAT_MODE compat,bool force_indicator)206 ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
207 enum ECPGttype type, enum ECPGttype ind_type,
208 char *var, char *ind, long varcharsize, long offset,
209 long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator)
210 {
211 struct sqlca_t *sqlca = ECPGget_sqlca();
212 char *pval = (char *) PQgetvalue(results, act_tuple, act_field);
213 int binary = PQfformat(results, act_field);
214 int size = PQgetlength(results, act_tuple, act_field);
215 int value_for_indicator = 0;
216 long log_offset;
217
218 if (sqlca == NULL)
219 {
220 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
221 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
222 return false;
223 }
224
225 /*
226 * If we are running in a regression test, do not log the offset variable,
227 * it depends on the machine's alignment.
228 */
229 if (ecpg_internal_regression_mode)
230 log_offset = -1;
231 else
232 log_offset = offset;
233
234 ecpg_log("ecpg_get_data on line %d: RESULT: %s offset: %ld; array: %s\n", lineno, pval ? (binary ? "BINARY" : pval) : "EMPTY", log_offset, ECPG_IS_ARRAY(isarray) ? "yes" : "no");
235
236 /* pval is a pointer to the value */
237 if (!pval)
238 {
239 /*
240 * This should never happen because we already checked that we found
241 * at least one tuple, but let's play it safe.
242 */
243 ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
244 return false;
245 }
246
247 /* We will have to decode the value */
248
249 /*
250 * check for null value and set indicator accordingly, i.e. -1 if NULL and
251 * 0 if not
252 */
253 if (PQgetisnull(results, act_tuple, act_field))
254 value_for_indicator = -1;
255
256 switch (ind_type)
257 {
258 case ECPGt_short:
259 case ECPGt_unsigned_short:
260 *((short *) (ind + ind_offset * act_tuple)) = value_for_indicator;
261 break;
262 case ECPGt_int:
263 case ECPGt_unsigned_int:
264 *((int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
265 break;
266 case ECPGt_long:
267 case ECPGt_unsigned_long:
268 *((long *) (ind + ind_offset * act_tuple)) = value_for_indicator;
269 break;
270 case ECPGt_long_long:
271 case ECPGt_unsigned_long_long:
272 *((long long int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
273 break;
274 case ECPGt_NO_INDICATOR:
275 if (value_for_indicator == -1)
276 {
277 if (force_indicator == false)
278 {
279 /*
280 * Informix has an additional way to specify NULLs note
281 * that this uses special values to denote NULL
282 */
283 ECPGset_noind_null(type, var + offset * act_tuple);
284 }
285 else
286 {
287 ecpg_raise(lineno, ECPG_MISSING_INDICATOR,
288 ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER,
289 NULL);
290 return false;
291 }
292 }
293 break;
294 default:
295 ecpg_raise(lineno, ECPG_UNSUPPORTED,
296 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
297 ecpg_type_name(ind_type));
298 return false;
299 break;
300 }
301
302 if (value_for_indicator == -1)
303 return true;
304
305 /* let's check if it really is an array if it should be one */
306 if (isarray == ECPG_ARRAY_ARRAY)
307 {
308 if (*pval != '{')
309 {
310 ecpg_raise(lineno, ECPG_DATA_NOT_ARRAY,
311 ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
312 return false;
313 }
314
315 switch (type)
316 {
317 case ECPGt_char:
318 case ECPGt_unsigned_char:
319 case ECPGt_varchar:
320 case ECPGt_string:
321 break;
322
323 default:
324 pval++;
325 break;
326 }
327 }
328
329 do
330 {
331 if (binary)
332 {
333 if (varcharsize == 0 || varcharsize * offset >= size)
334 memcpy(var + offset * act_tuple, pval, size);
335 else
336 {
337 memcpy(var + offset * act_tuple, pval, varcharsize * offset);
338
339 if (varcharsize * offset < size)
340 {
341 /* truncation */
342 switch (ind_type)
343 {
344 case ECPGt_short:
345 case ECPGt_unsigned_short:
346 *((short *) (ind + ind_offset * act_tuple)) = size;
347 break;
348 case ECPGt_int:
349 case ECPGt_unsigned_int:
350 *((int *) (ind + ind_offset * act_tuple)) = size;
351 break;
352 case ECPGt_long:
353 case ECPGt_unsigned_long:
354 *((long *) (ind + ind_offset * act_tuple)) = size;
355 break;
356 case ECPGt_long_long:
357 case ECPGt_unsigned_long_long:
358 *((long long int *) (ind + ind_offset * act_tuple)) = size;
359 break;
360 default:
361 break;
362 }
363 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
364 }
365 }
366 pval += size;
367 }
368 else
369 {
370 switch (type)
371 {
372 long res;
373 unsigned long ures;
374 double dres;
375 char *scan_length;
376 numeric *nres;
377 date ddres;
378 timestamp tres;
379 interval *ires;
380 char *endptr,
381 endchar;
382
383 case ECPGt_short:
384 case ECPGt_int:
385 case ECPGt_long:
386 res = strtol(pval, &scan_length, 10);
387 if (garbage_left(isarray, &scan_length, compat))
388 {
389 ecpg_raise(lineno, ECPG_INT_FORMAT,
390 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
391 return false;
392 }
393 pval = scan_length;
394
395 switch (type)
396 {
397 case ECPGt_short:
398 *((short *) (var + offset * act_tuple)) = (short) res;
399 break;
400 case ECPGt_int:
401 *((int *) (var + offset * act_tuple)) = (int) res;
402 break;
403 case ECPGt_long:
404 *((long *) (var + offset * act_tuple)) = (long) res;
405 break;
406 default:
407 /* Cannot happen */
408 break;
409 }
410 break;
411
412 case ECPGt_unsigned_short:
413 case ECPGt_unsigned_int:
414 case ECPGt_unsigned_long:
415 ures = strtoul(pval, &scan_length, 10);
416 if (garbage_left(isarray, &scan_length, compat))
417 {
418 ecpg_raise(lineno, ECPG_UINT_FORMAT,
419 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
420 return false;
421 }
422 pval = scan_length;
423
424 switch (type)
425 {
426 case ECPGt_unsigned_short:
427 *((unsigned short *) (var + offset * act_tuple)) = (unsigned short) ures;
428 break;
429 case ECPGt_unsigned_int:
430 *((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures;
431 break;
432 case ECPGt_unsigned_long:
433 *((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures;
434 break;
435 default:
436 /* Cannot happen */
437 break;
438 }
439 break;
440
441 #ifdef HAVE_STRTOLL
442 case ECPGt_long_long:
443 *((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
444 if (garbage_left(isarray, &scan_length, compat))
445 {
446 ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
447 return false;
448 }
449 pval = scan_length;
450
451 break;
452 #endif /* HAVE_STRTOLL */
453 #ifdef HAVE_STRTOULL
454 case ECPGt_unsigned_long_long:
455 *((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10);
456 if (garbage_left(isarray, &scan_length, compat))
457 {
458 ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
459 return false;
460 }
461 pval = scan_length;
462
463 break;
464 #endif /* HAVE_STRTOULL */
465
466 case ECPGt_float:
467 case ECPGt_double:
468 if (isarray && *pval == '"')
469 pval++;
470
471 if (!check_special_value(pval, &dres, &scan_length))
472 dres = strtod(pval, &scan_length);
473
474 if (isarray && *scan_length == '"')
475 scan_length++;
476
477 /* no special INFORMIX treatment for floats */
478 if (garbage_left(isarray, &scan_length, ECPG_COMPAT_PGSQL))
479 {
480 ecpg_raise(lineno, ECPG_FLOAT_FORMAT,
481 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
482 return false;
483 }
484 pval = scan_length;
485
486 switch (type)
487 {
488 case ECPGt_float:
489 *((float *) (var + offset * act_tuple)) = dres;
490 break;
491 case ECPGt_double:
492 *((double *) (var + offset * act_tuple)) = dres;
493 break;
494 default:
495 /* Cannot happen */
496 break;
497 }
498 break;
499
500 case ECPGt_bool:
501 if (pval[0] == 'f' && pval[1] == '\0')
502 {
503 *((bool *) (var + offset * act_tuple)) = false;
504 pval++;
505 break;
506 }
507 else if (pval[0] == 't' && pval[1] == '\0')
508 {
509 *((bool *) (var + offset * act_tuple)) = true;
510 pval++;
511 break;
512 }
513 else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field))
514 {
515 /* NULL is valid */
516 break;
517 }
518
519 ecpg_raise(lineno, ECPG_CONVERT_BOOL,
520 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
521 return false;
522 break;
523
524 case ECPGt_bytea:
525 {
526 struct ECPGgeneric_bytea *variable =
527 (struct ECPGgeneric_bytea *) (var + offset * act_tuple);
528 long dst_size,
529 src_size,
530 dec_size;
531
532 dst_size = ecpg_hex_enc_len(varcharsize);
533 src_size = size - 2; /* exclude backslash + 'x' */
534 dec_size = src_size < dst_size ? src_size : dst_size;
535 variable->len = hex_decode(pval + 2, dec_size, variable->arr);
536
537 if (dst_size < src_size)
538 {
539 long rcv_size = ecpg_hex_dec_len(size - 2);
540
541 /* truncation */
542 switch (ind_type)
543 {
544 case ECPGt_short:
545 case ECPGt_unsigned_short:
546 *((short *) (ind + ind_offset * act_tuple)) = rcv_size;
547 break;
548 case ECPGt_int:
549 case ECPGt_unsigned_int:
550 *((int *) (ind + ind_offset * act_tuple)) = rcv_size;
551 break;
552 case ECPGt_long:
553 case ECPGt_unsigned_long:
554 *((long *) (ind + ind_offset * act_tuple)) = rcv_size;
555 break;
556 case ECPGt_long_long:
557 case ECPGt_unsigned_long_long:
558 *((long long int *) (ind + ind_offset * act_tuple)) = rcv_size;
559 break;
560 default:
561 break;
562 }
563 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
564 }
565
566 pval += size;
567
568 }
569 break;
570
571 case ECPGt_char:
572 case ECPGt_unsigned_char:
573 case ECPGt_string:
574 {
575 char *str = (char *) (var + offset * act_tuple);
576
577 /*
578 * If varcharsize is unknown and the offset is that of
579 * char *, then this variable represents the array of
580 * character pointers. So, use extra indirection.
581 */
582 if (varcharsize == 0 && offset == sizeof(char *))
583 str = *(char **) str;
584
585 if (varcharsize == 0 || varcharsize > size)
586 {
587 /*
588 * compatibility mode, blank pad and null
589 * terminate char array
590 */
591 if (ORACLE_MODE(compat) && (type == ECPGt_char || type == ECPGt_unsigned_char))
592 {
593 memset(str, ' ', varcharsize);
594 memcpy(str, pval, size);
595 str[varcharsize - 1] = '\0';
596
597 /*
598 * compatibility mode empty string gets -1
599 * indicator but no warning
600 */
601 if (size == 0)
602 {
603 /* truncation */
604 switch (ind_type)
605 {
606 case ECPGt_short:
607 case ECPGt_unsigned_short:
608 *((short *) (ind + ind_offset * act_tuple)) = -1;
609 break;
610 case ECPGt_int:
611 case ECPGt_unsigned_int:
612 *((int *) (ind + ind_offset * act_tuple)) = -1;
613 break;
614 case ECPGt_long:
615 case ECPGt_unsigned_long:
616 *((long *) (ind + ind_offset * act_tuple)) = -1;
617 break;
618 case ECPGt_long_long:
619 case ECPGt_unsigned_long_long:
620 *((long long int *) (ind + ind_offset * act_tuple)) = -1;
621 break;
622 default:
623 break;
624 }
625 }
626 }
627 else
628 {
629 strncpy(str, pval, size + 1);
630 }
631 /* do the rtrim() */
632 if (type == ECPGt_string)
633 {
634 char *last = str + size;
635
636 while (last > str && (*last == ' ' || *last == '\0'))
637 {
638 *last = '\0';
639 last--;
640 }
641 }
642 }
643 else
644 {
645 strncpy(str, pval, varcharsize);
646
647 /* compatibility mode, null terminate char array */
648 if (ORACLE_MODE(compat) && (varcharsize - 1) < size)
649 {
650 if (type == ECPGt_char || type == ECPGt_unsigned_char)
651 str[varcharsize - 1] = '\0';
652 }
653
654 if (varcharsize < size || (ORACLE_MODE(compat) && (varcharsize - 1) < size))
655 {
656 /* truncation */
657 switch (ind_type)
658 {
659 case ECPGt_short:
660 case ECPGt_unsigned_short:
661 *((short *) (ind + ind_offset * act_tuple)) = size;
662 break;
663 case ECPGt_int:
664 case ECPGt_unsigned_int:
665 *((int *) (ind + ind_offset * act_tuple)) = size;
666 break;
667 case ECPGt_long:
668 case ECPGt_unsigned_long:
669 *((long *) (ind + ind_offset * act_tuple)) = size;
670 break;
671 case ECPGt_long_long:
672 case ECPGt_unsigned_long_long:
673 *((long long int *) (ind + ind_offset * act_tuple)) = size;
674 break;
675 default:
676 break;
677 }
678 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
679 }
680 }
681 pval += size;
682 }
683 break;
684
685 case ECPGt_varchar:
686 {
687 struct ECPGgeneric_varchar *variable =
688 (struct ECPGgeneric_varchar *) (var + offset * act_tuple);
689
690 variable->len = size;
691 if (varcharsize == 0)
692 strncpy(variable->arr, pval, variable->len);
693 else
694 {
695 strncpy(variable->arr, pval, varcharsize);
696
697 if (variable->len > varcharsize)
698 {
699 /* truncation */
700 switch (ind_type)
701 {
702 case ECPGt_short:
703 case ECPGt_unsigned_short:
704 *((short *) (ind + ind_offset * act_tuple)) = variable->len;
705 break;
706 case ECPGt_int:
707 case ECPGt_unsigned_int:
708 *((int *) (ind + ind_offset * act_tuple)) = variable->len;
709 break;
710 case ECPGt_long:
711 case ECPGt_unsigned_long:
712 *((long *) (ind + ind_offset * act_tuple)) = variable->len;
713 break;
714 case ECPGt_long_long:
715 case ECPGt_unsigned_long_long:
716 *((long long int *) (ind + ind_offset * act_tuple)) = variable->len;
717 break;
718 default:
719 break;
720 }
721 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
722
723 variable->len = varcharsize;
724 }
725 }
726 pval += size;
727 }
728 break;
729
730 case ECPGt_decimal:
731 case ECPGt_numeric:
732 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '}'; endptr++);
733 endchar = *endptr;
734 *endptr = '\0';
735 nres = PGTYPESnumeric_from_asc(pval, &scan_length);
736 *endptr = endchar;
737
738 /* did we get an error? */
739 if (nres == NULL)
740 {
741 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
742 lineno, pval, errno);
743
744 if (INFORMIX_MODE(compat))
745 {
746 /*
747 * Informix wants its own NULL value here instead
748 * of an error
749 */
750 nres = PGTYPESnumeric_new();
751 if (nres)
752 ECPGset_noind_null(ECPGt_numeric, nres);
753 else
754 {
755 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
756 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
757 return false;
758 }
759 }
760 else
761 {
762 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
763 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
764 return false;
765 }
766 }
767 else
768 {
769 if (!isarray && garbage_left(isarray, &scan_length, compat))
770 {
771 free(nres);
772 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
773 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
774 return false;
775 }
776 }
777 pval = scan_length;
778
779 if (type == ECPGt_numeric)
780 PGTYPESnumeric_copy(nres, (numeric *) (var + offset * act_tuple));
781 else
782 PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * act_tuple));
783
784 PGTYPESnumeric_free(nres);
785 break;
786
787 case ECPGt_interval:
788 if (*pval == '"')
789 pval++;
790
791 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
792 endchar = *endptr;
793 *endptr = '\0';
794 ires = PGTYPESinterval_from_asc(pval, &scan_length);
795 *endptr = endchar;
796
797 /* did we get an error? */
798 if (ires == NULL)
799 {
800 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
801 lineno, pval, errno);
802
803 if (INFORMIX_MODE(compat))
804 {
805 /*
806 * Informix wants its own NULL value here instead
807 * of an error
808 */
809 ires = (interval *) ecpg_alloc(sizeof(interval), lineno);
810 if (!ires)
811 return false;
812
813 ECPGset_noind_null(ECPGt_interval, ires);
814 }
815 else
816 {
817 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
818 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
819 return false;
820 }
821 }
822 else
823 {
824 if (*scan_length == '"')
825 scan_length++;
826
827 if (!isarray && garbage_left(isarray, &scan_length, compat))
828 {
829 free(ires);
830 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
831 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
832 return false;
833 }
834 }
835 pval = scan_length;
836
837 PGTYPESinterval_copy(ires, (interval *) (var + offset * act_tuple));
838 free(ires);
839 break;
840
841 case ECPGt_date:
842 if (*pval == '"')
843 pval++;
844
845 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
846 endchar = *endptr;
847 *endptr = '\0';
848 ddres = PGTYPESdate_from_asc(pval, &scan_length);
849 *endptr = endchar;
850
851 /* did we get an error? */
852 if (errno != 0)
853 {
854 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
855 lineno, pval, errno);
856
857 if (INFORMIX_MODE(compat))
858 {
859 /*
860 * Informix wants its own NULL value here instead
861 * of an error
862 */
863 ECPGset_noind_null(ECPGt_date, &ddres);
864 }
865 else
866 {
867 ecpg_raise(lineno, ECPG_DATE_FORMAT,
868 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
869 return false;
870 }
871 }
872 else
873 {
874 if (*scan_length == '"')
875 scan_length++;
876
877 if (!isarray && garbage_left(isarray, &scan_length, compat))
878 {
879 ecpg_raise(lineno, ECPG_DATE_FORMAT,
880 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
881 return false;
882 }
883 }
884
885 *((date *) (var + offset * act_tuple)) = ddres;
886 pval = scan_length;
887 break;
888
889 case ECPGt_timestamp:
890 if (*pval == '"')
891 pval++;
892
893 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
894 endchar = *endptr;
895 *endptr = '\0';
896 tres = PGTYPEStimestamp_from_asc(pval, &scan_length);
897 *endptr = endchar;
898
899 /* did we get an error? */
900 if (errno != 0)
901 {
902 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
903 lineno, pval, errno);
904
905 if (INFORMIX_MODE(compat))
906 {
907 /*
908 * Informix wants its own NULL value here instead
909 * of an error
910 */
911 ECPGset_noind_null(ECPGt_timestamp, &tres);
912 }
913 else
914 {
915 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
916 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
917 return false;
918 }
919 }
920 else
921 {
922 if (*scan_length == '"')
923 scan_length++;
924
925 if (!isarray && garbage_left(isarray, &scan_length, compat))
926 {
927 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
928 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
929 return false;
930 }
931 }
932
933 *((timestamp *) (var + offset * act_tuple)) = tres;
934 pval = scan_length;
935 break;
936
937 default:
938 ecpg_raise(lineno, ECPG_UNSUPPORTED,
939 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
940 ecpg_type_name(type));
941 return false;
942 break;
943 }
944 if (ECPG_IS_ARRAY(isarray))
945 {
946 bool string = false;
947
948 /* set array to next entry */
949 ++act_tuple;
950
951 /* set pval to the next entry */
952
953 /*
954 * *pval != '\0' should not be needed, but is used as a safety
955 * guard
956 */
957 for (; *pval != '\0' && (string || (!array_delimiter(isarray, *pval) && !array_boundary(isarray, *pval))); ++pval)
958 if (*pval == '"')
959 string = string ? false : true;
960
961 if (array_delimiter(isarray, *pval))
962 ++pval;
963 }
964 }
965 } while (*pval != '\0' && !array_boundary(isarray, *pval));
966
967 return true;
968 }
969