1 /********************************************************************/
2 /* */
3 /* sql_post.c Database access functions for PostgreSQL. */
4 /* Copyright (C) 1989 - 2020 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/sql_post.c */
27 /* Changes: 2014, 2015, 2017 - 2020 Thomas Mertes */
28 /* Content: Database access functions for PostgreSQL. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #include "string.h"
40 #include "time.h"
41 #include "limits.h"
42 #include "ctype.h"
43 #if SOCKET_LIB == UNIX_SOCKETS
44 #include "netinet/in.h"
45 #elif SOCKET_LIB == WINSOCK_SOCKETS
46 #include "winsock2.h"
47 #endif
48 #ifdef POSTGRESQL_INCLUDE
49 #include POSTGRESQL_INCLUDE
50 #ifdef POSTGRESQL_PG_TYPE_H
51 #include POSTGRESQL_PG_TYPE_H
52 #endif
53 #endif
54
55 #include "common.h"
56 #include "data_rtl.h"
57 #include "striutl.h"
58 #include "heaputl.h"
59 #include "numutl.h"
60 #include "int_rtl.h"
61 #include "flt_rtl.h"
62 #include "str_rtl.h"
63 #include "tim_rtl.h"
64 #include "big_drv.h"
65 #include "rtl_err.h"
66 #include "dll_drv.h"
67 #include "sql_base.h"
68 #include "sql_drv.h"
69
70 #ifdef POSTGRESQL_INCLUDE
71
72
73 typedef struct {
74 int ndigits; /* number of digits in digits[] - can be 0! */
75 int weight; /* weight of first digit */
76 int rscale; /* result scale */
77 int dscale; /* display scale */
78 int sign; /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */
79 const unsigned char *digits; /* decimal digits */
80 } numeric;
81
82 typedef struct {
83 uintType usage_count;
84 sqlFuncType sqlFunc;
85 intType driver;
86 PGconn *connection;
87 boolType integerDatetimes;
88 uintType nextStmtNum;
89 boolType autoCommit;
90 } dbRecord, *dbType;
91
92 typedef struct {
93 cstriType buffer;
94 boolType bound;
95 } bindDataRecord, *bindDataType;
96
97 typedef struct {
98 uintType usage_count;
99 sqlFuncType sqlFunc;
100 dbType db;
101 boolType integerDatetimes;
102 boolType implicitCommit;
103 uintType stmtNum;
104 char stmtName[30];
105 memSizeType param_array_size;
106 bindDataType param_array;
107 Oid *paramTypes;
108 cstriType *paramValues;
109 int *paramLengths;
110 int *paramFormats;
111 memSizeType result_column_count;
112 boolType executeSuccessful;
113 PGresult *execute_result;
114 ExecStatusType execute_status;
115 boolType fetchOkay;
116 int num_tuples;
117 int fetch_index;
118 boolType increment_index;
119 } preparedStmtRecord, *preparedStmtType;
120
121 static sqlFuncType sqlFunc = NULL;
122
123 #define DEFAULT_PORT 5432
124 #define MAX_BIND_VAR_SIZE 5
125 #define MIN_BIND_VAR_NUM 1
126 #define MAX_BIND_VAR_NUM 9999
127 /* Seconds between 1970-01-01 and 2000-01-01 */
128 #define SECONDS_FROM_1970_TO_2000 INT64_SUFFIX(946684800)
129 #define DEFAULT_DECIMAL_SCALE 1000
130
131
132 #ifdef POSTGRESQL_DLL
133
134 #ifndef CDECL
135 #if defined(_WIN32) && HAS_CDECL
136 #define CDECL __cdecl
137 #else
138 #define CDECL
139 #endif
140 #endif
141
142 typedef void (CDECL *tp_PQclear) (PGresult *res);
143 typedef PGresult *(CDECL *tp_PQdescribePrepared) (PGconn *conn, const char *stmt);
144 typedef char *(CDECL *tp_PQerrorMessage) (const PGconn *conn);
145 typedef PGresult *(CDECL *tp_PQexec) (PGconn *conn, const char *query);
146 typedef PGresult *(CDECL *tp_PQexecPrepared) (PGconn *conn,
147 const char *stmtName,
148 int nParams,
149 const char *const * paramValues,
150 const int *paramLengths,
151 const int *paramFormats,
152 int resultFormat);
153 typedef void (CDECL *tp_PQfinish) (PGconn *conn);
154 typedef char *(CDECL *tp_PQfname) (const PGresult *res, int field_num);
155 typedef Oid (CDECL *tp_PQftype) (const PGresult *res, int field_num);
156 typedef int (CDECL *tp_PQgetisnull) (const PGresult *res, int tup_num, int field_num);
157 typedef int (CDECL *tp_PQgetlength) (const PGresult *res, int tup_num, int field_num);
158 typedef char *(CDECL *tp_PQgetvalue) (const PGresult *res, int tup_num, int field_num);
159 typedef int (CDECL *tp_PQnfields) (const PGresult *res);
160 typedef int (CDECL *tp_PQnparams) (const PGresult *res);
161 typedef int (CDECL *tp_PQntuples) (const PGresult *res);
162 typedef const char *(CDECL *tp_PQparameterStatus) (const PGconn *conn, const char *paramName);
163 typedef Oid (CDECL *tp_PQparamtype) (const PGresult *res, int param_num);
164 typedef PGresult *(CDECL *tp_PQprepare) (PGconn *conn, const char *stmtName,
165 const char *query, int nParams,
166 const Oid *paramTypes);
167 typedef char *(CDECL *tp_PQresStatus) (ExecStatusType status);
168 typedef char *(CDECL *tp_PQresultErrorMessage) (const PGresult *res);
169 typedef ExecStatusType (CDECL *tp_PQresultStatus) (const PGresult *res);
170 typedef int (CDECL *tp_PQsetClientEncoding) (PGconn *conn, const char *encoding);
171 typedef PGconn *(CDECL *tp_PQsetdbLogin) (const char *pghost, const char *pgport,
172 const char *pgoptions, const char *pgtty,
173 const char *dbName,
174 const char *login, const char *pwd);
175 typedef ConnStatusType (CDECL *tp_PQstatus) (const PGconn *conn);
176
177 static tp_PQclear ptr_PQclear;
178 static tp_PQdescribePrepared ptr_PQdescribePrepared;
179 static tp_PQerrorMessage ptr_PQerrorMessage;
180 static tp_PQexec ptr_PQexec;
181 static tp_PQexecPrepared ptr_PQexecPrepared;
182 static tp_PQfinish ptr_PQfinish;
183 static tp_PQfname ptr_PQfname;
184 static tp_PQftype ptr_PQftype;
185 static tp_PQgetisnull ptr_PQgetisnull;
186 static tp_PQgetlength ptr_PQgetlength;
187 static tp_PQgetvalue ptr_PQgetvalue;
188 static tp_PQnfields ptr_PQnfields;
189 static tp_PQnparams ptr_PQnparams;
190 static tp_PQntuples ptr_PQntuples;
191 static tp_PQparameterStatus ptr_PQparameterStatus;
192 static tp_PQparamtype ptr_PQparamtype;
193 static tp_PQprepare ptr_PQprepare;
194 static tp_PQresStatus ptr_PQresStatus;
195 static tp_PQresultErrorMessage ptr_PQresultErrorMessage;
196 static tp_PQresultStatus ptr_PQresultStatus;
197 static tp_PQsetClientEncoding ptr_PQsetClientEncoding;
198 static tp_PQsetdbLogin ptr_PQsetdbLogin;
199 static tp_PQstatus ptr_PQstatus;
200
201 #define PQclear ptr_PQclear
202 #define PQdescribePrepared ptr_PQdescribePrepared
203 #define PQerrorMessage ptr_PQerrorMessage
204 #define PQexec ptr_PQexec
205 #define PQexecPrepared ptr_PQexecPrepared
206 #define PQfinish ptr_PQfinish
207 #define PQfname ptr_PQfname
208 #define PQftype ptr_PQftype
209 #define PQgetisnull ptr_PQgetisnull
210 #define PQgetlength ptr_PQgetlength
211 #define PQgetvalue ptr_PQgetvalue
212 #define PQnfields ptr_PQnfields
213 #define PQnparams ptr_PQnparams
214 #define PQntuples ptr_PQntuples
215 #define PQparameterStatus ptr_PQparameterStatus
216 #define PQparamtype ptr_PQparamtype
217 #define PQprepare ptr_PQprepare
218 #define PQresStatus ptr_PQresStatus
219 #define PQresultErrorMessage ptr_PQresultErrorMessage
220 #define PQresultStatus ptr_PQresultStatus
221 #define PQsetClientEncoding ptr_PQsetClientEncoding
222 #define PQsetdbLogin ptr_PQsetdbLogin
223 #define PQstatus ptr_PQstatus
224
225
226
setupDll(const char * dllName)227 static boolType setupDll (const char *dllName)
228
229 {
230 static void *dbDll = NULL;
231
232 /* setupDll */
233 logFunction(printf("setupDll(\"%s\")\n", dllName););
234 if (dbDll == NULL) {
235 #ifdef LIBINTL_DLL
236 {
237 const char *libIntlDllList[] = { LIBINTL_DLL };
238 unsigned int pos;
239 boolType found = FALSE;
240
241 for (pos = 0; pos < sizeof(libIntlDllList) / sizeof(char *) && !found; pos++) {
242 found = dllOpen(libIntlDllList[pos]) != NULL;
243 } /* for */
244 }
245 #endif
246 #ifdef LIBEAY32_DLL
247 {
248 const char *libeay32DllList[] = { LIBEAY32_DLL };
249 unsigned int pos;
250 boolType found = FALSE;
251
252 for (pos = 0; pos < sizeof(libeay32DllList) / sizeof(char *) && !found; pos++) {
253 found = dllOpen(libeay32DllList[pos]) != NULL;
254 } /* for */
255 }
256 #endif
257 #ifdef LIBCRYPTO_DLL
258 {
259 const char *libcryptoDllList[] = { LIBCRYPTO_DLL };
260 unsigned int pos;
261 boolType found = FALSE;
262
263 for (pos = 0; pos < sizeof(libcryptoDllList) / sizeof(char *) && !found; pos++) {
264 found = dllOpen(libcryptoDllList[pos]) != NULL;
265 } /* for */
266 }
267 #endif
268 #ifdef LIBSSL_DLL
269 {
270 const char *libsslDllList[] = { LIBSSL_DLL };
271 unsigned int pos;
272 boolType found = FALSE;
273
274 for (pos = 0; pos < sizeof(libsslDllList) / sizeof(char *) && !found; pos++) {
275 found = dllOpen(libsslDllList[pos]) != NULL;
276 } /* for */
277 }
278 #endif
279 dbDll = dllOpen(dllName);
280 if (dbDll != NULL) {
281 if ((PQclear = (tp_PQclear) dllFunc(dbDll, "PQclear")) == NULL ||
282 (PQdescribePrepared = (tp_PQdescribePrepared) dllFunc(dbDll, "PQdescribePrepared")) == NULL ||
283 (PQerrorMessage = (tp_PQerrorMessage) dllFunc(dbDll, "PQerrorMessage")) == NULL ||
284 (PQexec = (tp_PQexec) dllFunc(dbDll, "PQexec")) == NULL ||
285 (PQexecPrepared = (tp_PQexecPrepared) dllFunc(dbDll, "PQexecPrepared")) == NULL ||
286 (PQfinish = (tp_PQfinish) dllFunc(dbDll, "PQfinish")) == NULL ||
287 (PQfname = (tp_PQfname) dllFunc(dbDll, "PQfname")) == NULL ||
288 (PQftype = (tp_PQftype) dllFunc(dbDll, "PQftype")) == NULL ||
289 (PQgetisnull = (tp_PQgetisnull) dllFunc(dbDll, "PQgetisnull")) == NULL ||
290 (PQgetlength = (tp_PQgetlength) dllFunc(dbDll, "PQgetlength")) == NULL ||
291 (PQgetvalue = (tp_PQgetvalue) dllFunc(dbDll, "PQgetvalue")) == NULL ||
292 (PQnfields = (tp_PQnfields) dllFunc(dbDll, "PQnfields")) == NULL ||
293 (PQnparams = (tp_PQnparams) dllFunc(dbDll, "PQnparams")) == NULL ||
294 (PQntuples = (tp_PQntuples) dllFunc(dbDll, "PQntuples")) == NULL ||
295 (PQparameterStatus = (tp_PQparameterStatus) dllFunc(dbDll, "PQparameterStatus")) == NULL ||
296 (PQparamtype = (tp_PQparamtype) dllFunc(dbDll, "PQparamtype")) == NULL ||
297 (PQprepare = (tp_PQprepare) dllFunc(dbDll, "PQprepare")) == NULL ||
298 (PQresStatus = (tp_PQresStatus) dllFunc(dbDll, "PQresStatus")) == NULL ||
299 (PQresultErrorMessage = (tp_PQresultErrorMessage) dllFunc(dbDll, "PQresultErrorMessage")) == NULL ||
300 (PQresultStatus = (tp_PQresultStatus) dllFunc(dbDll, "PQresultStatus")) == NULL ||
301 (PQsetClientEncoding = (tp_PQsetClientEncoding) dllFunc(dbDll, "PQsetClientEncoding")) == NULL ||
302 (PQsetdbLogin = (tp_PQsetdbLogin) dllFunc(dbDll, "PQsetdbLogin")) == NULL ||
303 (PQstatus = (tp_PQstatus) dllFunc(dbDll, "PQstatus")) == NULL) {
304 dbDll = NULL;
305 } /* if */
306 } /* if */
307 } /* if */
308 logFunction(printf("setupDll --> %d\n", dbDll != NULL););
309 return dbDll != NULL;
310 } /* setupDll */
311
312
313
findDll(void)314 static boolType findDll (void)
315
316 {
317 const char *dllList[] = { POSTGRESQL_DLL };
318 unsigned int pos;
319 boolType found = FALSE;
320
321 /* findDll */
322 for (pos = 0; pos < sizeof(dllList) / sizeof(char *) && !found; pos++) {
323 found = setupDll(dllList[pos]);
324 } /* for */
325 if (!found) {
326 dllErrorMessage("sqlOpenPost", "findDll", dllList,
327 sizeof(dllList) / sizeof(char *));
328 } /* if */
329 return found;
330 } /* findDll */
331
332 #else
333
334 #define findDll() TRUE
335
336 #endif
337
338
339
340 #undef htonll
341 #undef ntohll
342
343 #if BIG_ENDIAN_INTTYPE
344
345 #define htonll(n) (n)
346 #define ntohll(n) (n)
347 #define htonf(n) (n)
348 #define ntohf(n) (n)
349 #define htond(n) (n)
350 #define ntohd(n) (n)
351
352 #else
353
354 #define htonll(n) swapUInt64(n)
355 #define ntohll(n) swapUInt64(n)
356 #define htonf(n) swap32float(n)
357 #define ntohf(n) swap32float(n)
358 #define htond(n) swap64double(n)
359 #define ntohd(n) swap64double(n)
360
swapUInt64(uint64Type n)361 static inline uint64Type swapUInt64 (uint64Type n)
362 {
363 return ((n & 0xFF) << 56) | ((n & 0xFF00) << 40) |
364 ((n & 0xFF0000) << 24) | ((n & 0xFF000000) << 8) |
365 ((n & 0xFF00000000) >> 8) | ((n & 0xFF0000000000) >> 24) |
366 ((n & 0xFF000000000000) >> 40) | ((n & 0xFF00000000000000) >> 56);
367 }
368
swap32float(float n)369 static inline float swap32float (float n)
370 {
371 union {
372 uint32Type i;
373 float f;
374 } flt2int;
375
376 flt2int.f = n;
377 flt2int.i = ntohl(flt2int.i);
378 return flt2int.f;
379 }
380
swap64double(double n)381 static inline double swap64double (double n)
382 {
383 union {
384 uint64Type i;
385 double f;
386 } flt2int;
387
388 flt2int.f = n;
389 flt2int.i = ntohll(flt2int.i);
390 return flt2int.f;
391 }
392
393 #endif
394
395
396
397 static void sqlClose (databaseType database);
398
399
400
setDbErrorMsg(const char * funcName,const char * dbFuncName,PGconn * connection)401 static void setDbErrorMsg (const char *funcName, const char *dbFuncName,
402 PGconn *connection)
403
404 { /* setDbErrorMsg */
405 dbError.funcName = funcName;
406 dbError.dbFuncName = dbFuncName;
407 dbError.errorCode = 0;
408 snprintf(dbError.message, DB_ERR_MESSAGE_SIZE, "%s",
409 PQerrorMessage(connection));
410 } /* setDbErrorMsg */
411
412
413
doExecSql(PGconn * connection,const char * query,errInfoType err_info)414 static errInfoType doExecSql (PGconn *connection, const char *query,
415 errInfoType err_info)
416
417 {
418 PGresult *execResult;
419
420 /* doExecSql */
421 logFunction(printf("doExecSql(" FMT_U_MEM ", \"%s\", %d)\n",
422 (memSizeType) connection, query, err_info););
423 if (likely(err_info == OKAY_NO_ERROR)) {
424 execResult = PQexec(connection, query);
425 if (unlikely(execResult == NULL)) {
426 err_info = MEMORY_ERROR;
427 } else {
428 if (PQresultStatus(execResult) != PGRES_COMMAND_OK) {
429 setDbErrorMsg("doExecSql", "PQexec", connection);
430 logError(printf("doExecSql: PQexec(" FMT_U_MEM ", \"%s\") "
431 "returns a status of %s:\n%s",
432 (memSizeType) connection, query,
433 PQresStatus(PQresultStatus(execResult)),
434 dbError.message););
435 err_info = DATABASE_ERROR;
436 } /* if */
437 PQclear(execResult);
438 } /* if */
439 } /* if */
440 logFunction(printf("doExecSql --> %d\n", err_info););
441 return err_info;
442 } /* doExecSql */
443
444
445
implicitCommit(const_cstriType query)446 static boolType implicitCommit (const_cstriType query)
447
448 {
449 const char *explicitCommit[] = {
450 /* DML */ "SELECT", "INSERT", "UPDATE", "DELETE", "MERGE",
451 /* TCS */ "COMMIT", "ROLLBACK", "SAVEPOINT", "BEGIN"};
452 const_cstriType startPos;
453 const_cstriType beyond;
454 const_cstriType pos;
455 char keyword[20];
456 int idx;
457 boolType implicitCommit = TRUE;
458
459 /* implicitCommit */
460 logFunction(printf("implicitCommit(\"%s\")\n", query););
461 startPos = query;
462 while (*startPos == ' ' || *startPos == '\t' ||
463 *startPos == '\n' || *startPos == '\r') {
464 startPos++;
465 } /* while */
466 beyond = startPos;
467 while (isalpha(*beyond)) {
468 beyond++;
469 } /* while */
470 if (beyond - startPos <= sizeof(keyword)) {
471 for (pos = startPos; pos != beyond; pos++) {
472 keyword[pos - startPos] = (char) toupper(*pos);
473 } /* for */
474 keyword[beyond - startPos] = '\0';
475 for (idx = 0; idx < sizeof(explicitCommit) / sizeof(char *) &&
476 implicitCommit; idx++) {
477 if (strcmp(keyword, explicitCommit[idx]) == 0) {
478 implicitCommit = FALSE;
479 } /* if */
480 } /* for */
481 } /* if */
482 logFunction(printf("implicitCommit --> %d\n", implicitCommit););
483 return implicitCommit;
484 } /* implicitCommit */
485
486
487
PQdeallocate(PGconn * conn,const char * stmtName)488 static PGresult *PQdeallocate (PGconn *conn, const char *stmtName)
489
490 {
491 const char deallocateCommand[] = "DEALLOCATE ";
492 memSizeType length;
493 char *command;
494 PGresult *deallocate_result;
495
496 /* PQdeallocate */
497 logFunction(printf("PQdeallocate(" FMT_X_MEM ", %s)\n",
498 (memSizeType) conn, stmtName););
499 length = STRLEN(deallocateCommand) + strlen(stmtName) + NULL_TERMINATION_LEN;
500 command = (char *) malloc(length);
501 if (command == NULL) {
502 deallocate_result = NULL;
503 } else {
504 memcpy(command, deallocateCommand, STRLEN(deallocateCommand));
505 strcpy(&command[STRLEN(deallocateCommand)], stmtName);
506 deallocate_result = PQexec(conn, command);
507 free(command);
508 } /* if */
509 return deallocate_result;
510 } /* PQdeallocate */
511
512
513
514 /**
515 * Closes a database and frees the memory used by it.
516 */
freeDatabase(databaseType database)517 static void freeDatabase (databaseType database)
518
519 {
520 dbType db;
521
522 /* freeDatabase */
523 logFunction(printf("freeDatabase(" FMT_U_MEM ")\n",
524 (memSizeType) database););
525 sqlClose(database);
526 db = (dbType) database;
527 FREE_RECORD2(db, dbRecord, count.database, count.database_bytes);
528 logFunction(printf("freeDatabase -->\n"););
529 } /* freeDatabase */
530
531
532
533 /**
534 * Closes a prepared statement and frees the memory used by it.
535 */
freePreparedStmt(sqlStmtType sqlStatement)536 static void freePreparedStmt (sqlStmtType sqlStatement)
537
538 {
539 preparedStmtType preparedStmt;
540 memSizeType pos;
541 static PGresult *deallocate_result;
542
543 /* freePreparedStmt */
544 logFunction(printf("freePreparedStmt(" FMT_U_MEM ")\n",
545 (memSizeType) sqlStatement););
546 preparedStmt = (preparedStmtType) sqlStatement;
547 if (preparedStmt->param_array != NULL) {
548 for (pos = 0; pos < preparedStmt->param_array_size; pos++) {
549 free(preparedStmt->param_array[pos].buffer);
550 } /* for */
551 FREE_TABLE(preparedStmt->param_array, bindDataRecord, preparedStmt->param_array_size);
552 } /* if */
553 if (preparedStmt->paramTypes != NULL) {
554 FREE_TABLE(preparedStmt->paramTypes, Oid, preparedStmt->param_array_size);
555 } /* if */
556 if (preparedStmt->paramValues != NULL) {
557 FREE_TABLE(preparedStmt->paramValues, cstriType, preparedStmt->param_array_size);
558 } /* if */
559 if (preparedStmt->paramLengths != NULL) {
560 FREE_TABLE(preparedStmt->paramLengths, int, preparedStmt->param_array_size);
561 } /* if */
562 if (preparedStmt->paramFormats != NULL) {
563 FREE_TABLE(preparedStmt->paramFormats, int, preparedStmt->param_array_size);
564 } /* if */
565 if (preparedStmt->execute_result != NULL) {
566 PQclear(preparedStmt->execute_result);
567 } /* if */
568 deallocate_result = PQdeallocate(preparedStmt->db->connection, preparedStmt->stmtName);
569 if (unlikely(deallocate_result != NULL)) {
570 /* Ignore possible errors. */
571 PQclear(deallocate_result);
572 } /* if */
573 preparedStmt->db->usage_count--;
574 if (preparedStmt->db->usage_count == 0) {
575 /* printf("FREE " FMT_X_MEM "\n", (memSizeType) preparedStmt->db); */
576 freeDatabase((databaseType) preparedStmt->db);
577 } /* if */
578 FREE_RECORD2(preparedStmt, preparedStmtRecord,
579 count.prepared_stmt, count.prepared_stmt_bytes);
580 logFunction(printf("freePreparedStmt -->\n"););
581 } /* freePreparedStmt */
582
583
584
585 #if LOG_FUNCTIONS_EVERYWHERE || LOG_FUNCTIONS || VERBOSE_EXCEPTIONS_EVERYWHERE || VERBOSE_EXCEPTIONS
nameOfBufferType(Oid buffer_type)586 static const char *nameOfBufferType (Oid buffer_type)
587
588 {
589 static char buffer[50];
590 const char *typeName;
591
592 /* nameOfBufferType */
593 logFunction(printf("nameOfBufferType(%d)\n", buffer_type););
594 switch (buffer_type) {
595 case BOOLOID: typeName = "BOOLOID"; break;
596 case BYTEAOID: typeName = "BYTEAOID"; break;
597 case CHAROID: typeName = "CHAROID"; break;
598 case NAMEOID: typeName = "NAMEOID"; break;
599 case INT8OID: typeName = "INT8OID"; break;
600 case INT2OID: typeName = "INT2OID"; break;
601 case INT2VECTOROID: typeName = "INT2VECTOROID"; break;
602 case INT4OID: typeName = "INT4OID"; break;
603 case REGPROCOID: typeName = "REGPROCOID"; break;
604 case TEXTOID: typeName = "TEXTOID"; break;
605 case OIDOID: typeName = "OIDOID"; break;
606 case TIDOID: typeName = "TIDOID"; break;
607 case XIDOID: typeName = "XIDOID"; break;
608 case CIDOID: typeName = "CIDOID"; break;
609 case OIDVECTOROID: typeName = "OIDVECTOROID"; break;
610 case XMLOID: typeName = "XMLOID"; break;
611 #ifdef PGNODETREEOID
612 case PGNODETREEOID: typeName = "PGNODETREEOID"; break;
613 #endif
614 case POINTOID: typeName = "POINTOID"; break;
615 case LSEGOID: typeName = "LSEGOID"; break;
616 case PATHOID: typeName = "PATHOID"; break;
617 case BOXOID: typeName = "BOXOID"; break;
618 case POLYGONOID: typeName = "POLYGONOID"; break;
619 case LINEOID: typeName = "LINEOID"; break;
620 case FLOAT4OID: typeName = "FLOAT4OID"; break;
621 case FLOAT8OID: typeName = "FLOAT8OID"; break;
622 case ABSTIMEOID: typeName = "ABSTIMEOID"; break;
623 case RELTIMEOID: typeName = "RELTIMEOID"; break;
624 case TINTERVALOID: typeName = "TINTERVALOID"; break;
625 case UNKNOWNOID: typeName = "UNKNOWNOID"; break;
626 case CIRCLEOID: typeName = "CIRCLEOID"; break;
627 case CASHOID: typeName = "CASHOID"; break;
628 case MACADDROID: typeName = "MACADDROID"; break;
629 case INETOID: typeName = "INETOID"; break;
630 case CIDROID: typeName = "CIDROID"; break;
631 #ifdef INT2ARRAYOID
632 case INT2ARRAYOID: typeName = "INT2ARRAYOID"; break;
633 #endif
634 case INT4ARRAYOID: typeName = "INT4ARRAYOID"; break;
635 case TEXTARRAYOID: typeName = "TEXTARRAYOID"; break;
636 #ifdef OIDARRAYOID
637 case OIDARRAYOID: typeName = "OIDARRAYOID"; break;
638 #endif
639 case FLOAT4ARRAYOID: typeName = "FLOAT4ARRAYOID"; break;
640 case ACLITEMOID: typeName = "ACLITEMOID"; break;
641 case CSTRINGARRAYOID: typeName = "CSTRINGARRAYOID"; break;
642 case BPCHAROID: typeName = "BPCHAROID"; break;
643 case VARCHAROID: typeName = "VARCHAROID"; break;
644 case DATEOID: typeName = "DATEOID"; break;
645 case TIMEOID: typeName = "TIMEOID"; break;
646 case TIMESTAMPOID: typeName = "TIMESTAMPOID"; break;
647 case TIMESTAMPTZOID: typeName = "TIMESTAMPTZOID"; break;
648 case INTERVALOID: typeName = "INTERVALOID"; break;
649 case TIMETZOID: typeName = "TIMETZOID"; break;
650 case BITOID: typeName = "BITOID"; break;
651 case VARBITOID: typeName = "VARBITOID"; break;
652 case NUMERICOID: typeName = "NUMERICOID"; break;
653 case REFCURSOROID: typeName = "REFCURSOROID"; break;
654 case REGPROCEDUREOID: typeName = "REGPROCEDUREOID"; break;
655 case REGOPEROID: typeName = "REGOPEROID"; break;
656 case REGOPERATOROID: typeName = "REGOPERATOROID"; break;
657 case REGCLASSOID: typeName = "REGCLASSOID"; break;
658 case REGTYPEOID: typeName = "REGTYPEOID"; break;
659 case REGTYPEARRAYOID: typeName = "REGTYPEARRAYOID"; break;
660 case TSVECTOROID: typeName = "TSVECTOROID"; break;
661 case GTSVECTOROID: typeName = "GTSVECTOROID"; break;
662 case TSQUERYOID: typeName = "TSQUERYOID"; break;
663 case REGCONFIGOID: typeName = "REGCONFIGOID"; break;
664 case REGDICTIONARYOID: typeName = "REGDICTIONARYOID"; break;
665 case RECORDOID: typeName = "RECORDOID"; break;
666 case RECORDARRAYOID: typeName = "RECORDARRAYOID"; break;
667 case CSTRINGOID: typeName = "CSTRINGOID"; break;
668 case ANYOID: typeName = "ANYOID"; break;
669 case ANYARRAYOID: typeName = "ANYARRAYOID"; break;
670 case VOIDOID: typeName = "VOIDOID"; break;
671 case TRIGGEROID: typeName = "TRIGGEROID"; break;
672 case LANGUAGE_HANDLEROID: typeName = "LANGUAGE_HANDLEROID"; break;
673 case INTERNALOID: typeName = "INTERNALOID"; break;
674 case OPAQUEOID: typeName = "OPAQUEOID"; break;
675 case ANYELEMENTOID: typeName = "ANYELEMENTOID"; break;
676 case ANYNONARRAYOID: typeName = "ANYNONARRAYOID"; break;
677 case ANYENUMOID: typeName = "ANYENUMOID"; break;
678 #ifdef FDW_HANDLEROID
679 case FDW_HANDLEROID: typeName = "FDW_HANDLEROID"; break;
680 #endif
681 default:
682 sprintf(buffer, "%d", buffer_type);
683 typeName = buffer;
684 break;
685 } /* switch */
686 logFunction(printf("nameOfBufferType --> %s\n", typeName););
687 return typeName;
688 } /* nameOfBufferType */
689 #endif
690
691
692
693 /**
694 * Process the bind variables in a statement string.
695 * Literals and comments are processed to avoid the misinterpretation
696 * of question marks (?).
697 */
processStatementStri(const const_striType sqlStatementStri,errInfoType * err_info)698 static striType processStatementStri (const const_striType sqlStatementStri,
699 errInfoType *err_info)
700
701 {
702 memSizeType pos = 0;
703 strElemType ch;
704 strElemType delimiter;
705 memSizeType destPos = 0;
706 unsigned int varNum = MIN_BIND_VAR_NUM;
707 striType processed;
708
709 /* processStatementStri */
710 logFunction(printf("processStatementStri(\"%s\")\n",
711 striAsUnquotedCStri(sqlStatementStri)););
712 if (unlikely(sqlStatementStri->size > MAX_STRI_LEN / MAX_BIND_VAR_SIZE ||
713 !ALLOC_STRI_SIZE_OK(processed, sqlStatementStri->size * MAX_BIND_VAR_SIZE))) {
714 *err_info = MEMORY_ERROR;
715 processed = NULL;
716 } else {
717 while (pos < sqlStatementStri->size && *err_info == OKAY_NO_ERROR) {
718 ch = sqlStatementStri->mem[pos];
719 if (ch == '?') {
720 if (varNum > MAX_BIND_VAR_NUM) {
721 logError(printf("processStatementStri: Too many variables\n"););
722 *err_info = RANGE_ERROR;
723 FREE_STRI(processed, sqlStatementStri->size * MAX_BIND_VAR_SIZE);
724 processed = NULL;
725 } else {
726 processed->mem[destPos++] = '$';
727 if (varNum >= 1000) {
728 processed->mem[destPos++] = '0' + ( varNum / 1000);
729 } /* if */
730 if (varNum >= 100) {
731 processed->mem[destPos++] = '0' + ((varNum / 100) % 10);
732 } /* if */
733 if (varNum >= 10) {
734 processed->mem[destPos++] = '0' + ((varNum / 10) % 10);
735 } /* if */
736 processed->mem[destPos++] = '0' + ( varNum % 10);
737 varNum++;
738 } /* if */
739 pos++;
740 } else if (ch == '\'' || ch == '"') {
741 delimiter = ch;
742 processed->mem[destPos++] = delimiter;
743 pos++;
744 while (pos < sqlStatementStri->size &&
745 (ch = sqlStatementStri->mem[pos]) != delimiter) {
746 processed->mem[destPos++] = ch;
747 pos++;
748 } /* while */
749 if (pos < sqlStatementStri->size) {
750 processed->mem[destPos++] = delimiter;
751 pos++;
752 } /* if */
753 } else if (ch == '/') {
754 pos++;
755 if (pos >= sqlStatementStri->size || sqlStatementStri->mem[pos] != '*') {
756 processed->mem[destPos++] = ch;
757 } else {
758 pos++;
759 do {
760 while (pos < sqlStatementStri->size && sqlStatementStri->mem[pos] != '*') {
761 pos++;
762 } /* while */
763 pos++;
764 } while (pos < sqlStatementStri->size && sqlStatementStri->mem[pos] != '/');
765 pos++;
766 /* Replace the comment with a space. */
767 processed->mem[destPos++] = ' ';
768 } /* if */
769 } else if (ch == '-') {
770 pos++;
771 if (pos >= sqlStatementStri->size || sqlStatementStri->mem[pos] != '-') {
772 processed->mem[destPos++] = ch;
773 } else {
774 pos++;
775 while (pos < sqlStatementStri->size && sqlStatementStri->mem[pos] != '\n') {
776 pos++;
777 } /* while */
778 /* The final newline replaces the comment. */
779 } /* if */
780 } else {
781 processed->mem[destPos++] = ch;
782 pos++;
783 } /* if */
784 } /* while */
785 processed->size = destPos;
786 } /* if */
787 logFunction(printf("processStatementStri --> \"%s\"\n",
788 striAsUnquotedCStri(processed)););
789 return processed;
790 } /* processStatementStri */
791
792
793
setupParameterColumn(preparedStmtType preparedStmt,int param_index,bindDataType param)794 static errInfoType setupParameterColumn (preparedStmtType preparedStmt,
795 int param_index, bindDataType param)
796
797 {
798 memSizeType paramLength = 0;
799 errInfoType err_info = OKAY_NO_ERROR;
800
801 /* setupParameterColumn */
802 switch (preparedStmt->paramTypes[param_index]) {
803 case INT2OID:
804 paramLength = sizeof(int16Type);
805 break;
806 case INT4OID:
807 paramLength = sizeof(int32Type);
808 break;
809 case INT8OID:
810 paramLength = sizeof(int64Type);
811 break;
812 case FLOAT4OID:
813 paramLength = sizeof(float);
814 break;
815 case FLOAT8OID:
816 paramLength = sizeof(double);
817 break;
818 case DATEOID:
819 paramLength = sizeof(int32Type);
820 break;
821 case TIMEOID:
822 if (preparedStmt->integerDatetimes) {
823 paramLength = sizeof(int64Type);
824 } else {
825 paramLength = sizeof(double);
826 } /* if */
827 break;
828 case TIMETZOID:
829 if (preparedStmt->integerDatetimes) {
830 paramLength = sizeof(int64Type) + sizeof(int32Type);
831 } else {
832 paramLength = sizeof(double) + sizeof(int32Type);
833 } /* if */
834 break;
835 case TIMESTAMPOID:
836 if (preparedStmt->integerDatetimes) {
837 paramLength = sizeof(int64Type);
838 } else {
839 paramLength = sizeof(double);
840 } /* if */
841 break;
842 case TIMESTAMPTZOID:
843 if (preparedStmt->integerDatetimes) {
844 paramLength = sizeof(int64Type);
845 } else {
846 paramLength = sizeof(double);
847 } /* if */
848 break;
849 case INTERVALOID:
850 if (preparedStmt->integerDatetimes) {
851 paramLength = sizeof(int64Type) + 2 * sizeof(int32Type);
852 } else {
853 paramLength = sizeof(double) + 2 * sizeof(int32Type);
854 } /* if */
855 break;
856 } /* switch */
857 if (paramLength != 0) {
858 param->buffer = (cstriType) malloc(paramLength);
859 if (unlikely(param->buffer == NULL)) {
860 err_info = MEMORY_ERROR;
861 } else {
862 preparedStmt->paramValues[param_index] = NULL;
863 preparedStmt->paramLengths[param_index] = (int) paramLength;
864 preparedStmt->paramFormats[param_index] = 1;
865 } /* if */
866 } else {
867 param->buffer = NULL;
868 preparedStmt->paramValues[param_index] = NULL;
869 preparedStmt->paramLengths[param_index] = 0;
870 preparedStmt->paramFormats[param_index] = 0;
871 } /* if */
872 return err_info;
873 } /* setupParameterColumn */
874
875
876
setupParameters(PGresult * describe_result,preparedStmtType preparedStmt)877 static errInfoType setupParameters (PGresult *describe_result, preparedStmtType preparedStmt)
878
879 {
880 int num_params;
881 int param_index;
882 errInfoType err_info = OKAY_NO_ERROR;
883
884 /* setupParameters */
885 logFunction(printf("setupParameters\n"););
886 num_params = PQnparams(describe_result);
887 if (unlikely(num_params < 0)) {
888 dbInconsistent("setupParameters", "PQnparams");
889 logError(printf("setupParameters: PQnparams returns negative number: %d\n",
890 num_params););
891 err_info = DATABASE_ERROR;
892 } else if (num_params == 0) {
893 /* malloc(0) may return NULL, which would wrongly trigger a MEMORY_ERROR. */
894 preparedStmt->param_array_size = 0;
895 preparedStmt->param_array = NULL;
896 preparedStmt->paramTypes = NULL;
897 preparedStmt->paramValues = NULL;
898 preparedStmt->paramLengths = NULL;
899 preparedStmt->paramFormats = NULL;
900 } else {
901 preparedStmt->param_array_size = (memSizeType) num_params;
902 if (unlikely(
903 !ALLOC_TABLE(preparedStmt->param_array, bindDataRecord, preparedStmt->param_array_size) ||
904 !ALLOC_TABLE(preparedStmt->paramTypes, Oid, preparedStmt->param_array_size) ||
905 !ALLOC_TABLE(preparedStmt->paramValues, cstriType, preparedStmt->param_array_size) ||
906 !ALLOC_TABLE(preparedStmt->paramLengths, int, preparedStmt->param_array_size) ||
907 !ALLOC_TABLE(preparedStmt->paramFormats, int, preparedStmt->param_array_size))) {
908 if (preparedStmt->param_array != NULL) {
909 FREE_TABLE(preparedStmt->param_array, bindDataRecord, preparedStmt->param_array_size);
910 } /* if */
911 if (preparedStmt->paramTypes != NULL) {
912 FREE_TABLE(preparedStmt->paramTypes, Oid, preparedStmt->param_array_size);
913 } /* if */
914 if (preparedStmt->paramValues != NULL) {
915 FREE_TABLE(preparedStmt->paramValues, cstriType, preparedStmt->param_array_size);
916 } /* if */
917 if (preparedStmt->paramLengths != NULL) {
918 FREE_TABLE(preparedStmt->paramLengths, int, preparedStmt->param_array_size);
919 } /* if */
920 if (preparedStmt->paramFormats != NULL) {
921 FREE_TABLE(preparedStmt->paramFormats, int, preparedStmt->param_array_size);
922 } /* if */
923 preparedStmt->param_array_size = 0;
924 preparedStmt->param_array = NULL;
925 preparedStmt->paramTypes = NULL;
926 preparedStmt->paramValues = NULL;
927 preparedStmt->paramLengths = NULL;
928 preparedStmt->paramFormats = NULL;
929 err_info = MEMORY_ERROR;
930 } else {
931 memset(preparedStmt->param_array, 0,
932 (memSizeType) num_params * sizeof(bindDataRecord));
933 for (param_index = 0; param_index < num_params &&
934 err_info == OKAY_NO_ERROR; param_index++) {
935 preparedStmt->paramTypes[param_index] = PQparamtype(describe_result, param_index);
936 /* printf("paramType: %s\n",
937 nameOfBufferType(preparedStmt->paramTypes[param_index])); */
938 err_info = setupParameterColumn(preparedStmt, param_index,
939 &preparedStmt->param_array[param_index]);
940 } /* if */
941 } /* if */
942 } /* if */
943 logFunction(printf("setupParameters --> %d\n", err_info););
944 return err_info;
945 } /* setupParameters */
946
947
948
setupResult(PGresult * describe_result,preparedStmtType preparedStmt)949 static errInfoType setupResult (PGresult *describe_result, preparedStmtType preparedStmt)
950
951 {
952 int num_columns;
953 /* int column_index; */
954 errInfoType err_info = OKAY_NO_ERROR;
955
956 /* setupResult */
957 logFunction(printf("setupResult\n"););
958 num_columns = PQnfields(describe_result);
959 if (num_columns < 0) {
960 dbInconsistent("setupResult", "PQnfields");
961 logError(printf("setupResult: PQnfields returns negative number: %d\n",
962 num_columns););
963 err_info = DATABASE_ERROR;
964 } else {
965 preparedStmt->result_column_count = (memSizeType) num_columns;
966 /* for (column_index = 0; column_index < num_columns &&
967 err_info == OKAY_NO_ERROR; column_index++) {
968 printf("Column %d name: %s\n", column_index + 1, PQfname(describe_result, column_index));
969 printf("Column %d type: %d\n", column_index + 1, PQftype(describe_result, column_index));
970 } */
971 } /* if */
972 logFunction(printf("setupResult --> %d\n", err_info););
973 return err_info;
974 } /* setupResult */
975
976
977
setupParametersAndResult(preparedStmtType preparedStmt)978 static errInfoType setupParametersAndResult (preparedStmtType preparedStmt)
979
980 {
981 PGresult *describe_result;
982 errInfoType err_info = OKAY_NO_ERROR;
983
984 /* setupParametersAndResult */
985 logFunction(printf("setupParametersAndResult\n"););
986 describe_result = PQdescribePrepared(preparedStmt->db->connection, preparedStmt->stmtName);
987 if (unlikely(describe_result == NULL)) {
988 err_info = MEMORY_ERROR;
989 } else {
990 if (PQresultStatus(describe_result) != PGRES_COMMAND_OK) {
991 setDbErrorMsg("setupParametersAndResult", "PQdescribePrepared", preparedStmt->db->connection);
992 logError(printf("setupParametersAndResult: PQdescribePrepared returns a status of %s:\n%s",
993 PQresStatus(PQresultStatus(describe_result)),
994 dbError.message););
995 err_info = DATABASE_ERROR;
996 } else {
997 err_info = setupParameters(describe_result, preparedStmt);
998 if (likely(err_info == OKAY_NO_ERROR)) {
999 err_info = setupResult(describe_result, preparedStmt);
1000 } /* if */
1001 } /* if */
1002 PQclear(describe_result);
1003 } /* if */
1004 logFunction(printf("setupParametersAndResult --> %d\n", err_info););
1005 return err_info;
1006 } /* setupParametersAndResult */
1007
1008
1009
allParametersBound(preparedStmtType preparedStmt)1010 static boolType allParametersBound (preparedStmtType preparedStmt)
1011
1012 {
1013 memSizeType column_index;
1014 boolType okay = TRUE;
1015
1016 /* allParametersBound */
1017 for (column_index = 0; column_index < preparedStmt->param_array_size;
1018 column_index++) {
1019 if (unlikely(!preparedStmt->param_array[column_index].bound)) {
1020 logError(printf("sqlExecute: Unbound parameter " FMT_U_MEM ".\n",
1021 column_index + 1););
1022 okay = FALSE;
1023 } /* if */
1024 } /* for */
1025 return okay;
1026 } /* allParametersBound */
1027
1028
1029
1030 #if LOG_FUNCTIONS_EVERYWHERE || LOG_FUNCTIONS || VERBOSE_EXCEPTIONS_EVERYWHERE || VERBOSE_EXCEPTIONS
dumpNumeric(const unsigned char * buffer)1031 static void dumpNumeric (const unsigned char *buffer)
1032
1033 {
1034 numeric numStruct;
1035 int idx;
1036
1037 /* dumpNumeric */
1038 printf("NUMERICOID: %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
1039 buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],
1040 buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[15], buffer[15]);
1041 numStruct.ndigits = 256 * buffer[0] + buffer[1];
1042 numStruct.weight = (int16Type) (buffer[2] << 8 | buffer[3]);
1043 numStruct.rscale = 256 * (buffer[4] & 0x3f) + buffer[5];
1044 numStruct.dscale = 256 * (buffer[6] & 0x3f) + buffer[7];
1045 numStruct.sign = (buffer[4] & 0x40) != 0;
1046
1047 printf("ndigits: %d\n", numStruct.ndigits);
1048 printf("weight: %d\n", numStruct.weight);
1049 printf("rscale: %d\n", numStruct.rscale);
1050 printf("dscale: %d\n", numStruct.dscale);
1051 printf("sign: %d\n", numStruct.sign);
1052
1053 for (idx = 0; idx < numStruct.ndigits; idx++) {
1054 printf("digit %d: %u\n", idx, 256 * buffer[8 + 2 * idx] + buffer[9 + 2 * idx]);
1055 }
1056 } /* dumpNumeric */
1057 #endif
1058
1059
1060
getNumericAsCStri(numeric * numStruct)1061 static cstriType getNumericAsCStri (numeric *numStruct)
1062
1063 {
1064 unsigned int length;
1065 unsigned int idx;
1066 unsigned int fourDigits;
1067 unsigned int digitNum;
1068 unsigned int scale;
1069 cstriType decimal;
1070
1071 /* getNumericAsCStri */
1072 if (numStruct->weight < numStruct->ndigits - 1) {
1073 scale = 4 * (unsigned int) (numStruct->ndigits - 1 - numStruct->weight);
1074 /* printf("getNumericAsCStri: 1 scale: %d\n", scale); */
1075 /* Provide space for sign, decimal point and a possible leading zero. */
1076 if (likely(ALLOC_CSTRI(decimal, 4 * (memSizeType) numStruct->ndigits + 3 + scale))) {
1077 length = 4 * (unsigned int) numStruct->ndigits + 1;
1078 /* printf("length: %u\n", length); */
1079 decimal[0] = numStruct->sign ? '-' : '+';
1080 for (idx = 0; idx < numStruct->ndigits; idx++) {
1081 fourDigits = 256 * (unsigned int) numStruct->digits[2 * idx] +
1082 (unsigned int) numStruct->digits[2 * idx + 1];
1083 for (digitNum = 4; digitNum >= 1; digitNum--) {
1084 decimal[4 * idx + digitNum] = (char) (fourDigits % 10 + '0');
1085 fourDigits /= 10;
1086 } /* for */
1087 } /* for */
1088 if (scale >= length - 1) {
1089 memmove(&decimal[scale - length + 4], &decimal[1], length - 1);
1090 decimal[1] = '0';
1091 decimal[2] = '.';
1092 memset(&decimal[3], '0', scale - length + 1);
1093 decimal[scale + 3] = '\0';
1094 } else {
1095 memmove(&decimal[length - scale + 1], &decimal[length - scale], scale);
1096 decimal[length - scale] = '.';
1097 decimal[length + 1] = '\0';
1098 } /* if */
1099 } /* if */
1100 } else {
1101 scale = 4 * (unsigned int) (numStruct->weight - (numStruct->ndigits - 1));
1102 /* printf("getNumericAsCStri: 2 scale: %d\n", scale); */
1103 /* Provide space for sign, decimal point and a possible trailing zero. */
1104 if (likely(ALLOC_CSTRI(decimal, 4 * (memSizeType) numStruct->ndigits + 3 + scale))) {
1105 length = 4 * (unsigned int) numStruct->ndigits + 1;
1106 /* printf("length: %u\n", length); */
1107 decimal[0] = numStruct->sign ? '-' : '+';
1108 for (idx = 0; idx < numStruct->ndigits; idx++) {
1109 fourDigits = 256 * (unsigned int) numStruct->digits[2 * idx] +
1110 (unsigned int) numStruct->digits[2 * idx + 1];
1111 for (digitNum = 4; digitNum >= 1; digitNum--) {
1112 decimal[4 * idx + digitNum] = (char) (fourDigits % 10 + '0');
1113 fourDigits /= 10;
1114 } /* for */
1115 } /* for */
1116 memset(&decimal[length], '0', scale);
1117 decimal[length + scale] = '.';
1118 decimal[length + scale + 1] = '0';
1119 decimal[length + scale + 2] = '\0';
1120 } /* if */
1121 } /* if */
1122 logFunction(printf("getNumericAsCStri --> %s\n",
1123 decimal != NULL ? decimal : "NULL"));
1124 return decimal;
1125 } /* getNumericAsCStri */
1126
1127
1128
getNumericAsStri(numeric * numStruct)1129 static striType getNumericAsStri (numeric *numStruct)
1130
1131 {
1132 unsigned int idx;
1133 unsigned int fourDigits;
1134 unsigned int digitNum;
1135 striType stri;
1136
1137 /* getNumericAsStri */
1138 /* Provide space for sign. */
1139 if (likely(ALLOC_STRI_SIZE_OK(stri, 4 * (memSizeType) numStruct->ndigits + 1))) {
1140 stri->size = 4 * (memSizeType) numStruct->ndigits + 1;
1141 stri->mem[0] = numStruct->sign ? '-' : '+';
1142 for (idx = 0; idx < numStruct->ndigits; idx++) {
1143 fourDigits = 256 * (unsigned int) numStruct->digits[2 * idx] +
1144 (unsigned int) numStruct->digits[2 * idx + 1];
1145 for (digitNum = 4; digitNum >= 1; digitNum--) {
1146 stri->mem[4 * idx + digitNum] = (strElemType) (fourDigits % 10 + '0');
1147 fourDigits /= 10;
1148 } /* for */
1149 } /* for */
1150 } /* if */
1151 logFunction(printf("getNumericAsStri --> %s\n",
1152 striAsUnquotedCStri(stri)));
1153 return stri;
1154 } /* getNumericAsStri */
1155
1156
1157
getNumericAsInt(const unsigned char * buffer)1158 static intType getNumericAsInt (const unsigned char *buffer)
1159
1160 {
1161 numeric numStruct;
1162 striType stri;
1163 intType factor;
1164 intType intValue;
1165
1166 /* getNumericAsInt */
1167 logFunction(printf("getNumericAsInt()\n");
1168 /* dumpNumeric(buffer); */);
1169 numStruct.ndigits = 256 * buffer[0] + buffer[1];
1170 numStruct.weight = (int16Type) (buffer[2] << 8 | buffer[3]);
1171 numStruct.rscale = 256 * (buffer[4] & 0x3f) + buffer[5];
1172 numStruct.dscale = 256 * (buffer[6] & 0x3f) + buffer[7];
1173 numStruct.sign = (buffer[4] & 0x40) != 0;
1174 numStruct.digits = &buffer[8];
1175 if (numStruct.ndigits == 0) {
1176 intValue = 0;
1177 } else if (unlikely(numStruct.weight < numStruct.ndigits - 1 ||
1178 numStruct.rscale != 0 ||
1179 numStruct.dscale != 0)) {
1180 logError(printf("getNumericAsInt: Number not integer\n"););
1181 raise_error(RANGE_ERROR);
1182 intValue = 0;
1183 } else if (unlikely((stri = getNumericAsStri(&numStruct)) == NULL)) {
1184 raise_error(MEMORY_ERROR);
1185 intValue = 0;
1186 } else {
1187 intValue = intParse(stri);
1188 strDestr(stri);
1189 if (intValue != 0 && numStruct.weight != numStruct.ndigits - 1) {
1190 switch (4 * (numStruct.weight - (numStruct.ndigits - 1))) {
1191 case 0: factor = 1; break;
1192 case 4: factor = 10000; break;
1193 case 8: factor = 100000000; break;
1194 case 12: factor = 1000000000000; break;
1195 case 16: factor = 10000000000000000; break;
1196 default:
1197 logError(printf("getNumericAsInt: Wrong decimal scale: %d\n",
1198 4 * (numStruct.weight - (numStruct.ndigits - 1))););
1199 raise_error(RANGE_ERROR);
1200 factor = 1;
1201 break;
1202 } /* switch */
1203 if (intValue < 0) {
1204 if (unlikely(intValue < INTTYPE_MIN / factor)) {
1205 logError(printf("getNumericAsInt: Value (" FMT_D
1206 ") smaller than minimum (" FMT_D ").\n",
1207 intValue, INTTYPE_MIN / factor));
1208 raise_error(RANGE_ERROR);
1209 factor = 1;
1210 } /* if */
1211 } else {
1212 if (unlikely(intValue > INTTYPE_MAX / factor)) {
1213 logError(printf("getNumericAsInt: Value (" FMT_D
1214 ") larger than maximum (" FMT_D ").\n",
1215 intValue, INTTYPE_MAX / factor));
1216 raise_error(RANGE_ERROR);
1217 factor = 1;
1218 } /* if */
1219 } /* if */
1220 intValue *= factor;
1221 } /* if */
1222 } /* if */
1223 logFunction(printf("getNumericAsInt --> " FMT_D "\n", intValue););
1224 return intValue;
1225 } /* getNumericAsInt */
1226
1227
1228
getNumericAsBigInt(const unsigned char * buffer)1229 static bigIntType getNumericAsBigInt (const unsigned char *buffer)
1230
1231 {
1232 numeric numStruct;
1233 striType stri;
1234 bigIntType powerOfTen;
1235 bigIntType bigIntValue;
1236
1237 /* getNumericAsBigInt */
1238 logFunction(printf("getNumericAsBigInt()\n");
1239 /* dumpNumeric(buffer); */);
1240 numStruct.ndigits = 256 * buffer[0] + buffer[1];
1241 numStruct.weight = (int16Type) (buffer[2] << 8 | buffer[3]);
1242 numStruct.rscale = 256 * (buffer[4] & 0x3f) + buffer[5];
1243 numStruct.dscale = 256 * (buffer[6] & 0x3f) + buffer[7];
1244 numStruct.sign = (buffer[4] & 0x40) != 0;
1245 numStruct.digits = &buffer[8];
1246 if (numStruct.ndigits == 0) {
1247 bigIntValue = bigZero();
1248 } else if (unlikely(numStruct.weight < numStruct.ndigits - 1 ||
1249 numStruct.rscale != 0 ||
1250 numStruct.dscale != 0)) {
1251 logError(printf("getNumericAsBigInt: Number not integer\n"););
1252 raise_error(RANGE_ERROR);
1253 bigIntValue = NULL;
1254 } else if (unlikely((stri = getNumericAsStri(&numStruct)) == NULL)) {
1255 raise_error(MEMORY_ERROR);
1256 bigIntValue = NULL;
1257 } else {
1258 bigIntValue = bigParse(stri);
1259 strDestr(stri);
1260 if (bigIntValue != NULL && numStruct.weight != numStruct.ndigits - 1) {
1261 powerOfTen = bigIPowSignedDigit(10,
1262 (intType) (4 * (numStruct.weight - (numStruct.ndigits - 1))));
1263 if (powerOfTen != NULL) {
1264 bigMultAssign(&bigIntValue, powerOfTen);
1265 bigDestr(powerOfTen);
1266 } /* if */
1267 } /* if */
1268 } /* if */
1269 logFunction(printf("getNumericAsBigInt --> %s\n",
1270 bigHexCStri(bigIntValue)););
1271 return bigIntValue;
1272 } /* getNumericAsBigInt */
1273
1274
1275
getNumericAsBigRat(const unsigned char * buffer,bigIntType * denominator)1276 static bigIntType getNumericAsBigRat (const unsigned char *buffer,
1277 bigIntType *denominator)
1278
1279 {
1280 numeric numStruct;
1281 striType stri;
1282 bigIntType powerOfTen;
1283 bigIntType numerator;
1284
1285 /* getNumericAsBigRat */
1286 logFunction(printf("getNumericAsBigRat()\n");
1287 /* dumpNumeric(buffer); */);
1288 numStruct.ndigits = 256 * buffer[0] + buffer[1];
1289 numStruct.weight = (int16Type) (buffer[2] << 8 | buffer[3]);
1290 numStruct.rscale = 256 * (buffer[4] & 0x3f) + buffer[5];
1291 numStruct.dscale = 256 * (buffer[6] & 0x3f) + buffer[7];
1292 numStruct.sign = (buffer[4] & 0x40) != 0;
1293 numStruct.digits = &buffer[8];
1294 if (numStruct.ndigits == 0) {
1295 numerator = bigZero();
1296 *denominator = bigFromInt32(1);
1297 } else if (unlikely((stri = getNumericAsStri(&numStruct)) == NULL)) {
1298 raise_error(MEMORY_ERROR);
1299 numerator = NULL;
1300 } else {
1301 numerator = bigParse(stri);
1302 strDestr(stri);
1303 if (numerator != NULL) {
1304 if (numStruct.weight >= numStruct.ndigits - 1) {
1305 if (numStruct.weight != numStruct.ndigits - 1) {
1306 powerOfTen = bigIPowSignedDigit(10,
1307 (intType) (4 * (numStruct.weight - (numStruct.ndigits - 1))));
1308 if (powerOfTen != NULL) {
1309 bigMultAssign(&numerator, powerOfTen);
1310 bigDestr(powerOfTen);
1311 } /* if */
1312 } /* if */
1313 *denominator = bigFromInt32(1);
1314 } else {
1315 *denominator = bigIPowSignedDigit(10,
1316 (intType) (4 * (numStruct.ndigits - 1 - numStruct.weight)));
1317 } /* if */
1318 } /* if */
1319 } /* if */
1320 logFunction(printf("getNumericAsBigRat --> %s",
1321 striAsUnquotedCStri(bigStr(numerator)));
1322 printf(" (denominator = %s)\n",
1323 striAsUnquotedCStri(bigStr(*denominator))););
1324 return numerator;
1325 } /* getNumericAsBigRat */
1326
1327
1328
getNumericAsFloat(const unsigned char * buffer)1329 static floatType getNumericAsFloat (const unsigned char *buffer)
1330
1331 {
1332 numeric numStruct;
1333 cstriType decimal;
1334 floatType floatValue;
1335
1336 /* getNumericAsFloat */
1337 logFunction(printf("getNumericAsFloat()\n");
1338 /* dumpNumeric(buffer); */);
1339 numStruct.ndigits = 256 * buffer[0] + buffer[1];
1340 numStruct.weight = (int16Type) (buffer[2] << 8 | buffer[3]);
1341 numStruct.rscale = 256 * (buffer[4] & 0x3f) + buffer[5];
1342 numStruct.dscale = 256 * (buffer[6] & 0x3f) + buffer[7];
1343 numStruct.sign = (buffer[4] & 0x40) != 0;
1344 numStruct.digits = &buffer[8];
1345 if (numStruct.ndigits == 0) {
1346 floatValue = 0.0;
1347 } else if (unlikely((decimal = getNumericAsCStri(&numStruct)) == NULL)) {
1348 raise_error(MEMORY_ERROR);
1349 floatValue = 0.0;
1350 } else {
1351 floatValue = (floatType) strtod(decimal, NULL);
1352 UNALLOC_CSTRI(decimal, strlen(decimal));
1353 } /* if */
1354 logFunction(printf("getNumericAsFloat --> " FMT_E "\n", floatValue););
1355 return floatValue;
1356 } /* getNumericAsFloat */
1357
1358
1359
getTimestamp1970(timeStampType timestamp,intType * micro_second)1360 static timeStampType getTimestamp1970 (timeStampType timestamp,
1361 intType *micro_second)
1362
1363 { /* getTimestamp1970 */
1364 logFunction(printf("getTimestamp1970(" FMT_D64 ")\n", timestamp););
1365 *micro_second = timestamp % 1000000;
1366 if (timestamp < 0) {
1367 if (*micro_second != 0) {
1368 *micro_second += 1000000;
1369 } /* if */
1370 timestamp = (timestamp + 1) / 1000000 - 1;
1371 } else {
1372 timestamp /= 1000000;
1373 } /* if */
1374 /* printf("timestamp2000: " FMT_U64 "\n", timestamp); */
1375 if (unlikely(timestamp > INT64TYPE_MAX - SECONDS_FROM_1970_TO_2000)) {
1376 logError(printf("getTimestamp1970: "
1377 "Cannot compute timestamp1970 from timestamp2000 (" FMT_D64 ").\n",
1378 timestamp););
1379 raise_error(RANGE_ERROR);
1380 } else {
1381 timestamp += SECONDS_FROM_1970_TO_2000;
1382 } /* if */
1383 logFunction(printf("getTimestamp1970 --> " FMT_D64 "\n", timestamp););
1384 return timestamp;
1385 } /* getTimestamp1970 */
1386
1387
1388
sqlBindBigInt(sqlStmtType sqlStatement,intType pos,const const_bigIntType value)1389 static void sqlBindBigInt (sqlStmtType sqlStatement, intType pos,
1390 const const_bigIntType value)
1391
1392 {
1393 preparedStmtType preparedStmt;
1394 bindDataType param;
1395 cstriType decimalNumber;
1396 memSizeType length;
1397 errInfoType err_info = OKAY_NO_ERROR;
1398
1399 /* sqlBindBigInt */
1400 logFunction(printf("sqlBindBigInt(" FMT_U_MEM ", " FMT_D ", %s)\n",
1401 (memSizeType) sqlStatement, pos, bigHexCStri(value)););
1402 preparedStmt = (preparedStmtType) sqlStatement;
1403 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1404 logError(printf("sqlBindBigInt: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1405 pos, preparedStmt->param_array_size););
1406 raise_error(RANGE_ERROR);
1407 } else {
1408 param = &preparedStmt->param_array[pos - 1];
1409 /* printf("paramType: %s\n",
1410 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1411 switch (preparedStmt->paramTypes[pos - 1]) {
1412 case INT2OID:
1413 preparedStmt->paramValues[pos - 1] = param->buffer;
1414 *(int16Type *) param->buffer =
1415 (int16Type) htons((uint16Type) bigToInt16(value, &err_info));
1416 break;
1417 case INT4OID:
1418 preparedStmt->paramValues[pos - 1] = param->buffer;
1419 *(int32Type *) param->buffer =
1420 (int32Type) htonl((uint32Type) bigToInt32(value, &err_info));
1421 break;
1422 case INT8OID:
1423 preparedStmt->paramValues[pos - 1] = param->buffer;
1424 *(int64Type *) param->buffer =
1425 (int64Type) htonll((uint64Type) bigToInt64(value, &err_info));
1426 break;
1427 case FLOAT4OID:
1428 preparedStmt->paramValues[pos - 1] = param->buffer;
1429 *(float *) param->buffer =
1430 htonf((float) bigIntToDouble(value));
1431 break;
1432 case FLOAT8OID:
1433 preparedStmt->paramValues[pos - 1] = param->buffer;
1434 *(double *) param->buffer =
1435 htond(bigIntToDouble(value));
1436 break;
1437 case NUMERICOID:
1438 case BPCHAROID:
1439 case VARCHAROID:
1440 decimalNumber = (cstriType) bigIntToDecimal(value, &length, &err_info);
1441 if (likely(decimalNumber != NULL)) {
1442 if (unlikely(length > INT_MAX)) {
1443 /* It is not possible to cast length to int. */
1444 free(decimalNumber);
1445 err_info = MEMORY_ERROR;
1446 } else {
1447 free(param->buffer);
1448 param->buffer = decimalNumber;
1449 preparedStmt->paramValues[pos - 1] = decimalNumber;
1450 preparedStmt->paramLengths[pos - 1] = (int) length;
1451 preparedStmt->paramFormats[pos - 1] = 0;
1452 } /* if */
1453 } /* if */
1454 break;
1455 default:
1456 logError(printf("sqlBindBigInt: Parameter " FMT_D " has the unknown type %s.\n",
1457 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1458 err_info = RANGE_ERROR;
1459 break;
1460 } /* switch */
1461 if (unlikely(err_info != OKAY_NO_ERROR)) {
1462 raise_error(err_info);
1463 } else {
1464 preparedStmt->executeSuccessful = FALSE;
1465 preparedStmt->fetchOkay = FALSE;
1466 param->bound = TRUE;
1467 } /* if */
1468 } /* if */
1469 } /* sqlBindBigInt */
1470
1471
1472
sqlBindBigRat(sqlStmtType sqlStatement,intType pos,const const_bigIntType numerator,const const_bigIntType denominator)1473 static void sqlBindBigRat (sqlStmtType sqlStatement, intType pos,
1474 const const_bigIntType numerator, const const_bigIntType denominator)
1475
1476 {
1477 preparedStmtType preparedStmt;
1478 bindDataType param;
1479 cstriType decimalNumber;
1480 memSizeType length;
1481 errInfoType err_info = OKAY_NO_ERROR;
1482
1483 /* sqlBindBigRat */
1484 logFunction(printf("sqlBindBigRat(" FMT_U_MEM ", " FMT_D ", %s, %s)\n",
1485 (memSizeType) sqlStatement, pos,
1486 bigHexCStri(numerator), bigHexCStri(denominator)););
1487 preparedStmt = (preparedStmtType) sqlStatement;
1488 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1489 logError(printf("sqlBindBigRat: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1490 pos, preparedStmt->param_array_size););
1491 raise_error(RANGE_ERROR);
1492 } else {
1493 param = &preparedStmt->param_array[pos - 1];
1494 /* printf("paramType: %s\n",
1495 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1496 switch (preparedStmt->paramTypes[pos - 1]) {
1497 case FLOAT4OID:
1498 preparedStmt->paramValues[pos - 1] = param->buffer;
1499 *(float *) param->buffer =
1500 htonf((float) bigRatToDouble(numerator, denominator));
1501 break;
1502 case FLOAT8OID:
1503 preparedStmt->paramValues[pos - 1] = param->buffer;
1504 *(double *) param->buffer =
1505 htond(bigRatToDouble(numerator, denominator));
1506 break;
1507 case NUMERICOID:
1508 decimalNumber = (cstriType) bigRatToDecimal(numerator, denominator,
1509 DEFAULT_DECIMAL_SCALE, &length, &err_info);
1510 if (likely(decimalNumber != NULL)) {
1511 if (unlikely(length > INT_MAX)) {
1512 /* It is not possible to cast length to int. */
1513 free(decimalNumber);
1514 err_info = MEMORY_ERROR;
1515 } else {
1516 free(param->buffer);
1517 param->buffer = decimalNumber;
1518 preparedStmt->paramValues[pos - 1] = decimalNumber;
1519 preparedStmt->paramLengths[pos - 1] = (int) length;
1520 preparedStmt->paramFormats[pos - 1] = 0;
1521 } /* if */
1522 } /* if */
1523 break;
1524 default:
1525 logError(printf("sqlBindBigRat: Parameter " FMT_D " has the unknown type %s.\n",
1526 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1527 err_info = RANGE_ERROR;
1528 break;
1529 } /* switch */
1530 if (unlikely(err_info != OKAY_NO_ERROR)) {
1531 raise_error(err_info);
1532 } else {
1533 preparedStmt->executeSuccessful = FALSE;
1534 preparedStmt->fetchOkay = FALSE;
1535 param->bound = TRUE;
1536 } /* if */
1537 } /* if */
1538 } /* sqlBindBigRat */
1539
1540
1541
sqlBindBool(sqlStmtType sqlStatement,intType pos,boolType value)1542 static void sqlBindBool (sqlStmtType sqlStatement, intType pos, boolType value)
1543
1544 {
1545 preparedStmtType preparedStmt;
1546 bindDataType param;
1547 errInfoType err_info = OKAY_NO_ERROR;
1548
1549 /* sqlBindBool */
1550 logFunction(printf("sqlBindBool(" FMT_U_MEM ", " FMT_D ", %s)\n",
1551 (memSizeType) sqlStatement, pos, value ? "TRUE" : "FALSE"););
1552 preparedStmt = (preparedStmtType) sqlStatement;
1553 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1554 logError(printf("sqlBindBool: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1555 pos, preparedStmt->param_array_size););
1556 raise_error(RANGE_ERROR);
1557 } else {
1558 param = &preparedStmt->param_array[pos - 1];
1559 /* printf("paramType: %s\n",
1560 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1561 switch (preparedStmt->paramTypes[pos - 1]) {
1562 case INT2OID:
1563 preparedStmt->paramValues[pos - 1] = param->buffer;
1564 *(int16Type *) param->buffer =
1565 (int16Type) htons((uint16Type) value);
1566 break;
1567 case INT4OID:
1568 preparedStmt->paramValues[pos - 1] = param->buffer;
1569 *(int32Type *) param->buffer =
1570 (int32Type) htonl((uint32Type) value);
1571 break;
1572 case INT8OID:
1573 preparedStmt->paramValues[pos - 1] = param->buffer;
1574 *(int64Type *) param->buffer =
1575 (int64Type) htonll((uint64Type) value);
1576 break;
1577 case NUMERICOID:
1578 case BPCHAROID:
1579 case VARCHAROID:
1580 free(param->buffer);
1581 if (unlikely((param->buffer = (cstriType) malloc(2)) == NULL)) {
1582 err_info = MEMORY_ERROR;
1583 } else {
1584 preparedStmt->paramValues[pos - 1] = param->buffer;
1585 param->buffer[0] = (char) ('0' + value);
1586 param->buffer[1] = '\0';
1587 preparedStmt->paramLengths[pos - 1] = 1;
1588 preparedStmt->paramFormats[pos - 1] = 0;
1589 } /* if */
1590 break;
1591 default:
1592 logError(printf("sqlBindBool: Parameter " FMT_D " has the unknown type %s.\n",
1593 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1594 err_info = RANGE_ERROR;
1595 break;
1596 } /* switch */
1597 if (unlikely(err_info != OKAY_NO_ERROR)) {
1598 raise_error(err_info);
1599 } else {
1600 preparedStmt->executeSuccessful = FALSE;
1601 preparedStmt->fetchOkay = FALSE;
1602 param->bound = TRUE;
1603 } /* if */
1604 } /* if */
1605 } /* sqlBindBool */
1606
1607
1608
sqlBindBStri(sqlStmtType sqlStatement,intType pos,const const_bstriType bstri)1609 static void sqlBindBStri (sqlStmtType sqlStatement, intType pos,
1610 const const_bstriType bstri)
1611
1612 {
1613 preparedStmtType preparedStmt;
1614 bindDataType param;
1615 errInfoType err_info = OKAY_NO_ERROR;
1616
1617 /* sqlBindBStri */
1618 logFunction(printf("sqlBindBStri(" FMT_U_MEM ", " FMT_D ", \"%s\")\n",
1619 (memSizeType) sqlStatement, pos, bstriAsUnquotedCStri(bstri)););
1620 preparedStmt = (preparedStmtType) sqlStatement;
1621 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1622 logError(printf("sqlBindBStri: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1623 pos, preparedStmt->param_array_size););
1624 raise_error(RANGE_ERROR);
1625 } else {
1626 param = &preparedStmt->param_array[pos - 1];
1627 /* printf("paramType: %s\n",
1628 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1629 switch (preparedStmt->paramTypes[pos - 1]) {
1630 case BYTEAOID:
1631 case BPCHAROID:
1632 case VARCHAROID:
1633 if (unlikely(bstri->size > INT_MAX)) {
1634 /* It is not possible to cast bstri->size to int. */
1635 err_info = MEMORY_ERROR;
1636 } else {
1637 free(param->buffer);
1638 if (unlikely((param->buffer = (cstriType) malloc(
1639 bstri->size + NULL_TERMINATION_LEN)) == NULL)) {
1640 err_info = MEMORY_ERROR;
1641 } else {
1642 preparedStmt->paramValues[pos - 1] = param->buffer;
1643 memcpy(param->buffer, bstri->mem, bstri->size);
1644 param->buffer[bstri->size] = '\0';
1645 preparedStmt->paramLengths[pos - 1] = (int) bstri->size;
1646 preparedStmt->paramFormats[pos - 1] = 1;
1647 } /* if */
1648 } /* if */
1649 break;
1650 default:
1651 logError(printf("sqlBindBStri: Parameter " FMT_D " has the unknown type %s.\n",
1652 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1653 err_info = RANGE_ERROR;
1654 break;
1655 } /* switch */
1656 if (unlikely(err_info != OKAY_NO_ERROR)) {
1657 raise_error(err_info);
1658 } else {
1659 preparedStmt->executeSuccessful = FALSE;
1660 preparedStmt->fetchOkay = FALSE;
1661 param->bound = TRUE;
1662 } /* if */
1663 } /* if */
1664 } /* sqlBindBStri */
1665
1666
1667
sqlBindDuration(sqlStmtType sqlStatement,intType pos,intType year,intType month,intType day,intType hour,intType minute,intType second,intType micro_second)1668 static void sqlBindDuration (sqlStmtType sqlStatement, intType pos,
1669 intType year, intType month, intType day, intType hour,
1670 intType minute, intType second, intType micro_second)
1671
1672 {
1673 preparedStmtType preparedStmt;
1674 bindDataType param;
1675 int64Type microsecDuration;
1676 errInfoType err_info = OKAY_NO_ERROR;
1677
1678 /* sqlBindDuration */
1679 logFunction(printf("sqlBindDuration(" FMT_U_MEM ", " FMT_D ", P"
1680 FMT_D "Y" FMT_D "M" FMT_D "DT"
1681 FMT_D "H" FMT_D "M%s" FMT_U "." F_U(06) "S)\n",
1682 (memSizeType) sqlStatement, pos,
1683 year, month, day, hour, minute,
1684 second < 0 || micro_second < 0 ? "-" : "",
1685 intAbs(second), intAbs(micro_second)););
1686 preparedStmt = (preparedStmtType) sqlStatement;
1687 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1688 logError(printf("sqlBindDuration: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1689 pos, preparedStmt->param_array_size););
1690 raise_error(RANGE_ERROR);
1691 } else if (unlikely(year < INT32TYPE_MIN || year > INT32TYPE_MAX || month < -12 || month > 12 ||
1692 day < -31 || day > 31 || hour <= -24 || hour >= 24 ||
1693 minute <= -60 || minute >= 60 || second <= -60 || second >= 60 ||
1694 micro_second <= -1000000 || micro_second >= 1000000)) {
1695 logError(printf("sqlBindDuration: Duration not in allowed range.\n"););
1696 raise_error(RANGE_ERROR);
1697 } else {
1698 param = &preparedStmt->param_array[pos - 1];
1699 /* printf("paramType: %s\n",
1700 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1701 switch (preparedStmt->paramTypes[pos - 1]) {
1702 case INTERVALOID:
1703 preparedStmt->paramValues[pos - 1] = param->buffer;
1704 microsecDuration = ((((int64Type) hour) * 60 +
1705 (int64Type) minute) * 60 +
1706 (int64Type) second) * 1000000 +
1707 (int64Type) micro_second;
1708 /* printf("microsecDuration: " FMT_D64 "\n", microsecDuration); */
1709 /* The interval is either an int64Type representing */
1710 /* microseconds, or a double representing seconds. */
1711 /* PQparameterStatus(connection, "integer_datetimes") is */
1712 /* used to determine if an int64Type or a double is used. */
1713 if (preparedStmt->integerDatetimes) {
1714 *(int64Type *) param->buffer =
1715 (int64Type) htonll((uint64Type) microsecDuration);
1716 } else {
1717 *(double *) param->buffer =
1718 htond((double) microsecDuration / 1000000.0);
1719 } /* if */
1720 *(int32Type *) ¶m->buffer[8] =
1721 (int32Type) htonl((uint32Type) day);
1722 *(int32Type *) ¶m->buffer[12] =
1723 (int32Type) htonl((uint32Type) (12 * year + month));
1724 break;
1725 default:
1726 logError(printf("sqlBindDuration: Parameter " FMT_D " has the unknown type %s.\n",
1727 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1728 err_info = RANGE_ERROR;
1729 break;
1730 } /* switch */
1731 if (unlikely(err_info != OKAY_NO_ERROR)) {
1732 raise_error(err_info);
1733 } else {
1734 preparedStmt->executeSuccessful = FALSE;
1735 preparedStmt->fetchOkay = FALSE;
1736 param->bound = TRUE;
1737 } /* if */
1738 } /* if */
1739 } /* sqlBindDuration */
1740
1741
1742
sqlBindFloat(sqlStmtType sqlStatement,intType pos,floatType value)1743 static void sqlBindFloat (sqlStmtType sqlStatement, intType pos, floatType value)
1744
1745 {
1746 preparedStmtType preparedStmt;
1747 bindDataType param;
1748 errInfoType err_info = OKAY_NO_ERROR;
1749
1750 /* sqlBindFloat */
1751 logFunction(printf("sqlBindFloat(" FMT_U_MEM ", " FMT_D ", " FMT_E ")\n",
1752 (memSizeType) sqlStatement, pos, value););
1753 preparedStmt = (preparedStmtType) sqlStatement;
1754 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1755 logError(printf("sqlBindFloat: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1756 pos, preparedStmt->param_array_size););
1757 raise_error(RANGE_ERROR);
1758 } else {
1759 param = &preparedStmt->param_array[pos - 1];
1760 /* printf("paramType: %s\n",
1761 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1762 switch (preparedStmt->paramTypes[pos - 1]) {
1763 case FLOAT4OID:
1764 preparedStmt->paramValues[pos - 1] = param->buffer;
1765 *(float *) param->buffer = htonf((float) value);
1766 break;
1767 case FLOAT8OID:
1768 preparedStmt->paramValues[pos - 1] = param->buffer;
1769 *(double *) param->buffer = htond(value);
1770 break;
1771 default:
1772 logError(printf("sqlBindFloat: Parameter " FMT_D " has the unknown type %s.\n",
1773 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1774 err_info = RANGE_ERROR;
1775 break;
1776 } /* switch */
1777 if (unlikely(err_info != OKAY_NO_ERROR)) {
1778 raise_error(err_info);
1779 } else {
1780 preparedStmt->executeSuccessful = FALSE;
1781 preparedStmt->fetchOkay = FALSE;
1782 param->bound = TRUE;
1783 } /* if */
1784 } /* if */
1785 } /* sqlBindFloat */
1786
1787
1788
sqlBindInt(sqlStmtType sqlStatement,intType pos,intType value)1789 static void sqlBindInt (sqlStmtType sqlStatement, intType pos, intType value)
1790
1791 {
1792 preparedStmtType preparedStmt;
1793 bindDataType param;
1794 errInfoType err_info = OKAY_NO_ERROR;
1795
1796 /* sqlBindInt */
1797 logFunction(printf("sqlBindInt(" FMT_U_MEM ", " FMT_D ", " FMT_D ")\n",
1798 (memSizeType) sqlStatement, pos, value););
1799 preparedStmt = (preparedStmtType) sqlStatement;
1800 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1801 logError(printf("sqlBindInt: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1802 pos, preparedStmt->param_array_size););
1803 raise_error(RANGE_ERROR);
1804 } else {
1805 param = &preparedStmt->param_array[pos - 1];
1806 /* printf("paramType: %s\n",
1807 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1808 switch (preparedStmt->paramTypes[pos - 1]) {
1809 case INT2OID:
1810 if (unlikely(value < INT16TYPE_MIN || value > INT16TYPE_MAX)) {
1811 logError(printf("sqlBindInt: Parameter " FMT_D ": "
1812 FMT_D " does not fit into a 16-bit integer.\n",
1813 pos, value));
1814 err_info = RANGE_ERROR;
1815 } else {
1816 preparedStmt->paramValues[pos - 1] = param->buffer;
1817 *(int16Type *) param->buffer =
1818 (int16Type) htons((uint16Type) value);
1819 } /* if */
1820 break;
1821 case INT4OID:
1822 if (unlikely(value < INT32TYPE_MIN || value > INT32TYPE_MAX)) {
1823 logError(printf("sqlBindInt: Parameter " FMT_D ": "
1824 FMT_D " does not fit into a 32-bit integer.\n",
1825 pos, value));
1826 err_info = RANGE_ERROR;
1827 } else {
1828 preparedStmt->paramValues[pos - 1] = param->buffer;
1829 *(int32Type *) param->buffer =
1830 (int32Type) htonl((uint32Type) value);
1831 } /* if */
1832 break;
1833 case INT8OID:
1834 preparedStmt->paramValues[pos - 1] = param->buffer;
1835 *(int64Type *) param->buffer =
1836 (int64Type) htonll((uint64Type) value);
1837 break;
1838 case FLOAT4OID:
1839 preparedStmt->paramValues[pos - 1] = param->buffer;
1840 *(float *) param->buffer = htonf((float) value);
1841 break;
1842 case FLOAT8OID:
1843 preparedStmt->paramValues[pos - 1] = param->buffer;
1844 *(double *) param->buffer = htond((double) value);
1845 break;
1846 case NUMERICOID:
1847 case BPCHAROID:
1848 case VARCHAROID:
1849 free(param->buffer);
1850 if (unlikely((param->buffer = (cstriType) malloc(
1851 INTTYPE_DECIMAL_SIZE + NULL_TERMINATION_LEN)) == NULL)) {
1852 err_info = MEMORY_ERROR;
1853 } else {
1854 preparedStmt->paramValues[pos - 1] = param->buffer;
1855 preparedStmt->paramLengths[pos - 1] =
1856 (int) sprintf(param->buffer, FMT_D, value);
1857 preparedStmt->paramFormats[pos - 1] = 0;
1858 } /* if */
1859 break;
1860 default:
1861 logError(printf("sqlBindInt: Parameter " FMT_D " has the unknown type %s.\n",
1862 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1863 err_info = RANGE_ERROR;
1864 break;
1865 } /* switch */
1866 if (unlikely(err_info != OKAY_NO_ERROR)) {
1867 raise_error(err_info);
1868 } else {
1869 preparedStmt->executeSuccessful = FALSE;
1870 preparedStmt->fetchOkay = FALSE;
1871 param->bound = TRUE;
1872 } /* if */
1873 } /* if */
1874 } /* sqlBindInt */
1875
1876
1877
sqlBindNull(sqlStmtType sqlStatement,intType pos)1878 static void sqlBindNull (sqlStmtType sqlStatement, intType pos)
1879
1880 {
1881 preparedStmtType preparedStmt;
1882
1883 /* sqlBindNull */
1884 logFunction(printf("sqlBindNull(" FMT_U_MEM ", " FMT_D ")\n",
1885 (memSizeType) sqlStatement, pos););
1886 preparedStmt = (preparedStmtType) sqlStatement;
1887 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1888 logError(printf("sqlBindNull: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1889 pos, preparedStmt->param_array_size););
1890 raise_error(RANGE_ERROR);
1891 } else {
1892 /* printf("paramType: %s\n",
1893 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1894 preparedStmt->paramValues[pos - 1] = NULL;
1895 preparedStmt->executeSuccessful = FALSE;
1896 preparedStmt->fetchOkay = FALSE;
1897 preparedStmt->param_array[pos - 1].bound = TRUE;
1898 } /* if */
1899 } /* sqlBindNull */
1900
1901
1902
sqlBindStri(sqlStmtType sqlStatement,intType pos,const const_striType stri)1903 static void sqlBindStri (sqlStmtType sqlStatement, intType pos,
1904 const const_striType stri)
1905
1906 {
1907 preparedStmtType preparedStmt;
1908 bindDataType param;
1909 cstriType stri8;
1910 cstriType resized_stri8;
1911 memSizeType length;
1912 cstriType cstri;
1913 errInfoType err_info = OKAY_NO_ERROR;
1914
1915 /* sqlBindStri */
1916 logFunction(printf("sqlBindStri(" FMT_U_MEM ", " FMT_D ", \"%s\")\n",
1917 (memSizeType) sqlStatement, pos, striAsUnquotedCStri(stri)););
1918 preparedStmt = (preparedStmtType) sqlStatement;
1919 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
1920 logError(printf("sqlBindStri: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
1921 pos, preparedStmt->param_array_size););
1922 raise_error(RANGE_ERROR);
1923 } else {
1924 param = &preparedStmt->param_array[pos - 1];
1925 /* printf("paramType: %s\n",
1926 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
1927 switch (preparedStmt->paramTypes[pos - 1]) {
1928 case BPCHAROID:
1929 case VARCHAROID:
1930 case TEXTOID:
1931 /* PostgreSQL doesn't support storing Null characters */
1932 /* ('\0;') in text fields. PQexecPrepared() returns a */
1933 /* status of PGRES_FATAL_ERROR, because 0x00 and 0xc080 */
1934 /* (the overlong UTF-8 encoding for the Null character) */
1935 /* are seen as invalid byte sequence for encoding "UTF8". */
1936 /* Therefore binding of strings with a Null character */
1937 /* ('\0;') inside will fail later with sqlExecute(). */
1938 stri8 = stri_to_cstri8_buf(stri, &length);
1939 if (unlikely(stri8 == NULL)) {
1940 err_info = MEMORY_ERROR;
1941 } else if (unlikely(length > INT_MAX)) {
1942 /* It is not possible to cast length to int. */
1943 free(stri8);
1944 err_info = MEMORY_ERROR;
1945 } else {
1946 resized_stri8 = REALLOC_CSTRI(stri8, length);
1947 if (likely(resized_stri8 != NULL)) {
1948 stri8 = resized_stri8;
1949 } /* if */
1950 free(param->buffer);
1951 param->buffer = stri8;
1952 preparedStmt->paramValues[pos - 1] = stri8;
1953 preparedStmt->paramLengths[pos - 1] = (int) length;
1954 preparedStmt->paramFormats[pos - 1] = 1;
1955 } /* if */
1956 break;
1957 case BYTEAOID:
1958 if (unlikely(stri->size > INT_MAX ||
1959 (cstri = (cstriType) malloc(stri->size)) == NULL)) {
1960 err_info = MEMORY_ERROR;
1961 } else if (unlikely(memcpy_from_strelem((ustriType) cstri,
1962 stri->mem, stri->size))) {
1963 free(cstri);
1964 err_info = RANGE_ERROR;
1965 } else {
1966 free(param->buffer);
1967 param->buffer = cstri;
1968 preparedStmt->paramValues[pos - 1] = cstri;
1969 preparedStmt->paramLengths[pos - 1] = (int) stri->size;
1970 preparedStmt->paramFormats[pos - 1] = 1;
1971 } /* if */
1972 break;
1973 default:
1974 logError(printf("sqlBindStri: Parameter " FMT_D " has the unknown type %s.\n",
1975 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
1976 err_info = RANGE_ERROR;
1977 break;
1978 } /* switch */
1979 if (unlikely(err_info != OKAY_NO_ERROR)) {
1980 raise_error(err_info);
1981 } else {
1982 preparedStmt->executeSuccessful = FALSE;
1983 preparedStmt->fetchOkay = FALSE;
1984 param->bound = TRUE;
1985 } /* if */
1986 } /* if */
1987 } /* sqlBindStri */
1988
1989
1990
sqlBindTime(sqlStmtType sqlStatement,intType pos,intType year,intType month,intType day,intType hour,intType minute,intType second,intType micro_second,intType time_zone)1991 static void sqlBindTime (sqlStmtType sqlStatement, intType pos,
1992 intType year, intType month, intType day, intType hour,
1993 intType minute, intType second, intType micro_second,
1994 intType time_zone)
1995
1996 {
1997 preparedStmtType preparedStmt;
1998 bindDataType param;
1999 timeStampType timestamp;
2000 int32Type zone;
2001 errInfoType err_info = OKAY_NO_ERROR;
2002
2003 /* sqlBindTime */
2004 logFunction(printf("sqlBindTime(" FMT_U_MEM ", " FMT_D ", "
2005 F_D(04) "-" F_D(02) "-" F_D(02) " "
2006 F_D(02) ":" F_D(02) ":" F_D(02) "." F_D(06) ", "
2007 FMT_D ")\n",
2008 (memSizeType) sqlStatement, pos,
2009 year, month, day,
2010 hour, minute, second, micro_second,
2011 time_zone););
2012 preparedStmt = (preparedStmtType) sqlStatement;
2013 if (unlikely(pos < 1 || (uintType) pos > preparedStmt->param_array_size)) {
2014 logError(printf("sqlBindTime: pos: " FMT_D ", max pos: " FMT_U_MEM ".\n",
2015 pos, preparedStmt->param_array_size););
2016 raise_error(RANGE_ERROR);
2017 } else if (unlikely(year <= INT16TYPE_MIN || year > INT16TYPE_MAX || month < 1 || month > 12 ||
2018 day < 1 || day > 31 || hour < 0 || hour >= 24 ||
2019 minute < 0 || minute >= 60 || second < 0 || second >= 60 ||
2020 micro_second < 0 || micro_second >= 1000000)) {
2021 logError(printf("sqlBindTime: Time not in allowed range.\n"););
2022 raise_error(RANGE_ERROR);
2023 } else {
2024 param = &preparedStmt->param_array[pos - 1];
2025 /* printf("paramType: %s\n",
2026 nameOfBufferType(preparedStmt->paramTypes[pos - 1])); */
2027 switch (preparedStmt->paramTypes[pos - 1]) {
2028 case DATEOID:
2029 preparedStmt->paramValues[pos - 1] = param->buffer;
2030 timestamp = timToTimestamp(year, month, day, 0, 0, 0, 0);
2031 timestamp = (timestamp - SECONDS_FROM_1970_TO_2000) / (24 * 60 * 60);
2032 /* printf("DATEOID timestamp: " FMT_D64 "\n", timestamp); */
2033 *(int32Type *) param->buffer =
2034 (int32Type) htonl((uint32Type) timestamp);
2035 break;
2036 case TIMEOID:
2037 preparedStmt->paramValues[pos - 1] = param->buffer;
2038 timestamp = timToTimestamp(2000, 1, 1, hour, minute, second, 0);
2039 /* printf("timestamp1970: " FMT_D64 "\n", timestamp); */
2040 timestamp = (timestamp - SECONDS_FROM_1970_TO_2000) * 1000000 + micro_second;
2041 /* printf("TIMEOID timestamp: " FMT_D64 "\n", timestamp); */
2042 /* The time is either an int64Type representing */
2043 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
2044 /* double representing seconds away from the same origin. */
2045 /* PQparameterStatus(connection, "integer_datetimes") is */
2046 /* used to determine if an int64Type or a double is used. */
2047 if (preparedStmt->integerDatetimes) {
2048 *(int64Type *) param->buffer =
2049 (int64Type) htonll((uint64Type) timestamp);
2050 } else {
2051 *(double *) param->buffer =
2052 htond((double) timestamp / 1000000.0);
2053 } /* if */
2054 break;
2055 case TIMETZOID:
2056 preparedStmt->paramValues[pos - 1] = param->buffer;
2057 timestamp = timToTimestamp(2000, 1, 1, hour, minute, second, 0);
2058 /* printf("timestamp1970: " FMT_D64 "\n", timestamp); */
2059 timestamp = (timestamp - SECONDS_FROM_1970_TO_2000) * 1000000 + micro_second;
2060 /* printf("TIMETZOID timestamp: " FMT_D64 "\n", timestamp); */
2061 /* The time is either an int64Type representing */
2062 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
2063 /* double representing seconds away from the same origin. */
2064 /* PQparameterStatus(connection, "integer_datetimes") is */
2065 /* used to determine if an int64Type or a double is used. */
2066 if (preparedStmt->integerDatetimes) {
2067 *(int64Type *) param->buffer =
2068 (int64Type) htonll((uint64Type) timestamp);
2069 } else {
2070 *(double *) param->buffer =
2071 htond((double) timestamp / 1000000.0);
2072 } /* if */
2073 /* printf("zone: " FMT_D32 "\n", (int32Type) (-time_zone * 60)); */
2074 zone = (int32Type) htonl((uint32Type) (-time_zone * 60));
2075 *(int64Type *) ¶m->buffer[8] = zone;
2076 break;
2077 case TIMESTAMPOID:
2078 preparedStmt->paramValues[pos - 1] = param->buffer;
2079 timestamp = timToTimestamp(year, month, day, hour, minute, second, 0);
2080 /* printf("timestamp1970: " FMT_D64 "\n", timestamp); */
2081 timestamp = (timestamp - SECONDS_FROM_1970_TO_2000) * 1000000 + micro_second;
2082 /* printf("TIMESTAMPOID timestamp: " FMT_D64 "\n", timestamp); */
2083 /* The timestamp is either an int64Type representing */
2084 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
2085 /* double representing seconds away from the same origin. */
2086 /* PQparameterStatus(connection, "integer_datetimes") is */
2087 /* used to determine if an int64Type or a double is used. */
2088 if (preparedStmt->integerDatetimes) {
2089 *(int64Type *) param->buffer =
2090 (int64Type) htonll((uint64Type) timestamp);
2091 } else {
2092 *(double *) param->buffer =
2093 htond((double) timestamp / 1000000.0);
2094 } /* if */
2095 break;
2096 case TIMESTAMPTZOID:
2097 preparedStmt->paramValues[pos - 1] = param->buffer;
2098 timestamp = timToTimestamp(year, month, day, hour, minute, second,
2099 time_zone);
2100 /* printf("timestamp1970: " FMT_D64 "\n", timestamp); */
2101 timestamp = (timestamp - SECONDS_FROM_1970_TO_2000) * 1000000 + micro_second;
2102 /* printf("TIMESTAMPTZOID timestamp: " FMT_D64 "\n", timestamp); */
2103 /* The timestamp is either an int64Type representing */
2104 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
2105 /* double representing seconds away from the same origin. */
2106 /* PQparameterStatus(connection, "integer_datetimes") is */
2107 /* used to determine if an int64Type or a double is used. */
2108 if (preparedStmt->integerDatetimes) {
2109 *(int64Type *) param->buffer =
2110 (int64Type) htonll((uint64Type) timestamp);
2111 } else {
2112 *(double *) param->buffer =
2113 htond((double) timestamp / 1000000.0);
2114 } /* if */
2115 break;
2116 default:
2117 logError(printf("sqlBindTime: Parameter " FMT_D " has the unknown type %s.\n",
2118 pos, nameOfBufferType(preparedStmt->paramTypes[pos - 1])););
2119 err_info = RANGE_ERROR;
2120 break;
2121 } /* switch */
2122 if (unlikely(err_info != OKAY_NO_ERROR)) {
2123 raise_error(err_info);
2124 } else {
2125 preparedStmt->executeSuccessful = FALSE;
2126 preparedStmt->fetchOkay = FALSE;
2127 param->bound = TRUE;
2128 } /* if */
2129 } /* if */
2130 } /* sqlBindTime */
2131
2132
2133
sqlClose(databaseType database)2134 static void sqlClose (databaseType database)
2135
2136 {
2137 dbType db;
2138
2139 /* sqlClose */
2140 logFunction(printf("sqlClose(" FMT_U_MEM ")\n",
2141 (memSizeType) database););
2142 db = (dbType) database;
2143 if (db->connection != NULL) {
2144 PQfinish(db->connection);
2145 db->connection = NULL;
2146 } /* if */
2147 logFunction(printf("sqlClose -->\n"););
2148 } /* sqlClose */
2149
2150
2151
sqlColumnBigInt(sqlStmtType sqlStatement,intType column)2152 static bigIntType sqlColumnBigInt (sqlStmtType sqlStatement, intType column)
2153
2154 {
2155 preparedStmtType preparedStmt;
2156 int isNull;
2157 const_cstriType buffer;
2158 Oid buffer_type;
2159 bigIntType columnValue;
2160
2161 /* sqlColumnBigInt */
2162 logFunction(printf("sqlColumnBigInt(" FMT_U_MEM ", " FMT_D ")\n",
2163 (memSizeType) sqlStatement, column););
2164 preparedStmt = (preparedStmtType) sqlStatement;
2165 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2166 (uintType) column > preparedStmt->result_column_count)) {
2167 logError(printf("sqlColumnBigInt: Fetch okay: %d, column: " FMT_D
2168 ", max column: " FMT_U_MEM ".\n",
2169 preparedStmt->fetchOkay, column,
2170 preparedStmt->result_column_count););
2171 raise_error(RANGE_ERROR);
2172 columnValue = NULL;
2173 } else {
2174 isNull = PQgetisnull(preparedStmt->execute_result,
2175 preparedStmt->fetch_index,
2176 (int) column - 1);
2177 if (isNull == 1) {
2178 /* printf("Column is NULL -> Use default value: 0\n"); */
2179 columnValue = bigZero();
2180 } else if (unlikely(isNull != 0)) {
2181 dbInconsistent("sqlColumnBigInt", "PQgetisnull");
2182 logError(printf("sqlColumnBigInt: Column " FMT_D ": "
2183 "PQgetisnull returns %d.\n",
2184 column, isNull););
2185 raise_error(DATABASE_ERROR);
2186 columnValue = NULL;
2187 } else {
2188 buffer = PQgetvalue(preparedStmt->execute_result,
2189 preparedStmt->fetch_index,
2190 (int) column - 1);
2191 if (unlikely(buffer == NULL)) {
2192 dbInconsistent("sqlColumnBigInt", "PQgetvalue");
2193 logError(printf("sqlColumnBigInt: Column " FMT_D ": "
2194 "PQgetvalue returns NULL.\n",
2195 column););
2196 raise_error(DATABASE_ERROR);
2197 columnValue = NULL;
2198 } else {
2199 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2200 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2201 switch (buffer_type) {
2202 case INT2OID:
2203 columnValue = bigFromInt32((int16Type) ntohs(*(uint16Type *) buffer));
2204 break;
2205 case INT4OID:
2206 columnValue = bigFromInt32((int32Type) ntohl(*(uint32Type *) buffer));
2207 break;
2208 case INT8OID:
2209 columnValue = bigFromInt64((int64Type) ntohll(*(uint64Type *) buffer));
2210 break;
2211 case NUMERICOID:
2212 columnValue = getNumericAsBigInt((const_ustriType) buffer);
2213 break;
2214 default:
2215 logError(printf("sqlColumnBigInt: Column " FMT_D " has the unknown type %s.\n",
2216 column, nameOfBufferType(buffer_type)););
2217 raise_error(RANGE_ERROR);
2218 columnValue = NULL;
2219 break;
2220 } /* switch */
2221 } /* if */
2222 } /* if */
2223 } /* if */
2224 logFunction(printf("sqlColumnBigInt --> %s\n", bigHexCStri(columnValue)););
2225 return columnValue;
2226 } /* sqlColumnBigInt */
2227
2228
2229
sqlColumnBigRat(sqlStmtType sqlStatement,intType column,bigIntType * numerator,bigIntType * denominator)2230 static void sqlColumnBigRat (sqlStmtType sqlStatement, intType column,
2231 bigIntType *numerator, bigIntType *denominator)
2232
2233 {
2234 preparedStmtType preparedStmt;
2235 int isNull;
2236 const_cstriType buffer;
2237 Oid buffer_type;
2238
2239 /* sqlColumnBigRat */
2240 logFunction(printf("sqlColumnBigRat(" FMT_U_MEM ", " FMT_D ", *, *)\n",
2241 (memSizeType) sqlStatement, column););
2242 preparedStmt = (preparedStmtType) sqlStatement;
2243 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2244 (uintType) column > preparedStmt->result_column_count)) {
2245 logError(printf("sqlColumnBigRat: Fetch okay: %d, column: " FMT_D
2246 ", max column: " FMT_U_MEM ".\n",
2247 preparedStmt->fetchOkay, column,
2248 preparedStmt->result_column_count););
2249 raise_error(RANGE_ERROR);
2250 } else {
2251 isNull = PQgetisnull(preparedStmt->execute_result,
2252 preparedStmt->fetch_index,
2253 (int) column - 1);
2254 if (isNull == 1) {
2255 /* printf("Column is NULL -> Use default value: 0\n"); */
2256 *numerator = bigZero();
2257 *denominator = bigFromInt32(1);
2258 } else if (unlikely(isNull != 0)) {
2259 dbInconsistent("sqlColumnBigRat", "PQgetisnull");
2260 logError(printf("sqlColumnBigRat: Column " FMT_D ": "
2261 "PQgetisnull returns %d.\n",
2262 column, isNull););
2263 raise_error(DATABASE_ERROR);
2264 } else {
2265 buffer = PQgetvalue(preparedStmt->execute_result,
2266 preparedStmt->fetch_index,
2267 (int) column - 1);
2268 if (unlikely(buffer == NULL)) {
2269 dbInconsistent("sqlColumnBigRat", "PQgetvalue");
2270 logError(printf("sqlColumnBigRat: Column " FMT_D ": "
2271 "PQgetvalue returns NULL.\n", column););
2272 raise_error(DATABASE_ERROR);
2273 } else {
2274 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2275 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2276 switch (buffer_type) {
2277 case INT2OID:
2278 *numerator = bigFromInt32((int16Type) ntohs(*(uint16Type *) buffer));
2279 *denominator = bigFromInt32(1);
2280 break;
2281 case INT4OID:
2282 *numerator = bigFromInt32((int32Type) ntohl(*(uint32Type *) buffer));
2283 *denominator = bigFromInt32(1);
2284 break;
2285 case INT8OID:
2286 *numerator = bigFromInt64((int64Type) ntohll(*(uint64Type *) buffer));
2287 *denominator = bigFromInt32(1);
2288 break;
2289 case FLOAT4OID:
2290 *numerator = roundDoubleToBigRat(ntohf(*(float *) buffer), FALSE, denominator);
2291 break;
2292 case FLOAT8OID:
2293 *numerator = roundDoubleToBigRat(ntohd(*(double *) buffer), TRUE, denominator);
2294 break;
2295 case NUMERICOID:
2296 *numerator = getNumericAsBigRat((const_ustriType) buffer, denominator);
2297 break;
2298 default:
2299 logError(printf("sqlColumnBigRat: Column " FMT_D " has the unknown type %s.\n",
2300 column, nameOfBufferType(buffer_type)););
2301 raise_error(RANGE_ERROR);
2302 } /* switch */
2303 } /* if */
2304 } /* if */
2305 } /* if */
2306 logFunction(printf("sqlColumnBigRat(" FMT_U_MEM ", " FMT_D ", %s, %s) -->\n",
2307 (memSizeType) sqlStatement, column,
2308 bigHexCStri(*numerator), bigHexCStri(*denominator)););
2309 } /* sqlColumnBigRat */
2310
2311
2312
sqlColumnBool(sqlStmtType sqlStatement,intType column)2313 static boolType sqlColumnBool (sqlStmtType sqlStatement, intType column)
2314
2315 {
2316 preparedStmtType preparedStmt;
2317 int isNull;
2318 const_cstriType buffer;
2319 Oid buffer_type;
2320 int length;
2321 intType columnValue;
2322
2323 /* sqlColumnBool */
2324 logFunction(printf("sqlColumnBool(" FMT_U_MEM ", " FMT_D ")\n",
2325 (memSizeType) sqlStatement, column););
2326 preparedStmt = (preparedStmtType) sqlStatement;
2327 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2328 (uintType) column > preparedStmt->result_column_count)) {
2329 logError(printf("sqlColumnBool: Fetch okay: %d, column: " FMT_D
2330 ", max column: " FMT_U_MEM ".\n",
2331 preparedStmt->fetchOkay, column,
2332 preparedStmt->result_column_count););
2333 raise_error(RANGE_ERROR);
2334 columnValue = 0;
2335 } else {
2336 isNull = PQgetisnull(preparedStmt->execute_result,
2337 preparedStmt->fetch_index,
2338 (int) column - 1);
2339 if (isNull == 1) {
2340 /* printf("Column is NULL -> Use default value: 0\n"); */
2341 columnValue = 0;
2342 } else if (unlikely(isNull != 0)) {
2343 dbInconsistent("sqlColumnBool", "PQgetisnull");
2344 logError(printf("sqlColumnBool: Column " FMT_D ": "
2345 "PQgetisnull returns %d.\n",
2346 column, isNull););
2347 raise_error(DATABASE_ERROR);
2348 columnValue = 0;
2349 } else {
2350 buffer = PQgetvalue(preparedStmt->execute_result,
2351 preparedStmt->fetch_index,
2352 (int) column - 1);
2353 if (unlikely(buffer == NULL)) {
2354 dbInconsistent("sqlColumnBool", "PQgetvalue");
2355 logError(printf("sqlColumnBool: Column " FMT_D ": "
2356 "PQgetvalue returns NULL.\n",
2357 column););
2358 raise_error(DATABASE_ERROR);
2359 columnValue = 0;
2360 } else {
2361 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2362 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2363 switch (buffer_type) {
2364 case INT2OID:
2365 columnValue = (int16Type) ntohs(*(uint16Type *) buffer);
2366 break;
2367 case INT4OID:
2368 columnValue = (int32Type) ntohl(*(uint32Type *) buffer);
2369 break;
2370 case INT8OID:
2371 columnValue = (int64Type) ntohll(*(uint64Type *) buffer);
2372 break;
2373 case CHAROID:
2374 case BPCHAROID:
2375 case VARCHAROID:
2376 case TEXTOID:
2377 length = PQgetlength(preparedStmt->execute_result,
2378 preparedStmt->fetch_index,
2379 (int) column - 1);
2380 if (unlikely(length != 1)) {
2381 logError(printf("sqlColumnBool: Column " FMT_D ": "
2382 "The size of a boolean field must be 1.\n", column););
2383 raise_error(RANGE_ERROR);
2384 columnValue = 0;
2385 } else {
2386 columnValue = buffer[0] != '0';
2387 } /* if */
2388 break;
2389 case BOOLOID:
2390 columnValue = buffer[0];
2391 break;
2392 default:
2393 logError(printf("sqlColumnBool: Column " FMT_D " has the unknown type %s.\n",
2394 column, nameOfBufferType(buffer_type)););
2395 raise_error(RANGE_ERROR);
2396 columnValue = 0;
2397 break;
2398 } /* switch */
2399 if (unlikely((uintType) columnValue >= 2)) {
2400 logError(printf("sqlColumnBool: Column " FMT_D ": "
2401 FMT_D " is not an allowed boolean value.\n",
2402 column, columnValue););
2403 raise_error(RANGE_ERROR);
2404 } /* if */
2405 } /* if */
2406 } /* if */
2407 } /* if */
2408 logFunction(printf("sqlColumnBool --> %s\n", columnValue ? "TRUE" : "FALSE"););
2409 return columnValue != 0;
2410 } /* sqlColumnBool */
2411
2412
2413
sqlColumnBStri(sqlStmtType sqlStatement,intType column)2414 static bstriType sqlColumnBStri (sqlStmtType sqlStatement, intType column)
2415
2416 {
2417 preparedStmtType preparedStmt;
2418 int isNull;
2419 const_cstriType buffer;
2420 Oid buffer_type;
2421 int length;
2422 errInfoType err_info = OKAY_NO_ERROR;
2423 bstriType columnValue;
2424
2425 /* sqlColumnBStri */
2426 logFunction(printf("sqlColumnBStri(" FMT_U_MEM ", " FMT_D ")\n",
2427 (memSizeType) sqlStatement, column););
2428 preparedStmt = (preparedStmtType) sqlStatement;
2429 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2430 (uintType) column > preparedStmt->result_column_count)) {
2431 logError(printf("sqlColumnBStri: Fetch okay: %d, column: " FMT_D
2432 ", max column: " FMT_U_MEM ".\n",
2433 preparedStmt->fetchOkay, column,
2434 preparedStmt->result_column_count););
2435 raise_error(RANGE_ERROR);
2436 columnValue = NULL;
2437 } else {
2438 isNull = PQgetisnull(preparedStmt->execute_result,
2439 preparedStmt->fetch_index,
2440 (int) column - 1);
2441 if (isNull == 1) {
2442 /* printf("Column is NULL -> Use default value: \"\"\n"); */
2443 if (unlikely(!ALLOC_BSTRI_SIZE_OK(columnValue, 0))) {
2444 raise_error(MEMORY_ERROR);
2445 } else {
2446 columnValue->size = 0;
2447 } /* if */
2448 } else if (unlikely(isNull != 0)) {
2449 dbInconsistent("sqlColumnBStri", "PQgetisnull");
2450 logError(printf("sqlColumnBStri: Column " FMT_D ": "
2451 "PQgetisnull returns %d.\n",
2452 column, isNull););
2453 raise_error(DATABASE_ERROR);
2454 columnValue = NULL;
2455 } else {
2456 buffer = PQgetvalue(preparedStmt->execute_result,
2457 preparedStmt->fetch_index,
2458 (int) column - 1);
2459 if (unlikely(buffer == NULL)) {
2460 dbInconsistent("sqlColumnBStri", "PQgetvalue");
2461 logError(printf("sqlColumnBStri: Column " FMT_D ": "
2462 "PQgetvalue returns NULL.\n",
2463 column););
2464 raise_error(DATABASE_ERROR);
2465 columnValue = NULL;
2466 } else {
2467 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2468 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2469 switch (buffer_type) {
2470 case BYTEAOID:
2471 length = PQgetlength(preparedStmt->execute_result,
2472 preparedStmt->fetch_index,
2473 (int) column - 1);
2474 if (unlikely(length < 0)) {
2475 dbInconsistent("sqlColumnBStri", "PQgetlength");
2476 logError(printf("sqlColumnBStri: Column " FMT_D ": "
2477 "PQgetlength returns %d.\n",
2478 column, length););
2479 raise_error(DATABASE_ERROR);
2480 columnValue = NULL;
2481 } else if (unlikely(!ALLOC_BSTRI_CHECK_SIZE(columnValue, (memSizeType) length))) {
2482 raise_error(MEMORY_ERROR);
2483 } else {
2484 memcpy(columnValue->mem, buffer, (memSizeType) length);
2485 columnValue->size = (memSizeType) length;
2486 } /* if */
2487 break;
2488 #if 0
2489 case NAMEOID:
2490 case CHAROID:
2491 case VARCHAROID:
2492 case TEXTOID:
2493 length = PQgetlength(preparedStmt->execute_result,
2494 preparedStmt->fetch_index,
2495 (int) column - 1);
2496 if (unlikely(length < 0)) {
2497 dbInconsistent("sqlColumnBStri", "PQgetlength");
2498 logError(printf("sqlColumnBStri: Column " FMT_D ": "
2499 "PQgetlength returns %d.\n",
2500 column, length););
2501 raise_error(DATABASE_ERROR);
2502 columnValue = NULL;
2503 } else {
2504 columnValue = cstri8_buf_to_stri(buffer, (memSizeType) length, &err_info);
2505 if (unlikely(columnValue == NULL)) {
2506 raise_error(err_info);
2507 } /* if */
2508 } /* if */
2509 break;
2510 case BPCHAROID:
2511 length = PQgetlength(preparedStmt->execute_result,
2512 preparedStmt->fetch_index,
2513 (int) column - 1);
2514 if (unlikely(length < 0)) {
2515 dbInconsistent("sqlColumnBStri", "PQgetlength");
2516 logError(printf("sqlColumnBStri: Column " FMT_D ": "
2517 "PQgetlength returns %d.\n",
2518 column, length););
2519 raise_error(DATABASE_ERROR);
2520 columnValue = NULL;
2521 } else {
2522 while (length > 0 && buffer[length - 1] == ' ') {
2523 length--;
2524 } /* if */
2525 columnValue = cstri8_buf_to_stri(buffer, (memSizeType) length, &err_info);
2526 if (unlikely(columnValue == NULL)) {
2527 raise_error(err_info);
2528 } /* if */
2529 } /* if */
2530 break;
2531 #endif
2532 default:
2533 logError(printf("sqlColumnBStri: Column " FMT_D " has the unknown type %s.\n",
2534 column, nameOfBufferType(buffer_type)););
2535 raise_error(RANGE_ERROR);
2536 columnValue = NULL;
2537 break;
2538 } /* switch */
2539 } /* if */
2540 } /* if */
2541 } /* if */
2542 logFunction(printf("sqlColumnBStri --> \"%s\"\n", bstriAsUnquotedCStri(columnValue)););
2543 return columnValue;
2544 } /* sqlColumnBStri */
2545
2546
2547
sqlColumnDuration(sqlStmtType sqlStatement,intType column,intType * year,intType * month,intType * day,intType * hour,intType * minute,intType * second,intType * micro_second)2548 static void sqlColumnDuration (sqlStmtType sqlStatement, intType column,
2549 intType *year, intType *month, intType *day, intType *hour,
2550 intType *minute, intType *second, intType *micro_second)
2551
2552 {
2553 preparedStmtType preparedStmt;
2554 int isNull;
2555 const_cstriType buffer;
2556 Oid buffer_type;
2557 int64Type microsecDuration;
2558 int32Type dayDuration;
2559 int32Type monthDuration;
2560
2561 /* sqlColumnDuration */
2562 logFunction(printf("sqlColumnDuration(" FMT_U_MEM ", " FMT_D ", *)\n",
2563 (memSizeType) sqlStatement, column););
2564 preparedStmt = (preparedStmtType) sqlStatement;
2565 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2566 (uintType) column > preparedStmt->result_column_count)) {
2567 logError(printf("sqlColumnDuration: Fetch okay: %d, column: " FMT_D
2568 ", max column: " FMT_U_MEM ".\n",
2569 preparedStmt->fetchOkay, column,
2570 preparedStmt->result_column_count););
2571 raise_error(RANGE_ERROR);
2572 } else {
2573 isNull = PQgetisnull(preparedStmt->execute_result,
2574 preparedStmt->fetch_index,
2575 (int) column - 1);
2576 if (isNull == 1) {
2577 /* printf("Column is NULL -> Use default value: P0D\n"); */
2578 *year = 0;
2579 *month = 0;
2580 *day = 0;
2581 *hour = 0;
2582 *minute = 0;
2583 *second = 0;
2584 *micro_second = 0;
2585 } else if (unlikely(isNull != 0)) {
2586 dbInconsistent("sqlColumnDuration", "PQgetisnull");
2587 logError(printf("sqlColumnDuration: Column " FMT_D ": "
2588 "PQgetisnull returns %d.\n",
2589 column, isNull););
2590 raise_error(DATABASE_ERROR);
2591 } else {
2592 buffer = PQgetvalue(preparedStmt->execute_result,
2593 preparedStmt->fetch_index,
2594 (int) column - 1);
2595 if (unlikely(buffer == NULL)) {
2596 dbInconsistent("sqlColumnDuration", "PQgetvalue");
2597 logError(printf("sqlColumnDuration: Column " FMT_D ": "
2598 "PQgetvalue returns NULL.\n",
2599 column););
2600 raise_error(DATABASE_ERROR);
2601 } else {
2602 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2603 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2604 switch (buffer_type) {
2605 case INTERVALOID:
2606 /* The interval is either an int64Type representing */
2607 /* microseconds, or a double representing seconds. */
2608 /* PQparameterStatus(connection, "integer_datetimes") is */
2609 /* used to determine if an int64Type or a double is used. */
2610 if (preparedStmt->integerDatetimes) {
2611 microsecDuration = (int64Type) ntohll(*(uint64Type *) buffer);
2612 } else {
2613 microsecDuration = (int64Type) (1000000.0 * ntohd(*(double *) buffer) + 0.5);
2614 } /* if */
2615 dayDuration = (int32Type) ntohl(*(uint32Type *) &buffer[8]);
2616 monthDuration = (int32Type) ntohl(*(uint32Type *) &buffer[12]);
2617 /* printf("microsecDuration: " FMT_D64 "\n", microsecDuration);
2618 printf("dayDuration: " FMT_D32 "\n", dayDuration);
2619 printf("monthDuration: " FMT_D32 "\n", monthDuration); */
2620 if (microsecDuration < 0) {
2621 microsecDuration = -microsecDuration;
2622 *micro_second = -(microsecDuration % 1000000);
2623 microsecDuration /= 1000000;
2624 *second = -(microsecDuration % 60);
2625 microsecDuration /= 60;
2626 *minute = -(microsecDuration % 60);
2627 microsecDuration /= 60;
2628 *hour = -(microsecDuration % 24);
2629 microsecDuration /= 24;
2630 microsecDuration = -microsecDuration;
2631 } else {
2632 *micro_second = microsecDuration % 1000000;
2633 microsecDuration /= 1000000;
2634 *second = microsecDuration % 60;
2635 microsecDuration /= 60;
2636 *minute = microsecDuration % 60;
2637 microsecDuration /= 60;
2638 *hour = microsecDuration % 24;
2639 microsecDuration /= 24;
2640 } /* if */
2641 *day = microsecDuration + dayDuration;
2642 if (monthDuration < 0) {
2643 monthDuration = -monthDuration;
2644 *month = -(monthDuration % 12);
2645 *year = -(monthDuration / 12);
2646 } else {
2647 *month = monthDuration % 12;
2648 *year = monthDuration / 12;
2649 } /* if */
2650 break;
2651 default:
2652 logError(printf("sqlColumnDuration: Column " FMT_D " has the unknown type %s.\n",
2653 column, nameOfBufferType(buffer_type)););
2654 raise_error(RANGE_ERROR);
2655 break;
2656 } /* switch */
2657 } /* if */
2658 } /* if */
2659 } /* if */
2660 logFunction(printf("sqlColumnDuration(" FMT_U_MEM ", " FMT_D ") -> P"
2661 FMT_D "Y" FMT_D "M" FMT_D "DT"
2662 FMT_D "H" FMT_D "M%s" FMT_U "." F_U(06) "S\n",
2663 (memSizeType) sqlStatement, column,
2664 *year, *month, *day, *hour, *minute,
2665 *second < 0 || *micro_second < 0 ? "-" : "",
2666 intAbs(*second), intAbs(*micro_second)););
2667 } /* sqlColumnDuration */
2668
2669
2670
sqlColumnFloat(sqlStmtType sqlStatement,intType column)2671 static floatType sqlColumnFloat (sqlStmtType sqlStatement, intType column)
2672
2673 {
2674 preparedStmtType preparedStmt;
2675 int isNull;
2676 const_cstriType buffer;
2677 Oid buffer_type;
2678 floatType columnValue;
2679
2680 /* sqlColumnFloat */
2681 logFunction(printf("sqlColumnFloat(" FMT_U_MEM ", " FMT_D ")\n",
2682 (memSizeType) sqlStatement, column););
2683 preparedStmt = (preparedStmtType) sqlStatement;
2684 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2685 (uintType) column > preparedStmt->result_column_count)) {
2686 logError(printf("sqlColumnFloat: Fetch okay: %d, column: " FMT_D
2687 ", max column: " FMT_U_MEM ".\n",
2688 preparedStmt->fetchOkay, column,
2689 preparedStmt->result_column_count););
2690 raise_error(RANGE_ERROR);
2691 columnValue = 0.0;
2692 } else {
2693 isNull = PQgetisnull(preparedStmt->execute_result,
2694 preparedStmt->fetch_index,
2695 (int) column - 1);
2696 if (isNull == 1) {
2697 /* printf("Column is NULL -> Use default value: 0.0\n"); */
2698 columnValue = 0.0;
2699 } else if (unlikely(isNull != 0)) {
2700 dbInconsistent("sqlColumnFloat", "PQgetisnull");
2701 logError(printf("sqlColumnFloat: Column " FMT_D ": "
2702 "PQgetisnull returns %d.\n",
2703 column, isNull););
2704 raise_error(DATABASE_ERROR);
2705 columnValue = 0.0;
2706 } else {
2707 buffer = PQgetvalue(preparedStmt->execute_result,
2708 preparedStmt->fetch_index,
2709 (int) column - 1);
2710 if (unlikely(buffer == NULL)) {
2711 dbInconsistent("sqlColumnFloat", "PQgetvalue");
2712 logError(printf("sqlColumnFloat: Column " FMT_D ": "
2713 "PQgetvalue returns NULL.\n",
2714 column););
2715 raise_error(DATABASE_ERROR);
2716 columnValue = 0.0;
2717 } else {
2718 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2719 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2720 switch (buffer_type) {
2721 case INT2OID:
2722 columnValue = (floatType) (int16Type) ntohs(*(uint16Type *) buffer);
2723 break;
2724 case INT4OID:
2725 columnValue = (floatType) (int32Type) ntohl(*(uint32Type *) buffer);
2726 break;
2727 case INT8OID:
2728 columnValue = (floatType) (int64Type) ntohll(*(uint64Type *) buffer);
2729 break;
2730 case FLOAT4OID:
2731 columnValue = ntohf(*(float *) buffer);
2732 break;
2733 case FLOAT8OID:
2734 columnValue = ntohd(*(double *) buffer);
2735 break;
2736 case NUMERICOID:
2737 columnValue = getNumericAsFloat((const_ustriType) buffer);
2738 break;
2739 default:
2740 logError(printf("sqlColumnFloat: Column " FMT_D " has the unknown type %s.\n",
2741 column, nameOfBufferType(buffer_type)););
2742 raise_error(RANGE_ERROR);
2743 columnValue = 0.0;
2744 break;
2745 } /* switch */
2746 } /* if */
2747 } /* if */
2748 } /* if */
2749 logFunction(printf("sqlColumnFloat --> " FMT_E "\n", columnValue););
2750 return columnValue;
2751 } /* sqlColumnFloat */
2752
2753
2754
sqlColumnInt(sqlStmtType sqlStatement,intType column)2755 static intType sqlColumnInt (sqlStmtType sqlStatement, intType column)
2756
2757 {
2758 preparedStmtType preparedStmt;
2759 int isNull;
2760 const_cstriType buffer;
2761 Oid buffer_type;
2762 intType columnValue;
2763
2764 /* sqlColumnInt */
2765 logFunction(printf("sqlColumnInt(" FMT_U_MEM ", " FMT_D ")\n",
2766 (memSizeType) sqlStatement, column););
2767 preparedStmt = (preparedStmtType) sqlStatement;
2768 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2769 (uintType) column > preparedStmt->result_column_count)) {
2770 logError(printf("sqlColumnInt: Fetch okay: %d, column: " FMT_D
2771 ", max column: " FMT_U_MEM ".\n",
2772 preparedStmt->fetchOkay, column,
2773 preparedStmt->result_column_count););
2774 raise_error(RANGE_ERROR);
2775 columnValue = 0;
2776 } else {
2777 isNull = PQgetisnull(preparedStmt->execute_result,
2778 preparedStmt->fetch_index,
2779 (int) column - 1);
2780 if (isNull == 1) {
2781 /* printf("Column is NULL -> Use default value: 0\n"); */
2782 columnValue = 0;
2783 } else if (unlikely(isNull != 0)) {
2784 dbInconsistent("sqlColumnInt", "PQgetisnull");
2785 logError(printf("sqlColumnInt: Column " FMT_D ": "
2786 "PQgetisnull returns %d.\n",
2787 column, isNull););
2788 raise_error(DATABASE_ERROR);
2789 columnValue = 0;
2790 } else {
2791 buffer = PQgetvalue(preparedStmt->execute_result,
2792 preparedStmt->fetch_index,
2793 (int) column - 1);
2794 if (unlikely(buffer == NULL)) {
2795 dbInconsistent("sqlColumnInt", "PQgetvalue");
2796 logError(printf("sqlColumnInt: Column " FMT_D ": "
2797 "PQgetvalue returns NULL.\n",
2798 column););
2799 raise_error(DATABASE_ERROR);
2800 columnValue = 0;
2801 } else {
2802 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2803 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2804 switch (buffer_type) {
2805 case INT2OID:
2806 columnValue = (int16Type) ntohs(*(uint16Type *) buffer);
2807 break;
2808 case INT4OID:
2809 columnValue = (int32Type) ntohl(*(uint32Type *) buffer);
2810 break;
2811 case INT8OID:
2812 columnValue = (int64Type) ntohll(*(uint64Type *) buffer);
2813 break;
2814 case NUMERICOID:
2815 columnValue = getNumericAsInt((const_ustriType) buffer);
2816 break;
2817 case OIDOID:
2818 columnValue = ntohl(*(uint32Type *) buffer);
2819 break;
2820 default:
2821 logError(printf("sqlColumnInt: Column " FMT_D " has the unknown type %s.\n",
2822 column, nameOfBufferType(buffer_type)););
2823 raise_error(RANGE_ERROR);
2824 columnValue = 0;
2825 break;
2826 } /* switch */
2827 } /* if */
2828 } /* if */
2829 } /* if */
2830 logFunction(printf("sqlColumnInt --> " FMT_D "\n", columnValue););
2831 return columnValue;
2832 } /* sqlColumnInt */
2833
2834
2835
sqlColumnStri(sqlStmtType sqlStatement,intType column)2836 static striType sqlColumnStri (sqlStmtType sqlStatement, intType column)
2837
2838 {
2839 preparedStmtType preparedStmt;
2840 int isNull;
2841 const_cstriType buffer;
2842 Oid buffer_type;
2843 int length;
2844 errInfoType err_info = OKAY_NO_ERROR;
2845 striType columnValue;
2846
2847 /* sqlColumnStri */
2848 logFunction(printf("sqlColumnStri(" FMT_U_MEM ", " FMT_D ")\n",
2849 (memSizeType) sqlStatement, column););
2850 preparedStmt = (preparedStmtType) sqlStatement;
2851 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2852 (uintType) column > preparedStmt->result_column_count)) {
2853 logError(printf("sqlColumnStri: Fetch okay: %d, column: " FMT_D
2854 ", max column: " FMT_U_MEM ".\n",
2855 preparedStmt->fetchOkay, column,
2856 preparedStmt->result_column_count););
2857 raise_error(RANGE_ERROR);
2858 columnValue = NULL;
2859 } else {
2860 isNull = PQgetisnull(preparedStmt->execute_result,
2861 preparedStmt->fetch_index,
2862 (int) column - 1);
2863 if (isNull == 1) {
2864 /* printf("Column is NULL -> Use default value: \"\"\n"); */
2865 columnValue = strEmpty();
2866 } else if (unlikely(isNull != 0)) {
2867 dbInconsistent("sqlColumnStri", "PQgetisnull");
2868 logError(printf("sqlColumnStri: Column " FMT_D ": "
2869 "PQgetisnull returns %d.\n",
2870 column, isNull););
2871 raise_error(DATABASE_ERROR);
2872 columnValue = NULL;
2873 } else {
2874 buffer = PQgetvalue(preparedStmt->execute_result,
2875 preparedStmt->fetch_index,
2876 (int) column - 1);
2877 if (unlikely(buffer == NULL)) {
2878 dbInconsistent("sqlColumnStri", "PQgetvalue");
2879 logError(printf("sqlColumnStri: Column " FMT_D ": "
2880 "PQgetvalue returns NULL.\n",
2881 column););
2882 raise_error(DATABASE_ERROR);
2883 columnValue = NULL;
2884 } else {
2885 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
2886 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
2887 switch (buffer_type) {
2888 case NAMEOID:
2889 case CHAROID:
2890 case VARCHAROID:
2891 case TEXTOID:
2892 length = PQgetlength(preparedStmt->execute_result,
2893 preparedStmt->fetch_index,
2894 (int) column - 1);
2895 if (unlikely(length < 0)) {
2896 dbInconsistent("sqlColumnStri", "PQgetlength");
2897 logError(printf("sqlColumnStri: Column " FMT_D ": "
2898 "PQgetlength returns %d.\n",
2899 column, length););
2900 raise_error(DATABASE_ERROR);
2901 columnValue = NULL;
2902 } else {
2903 columnValue = cstri8_buf_to_stri(buffer, (memSizeType) length, &err_info);
2904 if (unlikely(columnValue == NULL)) {
2905 raise_error(err_info);
2906 } /* if */
2907 } /* if */
2908 break;
2909 case BPCHAROID:
2910 length = PQgetlength(preparedStmt->execute_result,
2911 preparedStmt->fetch_index,
2912 (int) column - 1);
2913 if (unlikely(length < 0)) {
2914 dbInconsistent("sqlColumnStri", "PQgetlength");
2915 logError(printf("sqlColumnStri: Column " FMT_D ": "
2916 "PQgetlength returns %d.\n",
2917 column, length););
2918 raise_error(DATABASE_ERROR);
2919 columnValue = NULL;
2920 } else {
2921 while (length > 0 && buffer[length - 1] == ' ') {
2922 length--;
2923 } /* if */
2924 columnValue = cstri8_buf_to_stri(buffer, (memSizeType) length, &err_info);
2925 if (unlikely(columnValue == NULL)) {
2926 raise_error(err_info);
2927 } /* if */
2928 } /* if */
2929 break;
2930 case BYTEAOID:
2931 length = PQgetlength(preparedStmt->execute_result,
2932 preparedStmt->fetch_index,
2933 (int) column - 1);
2934 if (unlikely(length < 0)) {
2935 dbInconsistent("sqlColumnStri", "PQgetlength");
2936 logError(printf("sqlColumnStri: Column " FMT_D ": "
2937 "PQgetlength returns %d.\n",
2938 column, length););
2939 raise_error(DATABASE_ERROR);
2940 columnValue = NULL;
2941 } else if (unlikely(!ALLOC_STRI_CHECK_SIZE(columnValue, (memSizeType) length))) {
2942 raise_error(MEMORY_ERROR);
2943 } else {
2944 memcpy_to_strelem(columnValue->mem, (ustriType) buffer,
2945 (memSizeType) length);
2946 columnValue->size = (memSizeType) length;
2947 } /* if */
2948 break;
2949 default:
2950 logError(printf("sqlColumnStri: Column " FMT_D " has the unknown type %s.\n",
2951 column, nameOfBufferType(buffer_type)););
2952 raise_error(RANGE_ERROR);
2953 columnValue = NULL;
2954 break;
2955 } /* switch */
2956 } /* if */
2957 } /* if */
2958 } /* if */
2959 logFunction(printf("sqlColumnStri --> \"%s\"\n", striAsUnquotedCStri(columnValue)););
2960 return columnValue;
2961 } /* sqlColumnStri */
2962
2963
2964
sqlColumnTime(sqlStmtType sqlStatement,intType column,intType * year,intType * month,intType * day,intType * hour,intType * minute,intType * second,intType * micro_second,intType * time_zone,boolType * is_dst)2965 static void sqlColumnTime (sqlStmtType sqlStatement, intType column,
2966 intType *year, intType *month, intType *day, intType *hour,
2967 intType *minute, intType *second, intType *micro_second,
2968 intType *time_zone, boolType *is_dst)
2969
2970 {
2971 preparedStmtType preparedStmt;
2972 int isNull;
2973 const_cstriType buffer;
2974 Oid buffer_type;
2975 timeStampType timestamp;
2976 intType dummy_micro_second;
2977
2978 /* sqlColumnTime */
2979 logFunction(printf("sqlColumnTime(" FMT_U_MEM ", " FMT_D ", *)\n",
2980 (memSizeType) sqlStatement, column););
2981 preparedStmt = (preparedStmtType) sqlStatement;
2982 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
2983 (uintType) column > preparedStmt->result_column_count)) {
2984 logError(printf("sqlColumnTime: Fetch okay: %d, column: " FMT_D
2985 ", max column: " FMT_U_MEM ".\n",
2986 preparedStmt->fetchOkay, column,
2987 preparedStmt->result_column_count););
2988 raise_error(RANGE_ERROR);
2989 } else {
2990 isNull = PQgetisnull(preparedStmt->execute_result,
2991 preparedStmt->fetch_index,
2992 (int) column - 1);
2993 if (isNull == 1) {
2994 /* printf("Column is NULL -> Use default value: 0-01-01 00:00:00\n"); */
2995 *year = 0;
2996 *month = 1;
2997 *day = 1;
2998 *hour = 0;
2999 *minute = 0;
3000 *second = 0;
3001 *micro_second = 0;
3002 *time_zone = 0;
3003 *is_dst = 0;
3004 } else if (unlikely(isNull != 0)) {
3005 dbInconsistent("sqlColumnTime", "PQgetisnull");
3006 logError(printf("sqlColumnTime: Column " FMT_D ": "
3007 "PQgetisnull returns %d.\n",
3008 column, isNull););
3009 raise_error(DATABASE_ERROR);
3010 } else {
3011 buffer = PQgetvalue(preparedStmt->execute_result,
3012 preparedStmt->fetch_index,
3013 (int) column - 1);
3014 if (unlikely(buffer == NULL)) {
3015 dbInconsistent("sqlColumnTime", "PQgetvalue");
3016 logError(printf("sqlColumnTime: Column " FMT_D ": "
3017 "PQgetvalue returns NULL.\n",
3018 column););
3019 raise_error(DATABASE_ERROR);
3020 } else {
3021 buffer_type = PQftype(preparedStmt->execute_result, (int) column - 1);
3022 /* printf("buffer_type: %s\n", nameOfBufferType(buffer_type)); */
3023 switch (buffer_type) {
3024 case DATEOID:
3025 timestamp = (timeStampType) (int32Type) ntohl(*(uint32Type *) buffer);
3026 /* printf("DATEOID timestamp: " FMT_D64 "\n", timestamp); */
3027 timestamp = timestamp * 24 * 60 * 60 + SECONDS_FROM_1970_TO_2000;
3028 timUtcFromTimestamp(timestamp, year, month, day,
3029 hour, minute, second);
3030 *micro_second = 0;
3031 timSetLocalTZ(*year, *month, *day, *hour, *minute, *second,
3032 time_zone, is_dst);
3033 break;
3034 case TIMEOID:
3035 /* The time is either an int64Type representing */
3036 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
3037 /* double representing seconds away from the same origin. */
3038 /* PQparameterStatus(connection, "integer_datetimes") is */
3039 /* used to determine if an int64Type or a double is used. */
3040 if (preparedStmt->integerDatetimes) {
3041 timestamp = (timeStampType) ntohll(*(uint64Type *) buffer);
3042 } else {
3043 timestamp = (timeStampType) (1000000.0 * ntohd(*(double *) buffer) + 0.5);
3044 } /* if */
3045 /* printf("TIMEOID timestamp: " FMT_D64 "\n", timestamp); */
3046 timestamp = getTimestamp1970(timestamp, micro_second);
3047 timUtcFromTimestamp(timestamp, year, month, day,
3048 hour, minute, second);
3049 timSetLocalTZ(*year, *month, *day, *hour, *minute, *second,
3050 time_zone, is_dst);
3051 *year = 0;
3052 *month = 1;
3053 *day = 1;
3054 break;
3055 case TIMETZOID:
3056 /* The time is either an int64Type representing */
3057 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
3058 /* double representing seconds away from the same origin. */
3059 /* PQparameterStatus(connection, "integer_datetimes") is */
3060 /* used to determine if an int64Type or a double is used. */
3061 if (preparedStmt->integerDatetimes) {
3062 timestamp = (timeStampType) ntohll(*(uint64Type *) buffer);
3063 } else {
3064 timestamp = (timeStampType) (1000000.0 * ntohd(*(double *) buffer) + 0.5);
3065 } /* if */
3066 /* printf("TIMETZOID timestamp: " FMT_D64 "\n", timestamp); */
3067 timestamp = getTimestamp1970(timestamp, micro_second);
3068 timUtcFromTimestamp(timestamp, year, month, day,
3069 hour, minute, second);
3070 *is_dst = 0;
3071 /* printf("time_zone: " FMT_D32 "\n",
3072 (int32Type) -ntohl(*(uint32Type *) &buffer[8]) / 60); */
3073 *time_zone = -ntohl(*(uint32Type *) &buffer[8]) / 60;
3074 *year = 0;
3075 *month = 1;
3076 *day = 1;
3077 break;
3078 case TIMESTAMPOID:
3079 /* The timestamp is either an int64Type representing */
3080 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
3081 /* double representing seconds away from the same origin. */
3082 /* PQparameterStatus(connection, "integer_datetimes") is */
3083 /* used to determine if an int64Type or a double is used. */
3084 if (preparedStmt->integerDatetimes) {
3085 timestamp = (timeStampType) ntohll(*(uint64Type *) buffer);
3086 } else {
3087 timestamp = (timeStampType) (1000000.0 * ntohd(*(double *) buffer) + 0.5);
3088 } /* if */
3089 /* printf("TIMESTAMPOID timestamp: " FMT_D64 "\n", timestamp); */
3090 timestamp = getTimestamp1970(timestamp, micro_second);
3091 timUtcFromTimestamp(timestamp, year, month, day,
3092 hour, minute, second);
3093 timSetLocalTZ(*year, *month, *day, *hour, *minute, *second,
3094 time_zone, is_dst);
3095 break;
3096 case TIMESTAMPTZOID:
3097 /* The timestamp is either an int64Type representing */
3098 /* microseconds away from 2000-01-01 00:00:00 UTC, or a */
3099 /* double representing seconds away from the same origin. */
3100 /* PQparameterStatus(connection, "integer_datetimes") is */
3101 /* used to determine if an int64Type or a double is used. */
3102 if (preparedStmt->integerDatetimes) {
3103 timestamp = (timeStampType) ntohll(*(uint64Type *) buffer);
3104 } else {
3105 timestamp = (timeStampType) (1000000.0 * ntohd(*(double *) buffer) + 0.5);
3106 } /* if */
3107 /* printf("TIMESTAMPTZOID timestamp: " FMT_D64 "\n", timestamp); */
3108 timestamp = getTimestamp1970(timestamp, micro_second);
3109 *time_zone = 0;
3110 *is_dst = 0;
3111 timFromIntTimestamp((intType) timestamp, year, month, day,
3112 hour, minute, second, &dummy_micro_second,
3113 time_zone, is_dst);
3114 break;
3115 default:
3116 logError(printf("sqlColumnTime: Column " FMT_D " has the unknown type %s.\n",
3117 column, nameOfBufferType(buffer_type)););
3118 raise_error(RANGE_ERROR);
3119 break;
3120 } /* switch */
3121 } /* if */
3122 } /* if */
3123 } /* if */
3124 logFunction(printf("sqlColumnTime(" FMT_U_MEM ", " FMT_D ", "
3125 F_D(04) "-" F_D(02) "-" F_D(02) " "
3126 F_D(02) ":" F_D(02) ":" F_D(02) "."
3127 F_D(06) ", " FMT_D ", %d) -->\n",
3128 (memSizeType) sqlStatement, column,
3129 *year, *month, *day, *hour, *minute, *second,
3130 *micro_second, *time_zone, *is_dst););
3131 } /* sqlColumnTime */
3132
3133
3134
sqlCommit(databaseType database)3135 static void sqlCommit (databaseType database)
3136
3137 {
3138 dbType db;
3139 errInfoType err_info = OKAY_NO_ERROR;
3140
3141 /* sqlCommit */
3142 logFunction(printf("sqlCommit(" FMT_U_MEM ")\n",
3143 (memSizeType) database););
3144 db = (dbType) database;
3145 if (unlikely(db->connection == NULL)) {
3146 logError(printf("sqlCommit: Database is not open.\n"););
3147 raise_error(RANGE_ERROR);
3148 } else if (!db->autoCommit) {
3149 err_info = doExecSql(db->connection, "COMMIT", err_info);
3150 err_info = doExecSql(db->connection, "BEGIN TRANSACTION", err_info);
3151 if (unlikely(err_info != OKAY_NO_ERROR)) {
3152 raise_error(err_info);
3153 } /* if */
3154 } /* if */
3155 logFunction(printf("sqlCommit -->\n"););
3156 } /* sqlCommit */
3157
3158
3159
sqlExecute(sqlStmtType sqlStatement)3160 static void sqlExecute (sqlStmtType sqlStatement)
3161
3162 {
3163 preparedStmtType preparedStmt;
3164 errInfoType err_info = OKAY_NO_ERROR;
3165 int num_tuples;
3166
3167 /* sqlExecute */
3168 logFunction(printf("sqlExecute(" FMT_U_MEM ")\n",
3169 (memSizeType) sqlStatement););
3170 preparedStmt = (preparedStmtType) sqlStatement;
3171 if (unlikely(!allParametersBound(preparedStmt))) {
3172 dbLibError("sqlExecute", "SQLExecute",
3173 "Unbound statement parameter(s).\n");
3174 raise_error(DATABASE_ERROR);
3175 } else {
3176 preparedStmt->fetchOkay = FALSE;
3177 if (preparedStmt->execute_result != NULL) {
3178 PQclear(preparedStmt->execute_result);
3179 } /* if */
3180 preparedStmt->execute_result = PQexecPrepared(preparedStmt->db->connection,
3181 preparedStmt->stmtName,
3182 (int) preparedStmt->param_array_size,
3183 (const_cstriType *) preparedStmt->paramValues,
3184 preparedStmt->paramLengths,
3185 preparedStmt->paramFormats,
3186 1);
3187 if (unlikely(preparedStmt->execute_result == NULL)) {
3188 logError(printf("sqlExecute: PQexecPrepared returns NULL\n"););
3189 preparedStmt->executeSuccessful = FALSE;
3190 raise_error(MEMORY_ERROR);
3191 } else {
3192 preparedStmt->execute_status = PQresultStatus(preparedStmt->execute_result);
3193 if (preparedStmt->execute_status == PGRES_COMMAND_OK) {
3194 preparedStmt->executeSuccessful = TRUE;
3195 if (preparedStmt->implicitCommit && !preparedStmt->db->autoCommit) {
3196 err_info = doExecSql(preparedStmt->db->connection, "COMMIT", err_info);
3197 err_info = doExecSql(preparedStmt->db->connection, "BEGIN TRANSACTION", err_info);
3198 if (unlikely(err_info != OKAY_NO_ERROR)) {
3199 raise_error(err_info);
3200 } /* if */
3201 } /* if */
3202 } else if (preparedStmt->execute_status == PGRES_TUPLES_OK) {
3203 num_tuples = PQntuples(preparedStmt->execute_result);
3204 if (unlikely(num_tuples < 0)) {
3205 dbInconsistent("sqlExecute", "PQntuples");
3206 logError(printf("sqlExecute: PQntuples returns negative number: %d\n",
3207 num_tuples););
3208 preparedStmt->executeSuccessful = FALSE;
3209 raise_error(DATABASE_ERROR);
3210 } else {
3211 preparedStmt->num_tuples = num_tuples;
3212 /* printf("Number of tubles: %d\n", preparedStmt->num_tuples);
3213 printf("Number of columns: %d\n", PQnfields(preparedStmt->execute_result));
3214 printf("Result_column_count: " FMT_U_MEM "\n", preparedStmt->result_column_count);
3215 { int idx;
3216 for (idx = 0; idx < PQnfields(preparedStmt->execute_result); idx++) {
3217 printf("Type of column %d: %d\n", idx, PQftype(preparedStmt->execute_result, idx));
3218 }
3219 } */
3220 preparedStmt->executeSuccessful = TRUE;
3221 preparedStmt->fetch_index = 0;
3222 preparedStmt->increment_index = FALSE;
3223 } /* if */
3224 } else {
3225 setDbErrorMsg("sqlExecute", "PQexecPrepared", preparedStmt->db->connection);
3226 logError(printf("sqlExecute: PQexecPrepared returns a status of %s:\n%s",
3227 PQresStatus(preparedStmt->execute_status),
3228 dbError.message););
3229 preparedStmt->executeSuccessful = FALSE;
3230 raise_error(DATABASE_ERROR);
3231 } /* if */
3232 } /* if */
3233 } /* if */
3234 logFunction(printf("sqlExecute -->\n"););
3235 } /* sqlExecute */
3236
3237
3238
sqlFetch(sqlStmtType sqlStatement)3239 static boolType sqlFetch (sqlStmtType sqlStatement)
3240
3241 {
3242 preparedStmtType preparedStmt;
3243
3244 /* sqlFetch */
3245 logFunction(printf("sqlFetch(" FMT_U_MEM ")\n",
3246 (memSizeType) sqlStatement););
3247 preparedStmt = (preparedStmtType) sqlStatement;
3248 if (unlikely(!preparedStmt->executeSuccessful)) {
3249 dbLibError("sqlFetch", "PQexecPrepared",
3250 "Execute was not successful.\n");
3251 logError(printf("sqlFetch: Execute was not successful.\n"););
3252 preparedStmt->fetchOkay = FALSE;
3253 raise_error(DATABASE_ERROR);
3254 } else if (preparedStmt->result_column_count == 0 ||
3255 preparedStmt->execute_status == PGRES_COMMAND_OK) {
3256 preparedStmt->fetchOkay = FALSE;
3257 } else if (preparedStmt->execute_status == PGRES_TUPLES_OK) {
3258 if (!preparedStmt->increment_index) {
3259 preparedStmt->increment_index = TRUE;
3260 } else {
3261 preparedStmt->fetch_index++;
3262 } /* if */
3263 preparedStmt->fetchOkay =
3264 preparedStmt->fetch_index < preparedStmt->num_tuples;
3265 } else {
3266 preparedStmt->fetchOkay = FALSE;
3267 } /* if */
3268 logFunction(printf("sqlFetch --> %d\n", preparedStmt->fetchOkay););
3269 return preparedStmt->fetchOkay;
3270 } /* sqlFetch */
3271
3272
3273
sqlGetAutoCommit(databaseType database)3274 static boolType sqlGetAutoCommit (databaseType database)
3275
3276 {
3277 dbType db;
3278 boolType autoCommit;
3279
3280 /* sqlGetAutoCommit */
3281 logFunction(printf("sqlGetAutoCommit(" FMT_U_MEM ")\n",
3282 (memSizeType) database););
3283 db = (dbType) database;
3284 if (unlikely(db->connection == NULL)) {
3285 logError(printf("sqlGetAutoCommit: Database is not open.\n"););
3286 raise_error(RANGE_ERROR);
3287 autoCommit = FALSE;
3288 } else {
3289 autoCommit = db->autoCommit;
3290 } /* if */
3291 logFunction(printf("sqlGetAutoCommit --> %d\n", autoCommit););
3292 return autoCommit;
3293 } /* sqlGetAutoCommit */
3294
3295
3296
sqlIsNull(sqlStmtType sqlStatement,intType column)3297 static boolType sqlIsNull (sqlStmtType sqlStatement, intType column)
3298
3299 {
3300 preparedStmtType preparedStmt;
3301 boolType isNull;
3302
3303 /* sqlIsNull */
3304 logFunction(printf("sqlIsNull(" FMT_U_MEM ", " FMT_D ")\n",
3305 (memSizeType) sqlStatement, column););
3306 preparedStmt = (preparedStmtType) sqlStatement;
3307 if (unlikely(!preparedStmt->fetchOkay || column < 1 ||
3308 (uintType) column > preparedStmt->result_column_count)) {
3309 logError(printf("sqlIsNull: Fetch okay: %d, column: " FMT_D
3310 ", max column: " FMT_U_MEM ".\n",
3311 preparedStmt->fetchOkay, column,
3312 preparedStmt->result_column_count););
3313 raise_error(RANGE_ERROR);
3314 isNull = FALSE;
3315 } else {
3316 isNull = PQgetisnull(preparedStmt->execute_result,
3317 preparedStmt->fetch_index,
3318 (int) column - 1);
3319 } /* if */
3320 logFunction(printf("sqlIsNull --> %s\n", isNull ? "TRUE" : "FALSE"););
3321 return isNull;
3322 } /* sqlIsNull */
3323
3324
3325
sqlPrepare(databaseType database,const const_striType sqlStatementStri)3326 static sqlStmtType sqlPrepare (databaseType database,
3327 const const_striType sqlStatementStri)
3328
3329 {
3330 dbType db;
3331 striType statementStri;
3332 cstriType query;
3333 PGresult *prepare_result;
3334 errInfoType err_info = OKAY_NO_ERROR;
3335 preparedStmtType preparedStmt;
3336
3337 /* sqlPrepare */
3338 logFunction(printf("sqlPrepare(" FMT_U_MEM ", \"%s\")\n",
3339 (memSizeType) database,
3340 striAsUnquotedCStri(sqlStatementStri)););
3341 db = (dbType) database;
3342 if (unlikely(db->connection == NULL)) {
3343 logError(printf("sqlPrepare: Database is not open.\n"););
3344 err_info = RANGE_ERROR;
3345 preparedStmt = NULL;
3346 } else {
3347 statementStri = processStatementStri(sqlStatementStri, &err_info);
3348 if (statementStri == NULL) {
3349 preparedStmt = NULL;
3350 } else {
3351 query = stri_to_cstri8(statementStri, &err_info);
3352 if (unlikely(query == NULL)) {
3353 preparedStmt = NULL;
3354 } else {
3355 if (unlikely(!ALLOC_RECORD2(preparedStmt, preparedStmtRecord,
3356 count.prepared_stmt, count.prepared_stmt_bytes))) {
3357 err_info = MEMORY_ERROR;
3358 } else {
3359 memset(preparedStmt, 0, sizeof(preparedStmtRecord));
3360 preparedStmt->stmtNum = db->nextStmtNum;
3361 db->nextStmtNum++;
3362 sprintf(preparedStmt->stmtName, "prepstat_" FMT_U, preparedStmt->stmtNum);
3363 prepare_result = PQprepare(db->connection, preparedStmt->stmtName, query, 0, NULL);
3364 if (unlikely(prepare_result == NULL)) {
3365 FREE_RECORD2(preparedStmt, preparedStmtRecord,
3366 count.prepared_stmt, count.prepared_stmt_bytes);
3367 err_info = MEMORY_ERROR;
3368 preparedStmt = NULL;
3369 } else {
3370 if (PQresultStatus(prepare_result) != PGRES_COMMAND_OK) {
3371 setDbErrorMsg("sqlPrepare", "PQprepare", db->connection);
3372 logError(printf("sqlPrepare: PQprepare returns a status of %s:\n%s",
3373 PQresStatus(PQresultStatus(prepare_result)),
3374 dbError.message););
3375 FREE_RECORD2(preparedStmt, preparedStmtRecord,
3376 count.prepared_stmt, count.prepared_stmt_bytes);
3377 err_info = DATABASE_ERROR;
3378 preparedStmt = NULL;
3379 } else {
3380 preparedStmt->usage_count = 1;
3381 preparedStmt->sqlFunc = db->sqlFunc;
3382 preparedStmt->integerDatetimes = db->integerDatetimes;
3383 preparedStmt->implicitCommit = implicitCommit(query);
3384 preparedStmt->executeSuccessful = FALSE;
3385 preparedStmt->execute_result = NULL;
3386 preparedStmt->fetchOkay = FALSE;
3387 preparedStmt->db = db;
3388 db->usage_count++;
3389 err_info = setupParametersAndResult(preparedStmt);
3390 if (unlikely(err_info != OKAY_NO_ERROR)) {
3391 freePreparedStmt((sqlStmtType) preparedStmt);
3392 preparedStmt = NULL;
3393 } /* if */
3394 } /* if */
3395 PQclear(prepare_result);
3396 } /* if */
3397 } /* if */
3398 free_cstri8(query, statementStri);
3399 } /* if */
3400 FREE_STRI(statementStri, sqlStatementStri->size * MAX_BIND_VAR_SIZE);
3401 } /* if */
3402 } /* if */
3403 if (unlikely(err_info != OKAY_NO_ERROR)) {
3404 raise_error(err_info);
3405 } /* if */
3406 logFunction(printf("sqlPrepare --> " FMT_U_MEM "\n",
3407 (memSizeType) preparedStmt););
3408 return (sqlStmtType) preparedStmt;
3409 } /* sqlPrepare */
3410
3411
3412
sqlRollback(databaseType database)3413 static void sqlRollback (databaseType database)
3414
3415 {
3416 dbType db;
3417 errInfoType err_info = OKAY_NO_ERROR;
3418
3419 /* sqlRollback */
3420 logFunction(printf("sqlRollback(" FMT_U_MEM ")\n",
3421 (memSizeType) database););
3422 db = (dbType) database;
3423 if (unlikely(db->connection == NULL)) {
3424 logError(printf("sqlRollback: Database is not open.\n"););
3425 raise_error(RANGE_ERROR);
3426 } else if (!db->autoCommit) {
3427 err_info = doExecSql(db->connection, "ROLLBACK", err_info);
3428 err_info = doExecSql(db->connection, "BEGIN TRANSACTION", err_info);
3429 if (unlikely(err_info != OKAY_NO_ERROR)) {
3430 raise_error(err_info);
3431 } /* if */
3432 } /* if */
3433 logFunction(printf("sqlRollback -->\n"););
3434 } /* sqlRollback */
3435
3436
3437
sqlSetAutoCommit(databaseType database,boolType autoCommit)3438 static void sqlSetAutoCommit (databaseType database, boolType autoCommit)
3439
3440 {
3441 dbType db;
3442 errInfoType err_info = OKAY_NO_ERROR;
3443
3444 /* sqlSetAutoCommit */
3445 logFunction(printf("sqlSetAutoCommit(" FMT_U_MEM ", %d)\n",
3446 (memSizeType) database, autoCommit););
3447 db = (dbType) database;
3448 if (unlikely(db->connection == NULL)) {
3449 logError(printf("sqlSetAutoCommit: Database is not open.\n"););
3450 raise_error(RANGE_ERROR);
3451 } else {
3452 if (db->autoCommit != autoCommit) {
3453 if (autoCommit) {
3454 err_info = doExecSql(db->connection, "COMMIT", err_info);
3455 } else {
3456 err_info = doExecSql(db->connection, "BEGIN TRANSACTION", err_info);
3457 } /* if */
3458 if (unlikely(err_info != OKAY_NO_ERROR)) {
3459 raise_error(err_info);
3460 } else {
3461 db->autoCommit = autoCommit;
3462 } /* if */
3463 } /* if */
3464 } /* if */
3465 logFunction(printf("sqlSetAutoCommit -->\n"););
3466 } /* sqlSetAutoCommit */
3467
3468
3469
sqlStmtColumnCount(sqlStmtType sqlStatement)3470 static intType sqlStmtColumnCount (sqlStmtType sqlStatement)
3471
3472 {
3473 preparedStmtType preparedStmt;
3474 intType columnCount;
3475
3476 /* sqlStmtColumnCount */
3477 logFunction(printf("sqlStmtColumnCount(" FMT_U_MEM ")\n",
3478 (memSizeType) sqlStatement););
3479 preparedStmt = (preparedStmtType) sqlStatement;
3480 columnCount = (intType) preparedStmt->result_column_count;
3481 logFunction(printf("sqlStmtColumnCount --> " FMT_D "\n", columnCount););
3482 return columnCount;
3483 } /* sqlStmtColumnCount */
3484
3485
3486
sqlStmtColumnName(sqlStmtType sqlStatement,intType column)3487 static striType sqlStmtColumnName (sqlStmtType sqlStatement, intType column)
3488
3489 {
3490 preparedStmtType preparedStmt;
3491 cstriType col_name;
3492 errInfoType err_info = OKAY_NO_ERROR;
3493 striType name;
3494
3495 /* sqlStmtColumnName */
3496 logFunction(printf("sqlStmtColumnName(" FMT_U_MEM ", " FMT_D ")\n",
3497 (memSizeType) sqlStatement, column););
3498 preparedStmt = (preparedStmtType) sqlStatement;
3499 if (unlikely(!preparedStmt->executeSuccessful)) {
3500 dbLibError("sqlStmtColumnName", "PQexecPrepared",
3501 "Execute was not successful.\n");
3502 logError(printf("sqlStmtColumnName: Execute was not successful.\n"););
3503 raise_error(DATABASE_ERROR);
3504 name = NULL;
3505 } else if (unlikely(column < 1 ||
3506 (uintType) column > preparedStmt->result_column_count)) {
3507 logError(printf("sqlStmtColumnName: column: " FMT_D
3508 ", max column: " FMT_U_MEM ".\n",
3509 column, preparedStmt->result_column_count););
3510 raise_error(RANGE_ERROR);
3511 name = NULL;
3512 } else {
3513 col_name = PQfname(preparedStmt->execute_result,
3514 (int) column - 1);
3515 if (unlikely(col_name == NULL)) {
3516 dbInconsistent("sqlStmtColumnName", "PQfname");
3517 logError(printf("sqlStmtColumnName: Column " FMT_D ": "
3518 "PQfname returns NULL.\n",
3519 column););
3520 raise_error(DATABASE_ERROR);
3521 name = NULL;
3522 } else {
3523 name = cstri8_to_stri(col_name, &err_info);
3524 if (unlikely(name == NULL)) {
3525 raise_error(err_info);
3526 } /* if */
3527 } /* if */
3528 } /* if */
3529 logFunction(printf("sqlStmtColumnName --> \"%s\"\n",
3530 striAsUnquotedCStri(name)););
3531 return name;
3532 } /* sqlStmtColumnName */
3533
3534
3535
setupFuncTable(void)3536 static boolType setupFuncTable (void)
3537
3538 { /* setupFuncTable */
3539 if (sqlFunc == NULL) {
3540 if (ALLOC_RECORD(sqlFunc, sqlFuncRecord, count.sql_func)) {
3541 memset(sqlFunc, 0, sizeof(sqlFuncRecord));
3542 sqlFunc->freeDatabase = &freeDatabase;
3543 sqlFunc->freePreparedStmt = &freePreparedStmt;
3544 sqlFunc->sqlBindBigInt = &sqlBindBigInt;
3545 sqlFunc->sqlBindBigRat = &sqlBindBigRat;
3546 sqlFunc->sqlBindBool = &sqlBindBool;
3547 sqlFunc->sqlBindBStri = &sqlBindBStri;
3548 sqlFunc->sqlBindDuration = &sqlBindDuration;
3549 sqlFunc->sqlBindFloat = &sqlBindFloat;
3550 sqlFunc->sqlBindInt = &sqlBindInt;
3551 sqlFunc->sqlBindNull = &sqlBindNull;
3552 sqlFunc->sqlBindStri = &sqlBindStri;
3553 sqlFunc->sqlBindTime = &sqlBindTime;
3554 sqlFunc->sqlClose = &sqlClose;
3555 sqlFunc->sqlColumnBigInt = &sqlColumnBigInt;
3556 sqlFunc->sqlColumnBigRat = &sqlColumnBigRat;
3557 sqlFunc->sqlColumnBool = &sqlColumnBool;
3558 sqlFunc->sqlColumnBStri = &sqlColumnBStri;
3559 sqlFunc->sqlColumnDuration = &sqlColumnDuration;
3560 sqlFunc->sqlColumnFloat = &sqlColumnFloat;
3561 sqlFunc->sqlColumnInt = &sqlColumnInt;
3562 sqlFunc->sqlColumnStri = &sqlColumnStri;
3563 sqlFunc->sqlColumnTime = &sqlColumnTime;
3564 sqlFunc->sqlCommit = &sqlCommit;
3565 sqlFunc->sqlExecute = &sqlExecute;
3566 sqlFunc->sqlFetch = &sqlFetch;
3567 sqlFunc->sqlGetAutoCommit = &sqlGetAutoCommit;
3568 sqlFunc->sqlIsNull = &sqlIsNull;
3569 sqlFunc->sqlPrepare = &sqlPrepare;
3570 sqlFunc->sqlRollback = &sqlRollback;
3571 sqlFunc->sqlSetAutoCommit = &sqlSetAutoCommit;
3572 sqlFunc->sqlStmtColumnCount = &sqlStmtColumnCount;
3573 sqlFunc->sqlStmtColumnName = &sqlStmtColumnName;
3574 } /* if */
3575 } /* if */
3576 return sqlFunc != NULL;
3577 } /* setupFuncTable */
3578
3579
3580
sqlOpenPost(const const_striType host,intType port,const const_striType dbName,const const_striType user,const const_striType password)3581 databaseType sqlOpenPost (const const_striType host, intType port,
3582 const const_striType dbName, const const_striType user,
3583 const const_striType password)
3584
3585 {
3586 const_cstriType host8;
3587 const_cstriType dbName8;
3588 const_cstriType user8;
3589 const_cstriType password8;
3590 char portBuffer[INTTYPE_DECIMAL_SIZE + NULL_TERMINATION_LEN];
3591 cstriType pgport;
3592 dbRecord db;
3593 const_cstriType setting;
3594 errInfoType err_info = OKAY_NO_ERROR;
3595 dbType database;
3596
3597 /* sqlOpenPost */
3598 logFunction(printf("sqlOpenPost(\"%s\", ",
3599 striAsUnquotedCStri(host));
3600 printf(FMT_D ", \"%s\", ",
3601 port, striAsUnquotedCStri(dbName));
3602 printf("\"%s\", ", striAsUnquotedCStri(user));
3603 printf("\"%s\")\n", striAsUnquotedCStri(password)););
3604 if (!findDll()) {
3605 logError(printf("sqlOpenPost: findDll() failed\n"););
3606 err_info = DATABASE_ERROR;
3607 database = NULL;
3608 } else if (unlikely((host8 = stri_to_cstri8(host, &err_info)) == NULL)) {
3609 database = NULL;
3610 } else {
3611 dbName8 = stri_to_cstri8(dbName, &err_info);
3612 if (dbName8 == NULL) {
3613 database = NULL;
3614 } else {
3615 user8 = stri_to_cstri8(user, &err_info);
3616 if (user8 == NULL) {
3617 database = NULL;
3618 } else {
3619 password8 = stri_to_cstri8(password, &err_info);
3620 if (password8 == NULL) {
3621 database = NULL;
3622 } else {
3623 if (port == 0) {
3624 /* Use the default value for port, which is probably DEFAULT_PORT. */
3625 pgport = NULL;
3626 } else {
3627 sprintf(portBuffer, FMT_D, port);
3628 pgport = portBuffer;
3629 } /* if */
3630 db.connection = PQsetdbLogin(host8[0] == '\0' ? NULL : host8,
3631 pgport, NULL /* pgoptions */, NULL /* pgtty */,
3632 dbName8, user8, password8);
3633 if (unlikely(db.connection == NULL)) {
3634 logError(printf("sqlOpenPost: PQsetdbLogin(\"%s\", ... "
3635 "\"%s\", \"%s\", \"%s\") returns NULL\n",
3636 host8[0] == '\0' ? "NULL" : host8,
3637 dbName8, user8, password8););
3638 err_info = MEMORY_ERROR;
3639 database = NULL;
3640 } else if (PQstatus(db.connection) != CONNECTION_OK) {
3641 setDbErrorMsg("sqlOpenPost", "PQsetdbLogin", db.connection);
3642 logError(printf("sqlOpenPost: PQsetdbLogin(\"%s\", ... "
3643 "\"%s\", \"%s\", \"%s\") error:\n"
3644 "status=%d\nerror: %s\n",
3645 host8[0] == '\0' ? "NULL" : host8,
3646 dbName8, user8, password8,
3647 PQstatus(db.connection),
3648 dbError.message););
3649 err_info = DATABASE_ERROR;
3650 PQfinish(db.connection);
3651 database = NULL;
3652 } else if (PQsetClientEncoding(db.connection, "UNICODE") != 0) {
3653 setDbErrorMsg("sqlOpenPost", "PQsetClientEncoding", db.connection);
3654 logError(printf("sqlOpenPost: PQsetClientEncoding does not return 0:\n%s\n",
3655 dbError.message););
3656 err_info = DATABASE_ERROR;
3657 PQfinish(db.connection);
3658 database = NULL;
3659 } else if (unlikely(!setupFuncTable() ||
3660 !ALLOC_RECORD2(database, dbRecord,
3661 count.database, count.database_bytes))) {
3662 err_info = MEMORY_ERROR;
3663 PQfinish(db.connection);
3664 database = NULL;
3665 } else {
3666 memset(database, 0, sizeof(dbRecord));
3667 database->usage_count = 1;
3668 database->sqlFunc = sqlFunc;
3669 database->driver = DB_CATEGORY_POSTGRESQL;
3670 database->connection = db.connection;
3671 setting = PQparameterStatus(db.connection, "integer_datetimes");
3672 database->integerDatetimes = setting != NULL && strcmp(setting, "on") == 0;
3673 database->nextStmtNum = 1;
3674 database->autoCommit = TRUE;
3675 } /* if */
3676 free_cstri8(password8, password);
3677 } /* if */
3678 free_cstri8(user8, user);
3679 } /* if */
3680 free_cstri8(dbName8, dbName);
3681 } /* if */
3682 free_cstri8(host8, host);
3683 } /* if */
3684 if (unlikely(err_info != OKAY_NO_ERROR)) {
3685 raise_error(err_info);
3686 } /* if */
3687 logFunction(printf("sqlOpenPost --> " FMT_U_MEM "\n",
3688 (memSizeType) database););
3689 return (databaseType) database;
3690 } /* sqlOpenPost */
3691
3692 #else
3693
3694
3695
sqlOpenPost(const const_striType host,intType port,const const_striType dbName,const const_striType user,const const_striType password)3696 databaseType sqlOpenPost (const const_striType host, intType port,
3697 const const_striType dbName, const const_striType user,
3698 const const_striType password)
3699
3700 { /* sqlOpenPost */
3701 logError(printf("sqlOpenPost(\"%s\", ",
3702 striAsUnquotedCStri(host));
3703 printf(FMT_D ", \"%s\", ",
3704 port, striAsUnquotedCStri(dbName));
3705 printf("\"%s\", ", striAsUnquotedCStri(user));
3706 printf("\"%s\"): PostgreSQL driver not present.\n",
3707 striAsUnquotedCStri(password)););
3708 raise_error(RANGE_ERROR);
3709 return NULL;
3710 } /* sqlOpenPost */
3711
3712 #endif
3713