2
* SQLDA support routines
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.
9
#define POSTGRES_ECPG_INTERNAL
10
#include "postgres_fe.h"
13
#include "ecpg-pthread-win32.h"
17
#include "ecpgerrno.h"
20
#include "sqlda-native.h"
21
#include "sqlda-compat.h"
24
* Compute the next variable's offset with
25
* the current variable's size and alignment.
29
* - the current variable's offset in *current
30
* - the next variable's offset in *next
33
ecpg_sqlda_align_add_size(long offset, int alignment, int size, long *current, long *next)
35
if (offset % alignment)
36
offset += alignment - (offset % alignment);
45
sqlda_compat_empty_size(const PGresult *res)
49
int sqld = PQnfields(res);
51
/* Initial size to store main structure and field structures */
52
offset = sizeof(struct sqlda_compat) + sqld * sizeof(struct sqlvar_compat);
54
/* Add space for field names */
55
for (i = 0; i < sqld; i++)
56
offset += strlen(PQfname(res, i)) + 1;
58
/* Add padding to the first field value */
59
ecpg_sqlda_align_add_size(offset, sizeof(int), 0, &offset, NULL);
65
sqlda_common_total_size(const PGresult *res, int row, enum COMPAT_MODE compat, long offset)
67
int sqld = PQnfields(res);
71
/* Add space for the field values */
72
for (i = 0; i < sqld; i++)
74
enum ECPGttype type = sqlda_dynamic_type(PQftype(res, i), compat);
79
case ECPGt_unsigned_short:
80
ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
83
case ECPGt_unsigned_int:
84
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
87
case ECPGt_unsigned_long:
88
ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
91
case ECPGt_unsigned_long_long:
92
ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
95
ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
98
ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
101
ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
104
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
109
* Let's align both the numeric struct and the digits array to
110
* int Unfortunately we need to do double work here to compute
111
* the size of the space needed for the numeric structure.
113
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(numeric), &offset, &next_offset);
114
if (!PQgetisnull(res, row, i))
116
char *val = PQgetvalue(res, row, i);
119
num = PGTYPESnumeric_from_asc(val, NULL);
122
ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->ndigits + 1, &offset, &next_offset);
123
PGTYPESnumeric_free(num);
127
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(date), &offset, &next_offset);
129
case ECPGt_timestamp:
130
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(timestamp), &offset, &next_offset);
133
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(interval), &offset, &next_offset);
136
case ECPGt_unsigned_char:
140
long datalen = strlen(PQgetvalue(res, row, i)) + 1;
142
ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
146
offset = next_offset;
153
sqlda_compat_total_size(const PGresult *res, int row, enum COMPAT_MODE compat)
157
offset = sqlda_compat_empty_size(res);
162
offset = sqlda_common_total_size(res, row, compat, offset);
167
sqlda_native_empty_size(const PGresult *res)
170
int sqld = PQnfields(res);
172
/* Initial size to store main structure and field structures */
173
offset = sizeof(struct sqlda_struct) + (sqld - 1) * sizeof(struct sqlvar_struct);
175
/* Add padding to the first field value */
176
ecpg_sqlda_align_add_size(offset, sizeof(int), 0, &offset, NULL);
182
sqlda_native_total_size(const PGresult *res, int row, enum COMPAT_MODE compat)
186
offset = sqlda_native_empty_size(res);
191
offset = sqlda_common_total_size(res, row, compat, offset);
196
* Build "struct sqlda_compat" (metadata only) from PGresult
197
* leaving enough space for the field values in
198
* the given row number
200
struct sqlda_compat *
201
ecpg_build_compat_sqlda(int line, PGresult *res, int row, enum COMPAT_MODE compat)
203
struct sqlda_compat *sqlda;
204
struct sqlvar_compat *sqlvar;
210
size = sqlda_compat_total_size(res, row, compat);
211
sqlda = (struct sqlda_compat *) ecpg_alloc(size, line);
215
memset(sqlda, 0, size);
216
sqlvar = (struct sqlvar_compat *) (sqlda + 1);
217
sqld = PQnfields(res);
218
fname = (char *) (sqlvar + sqld);
221
ecpg_log("ecpg_build_compat_sqlda on line %d sqld = %d\n", line, sqld);
222
sqlda->desc_occ = size; /* cheat here, keep the full allocated size */
223
sqlda->sqlvar = sqlvar;
225
for (i = 0; i < sqlda->sqld; i++)
227
sqlda->sqlvar[i].sqltype = sqlda_dynamic_type(PQftype(res, i), compat);
228
strcpy(fname, PQfname(res, i));
229
sqlda->sqlvar[i].sqlname = fname;
230
fname += strlen(sqlda->sqlvar[i].sqlname) + 1;
231
/* this is reserved for future use, so we leave it empty for the time being */
232
/* sqlda->sqlvar[i].sqlformat = (char *) (long) PQfformat(res, i);*/
233
sqlda->sqlvar[i].sqlxid = PQftype(res, i);
234
sqlda->sqlvar[i].sqltypelen = PQfsize(res, i);
241
* Sets values from PGresult.
243
static int2 value_is_null = -1;
244
static int2 value_is_not_null = 0;
247
ecpg_set_compat_sqlda(int lineno, struct sqlda_compat ** _sqlda, const PGresult *res, int row, enum COMPAT_MODE compat)
249
struct sqlda_compat *sqlda = (*_sqlda);
257
/* Offset for the first field value */
258
offset = sqlda_compat_empty_size(res);
261
* Set sqlvar[i]->sqldata pointers and convert values to correct format
263
for (i = 0; i < sqlda->sqld; i++)
267
bool set_data = true;
269
switch (sqlda->sqlvar[i].sqltype)
272
case ECPGt_unsigned_short:
273
ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
274
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
275
sqlda->sqlvar[i].sqllen = sizeof(short);
278
case ECPGt_unsigned_int:
279
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
280
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
281
sqlda->sqlvar[i].sqllen = sizeof(int);
284
case ECPGt_unsigned_long:
285
ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
286
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
287
sqlda->sqlvar[i].sqllen = sizeof(long);
289
case ECPGt_long_long:
290
case ECPGt_unsigned_long_long:
291
ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
292
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
293
sqlda->sqlvar[i].sqllen = sizeof(long long);
296
ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
297
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
298
sqlda->sqlvar[i].sqllen = sizeof(bool);
301
ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
302
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
303
sqlda->sqlvar[i].sqllen = sizeof(float);
306
ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
307
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
308
sqlda->sqlvar[i].sqllen = sizeof(double);
311
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
312
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
313
sqlda->sqlvar[i].sqllen = sizeof(decimal);
322
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(numeric), &offset, &next_offset);
323
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
324
sqlda->sqlvar[i].sqllen = sizeof(numeric);
326
if (PQgetisnull(res, row, i))
328
ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
332
val = PQgetvalue(res, row, i);
333
num = PGTYPESnumeric_from_asc(val, NULL);
336
ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
340
memcpy(sqlda->sqlvar[i].sqldata, num, sizeof(numeric));
342
ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->ndigits + 1, &offset, &next_offset);
343
memcpy((char *) sqlda + offset, num->buf, num->ndigits + 1);
345
((numeric *) sqlda->sqlvar[i].sqldata)->buf = (NumericDigit *) sqlda + offset;
346
((numeric *) sqlda->sqlvar[i].sqldata)->digits = (NumericDigit *) sqlda + offset + (num->digits - num->buf);
348
PGTYPESnumeric_free(num);
353
ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
354
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
355
sqlda->sqlvar[i].sqllen = sizeof(date);
357
case ECPGt_timestamp:
358
ecpg_sqlda_align_add_size(offset, sizeof(timestamp), sizeof(timestamp), &offset, &next_offset);
359
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
360
sqlda->sqlvar[i].sqllen = sizeof(timestamp);
363
ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
364
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
365
sqlda->sqlvar[i].sqllen = sizeof(interval);
368
case ECPGt_unsigned_char:
371
datalen = strlen(PQgetvalue(res, row, i)) + 1;
372
ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
373
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
374
sqlda->sqlvar[i].sqllen = datalen;
376
sqlda->sqlvar[i].sqlilongdata = sqlda->sqlvar[i].sqldata;
380
isnull = PQgetisnull(res, row, i);
381
ecpg_log("ecpg_set_compat_sqlda on line %d row %d col %d %s\n", lineno, row, i, isnull ? "IS NULL" : "IS NOT NULL");
382
sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
383
sqlda->sqlvar[i].sqlitype = ECPGt_short;
384
sqlda->sqlvar[i].sqlilen = sizeof(short);
388
ecpg_get_data(res, row, i, lineno,
389
sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
390
sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
391
ECPG_ARRAY_NONE, compat, false);
394
ECPGset_noind_null(sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqldata);
396
offset = next_offset;
400
struct sqlda_struct *
401
ecpg_build_native_sqlda(int line, PGresult *res, int row, enum COMPAT_MODE compat)
403
struct sqlda_struct *sqlda;
407
size = sqlda_native_total_size(res, row, compat);
408
sqlda = (struct sqlda_struct *) ecpg_alloc(size, line);
412
memset(sqlda, 0, size);
414
sprintf(sqlda->sqldaid, "SQLDA ");
415
sqlda->sqld = sqlda->sqln = PQnfields(res);
416
ecpg_log("ecpg_build_native_sqlda on line %d sqld = %d\n", line, sqlda->sqld);
417
sqlda->sqldabc = sizeof(struct sqlda_struct) + (sqlda->sqld - 1) * sizeof(struct sqlvar_struct);
419
for (i = 0; i < sqlda->sqld; i++)
423
sqlda->sqlvar[i].sqltype = sqlda_dynamic_type(PQftype(res, i), compat);
424
fname = PQfname(res, i);
425
sqlda->sqlvar[i].sqlname.length = strlen(fname);
426
strcpy(sqlda->sqlvar[i].sqlname.data, fname);
433
ecpg_set_native_sqlda(int lineno, struct sqlda_struct ** _sqlda, const PGresult *res, int row, enum COMPAT_MODE compat)
435
struct sqlda_struct *sqlda = (*_sqlda);
443
/* Offset for the first field value */
444
offset = sqlda_native_empty_size(res);
447
* Set sqlvar[i]->sqldata pointers and convert values to correct format
449
for (i = 0; i < sqlda->sqld; i++)
453
bool set_data = true;
455
switch (sqlda->sqlvar[i].sqltype)
458
case ECPGt_unsigned_short:
459
ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
460
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
461
sqlda->sqlvar[i].sqllen = sizeof(short);
464
case ECPGt_unsigned_int:
465
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
466
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
467
sqlda->sqlvar[i].sqllen = sizeof(int);
470
case ECPGt_unsigned_long:
471
ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
472
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
473
sqlda->sqlvar[i].sqllen = sizeof(long);
475
case ECPGt_long_long:
476
case ECPGt_unsigned_long_long:
477
ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
478
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
479
sqlda->sqlvar[i].sqllen = sizeof(long long);
482
ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
483
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
484
sqlda->sqlvar[i].sqllen = sizeof(bool);
487
ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
488
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
489
sqlda->sqlvar[i].sqllen = sizeof(float);
492
ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
493
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
494
sqlda->sqlvar[i].sqllen = sizeof(double);
497
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
498
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
499
sqlda->sqlvar[i].sqllen = sizeof(decimal);
508
ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(numeric), &offset, &next_offset);
509
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
510
sqlda->sqlvar[i].sqllen = sizeof(numeric);
512
if (PQgetisnull(res, row, i))
514
ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
518
val = PQgetvalue(res, row, i);
519
num = PGTYPESnumeric_from_asc(val, NULL);
522
ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
526
memcpy(sqlda->sqlvar[i].sqldata, num, sizeof(numeric));
528
ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->ndigits + 1, &offset, &next_offset);
529
memcpy((char *) sqlda + offset, num->buf, num->ndigits + 1);
531
((numeric *) sqlda->sqlvar[i].sqldata)->buf = (NumericDigit *) sqlda + offset;
532
((numeric *) sqlda->sqlvar[i].sqldata)->digits = (NumericDigit *) sqlda + offset + (num->digits - num->buf);
534
PGTYPESnumeric_free(num);
539
ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
540
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
541
sqlda->sqlvar[i].sqllen = sizeof(date);
543
case ECPGt_timestamp:
544
ecpg_sqlda_align_add_size(offset, sizeof(timestamp), sizeof(timestamp), &offset, &next_offset);
545
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
546
sqlda->sqlvar[i].sqllen = sizeof(timestamp);
549
ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
550
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
551
sqlda->sqlvar[i].sqllen = sizeof(interval);
554
case ECPGt_unsigned_char:
557
datalen = strlen(PQgetvalue(res, row, i)) + 1;
558
ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
559
sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
560
sqlda->sqlvar[i].sqllen = datalen;
564
isnull = PQgetisnull(res, row, i);
565
ecpg_log("ecpg_set_native_sqlda on line %d row %d col %d %s\n", lineno, row, i, isnull ? "IS NULL" : "IS NOT NULL");
566
sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
570
ecpg_get_data(res, row, i, lineno,
571
sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
572
sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
573
ECPG_ARRAY_NONE, compat, false);
576
offset = next_offset;