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 *) &param->buffer[8] =
1721               (int32Type) htonl((uint32Type) day);
1722           *(int32Type *) &param->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 *) &param->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