00001
00002
00003
00004
00005
00006
00007
00008
00009 #define POSTGRES_ECPG_INTERNAL
00010 #include "postgres_fe.h"
00011 #include "pg_type.h"
00012
00013 #include "ecpg-pthread-win32.h"
00014 #include "decimal.h"
00015 #include "ecpgtype.h"
00016 #include "ecpglib.h"
00017 #include "ecpgerrno.h"
00018 #include "extern.h"
00019 #include "sqlca.h"
00020 #include "sqlda-native.h"
00021 #include "sqlda-compat.h"
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 static void
00033 ecpg_sqlda_align_add_size(long offset, int alignment, int size, long *current, long *next)
00034 {
00035 if (offset % alignment)
00036 offset += alignment - (offset % alignment);
00037 if (current)
00038 *current = offset;
00039 offset += size;
00040 if (next)
00041 *next = offset;
00042 }
00043
00044 static long
00045 sqlda_compat_empty_size(const PGresult *res)
00046 {
00047 long offset;
00048 int i;
00049 int sqld = PQnfields(res);
00050
00051
00052 offset = sizeof(struct sqlda_compat) + sqld * sizeof(struct sqlvar_compat);
00053
00054
00055 for (i = 0; i < sqld; i++)
00056 offset += strlen(PQfname(res, i)) + 1;
00057
00058
00059 ecpg_sqlda_align_add_size(offset, sizeof(int), 0, &offset, NULL);
00060
00061 return offset;
00062 }
00063
00064 static long
00065 sqlda_common_total_size(const PGresult *res, int row, enum COMPAT_MODE compat, long offset)
00066 {
00067 int sqld = PQnfields(res);
00068 int i;
00069 long next_offset;
00070
00071
00072 for (i = 0; i < sqld; i++)
00073 {
00074 enum ECPGttype type = sqlda_dynamic_type(PQftype(res, i), compat);
00075
00076 switch (type)
00077 {
00078 case ECPGt_short:
00079 case ECPGt_unsigned_short:
00080 ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
00081 break;
00082 case ECPGt_int:
00083 case ECPGt_unsigned_int:
00084 ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
00085 break;
00086 case ECPGt_long:
00087 case ECPGt_unsigned_long:
00088 ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
00089 break;
00090 case ECPGt_long_long:
00091 case ECPGt_unsigned_long_long:
00092 ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
00093 break;
00094 case ECPGt_bool:
00095 ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
00096 break;
00097 case ECPGt_float:
00098 ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
00099 break;
00100 case ECPGt_double:
00101 ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
00102 break;
00103 case ECPGt_decimal:
00104 ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
00105 break;
00106 case ECPGt_numeric:
00107
00108
00109
00110
00111
00112
00113 ecpg_sqlda_align_add_size(offset, sizeof(NumericDigit *), sizeof(numeric), &offset, &next_offset);
00114 if (!PQgetisnull(res, row, i))
00115 {
00116 char *val = PQgetvalue(res, row, i);
00117 numeric *num;
00118
00119 num = PGTYPESnumeric_from_asc(val, NULL);
00120 if (!num)
00121 break;
00122 if (num->ndigits)
00123 ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->ndigits + 1, &offset, &next_offset);
00124 PGTYPESnumeric_free(num);
00125 }
00126 break;
00127 case ECPGt_date:
00128 ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
00129 break;
00130 case ECPGt_timestamp:
00131 ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(timestamp), &offset, &next_offset);
00132 break;
00133 case ECPGt_interval:
00134 ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
00135 break;
00136 case ECPGt_char:
00137 case ECPGt_unsigned_char:
00138 case ECPGt_string:
00139 default:
00140 {
00141 long datalen = strlen(PQgetvalue(res, row, i)) + 1;
00142
00143 ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
00144 break;
00145 }
00146 }
00147 offset = next_offset;
00148 }
00149 return offset;
00150 }
00151
00152
00153 static long
00154 sqlda_compat_total_size(const PGresult *res, int row, enum COMPAT_MODE compat)
00155 {
00156 long offset;
00157
00158 offset = sqlda_compat_empty_size(res);
00159
00160 if (row < 0)
00161 return offset;
00162
00163 offset = sqlda_common_total_size(res, row, compat, offset);
00164 return offset;
00165 }
00166
00167 static long
00168 sqlda_native_empty_size(const PGresult *res)
00169 {
00170 long offset;
00171 int sqld = PQnfields(res);
00172
00173
00174 offset = sizeof(struct sqlda_struct) + (sqld - 1) * sizeof(struct sqlvar_struct);
00175
00176
00177 ecpg_sqlda_align_add_size(offset, sizeof(int), 0, &offset, NULL);
00178
00179 return offset;
00180 }
00181
00182 static long
00183 sqlda_native_total_size(const PGresult *res, int row, enum COMPAT_MODE compat)
00184 {
00185 long offset;
00186
00187 offset = sqlda_native_empty_size(res);
00188
00189 if (row < 0)
00190 return offset;
00191
00192 offset = sqlda_common_total_size(res, row, compat, offset);
00193 return offset;
00194 }
00195
00196
00197
00198
00199
00200
00201 struct sqlda_compat *
00202 ecpg_build_compat_sqlda(int line, PGresult *res, int row, enum COMPAT_MODE compat)
00203 {
00204 struct sqlda_compat *sqlda;
00205 struct sqlvar_compat *sqlvar;
00206 char *fname;
00207 long size;
00208 int sqld;
00209 int i;
00210
00211 size = sqlda_compat_total_size(res, row, compat);
00212 sqlda = (struct sqlda_compat *) ecpg_alloc(size, line);
00213 if (!sqlda)
00214 return NULL;
00215
00216 memset(sqlda, 0, size);
00217 sqlvar = (struct sqlvar_compat *) (sqlda + 1);
00218 sqld = PQnfields(res);
00219 fname = (char *) (sqlvar + sqld);
00220
00221 sqlda->sqld = sqld;
00222 ecpg_log("ecpg_build_compat_sqlda on line %d sqld = %d\n", line, sqld);
00223 sqlda->desc_occ = size;
00224 sqlda->sqlvar = sqlvar;
00225
00226 for (i = 0; i < sqlda->sqld; i++)
00227 {
00228 sqlda->sqlvar[i].sqltype = sqlda_dynamic_type(PQftype(res, i), compat);
00229 strcpy(fname, PQfname(res, i));
00230 sqlda->sqlvar[i].sqlname = fname;
00231 fname += strlen(sqlda->sqlvar[i].sqlname) + 1;
00232
00233
00234
00235
00236
00237
00238 sqlda->sqlvar[i].sqlxid = PQftype(res, i);
00239 sqlda->sqlvar[i].sqltypelen = PQfsize(res, i);
00240 }
00241
00242 return sqlda;
00243 }
00244
00245
00246
00247
00248 static int16 value_is_null = -1;
00249 static int16 value_is_not_null = 0;
00250
00251 void
00252 ecpg_set_compat_sqlda(int lineno, struct sqlda_compat ** _sqlda, const PGresult *res, int row, enum COMPAT_MODE compat)
00253 {
00254 struct sqlda_compat *sqlda = (*_sqlda);
00255 int i;
00256 long offset,
00257 next_offset;
00258
00259 if (row < 0)
00260 return;
00261
00262
00263 offset = sqlda_compat_empty_size(res);
00264
00265
00266
00267
00268 for (i = 0; i < sqlda->sqld; i++)
00269 {
00270 int isnull;
00271 int datalen;
00272 bool set_data = true;
00273
00274 switch (sqlda->sqlvar[i].sqltype)
00275 {
00276 case ECPGt_short:
00277 case ECPGt_unsigned_short:
00278 ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
00279 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00280 sqlda->sqlvar[i].sqllen = sizeof(short);
00281 break;
00282 case ECPGt_int:
00283 case ECPGt_unsigned_int:
00284 ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
00285 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00286 sqlda->sqlvar[i].sqllen = sizeof(int);
00287 break;
00288 case ECPGt_long:
00289 case ECPGt_unsigned_long:
00290 ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
00291 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00292 sqlda->sqlvar[i].sqllen = sizeof(long);
00293 break;
00294 case ECPGt_long_long:
00295 case ECPGt_unsigned_long_long:
00296 ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
00297 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00298 sqlda->sqlvar[i].sqllen = sizeof(long long);
00299 break;
00300 case ECPGt_bool:
00301 ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
00302 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00303 sqlda->sqlvar[i].sqllen = sizeof(bool);
00304 break;
00305 case ECPGt_float:
00306 ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
00307 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00308 sqlda->sqlvar[i].sqllen = sizeof(float);
00309 break;
00310 case ECPGt_double:
00311 ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
00312 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00313 sqlda->sqlvar[i].sqllen = sizeof(double);
00314 break;
00315 case ECPGt_decimal:
00316 ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
00317 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00318 sqlda->sqlvar[i].sqllen = sizeof(decimal);
00319 break;
00320 case ECPGt_numeric:
00321 {
00322 numeric *num;
00323 char *val;
00324
00325 set_data = false;
00326
00327 ecpg_sqlda_align_add_size(offset, sizeof(NumericDigit *), sizeof(numeric), &offset, &next_offset);
00328 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00329 sqlda->sqlvar[i].sqllen = sizeof(numeric);
00330
00331 if (PQgetisnull(res, row, i))
00332 {
00333 ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
00334 break;
00335 }
00336
00337 val = PQgetvalue(res, row, i);
00338 num = PGTYPESnumeric_from_asc(val, NULL);
00339 if (!num)
00340 {
00341 ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
00342 break;
00343 }
00344
00345 memcpy(sqlda->sqlvar[i].sqldata, num, sizeof(numeric));
00346
00347 if (num->ndigits)
00348 {
00349 ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->ndigits + 1, &offset, &next_offset);
00350 memcpy((char *) sqlda + offset, num->buf, num->ndigits + 1);
00351
00352 ((numeric *) sqlda->sqlvar[i].sqldata)->buf = (NumericDigit *) sqlda + offset;
00353 ((numeric *) sqlda->sqlvar[i].sqldata)->digits = (NumericDigit *) sqlda + offset + (num->digits - num->buf);
00354 }
00355
00356 PGTYPESnumeric_free(num);
00357
00358 break;
00359 }
00360 case ECPGt_date:
00361 ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
00362 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00363 sqlda->sqlvar[i].sqllen = sizeof(date);
00364 break;
00365 case ECPGt_timestamp:
00366 ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(timestamp), &offset, &next_offset);
00367 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00368 sqlda->sqlvar[i].sqllen = sizeof(timestamp);
00369 break;
00370 case ECPGt_interval:
00371 ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
00372 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00373 sqlda->sqlvar[i].sqllen = sizeof(interval);
00374 break;
00375 case ECPGt_char:
00376 case ECPGt_unsigned_char:
00377 case ECPGt_string:
00378 default:
00379 datalen = strlen(PQgetvalue(res, row, i)) + 1;
00380 ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
00381 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00382 sqlda->sqlvar[i].sqllen = datalen;
00383 if (datalen > 32768)
00384 sqlda->sqlvar[i].sqlilongdata = sqlda->sqlvar[i].sqldata;
00385 break;
00386 }
00387
00388 isnull = PQgetisnull(res, row, i);
00389 ecpg_log("ecpg_set_compat_sqlda on line %d row %d col %d %s\n", lineno, row, i, isnull ? "IS NULL" : "IS NOT NULL");
00390 sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
00391 sqlda->sqlvar[i].sqlitype = ECPGt_short;
00392 sqlda->sqlvar[i].sqlilen = sizeof(short);
00393 if (!isnull)
00394 {
00395 if (set_data)
00396 ecpg_get_data(res, row, i, lineno,
00397 sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
00398 sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
00399 ECPG_ARRAY_NONE, compat, false);
00400 }
00401 else
00402 ECPGset_noind_null(sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqldata);
00403
00404 offset = next_offset;
00405 }
00406 }
00407
00408 struct sqlda_struct *
00409 ecpg_build_native_sqlda(int line, PGresult *res, int row, enum COMPAT_MODE compat)
00410 {
00411 struct sqlda_struct *sqlda;
00412 long size;
00413 int i;
00414
00415 size = sqlda_native_total_size(res, row, compat);
00416 sqlda = (struct sqlda_struct *) ecpg_alloc(size, line);
00417 if (!sqlda)
00418 return NULL;
00419
00420 memset(sqlda, 0, size);
00421
00422 sprintf(sqlda->sqldaid, "SQLDA ");
00423 sqlda->sqld = sqlda->sqln = PQnfields(res);
00424 ecpg_log("ecpg_build_native_sqlda on line %d sqld = %d\n", line, sqlda->sqld);
00425 sqlda->sqldabc = sizeof(struct sqlda_struct) + (sqlda->sqld - 1) * sizeof(struct sqlvar_struct);
00426
00427 for (i = 0; i < sqlda->sqld; i++)
00428 {
00429 char *fname;
00430
00431 sqlda->sqlvar[i].sqltype = sqlda_dynamic_type(PQftype(res, i), compat);
00432 fname = PQfname(res, i);
00433 sqlda->sqlvar[i].sqlname.length = strlen(fname);
00434 strcpy(sqlda->sqlvar[i].sqlname.data, fname);
00435 }
00436
00437 return sqlda;
00438 }
00439
00440 void
00441 ecpg_set_native_sqlda(int lineno, struct sqlda_struct ** _sqlda, const PGresult *res, int row, enum COMPAT_MODE compat)
00442 {
00443 struct sqlda_struct *sqlda = (*_sqlda);
00444 int i;
00445 long offset,
00446 next_offset;
00447
00448 if (row < 0)
00449 return;
00450
00451
00452 offset = sqlda_native_empty_size(res);
00453
00454
00455
00456
00457 for (i = 0; i < sqlda->sqld; i++)
00458 {
00459 int isnull;
00460 int datalen;
00461 bool set_data = true;
00462
00463 switch (sqlda->sqlvar[i].sqltype)
00464 {
00465 case ECPGt_short:
00466 case ECPGt_unsigned_short:
00467 ecpg_sqlda_align_add_size(offset, sizeof(short), sizeof(short), &offset, &next_offset);
00468 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00469 sqlda->sqlvar[i].sqllen = sizeof(short);
00470 break;
00471 case ECPGt_int:
00472 case ECPGt_unsigned_int:
00473 ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(int), &offset, &next_offset);
00474 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00475 sqlda->sqlvar[i].sqllen = sizeof(int);
00476 break;
00477 case ECPGt_long:
00478 case ECPGt_unsigned_long:
00479 ecpg_sqlda_align_add_size(offset, sizeof(long), sizeof(long), &offset, &next_offset);
00480 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00481 sqlda->sqlvar[i].sqllen = sizeof(long);
00482 break;
00483 case ECPGt_long_long:
00484 case ECPGt_unsigned_long_long:
00485 ecpg_sqlda_align_add_size(offset, sizeof(long long), sizeof(long long), &offset, &next_offset);
00486 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00487 sqlda->sqlvar[i].sqllen = sizeof(long long);
00488 break;
00489 case ECPGt_bool:
00490 ecpg_sqlda_align_add_size(offset, sizeof(bool), sizeof(bool), &offset, &next_offset);
00491 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00492 sqlda->sqlvar[i].sqllen = sizeof(bool);
00493 break;
00494 case ECPGt_float:
00495 ecpg_sqlda_align_add_size(offset, sizeof(float), sizeof(float), &offset, &next_offset);
00496 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00497 sqlda->sqlvar[i].sqllen = sizeof(float);
00498 break;
00499 case ECPGt_double:
00500 ecpg_sqlda_align_add_size(offset, sizeof(double), sizeof(double), &offset, &next_offset);
00501 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00502 sqlda->sqlvar[i].sqllen = sizeof(double);
00503 break;
00504 case ECPGt_decimal:
00505 ecpg_sqlda_align_add_size(offset, sizeof(int), sizeof(decimal), &offset, &next_offset);
00506 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00507 sqlda->sqlvar[i].sqllen = sizeof(decimal);
00508 break;
00509 case ECPGt_numeric:
00510 {
00511 numeric *num;
00512 char *val;
00513
00514 set_data = false;
00515
00516 ecpg_sqlda_align_add_size(offset, sizeof(NumericDigit *), sizeof(numeric), &offset, &next_offset);
00517 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00518 sqlda->sqlvar[i].sqllen = sizeof(numeric);
00519
00520 if (PQgetisnull(res, row, i))
00521 {
00522 ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
00523 break;
00524 }
00525
00526 val = PQgetvalue(res, row, i);
00527 num = PGTYPESnumeric_from_asc(val, NULL);
00528 if (!num)
00529 {
00530 ECPGset_noind_null(ECPGt_numeric, sqlda->sqlvar[i].sqldata);
00531 break;
00532 }
00533
00534 memcpy(sqlda->sqlvar[i].sqldata, num, sizeof(numeric));
00535
00536 if (num->ndigits)
00537 {
00538 ecpg_sqlda_align_add_size(next_offset, sizeof(int), num->ndigits + 1, &offset, &next_offset);
00539 memcpy((char *) sqlda + offset, num->buf, num->ndigits + 1);
00540
00541 ((numeric *) sqlda->sqlvar[i].sqldata)->buf = (NumericDigit *) sqlda + offset;
00542 ((numeric *) sqlda->sqlvar[i].sqldata)->digits = (NumericDigit *) sqlda + offset + (num->digits - num->buf);
00543 }
00544
00545 PGTYPESnumeric_free(num);
00546
00547 break;
00548 }
00549 case ECPGt_date:
00550 ecpg_sqlda_align_add_size(offset, sizeof(date), sizeof(date), &offset, &next_offset);
00551 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00552 sqlda->sqlvar[i].sqllen = sizeof(date);
00553 break;
00554 case ECPGt_timestamp:
00555 ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(timestamp), &offset, &next_offset);
00556 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00557 sqlda->sqlvar[i].sqllen = sizeof(timestamp);
00558 break;
00559 case ECPGt_interval:
00560 ecpg_sqlda_align_add_size(offset, sizeof(int64), sizeof(interval), &offset, &next_offset);
00561 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00562 sqlda->sqlvar[i].sqllen = sizeof(interval);
00563 break;
00564 case ECPGt_char:
00565 case ECPGt_unsigned_char:
00566 case ECPGt_string:
00567 default:
00568 datalen = strlen(PQgetvalue(res, row, i)) + 1;
00569 ecpg_sqlda_align_add_size(offset, sizeof(int), datalen, &offset, &next_offset);
00570 sqlda->sqlvar[i].sqldata = (char *) sqlda + offset;
00571 sqlda->sqlvar[i].sqllen = datalen;
00572 break;
00573 }
00574
00575 isnull = PQgetisnull(res, row, i);
00576 ecpg_log("ecpg_set_native_sqlda on line %d row %d col %d %s\n", lineno, row, i, isnull ? "IS NULL" : "IS NOT NULL");
00577 sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
00578 if (!isnull)
00579 {
00580 if (set_data)
00581 ecpg_get_data(res, row, i, lineno,
00582 sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
00583 sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
00584 ECPG_ARRAY_NONE, compat, false);
00585 }
00586
00587 offset = next_offset;
00588 }
00589 }