Initial core-pgsql support based on native libpq; FS starts and stops without errors using core-pgsql.

This commit is contained in:
Eliot Gable 2012-09-30 01:48:48 +00:00
parent 0263ce9247
commit 5cb354dddc
17 changed files with 1283 additions and 90 deletions

View File

@ -207,7 +207,8 @@ library_include_HEADERS = \
libs/libteletone/src/libteletone.h \
libs/libtpl-1.5/src/tpl.h \
src/include/switch_limit.h \
src/include/switch_odbc.h
src/include/switch_odbc.h \
src/include/switch_pgsql.h
nodist_libfreeswitch_la_SOURCES = \
src/include/switch_frame.h \
@ -262,6 +263,7 @@ libfreeswitch_la_SOURCES = \
src/switch_config.c \
src/switch_time.c \
src/switch_odbc.c \
src/switch_pgsql.c \
src/switch_limit.c \
src/g711.c \
src/switch_pcm.c \

View File

@ -144,6 +144,8 @@
<param name="rtp-enable-zrtp" value="true"/>
<!-- Example DSN when using "./configure --enable-core-pgsql-support" -->
<!-- <param name="core-db-dsn" value="pgsql;hostaddr=127.0.0.1 dbname=freeswitch user=freeswitch password='' options='-c client_min_messages=NOTICE' application_name='freeswitch'" /> -->
<!-- <param name="core-db-dsn" value="dsn:username:password" /> -->
<!--
Allow to specify the sqlite db at a different location (In this example, move it to ramdrive for

View File

@ -213,6 +213,9 @@
<!--If you have ODBC support and a working dsn you can use it instead of SQLite-->
<!--<param name="odbc-dsn" value="dsn:user:pass"/>-->
<!-- Or, if you have PGSQL support, you can use that -->
<!--<param name="odbc-dsn" value="pgsql;hostaddr=127.0.0.1 dbname=freeswitch user=freeswitch password='' options='-c client_min_messages=NOTICE' application_name='freeswitch'" />-->
<!--Uncomment to set all inbound calls to no media mode-->
<!--<param name="inbound-bypass-media" value="true"/>-->

View File

@ -395,7 +395,30 @@ if test "x$enable_core_odbc_support" != "xno"; then
AC_CHECK_LIB([odbc], [SQLDisconnect],, AC_MSG_ERROR([no usable libodbc; please install unixodbc devel package or equivalent]))
fi
AC_ARG_ENABLE(core-pgsql-support,
[AS_HELP_STRING([--enable-core-pgsql-support], [Compile with PGSQL Support])],,[enable_core_pgsql_support="no"])
if test x"$enable_core_pgsql_support" = x"yes" ; then
AC_PATH_PROG([PG_CONFIG], [pg_config], [no])
if test "$PG_CONFIG" != "no"; then
AC_MSG_CHECKING([for PostgreSQL libraries])
POSTGRESQL_CFLAGS="`$PG_CONFIG --cflags` -I`$PG_CONFIG --includedir`"
POSTGRESQL_CXXFLAGS="`$PG_CONFIG --cppflags` -I`$PG_CONFIG --includedir`"
POSTGRESQL_LDFLAGS="`$PG_CONFIG --ldflags` -L`$PG_CONFIG --libdir` -lpq"
POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'`
AC_DEFINE([SWITCH_HAVE_PGSQL], [1], [Define to 1 if PostgreSQL libraries are available])
AC_CHECK_LIB([pq], [PQgetvalue],, AC_MSG_ERROR([no usable libpq; please install PostgreSQL devel package or equivalent]))
AC_MSG_RESULT([yes])
SWITCH_AM_CFLAGS="$POSTGRESQL_CFLAGS $SWITCH_AM_CFLAGS"
SWITCH_AM_CXXFLAGS="$POSTGRESQL_CXXFLAGS $SWITCH_AM_CXXFLAGS"
SWITCH_AM_LDFLAGS="$POSTGRESQL_LDFLAGS $SWITCH_AM_LDFLAGS"
else
AC_MSG_RESULT([no])
AC_MSG_FAILURE([Unabled to find pg_config in PATH. Is PostgreSQL installed?])
fi
fi
AC_ARG_ENABLE(timerfd-wrapper,
[AC_HELP_STRING([--enable-timerfd-wrapper],[timerfd is in the kernel but not in your libc])],[enable_timer_fd_wrapper="$enableval"],[enable_timer_fd_wrapper="no"])

View File

@ -135,6 +135,7 @@
#include "switch_config.h"
#include "switch_nat.h"
#include "switch_odbc.h"
#include "switch_pgsql.h"
#include "switch_json.h"
#include "switch_limit.h"

View File

@ -2210,12 +2210,14 @@ typedef enum {
typedef enum {
SCDB_TYPE_CORE_DB,
SCDB_TYPE_ODBC
SCDB_TYPE_ODBC,
SCDB_TYPE_PGSQL
} switch_cache_db_handle_type_t;
typedef union {
switch_core_db_t *core_db_dbh;
switch_odbc_handle_t *odbc_dbh;
switch_pgsql_handle_t *pgsql_dbh;
} switch_cache_db_native_handle_t;
typedef struct {
@ -2228,9 +2230,14 @@ typedef struct {
char *pass;
} switch_cache_db_odbc_options_t;
typedef struct {
char *dsn;
} switch_cache_db_pgsql_options_t;
typedef union {
switch_cache_db_core_db_options_t core_db_options;
switch_cache_db_odbc_options_t odbc_options;
switch_cache_db_pgsql_options_t pgsql_options;
} switch_cache_db_connection_options_t;
struct switch_cache_db_handle;
@ -2241,6 +2248,11 @@ static inline const char *switch_cache_db_type_name(switch_cache_db_handle_type_
const char *type_str = "INVALID";
switch (type) {
case SCDB_TYPE_PGSQL:
{
type_str = "PGSQL";
}
break;
case SCDB_TYPE_ODBC:
{
type_str = "ODBC";

162
src/include/switch_pgsql.h Normal file
View File

@ -0,0 +1,162 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
* Eliot Gable <egable@gmail.com>
*
* switch_pgsql.h -- PGSQL Driver
*
*/
#ifndef SWITCH_PGSQL_H
#define SWITCH_PGSQL_H
#include <switch.h>
#define DEFAULT_PGSQL_RETRIES 120
SWITCH_BEGIN_EXTERN_C
struct switch_pgsql_handle;
struct switch_pgsql_result;
typedef enum {
SWITCH_PGSQL_STATE_INIT,
SWITCH_PGSQL_STATE_DOWN,
SWITCH_PGSQL_STATE_CONNECTED,
SWITCH_PGSQL_STATE_ERROR
} switch_pgsql_state_t;
typedef enum {
SWITCH_PGSQL_SUCCESS = 0,
SWITCH_PGSQL_FAIL = -1
} switch_pgsql_status_t;
/*!
\brief Create a new handle for the PGSQL connection.
\param dsn The DSN of the database to connect to. See documentation for PQconnectdb() at
http://www.postgresql.org/docs/9.0/static/libpq-connect.html. The DSN *MUST* be
prefixed with 'pgsql;' to use the switch_cache_db* functionality. However, the DSN
passed to this function directly *MUST NOT* be prefixed with 'pgsql;'.
\return Returns a pointer to a newly allocated switch_pgsql_handle_t type or NULL on failure.
*/
SWITCH_DECLARE(switch_pgsql_handle_t *) switch_pgsql_handle_new(const char *dsn);
/*!
\brief Sets the number of retries if the PGSQL connection fails.
\param handle A fully allocated switch_pgsql_handle_t returned from a call to switch_pgsql_handle_new().
\param num_retries How many times to retry connecting to the database if this connection fails.
*/
SWITCH_DECLARE(void) switch_pgsql_set_num_retries(switch_pgsql_handle_t *handle, int num_retries);
/*!
\brief Disconnects a PGSQL connection from the database.
\param handle The PGSQL database handle to disconnect.
\return Returns SWITCH_PGSQL_SUCCESS or SWITCH_PGSQL_FAIL.
*/
SWITCH_DECLARE(switch_pgsql_status_t ) switch_pgsql_handle_disconnect(switch_pgsql_handle_t *handle);
#if 0
) /* Emacs formatting issue */
#endif
/*!
\brief Connect to the database specified by the DSN passed to the switch_pgsql_handle_new() call which
initialized this handle.
\param The database handle to connect to the database.
\return Returns SWITCH_PGSQL_SUCCESS or SWITCH_PGSQL_FAIL.
*/
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_connect(switch_pgsql_handle_t *handle);
/*!
*/
SWITCH_DECLARE(void) switch_pgsql_handle_destroy(switch_pgsql_handle_t **handlep);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_send_query(switch_pgsql_handle_t *handle, const char* sql);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_cancel_real(const char *file, const char *func, int line, switch_pgsql_handle_t *handle);
#define switch_pgsql_cancel(handle) switch_pgsql_cancel_real(__FILE__, (char * )__SWITCH_FUNC__, __LINE__, handle)
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pgsql_result_t **result_out, int seconds);
#define switch_pgsql_next_result(h, r) switch_pgsql_next_result_timed(h, r, 10000)
SWITCH_DECLARE(void) switch_pgsql_free_result(switch_pgsql_result_t **result);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_finish_results_real(const char* file, const char *func, int line, switch_pgsql_handle_t *handle);
#define switch_pgsql_finish_results(handle) switch_pgsql_finish_results_real(__FILE__, (char * )__SWITCH_FUNC__, __LINE__, handle)
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec_base(switch_pgsql_handle_t *handle, const char *sql, char **err);
SWITCH_DECLARE(switch_pgsql_state_t) switch_pgsql_handle_get_state(switch_pgsql_handle_t *handle);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec(switch_pgsql_handle_t *handle, const char *sql, char **err);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec_string(switch_pgsql_handle_t *handle, const char *sql, char *resbuf, size_t len, char **err);
SWITCH_DECLARE(switch_bool_t) switch_pgsql_available(void);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_SQLSetAutoCommitAttr(switch_pgsql_handle_t *handle, switch_bool_t on);
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_SQLEndTran(switch_pgsql_handle_t *handle, switch_bool_t commit);
/*!
\brief Execute the sql query and issue a callback for each row returned
\param file the file from which this function is called
\param func the function from which this function is called
\param line the line from which this function is called
\param handle the PGSQL handle
\param sql the sql string to execute
\param callback the callback function to execute
\param pdata the state data passed on each callback invocation
\return SWITCH_STATUS_SUCCESS if the operation was successful
\note none
*/
SWITCH_DECLARE(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);
/*!
\brief Execute the sql query and issue a callback for each row returned
\param handle the PGSQL handle
\param sql the sql string to execute
\param callback the callback function to execute
\param pdata the state data passed on each callback invocation
\return SWITCH_STATUS_SUCCESS if the operation was successful
\note none
*/
#define switch_pgsql_handle_callback_exec(handle, sql, callback, pdata, err) \
switch_pgsql_handle_callback_exec_detailed(__FILE__, (char * )__SWITCH_FUNC__, __LINE__, \
handle, sql, callback, pdata, err)
SWITCH_DECLARE(char *) switch_pgsql_handle_get_error(switch_pgsql_handle_t *handle);
SWITCH_DECLARE(int) switch_pgsql_handle_affected_rows(switch_pgsql_handle_t *handle);
SWITCH_END_EXTERN_C
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/

View File

@ -324,7 +324,7 @@ typedef enum {
SCF_CLEAR_SQL = (1 << 17),
SCF_THREADED_SYSTEM_EXEC = (1 << 18),
SCF_SYNC_CLOCK_REQUESTED = (1 << 19),
SCF_CORE_ODBC_REQ = (1 << 20),
SCF_CORE_NON_SQLITE_DB_REQ = (1 << 20),
SCF_DEBUG_SQL = (1 << 21),
SCF_API_EXPANSION = (1 << 22),
SCF_SESSION_THREAD_POOL = (1 << 23)
@ -1833,6 +1833,8 @@ typedef struct switch_buffer switch_buffer_t;
typedef struct switch_codec_settings switch_codec_settings_t;
typedef struct switch_codec_fmtp switch_codec_fmtp_t;
typedef struct switch_odbc_handle switch_odbc_handle_t;
typedef struct switch_pgsql_handle switch_pgsql_handle_t;
typedef struct switch_pgsql_result switch_pgsql_result_t;
typedef struct switch_io_routines switch_io_routines_t;
typedef struct switch_speech_handle switch_speech_handle_t;

View File

@ -94,12 +94,20 @@ static switch_cache_db_handle_t *cidlookup_get_db_handle(void)
switch_cache_db_handle_t *dbh = NULL;
if (!zstr(globals.odbc_dsn)) {
options.odbc_options.dsn = globals.odbc_dsn;
options.odbc_options.user = globals.odbc_user;
options.odbc_options.pass = globals.odbc_pass;
char *dsn;
if ((dsn = strstr(globals.odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_PGSQL, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
} else {
options.odbc_options.dsn = globals.odbc_dsn;
options.odbc_options.user = globals.odbc_user;
options.odbc_options.pass = globals.odbc_pass;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
}
}
return dbh;
}
@ -112,8 +120,8 @@ static switch_status_t config_callback_dsn(switch_xml_config_item_t *data, const
switch_cache_db_handle_t *dbh = NULL;
if (!switch_odbc_available()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC is not compiled in. Do not configure odbc-dsn parameter!\n");
if (!switch_odbc_available() && !switch_pgsql_available()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC and PGSQL are not compiled in. Do not configure odbc-dsn parameter!\n");
return SWITCH_STATUS_FALSE;
}
@ -134,7 +142,7 @@ static switch_status_t config_callback_dsn(switch_xml_config_item_t *data, const
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connecting to dsn: %s\n", globals.odbc_dsn);
if (!(dbh = cidlookup_get_db_handle())) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open Database!\n");
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
}
@ -195,7 +203,7 @@ static switch_bool_t cidlookup_execute_sql_callback(char *sql, switch_core_db_ca
retval = SWITCH_TRUE;
}
} else {
*err = switch_core_sprintf(cbt->pool, "Unable to get ODBC handle. dsn: %s, dbh is %s\n", globals.odbc_dsn, dbh ? "not null" : "null");
*err = switch_core_sprintf(cbt->pool, "Unable to get database handle. dsn: %s, dbh is %s\n", globals.odbc_dsn, dbh ? "not null" : "null");
}
switch_cache_db_release_db_handle(&dbh);
@ -564,7 +572,7 @@ static cid_data_t *do_lookup(switch_memory_pool_t *pool, switch_event_t *event,
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "caller_id_number", number);
/* database always wins */
if (switch_odbc_available() && globals.odbc_dsn && globals.sql) {
if ((switch_odbc_available() || switch_pgsql_available()) && globals.odbc_dsn && globals.sql) {
name = do_db_lookup(pool, event, number, globals.sql);
if (name) {
cid->name = name;
@ -610,7 +618,7 @@ static cid_data_t *do_lookup(switch_memory_pool_t *pool, switch_event_t *event,
switch_assert(cid);
}
/* append area if we can */
if (!cid->area && !skipcitystate && strlen(number) == 11 && number[0] == '1' && switch_odbc_available() && globals.odbc_dsn && globals.citystate_sql) {
if (!cid->area && !skipcitystate && strlen(number) == 11 && number[0] == '1' && (switch_odbc_available() || switch_pgsql_available()) && globals.odbc_dsn && globals.citystate_sql) {
/* yes, this is really area */
name = do_db_lookup(pool, event, number, globals.citystate_sql);
@ -768,7 +776,7 @@ SWITCH_STANDARD_API(cidlookup_function)
stream->write_function(stream, " odbc-dsn: %s\n sql: %s\n citystate-sql: %s\n",
globals.odbc_dsn ? globals.odbc_dsn : "(null)",
globals.sql ? globals.sql : "(null)", globals.citystate_sql ? globals.citystate_sql : "(null)");
stream->write_function(stream, " ODBC Compiled: %s\n", switch_odbc_available()? "true" : "false");
stream->write_function(stream, " ODBC Compiled: %s; PGSQL Compiled: %s\n", switch_odbc_available() ? "true" : "false", switch_pgsql_available() ? "true" : "false");
switch_goto_status(SWITCH_STATUS_SUCCESS, done);
}

View File

@ -92,12 +92,20 @@ switch_cache_db_handle_t *limit_get_db_handle(void)
switch_cache_db_handle_t *dbh = NULL;
if (!zstr(globals.odbc_dsn)) {
options.odbc_options.dsn = globals.odbc_dsn;
options.odbc_options.user = globals.odbc_user;
options.odbc_options.pass = globals.odbc_pass;
char *dsn;
if ((dsn = strstr(globals.odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_PGSQL, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
} else {
options.odbc_options.dsn = globals.odbc_dsn;
options.odbc_options.user = globals.odbc_user;
options.odbc_options.pass = globals.odbc_pass;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
}
return dbh;
} else {
options.core_db_options.db_path = globals.dbname;
@ -275,7 +283,7 @@ SWITCH_LIMIT_STATUS(limit_status_db)
/* INIT / Config */
static switch_xml_config_string_options_t limit_config_dsn = { NULL, 0, "[^:]+:[^:]+:.+" };
static switch_xml_config_string_options_t limit_config_dsn = { NULL, 0, "^pgsql;|[^:]+:[^:]+:.+" };
static switch_xml_config_item_t config_settings[] = {
SWITCH_CONFIG_ITEM("odbc-dsn", SWITCH_CONFIG_STRING, 0, &globals.odbc_dsn, NULL, &limit_config_dsn,

View File

@ -731,12 +731,20 @@ switch_cache_db_handle_t *fifo_get_db_handle(void)
switch_cache_db_handle_t *dbh = NULL;
if (!zstr(globals.odbc_dsn)) {
options.odbc_options.dsn = globals.odbc_dsn;
options.odbc_options.user = globals.odbc_user;
options.odbc_options.pass = globals.odbc_pass;
char *dsn;
if ((dsn = strstr(globals.odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS) {
dbh = NULL;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_PGSQL, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
} else {
options.odbc_options.dsn = globals.odbc_dsn;
options.odbc_options.user = globals.odbc_user;
options.odbc_options.pass = globals.odbc_pass;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS) {
dbh = NULL;
}
}
return dbh;
} else {
@ -4010,7 +4018,7 @@ static switch_status_t load_config(int reload, int del_all)
}
if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
if (switch_odbc_available()) {
if (switch_odbc_available() || switch_pgsql_available()) {
switch_set_string(globals.odbc_dsn, val);
if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
*globals.odbc_user++ = '\0';

View File

@ -167,12 +167,20 @@ switch_cache_db_handle_t *vm_get_db_handle(vm_profile_t *profile)
switch_cache_db_handle_t *dbh = NULL;
if (!zstr(profile->odbc_dsn)) {
options.odbc_options.dsn = profile->odbc_dsn;
options.odbc_options.user = profile->odbc_user;
options.odbc_options.pass = profile->odbc_pass;
char *dsn;
if ((dsn = strstr(profile->odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_PGSQL, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
} else {
options.odbc_options.dsn = profile->odbc_dsn;
options.odbc_options.user = profile->odbc_user;
options.odbc_options.pass = profile->odbc_pass;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
}
return dbh;
} else {
options.core_db_options.db_path = profile->dbname;

View File

@ -4414,7 +4414,7 @@ switch_status_t config_sofia(int reload, char *profile_name)
sofia_set_flag(profile, TFLAG_CAPTURE);
nua_set_params(profile->nua, TPTAG_CAPT(mod_sofia_globals.capture_server), TAG_END());
} else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
if (switch_odbc_available()) {
if (switch_odbc_available() || switch_pgsql_available()) {
profile->odbc_dsn = switch_core_strdup(profile->pool, val);
if ((profile->odbc_user = strchr(profile->odbc_dsn, ':'))) {
*profile->odbc_user++ = '\0';

View File

@ -6367,12 +6367,20 @@ switch_cache_db_handle_t *sofia_glue_get_db_handle(sofia_profile_t *profile)
switch_cache_db_handle_t *dbh = NULL;
if (!zstr(profile->odbc_dsn)) {
options.odbc_options.dsn = profile->odbc_dsn;
options.odbc_options.user = profile->odbc_user;
options.odbc_options.pass = profile->odbc_pass;
char *dsn;
if ((dsn = strstr(profile->odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_PGSQL, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
} else {
options.odbc_options.dsn = profile->odbc_dsn;
options.odbc_options.user = profile->odbc_user;
options.odbc_options.pass = profile->odbc_pass;
if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
dbh = NULL;
}
return dbh;
} else {
options.core_db_options.db_path = profile->dbname;

View File

@ -1910,7 +1910,7 @@ static void switch_load_core_config(const char *file)
} else if (!strcasecmp(var, "core-db-name") && !zstr(val)) {
runtime.dbname = switch_core_strdup(runtime.memory_pool, val);
} else if (!strcasecmp(var, "core-db-dsn") && !zstr(val)) {
if (switch_odbc_available()) {
if (switch_odbc_available() || switch_pgsql_available()) {
runtime.odbc_dsn = switch_core_strdup(runtime.memory_pool, val);
if ((runtime.odbc_user = strchr(runtime.odbc_dsn, ':'))) {
*runtime.odbc_user++ = '\0';
@ -1919,10 +1919,10 @@ static void switch_load_core_config(const char *file)
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC AND PGSQL ARE NOT AVAILABLE!\n");
}
} else if (!strcasecmp(var, "core-recovery-db-dsn") && !zstr(val)) {
if (switch_odbc_available()) {
if (switch_odbc_available() || switch_pgsql_available()) {
runtime.recovery_odbc_dsn = switch_core_strdup(runtime.memory_pool, val);
if ((runtime.recovery_odbc_user = strchr(runtime.recovery_odbc_dsn, ':'))) {
*runtime.recovery_odbc_user++ = '\0';
@ -1931,10 +1931,10 @@ static void switch_load_core_config(const char *file)
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC AND PGSQL ARE NOT AVAILABLE!\n");
}
} else if (!strcasecmp(var, "core-odbc-required") && !zstr(val)) {
switch_set_flag((&runtime), SCF_CORE_ODBC_REQ);
} else if (!strcasecmp(var, "core-non-sqlite-db-required") && !zstr(val)) {
switch_set_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ);
} else if (!strcasecmp(var, "core-dbtype") && !zstr(val)) {
if (!strcasecmp(val, "MSSQL")) {
runtime.odbc_dbtype = DBTYPE_MSSQL;

View File

@ -190,7 +190,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t
}
if (zstr(runtime.odbc_dsn)) {
if (switch_test_flag((&runtime), SCF_CORE_ODBC_REQ)) {
if (switch_test_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ)) {
return SWITCH_STATUS_FALSE;
}
@ -202,11 +202,18 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_CORE_DB, &options, file, func, line);
} else {
options.odbc_options.dsn = runtime.odbc_dsn;
options.odbc_options.user = runtime.odbc_user;
options.odbc_options.pass = runtime.odbc_pass;
char *dsn;
if ((dsn = strstr(runtime.odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_ODBC, &options, file, func, line);
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_PGSQL, &options, file, func, line);
} else {
options.odbc_options.dsn = runtime.odbc_dsn;
options.odbc_options.user = runtime.odbc_user;
options.odbc_options.pass = runtime.odbc_pass;
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_ODBC, &options, file, func, line);
}
}
/* I *think* we can do without this now, if not let me know
@ -218,6 +225,56 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t
return r;
}
#define SWITCH_CORE_PERSIST_DB "core"
/*!
\brief Open the default system database
*/
SWITCH_DECLARE(switch_status_t) _switch_core_persist_db_handle(switch_cache_db_handle_t **dbh, const char *file, const char *func, int line)
{
switch_cache_db_connection_options_t options = { {0} };
switch_status_t r;
if (!sql_manager.manage) {
return SWITCH_STATUS_FALSE;
}
if (zstr(runtime.odbc_dsn)) {
if (switch_test_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ)) {
return SWITCH_STATUS_FALSE;
}
if (runtime.dbname) {
options.core_db_options.db_path = runtime.dbname;
} else {
options.core_db_options.db_path = SWITCH_CORE_PERSIST_DB;
}
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_CORE_DB, &options, file, func, line);
} else {
char *dsn;
if ((dsn = strstr(runtime.odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_PGSQL, &options, file, func, line);
} else {
options.odbc_options.dsn = runtime.odbc_dsn;
options.odbc_options.user = runtime.odbc_user;
options.odbc_options.pass = runtime.odbc_pass;
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_ODBC, &options, file, func, line);
}
}
/* I *think* we can do without this now, if not let me know
if (r == SWITCH_STATUS_SUCCESS && !(*dbh)->io_mutex) {
(*dbh)->io_mutex = sql_manager.io_mutex;
}
*/
return r;
}
#define SWITCH_CORE_RECOVERY_DB "core_recovery"
SWITCH_DECLARE(switch_status_t) _switch_core_recovery_db_handle(switch_cache_db_handle_t **dbh, const char *file, const char *func, int line)
{
@ -229,7 +286,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_recovery_db_handle(switch_cache_db_
}
if (zstr(runtime.recovery_odbc_dsn)) {
if (switch_test_flag((&runtime), SCF_CORE_ODBC_REQ)) {
if (switch_test_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ)) {
return SWITCH_STATUS_FALSE;
}
@ -241,11 +298,18 @@ SWITCH_DECLARE(switch_status_t) _switch_core_recovery_db_handle(switch_cache_db_
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_CORE_DB, &options, file, func, line);
} else {
options.odbc_options.dsn = runtime.recovery_odbc_dsn;
options.odbc_options.user = runtime.recovery_odbc_user;
options.odbc_options.pass = runtime.recovery_odbc_pass;
char *dsn;
if ((dsn = strstr(runtime.recovery_odbc_dsn, "pgsql;")) != NULL) {
options.pgsql_options.dsn = (char*)(dsn + 6);
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_ODBC, &options, file, func, line);
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_PGSQL, &options, file, func, line);
} else {
options.odbc_options.dsn = runtime.recovery_odbc_dsn;
options.odbc_options.user = runtime.recovery_odbc_user;
options.odbc_options.pass = runtime.recovery_odbc_pass;
r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_ODBC, &options, file, func, line);
}
}
/* I *think* we can do without this now, if not let me know
@ -286,6 +350,11 @@ static void sql_close(time_t prune)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Dropping idle DB connection %s\n", dbh->name);
switch (dbh->type) {
case SCDB_TYPE_PGSQL:
{
switch_pgsql_handle_destroy(&dbh->native_handle.pgsql_dbh);
}
break;
case SCDB_TYPE_ODBC:
{
switch_odbc_handle_destroy(&dbh->native_handle.odbc_dbh);
@ -373,8 +442,8 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
uint32_t yield_len = 100000, total_yield = 0;
const char *db_name = NULL;
const char *db_user = NULL;
const char *db_pass = NULL;
const char *odbc_user = NULL;
const char *odbc_pass = NULL;
while(runtime.max_db_handles && sql_manager.total_handles >= runtime.max_db_handles && sql_manager.total_used_handles >= sql_manager.total_handles) {
if (!waiting++) {
@ -393,18 +462,24 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
}
switch (type) {
case SCDB_TYPE_PGSQL:
{
db_name = connection_options->odbc_options.dsn;
odbc_user = NULL;
odbc_pass = NULL;
}
case SCDB_TYPE_ODBC:
{
db_name = connection_options->odbc_options.dsn;
db_user = connection_options->odbc_options.user;
db_pass = connection_options->odbc_options.pass;
odbc_user = connection_options->odbc_options.user;
odbc_pass = connection_options->odbc_options.pass;
}
break;
case SCDB_TYPE_CORE_DB:
{
db_name = connection_options->core_db_options.db_path;
db_user = "";
db_pass = "";
odbc_user = NULL;
odbc_pass = NULL;
}
break;
}
@ -413,8 +488,11 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
return SWITCH_STATUS_FALSE;
}
snprintf(db_str, sizeof(db_str) - 1, "db=\"%s\";user=\"%s\";pass=\"%s\"", db_name, db_user, db_pass);
if (odbc_user || odbc_pass) {
snprintf(db_str, sizeof(db_str) - 1, "db=\"%s\";user=\"%s\";pass=\"%s\"", db_name, odbc_user, odbc_pass);
} else {
snprintf(db_str, sizeof(db_str) - 1, "db=\"%s\"", db_name);
}
snprintf(db_callsite_str, sizeof(db_callsite_str) - 1, "%s:%d", file, line);
snprintf(thread_str, sizeof(thread_str) - 1, "thread=\"%lu\"", (unsigned long) (intptr_t) self);
@ -424,8 +502,23 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
} else {
switch_core_db_t *db = NULL;
switch_odbc_handle_t *odbc_dbh = NULL;
switch_pgsql_handle_t *pgsql_dbh = NULL;
switch (type) {
case SCDB_TYPE_PGSQL:
{
if (!switch_pgsql_available()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! PGSQL NOT AVAILABLE! Can't connect to DSN %s\n", connection_options->pgsql_options.dsn);
goto end;
}
if ((pgsql_dbh = switch_pgsql_handle_new(connection_options->pgsql_options.dsn))) {
if (switch_pgsql_handle_connect(pgsql_dbh) != SWITCH_PGSQL_SUCCESS) {
switch_pgsql_handle_destroy(&pgsql_dbh);
}
}
}
break;
case SCDB_TYPE_ODBC:
{
@ -454,8 +547,8 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
goto end;
}
if (!db && !odbc_dbh) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure to connect to %s %s!\n", db?"SQLITE":"ODBC", db?connection_options->core_db_options.db_path:connection_options->odbc_options.dsn);
if (!db && !odbc_dbh && !pgsql_dbh) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure to connect to %s %s!\n", (db ? "SQLITE" : (odbc_dbh ? "ODBC" : "PGSQL")), (db ? connection_options->core_db_options.db_path : (odbc_dbh ? connection_options->odbc_options.dsn : connection_options->pgsql_options.dsn)));
goto end;
}
@ -466,8 +559,10 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
if (db) {
new_dbh->native_handle.core_db_dbh = db;
} else {
} else if (odbc_dbh) {
new_dbh->native_handle.odbc_dbh = odbc_dbh;
} else {
new_dbh->native_handle.pgsql_dbh = pgsql_dbh;
}
add_handle(new_dbh, db_str, db_callsite_str, thread_str);
@ -499,6 +594,11 @@ static switch_status_t switch_cache_db_execute_sql_real(switch_cache_db_handle_t
}
switch (dbh->type) {
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, sql, &errmsg);
}
break;
case SCDB_TYPE_ODBC:
{
status = switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, sql, NULL, &errmsg);
@ -650,6 +750,11 @@ SWITCH_DECLARE(int) switch_cache_db_affected_rows(switch_cache_db_handle_t *dbh)
return switch_odbc_handle_affected_rows(dbh->native_handle.odbc_dbh);
}
break;
case SCDB_TYPE_PGSQL:
{
return switch_pgsql_handle_affected_rows(dbh->native_handle.pgsql_dbh);
}
break;
}
return 0;
}
@ -707,6 +812,11 @@ SWITCH_DECLARE(char *) switch_cache_db_execute_sql2str(switch_cache_db_handle_t
status = switch_odbc_handle_exec_string(dbh->native_handle.odbc_dbh, sql, str, len, err);
}
break;
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_exec_string(dbh->native_handle.pgsql_dbh, sql, str, len, err);
}
break;
}
end:
@ -784,16 +894,34 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans(switch_
while (begin_retries > 0) {
again = 0;
if (runtime.odbc_dbtype == DBTYPE_DEFAULT) {
switch_cache_db_execute_sql_real(dbh, "BEGIN", &errmsg);
} else {
switch_odbc_status_t result;
if ((result = switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 0)) != SWITCH_ODBC_SUCCESS) {
char tmp[100];
switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
errmsg = strdup(tmp);
switch(dbh->type) {
case SCDB_TYPE_CORE_DB:
{
switch_cache_db_execute_sql_real(dbh, "BEGIN", &errmsg);
}
break;
case SCDB_TYPE_ODBC:
{
switch_odbc_status_t result;
if ((result = switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 0)) != SWITCH_ODBC_SUCCESS) {
char tmp[100];
switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
errmsg = strdup(tmp);
}
}
break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_status_t result;
if ((result = switch_pgsql_SQLSetAutoCommitAttr(dbh->native_handle.pgsql_dbh, 0)) != SWITCH_PGSQL_SUCCESS) {
char tmp[100];
switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
errmsg = strdup(tmp);
}
}
break;
}
if (errmsg) {
@ -807,11 +935,25 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans(switch_
errmsg = NULL;
if (again) {
if (runtime.odbc_dbtype == DBTYPE_DEFAULT) {
switch_cache_db_execute_sql_real(dbh, "COMMIT", NULL);
} else {
switch_odbc_SQLEndTran(dbh->native_handle.odbc_dbh, 1);
switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
switch(dbh->type) {
case SCDB_TYPE_CORE_DB:
{
switch_cache_db_execute_sql_real(dbh, "COMMIT", NULL);
}
break;
case SCDB_TYPE_ODBC:
{
switch_odbc_SQLEndTran(dbh->native_handle.odbc_dbh, 1);
switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
}
break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1);
switch_pgsql_SQLSetAutoCommitAttr(dbh->native_handle.pgsql_dbh, 1);
switch_pgsql_finish_results(dbh->native_handle.pgsql_dbh);
}
break;
}
goto again;
@ -868,11 +1010,25 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans(switch_
done:
if (runtime.odbc_dbtype == DBTYPE_DEFAULT) {
switch_cache_db_execute_sql_real(dbh, "COMMIT", NULL);
} else {
switch_odbc_SQLEndTran(dbh->native_handle.odbc_dbh, 1);
switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
switch(dbh->type) {
case SCDB_TYPE_CORE_DB:
{
switch_cache_db_execute_sql_real(dbh, "COMMIT", NULL);
}
break;
case SCDB_TYPE_ODBC:
{
switch_odbc_SQLEndTran(dbh->native_handle.odbc_dbh, 1);
switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
}
break;
case SCDB_TYPE_PGSQL:
{
switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1);
switch_pgsql_SQLSetAutoCommitAttr(dbh->native_handle.pgsql_dbh, 1);
switch_pgsql_finish_results(dbh->native_handle.pgsql_dbh);
}
break;
}
if (!zstr(runtime.core_db_post_trans_execute)) {
@ -903,6 +1059,11 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback(switch_cach
switch (dbh->type) {
case SCDB_TYPE_PGSQL:
{
status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err);
}
break;
case SCDB_TYPE_ODBC:
{
status = switch_odbc_handle_callback_exec(dbh->native_handle.odbc_dbh, sql, callback, pdata, err);
@ -951,6 +1112,17 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand
if (io_mutex) switch_mutex_lock(io_mutex);
switch (dbh->type) {
case SCDB_TYPE_PGSQL:
{
if (switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, test_sql, NULL) != SWITCH_PGSQL_SUCCESS) {
r = SWITCH_FALSE;
if (drop_sql) {
switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, drop_sql, NULL);
}
switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, reactive_sql, NULL);
}
}
break;
case SCDB_TYPE_ODBC:
{
if (switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, test_sql, NULL, NULL) != SWITCH_ODBC_SUCCESS) {
@ -1057,6 +1229,8 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread,
switch_mutex_lock(sql_manager.cond_mutex);
switch (sql_manager.event_db->type) {
case SCDB_TYPE_PGSQL:
break;
case SCDB_TYPE_ODBC:
break;
case SCDB_TYPE_CORE_DB:
@ -2313,7 +2487,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
if (switch_core_db_handle(&sql_manager.dbh) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n");
if (switch_test_flag((&runtime), SCF_CORE_ODBC_REQ)) {
if (switch_test_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC IS REQUIRED!\n");
return SWITCH_STATUS_FALSE;
}
@ -2336,6 +2510,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n");
switch (sql_manager.dbh->type) {
case SCDB_TYPE_PGSQL:
case SCDB_TYPE_ODBC:
if (switch_test_flag((&runtime), SCF_CLEAR_SQL)) {
char sql[512] = "";
@ -2376,6 +2551,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
switch (sql_manager.dbh->type) {
case SCDB_TYPE_PGSQL:
case SCDB_TYPE_ODBC:
{
char *err;
@ -2405,7 +2581,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
runtime.odbc_dsn = NULL;
runtime.odbc_user = NULL;
runtime.odbc_pass = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Transactions not supported on your DB, disabling ODBC\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Transactions not supported on your DB, disabling non-SQLite support; using SQLite\n");
switch_cache_db_release_db_handle(&sql_manager.dbh);
free(err);
goto top;
@ -2536,9 +2712,9 @@ SWITCH_DECLARE(void) switch_core_sqldb_start_thread(void)
if (switch_core_recovery_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n");
if (switch_test_flag((&runtime), SCF_CORE_ODBC_REQ)) {
if (switch_test_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ)) {
int arg = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC IS REQUIRED!\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC OR PGSQL IS REQUIRED!\n");
switch_core_session_ctl(SCSC_SHUTDOWN_NOW, &arg);
}
@ -2562,8 +2738,8 @@ SWITCH_DECLARE(void) switch_core_sqldb_start_thread(void)
if (switch_core_db_handle(&sql_manager.dbh) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n");
if (switch_test_flag((&runtime), SCF_CORE_ODBC_REQ)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC IS REQUIRED!\n");
if (switch_test_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC OR PGSQL IS REQUIRED!\n");
goto end;
}

770
src/switch_pgsql.c Normal file
View File

@ -0,0 +1,770 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
* Eliot Gable <egable@gmail.com>
*
* switch_pgsql.c -- PGSQL Driver
*
*/
#include <switch.h>
#include <switch_private.h>
#ifdef SWITCH_HAVE_PGSQL
#include <libpq-fe.h>
struct switch_pgsql_handle {
char *dsn;
const char *sql;
PGconn* con;
int sock;
switch_pgsql_state_t state;
int affected_rows;
int num_retries;
switch_bool_t auto_commit;
switch_bool_t in_txn;
};
struct switch_pgsql_result {
PGresult *result;
ExecStatusType status;
char *err;
int rows;
int cols;
};
#endif
SWITCH_DECLARE(switch_pgsql_handle_t *) switch_pgsql_handle_new(const char *dsn)
{
#ifdef SWITCH_HAVE_PGSQL
switch_pgsql_handle_t *new_handle;
if (!(new_handle = malloc(sizeof(*new_handle)))) {
goto err;
}
memset(new_handle, 0, sizeof(*new_handle));
if (!(new_handle->dsn = strdup(dsn))) {
goto err;
}
new_handle->sock = 0;
new_handle->state = SWITCH_PGSQL_STATE_INIT;
new_handle->con = NULL;
new_handle->affected_rows = 0;
new_handle->num_retries = DEFAULT_PGSQL_RETRIES;
new_handle->auto_commit = SWITCH_TRUE;
new_handle->in_txn = SWITCH_FALSE;
return new_handle;
err:
if (new_handle) {
switch_safe_free(new_handle->dsn);
switch_safe_free(new_handle);
}
#endif
return NULL;
}
SWITCH_DECLARE(void) switch_pgsql_set_num_retries(switch_pgsql_handle_t *handle, int num_retries)
{
#ifdef SWITCH_HAVE_PGSQL
if (handle) {
handle->num_retries = num_retries;
}
#endif
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_disconnect(switch_pgsql_handle_t *handle)
{
#ifdef SWITCH_HAVE_PGSQL
if (!handle) {
return SWITCH_PGSQL_FAIL;
}
if (handle->state == SWITCH_PGSQL_STATE_CONNECTED) {
PQfinish(handle->con);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Disconnected from [%s]\n", handle->dsn);
}
handle->state = SWITCH_PGSQL_STATE_DOWN;
return SWITCH_PGSQL_SUCCESS;
#else
return SWITCH_PGSQL_FAIL;
#endif
}
#ifdef SWITCH_HAVE_PGSQL
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_send_query(switch_pgsql_handle_t *handle, const char* sql)
{
char *err_str;
if (!PQsendQuery(handle->con, sql)) {
err_str = switch_pgsql_handle_get_error(handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to send query (%s) to database: %s\n", sql, err_str);
switch_pgsql_finish_results(handle);
goto error;
}
handle->sql = sql;
return SWITCH_PGSQL_SUCCESS;
error:
return SWITCH_PGSQL_FAIL;
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_cancel_real(const char *file, const char *func, int line, switch_pgsql_handle_t *handle)
{
char err_buf[256];
PGcancel *cancel = NULL;
switch_pgsql_status_t ret = SWITCH_PGSQL_SUCCESS;
memset(err_buf, 0, 256);
cancel = PQgetCancel(handle->con);
if(!PQcancel(cancel, err_buf, 256)) {
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);
ret = SWITCH_PGSQL_FAIL;
}
PQfreeCancel(cancel);
return ret;
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pgsql_result_t **result_out, int msec)
{
switch_pgsql_result_t *res;
switch_time_t start;
switch_time_t ctime;
unsigned int usec = msec * 1000;
char *err_str;
fd_set pgset;
struct timeval timeout;
if(!handle) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "**BUG** Null handle passed to switch_pgsql_next_result.\n");
return SWITCH_PGSQL_FAIL;
}
/* Try to consume input that might be waiting right away */
if (PQconsumeInput(handle->con)) {
/* And check to see if we have a full result ready for reading */
if (PQisBusy(handle->con)) {
/* Wait for a result to become available, up to msec milliseconds */
start = switch_time_now();
while((ctime = switch_time_now()) - start <= usec) {
FD_ZERO(&pgset);
FD_SET(handle->sock, &pgset);
timeout.tv_sec = 0;
timeout.tv_usec = 500;
/* Wait for the PostgreSQL socket to be ready for data reads. */
if (select(FD_SETSIZE, &pgset, NULL, NULL, &timeout) > 0) {
/* Then try to consume any input waiting. */
if (PQconsumeInput(handle->con)) {
/* And check to see if we have a full result ready for reading */
if (!PQisBusy(handle->con)) {
/* If we can pull a full result without blocking, then break this loop */
break;
}
} else {
/* If we had an error trying to consume input, report it and cancel the query. */
err_str = switch_pgsql_handle_get_error(handle);
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);
switch_safe_free(err_str);
switch_pgsql_cancel(handle);
goto error;
}
}
}
/* If we broke the loop above because of a timeout, report that and cancel the query. */
if (ctime - start > usec) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Query (%s) took too long to complete or database not responding.\n", handle->sql);
switch_pgsql_cancel(handle);
goto error;
}
}
} else {
/* If we had an error trying to consume input, report it and cancel the query. */
err_str = switch_pgsql_handle_get_error(handle);
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);
switch_safe_free(err_str);
switch_pgsql_cancel(handle);
goto error;
}
/* At this point, we know we can read a full result without blocking. */
if(!(res = malloc(sizeof(switch_pgsql_result_t)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Malloc failed!\n");
goto error;
}
memset(res, 0, sizeof(switch_pgsql_result_t));
res->result = PQgetResult(handle->con);
if (res->result) {
*result_out = res;
res->status = PQresultStatus(res->result);
switch(res->status) {
case PGRES_TUPLES_OK:
{
res->rows = PQntuples(res->result);
handle->affected_rows = res->rows;
res->cols = PQnfields(res->result);
}
break;
case PGRES_COPY_OUT:
case PGRES_COPY_IN:
case PGRES_COMMAND_OK:
break;
case PGRES_EMPTY_QUERY:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_EMPTY_QUERY\n", handle->sql);
case PGRES_BAD_RESPONSE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_BAD_RESPONSE\n", handle->sql);
case PGRES_NONFATAL_ERROR:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_NONFATAL_ERROR\n", handle->sql);
case PGRES_FATAL_ERROR:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_FATAL_ERROR\n", handle->sql);
res->err = PQresultErrorMessage(res->result);
goto error;
break;
}
} else {
free(res);
res = NULL;
*result_out = NULL;
goto error;
}
return SWITCH_PGSQL_SUCCESS;
error:
return SWITCH_PGSQL_FAIL;
}
SWITCH_DECLARE(void) switch_pgsql_free_result(switch_pgsql_result_t **result)
{
if (!*result) {
return;
}
if ((*result)->result) {
PQclear((*result)->result);
}
free(*result);
*result = NULL;
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_finish_results_real(const char* file, const char* func, int line, switch_pgsql_handle_t *handle)
{
switch_pgsql_result_t *res = NULL;
switch_pgsql_status_t final_status = SWITCH_PGSQL_SUCCESS;
int done = 0;
do {
switch_pgsql_next_result(handle, &res);
if (res && res->err) {
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Error executing query:\n%s\n", res->err);
final_status = SWITCH_PGSQL_FAIL;
}
if (!res) done = 1;
switch_pgsql_free_result(&res);
} while (!done);
return final_status;
}
static int db_is_up(switch_pgsql_handle_t *handle)
{
int ret = 0;
switch_event_t *event;
char *err_str = NULL;
int max_tries = DEFAULT_PGSQL_RETRIES;
int code = 0, recon = 0;
if (handle) {
max_tries = handle->num_retries;
if (max_tries < 1)
max_tries = DEFAULT_PGSQL_RETRIES;
}
top:
if (!handle) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No DB Handle\n");
goto done;
}
if (!handle->con) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No DB Connection\n");
goto done;
}
if (PQstatus(handle->con) == CONNECTION_BAD) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "PQstatus returned bad connection; reconnecting...\n");
handle->state = SWITCH_PGSQL_STATE_ERROR;
PQreset(handle->con);
if (PQstatus(handle->con) == CONNECTION_BAD) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "PQstatus returned bad connection -- reconnection failed!\n");
goto error;
}
handle->state = SWITCH_PGSQL_STATE_CONNECTED;
}
/* if (!PQsendQuery(handle->con, "SELECT 1")) {
code = __LINE__;
goto error;
}
if(switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
code = __LINE__;
goto error;
}
if (!result || result->status != PGRES_COMMAND_OK) {
code = __LINE__;
goto error;
}
switch_pgsql_free_result(&result);
switch_pgsql_finish_results(handle);
*/
ret = 1;
goto done;
error:
err_str = switch_pgsql_handle_get_error(handle);
if (PQstatus(handle->con) == CONNECTION_BAD) {
handle->state = SWITCH_PGSQL_STATE_ERROR;
PQreset(handle->con);
if (PQstatus(handle->con) == CONNECTION_OK) {
handle->state = SWITCH_PGSQL_STATE_CONNECTED;
recon = SWITCH_PGSQL_SUCCESS;
}
}
max_tries--;
if (switch_event_create(&event, SWITCH_EVENT_TRAP) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Failure-Message", "The sql server is not responding for DSN %s [%s][%d]",
switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The sql server is not responding for DSN %s [%s][%d]\n",
switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
if (recon == SWITCH_PGSQL_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection has been re-established");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "The connection has been re-established\n");
} else {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection could not be re-established");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The connection could not be re-established\n");
}
if (!max_tries) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "Giving up!");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Giving up!\n");
}
switch_event_fire(&event);
}
if (!max_tries) {
goto done;
}
switch_safe_free(err_str);
switch_yield(1000000);
goto top;
done:
switch_safe_free(err_str);
return ret;
}
#endif
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_connect(switch_pgsql_handle_t *handle)
{
#ifdef SWITCH_HAVE_PGSQL
if (handle->state == SWITCH_PGSQL_STATE_CONNECTED) {
switch_pgsql_handle_disconnect(handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Re-connecting %s\n", handle->dsn);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connecting %s\n", handle->dsn);
handle->con = PQconnectdb(handle->dsn);
if (PQstatus(handle->con) != CONNECTION_OK) {
char *err_str;
if ((err_str = switch_pgsql_handle_get_error(handle))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err_str);
switch_safe_free(err_str);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to connect to the database [%s]\n", handle->dsn);
switch_pgsql_handle_disconnect(handle);
}
return SWITCH_PGSQL_FAIL;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connected to [%s]\n", handle->dsn);
handle->state = SWITCH_PGSQL_STATE_CONNECTED;
handle->sock = PQsocket(handle->con);
return SWITCH_PGSQL_SUCCESS;
#else
return SWITCH_PGSQL_FAIL;
#endif
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec_string(switch_pgsql_handle_t *handle, const char *sql, char *resbuf, size_t len, char **err)
{
#ifdef SWITCH_HAVE_PGSQL
switch_pgsql_status_t sstatus = SWITCH_PGSQL_SUCCESS;
char *val = NULL;
switch_pgsql_result_t *result = NULL;
handle->affected_rows = 0;
if (switch_pgsql_handle_exec_base(handle, sql, err) == SWITCH_PGSQL_FAIL) {
goto error;
}
if(switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
goto error;
}
if (!result || result->status != PGRES_COMMAND_OK) {
sstatus = SWITCH_PGSQL_FAIL;
goto done;
}
if (handle->affected_rows <= 0) {
goto done;
}
val = PQgetvalue(result->result, 0, 0);
strncpy(resbuf, val, len);
done:
switch_pgsql_free_result(&result);
if (switch_pgsql_finish_results(handle) != SWITCH_PGSQL_SUCCESS) {
sstatus = SWITCH_PGSQL_FAIL;
}
return sstatus;
error:
return SWITCH_PGSQL_FAIL;
#else
return SWITCH_PGSQL_FAIL;
#endif
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec_base(switch_pgsql_handle_t *handle, const char *sql, char **err)
{
#ifdef SWITCH_HAVE_PGSQL
char *err_str = NULL;
handle->affected_rows = 0;
if (!db_is_up(handle)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not up!\n");
goto error;
}
if (handle->auto_commit == SWITCH_FALSE && handle->in_txn == SWITCH_FALSE) {
if (switch_pgsql_send_query(handle, "BEGIN") != SWITCH_PGSQL_SUCCESS) {
switch_pgsql_finish_results(handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error sending BEGIN!\n");
goto error;
}
if (switch_pgsql_finish_results(handle) != SWITCH_PGSQL_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error sending BEGIN!\n");
goto error;
}
handle->in_txn = SWITCH_TRUE;
}
if (switch_pgsql_send_query(handle, sql) != SWITCH_PGSQL_SUCCESS) {
switch_pgsql_finish_results(handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error sending query!\n");
goto error;
}
return SWITCH_PGSQL_SUCCESS;
error:
err_str = switch_pgsql_handle_get_error(handle);
if (zstr(err_str)) {
err_str = strdup((char *)"SQL ERROR!");
}
if (err_str) {
if (!switch_stristr("already exists", err_str) && !switch_stristr("duplicate key name", err_str)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
}
if (err) {
*err = err_str;
} else {
free(err_str);
}
}
#endif
return SWITCH_PGSQL_FAIL;
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_exec(switch_pgsql_handle_t *handle, const char *sql, char **err)
{
#ifdef SWITCH_HAVE_PGSQL
if (switch_pgsql_handle_exec_base(handle, sql, err) == SWITCH_PGSQL_FAIL) {
goto error;
}
return switch_pgsql_finish_results(handle);
error:
#endif
return SWITCH_PGSQL_FAIL;
}
SWITCH_DECLARE(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)
{
#ifdef SWITCH_HAVE_PGSQL
char *err_str = NULL;
int row = 0, col = 0, err_cnt = 0;
switch_pgsql_result_t *result = NULL;
handle->affected_rows = 0;
switch_assert(callback != NULL);
if (switch_pgsql_handle_exec_base(handle, sql, err) == SWITCH_PGSQL_FAIL) {
goto error;
}
if (switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
err_cnt++;
err_str = switch_pgsql_handle_get_error(handle);
if (result && !zstr(result->err)) {
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));
}
if (!zstr(err_str)) {
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));
}
switch_safe_free(err_str);
err_str = NULL;
}
while (result != NULL) {
for (row = 0; row < result->rows; ++row) {
char **names;
char **vals;
names = calloc(result->cols, sizeof(*names));
vals = calloc(result->cols, sizeof(*vals));
switch_assert(names && vals);
for (col = 0; col < result->cols; ++col) {
char * tmp;
int len;
tmp = PQfname(result->result, col);
if (tmp) {
len = strlen(tmp);
names[col] = malloc(len+1);
strncpy(names[col], tmp, len);
len = PQgetlength(result->result, row, col);
vals[col] = malloc(len+1);
tmp = PQgetvalue(result->result, row, col);
strncpy(vals[col], tmp, len);
} else {
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: Column number %d out of range\n", col);
}
}
if (callback(pdata, row, vals, names)) {
break;
}
for (col = 0; col < result->cols; ++col) {
free(names[col]);
free(vals[col]);
}
free(names);
free(vals);
}
if (switch_pgsql_next_result(handle, &result) == SWITCH_PGSQL_FAIL) {
err_cnt++;
err_str = switch_pgsql_handle_get_error(handle);
if (result && !zstr(result->err)) {
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));
}
if (!zstr(err_str)) {
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));
}
switch_safe_free(err_str);
err_str = NULL;
}
}
if (err_cnt) {
goto error;
}
return SWITCH_PGSQL_SUCCESS;
error:
#endif
return SWITCH_PGSQL_FAIL;
}
SWITCH_DECLARE(void) switch_pgsql_handle_destroy(switch_pgsql_handle_t **handlep)
{
#ifdef SWITCH_HAVE_PGSQL
switch_pgsql_handle_t *handle = NULL;
if (!handlep) {
return;
}
handle = *handlep;
if (handle) {
switch_pgsql_handle_disconnect(handle);
switch_safe_free(handle->dsn);
free(handle);
}
*handlep = NULL;
#else
return;
#endif
}
SWITCH_DECLARE(switch_pgsql_state_t) switch_pgsql_handle_get_state(switch_pgsql_handle_t *handle)
{
#ifdef SWITCH_HAVE_PGSQL
return handle ? handle->state : SWITCH_PGSQL_STATE_INIT;
#else
return SWITCH_PGSQL_STATE_ERROR;
#endif
}
SWITCH_DECLARE(char *) switch_pgsql_handle_get_error(switch_pgsql_handle_t *handle)
{
#ifdef SWITCH_HAVE_PGSQL
char * err_str;
if (!handle) {
return NULL;
};
switch_strdup(err_str, PQerrorMessage(handle->con));
return err_str;
#else
return NULL;
#endif
}
SWITCH_DECLARE(int) switch_pgsql_handle_affected_rows(switch_pgsql_handle_t *handle)
{
#ifdef SWITCH_HAVE_PGSQL
return handle->affected_rows;
#else
return 0;
#endif
}
SWITCH_DECLARE(switch_bool_t) switch_pgsql_available(void)
{
#ifdef SWITCH_HAVE_PGSQL
return SWITCH_TRUE;
#else
return SWITCH_FALSE;
#endif
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_SQLSetAutoCommitAttr(switch_pgsql_handle_t *handle, switch_bool_t on)
{
#ifdef SWITCH_HAVE_PGSQL
if (on) {
handle->auto_commit = SWITCH_TRUE;
} else {
handle->auto_commit = SWITCH_FALSE;
}
return SWITCH_PGSQL_SUCCESS;
#else
return (switch_pgsql_status_t) SWITCH_FALSE;
#endif
}
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_SQLEndTran(switch_pgsql_handle_t *handle, switch_bool_t commit)
{
#ifdef SWITCH_HAVE_PGSQL
char * err_str = NULL;
if (commit) {
if(!PQsendQuery(handle->con, "COMMIT")) {
err_str = switch_pgsql_handle_get_error(handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not commit transaction: %s\n", err_str);
switch_safe_free(err_str);
return SWITCH_PGSQL_FAIL;
}
} else {
if(!PQsendQuery(handle->con, "ROLLBACK")) {
err_str = switch_pgsql_handle_get_error(handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not rollback transaction: %s\n", err_str);
switch_safe_free(err_str);
return SWITCH_PGSQL_FAIL;
}
}
handle->in_txn = SWITCH_FALSE;
return SWITCH_PGSQL_SUCCESS;
#else
return (switch_pgsql_status_t) SWITCH_FALSE;
#endif
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/