db_ops module
=============

Author: tomas.mandys at iptel dot org

db operations from route script

mod_params
-----------
db_url - default database
declare_query - declare query for @db.query (see select syntax) or for reference from db_query(declare_no)
max_queries - number of max. open queries, i.e. max query_handle

format:

xltext = text_parsed_by_xl_lib
database = type ":" user:psw "@" host "/" database_name
field = xltext
fields = field [ "," field ... ]
op = "=" | "<" | ">" | "<=" | ">="  ; note: non-equal nit supported by db API
where = fields
ops = op [ "," op ... ]
order = field
type = "s" | "i" | "d" | "f" | "t" ; enables to force particular type when writing to db driver (string/int/double/float/datetime), valueable especially for datetime
value = [type ":"] xltext
values = value [ "," value ...]

select = "select/" [database "/"] table "/" fields "/" where "/" ops "/" order "/" values
insert = "insert/" [database "/"] table "/" fields "/" values
update = "update/" [database "/"] table "/" fields "/" where "/" ops "/" values
replace = "replace/" [database "/"] table "/" fields "/" values
delete = "delete/" [database "/"] table "/" where "/" ops "/" values
raw_query = "select ...." | "insert ..."   # not delimited by "/"

Note that even table/field/where/order are ptrcessed using xl_lib parser. Table name may be determined via AVP, probably useless but "magnifique".

commands
--------

db_query ( (insert | update | replace | delete) | declare_no)

db_query (select | declare_no, query_handle)
  query is accesable using @db.fetch select
db_close (query_handle)
  note all close after script processing automatically

db_foreach(select | declare_no, route)
  call route for each row, loop is interrupted if route return code <= 0, retcode of the last route call is returned as result of db_foreach (or -1 when no select is empty)

declare_no references to query declared using "declare_query"

selects
-------

@db.query look in table defined using declare_query, opens query, fetches value and closes table

@db.query[declare_no]                  .. get value from first row and first field
@db.query[declare_no].count            .. get number of rows
@db.query[declare_no].field[m]         .. get value from first row and m-th field
@db.query[declare_no].row[n]           .. get value from n-th row and first field, negative values count from the end (-1 == last row)
@db.query[declare_no].row[n].field[m]  .. get value from n-th row and m-th field

@db.fetch get value from query opened using dbops_open_query. Note all opened queries are closed in POST_SCRIPT callback not to leak memory

@db.fetch[query_handle]
@db.fetch[query_handle].count
@db.fetch[query_handle].field[m]
@db.fetch[query_handle].row[n]
@db.fetch[query_handle].row[n].field[m]

@*.field supports select_any_uri and select_any_nameaddr

m4 processor
------------

define(`db_declare_query', `gen_id(`db_declare_query_cnt') define(`$1', indir(`db_declare_query_cnt')) modparam("`db_ops'", "`declare_query'", $2)')

usage:

db_declare_query(SELECT_1, "select/foo/bar/rab///%$avp");
db_declare_query(SELECT_2, "select/foo/bar/rab,bra/=,>//%$avp,1");
db_declare_query(SELECT_3, "select contact from location where nat=1 and expires>=now()");

@db.query[SELECT_2]
db_query(SELECT_1, 1);


Examples:
--------
1) example
modparam("db_ops", "declare_query", "select/location/received/uid///%$f.uid");  #0
modparam("db_ops", "declare_query", "select/subscriber/email_address,greeting/uid,allow_find///%$uidparam,1");  #1
modparam("db_ops", "declare_query", "select/silo/body/uid//inc_time/%$f.uid");  #2
modparam("db_ops", "declare_query", "delete from location where expires<now()");  # 3  raw query

@db.query[0]               ..  SELECT received FROM location WHERE uid = "%$f.uid"
@db.query[0].count         ..  SELECT count(*) FROM location WHERE uid = "%$f.uid"
@db.query[1].field[0]      ..  SELECT email_address FROM subscriber WHERE uid = "%$f.uid" AND allow_find=1
@db.query[1].field[1]      ..  SELECT greeting FROM subscriber WHERE uid = "%$f.uid" AND allow_find=1
@db.query[2].count         ..  SELECT count(*) FROM silo WHERE uid = "%$f.uid"
@db.query[2].row[-1]       ..  SELECT body FROM silo WHERE uid = "%$f.uid" ORDER BY inc_time .. last row


db_query("delete/silo///");     ..  DELETE FROM silo
db_query("delete/silo/expired/<=/%Ts");     ..  DELETE FROM silo WHERE expired <= now;
db_query("insert/foo/bar,rab,abr,rbs/%$f.id,'hello world %fu',1,2");  .. INSERT INTO foo(bar,rab,abr,rbs) VALUES ("%$f.id","hello world %fu",1,2)
db_query("update/foo/rab,abr/bar//'hello world %f',1,2,%$f.id");       .. UPDATE foo SET rab="hello world %fu",rbs=45 WHERE bar="%$f.id"

db_query("delete/mysql://pretorian:sandra@net/fbi/identities//");

