next up previous external
Next: Manual page for mkfdf. Up: WDB Installation and Users Previous: How to use WDB

Porting WDB to other database systems

With WDB 1.2 the Sybase specific code has been isolated into a separate Database interface package (DBI). This should make it relatively easy to port WDB to other databases like Oracle, Informix, Ingres etc. (Any database which supports standard SQL and has a Perl interface).

Currently there are interfaces to Sybase, Informix, Oracle and mSQL (a public domain database). If you want to use WDB with another database system the first thing you have to do is to get a perl interface to it. Several of these are available on the Internet. If you can't find a ready interface you have to write one your self. That's a bit more tricky, but you can always cheat and only include the few commands that WDB needs to run ( open connection, query, fetch next row, close connection). The Perl Meta-FAQ lists where you can find the perl source for various versions and also the database interfaces etc. . The Meta-FAQ is available from :

http://www.khoros.unm.edu/staff/neilb/perl/metaFAQ/metaFAQ.html

A collection of pointers to Perl reference material in general are available at :

http://www.eecs.nwu.edu/perl/perl.html

Another important factor when porting WDB to another database is of course the SQL used. Each database system seems to implement it's own flavor of SQL, but fortunately the only SQL command that WDB sends directly to the DBI is a select statement. The select statement used by wdb has the following format :

select column field, column field, ... from table where where-list and constraints and join order by order

column
is the value of the column attribute in the FDF. It is inserted literally in the select statement without any parsing in WDB, so computations etc. supported by the database can be used in the FDF.

field
is the value of the FIELD attribute in the FDF. This is used as the label in the select, as the dbi_nextrow function should return the rows as an associative array keyed on this value. Not all databases support this notation, so a second mechanism is also supported. See below ...

table
is this is the value of the TABLE attribute in the FDF. It can contain one or more table names separated by commas.

where-list
is a list of search conditions composed by WDB from the input fields in the query form. The conditions of each field is and'ed together, and the standard operators <=, >=, !=, <, >, = and like are used.

constraints
is the value of the CONSTRAINTS attribute in the FDF.

join
is the value of the JOIN attribute in the FDF.

order
is the value of the ORDER attribute in the FDF.

If your database does not support the column field notation described above, an alternative notation is supported. Rather than specifying the field names as column labels in the select list they can be send separately to the DBI via a function called dbi_fieldnames. WDB automatically detects if such a function is defined in the DBI and uses this second notation. See the msql_dbi.pl file for an example of its use.

To give you an idea of what it takes to write a DBI file I have included the Informix DBI file below. As you can see it is simply an encapsulation of the DBD::Informix functions.

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#.IDENTIFICATION  informix_dbi.pl
#.LANGUAGE	  DBD::Informix script
#
#.PURPOSE	  Database Interface to Informix.
#
#		  &dbi_connect( $user, $pswd, $server, $database, \$dbproc );
#		  &dbi_dosql( $dbproc, \$sth, "... SQL commands ...");
#		  %row = &dbi_nextrow( $sth, @titles );
#                 &dbi_countrows( $dbproc, $sth, "... SQL commands ..." );
#		  &dbi_disconnect( $dbproc, \$sth );
#
#.AUTHOR	  Informix version Curtis Wong 
#.AUTHOR	  Bo Frese Rasmussen [ST-ECF]   
#.AUTHOR     DBD::Informix/mod_perl version, Jeff Rowe 
#
#.VERSION	1.0	22/12-1994     Creation
#			16/01-1995     Informix version -ckw
#			10/02-1995     make change suggested by Bo
#               1.1     26/11-1996     Changed to use DBD::Informix and mod_perl
#------------------------------------------------------------------------------	
use strict;
use DBI;
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#.PURPOSE	Connects to a database.
#
#.REMARKS	This function must be called before any of the other functions
#		in this package.
#		It logs in to the given database server and connects to a
#		database.
#               $dbproc MUST be passed in by reference, i.e.:
#               &dbi_connect( $user, $pswd, $server, $database, \$db_query);
#
#.RETURNS	Dies on error !
#------------------------------------------------------------------------------
sub dbi_connect
{
    my( $user, $pswd, $server, $database, $dbproc ) = @_;
    my( $drh );

    ( $drh = DBI->install_driver( 'Informix' ) )
      or die "Cannot install database driver: $DBI::errstr\n";

    ( $$dbproc = $drh->connect( $database, 'dbuser', 'dbpass' ) )
      or die "Cannot connect to database: $DBI::errstr\n";

}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#.PURPOSE	Prepares and executes an SQL statement, with error check etc.
#
#.REMARKS	Dies on error !
#
#.RETURNS	An Informix statement handle
#------------------------------------------------------------------------------
sub dbi_dosql 
{
    my($dbproc, $sth, $sql) = @_;

    $$sth = $dbproc->prepare($sql);
    if ( !defined $$sth ) { die "Cannot prepare handle: $DBI::errstr\n"; }

    $$sth->execute;
}

