FreeSWITCH API Documentation  1.7.0
switch_pgsql.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Eliot Gable <egable@gmail.com>
28  * Seven Du <dujinfang@gmail.com>
29  *
30  * switch_pgsql.c -- PGSQL Driver
31  *
32  */
33 
34 #include <switch.h>
35 
36 #ifndef WIN32
37 #include <switch_private.h>
38 #endif
39 
40 #ifdef SWITCH_HAVE_PGSQL
41 #include <libpq-fe.h>
42 #include <poll.h>
43 
44 
45 struct switch_pgsql_handle {
46  char *dsn;
47  char *sql;
48  PGconn* con;
49  int sock;
51  int affected_rows;
52  int num_retries;
53  switch_bool_t auto_commit;
54  switch_bool_t in_txn;
55 };
56 
57 struct switch_pgsql_result {
58  PGresult *result;
59  ExecStatusType status;
60  char *err;
61  int rows;
62  int cols;
63 };
64 #endif
65 
67 {
68 #ifdef SWITCH_HAVE_PGSQL
69  switch_pgsql_handle_t *new_handle;
70 
71  if (!(new_handle = malloc(sizeof(*new_handle)))) {
72  goto err;
73  }
74 
75  memset(new_handle, 0, sizeof(*new_handle));
76 
77  if (!(new_handle->dsn = strdup(dsn))) {
78  goto err;
79  }
80 
81  new_handle->sock = 0;
82  new_handle->state = SWITCH_PGSQL_STATE_INIT;
83  new_handle->con = NULL;
84  new_handle->affected_rows = 0;
85  new_handle->num_retries = DEFAULT_PGSQL_RETRIES;
86  new_handle->auto_commit = SWITCH_TRUE;
87  new_handle->in_txn = SWITCH_FALSE;
88 
89  return new_handle;
90 
91  err:
92  if (new_handle) {
93  switch_safe_free(new_handle->dsn);
94  switch_safe_free(new_handle);
95  }
96 #endif
97  return NULL;
98 }
99 
100 
101 #ifdef SWITCH_HAVE_PGSQL
102 static int db_is_up(switch_pgsql_handle_t *handle)
103 {
104  int ret = 0;
105  switch_event_t *event;
106  char *err_str = NULL;
107  int max_tries = DEFAULT_PGSQL_RETRIES;
108  int code = 0, recon = 0;
109 
110  if (handle) {
111  max_tries = handle->num_retries;
112  if (max_tries < 1)
113  max_tries = DEFAULT_PGSQL_RETRIES;
114  }
115 
116  top:
117 
118  if (!handle) {
120  goto done;
121  }
122  if (!handle->con) {
123  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No DB Connection\n");
124  goto done;
125  }
126 
127  /* Try a non-blocking read on the connection to gobble up any EOF from a closed connection and mark the connection BAD if it is closed. */
128  PQconsumeInput(handle->con);
129 
130  if (PQstatus(handle->con) == CONNECTION_BAD) {
131  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "PQstatus returned bad connection; reconnecting...\n");
132  handle->state = SWITCH_PGSQL_STATE_ERROR;
133  PQreset(handle->con);
134  if (PQstatus(handle->con) == CONNECTION_BAD) {
135  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "PQstatus returned bad connection -- reconnection failed!\n");
136  goto error;
137  }
138  handle->state = SWITCH_PGSQL_STATE_CONNECTED;
139  handle->sock = PQsocket(handle->con);
140  }
141 
142 /* if (!PQsendQuery(handle->con, "SELECT 1")) {
143  code = __LINE__;
144  goto error;
145  }
146 
147  if(switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
148  code = __LINE__;
149  goto error;
150  }
151 
152  if (!result || result->status != PGRES_COMMAND_OK) {
153  code = __LINE__;
154  goto error;
155  }
156 
157  switch_pgsql_free_result(&result);
158  switch_pgsql_finish_results(handle);
159 */
160  ret = 1;
161  goto done;
162 
163  error:
164  err_str = switch_pgsql_handle_get_error(handle);
165 
166  if (PQstatus(handle->con) == CONNECTION_BAD) {
167  handle->state = SWITCH_PGSQL_STATE_ERROR;
168  PQreset(handle->con);
169  if (PQstatus(handle->con) == CONNECTION_OK) {
170  handle->state = SWITCH_PGSQL_STATE_CONNECTED;
171  recon = SWITCH_PGSQL_SUCCESS;
172  handle->sock = PQsocket(handle->con);
173  }
174  }
175 
176  max_tries--;
177 
179  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Failure-Message", "The sql server is not responding for DSN %s [%s][%d]",
180  switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
181  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The sql server is not responding for DSN %s [%s][%d]\n",
182  switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
183 
184  if (recon == SWITCH_PGSQL_SUCCESS) {
185  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection has been re-established");
186  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "The connection has been re-established\n");
187  } else {
188  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection could not be re-established");
189  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The connection could not be re-established\n");
190  }
191  if (!max_tries) {
192  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "Giving up!");
194  }
195 
196  switch_event_fire(&event);
197  }
198 
199  if (!max_tries) {
200  goto done;
201  }
202 
203  switch_safe_free(err_str);
204  switch_yield(1000000);
205  goto top;
206 
207  done:
208 
209  switch_safe_free(err_str);
210 
211  return ret;
212 }
213 #endif
214 
215 
217 {
218 #ifdef SWITCH_HAVE_PGSQL
219  if (handle) {
220  handle->num_retries = num_retries;
221  }
222 #endif
223 }
224 
226 {
227 #ifdef SWITCH_HAVE_PGSQL
228 
229  if (!handle) {
230  return SWITCH_PGSQL_FAIL;
231  }
232 
233  if (handle->state == SWITCH_PGSQL_STATE_CONNECTED) {
234  PQfinish(handle->con);
235  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Disconnected from [%s]\n", handle->dsn);
236  }
237  switch_safe_free(handle->sql);
238  handle->state = SWITCH_PGSQL_STATE_DOWN;
239 
240  return SWITCH_PGSQL_SUCCESS;
241 #else
242  return SWITCH_PGSQL_FAIL;
243 #endif
244 }
245 
247 {
248 #ifdef SWITCH_HAVE_PGSQL
249  char *err_str;
250 
251  switch_safe_free(handle->sql);
252  handle->sql = strdup(sql);
253  if (!PQsendQuery(handle->con, sql)) {
254  err_str = switch_pgsql_handle_get_error(handle);
255  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to send query (%s) to database: %s\n", sql, err_str);
257  goto error;
258  }
259 
260  return SWITCH_PGSQL_SUCCESS;
261  error:
262 #endif
263  return SWITCH_PGSQL_FAIL;
264 }
265 
266 SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_cancel_real(const char *file, const char *func, int line, switch_pgsql_handle_t *handle)
267 {
269 #ifdef SWITCH_HAVE_PGSQL
270  char err_buf[256];
271  PGcancel *cancel = NULL;
272 
273  memset(err_buf, 0, 256);
274  cancel = PQgetCancel(handle->con);
275  if(!PQcancel(cancel, err_buf, 256)) {
276  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_CRIT, "Failed to cancel long-running query (%s): %s\n", handle->sql, err_buf);
277  ret = SWITCH_PGSQL_FAIL;
278  }
279  PQfreeCancel(cancel);
280  switch_pgsql_flush(handle);
281 
282 #endif
283  return ret;
284 }
285 
286 
288 {
289 #ifdef SWITCH_HAVE_PGSQL
291  switch_time_t start;
292  switch_time_t ctime;
293  unsigned int usec = msec * 1000;
294  char *err_str;
295  struct pollfd fds[2] = { {0} };
296  int poll_res = 0;
297 
298  if(!handle) {
299  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "**BUG** Null handle passed to switch_pgsql_next_result.\n");
300  return SWITCH_PGSQL_FAIL;
301  }
302 
303  /* Try to consume input that might be waiting right away */
304  if (PQconsumeInput(handle->con)) {
305  /* And check to see if we have a full result ready for reading */
306  if (PQisBusy(handle->con)) {
307 
308  /* Wait for a result to become available, up to msec milliseconds */
309  start = switch_micro_time_now();
310  while((ctime = switch_micro_time_now()) - start <= usec) {
311  int wait_time = (usec - (ctime - start)) / 1000;
312  fds[0].fd = handle->sock;
313  fds[0].events |= POLLIN;
314  fds[0].events |= POLLERR;
315  fds[0].events |= POLLNVAL;
316  fds[0].events |= POLLHUP;
317  fds[0].events |= POLLPRI;
318  fds[0].events |= POLLRDNORM;
319  fds[0].events |= POLLRDBAND;
320 
321  /* Wait for the PostgreSQL socket to be ready for data reads. */
322  if ((poll_res = poll(&fds[0], 1, wait_time)) > 0 ) {
323  if (fds[0].revents & POLLHUP || fds[0].revents & POLLNVAL) {
324  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "PGSQL socket closed or invalid while waiting for result for query (%s)\n", handle->sql);
325  goto error;
326  } else if (fds[0].revents & POLLERR) {
327  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll error trying to read PGSQL socket for query (%s)\n", handle->sql);
328  goto error;
329  } else if (fds[0].revents & POLLIN || fds[0].revents & POLLPRI || fds[0].revents & POLLRDNORM || fds[0].revents & POLLRDBAND) {
330  /* Then try to consume any input waiting. */
331  if (PQconsumeInput(handle->con)) {
332  if (PQstatus(handle->con) == CONNECTION_BAD) {
333  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Connection terminated while waiting for result.\n");
334  handle->state = SWITCH_PGSQL_STATE_ERROR;
335  goto error;
336  }
337 
338  /* And check to see if we have a full result ready for reading */
339  if (!PQisBusy(handle->con)) {
340  /* If we can pull a full result without blocking, then break this loop */
341  break;
342  }
343  } else {
344  /* If we had an error trying to consume input, report it and cancel the query. */
345  err_str = switch_pgsql_handle_get_error(handle);
346  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
347  switch_safe_free(err_str);
348  switch_pgsql_cancel(handle);
349  goto error;
350  }
351  }
352  } else if (poll_res == -1) {
353  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll failed trying to read PGSQL socket for query (%s)\n", handle->sql);
354  goto error;
355  }
356  }
357 
358  /* If we broke the loop above because of a timeout, report that and cancel the query. */
359  if (ctime - start > usec) {
360  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Query (%s) took too long to complete or database not responding.\n", handle->sql);
361  switch_pgsql_cancel(handle);
362  goto error;
363  }
364 
365  }
366  } else {
367  /* If we had an error trying to consume input, report it and cancel the query. */
368  err_str = switch_pgsql_handle_get_error(handle);
369  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
370  switch_safe_free(err_str);
371  /* switch_pgsql_cancel(handle); */
372  goto error;
373  }
374 
375 
376  /* At this point, we know we can read a full result without blocking. */
377  if(!(res = malloc(sizeof(switch_pgsql_result_t)))) {
379  goto error;
380  }
381  memset(res, 0, sizeof(switch_pgsql_result_t));
382 
383 
384  res->result = PQgetResult(handle->con);
385  if (res->result) {
386  *result_out = res;
387  res->status = PQresultStatus(res->result);
388  switch(res->status) {
389 #if POSTGRESQL_MAJOR_VERSION >= 9 && POSTGRESQL_MINOR_VERSION >= 2
390  case PGRES_SINGLE_TUPLE:
391  /* Added in PostgreSQL 9.2 */
392 #endif
393  case PGRES_TUPLES_OK:
394  {
395  res->rows = PQntuples(res->result);
396  handle->affected_rows = res->rows;
397  res->cols = PQnfields(res->result);
398  }
399  break;
400 #if POSTGRESQL_MAJOR_VERSION >= 9 && POSTGRESQL_MINOR_VERSION >= 1
401  case PGRES_COPY_BOTH:
402  /* Added in PostgreSQL 9.1 */
403 #endif
404  case PGRES_COPY_OUT:
405  case PGRES_COPY_IN:
406  case PGRES_COMMAND_OK:
407  break;
408  case PGRES_EMPTY_QUERY:
409  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_EMPTY_QUERY\n", handle->sql);
410  case PGRES_BAD_RESPONSE:
411  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_BAD_RESPONSE\n", handle->sql);
412  case PGRES_NONFATAL_ERROR:
413  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_NONFATAL_ERROR\n", handle->sql);
414  case PGRES_FATAL_ERROR:
415  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_FATAL_ERROR\n", handle->sql);
416  res->err = PQresultErrorMessage(res->result);
417  goto error;
418  break;
419  }
420  } else {
421  free(res);
422  res = NULL;
423  *result_out = NULL;
424  }
425 
426  return SWITCH_PGSQL_SUCCESS;
427  error:
428 
429  /* Make sure the failed connection does not have any transactions marked as in progress */
430  switch_pgsql_flush(handle);
431 
432  /* Try to reconnect to the DB if we were dropped */
433  db_is_up(handle);
434 
435 #endif
436  return SWITCH_PGSQL_FAIL;
437 }
438 
440 {
441 #ifdef SWITCH_HAVE_PGSQL
442 
443  if (!*result) {
444  return;
445  }
446 
447  if ((*result)->result) {
448  PQclear((*result)->result);
449  }
450  free(*result);
451  *result = NULL;
452 #else
453  return;
454 #endif
455 }
456 
458 {
459 #ifdef SWITCH_HAVE_PGSQL
460  switch_pgsql_result_t *res = NULL;
462  int done = 0;
463  do {
464  switch_pgsql_next_result(handle, &res);
465  if (res && res->err && !switch_stristr("already exists", res->err) && !switch_stristr("duplicate key name", res->err)) {
466  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Error executing query:\n%s\n", res->err);
467  final_status = SWITCH_PGSQL_FAIL;
468  }
469 
470  if (!res) {
471  done = 1;
472  } else if (res->result) {
473  char *affected_rows = PQcmdTuples(res->result);
474 
475  if (!zstr(affected_rows)) {
476  handle->affected_rows = atoi(affected_rows);
477  }
478  }
479 
481  } while (!done);
482  return final_status;
483 #else
484  return SWITCH_PGSQL_FAIL;
485 #endif
486 }
487 
488 
490 {
491 #ifdef SWITCH_HAVE_PGSQL
492  if (handle->state == SWITCH_PGSQL_STATE_CONNECTED) {
494  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Re-connecting %s\n", handle->dsn);
495  }
496 
497  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connecting %s\n", handle->dsn);
498 
499  handle->con = PQconnectdb(handle->dsn);
500  if (PQstatus(handle->con) != CONNECTION_OK) {
501  char *err_str;
502  if ((err_str = switch_pgsql_handle_get_error(handle))) {
504  switch_safe_free(err_str);
505  } else {
506  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to connect to the database [%s]\n", handle->dsn);
508  }
509  return SWITCH_PGSQL_FAIL;
510  }
511 
512  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connected to [%s]\n", handle->dsn);
513  handle->state = SWITCH_PGSQL_STATE_CONNECTED;
514  handle->sock = PQsocket(handle->con);
515  return SWITCH_PGSQL_SUCCESS;
516 #else
517  return SWITCH_PGSQL_FAIL;
518 #endif
519 }
520 
522  switch_pgsql_handle_t *handle, const char *sql, char *resbuf, size_t len, char **err)
523 {
524 #ifdef SWITCH_HAVE_PGSQL
526  char *val = NULL;
527  switch_pgsql_result_t *result = NULL;
528 
529  handle->affected_rows = 0;
530 
531  if (switch_pgsql_handle_exec_base_detailed(file, func, line, handle, sql, err) == SWITCH_PGSQL_FAIL) {
532  goto error;
533  }
534 
535  if(switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
536  goto error;
537  }
538 
539  if (result) {
540  switch (result->status) {
541 #if POSTGRESQL_MAJOR_VERSION >= 9 && POSTGRESQL_MINOR_VERSION >= 2
542  case PGRES_SINGLE_TUPLE:
543  /* Added in PostgreSQL 9.2 */
544 #endif
545  case PGRES_COMMAND_OK:
546  case PGRES_TUPLES_OK:
547  break;
548  default:
549  sstatus = SWITCH_PGSQL_FAIL;
550  goto done;
551  }
552  }
553 
554  if (handle->affected_rows <= 0) {
555  goto done;
556  }
557 
558  val = PQgetvalue(result->result, 0, 0);
559  strncpy(resbuf, val, len);
560 
561  done:
562 
563  switch_pgsql_free_result(&result);
565  sstatus = SWITCH_PGSQL_FAIL;
566  }
567 
568  return sstatus;
569  error:
570  return SWITCH_PGSQL_FAIL;
571 #else
572  return SWITCH_PGSQL_FAIL;
573 #endif
574 }
575 
577  switch_pgsql_handle_t *handle, const char *sql, char **err)
578 {
579 #ifdef SWITCH_HAVE_PGSQL
580  char *err_str = NULL, *er = NULL;
581 
582 
583 
584  switch_pgsql_flush(handle);
585  handle->affected_rows = 0;
586 
587  if (!db_is_up(handle)) {
588  er = strdup("Database is not up!");
589  goto error;
590  }
591 
592  if (handle->auto_commit == SWITCH_FALSE && handle->in_txn == SWITCH_FALSE) {
593  if (switch_pgsql_send_query(handle, "BEGIN") != SWITCH_PGSQL_SUCCESS) {
594  er = strdup("Error sending BEGIN!");
596  db_is_up(handle); /* If finish_results failed, maybe the db went dead */
597  }
598  goto error;
599  }
600 
602  db_is_up(handle);
603  er = strdup("Error sending BEGIN!");
604  goto error;
605  }
606  handle->in_txn = SWITCH_TRUE;
607  }
608 
609  if (switch_pgsql_send_query(handle, sql) != SWITCH_PGSQL_SUCCESS) {
610  er = strdup("Error sending query!");
612  db_is_up(handle);
613  }
614  goto error;
615  }
616 
617  return SWITCH_PGSQL_SUCCESS;
618 
619  error:
620  err_str = switch_pgsql_handle_get_error(handle);
621 
622  if (zstr(err_str)) {
623  if (zstr(er)) {
624  err_str = strdup((char *)"SQL ERROR!");
625  } else {
626  err_str = er;
627  }
628  } else {
629  if (!zstr(er)) {
630  free(er);
631  }
632  }
633 
634  if (err_str) {
635  if (!switch_stristr("already exists", err_str) && !switch_stristr("duplicate key name", err_str)) {
636  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
637  }
638  if (err) {
639  *err = err_str;
640  } else {
641  free(err_str);
642  }
643  }
644 #endif
645  return SWITCH_PGSQL_FAIL;
646 }
647 
648 SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec_detailed(const char *file, const char *func, int line,
649  switch_pgsql_handle_t *handle, const char *sql, char **err)
650 {
651 #ifdef SWITCH_HAVE_PGSQL
652  if (switch_pgsql_handle_exec_base_detailed(file, func, line, handle, sql, err) == SWITCH_PGSQL_FAIL) {
653  goto error;
654  }
655 
656  return switch_pgsql_finish_results(handle);
657  error:
658 #endif
659  return SWITCH_PGSQL_FAIL;
660 }
661 
663  switch_pgsql_handle_t *handle,
664  const char *sql, switch_core_db_callback_func_t callback, void *pdata,
665  char **err)
666 {
667 #ifdef SWITCH_HAVE_PGSQL
668  char *err_str = NULL;
669  int row = 0, col = 0, err_cnt = 0;
670  switch_pgsql_result_t *result = NULL;
671 
672  handle->affected_rows = 0;
673 
674  switch_assert(callback != NULL);
675 
676  if (switch_pgsql_handle_exec_base(handle, sql, err) == SWITCH_PGSQL_FAIL) {
677  goto error;
678  }
679 
680  if (switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
681  err_cnt++;
682  err_str = switch_pgsql_handle_get_error(handle);
683  if (result && !zstr(result->err)) {
684  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(result->err));
685  }
686  if (!zstr(err_str)) {
687  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
688  }
689  switch_safe_free(err_str);
690  err_str = NULL;
691  }
692 
693  while (result != NULL) {
694  /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Processing result with %d rows and %d columns.\n", result->rows, result->cols);*/
695  for (row = 0; row < result->rows; ++row) {
696  char **names;
697  char **vals;
698 
699  names = calloc(result->cols, sizeof(*names));
700  vals = calloc(result->cols, sizeof(*vals));
701 
702  switch_assert(names && vals);
703 
704  for (col = 0; col < result->cols; ++col) {
705  char * tmp;
706  int len;
707 
708  tmp = PQfname(result->result, col);
709  if (tmp) {
710  len = strlen(tmp);
711  names[col] = malloc(len+1);
712  names[col][len] = '\0';
713  strncpy(names[col], tmp, len);
714 
715  len = PQgetlength(result->result, row, col);
716  vals[col] = malloc(len+1);
717  vals[col][len] = '\0';
718  tmp = PQgetvalue(result->result, row, col);
719  strncpy(vals[col], tmp, len);
720  /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Processing result row %d, col %d: %s => %s\n", row, col, names[col], vals[col]);*/
721  } else {
722  /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Processing result row %d, col %d.\n", row, col);*/
723  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: Column number %d out of range\n", col);
724  }
725  }
726 
727  /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Executing callback for row %d...\n", row);*/
728  if (callback(pdata, result->cols, vals, names)) {
729  switch_pgsql_finish_results(handle); /* Makes sure next call to switch_pgsql_next_result will return NULL */
730  row = result->rows; /* Makes us exit the for loop */
731  }
732 
733  for (col = 0; col < result->cols; ++col) {
734  free(names[col]);
735  free(vals[col]);
736  }
737  free(names);
738  free(vals);
739  }
740  switch_pgsql_free_result(&result);
741  if (switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
742  err_cnt++;
743  err_str = switch_pgsql_handle_get_error(handle);
744  if (result && !zstr(result->err)) {
745  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(result->err));
746  }
747  if (!zstr(err_str)) {
748  switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
749  }
750  switch_safe_free(err_str);
751  err_str = NULL;
752  }
753  }
754  if (err_cnt) {
755  goto error;
756  }
757 
758  return SWITCH_PGSQL_SUCCESS;
759  error:
760 #endif
761  return SWITCH_PGSQL_FAIL;
762 }
763 
765 {
766 #ifdef SWITCH_HAVE_PGSQL
767 
768  switch_pgsql_handle_t *handle = NULL;
769 
770  if (!handlep) {
771  return;
772  }
773  handle = *handlep;
774 
775  if (handle) {
777 
778  switch_safe_free(handle->dsn);
779  free(handle);
780  }
781  *handlep = NULL;
782 #else
783  return;
784 #endif
785 }
786 
788 {
789 #ifdef SWITCH_HAVE_PGSQL
790  return handle ? handle->state : SWITCH_PGSQL_STATE_INIT;
791 #else
793 #endif
794 }
795 
797 {
798 #ifdef SWITCH_HAVE_PGSQL
799  char * err_str;
800  if (!handle) {
801  return NULL;
802  };
803  switch_strdup(err_str, PQerrorMessage(handle->con));
804  return err_str;
805 #else
806  return NULL;
807 #endif
808 }
809 
811 {
812 #ifdef SWITCH_HAVE_PGSQL
813  return handle->affected_rows;
814 #else
815  return 0;
816 #endif
817 }
818 
820 {
821 #ifdef SWITCH_HAVE_PGSQL
822  return SWITCH_TRUE;
823 #else
824  return SWITCH_FALSE;
825 #endif
826 }
827 
829 {
830 #ifdef SWITCH_HAVE_PGSQL
831  if (on) {
832  handle->auto_commit = SWITCH_TRUE;
833  } else {
834  handle->auto_commit = SWITCH_FALSE;
835  }
836  return SWITCH_PGSQL_SUCCESS;
837 #else
839 #endif
840 }
841 
843 {
844 #ifdef SWITCH_HAVE_PGSQL
845 
846  PGresult *tmp = NULL;
847  int x = 0;
848 
849  /* Make sure the query is fully cleared */
850  while ((tmp = PQgetResult(handle->con)) != NULL) {
851  PQclear(tmp);
852  x++;
853  }
854 
855  if (x) {
856  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Flushing %d results\n", x);
857  }
858 
859  return SWITCH_PGSQL_SUCCESS;
860 #else
862 #endif
863 }
864 
866 {
867 #ifdef SWITCH_HAVE_PGSQL
868  char * err_str = NULL;
869  if (commit) {
870  if(!PQsendQuery(handle->con, "COMMIT")) {
871  err_str = switch_pgsql_handle_get_error(handle);
872  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not commit transaction: %s\n", err_str);
873  switch_safe_free(err_str);
874  return SWITCH_PGSQL_FAIL;
875  }
876  } else {
877  if(!PQsendQuery(handle->con, "ROLLBACK")) {
878  err_str = switch_pgsql_handle_get_error(handle);
879  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not rollback transaction: %s\n", err_str);
880  switch_safe_free(err_str);
881  return SWITCH_PGSQL_FAIL;
882  }
883  }
884  handle->in_txn = SWITCH_FALSE;
885  return SWITCH_PGSQL_SUCCESS;
886 #else
888 #endif
889 }
890 
891 
892 /* For Emacs:
893  * Local Variables:
894  * mode:c
895  * indent-tabs-mode:t
896  * tab-width:4
897  * c-basic-offset:4
898  * End:
899  * For VIM:
900  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
901  */
switch_pgsql_status_t
Definition: switch_pgsql.h:53
switch_time_t switch_micro_time_now(void)
Get the current epoch time in microseconds.
Definition: switch_time.c:310
#define switch_event_fire(event)
Fire an event filling in most of the arguements with obvious values.
Definition: switch_event.h:412
#define switch_strdup(ptr, s)
#define SWITCH_CHANNEL_LOG
switch_pgsql_status_t switch_pgsql_SQLEndTran(switch_pgsql_handle_t *handle, switch_bool_t commit)
Definition: switch_pgsql.c:865
switch_bool_t
Definition: switch_types.h:405
struct switch_pgsql_handle switch_pgsql_handle_t
switch_status_t switch_event_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *fmt,...) PRINTF_FUNCTION(4
Add a header to an event.
Representation of an event.
Definition: switch_event.h:80
switch_pgsql_status_t switch_pgsql_handle_exec_detailed(const char *file, const char *func, int line, switch_pgsql_handle_t *handle, const char *sql, char **err)
Definition: switch_pgsql.c:648
void switch_pgsql_set_num_retries(switch_pgsql_handle_t *handle, int num_retries)
Sets the number of retries if the PGSQL connection fails.
Definition: switch_pgsql.c:216
void switch_pgsql_free_result(switch_pgsql_result_t **result)
Definition: switch_pgsql.c:439
#define DEFAULT_PGSQL_RETRIES
Definition: switch_pgsql.h:38
int(* switch_core_db_callback_func_t)(void *pArg, int argc, char **argv, char **columnNames)
switch_pgsql_state_t switch_pgsql_handle_get_state(switch_pgsql_handle_t *handle)
Definition: switch_pgsql.c:787
switch_pgsql_status_t switch_pgsql_handle_callback_exec_detailed(const char *file, const char *func, int line, switch_pgsql_handle_t *handle, const char *sql, switch_core_db_callback_func_t callback, void *pdata, char **err)
Execute the sql query and issue a callback for each row returned.
Definition: switch_pgsql.c:662
#define zstr(x)
Definition: switch_utils.h:281
switch_pgsql_status_t switch_pgsql_SQLSetAutoCommitAttr(switch_pgsql_handle_t *handle, switch_bool_t on)
Definition: switch_pgsql.c:828
int64_t switch_time_t
Definition: switch_apr.h:188
struct switch_pgsql_result switch_pgsql_result_t
switch_pgsql_status_t switch_pgsql_handle_exec_string_detailed(const char *file, const char *func, int line, switch_pgsql_handle_t *handle, const char *sql, char *resbuf, size_t len, char **err)
Definition: switch_pgsql.c:521
#define switch_yield(ms)
Wait a desired number of microseconds and yield the CPU.
Definition: switch_utils.h:908
switch_pgsql_status_t switch_pgsql_cancel_real(const char *file, const char *func, int line, switch_pgsql_handle_t *handle)
Definition: switch_pgsql.c:266
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
switch_pgsql_status_t switch_pgsql_flush(switch_pgsql_handle_t *handle)
Definition: switch_pgsql.c:842
#define switch_pgsql_finish_results(handle)
Definition: switch_pgsql.h:107
switch_pgsql_status_t switch_pgsql_finish_results_real(const char *file, const char *func, int line, switch_pgsql_handle_t *handle)
Definition: switch_pgsql.c:457
switch_pgsql_status_t switch_pgsql_send_query(switch_pgsql_handle_t *handle, const char *sql)
Definition: switch_pgsql.c:246
switch_pgsql_status_t switch_pgsql_handle_disconnect(switch_pgsql_handle_t *handle)
Disconnects a PGSQL connection from the database.
Definition: switch_pgsql.c:225
#define switch_pgsql_next_result(h, r)
Definition: switch_pgsql.h:102
#define switch_pgsql_handle_exec_base(handle, sql, err)
Definition: switch_pgsql.h:111
#define switch_str_nil(s)
Make a null string a blank string instead.
Definition: switch_utils.h:903
void switch_pgsql_handle_destroy(switch_pgsql_handle_t **handlep)
Definition: switch_pgsql.c:764
#define switch_pgsql_cancel(handle)
Definition: switch_pgsql.h:99
char * switch_pgsql_handle_get_error(switch_pgsql_handle_t *handle)
Definition: switch_pgsql.c:796
switch_pgsql_handle_t * switch_pgsql_handle_new(const char *dsn)
Create a new handle for the PGSQL connection.
Definition: switch_pgsql.c:66
Main Library Header.
#define switch_event_create(event, id)
Create a new event assuming it will not be custom event and therefore hiding the unused parameters...
Definition: switch_event.h:383
switch_pgsql_state_t
Definition: switch_pgsql.h:46
#define SWITCH_DECLARE(type)
switch_pgsql_status_t switch_pgsql_handle_exec_base_detailed(const char *file, const char *func, int line, switch_pgsql_handle_t *handle, const char *sql, char **err)
Definition: switch_pgsql.c:576
switch_bool_t switch_pgsql_available(void)
Definition: switch_pgsql.c:819
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const char * switch_stristr(const char *instr, const char *str)
int switch_pgsql_handle_affected_rows(switch_pgsql_handle_t *handle)
Definition: switch_pgsql.c:810
#define switch_assert(expr)
switch_pgsql_status_t switch_pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pgsql_result_t **result_out, int msec)
Definition: switch_pgsql.c:287
memset(buf, 0, buflen)
switch_pgsql_status_t switch_pgsql_handle_connect(switch_pgsql_handle_t *handle)
Connect to the database specified by the DSN passed to the switch_pgsql_handle_new() call which initi...
Definition: switch_pgsql.c:489