db_query("select/silo/body/uid//inc_time/%$f.uid", 4);  .. SELECT body FROM silo WHERE uid = "%$f.uid" ORDER BY inc_time
@db.fetch[4]             ..  get first raw
@db.fetch[4].raw[1]      ..  get second raw

db_query("select/silo/src_addr,dest_addr,body/uid//inc_time/%$t.uid", 5);  .. SELECT src_addr,dest_addr,body FROM silo WHERE uid = "%$t.uid" ORDER BY inc_time
@db.fetch[5].raw[-1].field[1]	.. get last dest_addr
db_close(4);
db_close(5);

# parametrization of queries
$uidparam="xx";
@db.query[1]

$uidparam="yy";
@db.query[1]

$uidparam="zz";
db_query(1, 5);
$uidparam="qq";
db_query(1, 6);
if (@db.fetch[6] == @db.fetch[5]) ....

db_close(5);
db_close(6);

db_query(SELECT_3, 1);
forach(1, PROCESS_ROW_ROUTE);


2)Test config
-----------
loadmodule "modules/mysql/mysql.so"
loadmodule "modules/xlog/xlog.so"
loadmodule "../../mods/db_ops/trunk/db_ops.so"

# -------------------------  request routing logic -------------------


modparam("db_ops", "declare_query", "select/location/received/uid///%$f.uid");
modparam("db_ops", "declare_query", "select/subscriber/email_address,greeting/uid,allow_find///%$t.uid,1");
modparam("db_ops", "declare_query", "select/silo/body/uid//inc_time/%$f.uid");
modparam("db_ops", "declare_query", "select/flexroute/flexroute_name,avps_in,avps_out/flexroute_name//priority/%$fxname");
modparam("db_ops", "declare_query", "select * from location");

# main routing logic

route{

$f.uid="QWERTY";

#db_query("delete/silo///");
#db_query("insert/foo/bar,rab,abr,rbs/%$f.id,'hello world %fu %$f.uid',1,2");
#db_query("update/foo/rab,abr/bar//'hello world %fu',1,%$f.id");

#db_query("delete/mysql://root@localhost/tekcore/identities///");

$fxname="enum";

$f.count=@db.query[3].count;
$f.r0f0=@db.query[3];
$f.r0f1=@db.query[3].field[1];
$f.r0f2=@db.query[3].field[2];
$f.r1f0=@db.query[3].row[1];
$f.r1f1=@db.query[3].row[1].field[1];
$f.r1f2=@db.query[3].row[1].field[2];
$f.rnf0=@db.query[3].row[-1];
$f.rnf1=@db.query[3].row[-1].field[1];
$f.rnf2=@db.query[3].row[-1].field[2];
xlog("L_INFO","LOG_SELECT: count:%$f.count {{%$f.r0f0,'%$f.r0f1','%$f.r0f2'},{%$f.r1f0,'%$f.r1f1','%$f.r1f2'}, {%$f.rnf0,'%$f.rnf1','%$f.rnf2'}}\n");

db_query("select/flexroute/domain_name,avps_in,avps_out/flexroute_name//priority/tc2ms", 4);

$f.count=@db.fetch[4].count;
$f.r0f0=@db.fetch[4];
$f.r0f1=@db.fetch[4].field[1];
$f.r0f2=@db.fetch[4].field[2];
$f.r1f0=@db.fetch[4].row[1];
$f.r1f1=@db.fetch[4].row[1].field[1];
$f.r1f2=@db.fetch[4].row[1].field[2];
$f.rnf0=@db.fetch[4].row[-1];
$f.rnf1=@db.fetch[4].row[-1].field[1];
$f.rnf2=@db.fetch[4].row[-1].field[2];

xlog("L_INFO","LOG_FETCH: count:%$f.count {{%$f.r0f0,'%$f.r0f1','%$f.r0f2'},{%$f.r1f0,'%$f.r1f1','%$f.r1f2'}, {%$f.rnf0,'%$f.rnf1','%$f.rnf2'}}\n");


#@db.fetch[4]             ..  get first raw
#@db.fetch[4].raw[1]      ..  get second raw

#parametrized query
$fxname="tc2smg";
db_query(3, 5);
$f.count=@db.fetch[5].count;
$f.r0f0=@db.fetch[5];
$f.r0f1=@db.fetch[5].field[1];
$f.r0f2=@db.fetch[5].field[2];
$f.r1f0=@db.fetch[5].row[1];
$f.r1f1=@db.fetch[5].row[1].field[1];
$f.r1f2=@db.fetch[5].row[1].field[2];
$f.rnf0=@db.fetch[5].row[-1];
$f.rnf1=@db.fetch[5].row[-1].field[1];
$f.rnf2=@db.fetch[5].row[-1].field[2];

xlog("L_INFO","LOG_FETCH_REF: count:%$f.count {{%$f.r0f0,'%$f.r0f1','%$f.r0f2'},{%$f.r1f0,'%$f.r1f1','%$f.r1f2'}, {%$f.rnf0,'%$f.rnf1','%$f.rnf2'}}\n");

#db_query("select/silo/src_addr,dest_addr,body/uid//inc_time/%$t.uid", 5);
# $avm = db.fetch[5].raw[-1].field[1] ==
db_close(4);
db_close(5);

}

