$Id: dag.txt,v 1.7 2000/02/19 19:11:39 remlali Exp $ Think this guide should explain how to use the Client API and how to make a table-plugin. Database API guide INDEX 1 Introduction 2 Client API 2.1 Client API layers 2.1.1 Object API 2.1.2 gsqldb API 2.1.3 Primitive API 3.1 API example with a simple client 3.1.1 Include files and definitions A Packet layout B MemberRecord C Code documentation C.1 Loading a table filtered 2.1 Client API layers Here is a brief overview description of how the Client API is structured. Here are the layers currently in used and planned. 1 Object 2 g_sqldb 3 primitive 2.1.1 Object API This section ( 2.1.1 ) talks about the Object API usage. 2.1.1.1 Object API introduction This is the API one should use to "talk object oriented" with the database. The object API layer is based on the code found in the DB_* files. API functions has a prefix of 'gxobject_', here is those functions that are defined today: gxobject_db_create ( Type_of_object ) gxobject_db_destroy ( gxobject * ) gxobject_db_add ( gxobject * ) gxobject_db_update ( gxobject * ) gxobject_db_delete ( gxobject * ) gxobject_db_find ( gxobject * ) gxobject_db_load ( gxobject * ) These functions operate on object structures. Mainly what is done here is that when you call gxobject_db_add() for example it will dispatch to the table-plugin and call a function that is equal to the old DB_ files. For example, if the code used to call host_add. Then if we setup a object, and call gxobject_db_add(), we should be executing same lines of code in the plugin that host_add() had. Here is how the object structures look like: First we have a context structure that is to be used with database objects. typedef struct _gxobject_ctx { gint type; /* type of table to use (same as name of table) */ gint sock; /* socket to use if we contact database daemon */ gxdb_tables tables; /* pointer to all tables loaded in memory */ gpointer user; /* various information held here, filter etc.. */ } gxobject_ctx; This is the gxobject structure typedef struct _gxobject { gint objnum; /* unique object number */ gint type; /* type of object */ gpointer ctx; /* additional context information */ gpointer obj; /* object */ } gxobject; The purpose of the gxobject_ctx structure is to provide additional information along with the object. For example the database must have socket, and table information to act on a object. 2.1.1.2 Object API Filter capability The Object API uses a general filter struct to do filtering, that was previous made by alot of functions. Therefor setting up a filter takes more code now, and the code should have predefined filters. These are found in database/lib/db_filters.c The function gxobject_db_find() and gxobject_db_load functions currently supports the filter capability. Goal is to make the filter a general capability. Here is the structures used by the filter function. typedef enum { OBJ_FIND_MULTI = 1, OBJ_FIND_SINGLE } GxSNMP_OBJECT_FILTER; typedef struct _gxobject_db_filter { gint method; /* match method */ gchar **args; /* a setup of filters */ } gxobject_db_filter; Here is a example of how to setup and perform filtering: The original code did: dialog->selected_interface = interface_find_by_rowid (rowid); Here is the equal code, setting up the filter manually: gxobject gxobj; gxobject_ctx gxctx; gxobject_db_filter gxfilter; gint xa,xb; void *arg[4]; gxobj.ctx = &gxctx; // address to context information gxctx.type = OBJ_DB_INTERFACE; // its a INTERFACE object gxctx.user = &gxfilter; // address to filter gxfilter.method = OBJ_FIND_SINGLE; // find ONE match gxfilter.args = &arg; // address to filter array xa = OBJ_DB_TABLE_INTERFACE_ROWID; // ROWID field in interface table xb = rowid; // should match with 'rowid' var. arg[0] = &xa; arg[1] = &xb; arg[2] = 0; // null terminate array dialog->selected_interface = gxobject_db_find(&gxobj); Here is a example using a predefined filter: gxobj.ctx = &gxctx; gxctx.type = OBJ_DB_INTERFACE; gxctx.user = &db_find_by_rowid; /* pointer filter to the predefined filter */ Here we put new data, that will be searched for. *((gint *) db_find_by_rowid.args[0]) = OBJ_DB_TABLE_INTERFACE_ROWID; /*set table to use */ *((gint *) db_find_by_rowid.args[1]) = rowid; /* rowid in table to search for */ dialog->selected_interface = gxobject_db_find(&gxobj); 2.1.2 gsqldb API This is the API that should be nearly compatible with the g_sqldb functions. API functions has a prefix of 'g_sqldb_'. 2.1.3 Primitive API This has not been implemented. It should be a simple interface to provide database access. 3.1 API example with a simple client This section gives an example of how to use the Client API. 3.1.1 Include files and definitions The client application needs to include following files: #include #include #include "debug.h" #include "gxsnmpdbc.h" #include "gxsnmpdb.h" #include "db_filters.h" Following needs to be defined: extern gxdb_tables db_tables; int debug_level; int dcsock; gchar packet[4000]; gchar bufx[4000]; Order of execution. The application must execute following block in order. Each step is explained with example code. Load configuration Load table-plugins Start table-plugins Connect to database daemon. User code with Client API Disconnect to database daemon. Appendix A Packet layout Packet layout defines how the client API and the database daemon should exchange information. All information exchanged has a common packet layout. +-------+------+-------+---+------------+-----+ |Action |Objlen|Objects|TPL|MemberRecord| ... | +-------+------+-------+---+------------+-----+ <--- Header ----> Fig. An example of a packet to add a row in the 'host' table. First is the Header, that has a maximum size of 40 bytes. TAR is the command to add a row into a table. Objects is data. TPL is total packet length. MemberRecord is each field in the table. Appendix B MemberRecord The MemberRecord is how the client API and the database daemon exchange data. This data is actually SQL field data that is inserted or processed into structures etc.. This is how a MemberRecord looks like: +----------+------------+------------+ |MemberLen | MemberType | MemberData | +----------+------------+------------+ MemberLen is how long the whole MemberRecord is. MemberType identifies what type of data is containd in MemberData. Currently we have defined 32bit integer and ASCIIZ. Appendix C Code documentation This section will describe how the code under gxsnmp/database works C.1 Loading a table filtered The gxobject_load() function ( under dev ) will load a whole table into memory. If the contexts user pointer ( ctx->user ) is set to a filter, this filter will be used when loading. Here is a short description of how it works: gxobject_load() will lookup the right table plugin to use and calls the obj_load() function in the plugin. obj_load() checks if a filter is set. If that is true, it will convert the filter into memberrecords, with a packet header of TABLE_LOAD_FILTERED. Now it can send the packet to the database daemon. The DD will in turn call the same plugin to encode a proper SQL string, to send to the database. This is done with encode_sql function in plugin, with SQL_SELECT switch.