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