PageRenderTime 27ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mod/languages/mod_spidermonkey/mod_spidermonkey_odbc.c

https://github.com/ppanhoto/Freeswitch-mod_mp4
C | 566 lines | 440 code | 93 blank | 33 comment | 69 complexity | 150e8427bc35775230fb302d32982220 MD5 | raw file
  1. /*
  2. * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
  3. * Copyright (C) 2005-2010, 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. *
  28. *
  29. * mod_spidermonkey_odbc.c -- ODBC Javascript Module
  30. *
  31. */
  32. #include "mod_spidermonkey.h"
  33. #include <sql.h>
  34. #ifdef _MSC_VER
  35. #pragma warning(push)
  36. #pragma warning(disable:4201)
  37. #include <sqlext.h>
  38. #pragma warning(pop)
  39. #else
  40. #include <sqlext.h>
  41. #endif
  42. #include <sqltypes.h>
  43. static const char modname[] = "ODBC";
  44. struct odbc_obj {
  45. switch_odbc_handle_t *handle;
  46. SQLHSTMT stmt;
  47. SQLCHAR *colbuf;
  48. int32 cblen;
  49. SQLCHAR *code;
  50. int32 codelen;
  51. };
  52. typedef struct odbc_obj odbc_obj_t;
  53. static odbc_obj_t *new_odbc_obj(char *dsn, char *username, char *password)
  54. {
  55. odbc_obj_t *new_obj;
  56. if (!(new_obj = malloc(sizeof(*new_obj)))) {
  57. goto err;
  58. }
  59. memset(new_obj, 0, sizeof(odbc_obj_t));
  60. if (!(new_obj->handle = switch_odbc_handle_new(dsn, username, password))) {
  61. goto err;
  62. }
  63. return new_obj;
  64. err:
  65. if (new_obj) {
  66. if (new_obj->handle) {
  67. switch_odbc_handle_destroy(&new_obj->handle);
  68. }
  69. switch_safe_free(new_obj);
  70. }
  71. return NULL;
  72. }
  73. switch_odbc_status_t odbc_obj_connect(odbc_obj_t *obj)
  74. {
  75. return switch_odbc_handle_connect(obj->handle);
  76. }
  77. static void destroy_odbc_obj(odbc_obj_t ** objp)
  78. {
  79. odbc_obj_t *obj = *objp;
  80. if (obj == NULL)
  81. return;
  82. if (obj->stmt) {
  83. SQLFreeHandle(SQL_HANDLE_STMT, obj->stmt);
  84. }
  85. if (obj->handle) {
  86. switch_odbc_handle_destroy(&obj->handle);
  87. }
  88. switch_safe_free(obj->colbuf);
  89. switch_safe_free(obj->code);
  90. switch_safe_free(obj);
  91. }
  92. /* ODBC Object */
  93. /*********************************************************************************/
  94. static JSBool odbc_construct(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  95. {
  96. odbc_obj_t *odbc_obj = NULL;
  97. char *dsn, *username, *password;
  98. int32 blen = 1024;
  99. if (argc < 3) {
  100. return JS_FALSE;
  101. }
  102. dsn = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
  103. username = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
  104. password = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
  105. if (argc > 3) {
  106. int32 len;
  107. JS_ValueToInt32(cx, argv[3], &len);
  108. if (len > 0) {
  109. blen = len;
  110. }
  111. }
  112. if (zstr(username)) {
  113. username = NULL;
  114. }
  115. if (zstr(password)) {
  116. password = NULL;
  117. }
  118. if (dsn) {
  119. odbc_obj = new_odbc_obj(dsn, username, password);
  120. }
  121. if (!odbc_obj) {
  122. return JS_FALSE;
  123. }
  124. if (!(odbc_obj->colbuf = (SQLCHAR *) malloc(blen))) {
  125. destroy_odbc_obj(&odbc_obj);
  126. return JS_FALSE;
  127. }
  128. odbc_obj->cblen = blen;
  129. blen += 1536;
  130. if (!(odbc_obj->code = (SQLCHAR *) malloc(blen))) {
  131. destroy_odbc_obj(&odbc_obj);
  132. return JS_FALSE;
  133. }
  134. odbc_obj->codelen = blen;
  135. JS_SetPrivate(cx, obj, odbc_obj);
  136. return JS_TRUE;
  137. }
  138. static void odbc_destroy(JSContext * cx, JSObject * obj)
  139. {
  140. odbc_obj_t *odbc_obj;
  141. if (obj == NULL)
  142. return;
  143. odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  144. if (odbc_obj) {
  145. destroy_odbc_obj(&odbc_obj);
  146. JS_SetPrivate(cx, obj, NULL);
  147. }
  148. }
  149. static JSBool odbc_connect(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  150. {
  151. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  152. JSBool tf = JS_TRUE;
  153. if (odbc_obj) {
  154. if (odbc_obj_connect(odbc_obj) == SWITCH_ODBC_SUCCESS) {
  155. tf = JS_TRUE;
  156. } else {
  157. tf = JS_FALSE;
  158. }
  159. } else {
  160. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database handle is not initialized!\n");
  161. }
  162. *rval = BOOLEAN_TO_JSVAL(tf);
  163. return JS_TRUE;
  164. }
  165. static JSBool odbc_execute(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  166. {
  167. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  168. char *sql;
  169. JSBool tf = JS_FALSE;
  170. SQLHSTMT stmt;
  171. if (argc < 1) {
  172. goto done;
  173. }
  174. if (!odbc_obj || switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  175. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  176. goto done;
  177. }
  178. sql = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
  179. if (switch_odbc_handle_exec(odbc_obj->handle, sql, &stmt, NULL) != SWITCH_ODBC_SUCCESS) {
  180. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[ODBC] Execute failed for: %s\n", sql);
  181. goto done;
  182. }
  183. SQLFreeHandle(SQL_HANDLE_STMT, stmt);
  184. tf = JS_TRUE;
  185. done:
  186. *rval = BOOLEAN_TO_JSVAL(tf);
  187. return JS_TRUE;
  188. }
  189. static JSBool odbc_exec(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  190. {
  191. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  192. char *sql;
  193. JSBool tf = JS_FALSE;
  194. if (argc < 1) {
  195. goto done;
  196. }
  197. if (!odbc_obj || switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  198. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  199. goto done;
  200. }
  201. if (odbc_obj->stmt) {
  202. SQLFreeHandle(SQL_HANDLE_STMT, odbc_obj->stmt);
  203. odbc_obj->stmt = NULL;
  204. }
  205. sql = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
  206. if (switch_odbc_handle_exec(odbc_obj->handle, sql, &odbc_obj->stmt, NULL) != SWITCH_ODBC_SUCCESS) {
  207. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[ODBC] query failed: %s\n", sql);
  208. goto done;
  209. }
  210. tf = JS_TRUE;
  211. done:
  212. *rval = BOOLEAN_TO_JSVAL(tf);
  213. return JS_TRUE;
  214. }
  215. static JSBool odbc_num_rows(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  216. {
  217. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  218. SQLLEN row_count = 0;
  219. if (!odbc_obj || switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  220. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  221. goto done;
  222. }
  223. if (odbc_obj->stmt) {
  224. SQLRowCount(odbc_obj->stmt, &row_count);
  225. }
  226. done:
  227. *rval = INT_TO_JSVAL(row_count);
  228. return JS_TRUE;
  229. }
  230. static JSBool odbc_num_cols(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  231. {
  232. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  233. SQLSMALLINT cols = 0;
  234. if (!odbc_obj || switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  235. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  236. goto done;
  237. }
  238. if (odbc_obj->stmt) {
  239. SQLNumResultCols(odbc_obj->stmt, &cols);
  240. }
  241. done:
  242. *rval = INT_TO_JSVAL(cols);
  243. return JS_TRUE;
  244. }
  245. static JSBool odbc_next_row(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  246. {
  247. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  248. int result = 0;
  249. JSBool tf = JS_FALSE;
  250. if (!odbc_obj || switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  251. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  252. goto done;
  253. }
  254. if (odbc_obj->stmt) {
  255. if ((result = SQLFetch(odbc_obj->stmt) == SQL_SUCCESS)) {
  256. tf = JS_TRUE;
  257. }
  258. }
  259. done:
  260. *rval = BOOLEAN_TO_JSVAL(tf);
  261. return JS_TRUE;
  262. }
  263. static char *escape_data(char *in, char escapeChar)
  264. {
  265. switch_size_t nlen = strlen(in);
  266. uint32_t qc = 0;
  267. char *p, *q, *r;
  268. for (p = in; p && *p; p++) {
  269. if (*p == '"') {
  270. qc += 2;
  271. }
  272. if (*p == '\'') {
  273. qc += 2;
  274. }
  275. }
  276. nlen += qc + 1;
  277. if (!(q = (char *) malloc(nlen))) {
  278. return NULL;
  279. }
  280. r = q;
  281. qc = 0;
  282. for (p = in; p && *p; p++) {
  283. if (*p == '"') {
  284. *r++ = escapeChar;
  285. }
  286. if (*p == '\'') {
  287. *r++ = escapeChar;
  288. }
  289. *r++ = *p;
  290. if (++qc > nlen) {
  291. break;
  292. }
  293. }
  294. *r++ = '\0';
  295. return q;
  296. }
  297. static JSBool odbc_get_data(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  298. {
  299. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  300. JSBool tf = JS_FALSE;
  301. if (!odbc_obj || switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  302. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  303. goto done;
  304. }
  305. if (odbc_obj->stmt) {
  306. SQLSMALLINT nColumns = 0, x = 0;
  307. eval_some_js("~var _oDbC_dB_RoW_DaTa_ = {}", cx, obj, rval);
  308. if (*rval == JS_FALSE) {
  309. return JS_TRUE;
  310. }
  311. if (SQLNumResultCols(odbc_obj->stmt, &nColumns) != SQL_SUCCESS)
  312. return JS_FALSE;
  313. for (x = 1; x <= nColumns; x++) {
  314. SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable;
  315. SQLULEN ColumnSize;
  316. SQLCHAR name[1024] = "";
  317. SQLCHAR *data = odbc_obj->colbuf;
  318. SQLCHAR *esc = NULL;
  319. SQLDescribeCol(odbc_obj->stmt, x, name, sizeof(name), &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
  320. SQLGetData(odbc_obj->stmt, x, SQL_C_CHAR, odbc_obj->colbuf, odbc_obj->cblen, NULL);
  321. if (strchr((char *) odbc_obj->colbuf, '"')) { /* please don't */
  322. esc = (SQLCHAR *) escape_data((char *) odbc_obj->colbuf, '\\');
  323. data = esc;
  324. }
  325. switch_snprintf((char *) odbc_obj->code, odbc_obj->codelen, "~_oDbC_dB_RoW_DaTa_[\"%s\"] = \"%s\"", name, data);
  326. switch_safe_free(esc);
  327. eval_some_js((char *) odbc_obj->code, cx, obj, rval);
  328. if (*rval == JS_FALSE) {
  329. return JS_TRUE;
  330. }
  331. }
  332. JS_GetProperty(cx, obj, "_oDbC_dB_RoW_DaTa_", rval);
  333. return JS_TRUE;
  334. }
  335. done:
  336. *rval = BOOLEAN_TO_JSVAL(tf);
  337. return JS_TRUE;
  338. }
  339. static JSBool odbc_close(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  340. {
  341. odbc_destroy(cx, obj);
  342. return JS_TRUE;
  343. }
  344. static JSBool odbc_disconnect(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval)
  345. {
  346. odbc_obj_t *odbc_obj = (odbc_obj_t *) JS_GetPrivate(cx, obj);
  347. if (!odbc_obj) {
  348. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database handle is not initialized!\n");
  349. goto done;
  350. }
  351. if (switch_odbc_handle_get_state(odbc_obj->handle) != SWITCH_ODBC_STATE_CONNECTED) {
  352. switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Database is not connected!\n");
  353. goto done;
  354. }
  355. if (odbc_obj->stmt) {
  356. SQLFreeHandle(SQL_HANDLE_STMT, odbc_obj->stmt);
  357. odbc_obj->stmt = NULL;
  358. }
  359. switch_odbc_handle_disconnect(odbc_obj->handle);
  360. done:
  361. return JS_TRUE;
  362. }
  363. enum odbc_tinyid {
  364. odbc_NAME
  365. };
  366. static JSFunctionSpec odbc_methods[] = {
  367. {"connect", odbc_connect, 1},
  368. {"disconnect", odbc_disconnect, 1},
  369. {"exec", odbc_exec, 1},
  370. {"query", odbc_exec, 1},
  371. {"execute", odbc_execute, 1},
  372. {"numRows", odbc_num_rows, 1},
  373. {"numCols", odbc_num_cols, 1},
  374. {"nextRow", odbc_next_row, 1},
  375. {"getData", odbc_get_data, 1},
  376. {"close", odbc_close, 1},
  377. {0}
  378. };
  379. static JSPropertySpec odbc_props[] = {
  380. {"name", odbc_NAME, JSPROP_READONLY | JSPROP_PERMANENT},
  381. {0}
  382. };
  383. static JSBool odbc_setProperty(JSContext * cx, JSObject * obj, jsval id, jsval * vp)
  384. {
  385. char *name = JS_GetStringBytes(JS_ValueToString(cx, id));
  386. if (strcmp(name, "_oDbC_dB_RoW_DaTa_")) {
  387. eval_some_js("~throw new Error(\"this property cannot be changed!\");", cx, obj, vp);
  388. *vp = BOOLEAN_TO_JSVAL(JS_FALSE);
  389. }
  390. return JS_TRUE;
  391. }
  392. static JSBool odbc_getProperty(JSContext * cx, JSObject * obj, jsval id, jsval * vp)
  393. {
  394. int param;
  395. char *name = JS_GetStringBytes(JS_ValueToString(cx, id));
  396. /* numbers are our props anything else is a method */
  397. if (name[0] >= 48 && name[0] <= 57) {
  398. param = atoi(name);
  399. } else {
  400. return JS_TRUE;
  401. }
  402. *vp = BOOLEAN_TO_JSVAL(JS_FALSE);
  403. return JS_TRUE;
  404. }
  405. JSClass odbc_class = {
  406. modname, JSCLASS_HAS_PRIVATE,
  407. JS_PropertyStub, JS_PropertyStub, odbc_getProperty, odbc_setProperty,
  408. JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, odbc_destroy, NULL, NULL, NULL,
  409. odbc_construct
  410. };
  411. switch_status_t odbc_load(JSContext * cx, JSObject * obj)
  412. {
  413. JS_InitClass(cx, obj, NULL, &odbc_class, odbc_construct, 3, odbc_props, odbc_methods, odbc_props, odbc_methods);
  414. return SWITCH_STATUS_SUCCESS;
  415. }
  416. const sm_module_interface_t odbc_module_interface = {
  417. /*.name = */ modname,
  418. /*.spidermonkey_load */ odbc_load,
  419. /*.next */ NULL
  420. };
  421. SWITCH_MOD_DECLARE_NONSTD(switch_status_t) spidermonkey_init(const sm_module_interface_t ** module_interface)
  422. {
  423. *module_interface = &odbc_module_interface;
  424. return SWITCH_STATUS_SUCCESS;
  425. }
  426. /* For Emacs:
  427. * Local Variables:
  428. * mode:c
  429. * indent-tabs-mode:t
  430. * tab-width:4
  431. * c-basic-offset:4
  432. * End:
  433. * For VIM:
  434. * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
  435. */