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