pg_mod.c

Go to the documentation of this file.
00001 /* 
00002  * $Id$ 
00003  *
00004  * PostgreSQL Database Driver for SER
00005  *
00006  * Portions Copyright (C) 2001-2003 FhG FOKUS
00007  * Copyright (C) 2003 August.Net Services, LLC
00008  * Portions Copyright (C) 2005-2008 iptelorg GmbH
00009  *
00010  * This file is part of SER, a free SIP server.
00011  *
00012  * SER is free software; you can redistribute it and/or modify it under the
00013  * terms of the GNU General Public License as published by the Free Software
00014  * Foundation; either version 2 of the License, or (at your option) any later
00015  * version
00016  *
00017  * For a license to use the ser software under conditions other than those
00018  * described here, or to purchase support for this software, please contact
00019  * iptel.org by e-mail at the following addresses: info@iptel.org
00020  *
00021  * SER is distributed in the hope that it will be useful, but WITHOUT ANY
00022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00023  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00024  * details.
00025  *
00026  * You should have received a copy of the GNU General Public License along
00027  * with this program; if not, write to the Free Software Foundation, Inc., 59
00028  * Temple Place, Suite 330, Boston, MA 02111-1307 USA
00029  */
00030 
00039 #include "pg_mod.h"
00040 #include "pg_uri.h"
00041 #include "pg_con.h"
00042 #include "pg_cmd.h"
00043 #include "pg_res.h"
00044 #include "pg_fld.h"
00045 #include "km_db_postgres.h"
00046 
00047 #include "../../sr_module.h"
00048 
00049 #ifdef PG_TEST
00050 #include <limits.h>
00051 #include <float.h>
00052 #endif
00053 
00054 MODULE_VERSION
00055 
00056 static int pg_mod_init(void);
00057 static void pg_mod_destroy(void);
00058 
00059 int pg_connect_timeout = 0;  /* Default is unlimited */
00060 int pg_retries = 2;  /* How many times should the module try re-execute failed commands.
00061                                           * 0 disables reconnecting */
00062 
00063 int pg_lockset = 4;
00064 
00065 /*
00066  * Postgres module interface
00067  */
00068 static cmd_export_t cmds[] = {
00069         {"db_ctx",    (cmd_function)NULL, 0, 0, 0},
00070         {"db_con",    (cmd_function)pg_con, 0, 0, 0},
00071         {"db_uri",    (cmd_function)pg_uri, 0, 0, 0},
00072         {"db_cmd",    (cmd_function)pg_cmd, 0, 0, 0},
00073         {"db_put",    (cmd_function)pg_cmd_exec, 0, 0, 0},
00074         {"db_del",    (cmd_function)pg_cmd_exec, 0, 0, 0},
00075         {"db_get",    (cmd_function)pg_cmd_exec, 0, 0, 0},
00076         {"db_upd",    (cmd_function)pg_cmd_exec, 0, 0, 0},
00077         {"db_sql",    (cmd_function)pg_cmd_exec, 0, 0, 0},
00078         {"db_res",    (cmd_function)pg_res, 0, 0, 0},
00079         {"db_fld",    (cmd_function)pg_fld, 0, 0, 0},
00080         {"db_first",  (cmd_function)pg_cmd_first, 0, 0, 0},
00081         {"db_next",   (cmd_function)pg_cmd_next, 0, 0, 0},
00082         {"db_setopt", (cmd_function)pg_setopt, 0, 0, 0},
00083         {"db_getopt", (cmd_function)pg_getopt, 0, 0, 0},
00084         {"db_bind_api", (cmd_function)db_postgres_bind_api, 0, 0, 0},
00085         {0, 0, 0, 0, 0}
00086 };
00087 
00088 
00089 /*
00090  * Exported parameters
00091  */
00092 static param_export_t params[] = {
00093         {"retries",         PARAM_INT, &pg_retries },
00094         {"lockset",         PARAM_INT, &pg_lockset },
00095         {0, 0, 0}
00096 };
00097 
00098 
00099 struct module_exports exports = {
00100         "db_postgres",
00101         cmds,
00102         0,            /* RPC method */
00103         params,       /* module parameters */
00104         pg_mod_init,  /* module initialization function */
00105         0,            /* response function*/
00106         pg_mod_destroy,  /* destroy function */
00107         0,            /* oncancel function */
00108         0             /* per-child init function */
00109 };
00110 
00111 /*
00112 CREATE TABLE test (
00113     col_bool BOOL,
00114     col_bytea BYTEA,
00115     col_char CHAR,
00116     col_int8 INT8,
00117     col_int4 INT4,
00118     col_int2 INT2,
00119     col_text TEXT,
00120     col_float4 FLOAT4,
00121     col_float8 FLOAT8,
00122     col_inet INET,
00123     col_bpchar BPCHAR,
00124     col_varchar VARCHAR,
00125     col_timestamp TIMESTAMP,
00126     col_timestamptz TIMESTAMPTZ,
00127     col_bit BIT(32),
00128     col_varbit VARBIT
00129 );
00130 */
00131 
00132 
00133 #ifdef PG_TEST
00134 int pg_test(void)
00135 {
00136         int i, row;
00137         db_ctx_t* db;
00138         db_cmd_t* put, *del, *get;
00139         db_res_t* result;
00140         db_rec_t* rec;
00141         char* times;
00142 
00143         db_fld_t int_vals[] = {
00144                 {.name = "col_bool",        .type = DB_INT},
00145                 {.name = "col_int8",        .type = DB_INT},
00146                 {.name = "col_int4",        .type = DB_INT},
00147                 {.name = "col_inet",        .type = DB_INT},
00148                 {.name = "col_timestamp",   .type = DB_INT},
00149                 {.name = "col_timestamptz", .type = DB_INT},
00150                 {.name = "col_bit",         .type = DB_INT},
00151                 {.name = "col_varbit",      .type = DB_INT},
00152                 {.name = NULL}
00153         };
00154 
00155         db_fld_t datetime_vals[] = {
00156                 {.name = "col_int8",        .type = DB_INT},
00157                 {.name = "col_int4",        .type = DB_INT},
00158                 {.name = "col_timestamp",   .type = DB_INT},
00159                 {.name = "col_timestamptz", .type = DB_INT},
00160                 {.name = NULL}
00161         };
00162 
00163 
00164         db_fld_t bitmap_vals[] = {
00165                 {.name = "col_int8",      .type = DB_INT},
00166                 {.name = "col_int4",      .type = DB_INT},
00167                 {.name = "col_bit",       .type = DB_INT},
00168                 {.name = "col_varbit",    .type = DB_INT},
00169                 {.name = NULL}
00170         };
00171 
00172         db_fld_t float_vals[] = {
00173                 {.name = "col_float4", .type = DB_FLOAT},
00174                 {.name = "col_float8", .type = DB_FLOAT},
00175                 {.name = NULL}
00176         };
00177 
00178         db_fld_t double_vals[] = {
00179                 {.name = "col_float8", .type = DB_DOUBLE},
00180                 {.name = NULL}
00181         };
00182 
00183         db_fld_t str_vals[] = {
00184                 {.name = "col_varchar", .type = DB_STR},
00185                 {.name = "col_bytea",   .type = DB_STR},
00186                 {.name = "col_text",    .type = DB_STR},
00187                 {.name = "col_bpchar",  .type = DB_STR},
00188                 {.name = "col_char",    .type = DB_STR},
00189                 {.name = NULL}
00190         };
00191 
00192         db_fld_t cstr_vals[] = {
00193                 {.name = "col_varchar", .type = DB_CSTR},
00194                 {.name = "col_bytea",   .type = DB_CSTR},
00195                 {.name = "col_text",    .type = DB_CSTR},
00196                 {.name = "col_bpchar",  .type = DB_CSTR},
00197                 {.name = "col_char",    .type = DB_CSTR},
00198                 {.name = NULL}
00199         };
00200 
00201         db_fld_t blob_vals[] = {
00202                 {.name = "col_bytea",   .type = DB_BLOB},
00203                 {.name = NULL}
00204         };
00205 
00206 
00207         db_fld_t res[] = {
00208                 {.name = "col_bool",        .type = DB_INT},
00209                 {.name = "col_bytea",       .type = DB_BLOB},
00210                 {.name = "col_char",        .type = DB_STR},
00211                 {.name = "col_int8",        .type = DB_INT},
00212                 {.name = "col_int4",        .type = DB_INT},
00213                 {.name = "col_int2",        .type = DB_INT},
00214                 {.name = "col_text",        .type = DB_STR},
00215                 {.name = "col_float4",      .type = DB_FLOAT},
00216                 {.name = "col_float8",      .type = DB_DOUBLE},
00217                 {.name = "col_inet",        .type = DB_INT},
00218                 {.name = "col_bpchar",      .type = DB_STR},
00219                 {.name = "col_varchar",     .type = DB_STR},
00220                 {.name = "col_timestamp",   .type = DB_DATETIME},
00221                 {.name = "col_timestamptz", .type = DB_DATETIME},
00222                 {.name = "col_bit",         .type = DB_BITMAP},
00223                 {.name = "col_varbit",      .type = DB_BITMAP},
00224                 {.name = NULL}
00225         };
00226 
00227 
00228         db = db_ctx("postgres");
00229         if (db == NULL) {
00230                 ERR("Error while initializing database layer\n");
00231                 goto error;
00232         }
00233         if (db_add_db(db, "postgres://janakj:heslo@localhost/ser") < 0) goto error;
00234         if (db_connect(db) < 0) goto error;
00235         
00236         del = db_cmd(DB_DEL, db, "test", NULL, NULL, NULL);
00237         if (del == NULL) {
00238                 ERR("Error while building delete * query\n");
00239                 goto error;
00240         }
00241 
00242     put = db_cmd(DB_PUT, db, "test", NULL, NULL, int_vals);
00243         if (put == NULL) {
00244                 ERR("Error while building test query\n");
00245                 goto error;
00246         }
00247 
00248         if (db_exec(NULL, del)) {
00249                 ERR("Error while deleting rows from test table\n");
00250                 goto error;
00251         }
00252 
00253         put->vals[0].v.int4 = 0xffffffff;
00254         put->vals[1].v.int4 = 0xffffffff;
00255         put->vals[2].v.int4 = 0xffffffff;
00256         put->vals[3].v.int4 = 0xffffffff;
00257         put->vals[4].v.int4 = 0xffffffff;
00258         put->vals[5].v.int4 = 0xffffffff;
00259         put->vals[6].v.int4 = 0xffffffff;
00260         put->vals[7].v.int4 = 0xffffffff;
00261 
00262         if (db_exec(NULL, put)) {
00263                 ERR("Error while executing database command\n");
00264                 goto error;
00265         }
00266 
00267         put->vals[0].v.int4 = 0;
00268         put->vals[1].v.int4 = 0;
00269         put->vals[2].v.int4 = 0;
00270         put->vals[3].v.int4 = 0;
00271         put->vals[4].v.int4 = 0;
00272         put->vals[5].v.int4 = 0;
00273         put->vals[6].v.int4 = 0;
00274         put->vals[7].v.int4 = 0;
00275 
00276         if (db_exec(NULL, put)) {
00277                 ERR("Error while executing database command\n");
00278                 goto error;
00279         }
00280 
00281         db_cmd_free(put);
00282 
00283         put = db_cmd(DB_PUT, db, "test", NULL, NULL, bitmap_vals);
00284         if (put == NULL) {
00285                 ERR("Error while building bitmap test query\n");
00286                 goto error;
00287         }
00288 
00289         put->vals[0].v.int4 = 0xffffffff;
00290         put->vals[1].v.int4 = 0xffffffff;
00291         put->vals[2].v.int4 = 0xffffffff;
00292         put->vals[3].v.int4 = 0xffffffff;
00293         put->vals[4].v.int4 = 0xffffffff;
00294         if (db_exec(NULL, put)) {
00295                 ERR("Error while executing database command\n");
00296                 goto error;
00297         }
00298 
00299         put->vals[0].v.int4 = 0;
00300         put->vals[1].v.int4 = 0;
00301         put->vals[2].v.int4 = 0;
00302         put->vals[3].v.int4 = 0;
00303         put->vals[4].v.int4 = 0;
00304         if (db_exec(NULL, put)) {
00305                 ERR("Error while executing database command\n");
00306                 goto error;
00307         }
00308 
00309         db_cmd_free(put);
00310 
00311         put = db_cmd(DB_PUT, db, "test", NULL, NULL, float_vals);
00312         if (put == NULL) {
00313                 ERR("Error while building float test query\n");
00314                 goto error;
00315         }
00316 
00317         put->vals[0].v.flt = FLT_MAX;
00318         put->vals[1].v.flt = FLT_MAX;
00319         if (db_exec(NULL, put)) {
00320                 ERR("Error while executing database command\n");
00321                 goto error;
00322         }
00323 
00324         put->vals[0].v.flt = FLT_MIN;
00325         put->vals[1].v.flt = FLT_MIN;
00326         if (db_exec(NULL, put)) {
00327                 ERR("Error while executing database command\n");
00328                 goto error;
00329         }
00330 
00331         db_cmd_free(put);
00332 
00333         put = db_cmd(DB_PUT, db, "test", NULL, NULL, double_vals);
00334         if (put == NULL) {
00335                 ERR("Error while building double test query\n");
00336                 goto error;
00337         }
00338 
00339         put->vals[0].v.dbl = DBL_MAX;
00340         if (db_exec(NULL, put)) {
00341                 ERR("Error while executing database command\n");
00342                 goto error;
00343         }
00344 
00345         put->vals[0].v.dbl = DBL_MIN;
00346         if (db_exec(NULL, put)) {
00347                 ERR("Error while executing database command\n");
00348                 goto error;
00349         }
00350 
00351 
00352         db_cmd_free(put);
00353 
00354         put = db_cmd(DB_PUT, db, "test", NULL, NULL, str_vals);
00355         if (put == NULL) {
00356                 ERR("Error while building str test query\n");
00357                 goto error;
00358         }
00359 
00360         put->vals[0].v.lstr.s = "";
00361         put->vals[0].v.lstr.len = 0;
00362         put->vals[1].v.lstr.s = "";
00363         put->vals[1].v.lstr.len = 0;
00364         put->vals[2].v.lstr.s = "";
00365         put->vals[2].v.lstr.len = 0;
00366         put->vals[3].v.lstr.s = "";
00367         put->vals[3].v.lstr.len = 0;
00368         put->vals[4].v.lstr.s = "";
00369         put->vals[4].v.lstr.len = 0;
00370         if (db_exec(NULL, put)) {
00371                 ERR("Error while executing database command\n");
00372                 goto error;
00373         }
00374 
00375         put->vals[0].v.lstr.s = "abc should not be there";
00376         put->vals[0].v.lstr.len = 3;
00377         put->vals[1].v.lstr.s = "abc should not be there";
00378         put->vals[1].v.lstr.len = 3;
00379         put->vals[2].v.lstr.s = "abc should not be there";
00380         put->vals[2].v.lstr.len = 3;
00381         put->vals[3].v.lstr.s = "abc should not be there";
00382         put->vals[3].v.lstr.len = 3;
00383         put->vals[4].v.lstr.s = "a should not be there";
00384         put->vals[4].v.lstr.len = 1;
00385         if (db_exec(NULL, put)) {
00386                 ERR("Error while executing database command\n");
00387                 goto error;
00388         }
00389 
00390         db_cmd_free(put);
00391 
00392         put = db_cmd(DB_PUT, db, "test", NULL, NULL, cstr_vals);
00393         if (put == NULL) {
00394                 ERR("Error while building cstr test query\n");
00395                 goto error;
00396         }
00397 
00398         put->vals[0].v.cstr = "";
00399         put->vals[1].v.cstr = "";
00400         put->vals[2].v.cstr = "";
00401         put->vals[3].v.cstr = "";
00402         put->vals[4].v.cstr = "";
00403         if (db_exec(NULL, put)) {
00404                 ERR("Error while executing database command\n");
00405                 goto error;
00406         }
00407 
00408         put->vals[0].v.cstr = "def";
00409         put->vals[1].v.cstr = "def";
00410         put->vals[2].v.cstr = "def";
00411         put->vals[3].v.cstr = "def";
00412         put->vals[4].v.cstr = "d";
00413         if (db_exec(NULL, put)) {
00414                 ERR("Error while executing database command\n");
00415                 goto error;
00416         }
00417 
00418         db_cmd_free(put);
00419 
00420         put = db_cmd(DB_PUT, db, "test", NULL, NULL, blob_vals);
00421         if (put == NULL) {
00422                 ERR("Error while building blob test query\n");
00423                 goto error;
00424         }
00425 
00426         put->vals[0].v.blob.s = "\0\0\0\0";
00427         put->vals[0].v.blob.len = 4;
00428         if (db_exec(NULL, put)) {
00429                 ERR("Error while executing database command\n");
00430                 goto error;
00431         }
00432 
00433 
00434         db_cmd_free(put);
00435 
00436         put = db_cmd(DB_PUT, db, "test", NULL, NULL, datetime_vals);
00437         if (put == NULL) {
00438                 ERR("Error while building datetime test query\n");
00439                 goto error;
00440         }
00441 
00442         put->vals[0].v.time = 0xffffffff;
00443         put->vals[1].v.time = 0xffffffff;
00444         put->vals[2].v.time = 0xffffffff;
00445         put->vals[3].v.time = 0xffffffff;
00446         if (db_exec(NULL, put)) {
00447                 ERR("Error while executing database command\n");
00448                 goto error;
00449         }
00450 
00451         put->vals[0].v.time = 0;
00452         put->vals[1].v.time = 0;
00453         put->vals[2].v.time = 0;
00454         put->vals[3].v.time = 0;
00455         if (db_exec(NULL, put)) {
00456                 ERR("Error while executing database command\n");
00457                 goto error;
00458         }
00459 
00460         if (put) db_cmd_free(put);
00461         if (del) db_cmd_free(del);
00462         put = NULL;
00463         del = NULL;
00464 
00465 
00466         get = db_cmd(DB_GET, db, "test", res, NULL, NULL);
00467         if (get == NULL) {
00468                 ERR("Error while building select query\n");
00469                 goto error;
00470         }
00471 
00472         if (db_exec(&result, get)) {
00473                 ERR("Error while executing select query\n");
00474                 goto error;
00475         }
00476 
00477         rec = db_first(result);
00478         row = 1;
00479         while(rec) {
00480                 ERR("row: %d\n", row);
00481                 for(i = 0; !DB_FLD_LAST(rec->fld[i]); i++) {
00482                         if (rec->fld[i].flags & DB_NULL) {
00483                                 ERR("%s: NULL\n", rec->fld[i].name);
00484                         } else {
00485                                 switch(rec->fld[i].type) {
00486                                 case DB_INT:
00487                                 case DB_BITMAP:
00488                                         ERR("%s: %d\n", rec->fld[i].name, rec->fld[i].v.int4);
00489                                         break;
00490                                         
00491                                 case DB_DATETIME:
00492                                         times = ctime(&rec->fld[i].v.time);
00493                                         ERR("%s: %d:%.*s\n", rec->fld[i].name, rec->fld[i].v.time, strlen(times) - 1, times);
00494                                         break;
00495                                         
00496                                 case DB_DOUBLE:
00497                                         ERR("%s: %f\n", rec->fld[i].name, rec->fld[i].v.dbl);
00498                                         break;
00499                                         
00500                                 case DB_FLOAT:
00501                                         ERR("%s: %f\n", rec->fld[i].name, rec->fld[i].v.flt);
00502                                         break;
00503                                         
00504                                 case DB_STR:
00505                                 case DB_BLOB:
00506                                         ERR("%s: %.*s\n", rec->fld[i].name, rec->fld[i].v.lstr.len, rec->fld[i].v.lstr.s);
00507                                         break;
00508                                         
00509                                 case DB_CSTR:
00510                                         ERR("%s: %s\n", rec->fld[i].name, rec->fld[i].v.cstr);
00511                                         break;
00512                                 }
00513                         }
00514                 }
00515                 ERR("\n");
00516                 rec = db_next(result);
00517                 row++;
00518         }
00519 
00520         db_res_free(result);
00521 
00522         db_cmd_free(get);
00523         db_disconnect(db);
00524         db_ctx_free(db);
00525         return 0;
00526 
00527  error:
00528         if (get) db_cmd_free(get);
00529         if (put) db_cmd_free(put);
00530         if (del) db_cmd_free(del);
00531         db_disconnect(db);
00532         db_ctx_free(db);
00533         return -1;
00534 }
00535 #endif /* PG_TEST */
00536 
00537 int mod_register(char *path, int *dlflags, void *p1, void *p2)
00538 {
00539         if(db_api_init()<0)
00540                 return -1;
00541         return 0;
00542 }
00543 
00544 static int pg_mod_init(void)
00545 {
00546 #ifdef PG_TEST
00547         if (pg_test() == 0) {
00548                 ERR("postgres: Testing successful\n");
00549         } else {
00550                 ERR("postgres: Testing failed\n");
00551         }
00552         return -1;
00553 #endif /* PG_TEST */
00554         if(pg_init_lock_set(pg_lockset)<0)
00555                 return -1;
00556         return km_postgres_mod_init();
00557 }
00558 
00559 static void pg_mod_destroy(void)
00560 {
00561         pg_destroy_lock_set();
00562 }
00563