GxSNMP Database documentation hello GxSNMP Database introduction This is a introduction to use the virtual database system. An application utilizes the database engine client API. It sets up a connection to a database daemon server, that handles connection between applications and databases. An application can have database tables located at several databases, by having several connections to database daemon servers. All this is determined at connection time and stored in a table_data_storage structures. So we have: Application connection setup GxSNMP Native API GxSNMP CORBA API Database daemon server Table_data_storage Application connection setup The application must first setup a connection to a running database daemon server. See the examples of how to setup this connection. API Various interfaces to access the database. Read more about this in . Read more about this in . Database daemon server A database daemon handles data between a database and several clients. The daemon can only handle one database vendor at a time. Although the client can connect to several database daemons. Table_data_storage This is a structure that is used by the API and stores information about, table records loaded filter information, connection descriptor and more. Read more about this structure in Database data types. GxSNMP Database data types Description These database types is used by the database engine, and here we describe what the user must setup, before utilizing the engine, and how data is presented. Globals To the user there is no known globals :-) The database client API itself uses a few globals internally. Therefor the library isn't thread safe. typedef G_sqldb_table This is mainly a data storage for a database table, along with connection related information. typedef struct _G_sqldb_table { G_sql * engine; /* SQL engine structure */ gchar ** database; /* Name of the SQL database */ gchar * name; /* Name of the SQL table */ gint type; /* unused */ gint sock; /* Database daemon server socket */ gpointer filter; /* load/find filter to use */ gint row_length; /* Size of each row in bytes */ gint row_private; /* Offset in row to gpointer for use by library only */ G_sqldb_column * columns; /* Pointer to column array */ struct _G_sqldb_table_private * private; /* For use by library only */ } G_sqldb_table; Example: static G_sqldb_table snmp_db_struct = { 0, /* Pointer to G_sql structure */ 0, /* Pointer to database name */ "snmp", /* Pointer to table name */ 0, my_socket_to_ddserver, /* connection descriptor to gxdd */ 0, sizeof (DB_snmp), /* Length of a row in bytes */ G_STRUCT_OFFSET (DB_snmp, g_sqldb_private), /* Offset of private hndl */ 0 /* List of column definitions */ }; G_sqldb_table * snmp_sqldb = & snmp_db_struct; In this example We set up a G_sqldb_table that holds loaded table data. Use the Client API call g_sqldb_table_load () to load this structure with table data. Notification callback function This function is passed all information in a notification. void (* func)(GIOChannel *channel, gint type, /* Type of notification */ guint rowid, /* database row number */ gchar *table, /* database table name */ gpointer data); /* Notification data */ Notification Types: typedef enum { DB_NOTIF_TABLE_CHANGED = 1, /* db-table has changed */ DB_NOTIF_TABLE_FIELD_CHANGED, /* db-field has changed */ DB_NOTIF_TABLE_RECORD_CHANGED /* db-record has changed */ } DB_Notification_Types; GxSNMP Database Native API reference #include "dbapi.h" gint db_server_connect_config (gchar *host, gint port) gint db_server_connect (gchar *host, gint port) gint db_server_disconnect (gchar *host, gint port) gint g_sqldb_dbctl (G_sqldb_table *sqldb, gint value) gboolean g_sqldb_table_load (G_sqldb_table *sqldb) gboolean g_sqldb_table_list (G_sqldb_table *sqldb) gboolean g_sqldb_row_add (G_sqldb_table *sqldb, gpointer row) gboolean g_sqldb_row_delete (G_sqldb_table *sqldb, gpointer row) gpointer g_sqldb_row_find (G_sqldb_table *sqldb, gpointer row, gchar *field, gpointer keyp) gboolean g_sqldb_reload_row (G_sqldb_table *sqldb, gpointer row) gint g_sqldb_highest_rowid (G_sqldb_table *sqldb, gchar *field) gint g_sqldb_table_cb (G_sqldb_table *sqldb, gpointer row, G_sqldb_cb_type type, G_sqldb_cb func, gpointer data) gpointer db_create_row (gchar *tablename) gint db_destroy_row (gchar *tablename, gpointer row) GList db_load_table (G_sqldb_table *sqldb) GList db_find_rows (G_sqldb_table *sqldb) gint db_filter_setup (db_filter *filter, gchar *name, guint method) gint db_filter_add (db_filter *filter, gchar *name, gpointer value) gint db_filter_modify (db_filter *filter, gchar *field, gpointer value) gint db_filter_del (db_filter *filter, gchar *field) void db_notification_add (gpointer func) void db_notification_del (gpointer func) Description Client API is used by the application to store and utilize data in a database. The functions operate on database tables and records. A database table is loaded into memory where application can use it. Then updates is sent to memory and database. Details hello db_server_connect_config () gint db_server_connect_config (gchar *host, gint port) Before the database API is ready for use, one must learn the API about database table it will use, this is done by calling for a Master table, that has information about all database tables used in the Virtual Database System. The Master table is located at host at TCP port . host: machine running a DB daemon serving the Master table. port: TCP port DB daemon is listening to. returns: Socket of connection to DB daemon. db_server_connect () gint db_server_connect (gchar *host, gint port) After the Master table has been loaded, one can start connecting to other DB daemons serving other tables, that has been described in the Master table. If the DB daemon serving the Master table, also serves those table, there is no need to call this function. host: machine running a DB daemon serving the Master table. port: TCP port DB daemon is listening to. returns: Socket of connection to DB daemon. db_server_disconnect () gint db_server_disconnect (gint port) Disconnecting to a DB daemon. sock: Connection descriptor to a DB daemon. returns: NULL if successful. g_sqldb_dbctl () gint g_sqldb_dbctl (G_sqldb_table * sqldb, gint value) Change connection parameters of a database server daemon connection. /* This will set the connection with full notification, autorized, and read/write access */ gint value = DBCTL_NOTIFY_FULL | DBCTL_AUTH | DBCTL_RW; g_sqldb_dbctl (sqldb, value); sqldb: Table information with connection descriptor. value: the value to apply to this connection. returns: TRUE if successful. g_sqldb_table_load () gboolean g_sqldb_table_load (G_sqldb_table * sqldb) Load a database table into memory GList *gl; DB_host row; /* structure of a record */ g_sqldb_table_load (host_sqldb); gl = g_sqldb_table_list (host_sqldb); while(gl){ /* traverse whole table */ row = gl->data; /* use row data */ gl = gl->next; } table: data storage. returns: TRUE if successful. g_sqldb_table_list () GList * g_sqldb_table_list (G_sqldb_table * sqldb) Get table records from a database table previously loaded. table: data storage. returns: GList of database rows. g_sqldb_row_add () gboolean g_sqldb_row_add (G_sqldb_table * sqldb, gpointer row) Add a database record into database and memory. table: data storage. row: database table record. returns: TRUE if successful. g_sqldb_row_update () gboolean g_sqldb_row_update (G_sqldb_table * sqldb, gpointer row) Update a database record in both memory and database. table: data storage. row: database table record. returns: TRUE if successful. g_sqldb_row_delete () gboolean g_sqldb_row_delete (G_sqldb_table * sqldb, gpointer row) Delete a record from database and memory. table: data storage. row: database table record. returns: TRUE if successful. g_sqldb_row_find () gpointer g_sqldb_row_find (G_sqldb_table * sqldb, gchar *field, gpointer keyp) Find a record in memory loaded database table. EXAMPLE NEEDED ! table: data storage. field: database field name. keyp: pointer to a rowid of a record. returns: TRUE if successful. g_sqldb_row_reload () gboolean g_sqldb_row_reload (G_sqldb_table * sqldb, gpointer row) Reload a single record in memory from a database table. table: data storage. row: database record. returns: TRUE if successful. g_sqldb_highest_rowid () gint g_sqldb_highest_rowid (G_sqldb_table * sqldb, gchar *field) Find highest ROWID in memory loaded database table. table: data storage. field: database field name. returns: TRUE if successful. g_sqldb_table_cb_add() gint g_sqldb_table_cb_add (G_sqldb_table *sqldb, gpointer row, G_sqldb_cb_type type, G_sqldb_cb func, gpointer data) Find highest ROWID in memory loaded database table. table: data storage. row: database record. type: callback type. func: callback function. data: callback data. returns: TRUE if successful. db_create_row () gpointer db_create_row (gchar *tablename) Allocate memory to hold a structure that corresponds to the size of the record identified by tablename. It will also setup initial parameters if possible. DB_host *dbh; dbh = db_create_row("host"); /* table name is used to identify record type*/ printf("%s", dbh->created); printf("%s", dbh->modified); tablename: type of record to create. returns: Object created. db_destroy_row() gint db_destroy_row (gpointer row) Destroys as much as possible of an record, prior to user application freeing it. Using record descriptors we know what fields is possible to free and what is not. row: record to destroy. returns: TRUE if destroyed. db_load_table () GList db_load_table (G_sqldb_table *table) Is used to load a table from the database to memory. A filter can be used to select specific records. The function returns a GList of records. table: data storage. returns: TRUE if destroyed. db_find_rows () GList db_find_rows (G_sqldb_table *table) Sqldb contains a loaded database table, and using db_find_rows() we can use a filter to sort out specific rows in this table. The function returns a GList of records. DB_host *dbhp; host_sqldb->sock = socket_to_gxddserver; /* Set socket in our G_sqldb_table */ g_sqldb_table_load(host_sqldb); /* load in table in our G_sqldb_table */ /* setup filter */ host_sqldb->filter = & filter; db_filter_setup(& filter, "host", OBJ_FIND_SINGLE); /* "host" is tablename */ db_filter_add(& filter, "name", "my-unix-machine"); /* "name" is fieldname, "my-unix-machine" is the fieldvalue to search for in fieldname */ gl = db_find_rows(host_sqldb); /* make the search */ if(!gl){ fprintf(stderr,"Nothing passed through the filter.\n"); } else while(gl){ fprintf(stderr, "going though GList pointer\n"); dbhp = gl->data; printf("created: %s\n", dbhp->created); printf("modified: %s\n", dbhp->modified); printf("dns_name: %s\n", dbhp->dns_name); printf("name: %s\n", dbhp->name); printf("description: %s\n", dbhp->description); gl = gl->next; } table: data storage ( previously loaded). returns: GList of records matching filter. db_filter_setup () gint db_filter_setup (db_filter *filter, gchar *name, guint method) Initialize a filter. filter: filter to initialize. name: tablename this filter is used for. method: search method. returns: TRUE if successful. db_filter_add () gint db_filter_add (db_filter *filter, gchar *field, gpointer value) Add a search entry in the filter. /* setup filter */ host_sqldb->filter = & filter; db_filter_setup(& filter, "host", OBJ_FIND_SINGLE); /* "host" is tablename */ db_filter_add(& filter, "name", "my-unix-machine"); /* "name" is fieldname, "my-unix-machine" is the fieldvalue to search for in fieldname */ filter: filter to add entry in. field: database fieldname. value: value to search for in fieldname. returns: TRUE if successful. db_filter_modify () gint db_filter_modify (db_filter *filter, gchar *field, gpointer value) modify a search entry in the filter. host_sqldb->filter = & filter; db_filter_setup(& filter, "host", OBJ_FIND_SINGLE); /* "host" is tablename */ db_filter_add(& filter, "name", "my-unix-machine"); /* "name" is fieldname, "my-unix-machine" is the fieldvalue to search for in fieldname */ db_filter_modify(& filter, "name", "my-unix-host"); filter: filter to modify entry in. field: database fieldname filter entry to modify. value: value to modify in fieldname. returns: TRUE if successful. db_filter_del () gint db_filter_del (db_filter *filter, gchar *field) delete a search entry in the filter. /* setup filter */ host_sqldb->filter = & filter; db_filter_setup(& filter, "host", OBJ_FIND_SINGLE); /* "host" is tablename */ db_filter_add(& filter, "name", "my-unix-machine"); /* "name" is fieldname, "my-unix-machine" is the fieldvalue to search for in fieldname */ db_filter_modify(& filter, "name", "my-unix-host"); db_filter_delete(& filter, "name"); filter: filter to delete entry in. field: fieldname entry to delete. returns: TRUE if successful. db_notification_add () void db_notification_add (gpointer func) Registers a function that will be called each time we receive a notification. static void notification_cb(GIOChannel *channel,gint type,guint rowid, gchar *table,gpointer data); /*** Database notification callback ***/ static void notification_cb (GIOChannel *channel, gint type, guint rowid, gchar *table, gpointer data) { DB_interface * dbi; DB_host * dbh; gchar * oldtag; dbi = g_sqldb_row_find(interface_sqldb, "_rowid", &rowid); if(dbi){ oldtag = g_strdup(dbi->tags); g_sqldb_reload_row(interface_sqldb, dbi); dbi = g_sqldb_row_find(interface_sqldb, "_rowid", &rowid); dbh = g_sqldb_row_find(host_sqldb, "_rowid", &dbi->host); if(dbi && dbh) fprintf(stderr,"Host %s, Interface %s(%s) is %s\n", dbh->name, dbi->name, dbi->address, dbi->tags); } } gint main (int argc, char *argv[]) { /* start the Virtual Database System */ ddchannel = db_server_connect_config ("127.0.0.1", 4000); /* Register a notificatoin callback */ db_notification_add (notification_cb); gtk_main(); } func: Callback function to register. returns: db_notification_del () void db_notification_del (gpointer func) Removes a previous registered notification callback function. func: Callback function to unregister. returns: GxSNMP Database CORBA interface reference void TableOpen (in GSQLDBTable table) void TableClose (in GSQLDBTable table) RowHost GetRowHost () RowInterface GetRowInterface () Description The CORBA interface is not yet defined. Details module GxSNMP { interface GSQLDB { struct GSQLDBTable { string table; }; struct RowHost { long objid; string created; string modified; string dnsname; string name; string description; string contact; string tags; }; struct RowInterface { long objid; string created; string modified; long host; long snmp; long transport; string address; string netmask; string name; string tags; }; struct RowMap { long objid; string created; string modified; string name; string tab; string description; string tags; }; struct RowGraph { long objid; string created; string modified; long map; long type; long host; long network; string details; long x; long y; string pixmap; string tags; }; void TableOpen (in GSQLDBTable table); void TableClose (in GSQLDBTable table); RowHost GetRowHost (); RowInterface GetRowInterface (); RowMap GetRowMap (); RowGraph GetRowGraph (); }; }; GxSNMP Database tutorial This example will show how to use the API in the simplest of ways. Please read the for reference. Step by step A walkthrough of what happens in this example. First call TableOpen on our database table. This is also a client init for the database server. Now we call a GetRow function, that returns a pointer to a row in our database table. The layout of the memory is specified in the IDL file. Done, call TableClose to tell database server we are done. Lets look at our first example. The point in this example is to show that we are only dependent on the IDL interface, to be able to communicate to the database server. #include "gnome.h" #include "orb/orbit.h" #include "liboaf/liboaf.h" #include "orbit-gxsnmp-db.h" int main (int argc, char **argv) { CORBA_Environment ev; CORBA_ORB orb; GxSNMP_GSQLDB gsqldbclient; GxSNMP_GSQLDB_GSQLDBTable *table; GxSNMP_GSQLDB_RowHost *host; gchar *query; CORBA_exception_init (& ev); orb = oaf_init(argc,argv); query = g_strdup("repo_ids.has ('IDL:GxSNMP/DB:1.0')"); gsqldbclient = oaf_activate (query, NULL, 0, NULL, & ev); g_free(query); if(gsqldbclient == CORBA_OBJECT_NIL) { g_print("cannot bind to object\n"); exit(-1); } table = GxSNMP_GSQLDB_GSQLDBTable__alloc(); table->table = CORBA_string_dup("host"); GxSNMP_GSQLDB_TableOpen (gsqldbclient, table, & ev); while((host = GxSNMP_GSQLDB_GetRowHost (gsqldbclient, & ev))){ if(ev._major != CORBA_NO_EXCEPTION) break; printf("objid: %d\n", host->objid); printf("created: %s\n", host->created); printf("modified: %s\n", host->modified); printf("dnsname: %s\n", host->dnsname); printf("name: %s\n", host->name); printf("description: %s\n", host->description); printf("contact: %s\n", host->contact); printf("tags: %s\n\n", host->tags); CORBA_free(host); } GxSNMP_GSQLDB_TableClose (gsqldbclient, table, & ev); CORBA_free(table); CORBA_exception_free (& ev); exit(0); } The example first locates our object ( which is the database CORBA interface ). It is located using a local OAF daemon. We ask for a interface that supports the 'IDL:GxSNMP/DB:1.0' interface. Native API simplest example This example will show how to use the Native API in the simplest of ways. Please read the for reference. #include "dbapi.h" #include "gxsnmp/gxsnmp_dbapi.h" int main (int argc, char **argv) { DB_host *row; GList *gl; /* start the Virtual Database System */ dcsock = db_server_connect_config ("127.0.0.1", 4000); host_sqldb->sock = dcsock; g_sqldb_table_load (host_sqldb); gl = g_sqldb_table_list(host_sqldb); while(gl){ row = gl->data; printf("name: %s\n", row->dns_name); } /* please notice we doesn't do any memory cleanup */ } Database daemon internals Here is a overview of the internals of the database daemon. It is the "design".
gxdd
What follows is a discussion of the internal components of the database daemon. The picture is a conceptual view of the actual process running. Each square represents a code block, that consist of a few source files. SQL-plugin. A vendor native interface between the database and the g_sql-api. EXAMPLE plugins/mysql/mysql_backend.c. g_sql-api. This is a generic api over the SQL-plugin. lib/g_sql.c. Request processor. Executes client requests from the reqlist. server/queue.c. Reqlist. A list of pending requests. server/main.c:GList *tranq. Connection handler. Handles connection to clients. server/tcp_services.c. Corba skel. This is a corba implementation to enable corba users. server/impl-host.c, server/impl-host.c. Encode/Decode, Table Descriptor. These to is a group of functions on both the server and the client side. The Encode/Decode is used to translate between C structures, encapsulated pdus and with help of the g_sql-api; native SQL structures. The Table Descriptor is a group of functions that has to be initialized with data that describes each table that the database engine is going to use. lib/table-common.c. lib/pdu.c.
Client side internals Here is a overview of the internals of the APIs that the client uses.
client
What follows is a discussion of the internal components of the Client APIs. The picture is a conceptual view of the actual process running. Each square represents a code block, that consist of a few source files. I/O. The I/O transmit and receives data to/from the database engine. It is also the API how the clients connect. lib/ddclient.c. g_sqldb-api. This is a API that load data into memory, sends data to the daemon. It also handles notification. lib/g_sqldb.c. db-api. The db-api uses the g_sqldb-api and adds some own APIs. It can be used to load into memory using a table filter, or copy from memory to memory using a table filter. lib/object.c. GxSNMP Addon API. Convenient functions that uses the g_sqldb-api and the db-api to load a bulk of tables, setup internal pointers, ie, private pointers that the VDS doesn't know how to use. It also setups predefined filter. The GxSNMP Addon API, can be modified to fit another type of application, if the VDS ever would be used outside GxSNMP. lib/gxsnmp_*. include/gxsnmp/*. Encode/Decode, Table Descriptor. Please see the Database daemon internals for info. The client side initializes the Table descriptors by calling db_server_connect_config ().