diff --git a/docs/AUTHORS b/docs/AUTHORS index 840d8f30bd..9de58bc646 100644 --- a/docs/AUTHORS +++ b/docs/AUTHORS @@ -32,7 +32,8 @@ that much better: Johny Kadarisman - mod_python fixups. Michael Murdock - testing, documentation, bug finding and usability enhancements. Matt Klein - + Jonas Gauffin - Bugfixes and additions in mod_spidermonkey_odbc + A big THANK YOU goes to: Justin Cassidy - Build related cleanups and automatic build setup. diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index 221b548c87..e247db0d55 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -2114,7 +2114,9 @@ static JSPropertySpec session_props[] = { {"dialplan", PROFILE_DIALPLAN, JSPROP_READONLY | JSPROP_PERMANENT}, {"caller_id_name", PROFILE_CID_NAME, JSPROP_READONLY | JSPROP_PERMANENT}, {"caller_id_num", PROFILE_CID_NUM, JSPROP_READONLY | JSPROP_PERMANENT}, + {"caller_id_number", PROFILE_CID_NUM, JSPROP_READONLY | JSPROP_PERMANENT}, {"network_addr", PROFILE_IP, JSPROP_READONLY | JSPROP_PERMANENT}, + {"network_address", PROFILE_IP, JSPROP_READONLY | JSPROP_PERMANENT}, {"ani", PROFILE_ANI, JSPROP_READONLY | JSPROP_PERMANENT}, {"aniii", PROFILE_ANI_II, JSPROP_READONLY | JSPROP_PERMANENT}, {"destination", PROFILE_DEST, JSPROP_READONLY | JSPROP_PERMANENT}, diff --git a/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c b/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c index 37e695c69e..7dca90b582 100644 --- a/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c +++ b/src/mod/languages/mod_spidermonkey_odbc/mod_spidermonkey_odbc.c @@ -52,6 +52,7 @@ static odbc_obj_t *new_odbc_obj(char *dsn, char *username, char *password) goto err; } + memset(new_obj, 0, sizeof(odbc_obj_t)); if (!(new_obj->handle = switch_odbc_handle_new(dsn, username, password))) { goto err; } @@ -79,12 +80,12 @@ static void destroy_odbc_obj(odbc_obj_t ** objp) { odbc_obj_t *obj = *objp; - if (obj->handle) { - switch_odbc_handle_destroy(&obj->handle); - } if (obj->stmt) { SQLFreeHandle(SQL_HANDLE_STMT, obj->stmt); } + if (obj->handle) { + switch_odbc_handle_destroy(&obj->handle); + } switch_safe_free(obj->colbuf); switch_safe_free(obj->code); switch_safe_free(obj); @@ -180,6 +181,40 @@ static JSBool odbc_connect(JSContext * cx, JSObject * obj, uintN argc, jsval *ar return JS_TRUE; } +static JSBool odbc_execute(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) +{ + odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); + char *sql; + JSBool tf = JS_FALSE; + SQLHSTMT stmt; + + if (argc < 1) { + goto done; + } + + if (switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n"); + goto done; + } + + sql = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + + if (switch_odbc_handle_exec(odbc_obj->handle, sql, &stmt) != SWITCH_ODBC_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[ODBC] Execute failed for: %s\n", sql); + goto done; + } + + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + + tf = JS_TRUE; + + done: + + *rval = BOOLEAN_TO_JSVAL(tf); + + return JS_TRUE; +} + static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, jsval *rval) { odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj); @@ -202,8 +237,8 @@ static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval *argv, sql = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); - if (switch_odbc_handle_exec(odbc_obj->handle, sql, &odbc_obj->stmt) != SWITCH_ODBC_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[ODBC] query failed: %s\n", sql); goto done; } @@ -265,7 +300,7 @@ static JSBool odbc_next_row(JSContext * cx, JSObject * obj, uintN argc, jsval *a return JS_TRUE; } -static char *escape_data(char *in) +static char *escape_data(char *in, char escapeChar) { switch_size_t nlen = strlen(in); uint32_t qc = 0; @@ -275,6 +310,9 @@ static char *escape_data(char *in) if (*p == '"') { qc += 2; } + if (*p == '\'') { + qc += 2; + } } nlen += qc + 1; @@ -287,7 +325,10 @@ static char *escape_data(char *in) qc = 0; for (p = in; p && *p; p++) { if (*p == '"') { - *r++ = '\\'; + *r++ = escapeChar; + } + if (*p == '\'') { + *r++ = escapeChar; } *r++ = *p; if (++qc > nlen) { @@ -338,7 +379,7 @@ static JSBool odbc_get_data(JSContext * cx, JSObject * obj, uintN argc, jsval *a SQLGetData(odbc_obj->stmt, x, SQL_C_CHAR, odbc_obj->colbuf, odbc_obj->cblen, NULL); if (strchr((char *) odbc_obj->colbuf, '"')) { /* please don't */ - esc = (SQLCHAR *) escape_data((char *) odbc_obj->colbuf); + esc = (SQLCHAR *) escape_data((char *) odbc_obj->colbuf, '\\'); data = esc; } @@ -373,6 +414,8 @@ enum odbc_tinyid { static JSFunctionSpec odbc_methods[] = { {"connect", odbc_connect, 1}, {"exec", odbc_exec, 1}, + {"query", odbc_exec, 1}, + {"execute", odbc_execute, 1}, {"numRows", odbc_num_rows, 1}, {"nextRow", odbc_next_row, 1}, {"getData", odbc_get_data, 1}, diff --git a/src/switch_odbc.c b/src/switch_odbc.c index 7bee2763bc..18366392e9 100644 --- a/src/switch_odbc.c +++ b/src/switch_odbc.c @@ -38,6 +38,8 @@ struct switch_odbc_handle { SQLHENV env; SQLHDBC con; switch_odbc_state_t state; + char odbc_driver[256]; + BOOL is_firebird; }; @@ -110,6 +112,8 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_hand SQLINTEGER err; int16_t mlen; unsigned char msg[200], stat[10]; + SQLSMALLINT valueLength = 0; + int i = 0; if (handle->env == SQL_NULL_HANDLE) { result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle->env); @@ -156,13 +160,25 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_hand } SQLFreeHandle(SQL_HANDLE_ENV, handle->env); return SWITCH_ODBC_FAIL; - } else { - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to [%s]\n", handle->dsn); - handle->state = SWITCH_ODBC_STATE_CONNECTED; - return SWITCH_ODBC_SUCCESS; } + result = SQLGetInfo(handle->con, SQL_DRIVER_NAME, (SQLCHAR*)handle->odbc_driver, 255, &valueLength); + if ( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO) + { + for (i = 0; i < valueLength; ++i) + handle->odbc_driver[i] = (char)toupper(handle->odbc_driver[i]); + } + + //Firebird do not support "SELECT 1" + if (strstr(handle->odbc_driver, "FIREBIRD") != 0 || strstr(handle->odbc_driver, "FB32") != 0 || strstr(handle->odbc_driver, "FB64") != 0) + handle->is_firebird = TRUE; + else + handle->is_firebird = FALSE; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to [%s]\n", handle->dsn); + handle->state = SWITCH_ODBC_STATE_CONNECTED; + return SWITCH_ODBC_SUCCESS; + } static int db_is_up(switch_odbc_handle_t *handle) @@ -172,9 +188,16 @@ static int db_is_up(switch_odbc_handle_t *handle) SQLINTEGER m = 0; int result; switch_event_t *event; - switch_odbc_status_t recon; + switch_odbc_status_t recon = 0; char *err_str = NULL; - SQLCHAR sql[] = "select 1"; + SQLCHAR sql[255]; + + //Firebird do not support "SELECT 1" + sql[0] = 0; + if (handle->is_firebird) + strcpy((char*)sql, "select first 1 * from RDB$RELATIONS"); + else + strcpy((char*)sql, "select 1"); if (!handle) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No DB Handle\n"); @@ -197,10 +220,15 @@ static int db_is_up(switch_odbc_handle_t *handle) goto done; error: - - recon = switch_odbc_handle_connect(handle); err_str = switch_odbc_handle_get_error(handle, stmt); + // No need to reconnect if we can get the string anyway. + if (err_str == 0) + { + recon = switch_odbc_handle_connect(handle); + err_str = switch_odbc_handle_get_error(handle, stmt); + } + 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]", switch_str_nil(handle->dsn), switch_str_nil(err_str));