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 (*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 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)126 ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
127 enum ECPGttype type, enum ECPGttype ind_type,
128 char *var, char *ind, long varcharsize, long offset,
129 long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator)
130 {
131 struct sqlca_t *sqlca = ECPGget_sqlca();
132 char *pval = (char *) PQgetvalue(results, act_tuple, act_field);
133 int binary = PQfformat(results, act_field);
134 int size = PQgetlength(results, act_tuple, act_field);
135 int value_for_indicator = 0;
136 long log_offset;
137
138 if (sqlca == NULL)
139 {
140 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
141 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
142 return (false);
143 }
144
145 /*
146 * If we are running in a regression test, do not log the offset variable,
147 * it depends on the machine's alignment.
148 */
149 if (ecpg_internal_regression_mode)
150 log_offset = -1;
151 else
152 log_offset = offset;
153
154 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");
155
156 /* pval is a pointer to the value */
157 if (!pval)
158 {
159 /*
160 * This should never happen because we already checked that we found
161 * at least one tuple, but let's play it safe.
162 */
163 ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
164 return (false);
165 }
166
167 /* We will have to decode the value */
168
169 /*
170 * check for null value and set indicator accordingly, i.e. -1 if NULL and
171 * 0 if not
172 */
173 if (PQgetisnull(results, act_tuple, act_field))
174 value_for_indicator = -1;
175
176 switch (ind_type)
177 {
178 case ECPGt_short:
179 case ECPGt_unsigned_short:
180 *((short *) (ind + ind_offset * act_tuple)) = value_for_indicator;
181 break;
182 case ECPGt_int:
183 case ECPGt_unsigned_int:
184 *((int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
185 break;
186 case ECPGt_long:
187 case ECPGt_unsigned_long:
188 *((long *) (ind + ind_offset * act_tuple)) = value_for_indicator;
189 break;
190 #ifdef HAVE_LONG_LONG_INT
191 case ECPGt_long_long:
192 case ECPGt_unsigned_long_long:
193 *((long long int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
194 break;
195 #endif /* HAVE_LONG_LONG_INT */
196 case ECPGt_NO_INDICATOR:
197 if (value_for_indicator == -1)
198 {
199 if (force_indicator == false)
200 {
201 /*
202 * Informix has an additional way to specify NULLs note
203 * that this uses special values to denote NULL
204 */
205 ECPGset_noind_null(type, var + offset * act_tuple);
206 }
207 else
208 {
209 ecpg_raise(lineno, ECPG_MISSING_INDICATOR,
210 ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER,
211 NULL);
212 return (false);
213 }
214 }
215 break;
216 default:
217 ecpg_raise(lineno, ECPG_UNSUPPORTED,
218 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
219 ecpg_type_name(ind_type));
220 return (false);
221 break;
222 }
223
224 if (value_for_indicator == -1)
225 return (true);
226
227 /* let's check if it really is an array if it should be one */
228 if (isarray == ECPG_ARRAY_ARRAY)
229 {
230 if (*pval != '{')
231 {
232 ecpg_raise(lineno, ECPG_DATA_NOT_ARRAY,
233 ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
234 return (false);
235 }
236
237 switch (type)
238 {
239 case ECPGt_char:
240 case ECPGt_unsigned_char:
241 case ECPGt_varchar:
242 case ECPGt_string:
243 break;
244
245 default:
246 pval++;
247 break;
248 }
249 }
250
251 do
252 {
253 if (binary)
254 {
255 if (varcharsize == 0 || varcharsize * offset >= size)
256 memcpy(var + offset * act_tuple, pval, size);
257 else
258 {
259 memcpy(var + offset * act_tuple, pval, varcharsize * offset);
260
261 if (varcharsize * offset < size)
262 {
263 /* truncation */
264 switch (ind_type)
265 {
266 case ECPGt_short:
267 case ECPGt_unsigned_short:
268 *((short *) (ind + ind_offset * act_tuple)) = size;
269 break;
270 case ECPGt_int:
271 case ECPGt_unsigned_int:
272 *((int *) (ind + ind_offset * act_tuple)) = size;
273 break;
274 case ECPGt_long:
275 case ECPGt_unsigned_long:
276 *((long *) (ind + ind_offset * act_tuple)) = size;
277 break;
278 #ifdef HAVE_LONG_LONG_INT
279 case ECPGt_long_long:
280 case ECPGt_unsigned_long_long:
281 *((long long int *) (ind + ind_offset * act_tuple)) = size;
282 break;
283 #endif /* HAVE_LONG_LONG_INT */
284 default:
285 break;
286 }
287 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
288 }
289 }
290 pval += size;
291 }
292 else
293 {
294 switch (type)
295 {
296 long res;
297 unsigned long ures;
298 double dres;
299 char *scan_length;
300 numeric *nres;
301 date ddres;
302 timestamp tres;
303 interval *ires;
304 char *endptr,
305 endchar;
306
307 case ECPGt_short:
308 case ECPGt_int:
309 case ECPGt_long:
310 res = strtol(pval, &scan_length, 10);
311 if (garbage_left(isarray, &scan_length, compat))
312 {
313 ecpg_raise(lineno, ECPG_INT_FORMAT,
314 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
315 return (false);
316 }
317 pval = scan_length;
318
319 switch (type)
320 {
321 case ECPGt_short:
322 *((short *) (var + offset * act_tuple)) = (short) res;
323 break;
324 case ECPGt_int:
325 *((int *) (var + offset * act_tuple)) = (int) res;
326 break;
327 case ECPGt_long:
328 *((long *) (var + offset * act_tuple)) = (long) res;
329 break;
330 default:
331 /* Cannot happen */
332 break;
333 }
334 break;
335
336 case ECPGt_unsigned_short:
337 case ECPGt_unsigned_int:
338 case ECPGt_unsigned_long:
339 ures = strtoul(pval, &scan_length, 10);
340 if (garbage_left(isarray, &scan_length, compat))
341 {
342 ecpg_raise(lineno, ECPG_UINT_FORMAT,
343 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
344 return (false);
345 }
346 pval = scan_length;
347
348 switch (type)
349 {
350 case ECPGt_unsigned_short:
351 *((unsigned short *) (var + offset * act_tuple)) = (unsigned short) ures;
352 break;
353 case ECPGt_unsigned_int:
354 *((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures;
355 break;
356 case ECPGt_unsigned_long:
357 *((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures;
358 break;
359 default:
360 /* Cannot happen */
361 break;
362 }
363 break;
364
365 #ifdef HAVE_LONG_LONG_INT
366 #ifdef HAVE_STRTOLL
367 case ECPGt_long_long:
368 *((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
369 if (garbage_left(isarray, &scan_length, compat))
370 {
371 ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
372 return (false);
373 }
374 pval = scan_length;
375
376 break;
377 #endif /* HAVE_STRTOLL */
378 #ifdef HAVE_STRTOULL
379 case ECPGt_unsigned_long_long:
380 *((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10);
381 if (garbage_left(isarray, &scan_length, compat))
382 {
383 ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
384 return (false);
385 }
386 pval = scan_length;
387
388 break;
389 #endif /* HAVE_STRTOULL */
390 #endif /* HAVE_LONG_LONG_INT */
391
392 case ECPGt_float:
393 case ECPGt_double:
394 if (isarray && *pval == '"')
395 pval++;
396
397 if (!check_special_value(pval, &dres, &scan_length))
398 dres = strtod(pval, &scan_length);
399
400 if (isarray && *scan_length == '"')
401 scan_length++;
402
403 /* no special INFORMIX treatment for floats */
404 if (garbage_left(isarray, &scan_length, ECPG_COMPAT_PGSQL))
405 {
406 ecpg_raise(lineno, ECPG_FLOAT_FORMAT,
407 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
408 return (false);
409 }
410 pval = scan_length;
411
412 switch (type)
413 {
414 case ECPGt_float:
415 *((float *) (var + offset * act_tuple)) = dres;
416 break;
417 case ECPGt_double:
418 *((double *) (var + offset * act_tuple)) = dres;
419 break;
420 default:
421 /* Cannot happen */
422 break;
423 }
424 break;
425
426 case ECPGt_bool:
427 if (pval[0] == 'f' && pval[1] == '\0')
428 {
429 *((bool *) (var + offset * act_tuple)) = false;
430 pval++;
431 break;
432 }
433 else if (pval[0] == 't' && pval[1] == '\0')
434 {
435 *((bool *) (var + offset * act_tuple)) = true;
436 pval++;
437 break;
438 }
439 else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field))
440 {
441 /* NULL is valid */
442 break;
443 }
444
445 ecpg_raise(lineno, ECPG_CONVERT_BOOL,
446 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
447 return (false);
448 break;
449
450 case ECPGt_char:
451 case ECPGt_unsigned_char:
452 case ECPGt_string:
453 {
454 char *str = (char *) (var + offset * act_tuple);
455
456 /*
457 * If varcharsize is unknown and the offset is that of
458 * char *, then this variable represents the array of
459 * character pointers. So, use extra indirection.
460 */
461 if (varcharsize == 0 && offset == sizeof(char *))
462 str = *(char **) str;
463
464 if (varcharsize == 0 || varcharsize > size)
465 {
466 strncpy(str, pval, size + 1);
467 /* do the rtrim() */
468 if (type == ECPGt_string)
469 {
470 char *last = str + size;
471
472 while (last > str && (*last == ' ' || *last == '\0'))
473 {
474 *last = '\0';
475 last--;
476 }
477 }
478 }
479 else
480 {
481 strncpy(str, pval, varcharsize);
482
483 if (varcharsize < size)
484 {
485 /* truncation */
486 switch (ind_type)
487 {
488 case ECPGt_short:
489 case ECPGt_unsigned_short:
490 *((short *) (ind + ind_offset * act_tuple)) = size;
491 break;
492 case ECPGt_int:
493 case ECPGt_unsigned_int:
494 *((int *) (ind + ind_offset * act_tuple)) = size;
495 break;
496 case ECPGt_long:
497 case ECPGt_unsigned_long:
498 *((long *) (ind + ind_offset * act_tuple)) = size;
499 break;
500 #ifdef HAVE_LONG_LONG_INT
501 case ECPGt_long_long:
502 case ECPGt_unsigned_long_long:
503 *((long long int *) (ind + ind_offset * act_tuple)) = size;
504 break;
505 #endif /* HAVE_LONG_LONG_INT */
506 default:
507 break;
508 }
509 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
510 }
511 }
512 pval += size;
513 }
514 break;
515
516 case ECPGt_varchar:
517 {
518 struct ECPGgeneric_varchar *variable =
519 (struct ECPGgeneric_varchar *) (var + offset * act_tuple);
520
521 variable->len = size;
522 if (varcharsize == 0)
523 strncpy(variable->arr, pval, variable->len);
524 else
525 {
526 strncpy(variable->arr, pval, varcharsize);
527
528 if (variable->len > varcharsize)
529 {
530 /* truncation */
531 switch (ind_type)
532 {
533 case ECPGt_short:
534 case ECPGt_unsigned_short:
535 *((short *) (ind + ind_offset * act_tuple)) = variable->len;
536 break;
537 case ECPGt_int:
538 case ECPGt_unsigned_int:
539 *((int *) (ind + ind_offset * act_tuple)) = variable->len;
540 break;
541 case ECPGt_long:
542 case ECPGt_unsigned_long:
543 *((long *) (ind + ind_offset * act_tuple)) = variable->len;
544 break;
545 #ifdef HAVE_LONG_LONG_INT
546 case ECPGt_long_long:
547 case ECPGt_unsigned_long_long:
548 *((long long int *) (ind + ind_offset * act_tuple)) = variable->len;
549 break;
550 #endif /* HAVE_LONG_LONG_INT */
551 default:
552 break;
553 }
554 sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W';
555
556 variable->len = varcharsize;
557 }
558 }
559 pval += size;
560 }
561 break;
562
563 case ECPGt_decimal:
564 case ECPGt_numeric:
565 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '}'; endptr++);
566 endchar = *endptr;
567 *endptr = '\0';
568 nres = PGTYPESnumeric_from_asc(pval, &scan_length);
569 *endptr = endchar;
570
571 /* did we get an error? */
572 if (nres == NULL)
573 {
574 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
575 lineno, pval, errno);
576
577 if (INFORMIX_MODE(compat))
578 {
579 /*
580 * Informix wants its own NULL value here instead
581 * of an error
582 */
583 nres = PGTYPESnumeric_new();
584 if (nres)
585 ECPGset_noind_null(ECPGt_numeric, nres);
586 else
587 {
588 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
589 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
590 return (false);
591 }
592 }
593 else
594 {
595 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
596 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
597 return (false);
598 }
599 }
600 else
601 {
602 if (!isarray && garbage_left(isarray, &scan_length, compat))
603 {
604 free(nres);
605 ecpg_raise(lineno, ECPG_NUMERIC_FORMAT,
606 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
607 return (false);
608 }
609 }
610 pval = scan_length;
611
612 if (type == ECPGt_numeric)
613 PGTYPESnumeric_copy(nres, (numeric *) (var + offset * act_tuple));
614 else
615 PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * act_tuple));
616
617 PGTYPESnumeric_free(nres);
618 break;
619
620 case ECPGt_interval:
621 if (*pval == '"')
622 pval++;
623
624 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
625 endchar = *endptr;
626 *endptr = '\0';
627 ires = PGTYPESinterval_from_asc(pval, &scan_length);
628 *endptr = endchar;
629
630 /* did we get an error? */
631 if (ires == NULL)
632 {
633 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
634 lineno, pval, errno);
635
636 if (INFORMIX_MODE(compat))
637 {
638 /*
639 * Informix wants its own NULL value here instead
640 * of an error
641 */
642 ires = (interval *) ecpg_alloc(sizeof(interval), lineno);
643 if (!ires)
644 return (false);
645
646 ECPGset_noind_null(ECPGt_interval, ires);
647 }
648 else
649 {
650 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
651 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
652 return (false);
653 }
654 }
655 else
656 {
657 if (*scan_length == '"')
658 scan_length++;
659
660 if (!isarray && garbage_left(isarray, &scan_length, compat))
661 {
662 free(ires);
663 ecpg_raise(lineno, ECPG_INTERVAL_FORMAT,
664 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
665 return (false);
666 }
667 }
668 pval = scan_length;
669
670 PGTYPESinterval_copy(ires, (interval *) (var + offset * act_tuple));
671 free(ires);
672 break;
673
674 case ECPGt_date:
675 if (*pval == '"')
676 pval++;
677
678 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
679 endchar = *endptr;
680 *endptr = '\0';
681 ddres = PGTYPESdate_from_asc(pval, &scan_length);
682 *endptr = endchar;
683
684 /* did we get an error? */
685 if (errno != 0)
686 {
687 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
688 lineno, pval, errno);
689
690 if (INFORMIX_MODE(compat))
691 {
692 /*
693 * Informix wants its own NULL value here instead
694 * of an error
695 */
696 ECPGset_noind_null(ECPGt_date, &ddres);
697 }
698 else
699 {
700 ecpg_raise(lineno, ECPG_DATE_FORMAT,
701 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
702 return (false);
703 }
704 }
705 else
706 {
707 if (*scan_length == '"')
708 scan_length++;
709
710 if (!isarray && garbage_left(isarray, &scan_length, compat))
711 {
712 ecpg_raise(lineno, ECPG_DATE_FORMAT,
713 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
714 return (false);
715 }
716 }
717
718 *((date *) (var + offset * act_tuple)) = ddres;
719 pval = scan_length;
720 break;
721
722 case ECPGt_timestamp:
723 if (*pval == '"')
724 pval++;
725
726 for (endptr = pval; *endptr && *endptr != ',' && *endptr != '"' && *endptr != '}'; endptr++);
727 endchar = *endptr;
728 *endptr = '\0';
729 tres = PGTYPEStimestamp_from_asc(pval, &scan_length);
730 *endptr = endchar;
731
732 /* did we get an error? */
733 if (errno != 0)
734 {
735 ecpg_log("ecpg_get_data on line %d: RESULT %s; errno %d\n",
736 lineno, pval, errno);
737
738 if (INFORMIX_MODE(compat))
739 {
740 /*
741 * Informix wants its own NULL value here instead
742 * of an error
743 */
744 ECPGset_noind_null(ECPGt_timestamp, &tres);
745 }
746 else
747 {
748 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
749 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
750 return (false);
751 }
752 }
753 else
754 {
755 if (*scan_length == '"')
756 scan_length++;
757
758 if (!isarray && garbage_left(isarray, &scan_length, compat))
759 {
760 ecpg_raise(lineno, ECPG_TIMESTAMP_FORMAT,
761 ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
762 return (false);
763 }
764 }
765
766 *((timestamp *) (var + offset * act_tuple)) = tres;
767 pval = scan_length;
768 break;
769
770 default:
771 ecpg_raise(lineno, ECPG_UNSUPPORTED,
772 ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
773 ecpg_type_name(type));
774 return (false);
775 break;
776 }
777 if (ECPG_IS_ARRAY(isarray))
778 {
779 bool string = false;
780
781 /* set array to next entry */
782 ++act_tuple;
783
784 /* set pval to the next entry */
785
786 /*
787 * *pval != '\0' should not be needed, but is used as a safety
788 * guard
789 */
790 for (; *pval != '\0' && (string || (!array_delimiter(isarray, *pval) && !array_boundary(isarray, *pval))); ++pval)
791 if (*pval == '"')
792 string = string ? false : true;
793
794 if (array_delimiter(isarray, *pval))
795 ++pval;
796 }
797 }
798 } while (*pval != '\0' && !array_boundary(isarray, *pval));
799
800 return (true);
801 }
802