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