freeswitch/src/mod/languages/mod_v8/src/fsodbc.cpp

436 lines
9.4 KiB
C++

/*
* mod_v8 for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013-2014, Peter Olsson <peter@olssononline.se>
*
* 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.
*
* Ported from the Original Code in 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):
* Peter Olsson <peter@olssononline.se>
* Anthony Minessale II <anthm@freeswitch.org>
*
* fsodbc.cpp -- JavaScript ODBC class
*
*/
#include "fsodbc.hpp"
using namespace std;
using namespace v8;
#ifdef HAVE_ODBC
static const char js_class_name[] = "ODBC";
FSODBC::~FSODBC(void)
{
if (_stmt) {
SQLFreeHandle(SQL_HANDLE_STMT, _stmt);
}
if (_handle) {
switch_odbc_handle_destroy(&_handle);
}
switch_safe_free(_colbuf);
}
string FSODBC::GetJSClassName()
{
return js_class_name;
}
void FSODBC::Init()
{
_handle = NULL;
_stmt = NULL;
_colbuf = NULL;
_cblen = 0;
}
FSODBC *FSODBC::New(char *dsn, char *username, char *password, const v8::FunctionCallbackInfo<Value>& info)
{
FSODBC *new_obj = NULL;
if (!(new_obj = new FSODBC(info))) {
goto err;
}
if (!(new_obj->_handle = switch_odbc_handle_new(dsn, username, password))) {
goto err;
}
new_obj->_dsn = dsn;
return new_obj;
err:
if (new_obj) {
if (new_obj->_handle) {
switch_odbc_handle_destroy(&new_obj->_handle);
}
delete new_obj;
}
return NULL;
}
switch_odbc_status_t FSODBC::Connect()
{
return switch_odbc_handle_connect(_handle);
}
void *FSODBC::Construct(const v8::FunctionCallbackInfo<Value>& info)
{
FSODBC *odbc_obj = NULL;
char *dsn, *username, *password;
int32_t blen = 1024;
if (info.Length() < 3) {
info.GetIsolate()->ThrowException(String::NewFromUtf8(info.GetIsolate(), "Invalid parameters"));
return NULL;
}
String::Utf8Value str1(info[0]);
String::Utf8Value str2(info[1]);
String::Utf8Value str3(info[2]);
dsn = *str1;
username = *str2;
password = *str3;
if (info.Length() > 3) {
int32_t len = info[3]->Int32Value();
if (len > 0) {
blen = len;
}
}
if (zstr(username)) {
username = NULL;
}
if (zstr(password)) {
password = NULL;
}
if (dsn) {
odbc_obj = New(dsn, username, password, info);
}
if (!odbc_obj) {
info.GetIsolate()->ThrowException(String::NewFromUtf8(info.GetIsolate(), "Failed to create new ODBC instance"));
return NULL;
}
if (!(odbc_obj->_colbuf = (SQLCHAR *) malloc(blen))) {
delete odbc_obj;
info.GetIsolate()->ThrowException(String::NewFromUtf8(info.GetIsolate(), "Memory error"));
return NULL;
}
odbc_obj->_cblen = blen;
return odbc_obj;
}
JS_ODBC_FUNCTION_IMPL(Connect)
{
HandleScope handle_scope(info.GetIsolate());
bool tf = true;
if (Connect() == SWITCH_ODBC_SUCCESS) {
tf = true;
} else {
tf = false;
}
info.GetReturnValue().Set(tf);
}
JS_ODBC_FUNCTION_IMPL(Execute)
{
HandleScope handle_scope(info.GetIsolate());
const char *sql;
bool tf = false;
SQLHSTMT local_stmt;
String::Utf8Value str(info[0]);
if (info.Length() < 1) {
goto done;
}
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
goto done;
}
sql = js_safe_str(*str);
if (switch_odbc_handle_exec(_handle, sql, &local_stmt, NULL) != 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, local_stmt);
tf = true;
done:
info.GetReturnValue().Set(tf);
}
JS_ODBC_FUNCTION_IMPL(Exec)
{
HandleScope handle_scope(info.GetIsolate());
const char *sql;
bool tf = false;
String::Utf8Value str(info[0]);
if (info.Length() < 1) {
goto done;
}
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
goto done;
}
if (_stmt) {
SQLFreeHandle(SQL_HANDLE_STMT, _stmt);
_stmt = NULL;
}
sql = js_safe_str(*str);
if (switch_odbc_handle_exec(_handle, sql, &_stmt, NULL) != SWITCH_ODBC_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[ODBC] query failed: %s\n", sql);
goto done;
}
tf = true;
done:
info.GetReturnValue().Set(tf);
}
JS_ODBC_FUNCTION_IMPL(NumRows)
{
HandleScope handle_scope(info.GetIsolate());
SQLLEN row_count = 0;
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
goto done;
}
if (_stmt) {
SQLRowCount(_stmt, &row_count);
}
done:
info.GetReturnValue().Set(Integer::New(info.GetIsolate(), (int32_t)row_count));
}
JS_ODBC_FUNCTION_IMPL(NumCols)
{
HandleScope handle_scope(info.GetIsolate());
SQLSMALLINT cols = 0;
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
goto done;
}
if (_stmt) {
SQLNumResultCols(_stmt, &cols);
}
done:
info.GetReturnValue().Set(cols);
}
JS_ODBC_FUNCTION_IMPL(NextRow)
{
HandleScope handle_scope(info.GetIsolate());
int result = 0;
bool tf = false;
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
goto done;
}
if (_stmt) {
if ((result = SQLFetch(_stmt) == SQL_SUCCESS)) {
tf = true;
}
}
done:
info.GetReturnValue().Set(tf);
}
JS_ODBC_FUNCTION_IMPL(GetData)
{
HandleScope handle_scope(info.GetIsolate());
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
goto done;
}
if (_stmt) {
SQLSMALLINT nColumns = 0, x = 0;
if (SQLNumResultCols(_stmt, &nColumns) != SQL_SUCCESS) {
goto done;
}
Handle<Array> arg = Array::New(GetIsolate(), nColumns);
for (x = 1; x <= nColumns; x++) {
SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable;
SQLULEN ColumnSize;
SQLCHAR name[1024] = "";
SQLCHAR *data = _colbuf;
SQLLEN pcbValue;
SQLDescribeCol(_stmt, x, name, sizeof(name), &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
SQLGetData(_stmt, x, SQL_C_CHAR, _colbuf, _cblen, &pcbValue);
if (name) {
if (SQL_NULL_DATA == pcbValue) {
arg->Set(String::NewFromUtf8(GetIsolate(), (const char *)name), Null(info.GetIsolate()));
} else {
arg->Set(String::NewFromUtf8(GetIsolate(), (const char *)name), String::NewFromUtf8(GetIsolate(), data ? (const char *)data : ""));
}
}
}
info.GetReturnValue().Set(arg);
return;
}
done:
info.GetReturnValue().Set(false);
}
JS_ODBC_FUNCTION_IMPL_STATIC(Close)
{
JS_CHECK_SCRIPT_STATE();
HandleScope handle_scope(info.GetIsolate());
FSODBC *obj = JSBase::GetInstance<FSODBC>(info);
if (obj) {
delete obj;
}
}
JS_ODBC_FUNCTION_IMPL(Disconnect)
{
HandleScope handle_scope(info.GetIsolate());
if (switch_odbc_handle_get_state(_handle) != SWITCH_ODBC_STATE_CONNECTED) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Database is not connected!\n");
return;
}
if (_stmt) {
SQLFreeHandle(SQL_HANDLE_STMT, _stmt);
_stmt = NULL;
}
switch_odbc_handle_disconnect(_handle);
}
JS_ODBC_GET_PROPERTY_IMPL(GetProperty)
{
HandleScope handle_scope(info.GetIsolate());
String::Utf8Value str(property);
if (!strcmp(js_safe_str(*str), "name")) {
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), _dsn.length() > 0 ? _dsn.c_str() : ""));
} else {
info.GetIsolate()->ThrowException(String::NewFromUtf8(info.GetIsolate(), "Bad property"));
}
}
static const js_function_t odbc_methods[] = {
{"connect", FSODBC::Connect},
{"disconnect", FSODBC::Disconnect},
{"exec", FSODBC::Exec}, // Deprecated
{"query", FSODBC::Exec},
{"execute", FSODBC::Execute},
{"numRows", FSODBC::NumRows},
{"numCols", FSODBC::NumCols},
{"nextRow", FSODBC::NextRow},
{"getData", FSODBC::GetData},
{"close", FSODBC::Close},
{0}
};
static const js_property_t odbc_props[] = {
{"name", FSODBC::GetProperty, JSBase::DefaultSetProperty},
{0}
};
static const js_class_definition_t odbc_desc = {
js_class_name,
FSODBC::Construct,
odbc_methods,
odbc_props
};
static switch_status_t odbc_load(const v8::FunctionCallbackInfo<Value>& info)
{
JSBase::Register(info.GetIsolate(), &odbc_desc);
return SWITCH_STATUS_SUCCESS;
}
static const v8_mod_interface_t odbc_module_interface = {
/*.name = */ js_class_name,
/*.js_mod_load */ odbc_load
};
const v8_mod_interface_t *FSODBC::GetModuleInterface()
{
return &odbc_module_interface;
}
#endif /* HAVE_ODBC */
/* 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 noet:
*/