1 /*
2  * libdbi - database independent abstraction layer for C.
3  * Copyright (C) 2001-2002, David Parker and Mark Tobenkin.
4  * http://libdbi.sourceforge.net
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * dbd_pgsql.c: PostgreSQL database support (using libpq)
21  * Copyright (C) 2001-2002, David A. Parker <david@neongoat.com>.
22  * http://libdbi.sourceforge.net
23  *
24  * $Id: dbd_pgsql.c,v 1.69 2013/02/08 01:01:31 mhoenicka Exp $
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #define _GNU_SOURCE /* we need asprintf */
32 
33 #ifndef HAVE_ATOLL
34 long long atoll(const char *str);
35 #endif
36 
37 #ifndef HAVE_STRTOLL
38 long long strtoll(const char *nptr, char **endptr, int base);
39 #endif
40 
41 /* In 7.4 PQfreeNotify was deprecated and PQfreemem is used instead.  A
42    macro exists in 7.4 for backwards compatibility. */
43 #ifndef PQfreeNotify   /* must be earlier than 7.4 */
44 #define PQfreemem PQfreeNotify
45 #endif
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h> /* for isdigit() */
51 
52 #include <dbi/dbi.h>
53 #include <dbi/dbi-dev.h>
54 #include <dbi/dbd.h>
55 
56 #include <libpq-fe.h>
57 #include "dbd_pgsql.h"
58 
59 static const dbi_info_t driver_info = {
60 	"pgsql",
61 	"PostgreSQL database support (using libpq)",
62 	"David A. Parker <david@neongoat.com>",
63 	"http://libdbi-drivers.sourceforge.net",
64 	"dbd_pgsql v" VERSION,
65 	__DATE__
66 };
67 
68 static const char *custom_functions[] = PGSQL_CUSTOM_FUNCTIONS;
69 static const char *reserved_words[] = PGSQL_RESERVED_WORDS;
70 
71 /* encoding strings, array is terminated by a pair of empty strings */
72 static const char pgsql_encoding_hash[][16] = {
73   /* PostgreSQL , www.iana.org */
74   "SQL_ASCII", "US-ASCII",
75   "EUC_JP", "EUC-JP",
76   "EUC_KR", "EUC-KR",
77   "UNICODE", "UTF-8",
78   "UTF8", "UTF-8",
79   "LATIN1", "ISO-8859-1",
80   "LATIN2", "ISO-8859-2",
81   "LATIN3", "ISO-8859-3",
82   "LATIN4", "ISO-8859-4",
83   "LATIN5", "ISO-8859-9",
84   "LATIN6", "ISO-8859-10",
85   "LATIN7", "ISO-8859-13",
86   "LATIN8", "ISO-8859-14",
87   "LATIN9", "ISO-8859-15",
88   "LATIN10", "ISO-8859-16",
89   "ISO-8859-5", "ISO-8859-5",
90   "ISO-8859-6", "ISO-8859-6",
91   "ISO-8859-7", "ISO-8859-7",
92   "ISO-8859-8", "ISO-8859-8",
93   "KOI8", "KOI8-R",
94   "WIN", "windows-1251",
95   "ALT", "IBM866",
96   "", ""
97 };
98 
99 /* forward declarations of internal functions */
100 void _translate_postgresql_type(unsigned int oid, unsigned short *type, unsigned int *attribs);
101 void _get_field_info(dbi_result_t *result);
102 void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx);
103 int _dbd_real_connect(dbi_conn_t *conn, const char *db);
104 char *_unescape_hex_binary(char* raw, size_t in_len, size_t* out_len);
105 int _digit_to_number(const char c);
106 
107 /* this function is available through the PostgreSQL client library, but it
108    is not declared in any of their headers. I hope this won't break anything */
109 const char *pg_encoding_to_char(int encoding_id);
110 
111 
112 /* these are helpers for dbd_real_connect */
113 #define CONNINFO_APPEND_ESCAPED(conninfo, fmt, key, value )          \
114     do {                                                             \
115         size_t orig_size = strlen( value );                          \
116         char *value_escaped = malloc( 2 * orig_size + 1 );           \
117         _dbd_escape_chars( value_escaped, value, orig_size, "\\'" ); \
118         CONNINFO_APPEND( conninfo, fmt, key, value_escaped );        \
119         free( value_escaped );                                       \
120     } while(0)
121 
122 #define CONNINFO_APPEND(conninfo, fmt, key, value )                  \
123     do {                                                             \
124         char *tmp = conninfo;                                        \
125         if( conninfo ) {                                             \
126             asprintf( &conninfo, "%s " fmt, tmp, key, value );       \
127             free( tmp );                                             \
128         }                                                            \
129         else                                                         \
130             asprintf( &conninfo, fmt, key, value );                  \
131 	} while(0)
132 
133 
134 /* base36 decoding to convert the 5 alphanumeric chars of SQLSTATE to a 32bit int */
base36decode(char * base36)135 int base36decode(char *base36) {
136     int len = strlen(base36);
137     int output = 0;
138     int pos = 0;
139 
140     for (; pos < len; pos++) {
141         char c = base36[pos];
142         if ( ((c - '0') >= 0) && ((c - '0') <= 9) ) {
143             c = c - '0';
144         } else {
145             c = c - 'A' + 10;
146         }
147         output = 36 * output + c;
148     }
149 
150     return output;
151 }
152 
153 /* real code starts here */
dbd_register_driver(const dbi_info_t ** _driver_info,const char *** _custom_functions,const char *** _reserved_words)154 void dbd_register_driver(const dbi_info_t **_driver_info, const char ***_custom_functions, const char ***_reserved_words) {
155 	/* this is the first function called after the driver module is loaded into memory */
156 	*_driver_info = &driver_info;
157 	*_custom_functions = custom_functions;
158 	*_reserved_words = reserved_words;
159 }
160 
dbd_initialize(dbi_driver_t * driver)161 int dbd_initialize(dbi_driver_t *driver) {
162 	/* perform any database-specific server initialization.
163 	 * this is called right after dbd_register_driver().
164 	 * return -1 on error, 0 on success. if -1 is returned, the driver will not
165 	 * be added to the list of available drivers. */
166 
167         /* this indicates the driver can be safely unloaded when libdbi is
168 	   shut down. Change the value to '0' (zero) if the driver, or a
169 	   library it is linked against, installs exit handlers via
170 	   atexit() */
171         _dbd_register_driver_cap(driver, "safe_dlclose", 1);
172 
173 	/* this indicates the database engine supports transactions */
174         _dbd_register_driver_cap(driver, "transaction_support", 1);
175 
176 	/* this indicates the database engine supports savepoints */
177         _dbd_register_driver_cap(driver, "savepoint_support", 1);
178 
179 	return 0;
180 }
181 
dbd_finalize(dbi_driver_t * driver)182 int dbd_finalize(dbi_driver_t *driver) {
183 	/* perform any database-specific client library shutdown.
184 	 * this is called right before dlclose()ing the driver.
185 	 * return -1 on error, 0 on success. */
186 
187 	return 0;
188 }
189 
dbd_connect(dbi_conn_t * conn)190 int dbd_connect(dbi_conn_t *conn) {
191   return _dbd_real_connect(conn, NULL);
192 }
193 
_dbd_real_connect(dbi_conn_t * conn,const char * db)194 int _dbd_real_connect(dbi_conn_t *conn, const char *db) {
195 	const char *dbname;
196 	const char *encoding = dbi_conn_get_option(conn, "encoding");
197 
198 	PGconn *pgconn;
199 	char *conninfo = NULL;
200 
201 	const char *optname = NULL;
202 	const char *pgopt;
203 	const char *optval;
204 	int         optval_num;
205 	int have_port = 0;
206 
207 	/* PQconnectdb accepts additional options as a string of
208 	   "key=value" pairs. Assemble that string from the option
209 	   list */
210 	while(( pgopt = optname = dbi_conn_get_option_list( conn, optname ) ))
211 	{
212 		/* Ignore "encoding" and "dbname"; we'll deal with them later */
213 	  if ( !strcmp( pgopt, "encoding" ) || !strcmp( pgopt, "dbname" ) ) {
214 	    continue;
215 	  }
216 
217 	  /* Map "username" to "user" */
218 	  else if( !strcmp( pgopt, "username" ) ) {
219 	    pgopt = "user";
220 	  }
221 
222 	  else if (!strcmp(pgopt, "timeout")) {
223 	    pgopt = "connect_timeout";
224 	  }
225 
226 	  /* Map "pgsql_foo" to "foo" */
227 	  else if( !strncmp( pgopt, "pgsql_", 6 ) ) {
228 	    pgopt += 6;
229 	  }
230 
231 	  /* Accept these non-pgsql_ options but discard all others */
232 	  else if (strcmp(pgopt, "password")
233 		   && strcmp(pgopt, "host")
234 		   && strcmp(pgopt, "port")) {
235 	    continue;
236 	  }
237 
238 	  if (!strcmp(pgopt, "port")) {
239 	    have_port++;
240 	  }
241 
242 	  optval     = dbi_conn_get_option( conn, optname );
243 	  optval_num = dbi_conn_get_option_numeric( conn, optname );
244 
245 	  if( optval ) {
246 	    CONNINFO_APPEND_ESCAPED( conninfo, "%s='%s'", pgopt, optval );
247 	  }
248 	  else {
249 	    CONNINFO_APPEND( conninfo, "%s='%d'", pgopt, optval_num );
250 	  }
251 	}
252 
253 	if (db && *db) {
254 	  dbname = db;
255 	}
256 	else {
257 	  dbname = dbi_conn_get_option(conn, "dbname");
258 	}
259 
260 	if( dbname )
261 		CONNINFO_APPEND_ESCAPED( conninfo, "%s='%s'", "dbname", dbname );
262 
263 	/* if no port was specified, fill in the default PostgreSQL port */
264 	if (!have_port) {
265 	    CONNINFO_APPEND( conninfo, "%s='%d'", "port", 5432 );
266 	}
267 
268 	/* send an empty string instead of NULL if there are no options */
269 	pgconn = PQconnectdb(conninfo ? conninfo : "");
270 	if (conninfo) free(conninfo);
271 	if (!pgconn) return -1;
272 
273 	if (PQstatus(pgconn) == CONNECTION_BAD) {
274 		conn->connection = (void *)pgconn; // still need this set so _error_handler can grab information
275 		_dbd_internal_error_handler(conn, NULL, DBI_ERROR_DBD);
276 		PQfinish(pgconn);
277 		conn->connection = NULL; // pgconn no longer valid
278 		return -2;
279 	}
280 	else {
281 		conn->connection = (void *)pgconn;
282 		if (dbname) conn->current_db = strdup(dbname);
283 	}
284 
285 	if (encoding && *encoding) {
286 	  /* set connection encoding */
287 	  if (strcmp(encoding, "auto")) {
288 	    if (PQsetClientEncoding(pgconn, dbd_encoding_from_iana(encoding))) {
289 /* 	      printf("could not set client encoding to %s\n", dbd_encoding_from_iana(encoding)); */
290 	    }
291 	  }
292 	  /* else: by default, pgsql uses the database encoding
293 	     as the client encoding, nothing to do */
294 	}
295 
296 	return 0;
297 }
298 
dbd_disconnect(dbi_conn_t * conn)299 int dbd_disconnect(dbi_conn_t *conn) {
300   if (conn->connection) {
301     PQfinish((PGconn *)conn->connection);
302   }
303   return 0;
304 }
305 
dbd_fetch_row(dbi_result_t * result,unsigned long long rowidx)306 int dbd_fetch_row(dbi_result_t *result, unsigned long long rowidx) {
307 	dbi_row_t *row = NULL;
308 
309 	if (result->result_state == NOTHING_RETURNED) return 0;
310 
311 	if (result->result_state == ROWS_RETURNED) {
312 		/* get row here */
313 		row = _dbd_row_allocate(result->numfields);
314 		_get_row_data(result, row, rowidx);
315 		_dbd_row_finalize(result, row, rowidx);
316 	}
317 
318 	return 1; /* 0 on error, 1 on successful fetchrow */
319 }
320 
dbd_free_query(dbi_result_t * result)321 int dbd_free_query(dbi_result_t *result) {
322 	PQclear((PGresult *)result->result_handle);
323 	return 0;
324 }
325 
dbd_goto_row(dbi_result_t * result,unsigned long long rowidx,unsigned long long currowidx)326 int dbd_goto_row(dbi_result_t *result, unsigned long long rowidx, unsigned long long currowidx) {
327 	/* libpq doesn't have to do anything, the row index is specified when
328 	 * fetching fields */
329 	return 1;
330 }
331 
dbd_get_socket(dbi_conn_t * conn)332 int dbd_get_socket(dbi_conn_t *conn)
333 {
334 	PGconn *pgconn = (PGconn*) conn->connection;
335 
336 	if(!pgconn) return -1;
337 
338 	return PQsocket(pgconn);
339 }
340 
dbd_get_encoding(dbi_conn_t * conn)341 const char *dbd_get_encoding(dbi_conn_t *conn){
342 	const char* my_enc;
343 	int n_encoding;
344 	const char* encodingopt;
345 	char* sql_cmd;
346 	dbi_result dbires = NULL;
347 	PGconn *pgconn = (PGconn*) conn->connection;
348 
349 	if(!pgconn) return NULL;
350 
351 	encodingopt = dbi_conn_get_option(conn, "encoding");
352 	if (encodingopt && !strcmp(encodingopt, "auto")) {
353 
354 	  /* this is somewhat murky as the pg_encoding_to_char()
355 	     function is not declared properly by the PostgreSQL client
356 	     library headers.  This may indicate that it is not supposed
357 	     to be exported or that it may disappear without a trace
358 	     eventually. If it breaks, use a query "SHOW CLIENT_ENCODING"
359 	     instead */
360 	  my_enc = pg_encoding_to_char(PQclientEncoding(pgconn));
361 /*  	  printf("use PQclientEncoding, auto\n"); */
362 	}
363 	else if (encodingopt) {
364 	  my_enc = pg_encoding_to_char(PQclientEncoding(pgconn));
365 /*  	  printf("use PQclientEncoding, %s\n", encodingopt); */
366 	}
367 	else {
368 	  asprintf(&sql_cmd, "SELECT encoding FROM pg_database WHERE datname='%s'", conn->current_db);
369 
370 	  dbires = dbi_conn_query(conn, sql_cmd);
371 	  free(sql_cmd);
372 
373 	  if (dbires && dbi_result_next_row(dbires)) {
374 	    n_encoding = dbi_result_get_int_idx(dbires, 1);
375 	    my_enc = pg_encoding_to_char(n_encoding);
376 /*  	    printf("select returned encoding %d<<%s\n", n_encoding, my_enc); */
377 	  }
378 	}
379 
380 	if (!my_enc) {
381 	  return NULL;
382 	}
383 	else {
384 	  return dbd_encoding_to_iana(my_enc);
385 	}
386 }
387 
dbd_encoding_to_iana(const char * db_encoding)388 const char* dbd_encoding_to_iana(const char *db_encoding) {
389   int i = 0;
390 
391   /* loop over all even entries in hash and compare to penc */
392   while (*pgsql_encoding_hash[i]) {
393     if (!strcmp(pgsql_encoding_hash[i], db_encoding)) {
394       /* return corresponding odd entry */
395       return pgsql_encoding_hash[i+1];
396     }
397     i+=2;
398   }
399 
400   /* don't know how to translate, return original encoding */
401   return db_encoding;
402 }
403 
dbd_encoding_from_iana(const char * iana_encoding)404 const char* dbd_encoding_from_iana(const char *iana_encoding) {
405   int i = 0;
406 
407   /* loop over all odd entries in hash and compare to ienc */
408   while (*pgsql_encoding_hash[i+1]) {
409     if (!strcmp(pgsql_encoding_hash[i+1], iana_encoding)) {
410       /* return corresponding even entry */
411       return pgsql_encoding_hash[i];
412     }
413     i+=2;
414   }
415 
416   /* don't know how to translate, return original encoding */
417   return iana_encoding;
418 }
419 
dbd_get_engine_version(dbi_conn_t * conn,char * versionstring)420 char *dbd_get_engine_version(dbi_conn_t *conn, char *versionstring) {
421   snprintf(versionstring, VERSIONSTRING_LENGTH, "%d", PQserverVersion((PGconn *)conn->connection));
422   return versionstring;
423 }
424 
dbd_list_dbs(dbi_conn_t * conn,const char * pattern)425 dbi_result_t *dbd_list_dbs(dbi_conn_t *conn, const char *pattern) {
426 	dbi_result_t *res;
427 	char *sql_cmd;
428 
429 	if (pattern == NULL) {
430 		return dbd_query(conn, "SELECT datname FROM pg_database");
431 	}
432 	else {
433 		asprintf(&sql_cmd, "SELECT datname FROM pg_database WHERE datname LIKE '%s'", pattern);
434 		res = dbd_query(conn, sql_cmd);
435 		free(sql_cmd);
436 		return res;
437 	}
438 }
439 
dbd_list_tables(dbi_conn_t * conn,const char * db,const char * pattern)440 dbi_result_t *dbd_list_tables(dbi_conn_t *conn, const char *db, const char *pattern) {
441 	if (db == NULL) {
442 		return NULL;
443 	}
444 
445 	if (pattern == NULL) {
446 		return (dbi_result_t *)dbi_conn_queryf((dbi_conn)conn, "SELECT relname FROM pg_class WHERE relname !~ '^pg_' AND relkind = 'r' AND relowner = (SELECT datdba FROM pg_database WHERE datname = '%s') ORDER BY relname", db);
447 	}
448 	else {
449 		return (dbi_result_t *)dbi_conn_queryf((dbi_conn)conn, "SELECT relname FROM pg_class WHERE relname !~ '^pg_' AND relname LIKE '%s' AND relkind = 'r' AND relowner = (SELECT datdba FROM pg_database WHERE datname = '%s') ORDER BY relname", pattern, db);
450 	}
451 }
452 
dbd_quote_string(dbi_driver_t * driver,const char * orig,char * dest)453 size_t dbd_quote_string(dbi_driver_t *driver, const char *orig, char *dest) {
454 	/* foo's -> 'foo\'s' */
455 	size_t len;
456 
457 	strcpy(dest, "'");
458 	len = PQescapeString(dest+1, orig, strlen(orig));
459 	strcat(dest, "'");
460 
461 	return len+2;
462 }
463 
dbd_conn_quote_string(dbi_conn_t * conn,const char * orig,char * dest)464 size_t dbd_conn_quote_string(dbi_conn_t *conn, const char *orig, char *dest) {
465   return dbd_quote_string(conn->driver, orig, dest);
466 }
467 
dbd_quote_binary(dbi_conn_t * conn,const unsigned char * orig,size_t from_length,unsigned char ** ptr_dest)468 size_t dbd_quote_binary(dbi_conn_t *conn, const unsigned char* orig, size_t from_length, unsigned char **ptr_dest) {
469   unsigned char *temp = NULL;
470   unsigned char *quoted_temp = NULL;
471   size_t to_length;
472 
473   temp = PQescapeByteaConn((PGconn *)conn->connection, orig, from_length, &to_length);
474 
475   if (!temp) {
476     return 0;
477   }
478 
479   if ((quoted_temp = malloc(to_length+2)) == NULL) {
480     PQfreemem((void *)temp);
481     return 0;
482   }
483 
484   strcpy((char *)quoted_temp, "'");
485   strcpy((char *)(quoted_temp+1), (char *)temp);
486   strcat((char *)quoted_temp, "'");
487 
488   PQfreemem((void*)temp);
489 
490   *ptr_dest = quoted_temp;
491 
492   /* to_length already contains one extra byte for the trailing NULL byte */
493   return to_length+1;
494 }
495 
dbd_query(dbi_conn_t * conn,const char * statement)496 dbi_result_t *dbd_query(dbi_conn_t *conn, const char *statement) {
497 	/* allocate a new dbi_result_t and fill its applicable members:
498 	 *
499 	 * result_handle, numrows_matched, and numrows_changed.
500 	 * everything else will be filled in by DBI */
501 
502 	dbi_result_t *result;
503 	PGresult *res;
504 	int resstatus;
505 
506 	res = PQexec((PGconn *)conn->connection, statement);
507 	if (res) resstatus = PQresultStatus(res);
508 	if (!res || ((resstatus != PGRES_COMMAND_OK) && (resstatus != PGRES_TUPLES_OK) && (resstatus != PGRES_COPY_OUT) && (resstatus != PGRES_COPY_IN))) {
509 	  char *base36 = PQresultErrorField(res, PG_DIAG_SQLSTATE);
510 	  conn->error_number = (! base36) ? 0 : base36decode(base36);
511 	  PQclear(res);
512 	  return NULL;
513 	}
514 
515 	conn->error_number = 0;
516 
517 	result = _dbd_result_create(conn, (void *)res, (unsigned long long)PQntuples(res), (unsigned long long)atoll(PQcmdTuples(res)));
518 	_dbd_result_set_numfields(result, (unsigned int)PQnfields((PGresult *)result->result_handle));
519 	_get_field_info(result);
520 
521 	return result;
522 }
523 
dbd_query_null(dbi_conn_t * conn,const unsigned char * statement,size_t st_length)524 dbi_result_t *dbd_query_null(dbi_conn_t *conn, const unsigned char *statement, size_t st_length) {
525 	return NULL;
526 }
527 
dbd_transaction_begin(dbi_conn_t * conn)528 int dbd_transaction_begin(dbi_conn_t *conn) {
529   if (dbd_query(conn, "BEGIN TRANSACTION") == NULL) {
530     return 1;
531   }
532   else {
533     return 0;
534   }
535 }
536 
dbd_transaction_commit(dbi_conn_t * conn)537 int dbd_transaction_commit(dbi_conn_t *conn) {
538   if (dbd_query(conn, "COMMIT") == NULL) {
539     return 1;
540   }
541   else {
542     return 0;
543   }
544 }
545 
dbd_transaction_rollback(dbi_conn_t * conn)546 int dbd_transaction_rollback(dbi_conn_t *conn) {
547   if (dbd_query(conn, "ROLLBACK") == NULL) {
548     return 1;
549   }
550   else {
551     return 0;
552   }
553 }
554 
dbd_savepoint(dbi_conn_t * conn,const char * savepoint)555 int dbd_savepoint(dbi_conn_t *conn, const char *savepoint) {
556   char* query;
557 
558   if (!savepoint) {
559     return 1;
560   }
561 
562   asprintf(&query, "SAVEPOINT %s", savepoint);
563 
564   if (dbd_query(conn, query) == NULL) {
565     free(query);
566     return 1;
567   }
568   else {
569     free(query);
570     return 0;
571   }
572 }
573 
dbd_rollback_to_savepoint(dbi_conn_t * conn,const char * savepoint)574 int dbd_rollback_to_savepoint(dbi_conn_t *conn, const char *savepoint) {
575   char* query;
576 
577   if (!savepoint) {
578     return 1;
579   }
580 
581   asprintf(&query, "ROLLBACK TO SAVEPOINT %s", savepoint);
582 
583   if (dbd_query(conn, query) == NULL) {
584     free(query);
585     return 1;
586   }
587   else {
588     free(query);
589     return 0;
590   }
591 }
592 
dbd_release_savepoint(dbi_conn_t * conn,const char * savepoint)593 int dbd_release_savepoint(dbi_conn_t *conn, const char *savepoint) {
594   char* query;
595 
596   if (!savepoint) {
597     return 1;
598   }
599 
600   asprintf(&query, "RELEASE SAVEPOINT %s", savepoint);
601 
602   if (dbd_query(conn, query) == NULL) {
603     free(query);
604     return 1;
605   }
606   else {
607     free(query);
608     return 0;
609   }
610 }
611 
dbd_select_db(dbi_conn_t * conn,const char * db)612 const char *dbd_select_db(dbi_conn_t *conn, const char *db) {
613   /* postgresql doesn't support switching databases without reconnecting */
614   if (!db || !*db) {
615     return NULL;
616   }
617 
618   if (conn->connection) {
619     PQfinish((PGconn *)conn->connection);
620     conn->connection = NULL;
621   }
622 
623   if (_dbd_real_connect(conn, db)) {
624     return NULL;
625   }
626 
627   return db;
628 }
629 
dbd_geterror(dbi_conn_t * conn,int * err_no,char ** errstr)630 int dbd_geterror(dbi_conn_t *conn, int *err_no, char **errstr) {
631 	/* put error number into err_no, error string into errstr
632 	 * return 0 if error, 1 if err_no filled, 2 if errstr filled, 3 if both err_no and errstr filled */
633 
634 	*err_no = conn->error_number;
635 	*errstr = strdup(PQerrorMessage((PGconn *)conn->connection));
636 
637 	return 3;
638 }
639 
dbd_get_seq_last(dbi_conn_t * conn,const char * sequence)640 unsigned long long dbd_get_seq_last(dbi_conn_t *conn, const char *sequence) {
641 	unsigned long long seq_last = 0;
642 	char *sql_cmd;
643 	char *rawdata;
644 	dbi_result_t *result;
645 
646 	asprintf(&sql_cmd, "SELECT currval('%s')", sequence);
647 	if (!sql_cmd) return 0;
648 	result = dbd_query(conn, sql_cmd);
649 	free(sql_cmd);
650 
651 	if (result) {
652 		rawdata = PQgetvalue((PGresult *)result->result_handle, 0, 0);
653 		if (rawdata) {
654 			seq_last = (unsigned long long)atoll(rawdata);
655 		}
656 		dbi_result_free((dbi_result)result);
657 	}
658 
659 	return seq_last;
660 }
661 
dbd_get_seq_next(dbi_conn_t * conn,const char * sequence)662 unsigned long long dbd_get_seq_next(dbi_conn_t *conn, const char *sequence) {
663 	unsigned long long seq_next = 0;
664 	char *sql_cmd;
665 	char *rawdata;
666 	dbi_result_t *result;
667 
668 	asprintf(&sql_cmd, "SELECT nextval('%s')", sequence);
669 	if (!sql_cmd) return 0;
670 	result = dbd_query(conn, sql_cmd);
671 	free(sql_cmd);
672 
673 	if (result) {
674 		rawdata = PQgetvalue((PGresult *)result->result_handle, 0, 0);
675 		if (rawdata) {
676 			seq_next = (unsigned long long)atoll(rawdata);
677 		}
678 		dbi_result_free((dbi_result)result);
679 	}
680 
681 	return seq_next;
682 }
683 
dbd_ping(dbi_conn_t * conn)684 int dbd_ping(dbi_conn_t *conn) {
685 	PGconn *pgsql = (PGconn *)conn->connection;
686 	PGresult *res;
687 
688 	res = PQexec(pgsql, "SELECT 1");
689 	if (res) {
690 	  PQclear (res);
691 	}
692 
693 	if (PQstatus(pgsql) == CONNECTION_OK) {
694 		return 1;
695 	}
696 
697 	PQreset(pgsql); // attempt a reconnection
698 
699 	if (PQstatus(pgsql) == CONNECTION_OK) {
700 		return 1;
701 	}
702 
703 	return 0;
704 }
705 
706 /* CORE POSTGRESQL DATA FETCHING STUFF */
707 
_translate_postgresql_type(unsigned int oid,unsigned short * type,unsigned int * attribs)708 void _translate_postgresql_type(unsigned int oid, unsigned short *type, unsigned int *attribs) {
709 	unsigned int _type = 0;
710 	unsigned int _attribs = 0;
711 
712 /* 	  fprintf(stderr, "oid went to %d\n", oid); */
713 	switch (oid) {
714 		case PG_TYPE_CHAR:
715 			_type = DBI_TYPE_INTEGER;
716 			_attribs |= DBI_INTEGER_SIZE1;
717 			break;
718 		case PG_TYPE_INT2:
719 			_type = DBI_TYPE_INTEGER;
720 			_attribs |= DBI_INTEGER_SIZE2;
721 			break;
722 		case PG_TYPE_INT4:
723 			_type = DBI_TYPE_INTEGER;
724 			_attribs |= DBI_INTEGER_SIZE4;
725 			break;
726 		case PG_TYPE_INT8:
727 			_type = DBI_TYPE_INTEGER;
728 			_attribs |= DBI_INTEGER_SIZE8;
729 			break;
730 		case PG_TYPE_OID:
731 			_type = DBI_TYPE_INTEGER;
732 			_attribs |= DBI_INTEGER_SIZE8;
733 			_attribs |= DBI_INTEGER_UNSIGNED;
734 			break;
735 
736 		case PG_TYPE_FLOAT4:
737 			_type = DBI_TYPE_DECIMAL;
738 			_attribs |= DBI_DECIMAL_SIZE4;
739 			break;
740 		case PG_TYPE_FLOAT8:
741 			_type = DBI_TYPE_DECIMAL;
742 			_attribs |= DBI_DECIMAL_SIZE8;
743 			break;
744 
745         case PG_TYPE_DATE:
746 	        _type = DBI_TYPE_DATETIME;
747             _attribs |= DBI_DATETIME_DATE;
748             break;
749         case PG_TYPE_TIME:
750         case PG_TYPE_TIMETZ:
751             _type = DBI_TYPE_DATETIME;
752             _attribs |= DBI_DATETIME_TIME;
753             break;
754         case PG_TYPE_TIMESTAMP:
755         case PG_TYPE_TIMESTAMPTZ:
756 			_type = DBI_TYPE_DATETIME;
757 			_attribs |= DBI_DATETIME_DATE;
758 			_attribs |= DBI_DATETIME_TIME;
759 			break;
760 
761 		case PG_TYPE_NAME:
762 		case PG_TYPE_TEXT:
763 		case PG_TYPE_CHAR2:
764 		case PG_TYPE_CHAR4:
765 		case PG_TYPE_CHAR8:
766 		case PG_TYPE_BPCHAR:
767 		case PG_TYPE_VARCHAR:
768 			_type = DBI_TYPE_STRING;
769 			break;
770 
771 		case PG_TYPE_BYTEA:
772 			_type = DBI_TYPE_BINARY;
773 			break;
774 
775 		default:
776 			_type = DBI_TYPE_STRING;
777 			break;
778 	}
779 
780 	*type = _type;
781 	*attribs = _attribs;
782 }
783 
_get_field_info(dbi_result_t * result)784 void _get_field_info(dbi_result_t *result) {
785 	unsigned int idx = 0;
786 	unsigned int pgOID = 0;
787 	char *fieldname;
788 	unsigned short fieldtype;
789 	unsigned int fieldattribs;
790 
791 	while (idx < result->numfields) {
792 		pgOID = PQftype((PGresult *)result->result_handle, idx);
793 		fieldname = PQfname((PGresult *)result->result_handle, idx);
794 		_translate_postgresql_type(pgOID, &fieldtype, &fieldattribs);
795 		_dbd_result_add_field(result, idx, fieldname, fieldtype, fieldattribs);
796 		idx++;
797 	}
798 }
799 
_get_row_data(dbi_result_t * result,dbi_row_t * row,unsigned long long rowidx)800 void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx) {
801 	unsigned int curfield = 0;
802 	char *raw = NULL;
803 	size_t strsize = 0;
804 	unsigned int sizeattrib;
805 	dbi_data_t *data;
806 	unsigned char *temp = NULL;
807 	size_t unquoted_length;
808 
809 
810 	while (curfield < result->numfields) {
811 		raw = PQgetvalue((PGresult *)result->result_handle, rowidx, curfield);
812 		data = &row->field_values[curfield];
813 
814 		row->field_sizes[curfield] = 0;
815 		/* will be set to strlen later on for strings */
816 
817 		if (PQgetisnull((PGresult *)result->result_handle, rowidx, curfield) == 1) {
818 		        _set_field_flag( row, curfield, DBI_VALUE_NULL, 1);
819 			curfield++;
820 			continue;
821 		}
822 
823 		switch (result->field_types[curfield]) {
824 			case DBI_TYPE_INTEGER:
825 				switch (result->field_attribs[curfield] & DBI_INTEGER_SIZEMASK) {
826 					case DBI_INTEGER_SIZE1:
827 						data->d_char = (char) atol(raw); break;
828 					case DBI_INTEGER_SIZE2:
829 						data->d_short = (short) atol(raw); break;
830 					case DBI_INTEGER_SIZE3:
831 					case DBI_INTEGER_SIZE4:
832 						data->d_long = (int) atol(raw); break;
833 					case DBI_INTEGER_SIZE8:
834 						data->d_longlong = (long long) atoll(raw); break; /* hah, wonder if that'll work */
835 					default:
836 						break;
837 				}
838 				break;
839 			case DBI_TYPE_DECIMAL:
840 				switch (result->field_attribs[curfield] & DBI_DECIMAL_SIZEMASK) {
841 					case DBI_DECIMAL_SIZE4:
842 						data->d_float = (float) strtod(raw, NULL); break;
843 					case DBI_DECIMAL_SIZE8:
844 						data->d_double = (double) strtod(raw, NULL); break;
845 					default:
846 						break;
847 				}
848 				break;
849 			case DBI_TYPE_STRING:
850 			    strsize = (size_t)PQgetlength((PGresult *)result->result_handle, rowidx, curfield);
851 				data->d_string = strdup(raw);
852 				row->field_sizes[curfield] = strsize;
853 				break;
854 			case DBI_TYPE_BINARY:
855 			  strsize = (size_t)PQgetlength((PGresult *)result->result_handle, rowidx, curfield);
856 			  if (strsize > 2
857 			      && raw[0] == '\\'
858 			      && raw[1] == 'x') {
859 			    /* hex format */
860 				/* row->field_sizes[curfield] = strsize; */
861 				/* data->d_string = malloc(strsize); */
862 				/* memcpy(data->d_string, raw, strsize); */
863 			    temp = PQunescapeBytea((const unsigned char *)_unescape_hex_binary(raw, strsize, &unquoted_length), &(row->field_sizes[curfield]));
864 			    if ((data->d_string = malloc(row->field_sizes[curfield])) == NULL) {
865 			      PQfreemem(temp);
866 			      break;
867 			    }
868 			    memmove(data->d_string, temp, row->field_sizes[curfield]);
869 			    PQfreemem(temp);
870 			  }
871 			  else {
872 			    temp = PQunescapeBytea((const unsigned char *)raw, &unquoted_length);
873 			    if ((data->d_string = malloc(unquoted_length)) == NULL) {
874 			      PQfreemem(temp);
875 			      break;
876 			    }
877 			    memmove(data->d_string, temp, unquoted_length);
878 			    PQfreemem(temp);
879 			    row->field_sizes[curfield] = unquoted_length;
880 			  }
881 			  break;
882 
883 			case DBI_TYPE_DATETIME:
884 				sizeattrib = result->field_attribs[curfield] & (DBI_DATETIME_DATE|DBI_DATETIME_TIME);
885 				data->d_datetime = _dbd_parse_datetime(raw, sizeattrib);
886 				break;
887 
888 			default:
889 				break;
890 		}
891 
892 		curfield++;
893 	}
894 }
895 
896 /* this function reverts the changes done by PQescapeByteaConn to a
897    binary string. libpq does not provide such a function.  Returns the
898    result as a malloc'ed string which must be freed by the caller. The
899    output string is in the BYTEA escape format with single backslashes
900    and single single quotes. It must be post-processed by
901    PQunescapeBytea() to obtain true binary data
902 */
_unescape_hex_binary(char * raw,size_t in_len,size_t * out_len)903 char *_unescape_hex_binary(char* raw, size_t in_len, size_t* out_len) {
904   size_t i;
905   int in_pair = 0;
906   int last_nibble = 0;
907   char *outstring;
908   char *end_of_outstring;
909   int have_backslash = 0;
910   int have_singlequote = 0;
911   char tempchar;
912 
913   /* algorithm borrowed and modified from:
914      http://pqxx.org/development/libpqxx/browser/trunk/src/binarystring.cxx
915   */
916 
917   if ((outstring = malloc(((in_len-2)/2)+1)) == NULL) {
918     return NULL;
919   }
920   end_of_outstring = outstring;
921 
922   for (i=2; i<in_len; ++i) {
923     const unsigned char c = raw[i];
924     if (isspace(c)) {
925       if (in_pair) {
926 	/* "Escaped binary data is malformed." */
927       }
928     }
929     else if (!isxdigit(c)) {
930       /* "Escaped binary data contains invalid characters." */
931     }
932     else {
933       const int nibble = (isdigit(c) ? _digit_to_number(c) : (10 + tolower(c) - 'a'));
934       if (in_pair) {
935 	tempchar = (char)((last_nibble<<4) | nibble);
936 	if (tempchar == '\\' && have_backslash) {
937 	  /* skip second consecutive backslash */
938 	  have_backslash = 0;
939 	}
940 	else if (tempchar == '\'' && have_singlequote) {
941 	  /* skip second consecutive single quote */
942 	  have_singlequote = 0;
943 	}
944 	else {
945 	  if (tempchar == '\\') {
946 	    have_backslash = 1;
947 	  }
948 	  else if (tempchar == '\'') {
949 	    have_singlequote = 1;
950 	  }
951 	  else {
952 	    have_backslash = 0;
953 	    have_singlequote = 0;
954 	  }
955 	  *end_of_outstring = tempchar;
956 	  end_of_outstring++;
957 	}
958       }
959       else {
960 	last_nibble = nibble;
961       }
962       in_pair = !in_pair;
963     }
964   }
965   *end_of_outstring = '\0';
966   *out_len = end_of_outstring-outstring;
967   return outstring;
968 }
969 
970 /* converts an ASCII character code to an integer */
_digit_to_number(const char c)971 int _digit_to_number(const char c) {
972   return (int)c - (int)'0';
973 }
974