# KEEP THIS SUBROUTINE!  Nothing will work without it, trust me.
sub dbi_fieldnames
{
}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#.PURPOSE	Gets the next row from a previous select (dbi_dosql).
#
#.REMARKS	After a dbi_dosql("select ... ") call, this function can be 
#		called repeatetly to retrieve all rows of the query.
#
#		Example :
#			&dbi_dosql("select * from mytab");
#			while( %row = &dbi_nextrow  ) {
#			    print $row{'columnname'};
#			    ...
#			}
#
#.RETURNS	An associative array (keyed on the column name) of formatted 
#		data, based on the datatype of the corresponding columns.
#               Return the empty list if the fetch failed.
#------------------------------------------------------------------------------
sub dbi_nextrow
{
    my($sth, @titles) = @_;
    my(@trow,$i,%row);

    if (@trow = $sth->fetchrow) { #found a row of data
    	for ( $i = 0 ; $i <= $#titles; ++$i) {
 	   $row{$titles[$i]} = $trow[$i];
      	}
     } else {
	%row = ();     
     }
     return %row;
}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#
#.PURPOSE	Returns a count of records returned by a SQL statement.
#
#.REMARKS	Requires a SQL statement in the form:
#               "select count(*) from tablename where where_clause"
#
#.RETURNS	A number
#------------------------------------------------------------------------------
sub dbi_countrows
{
    my($dbproc, $sth, $sql) = @_;
    my($ch, @titles, %count_result);

    &dbi_dosql($dbproc, \$ch, $sql);
    push(@titles, "(count(*))");
    %count_result = &dbi_nextrow($ch, @titles);
    $ch->finish;
    undef $ch;
    return $count_result{'(count(*))'};
}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#
#.PURPOSE	Disconnects the current database connection
#
#.REMARKS	After this function is called there are no current database 
#		connection => no other function from this package can be 
#		called before a new dbi_connect call.
#
#.RETURNS	nothing.
#------------------------------------------------------------------------------
sub dbi_disconnect
{
   my($dbproc, $sth) = @_;

   if ($$sth) {
      $$sth->finish;
      undef $$sth;
   }
   if ($dbproc) {
      $dbproc->disconnect;
   }
}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#.PURPOSE       Gets the next serial key value for a particular table.
#
#.REMARKS       This is a suggested way of generating serial key values.
#
#               Requires a table named serial_keys, and an entry in that table
#               for each table that has a serial key value.  The value in the
#               table is retrieved, incremented by one, and the new value is
#               inserted into the serial_keys table.
#                 Table : serial_keys
#                 Fields: table_name, key_value
#               NOTE: This is only necessary for mSQL.  For Informix, just
#               return a 0, as Informix takes care of its own serial keys.
#               Sybase 4.9.x might need this method also.  Dunno about Oracle.
#
#.RETURNS       The serial key value.
#------------------------------------------------------------------------------
sub dbi_getnextserialkey
{
   return 0;
}

1;


next up previous external
Next: Manual page for mkfdf. Up: WDB Installation and Users Previous: How to use WDB

Copyright © 1996 Bo Frese Rasmussen