pg_mod.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * $Id$
  3. *
  4. * PostgreSQL Database Driver for SER
  5. *
  6. * Portions Copyright (C) 2001-2003 FhG FOKUS
  7. * Copyright (C) 2003 August.Net Services, LLC
  8. * Portions Copyright (C) 2005-2008 iptelorg GmbH
  9. *
  10. * This file is part of SER, a free SIP server.
  11. *
  12. * SER is free software; you can redistribute it and/or modify it under the
  13. * terms of the GNU General Public License as published by the Free Software
  14. * Foundation; either version 2 of the License, or (at your option) any later
  15. * version
  16. *
  17. * For a license to use the ser software under conditions other than those
  18. * described here, or to purchase support for this software, please contact
  19. * iptel.org by e-mail at the following addresses: [email protected]
  20. *
  21. * SER is distributed in the hope that it will be useful, but WITHOUT ANY
  22. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  23. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  24. * details.
  25. *
  26. * You should have received a copy of the GNU General Public License along
  27. * with this program; if not, write to the Free Software Foundation, Inc., 59
  28. * Temple Place, Suite 330, Boston, MA 02111-1307 USA
  29. */
  30. /** \addtogroup postgres
  31. * @{
  32. */
  33. /** \file
  34. * Postgres module interface.
  35. */
  36. #include "pg_mod.h"
  37. #include "pg_uri.h"
  38. #include "pg_con.h"
  39. #include "pg_cmd.h"
  40. #include "pg_res.h"
  41. #include "pg_fld.h"
  42. #include "km_db_postgres.h"
  43. #include "../../sr_module.h"
  44. #ifdef PG_TEST
  45. #include <limits.h>
  46. #include <float.h>
  47. #endif
  48. MODULE_VERSION
  49. static int pg_mod_init(void);
  50. static void pg_mod_destroy(void);
  51. int pg_connect_timeout = 0; /* Default is unlimited */
  52. int pg_retries = 2; /* How many times should the module try re-execute failed commands.
  53. * 0 disables reconnecting */
  54. int pg_lockset = 4;
  55. int pg_timeout = 0; /* default = no timeout */
  56. int pg_keepalive = 0;
  57. /*
  58. * Postgres module interface
  59. */
  60. static cmd_export_t cmds[] = {
  61. {"db_ctx", (cmd_function)NULL, 0, 0, 0},
  62. {"db_con", (cmd_function)pg_con, 0, 0, 0},
  63. {"db_uri", (cmd_function)pg_uri, 0, 0, 0},
  64. {"db_cmd", (cmd_function)pg_cmd, 0, 0, 0},
  65. {"db_put", (cmd_function)pg_cmd_exec, 0, 0, 0},
  66. {"db_del", (cmd_function)pg_cmd_exec, 0, 0, 0},
  67. {"db_get", (cmd_function)pg_cmd_exec, 0, 0, 0},
  68. {"db_upd", (cmd_function)pg_cmd_exec, 0, 0, 0},
  69. {"db_sql", (cmd_function)pg_cmd_exec, 0, 0, 0},
  70. {"db_res", (cmd_function)pg_res, 0, 0, 0},
  71. {"db_fld", (cmd_function)pg_fld, 0, 0, 0},
  72. {"db_first", (cmd_function)pg_cmd_first, 0, 0, 0},
  73. {"db_next", (cmd_function)pg_cmd_next, 0, 0, 0},
  74. {"db_setopt", (cmd_function)pg_setopt, 0, 0, 0},
  75. {"db_getopt", (cmd_function)pg_getopt, 0, 0, 0},
  76. {"db_bind_api", (cmd_function)db_postgres_bind_api, 0, 0, 0},
  77. {0, 0, 0, 0, 0}
  78. };
  79. /*
  80. * Exported parameters
  81. */
  82. static param_export_t params[] = {
  83. {"retries", PARAM_INT, &pg_retries },
  84. {"lockset", PARAM_INT, &pg_lockset },
  85. {"timeout", PARAM_INT, &pg_timeout },
  86. {"tcp_keepalive", PARAM_INT, &pg_keepalive },
  87. {0, 0, 0}
  88. };
  89. struct module_exports exports = {
  90. "db_postgres",
  91. cmds,
  92. 0, /* RPC method */
  93. params, /* module parameters */
  94. pg_mod_init, /* module initialization function */
  95. 0, /* response function*/
  96. pg_mod_destroy, /* destroy function */
  97. 0, /* oncancel function */
  98. 0 /* per-child init function */
  99. };
  100. /*
  101. CREATE TABLE test (
  102. col_bool BOOL,
  103. col_bytea BYTEA,
  104. col_char CHAR,
  105. col_int8 INT8,
  106. col_int4 INT4,
  107. col_int2 INT2,
  108. col_text TEXT,
  109. col_float4 FLOAT4,
  110. col_float8 FLOAT8,
  111. col_inet INET,
  112. col_bpchar BPCHAR,
  113. col_varchar VARCHAR,
  114. col_timestamp TIMESTAMP,
  115. col_timestamptz TIMESTAMPTZ,
  116. col_bit BIT(32),
  117. col_varbit VARBIT
  118. );
  119. */
  120. #ifdef PG_TEST
  121. int pg_test(void)
  122. {
  123. int i, row;
  124. db_ctx_t* db;
  125. db_cmd_t* put, *del, *get;
  126. db_res_t* result;
  127. db_rec_t* rec;
  128. char* times;
  129. db_fld_t int_vals[] = {
  130. {.name = "col_bool", .type = DB_INT},
  131. {.name = "col_int8", .type = DB_INT},
  132. {.name = "col_int4", .type = DB_INT},
  133. {.name = "col_inet", .type = DB_INT},
  134. {.name = "col_timestamp", .type = DB_INT},
  135. {.name = "col_timestamptz", .type = DB_INT},
  136. {.name = "col_bit", .type = DB_INT},
  137. {.name = "col_varbit", .type = DB_INT},
  138. {.name = NULL}
  139. };
  140. db_fld_t datetime_vals[] = {
  141. {.name = "col_int8", .type = DB_INT},
  142. {.name = "col_int4", .type = DB_INT},
  143. {.name = "col_timestamp", .type = DB_INT},
  144. {.name = "col_timestamptz", .type = DB_INT},
  145. {.name = NULL}
  146. };
  147. db_fld_t bitmap_vals[] = {
  148. {.name = "col_int8", .type = DB_INT},
  149. {.name = "col_int4", .type = DB_INT},
  150. {.name = "col_bit", .type = DB_INT},
  151. {.name = "col_varbit", .type = DB_INT},
  152. {.name = NULL}
  153. };
  154. db_fld_t float_vals[] = {
  155. {.name = "col_float4", .type = DB_FLOAT},
  156. {.name = "col_float8", .type = DB_FLOAT},
  157. {.name = NULL}
  158. };
  159. db_fld_t double_vals[] = {
  160. {.name = "col_float8", .type = DB_DOUBLE},
  161. {.name = NULL}
  162. };
  163. db_fld_t str_vals[] = {
  164. {.name = "col_varchar", .type = DB_STR},
  165. {.name = "col_bytea", .type = DB_STR},
  166. {.name = "col_text", .type = DB_STR},
  167. {.name = "col_bpchar", .type = DB_STR},
  168. {.name = "col_char", .type = DB_STR},
  169. {.name = NULL}
  170. };
  171. db_fld_t cstr_vals[] = {
  172. {.name = "col_varchar", .type = DB_CSTR},
  173. {.name = "col_bytea", .type = DB_CSTR},
  174. {.name = "col_text", .type = DB_CSTR},
  175. {.name = "col_bpchar", .type = DB_CSTR},
  176. {.name = "col_char", .type = DB_CSTR},
  177. {.name = NULL}
  178. };
  179. db_fld_t blob_vals[] = {
  180. {.name = "col_bytea", .type = DB_BLOB},
  181. {.name = NULL}
  182. };
  183. db_fld_t res[] = {
  184. {.name = "col_bool", .type = DB_INT},
  185. {.name = "col_bytea", .type = DB_BLOB},
  186. {.name = "col_char", .type = DB_STR},
  187. {.name = "col_int8", .type = DB_INT},
  188. {.name = "col_int4", .type = DB_INT},
  189. {.name = "col_int2", .type = DB_INT},
  190. {.name = "col_text", .type = DB_STR},
  191. {.name = "col_float4", .type = DB_FLOAT},
  192. {.name = "col_float8", .type = DB_DOUBLE},
  193. {.name = "col_inet", .type = DB_INT},
  194. {.name = "col_bpchar", .type = DB_STR},
  195. {.name = "col_varchar", .type = DB_STR},
  196. {.name = "col_timestamp", .type = DB_DATETIME},
  197. {.name = "col_timestamptz", .type = DB_DATETIME},
  198. {.name = "col_bit", .type = DB_BITMAP},
  199. {.name = "col_varbit", .type = DB_BITMAP},
  200. {.name = NULL}
  201. };
  202. db = db_ctx("postgres");
  203. if (db == NULL) {
  204. ERR("Error while initializing database layer\n");
  205. goto error;
  206. }
  207. if (db_add_db(db, "postgres://janakj:heslo@localhost/ser") < 0) goto error;
  208. if (db_connect(db) < 0) goto error;
  209. del = db_cmd(DB_DEL, db, "test", NULL, NULL, NULL);
  210. if (del == NULL) {
  211. ERR("Error while building delete * query\n");
  212. goto error;
  213. }
  214. put = db_cmd(DB_PUT, db, "test", NULL, NULL, int_vals);
  215. if (put == NULL) {
  216. ERR("Error while building test query\n");
  217. goto error;
  218. }
  219. if (db_exec(NULL, del)) {
  220. ERR("Error while deleting rows from test table\n");
  221. goto error;
  222. }
  223. put->vals[0].v.int4 = 0xffffffff;
  224. put->vals[1].v.int4 = 0xffffffff;
  225. put->vals[2].v.int4 = 0xffffffff;
  226. put->vals[3].v.int4 = 0xffffffff;
  227. put->vals[4].v.int4 = 0xffffffff;
  228. put->vals[5].v.int4 = 0xffffffff;
  229. put->vals[6].v.int4 = 0xffffffff;
  230. put->vals[7].v.int4 = 0xffffffff;
  231. if (db_exec(NULL, put)) {
  232. ERR("Error while executing database command\n");
  233. goto error;
  234. }
  235. put->vals[0].v.int4 = 0;
  236. put->vals[1].v.int4 = 0;
  237. put->vals[2].v.int4 = 0;
  238. put->vals[3].v.int4 = 0;
  239. put->vals[4].v.int4 = 0;
  240. put->vals[5].v.int4 = 0;
  241. put->vals[6].v.int4 = 0;
  242. put->vals[7].v.int4 = 0;
  243. if (db_exec(NULL, put)) {
  244. ERR("Error while executing database command\n");
  245. goto error;
  246. }
  247. db_cmd_free(put);
  248. put = db_cmd(DB_PUT, db, "test", NULL, NULL, bitmap_vals);
  249. if (put == NULL) {
  250. ERR("Error while building bitmap test query\n");
  251. goto error;
  252. }
  253. put->vals[0].v.int4 = 0xffffffff;
  254. put->vals[1].v.int4 = 0xffffffff;
  255. put->vals[2].v.int4 = 0xffffffff;
  256. put->vals[3].v.int4 = 0xffffffff;
  257. put->vals[4].v.int4 = 0xffffffff;
  258. if (db_exec(NULL, put)) {
  259. ERR("Error while executing database command\n");
  260. goto error;
  261. }
  262. put->vals[0].v.int4 = 0;
  263. put->vals[1].v.int4 = 0;
  264. put->vals[2].v.int4 = 0;
  265. put->vals[3].v.int4 = 0;
  266. put->vals[4].v.int4 = 0;
  267. if (db_exec(NULL, put)) {
  268. ERR("Error while executing database command\n");
  269. goto error;
  270. }
  271. db_cmd_free(put);
  272. put = db_cmd(DB_PUT, db, "test", NULL, NULL, float_vals);
  273. if (put == NULL) {
  274. ERR("Error while building float test query\n");
  275. goto error;
  276. }
  277. put->vals[0].v.flt = FLT_MAX;
  278. put->vals[1].v.flt = FLT_MAX;
  279. if (db_exec(NULL, put)) {
  280. ERR("Error while executing database command\n");
  281. goto error;
  282. }
  283. put->vals[0].v.flt = FLT_MIN;
  284. put->vals[1].v.flt = FLT_MIN;
  285. if (db_exec(NULL, put)) {
  286. ERR("Error while executing database command\n");
  287. goto error;
  288. }
  289. db_cmd_free(put);
  290. put = db_cmd(DB_PUT, db, "test", NULL, NULL, double_vals);
  291. if (put == NULL) {
  292. ERR("Error while building double test query\n");
  293. goto error;
  294. }
  295. put->vals[0].v.dbl = DBL_MAX;
  296. if (db_exec(NULL, put)) {
  297. ERR("Error while executing database command\n");
  298. goto error;
  299. }
  300. put->vals[0].v.dbl = DBL_MIN;
  301. if (db_exec(NULL, put)) {
  302. ERR("Error while executing database command\n");
  303. goto error;
  304. }
  305. db_cmd_free(put);
  306. put = db_cmd(DB_PUT, db, "test", NULL, NULL, str_vals);
  307. if (put == NULL) {
  308. ERR("Error while building str test query\n");
  309. goto error;
  310. }
  311. put->vals[0].v.lstr.s = "";
  312. put->vals[0].v.lstr.len = 0;
  313. put->vals[1].v.lstr.s = "";
  314. put->vals[1].v.lstr.len = 0;
  315. put->vals[2].v.lstr.s = "";
  316. put->vals[2].v.lstr.len = 0;
  317. put->vals[3].v.lstr.s = "";
  318. put->vals[3].v.lstr.len = 0;
  319. put->vals[4].v.lstr.s = "";
  320. put->vals[4].v.lstr.len = 0;
  321. if (db_exec(NULL, put)) {
  322. ERR("Error while executing database command\n");
  323. goto error;
  324. }
  325. put->vals[0].v.lstr.s = "abc should not be there";
  326. put->vals[0].v.lstr.len = 3;
  327. put->vals[1].v.lstr.s = "abc should not be there";
  328. put->vals[1].v.lstr.len = 3;
  329. put->vals[2].v.lstr.s = "abc should not be there";
  330. put->vals[2].v.lstr.len = 3;
  331. put->vals[3].v.lstr.s = "abc should not be there";
  332. put->vals[3].v.lstr.len = 3;
  333. put->vals[4].v.lstr.s = "a should not be there";
  334. put->vals[4].v.lstr.len = 1;
  335. if (db_exec(NULL, put)) {
  336. ERR("Error while executing database command\n");
  337. goto error;
  338. }
  339. db_cmd_free(put);
  340. put = db_cmd(DB_PUT, db, "test", NULL, NULL, cstr_vals);
  341. if (put == NULL) {
  342. ERR("Error while building cstr test query\n");
  343. goto error;
  344. }
  345. put->vals[0].v.cstr = "";
  346. put->vals[1].v.cstr = "";
  347. put->vals[2].v.cstr = "";
  348. put->vals[3].v.cstr = "";
  349. put->vals[4].v.cstr = "";
  350. if (db_exec(NULL, put)) {
  351. ERR("Error while executing database command\n");
  352. goto error;
  353. }
  354. put->vals[0].v.cstr = "def";
  355. put->vals[1].v.cstr = "def";
  356. put->vals[2].v.cstr = "def";
  357. put->vals[3].v.cstr = "def";
  358. put->vals[4].v.cstr = "d";
  359. if (db_exec(NULL, put)) {
  360. ERR("Error while executing database command\n");
  361. goto error;
  362. }
  363. db_cmd_free(put);
  364. put = db_cmd(DB_PUT, db, "test", NULL, NULL, blob_vals);
  365. if (put == NULL) {
  366. ERR("Error while building blob test query\n");
  367. goto error;
  368. }
  369. put->vals[0].v.blob.s = "\0\0\0\0";
  370. put->vals[0].v.blob.len = 4;
  371. if (db_exec(NULL, put)) {
  372. ERR("Error while executing database command\n");
  373. goto error;
  374. }
  375. db_cmd_free(put);
  376. put = db_cmd(DB_PUT, db, "test", NULL, NULL, datetime_vals);
  377. if (put == NULL) {
  378. ERR("Error while building datetime test query\n");
  379. goto error;
  380. }
  381. put->vals[0].v.time = 0xffffffff;
  382. put->vals[1].v.time = 0xffffffff;
  383. put->vals[2].v.time = 0xffffffff;
  384. put->vals[3].v.time = 0xffffffff;
  385. if (db_exec(NULL, put)) {
  386. ERR("Error while executing database command\n");
  387. goto error;
  388. }
  389. put->vals[0].v.time = 0;
  390. put->vals[1].v.time = 0;
  391. put->vals[2].v.time = 0;
  392. put->vals[3].v.time = 0;
  393. if (db_exec(NULL, put)) {
  394. ERR("Error while executing database command\n");
  395. goto error;
  396. }
  397. if (put) db_cmd_free(put);
  398. if (del) db_cmd_free(del);
  399. put = NULL;
  400. del = NULL;
  401. get = db_cmd(DB_GET, db, "test", res, NULL, NULL);
  402. if (get == NULL) {
  403. ERR("Error while building select query\n");
  404. goto error;
  405. }
  406. if (db_exec(&result, get)) {
  407. ERR("Error while executing select query\n");
  408. goto error;
  409. }
  410. rec = db_first(result);
  411. row = 1;
  412. while(rec) {
  413. ERR("row: %d\n", row);
  414. for(i = 0; !DB_FLD_LAST(rec->fld[i]); i++) {
  415. if (rec->fld[i].flags & DB_NULL) {
  416. ERR("%s: NULL\n", rec->fld[i].name);
  417. } else {
  418. switch(rec->fld[i].type) {
  419. case DB_INT:
  420. case DB_BITMAP:
  421. ERR("%s: %d\n", rec->fld[i].name, rec->fld[i].v.int4);
  422. break;
  423. case DB_DATETIME:
  424. times = ctime(&rec->fld[i].v.time);
  425. ERR("%s: %d:%.*s\n", rec->fld[i].name, rec->fld[i].v.time, strlen(times) - 1, times);
  426. break;
  427. case DB_DOUBLE:
  428. ERR("%s: %f\n", rec->fld[i].name, rec->fld[i].v.dbl);
  429. break;
  430. case DB_FLOAT:
  431. ERR("%s: %f\n", rec->fld[i].name, rec->fld[i].v.flt);
  432. break;
  433. case DB_STR:
  434. case DB_BLOB:
  435. ERR("%s: %.*s\n", rec->fld[i].name, rec->fld[i].v.lstr.len, rec->fld[i].v.lstr.s);
  436. break;
  437. case DB_CSTR:
  438. ERR("%s: %s\n", rec->fld[i].name, rec->fld[i].v.cstr);
  439. break;
  440. }
  441. }
  442. }
  443. ERR("\n");
  444. rec = db_next(result);
  445. row++;
  446. }
  447. db_res_free(result);
  448. db_cmd_free(get);
  449. db_disconnect(db);
  450. db_ctx_free(db);
  451. return 0;
  452. error:
  453. if (get) db_cmd_free(get);
  454. if (put) db_cmd_free(put);
  455. if (del) db_cmd_free(del);
  456. db_disconnect(db);
  457. db_ctx_free(db);
  458. return -1;
  459. }
  460. #endif /* PG_TEST */
  461. int mod_register(char *path, int *dlflags, void *p1, void *p2)
  462. {
  463. if(db_api_init()<0)
  464. return -1;
  465. return 0;
  466. }
  467. static int pg_mod_init(void)
  468. {
  469. #ifdef PG_TEST
  470. if (pg_test() == 0) {
  471. ERR("postgres: Testing successful\n");
  472. } else {
  473. ERR("postgres: Testing failed\n");
  474. }
  475. return -1;
  476. #endif /* PG_TEST */
  477. if(pg_init_lock_set(pg_lockset)<0)
  478. return -1;
  479. return km_postgres_mod_init();
  480. }
  481. static void pg_mod_destroy(void)
  482. {
  483. pg_destroy_lock_set();
  484. }
  485. /** @} */