![]() [ DBI ] |
DBI - A Database Interface for perl5Alligator Descartes
Abstract:DBI, the Database Interface for perl5, is an ongoing effort to design and implement a database-independent interface for database connectivity which abstracts the complexity of understanding the low-level 'guts' of database technologies away from the programmer. With the explosion in popularity of perl as the de rigeur language for CGI programming, a simple, and standard, connection interface to databases is imperative.
The Architecture of DBI
The architecture of DBI is an elegant one. By the very concept of the interface
that we are trying to define, we are channelled towards the solution. However,
perl, as usual, helps us along the way by providing powerful syntactic
constructs and regular expression handling capabilities that are core to the
usability and simplicity of data processing on the scale required by large
database applications. The DBI interface is the term used to describe both the interface specification, ie, the methods with which we write programs and the software modules that comprise the system. We shall firstly take a look at why you should be using DBI, then describe the modular structure of DBI and its interaction with perl. We finally present an example application using DBI. Why DBI?
Database IndependenceDatabase programming, as you will learn after you've programmed and / or administrated a few different ones, is pretty much-of-a-muchness. Hence, DBI. The fundamental processes involved in doing anything with a database are pretty similar right across the board. The typical order in which this happens is:
Now, assuming we've fetched some data from the database, what next? Well, the good news is that DBI fetches data back into scalar variables Another extremely useful thing that can be acheived with DBI is to connect to more than one database simultaneously from within the same perl program, even, dare we say it, to databases of separate vendor types, eg, you can connect to an Oracle and an mSQL and an Informix database simultaneously from within one script. ``What's the point in that?'', I hear you cry. Well, say you have a corporate Oracle database that you want to publish some cut-down data from on the WWW Option number 1 is to write a program that runs SQL scripts and dumps the data to a flat file, say, comma-separated, which another program then reads and loads into the mSQL database. This is really stupid. Option number 2 is to write a single perl script that connects simultaneously to both the Oracle and the mSQL databases, reads the data from Oracle, and puts it into mSQL...transparently. Change Oracle to Informix and you won't need to alter a thing. Think on that the next time you're writing two separate programs in C DBI is a current and living organism and, coupled with perl's current popularity as a CGI scripting language and rapid development tool, is set to become a more important factor in decisions to use perl as a ``serious'' programming language. Similarities have been drawn between DBI and ODBC Databases vs. dbmDatabases, be they Object DataBase Management Systems ( ODBMS ) or the more common Relational DataBase Management Systems ( RDBMS ) are engineered to store and retrieve data. That's their prime purpose. UNIX was originally blessed with simple file-based ``databases'', namely the dbm or DataBase Manager system. This system provided a capability to store data in files, and retrieve that data quickly. However, this system also had several notable drawbacks:
The Modules
perl5 has a powerful mechanism to 'plug' external modules into the perl
interpreter. This mechanism is realised by actually compiling and linking the
module into the perl interpreter, or by Dynaloading, or dynamically
loading, the module into a running interpreter as and when it is required.
This system of plugging modules in is core to the philosophy of both perl
and DBI. #!/usr/bin/perl -w
use DBI;
And that's it! Honest. If you don't believe me, try this $ PERL_DL_DEBUG=255 perl -e 'use DBI;'
DynaLoader.pm loaded (/usr/local/lib/perl5/i486-linux/5.003 /usr/local/lib/perl5
/usr/local/lib/perl5/site_perl/i486-linux /usr/local/lib/perl5/site_perl .
/usr/local/lib /usr/local/lib /lib /usr/lib)
DynaLoader::bootstrap for DBI (auto/DBI/DBI.so)
See. That simple statement has Dynaloaded the shared library containing the
DBI code into the interpreter, and it has also imported the DBI interface
methods, which means we can now start using DBI in anger.If you refer back to the Architecture diagram in Figure 1, you can clearly see that all access to the databases are marshalled, or funnelled, through the DBI module. Therefore, we need to make perl aware of our DBDs. and to do this, we need to use DBI. There are two ways to load drivers with DBI. One is the proper way to do it, the other is the naughty, unsupported way to do it. The supported, clever and ``Don't annoy Tim Bunce #!/usr/bin/perl -w
use DBI;
$dbh = DBI->connect( 'connection_string', 'username', 'password', 'mSQL' );
if ( !defined $dbh ) {
die "Cannot do \$dbh->connect: $DBI::errstr\n";
}
which will load the DBI driver, then load the mSQL driver and attempt a database
connection to the specified mSQL database. This call returns a database
handle, which we shall see more of later. To use this method for other
DBDs, simply change the 4 The second, sneaky and ``Don't tell Tim'' method is to use an internal method to DBI called install_driver(), which explicitly loads the driver and returns what is called a driver handle. For example: #!/usr/bin/perl -w
use DBI;
$drh = DBI->install_driver( 'mSQL' );
if ( !defined $drh ) {
die "Cannot load driver: $!\n";
}
This technique is quite useful for checking whether or not your version of
perl has various drivers installed when you don't actually want to attempt a
database connection. However, as I said, don't tell Tim.
Handles
Handles are perl objects returned by various DBI methods which the programmer can use to access data at various abstracted layers. The handles that are used by DBI are as follows and can be seen in Figure 2:
Emulation Layers
Some of the most commonly asked questions on the comp.lang.perl.*
newsgroups and DBI mailing lists are ``I can't get oraperl to compile for perl5.
It only seems to work with perl4. What do I do?'' and ``I've got all this
Oraperl/Ingperl/isqlperl stuff and I want to upgrade to DBI, but I don't
want to recode it all. What can I do?'' ResourcesSeveral resources dedicated to DBI are available on the via the World Wide Web, anonymous ftp and mailing lists. DBI Mailing ListsThe mailing lists related to DBI are run excellently by Ted Mellon. There are three lists to date, being dbi-users, for general chit-chat and support, dbi-dev, for developers to discuss ideas and dbi-announce, for announcements of new driver releases and so on. To join these lists, please see the URL: http://www.fugue.com/dbiand use the forms there. To join the mailing list via email, please see the Frequently Asked Questions. DBI WWW PagesThe DBI WWW pages are located at: http://www.arcana.co.uk/technologia/perl/DBIand should be consulted at all opportunities. The Frequently Asked Questions, DBI Specification and pointers to documentation sources including the mailing list archives are here, amongst other things. DBI ftpThe DBI modules and drivers are available via anonymous ftp from: ftp://ftp.demon.co.uk/pub/perl/dbThe modules are also available via the WWW pages through CPAN, which may be reached via http://www.perl.com/CPAN/ Example CodeWe now present some simple example code using the DBI interface which should be consulted in conjunction with the documentation available at the resources detailed above. Basic Connection and Disconnection
#!/usr/bin/perl -w
#
# (c)1996 Alligator Descartes <descarte@hermetica.com>
#
# inout.pl: Connects and disconnects from a specified database
use DBI;
if ( $#ARGV < 0 ) {
die "Usage: inout.pl <Database String> <Database Vendor>\n";
}
# Create new database handle. If we can't connect, die()
$dbh = DBI->connect( '', $ARGV[0], '', $ARGV[1] );
if ( !defined $dbh ) {
die "Cannot connect to mSQL server: $DBI::errstr\n";
}
# Disconnect from the database
$dbh->disconnect;
exit;
SELECTing data from the database
#!/usr/bin/perl -w
#
# (c)1996 Alligator Descartes <descarte@hermetica.com>
#
# select.pl: Connects to a database called 'test' on a
# given database, then SELECTs some basic data
# out in array and scalar forms
use DBI;
if ( $#ARGV < 0 ) {
die "Usage: select.pl <Database String> <Database Vendor>\n";
}
# Create new database handle. If we can't connect, die()
$dbh = DBI->connect( '', $ARGV[0], '', $ARGV[1] );
if ( !defined $dbh ) {
die "Cannot connect to mSQL server: $DBI::errstr\n";
}
# Prepare the statement for execution
$sth =
$dbh->prepare( "
SELECT id, name
FROM table
" );
if ( !defined $sth ) {
die "Cannot prepare statement: $DBI::errstr\n";
}
# Execute the statement at the database level
$sth->execute;
# Fetch the rows back from the SELECT statement
while ( @row = $sth->fetchrow() ) {
print "Row returned: @row\n";
}
# Re-execute the statement to bring the rows back again
$sth->execute;
# Fetch the data back into separate variables this time
while ( ( $id, $name ) = $sth->fetchrow() ) {
print "ID: $id\tName: $name\n";
}
# Release the statement handle resources
$sth->finish;
# Disconnect from the database
$dbh->disconnect;
exit;
Executing immediate statements
#!/usr/bin/perl -w
#
# (c)1996 Alligator Descartes <descarte@hermetica.com>
#
# execute.pl: Connects to a database called 'test' on a
# given database, then EXECUTEs an update
# statement. This is non-cursorial, so do()
# is used.
use DBI;
if ( $#ARGV < 0 ) {
die "Usage: execute.pl <Database String> <Database Vendor>\n";
}
# Create new database handle. If we can't connect, die()
$dbh = DBI->connect( '', $ARGV[0], '', $ARGV[1] );
if ( !defined $dbh ) {
die "Cannot connect to mSQL server: $DBI::errstr\n";
}
# Prepare the statement for immediate execution
$rv =
$dbh->do( "
UPDATE table
SET name = 'Alligator Descartes'
WHERE id = 1
" );
if ( !defined $rv ) {
die "Statement execution failed: $DBI::errstr\n";
}
# Disconnect from the database
$dbh->disconnect;
exit;
About this document ...DBI - A Database Interface for perl5 This document was generated using the LaTeX2HTML translator Version 96.1 (Feb 5, 1996) Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds. The command line arguments were: The translation was initiated by Alligator Descartes on Sun Jul 5 16:37:18 BST 1998
|