1 /*
2  * SQLDA support routines
3  *
4  * The allocated memory area pointed by an sqlda pointer
5  * contains both the metadata and the data, so freeing up
6  * is a simple free(sqlda) as expected by the ESQL/C examples.
7  */
8 
9 #define POSTGRES_ECPG_INTERNAL
10 #include "postgres_fe.h"
11 #include "pg_type.h"
12 
13 #include "ecpg-pthread-win32.h"
14 #include "decimal.h"
15 #include "ecpgtype.h"
16 #include "ecpglib.h"
17 #include "ecpgerrno.h"
18 #include "extern.h"
19 #include "sqlca.h"
20 #include "sqlda-native.h"
21 #include "sqlda-compat.h"
22 
23 /*
24  * Compute the next variable's offset with
25  * the current variable's size and alignment.
26  *
27  *
28  * Returns:
29  * - the current variable's offset in *current
30  * - the next variable's offset in *next
31  */
32 static void
ecpg_sqlda_align_add_size(long offset,int alignment,int size,long * current,long * next)33 ecpg_sqlda_align_add_size(long offset, int alignment, int size, long *current, long *next)
34 {
35 	if (offset % alignment)
36 		offset += alignment - (offset % alignment);
37 	if (current)
38 		*current = offset;
39 	offset += size;
40 	if (next)
41 		*next = offset;
42 }
43 
44 static long
sqlda_compat_empty_size(const PGresult * res)45 sqlda_compat_empty_size(const PGresult *res)
46 {
47 	long		offset;
48 	int			i;
49 	int			sqld = PQnfields(res);
50 
51 	/* Initial size to store main structure and field structures */
52 	offset = sizeof(struct sqlda_compat) + sqld * sizeof(struct sqlvar_compat);
53 
54 	/* Add space for field names */
55 	for (i = 0; i < sqld; i++)
56 		offset += strlen(PQfname(res, i)) + 1;
57 
58 	/* Add padding to the first field value */
59 	ecpg_sqlda_align_add_size(offset, sizeof(int), 0, &offset, NULL);
60 
61 	return offset;
62 }
63 
64 static long
sqlda_common_total_size(const PGresult * res,int row,enum COMPAT_MODE compat,long offset)65 sqlda_common_total_size(const PGresult *res, int row, enum COMPAT_MODE compat, long offset)
66 {
67 	int			sqld = PQnfields(res);
68 	int			i;
69 	long		next_offset;
70 
71 	/* Add space for the field values */
72 	for (i = 0; i < sqld; i++)
73 	{
74 		enum ECPGttype type = sqlda_dynamic_type(PQftype(res, i), compat);
75 
76 		switch (type)
77 		{
78 			case ECPGt_short:
79 			case ECPGt_unsigned_short:
80 				ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
81 				break;
82 			case ECPGt_int:
83 			case ECPGt_unsigned_int:
84 				ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
85 				break;
86 			case ECPGt_long:
87 			case ECPGt_unsigned_long:
88 				ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
89 				break;
90 			case ECPGt_long_long:
91 			case ECPGt_unsigned_long_long:
92 				ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
93 				break;
94 			case ECPGt_bool:
95 				ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
96 				break;
97 			case ECPGt_float:
98 				ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
99 				break;
100 			case ECPGt_double:
101 				ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
102 				break;
103 			case ECPGt_decimal:
104 				ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
105 				break;
106 			case ECPGt_numeric:
107 
108 				/*
109 				 * We align the numeric struct to allow it to store a pointer,
110 				 * while the digits array is aligned to int (which seems like
111 				 * overkill, but let's keep compatibility here).
112 				 *
113 				 * Unfortunately we need to deconstruct the value twice to
114 				 * find out the digits array's size and then later fill it.
115 				 */
116 				ecpg_sqlda_align_add_size(offset, sizeof(NumericDigit *), sizeof(numeric), &offset, &next_offset);
117 				if (!PQgetisnull(res, row, i))
118 				{
119 					char	   *val = PQgetvalue(res, row, i);
120 					numeric    *num;
121 
122 					num = PGTYPESnumeric_from_asc(val, NULL);
123 					if (!num)
124 						break;
125 					if (num->buf)
126 						ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->digits - num->buf + num->ndigits, &offset, &next_offset);
127 					PGTYPESnumeric_free(num);
128 				}
129 				break;
130 			case ECPGt_date:
131 				ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
132 				break;
133 			case ECPGt_timestamp:
134 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(timestamp), &offset, &next_offset);
135 				break;
136 			case ECPGt_interval:
137 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
138 				break;
139 			case ECPGt_char:
140 			case ECPGt_unsigned_char:
141 			case ECPGt_string:
142 			default:
143 				{
144 					long		datalen = strlen(PQgetvalue(res, row, i)) + 1;
145 
146 					ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
147 					break;
148 				}
149 		}
150 		offset = next_offset;
151 	}
152 	return offset;
153 }
154 
155 
156 static long
sqlda_compat_total_size(const PGresult * res,int row,enum COMPAT_MODE compat)157 sqlda_compat_total_size(const PGresult *res, int row, enum COMPAT_MODE compat)
158 {
159 	long		offset;
160 
161 	offset = sqlda_compat_empty_size(res);
162 
163 	if (row < 0)
164 		return offset;
165 
166 	offset = sqlda_common_total_size(res, row, compat, offset);
167 	return offset;
168 }
169 
170 static long
sqlda_native_empty_size(const PGresult * res)171 sqlda_native_empty_size(const PGresult *res)
172 {
173 	long		offset;
174 	int			sqld = PQnfields(res);
175 
176 	/* Initial size to store main structure and field structures */
177 	offset = sizeof(struct sqlda_struct) + (sqld - 1) * sizeof(struct sqlvar_struct);
178 
179 	/* Add padding to the first field value */
180 	ecpg_sqlda_align_add_size(offset, sizeof(int), 0, &offset, NULL);
181 
182 	return offset;
183 }
184 
185 static long
sqlda_native_total_size(const PGresult * res,int row,enum COMPAT_MODE compat)186 sqlda_native_total_size(const PGresult *res, int row, enum COMPAT_MODE compat)
187 {
188 	long		offset;
189 
190 	offset = sqlda_native_empty_size(res);
191 
192 	if (row < 0)
193 		return offset;
194 
195 	offset = sqlda_common_total_size(res, row, compat, offset);
196 	return offset;
197 }
198 
199 /*
200  * Build "struct sqlda_compat" (metadata only) from PGresult
201  * leaving enough space for the field values in
202  * the given row number
203  */
204 struct sqlda_compat *
ecpg_build_compat_sqlda(int line,PGresult * res,int row,enum COMPAT_MODE compat)205 ecpg_build_compat_sqlda(int line, PGresult *res, int row, enum COMPAT_MODE compat)
206 {
207 	struct sqlda_compat *sqlda;
208 	struct sqlvar_compat *sqlvar;
209 	char	   *fname;
210 	long		size;
211 	int			sqld;
212 	int			i;
213 
214 	size = sqlda_compat_total_size(res, row, compat);
215 	sqlda = (struct sqlda_compat *) ecpg_alloc(size, line);
216 	if (!sqlda)
217 		return NULL;
218 
219 	memset(sqlda, 0, size);
220 	sqlvar = (struct sqlvar_compat *) (sqlda + 1);
221 	sqld = PQnfields(res);
222 	fname = (char *) (sqlvar + sqld);
223 
224 	sqlda->sqld = sqld;
225 	ecpg_log("ecpg_build_compat_sqlda on line %d sqld = %d\n", line, sqld);
226 	sqlda->desc_occ = size;		/* cheat here, keep the full allocated size */
227 	sqlda->sqlvar = sqlvar;
228 
229 	for (i = 0; i < sqlda->sqld; i++)
230 	{
231 		sqlda->sqlvar[i].sqltype = sqlda_dynamic_type(PQftype(res, i), compat);
232 		strcpy(fname, PQfname(res, i));
233 		sqlda->sqlvar[i].sqlname = fname;
234 		fname += strlen(sqlda->sqlvar[i].sqlname) + 1;
235 
236 		/*
237 		 * this is reserved for future use, so we leave it empty for the time
238 		 * being
239 		 */
240 		/* sqlda->sqlvar[i].sqlformat = (char *) (long) PQfformat(res, i); */
241 		sqlda->sqlvar[i].sqlxid = PQftype(res, i);
242 		sqlda->sqlvar[i].sqltypelen = PQfsize(res, i);
243 	}
244 
245 	return sqlda;
246 }
247 
248 /*
249  * Sets values from PGresult.
250  */
251 static int16 value_is_null = -1;
252 static int16 value_is_not_null = 0;
253 
254 void
ecpg_set_compat_sqlda(int lineno,struct sqlda_compat ** _sqlda,const PGresult * res,int row,enum COMPAT_MODE compat)255 ecpg_set_compat_sqlda(int lineno, struct sqlda_compat **_sqlda, const PGresult *res, int row, enum COMPAT_MODE compat)
256 {
257 	struct sqlda_compat *sqlda = (*_sqlda);
258 	int			i;
259 	long		offset,
260 				next_offset;
261 
262 	if (row < 0)
263 		return;
264 
265 	/* Offset for the first field value */
266 	offset = sqlda_compat_empty_size(res);
267 
268 	/*
269 	 * Set sqlvar[i]->sqldata pointers and convert values to correct format
270 	 */
271 	for (i = 0; i < sqlda->sqld; i++)
272 	{
273 		int			isnull;
274 		int			datalen;
275 		bool		set_data = true;
276 
277 		switch (sqlda->sqlvar[i].sqltype)
278 		{
279 			case ECPGt_short:
280 			case ECPGt_unsigned_short:
281 				ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
282 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
283 				sqlda->sqlvar[i].sqllen = sizeof(short);
284 				break;
285 			case ECPGt_int:
286 			case ECPGt_unsigned_int:
287 				ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
288 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
289 				sqlda->sqlvar[i].sqllen = sizeof(int);
290 				break;
291 			case ECPGt_long:
292 			case ECPGt_unsigned_long:
293 				ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
294 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
295 				sqlda->sqlvar[i].sqllen = sizeof(long);
296 				break;
297 			case ECPGt_long_long:
298 			case ECPGt_unsigned_long_long:
299 				ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
300 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
301 				sqlda->sqlvar[i].sqllen = sizeof(long long);
302 				break;
303 			case ECPGt_bool:
304 				ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
305 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
306 				sqlda->sqlvar[i].sqllen = sizeof(bool);
307 				break;
308 			case ECPGt_float:
309 				ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
310 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
311 				sqlda->sqlvar[i].sqllen = sizeof(float);
312 				break;
313 			case ECPGt_double:
314 				ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
315 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
316 				sqlda->sqlvar[i].sqllen = sizeof(double);
317 				break;
318 			case ECPGt_decimal:
319 				ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
320 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
321 				sqlda->sqlvar[i].sqllen = sizeof(decimal);
322 				break;
323 			case ECPGt_numeric:
324 				{
325 					numeric    *num;
326 					char	   *val;
327 
328 					set_data = false;
329 
330 					ecpg_sqlda_align_add_size(offset, sizeof(NumericDigit *), sizeof(numeric), &offset, &next_offset);
331 					sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
332 					sqlda->sqlvar[i].sqllen = sizeof(numeric);
333 
334 					if (PQgetisnull(res, row, i))
335 					{
336 						ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
337 						break;
338 					}
339 
340 					val = PQgetvalue(res, row, i);
341 					num = PGTYPESnumeric_from_asc(val, NULL);
342 					if (!num)
343 					{
344 						ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
345 						break;
346 					}
347 
348 					memcpy(sqlda->sqlvar[i].sqldata, num, sizeof(numeric));
349 
350 					if (num->buf)
351 					{
352 						ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->digits - num->buf + num->ndigits, &offset, &next_offset);
353 						memcpy((char *) sqlda + offset, num->buf, num->digits - num->buf + num->ndigits);
354 
355 						((numeric *) sqlda->sqlvar[i].sqldata)->buf = (NumericDigit *) sqlda + offset;
356 						((numeric *) sqlda->sqlvar[i].sqldata)->digits = (NumericDigit *) sqlda + offset + (num->digits - num->buf);
357 					}
358 
359 					PGTYPESnumeric_free(num);
360 
361 					break;
362 				}
363 			case ECPGt_date:
364 				ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
365 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
366 				sqlda->sqlvar[i].sqllen = sizeof(date);
367 				break;
368 			case ECPGt_timestamp:
369 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(timestamp), &offset, &next_offset);
370 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
371 				sqlda->sqlvar[i].sqllen = sizeof(timestamp);
372 				break;
373 			case ECPGt_interval:
374 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
375 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
376 				sqlda->sqlvar[i].sqllen = sizeof(interval);
377 				break;
378 			case ECPGt_char:
379 			case ECPGt_unsigned_char:
380 			case ECPGt_string:
381 			default:
382 				datalen = strlen(PQgetvalue(res, row, i)) + 1;
383 				ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
384 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
385 				sqlda->sqlvar[i].sqllen = datalen;
386 				if (datalen > 32768)
387 					sqlda->sqlvar[i].sqlilongdata = sqlda->sqlvar[i].sqldata;
388 				break;
389 		}
390 
391 		isnull = PQgetisnull(res, row, i);
392 		ecpg_log("ecpg_set_compat_sqlda on line %d row %d col %d %s\n", lineno, row, i, isnull ? "IS NULL" : "IS NOT NULL");
393 		sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
394 		sqlda->sqlvar[i].sqlitype = ECPGt_short;
395 		sqlda->sqlvar[i].sqlilen = sizeof(short);
396 		if (!isnull)
397 		{
398 			if (set_data)
399 				ecpg_get_data(res, row, i, lineno,
400 							  sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
401 							  sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
402 							  ECPG_ARRAY_NONE, compat, false);
403 		}
404 		else
405 			ECPGset_noind_null(sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqldata);
406 
407 		offset = next_offset;
408 	}
409 }
410 
411 struct sqlda_struct *
ecpg_build_native_sqlda(int line,PGresult * res,int row,enum COMPAT_MODE compat)412 ecpg_build_native_sqlda(int line, PGresult *res, int row, enum COMPAT_MODE compat)
413 {
414 	struct sqlda_struct *sqlda;
415 	long		size;
416 	int			i;
417 
418 	size = sqlda_native_total_size(res, row, compat);
419 	sqlda = (struct sqlda_struct *) ecpg_alloc(size, line);
420 	if (!sqlda)
421 		return NULL;
422 
423 	memset(sqlda, 0, size);
424 
425 	sprintf(sqlda->sqldaid, "SQLDA  ");
426 	sqlda->sqld = sqlda->sqln = PQnfields(res);
427 	ecpg_log("ecpg_build_native_sqlda on line %d sqld = %d\n", line, sqlda->sqld);
428 	sqlda->sqldabc = sizeof(struct sqlda_struct) + (sqlda->sqld - 1) * sizeof(struct sqlvar_struct);
429 
430 	for (i = 0; i < sqlda->sqld; i++)
431 	{
432 		char	   *fname;
433 
434 		sqlda->sqlvar[i].sqltype = sqlda_dynamic_type(PQftype(res, i), compat);
435 		fname = PQfname(res, i);
436 		sqlda->sqlvar[i].sqlname.length = strlen(fname);
437 		strcpy(sqlda->sqlvar[i].sqlname.data, fname);
438 	}
439 
440 	return sqlda;
441 }
442 
443 void
ecpg_set_native_sqlda(int lineno,struct sqlda_struct ** _sqlda,const PGresult * res,int row,enum COMPAT_MODE compat)444 ecpg_set_native_sqlda(int lineno, struct sqlda_struct **_sqlda, const PGresult *res, int row, enum COMPAT_MODE compat)
445 {
446 	struct sqlda_struct *sqlda = (*_sqlda);
447 	int			i;
448 	long		offset,
449 				next_offset;
450 
451 	if (row < 0)
452 		return;
453 
454 	/* Offset for the first field value */
455 	offset = sqlda_native_empty_size(res);
456 
457 	/*
458 	 * Set sqlvar[i]->sqldata pointers and convert values to correct format
459 	 */
460 	for (i = 0; i < sqlda->sqld; i++)
461 	{
462 		int			isnull;
463 		int			datalen;
464 		bool		set_data = true;
465 
466 		switch (sqlda->sqlvar[i].sqltype)
467 		{
468 			case ECPGt_short:
469 			case ECPGt_unsigned_short:
470 				ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
471 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
472 				sqlda->sqlvar[i].sqllen = sizeof(short);
473 				break;
474 			case ECPGt_int:
475 			case ECPGt_unsigned_int:
476 				ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
477 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
478 				sqlda->sqlvar[i].sqllen = sizeof(int);
479 				break;
480 			case ECPGt_long:
481 			case ECPGt_unsigned_long:
482 				ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
483 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
484 				sqlda->sqlvar[i].sqllen = sizeof(long);
485 				break;
486 			case ECPGt_long_long:
487 			case ECPGt_unsigned_long_long:
488 				ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
489 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
490 				sqlda->sqlvar[i].sqllen = sizeof(long long);
491 				break;
492 			case ECPGt_bool:
493 				ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
494 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
495 				sqlda->sqlvar[i].sqllen = sizeof(bool);
496 				break;
497 			case ECPGt_float:
498 				ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
499 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
500 				sqlda->sqlvar[i].sqllen = sizeof(float);
501 				break;
502 			case ECPGt_double:
503 				ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
504 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
505 				sqlda->sqlvar[i].sqllen = sizeof(double);
506 				break;
507 			case ECPGt_decimal:
508 				ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
509 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
510 				sqlda->sqlvar[i].sqllen = sizeof(decimal);
511 				break;
512 			case ECPGt_numeric:
513 				{
514 					numeric    *num;
515 					char	   *val;
516 
517 					set_data = false;
518 
519 					ecpg_sqlda_align_add_size(offset, sizeof(NumericDigit *), sizeof(numeric), &offset, &next_offset);
520 					sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
521 					sqlda->sqlvar[i].sqllen = sizeof(numeric);
522 
523 					if (PQgetisnull(res, row, i))
524 					{
525 						ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
526 						break;
527 					}
528 
529 					val = PQgetvalue(res, row, i);
530 					num = PGTYPESnumeric_from_asc(val, NULL);
531 					if (!num)
532 					{
533 						ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
534 						break;
535 					}
536 
537 					memcpy(sqlda->sqlvar[i].sqldata, num, sizeof(numeric));
538 
539 					if (num->buf)
540 					{
541 						ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->digits - num->buf + num->ndigits, &offset, &next_offset);
542 						memcpy((char *) sqlda + offset, num->buf, num->digits - num->buf + num->ndigits);
543 
544 						((numeric *) sqlda->sqlvar[i].sqldata)->buf = (NumericDigit *) sqlda + offset;
545 						((numeric *) sqlda->sqlvar[i].sqldata)->digits = (NumericDigit *) sqlda + offset + (num->digits - num->buf);
546 					}
547 
548 					PGTYPESnumeric_free(num);
549 
550 					break;
551 				}
552 			case ECPGt_date:
553 				ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
554 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
555 				sqlda->sqlvar[i].sqllen = sizeof(date);
556 				break;
557 			case ECPGt_timestamp:
558 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(timestamp), &offset, &next_offset);
559 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
560 				sqlda->sqlvar[i].sqllen = sizeof(timestamp);
561 				break;
562 			case ECPGt_interval:
563 				ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
564 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
565 				sqlda->sqlvar[i].sqllen = sizeof(interval);
566 				break;
567 			case ECPGt_char:
568 			case ECPGt_unsigned_char:
569 			case ECPGt_string:
570 			default:
571 				datalen = strlen(PQgetvalue(res, row, i)) + 1;
572 				ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
573 				sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
574 				sqlda->sqlvar[i].sqllen = datalen;
575 				break;
576 		}
577 
578 		isnull = PQgetisnull(res, row, i);
579 		ecpg_log("ecpg_set_native_sqlda on line %d row %d col %d %s\n", lineno, row, i, isnull ? "IS NULL" : "IS NOT NULL");
580 		sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
581 		if (!isnull)
582 		{
583 			if (set_data)
584 				ecpg_get_data(res, row, i, lineno,
585 							  sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
586 							  sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
587 							  ECPG_ARRAY_NONE, compat, false);
588 		}
589 
590 		offset = next_offset;
591 	}
592 }
593