You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/db_perlvdb/perlvdbfunc.c

359 lines
7.2 KiB

/*
* $Id: perlvdbfunc.c 816 2007-02-13 18:33:22Z bastian $
*
* Perl virtual database module interface
*
* Copyright (C) 2007 Collax GmbH
* (Bastian Friedrich <bastian.friedrich@collax.com>)
*
* This file is part of Kamailio, a free SIP server.
*
* Kamailio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* Kamailio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "db_perlvdb.h"
#include "perlvdbfunc.h"
#include "../../str.h"
/*
* Simple conversion IV -> int
* including decreasing ref cnt
*/
long IV2int(SV *in) {
int ret = -1;
if (SvOK(in)) {
if (SvIOK(in)) {
ret = SvIV(in);
}
SvREFCNT_dec(in);
}
return ret;
}
/*
* Returns the class part of the URI
*/
char *parseurl(const char* url) {
char *cn;
cn = strchr(url, ':') + 1;
if (strlen(cn) > 0)
return cn;
else
return NULL;
}
SV *newvdbobj(const char* cn) {
SV* obj;
SV *class;
class = newSVpv(cn, 0);
obj = perlvdb_perlmethod(class, PERL_CONSTRUCTOR_NAME,
NULL, NULL, NULL, NULL);
return obj;
}
SV *getobj(db1_con_t *con) {
return ((SV*)CON_TAIL(con));
}
/*
* Checks whether the passed SV is a valid VDB object:
* - not null
* - not undef
* - an object
* - derived from Kamailio::VDB
*/
int checkobj(SV* obj) {
if (obj != NULL) {
if (obj != &PL_sv_undef) {
if (sv_isobject(obj)) {
if (sv_derived_from(obj, PERL_VDB_BASECLASS)) {
return 1;
}
}
}
}
return 0;
}
/*
* Initialize database module
* No function should be called before this
*/
db1_con_t* perlvdb_db_init(const char* url) {
db1_con_t* res;
char *cn;
SV *obj = NULL;
int consize = sizeof(db1_con_t) + sizeof(SV);
if (!url) {
LM_ERR("invalid parameter value\n");
return NULL;
}
cn = parseurl(url);
if (!cn) {
LM_ERR("invalid perl vdb url.\n");
return NULL;
}
obj = newvdbobj(cn);
if (!checkobj(obj)) {
LM_ERR("could not initialize module. Not inheriting from %s?\n",
PERL_VDB_BASECLASS);
return NULL;
}
res = pkg_malloc(consize);
if (!res) {
LM_ERR("no pkg memory left\n");
return NULL;
}
memset(res, 0, consize);
CON_TAIL(res) = (unsigned int)(unsigned long)obj;
return res;
}
/*
* Store name of table that will be used by
* subsequent database functions
*/
int perlvdb_use_table(db1_con_t* h, const str* t) {
SV *ret;
if (!h || !t || !t->s) {
LM_ERR("invalid parameter value\n");
return -1;
}
ret = perlvdb_perlmethod(getobj(h), PERL_VDB_USETABLEMETHOD,
sv_2mortal(newSVpv(t->s, t->len)), NULL, NULL, NULL);
return IV2int(ret);
}
void perlvdb_db_close(db1_con_t* h) {
if (!h) {
LM_ERR("invalid parameter value\n");
return;
}
pkg_free(h);
}
/*
* Insert a row into specified table
* h: structure representing database connection
* k: key names
* v: values of the keys
* n: number of key=value pairs
*/
int perlvdb_db_insertreplace(db1_con_t* h, db_key_t* k, db_val_t* v,
int n, char *insertreplace) {
AV *arr;
SV *arrref;
SV *ret;
arr = pairs2perlarray(k, v, n);
arrref = newRV_noinc((SV*)arr);
ret = perlvdb_perlmethod(getobj(h), insertreplace,
arrref, NULL, NULL, NULL);
av_undef(arr);
return IV2int(ret);
}
int perlvdb_db_insert(db1_con_t* h, db_key_t* k, db_val_t* v, int n) {
return perlvdb_db_insertreplace(h, k, v, n, PERL_VDB_INSERTMETHOD);
}
/*
* Just like insert, but replace the row if it exists
*/
int perlvdb_db_replace(db1_con_t* h, db_key_t* k, db_val_t* v, int n) {
return perlvdb_db_insertreplace(h, k, v, n, PERL_VDB_REPLACEMETHOD);
}
/*
* Delete a row from the specified table
* h: structure representing database connection
* k: key names
* o: operators
* v: values of the keys that must match
* n: number of key=value pairs
*/
int perlvdb_db_delete(db1_con_t* h, db_key_t* k, db_op_t* o, db_val_t* v,
int n) {
AV *arr;
SV *arrref;
SV *ret;
arr = conds2perlarray(k, o, v, n);
arrref = newRV_noinc((SV*)arr);
ret = perlvdb_perlmethod(getobj(h), PERL_VDB_DELETEMETHOD,
arrref, NULL, NULL, NULL);
av_undef(arr);
return IV2int(ret);
}
/*
* Update some rows in the specified table
* _h: structure representing database connection
* _k: key names
* _o: operators
* _v: values of the keys that must match
* _uk: updated columns
* _uv: updated values of the columns
* _n: number of key=value pairs
* _un: number of columns to update
*/
int perlvdb_db_update(db1_con_t* h, db_key_t* k, db_op_t* o, db_val_t* v,
db_key_t* uk, db_val_t* uv, int n, int un) {
AV *condarr;
AV *updatearr;
SV *condarrref;
SV *updatearrref;
SV *ret;
condarr = conds2perlarray(k, o, v, n);
updatearr = pairs2perlarray(uk, uv, un);
condarrref = newRV_noinc((SV*)condarr);
updatearrref = newRV_noinc((SV*)updatearr);
ret = perlvdb_perlmethod(getobj(h), PERL_VDB_UPDATEMETHOD,
condarrref, updatearrref, NULL, NULL);
av_undef(condarr);
av_undef(updatearr);
return IV2int(ret);
}
/*
* Query table for specified rows
* h: structure representing database connection
* k: key names
* op: operators
* v: values of the keys that must match
* c: column names to return
* n: number of key=values pairs to compare
* nc: number of columns to return
* o: order by the specified column
*/
int perlvdb_db_query(db1_con_t* h, db_key_t* k, db_op_t* op, db_val_t* v,
db_key_t* c, int n, int nc,
db_key_t o, db1_res_t** r) {
AV *condarr;
AV *retkeysarr;
SV *order;
SV *condarrref;
SV *retkeysref;
SV *resultset;
int retval = 0;
/* Create parameter set */
condarr = conds2perlarray(k, op, v, n);
retkeysarr = keys2perlarray(c, nc);
if (o) order = newSVpv(o->s, o->len);
else order = &PL_sv_undef;
condarrref = newRV_noinc((SV*)condarr);
retkeysref = newRV_noinc((SV*)retkeysarr);
/* Call perl method */
resultset = perlvdb_perlmethod(getobj(h), PERL_VDB_QUERYMETHOD,
condarrref, retkeysref, order, NULL);
av_undef(condarr);
av_undef(retkeysarr);
/* Transform perl result set to Kamailio result set */
if (!resultset) {
/* No results. */
LM_ERR("no perl result set.\n");
retval = -1;
} else {
if (sv_isa(resultset, "Kamailio::VDB::Result")) {
retval = perlresult2dbres(resultset, r);
/* Nested refs are decreased/deleted inside the routine */
SvREFCNT_dec(resultset);
} else {
LM_ERR("invalid result set retrieved from perl call.\n");
retval = -1;
}
}
return retval;
}
/*
* Release a result set from memory
*/
int perlvdb_db_free_result(db1_con_t* _h, db1_res_t* _r) {
int i;
if (_r) {
for (i = 0; i < _r->n; i++) {
if (_r->rows[i].values)
pkg_free(_r->rows[i].values);
}
if (_r->col.types)
pkg_free(_r->col.types);
if (_r->col.names)
pkg_free(_r->col.names);
if (_r->rows)
pkg_free(_r->rows);
pkg_free(_r);
}
return 0;
}