You are on page 1of 37

Using Perl DBI to interface to MySQL

Why Perl? Why not PHP? After all, PHP4 is supposed to be fast now that
it's using a new interpreter.
Because Perl is still what's most widely used. I like going with the industry
standard. Perl has massive support online and the most books written
about it. There is CPAN, the Comprehensive Perl Archive Network, where
you'll find modules to do almost anything you'd want. DBI gives you an
interface that'll work with the "primitive" CSV format (comma separated
value text files) all the way up to the highest end Oracle RDBMS.
Let's start by connecting to the database:
use DBI;
my $dsn = 'DBI:mysql:my_database:localhost';
my $db_user_name = 'admin';
my $db_password = 'secret';
my ($id, $password);
my $dbh = DBI->connect($dsn, $db_user_name, $db_password);
Let's assume we've received as form input a nickname and password
from a login screen. So right now,
$input_nickname = 'Cowlick' and $input_password = 'udder'
We want to verify that the entered password matches what we have in
our database.
my $sth = $dbh->prepare(qq{
select id, password from users
where nickname = $input_nickname
});
$sth->execute();
Notice there is no command-terminating semi-colon.
How do we get the results? Since we only expect one row,
($id, $password) = $sth->fetchrow_array();
$sth->finish(): # we're done with this query

if ($input_password eq $password) # case-sensitive


{
... # login successful
}
What if our result is more than one row? Successive calls to
$sth->fetchrow_array()
will return the rest of the result set.
my $sth = $dbh->prepare(qq{
select nickname, favorite_number from users
});
$sth->execute();
while (my ($nickname, $favorite_number) =
$sth->fetchrow_array())

# keep fetching until


# there's nothing left

{
print "$nickname, $favorite_number\n";
}
$sth->finish();
If we want to save the entire result set first for processing later,
my (@matrix) = ();
while (my @ary = $sth->fetchrow_array())
{
push(@matrix, [@ary]);

# [@ary] is a reference

}
$sth->finish();
A reference, for C programers, can be thought of as a pointer. The Matrix
is now an array of array references, or a two-dimensional array.

You can access row $i with:


@{matrix[$i]}
Or, you can access a specific row and column ($i, $j) in the table with:
$matrix[$i][$j]
For MySQL operations that don't return a result you can use the do
method instead of prepare then execute.
$dbh->do("insert into message_votes
(message_id, user_id, vote) values (1, 3, 'good')");
When you're done with the database:
$dbh->disconnect();
That should be enough to get you started. You can see that using Perl DBI
is a matter of calling a method with the MySQL command as a string.
For more in-depth information regarding Perl DBI and MySQL refer to the
book MySQL (OTHER NEW RIDERS) by Paul Dubois. Great reviews on
Amazon convinced me to buy it and while I can't quite rave about the
book, because it's hard to find what you want most of the time, it seems
very competently written. Of course, I have no frame of reference since
this is the only MySQL book I've looked at.
For the best all-around CGI book out there, you must get the excellent CGI
Programming with Perl (2nd Edition) published by O'Reilly. You should
know some Perl before starting in on this but you'll learn more than a little
bit about everything CGI by the time you've finished. Plenty of relevant
examples and excellent sections on Security, DBI, and Maintaining State
make this book a must have. Disregard the bad reviews on Amazon unless
you're the kind of person who likes to type in the examples from the book,
in which case, you will have a tough time. Use it instead to learn the
concepts and then write your own code!

Introduction to MySQL (using Perl DBI)


My theory is, if the title doesn't sound alien to you, then you're probably
in the right place.
MySQL is a relational database management system. It sounds fancy, but
doesn't have to be. The novice, like me, can treat it as a black box. Put
stuff in, ask for certain stuff out. It just works. That simple.
MySQL is based on a client/server model, so the black box is the MySQL
server and your interface to it is the MySQL client program. All the
examples of MySQL commands in this article can be entered straight into
the MySQL client command line. MySQL supports multi-line commands
and uses a semicolon to designate the end of the command.
Why MySQL and not another database system that supports SQL?
Because MySQL is free, well-supported and fast.
Even for a novice, it's probably more helpful to think of MySQL as a
secretary ready to do your filing for you. You give her instructions on how
to file the items. If you know that you'll be asking for items by their date,
then tell the secretary to file by date and when you ask for things, it
doesn't take her all day to find what you're looking for.
Data is organized into rows and columns, defining a matrix. In SQL-speak,
the matrix is called a table.
The best way for a C programmer to think of it is:
Each row is a structure reference.
Every column is a member of that structure.
Here's a typical C data structure:
struct users
{
int

id;

char nickname[17]; // 16 char NULL terminated string


char password[17]; // ditto

};

int

socks;

// pairs of socks

int

favorite_number;

It looks like user information collected by a web-site, perhaps.


The MySQL version of this structure is created with this command to the
MySQL client program:
create table users
(
id

int auto_increment not null,

nickname

varchar(16) not null,

password

varchar(16) not null,

socks

int,

favorite_number int,
primary key

(user_id),

unique

(nickname)

);

See any similairities?


This is what it looks like as a row in MySQL:
+----+----------+----------+-------+-----------------+
| id | nickname | password | socks | favorite_number |
+----+----------+----------+-------+-----------------+

What is The Matrix? The matrix of data for three hypothetical users:
+----+----------+----------+-------+-----------------+
|

1 | GdayMate | dingo

57 |

42 |

+----+----------+----------+-------+-----------------+
|

2 | Javier

| cigar

1 |

945 |

+----+----------+----------+-------+-----------------+
|

3 | Rolo

| pudding

9 |

8 |

+----+----------+----------+-------+-----------------+

That's it? Yup. In fact, these tables are exactly what you'd see if you gave
MySQL this command:

select * from users;


The asterisk means to select all the columns from the users table.
The table is the structural foundation for the multi-billion dollar a year
database industry which includes companies like Oracle and Informix.
Simple MySQL Commands
Let's run through some simple SQL commands. You already know the
create table command.
create table users
(
id

int auto_increment not null,

nickname

varchar(16) not null,

password

varchar(16) not null,

socks

int,

favorite_number int,
primary key

(user_id),

unique

(nickname)

);

What if we just want user nicknames and their favorite number?


select nickname, favorite_number from users;
This gives us:
+----------+-----------------+
| nickname | favorite_number |
+----------+-----------------+
| GdayMate |

42 |

+----------+-----------------+
|

Javier |

945 |

+----------+-----------------+
|

Rolo |

8 |

+----------+-----------------+

And if we want all nicknames of users with less than 10 pairs of socks and
whose favorite number is greater than 100?
select nickname from users where socks < 10 and
favorite_number > 100;
+----------+
| nickname |
+----------+
|

Javier |

+----------+

So how do you insert a row of data into the table? Simple.


insert into users (nickname, socks)
values ('Cowlick', 0);
Uh oh, the row that's created is missing the password column! Remember
the line used to create the password column in the users table?
create table users
(
...
password varchar(16) not null,
...
);

The not null means you must have some value for the column. So MySQL
gives an error in this case. We should use instead:
insert into users (nickname, password, socks)
values ('Cowlick', 'udder', 0);
This results in a row like this:
+----+----------+----------+-------+-----------------+
| id | nickname | password | socks | favorite_number |
+----+----------+----------+-------+-----------------+

4 |

Cowlick |

udder |

0 |

NULL |

+----+----------+----------+-------+-----------------+

But wait! Why didn't we have to specify an id? That's not null also. The
line from the create table users command:
create table users
(
id int auto_increment not null,
...
);

In the case of the id column, we have specified auto_increment and


MySQL creates the value for us by adding 1 to the greatest value it finds
in that column (Rolo has an id of 3).
We've forgotten to include Cowlick's favorite number. Which is -1, by the
way. For this we use the update command.
update users set favorite_number = -1
where id = 4;
We could have also used:
update users set favorite_number = -1
where nickname = 'Cowlick';
But what if there were more than one user with the nickname Cowlick? In
our example, there can't be, because in the create table command we've
specified
create tables users
(
...
unique (nickname)
);

If we try and insert another user with the nickname Cowlick, we'd get an
error from MySQL.
Let's
say
you've
built
up
a
large
community
of
sock
aficionados/numerologists and you've been having a lot of problems with
Javier. He keeps talking off subject about high jumping and hunting for

truffles. The other members of the community are up in arms because


they see Javier as a trouble maker and his posts as noise.
delete from users where nickname = 'Javier';
Of course, this doesn't stop Javier from re-registering and continuing his
annoying banter.
Let's say you're sick of all the talk about gold toe vs. tube and WesternLucky-7 vs. Chinese-Good-Fortune-8. You realize there is a demand for a
site about high jumping and hunting for truffles. You want to revamp the
site.
drop table users;
The table definition and all the data are now gone. Be very careful with
this command.
MySQL types and primary key
We haven't talked about the primary key directive in the create table
command.
create table users
(
...
primary key

(user_id),

...
)

This is an instruction to the MySQL "secretary" to file things by user_id.


The constraint imposed on a primary key is that each row must have a
unique value for the key. Technically, MySQL creates a B-tree to make
lookup of a specific row by user_id fast. So this
select * from users where user_id = 2;
is faster than
select * from users where favorite_number = 945;
Is MySQL limited to small data types? Only if you think 4 gigabytes is
small. That's what the LongBlob and LongText types can hold.
Let's say we want to create a message system. A simple example of a
message row is created with:
create table messages

(
id

int auto_increment not null,

user_id

int not null,

posting_date datetime not null,


comment_body text
primary key

(id)

This introduces two new SQL types: datetime and text.


The datetime column data is structured like so, "YYYY-MM-DD hh:mm:ss".
This way, datetimes can be ASCII sorted into chronological order. To us, it's
a string, that's the format we give to MySQL and the format we get out,
but internally, it's an 8 byte bitstream.
The text type holds up to 64Kb of data, more than enough for a message.
The user_id column, that's the relational part of Relational Database
Management System (RDBMS). The user_id in our example references the
id column of the users table. This way we're relating the message to the
user who is the author. The table is the structural foundation but this
concept of referencing is the functional basis for RDBMS.

Here's an example message row (the message_body can be much


longer):
+----+---------+---------------------+--------------+
| id | user_id |

posting_date | message_body |

+----+---------+---------------------+--------------+
|

1 |

3 | 2000-10-10 10:00:00 |

Wassup! |

+----+---------+---------------------+--------------+

Let's say we have a voting system, where users can vote on whether or
not the message was worth reading. We'd create a table like this:
create table message_votes
(
message_id

int not null,

user_id

int not null,

vote

enum('good', 'bad') not null,

primary key (message_id, user_id)


);

In this example, the vote column can contain either the value 'good' or
the value 'bad'.
The primary key directive specifies two columns to "file" by. Since primary
keys are by definition unique, (message_id, user_id) as a value pair must
be unique. This imposes the constraint that each user can only vote on a
specific message once.
Also, in this example, MySQL "files" message votes "sorting" by
message_id first then by user_id. Which means lookups like:
select * from message_votes where message_id = 3;

are going to be faster than


select * from message_votes where user_id = 2;

But the fastest way to lookup a message vote is:


select * from message_votes where
message_id = 3 and user_id = 2;

Now we're ready to use Perl DBI to interface with MySQL.

Database Management in PERL - DBI


This session will teach you how to access Oracle Database and other
databases using PERL.
Starting from Perl 5 it has become very easy to write database
applications using DBI. DBI stands for Database independent interface for
Perl which means DBI provides an abstraction layer between the Perl code
and the underlying database, allowing you to switch database
implementations really easily.
The DBI is a database access module for the Perl programming language.
It defines a set of methods, variables, and conventions that provide a
consistent database interface, independent of the actual database being
used.
Architecture of a DBI Application
DBI is independent of any database available in backend. You can use DBI
whether you are working with Oracle, MySQL or Informix etc. This is clear
from the following architure diagram.
Here DBI is responsible of taking all SQL commands through the API, or
Application Programming Interface, and to dispatch them to the
appropriate driver for actual execution. And finally DBI is responsible of
taking results from the driver and giving back it to the calling scritp.
Notation and Conventions
Throughout this chapter following notations will be used and it is
recommended that you should also follow the same convention.
$dsn

Database source name

$dbh

Database handle object

$sth

Statement handle object

$h

Any of the handle types above ($dbh, $sth, or $drh)

$rc

General Return Code (boolean: true=ok, false=error)

$rv

General Return Value (typically an integer)

@ary

List of values returned from the database.

$rows Number of rows processed (if available, else -1)


$fh

A filehandle

undef NULL values are represented by undefined values in Perl

\%attr Reference to a hash of attribute values passed to methods


Database Connection
Assuming we are going to work with MySQL database. Before connecting
to a database make sure followings:
You have created a database TESTDB.
You have created TEST_TABLE in TESTDB.
This table is having fields FIRST_NAME, LAST_NAME, AGE, SEX and
INCOME.
User ID "testuser" and password "test123" are set to access TESTDB
Perl Module DBI is installed properly on your machine.
You have gone through MySQL tutorial to understand MySQL Basics.

Following is the example of connecting with MySQL database "TESTDB"


#!/usr/bin/perl
use DBI
use strict;

my $driver = "mysql";
my $database = "TESTDB";
my $dsn = "DBI:$driver:database=$database";
my $userid = "testuser";
my $password = "test123";
my $dbh = DBI->connect($dsn, $userid, $password )
or die $DBI::errstr;

If a connection is established with the datasource then a Database Handle


is returned and saved into $dbh for further use otherwise $dbh is set to
undef value and $DBI::errstr returns an error string.

INSERT Operation
INSERT operation is required when you want to create your records into
TEST_TABLE. So once our database connection is established, we are
ready to create records into TEST_TABLE. Following is the procedure to
create single record into TEST_TABLE. You can create many records in
similar fashion.
Record creation takes following steps
Prearing SQL statement with INSERT statement. This will be done using
prepare() API.
Executing SQL query to select all the results from the database. This will
be done using execute() API.
Releasing Stattement handle. This will be done using finish() API
If everything goes fine then commit this operation otherwise you can
rollback complete transaction. Commit and Rollback are explained in next
sections.
my $sth = $dbh->prepare("INSERT INTO TEST_TABLE
(FIRST_NAME, LAST_NAME, SEX, AGE, INCOME )
values
('john', 'poul', 'M', 30, 13000)");
$sth->execute() or die $DBI::errstr;
$sth->finish();
$dbh->commit or die $DBI::errstr;

Using Bind Values


There may be a case when values to be entered is not given in advance.
In such case binding values are used. A question mark is used in place of
actual value and then actual values are passed through execute() API.
Following is the example.

my $first_name = "john";
my $last_name = "poul";
my $sex = "M";
my $income = 13000;
my $age = 30;

my $sth = $dbh->prepare("INSERT INTO TEST_TABLE


(FIRST_NAME, LAST_NAME, SEX, AGE, INCOME )
values
(?,?,?,?)");
$sth->execute($first_name,$last_name,$sex, $age, $income)
or die $DBI::errstr;
$sth->finish();
$dbh->commit or die $DBI::errstr;

READ Operation
READ Operation on any databasse means to fetch some useful
information from the database. So once our database connection is
established, we are ready to make a query into this database. Following is
the procedure to query all the records having AGE greater than 20. This
will take four steps
Prearing SQL query based on required conditions. This will be done using
prepare() API.
Executing SQL query to select all the results from the database. This will
be done using execute() API.
Fetching all the results one by one and printing those results.This will be
done using fetchrow_array() API.
Releasing Stattement handle. This will be done using finish() API

my $sth = $dbh->prepare("SELECT FIRST_NAME, LAST_NAME


FROM TEST_TABLE
WHERE AGE > 20");
$sth->execute() or die $DBI::errstr;
print "Number of rows found :" + $sth->rows;
while (my @row = $sth->fetchrow_array()) {
my ($first_name, $last_name ) = @row;
print "First Name = $first_name, Last Name = $last_name\n";
}
$sth->finish();

Using Bind Values


There may be a case when condition is not given in advance. In such case
binding values are used. A question mark is used in place of actual value
and then actual value is passed through execute() API. Following is the
example.

$age = 20;
my $sth = $dbh->prepare("SELECT FIRST_NAME, LAST_NAME
FROM TEST_TABLE
WHERE AGE > ?");
$sth->execute( $age ) or die $DBI::errstr;
print "Number of rows found :" + $sth->rows;
while (my @row = $sth->fetchrow_array()) {
my ($first_name, $last_name ) = @row;
print "First Name = $first_name, Last Name = $last_name\n";
}
$sth->finish();

UPDATE Operation
UPDATE Operation on any databasse means to update one or more
records already available in the database. Following is the procedure to
update all the records having SEX as 'M'. Here we will increase AGE of all
the males by one year. This will take three steps

Prearing SQL query based on required conditions. This will be done using
prepare() API.
Executing SQL query to select all the results from the database. This will
be done using execute() API.
Releasing Stattement handle. This will be done using finish() API
If everything goes fine then commit this operation otherwise you can
rollback complete transaction. See next section for commit and rollback
APIs.

my $sth = $dbh->prepare("UPDATE TEST_TABLE


SET

AGE = AGE + 1

WHERE SEX = 'M'");


$sth->execute() or die $DBI::errstr;
print "Number of rows updated :" + $sth->rows;
$sth->finish();
$dbh->commit or die $DBI::errstr;

Using Bind Values


There may be a case when condition is not given in advance. In such case
binding values are used. A question mark is used in place of actual value
and then actual value is passed through execute() API. Following is the
example.

$sex = 'M';
my $sth = $dbh->prepare("UPDATE TEST_TABLE
SET

AGE = AGE + 1

WHERE SEX = ?");


$sth->execute('$sex') or die $DBI::errstr;
print "Number of rows updated :" + $sth->rows;
$sth->finish();
$dbh->commit or die $DBI::errstr;

In some case you would like to set a value which is not given in advance
so you can use binding value as follows. In this example income of all
males will be set to 10000.

$sex = 'M';
$income = 10000;
my $sth = $dbh->prepare("UPDATE TEST_TABLE
SET

INCOME = ?

WHERE SEX = ?");

$sth->execute( $income, '$sex') or die $DBI::errstr;


print "Number of rows updated :" + $sth->rows;
$sth->finish();

DELETE Operation
DELETE operation is required when you want to delete some records from
your database. Following is the procedure to delete all the records from
TEST_TABLE where AGE is equal to 30. This operation will take following
steps.
Prearing SQL query based on required conditions. This will be done using
prepare() API.
Executing SQL query to delete required records from the database. This
will be done using execute() API.
Releasing Stattement handle. This will be done using finish() API

If everything goes fine then commit this operation otherwise you can
rollback complete transaction.

$age = 30;
my $sth = $dbh->prepare("DELETE FROM TEST_TABLE
WHERE AGE = ?");
$sth->execute( $age ) or die $DBI::errstr;
print "Number of rows deleted :" + $sth->rows;
$sth->finish();
$dbh->commit or die $DBI::errstr;

Using do Statement
If you're doing an UPDATE, INSERT, or DELETE there is no data that comes
back from the database, so there is a short cut to perform this operation.
You can use do statement to execute any of the command as follows.
$dbh->do('DELETE FROM TEST_TABLE WHERE age =30');

do returns a true value if it succeeded, and a false value if it failed.


Actually, if it succeeds it returns the number of affected rows. In the
example it would return the number of rows that were actually deleted.

COMMIT Operation
Commit is the operation which gives a green signal to database to finalize
the changes and after this operation no change can be reverted back.
Here is a simple example to call commit API.
$dbh->commit or die $dbh->errstr;

ROLLBACK Operation
If you are not satisfied with all the changes and you want to revert back
those changes then use rollback API.
Here is a simple example to call rollback API.
$dbh->rollback or die $dbh->errstr;

Begin Transaction
Many databases support transactions. This means that you can make a
whole bunch of queries which would modify the databases, but none of
the changes are actually made. Then at the end you issue the special SQL
query COMMIT, and all the changes are made simultaneously.
Alternatively, you can issue the query ROLLBACK, in which case all the
queries are thrown away.
begin_work API enables transactions (by turning AutoCommit off) until the
next call to commit or rollback. After the next commit or rollback,
AutoCommit will automatically be turned on again.
$rc

= $dbh->begin_work

or die $dbh->errstr;

AutoCommit Option
If your transactions are simple, you can save yourself the trouble of
having to issue a lot of commits. When you make the connect call, you
can specify an AutoCommit option which will perform an automatic
commit operation after every successful query. Here's what it looks like:

my $dbh = DBI->connect($dsn, $userid, $password,


{AutoCommit => 1})
or die $DBI::errstr;

Here AutoCommit can take value 1 or 0.


Automatic Error Handling
When you make the connect call, you can specify a RaiseErrors option
that handles errors for you automatically. When an error occurs, DBI will
abort your program instead of returning a failure code. If all you want is to
abort the program on an error, this can be convenient. Here's what it looks
like:
my $dbh = DBI->connect($dsn, $userid, $password,
{RaiseError => 1})
or die $DBI::errstr;

Here RaiseError can take value 1 or 0.

Disconnecting Database
To disconnect Database connection, use disconnect API.
$rc = $dbh->disconnect

or warn $dbh->errstr;

The transaction behaviour of the disconnect method is, sadly, undefined.


Some database systems (such as Oracle and Ingres) will automatically
commit any outstanding changes, but others (such as Informix) will
rollback any outstanding changes. Applications not using AutoCommit
should explicitly call commit or rollback before calling disconnect.
Using NULL values
Undefined values, or undef, are used to indicate NULL values. You can
insert and update columns with a NULL value as you would a non-NULL
value. These examples insert and update the column age with a NULL
value:

$sth = $dbh->prepare(qq{
INSERT INTO TEST_TABLE (FIRST_NAME, AGE) VALUES (?, ?)
});
$sth->execute("Joe", undef);

Here qq{} is used to return q quoted string to prepare API.


However, care must be taken when trying to use NULL values in a WHERE
clause. Consider:

SELECT FIRST_NAME FROM TEST_TABLE WHERE age = ?

Binding an undef (NULL) to the placeholder will not select rows which
have a NULL age! At least for database engines that conform to the SQL
standard. Refer to the SQL manual for your database engine or any SQL
book for the reasons for this. To explicitly select NULLs you have to say
"WHERE age IS NULL".
A common issue is to have a code fragment handle a value that could be
either defined or undef (non-NULL or NULL) at runtime. A simple technique
is to prepare the appropriate statement as needed, and substitute the
placeholder for non-NULL cases:

$sql_clause = defined $age? "age = ?" : "age IS NULL";


$sth = $dbh->prepare(qq{
SELECT FIRST_NAME FROM TEST_TABLE WHERE $sql_clause
});
$sth->execute(defined $age ? $age : ());

Some other DBI functions


available_drivers
@ary = DBI->available_drivers;
@ary = DBI->available_drivers($quiet);
Returns a list of all available drivers by searching for DBD::* modules
through the directories in @INC. By default, a warning is given if some
drivers are hidden by others of the same name in earlier directories.
Passing a true value for $quiet will inhibit the warning.
installed_drivers
%drivers = DBI->installed_drivers();
Returns a list of driver name and driver handle pairs for all drivers
'installed' (loaded) into the current process. The driver name does not
include the 'DBD::' prefix.
data_sources
@ary = DBI->data_sources($driver);

Returns a list of data sources (databases) available via the named driver.
If $driver is empty or undef, then the value of the DBI_DRIVER
environment variable is used.
quote
$sql = $dbh->quote($value);
$sql = $dbh->quote($value, $data_type);
Quote a string literal for use as a literal value in an SQL statement, by
escaping any special characters (such as quotation marks) contained
within the string and adding the required type of outer quotation marks.
$sql = sprintf "SELECT foo FROM bar WHERE baz = %s",
$dbh->quote("Don't");
For most database types, quote would return 'Don''t' (including the outer
quotation marks). It is valid for the quote() method to return an SQL
expression that evaluates to the desired string. For example:
$quoted = $dbh->quote("one\ntwo\0three")
may produce results which will be equivalent to
CONCAT('one', CHAR(12), 'two', CHAR(0), 'three')

Methods Common to all Handles


err
$rv = $h->err;
or
$rv = $DBI::err
or
$rv = $h->err
Returns the native database engine error code from the last driver
method called. The code is typically an integer but you should not assume
that. This is equivalent to $DBI::err or $h->err.
errstr
$str = $h->errstr;
or

$str = $DBI::errstr
or
$str = $h->errstr
Returns the native database engine error message from the last DBI
method called. This has the same lifespan issues as the "err" method
described above. This is equivalent to $DBI::errstr or $h->errstr.

rows
$rv = $h->rows;
or
$rv = $DBI::rows
This returns the number of rows effected by previous SQL statement and
equivalent to $DBI::rows.
trace
$h->trace($trace_settings);
DBI sports an extremely useful ability to generate runtime tracing
information of what it's doing, which can be a huge time-saver when
trying to track down strange problems in your DBI programs. You can use
different values to set trace level. These values varies from 0 to 4. The
value 0 means disable trace and 4 means generate complete trace.
Interpolated Statements are Prohebited
It is highly recommended not to use interpolated statements as follows:
while ($first_name = <>) {
my $sth = $dbh->prepare("SELECT *
FROM TEST_TABLE
WHERE FIRST_NAME = '$first_name'");
$sth->execute();
# and so on ...
}

There are following reasons to avoid interploated statements:

First, prepare calls can take a long time. The database server has to
compile the SQL and figure out how it is going to run the query. If you
have many similar queries, that is a waste of time.
Second, it will not work if $first_name contains a name like O'Brien or
D'Fecto or some other name with an '. The ' has a special meaning in SQL,
and the database will not understand when you ask it to prepare an SQL
statement.

Finally, if you're going to be constructing your query based on a user


input then it's unsafe to simply interpolate the input directly into the
query, because the user can construct a strange input in an attempt to
trick your program into doing something it didn't expect. For example,
suppose the user enters the following bizarre value for $input:
x' or first_name = first_name or first_name = 'y

Now our query has become something very surprising:


SELECT *
FROM TEST_TABLE
WHERE first_name = 'x'
or first_name = first_name or first_name = 'y'

The part of this query that our sneaky user is interested in is the second
or clause. This clause selects all the records for which first_name is equal
to first_name; that is, all of them.
Thus don't use interpolated statement instead use bind value to prepare
dynamic SQL statement.

A simple introduction to database interface using perl dbi.


DBI DataBase Interface module (more precisely a collection of modules)
is a feature rich, efficient and yet simple tool to access databases using
perl. Almost all Linux distributions have them, if not you can download
from cpan.org. The interface to any DBMS requires two sets of tools one
DBI itself which is generic, two the DBD::the_database. DBD is the driver
component and you should install drivers for whatever database you are
using. DBI drivers are available for almost all standard databases.
Normally database access workflow is like this:
a.Connect to the database (logging) using username,password etc.. Once
properly authenticated a database-handle will be given.
b.Create the sql query, use database-handle to send the query to the
server and ask it to prepare the query.
c. Server parses the sql, if no errors, returns a statement-handle.
d.Use the statement-handle to execute the query.
f.Use statement-handle to fetch data single row or multiple rows at a
time.
g.Close the statement handle
h. Repeat steps b to g as long as you want, with new queries
i.Finally disconnect from database(logout) using database-handle.

Let us see them by means of a sample code.


Assumptions:
Database Server: mysql running on local host
Database user name: test Password: test123
Database name : testdb
Table : names
Columns in the table: id,name,age
Objective 1:

1. List all records in the table and find out average age

Let us start the code. (codes are give in italics and bold)

Step 1:
Connecting to the database
use DBI;
my $dbh=DBI>connect(DBI:mysql:database=testdb;host=localhost,'test,'test123);
Connect requires three arguments : datasource, username,password
First argument -datasource gives information about the database server
like type of dbms, location etc.
In our example datasource is specified as
DBI:mysql:database=testdb;host=localhost
Here DBI:mysql means use mysql driver.
database=testdb means use the database testdb.
host=localhost means the host in which the database is running.
Other two arguments are username and password which need no
explanation.

Step 2
Run the select query on the server.
First store sql in a variable like this
my $query=select * from name ;
Then send the sql to the server for parsing and checking
my $sth=$dbh->prepare($query) or die could not prepare $query\n;
In the above statement
$dbh is the database connection handle we got while using DBI->connect
earlier.

$sth is the statement handle returned upon successful preparation.

$query refers to the sql statement. The query can be given directly as
string also.
Here we do some error checking by using die. The $sth that is returned
will be required for any further opertion on this query.
Now we will run the query on the server
$sth->execute();
Note here, we are simply using $sth to run the query. Once we call
execute, the server runs the query and keeps the result set ready for
retrieval.
Step 3
Get results from the server one row at a time.
fetchrow_array() is a function that will return one row of data and store
result in an array.
We will use a while loop to fetch all rows from the server.
while (($id,$name,$age)=$sth->fetchrow_array()){
print id=$id name=$name age=$age\n;
}
$sth->fetchrow will return a null when there are no more rows. Thus this
loop will run until null.
($id,$name,$age)=$sth->fetchrow_array() is used to equate the rows
returned to a set of variables.
Step 4
Close the statement handle
$sth->finish();
Step 5
Close the database connection
$dbh->disconnect();
Here is the output of running the script.

id=1 name=RAMAN age=45


id=2 name=RAVI age=35

For the sake convenience I am repeating program listing here.


use DBI;
my $dbh=DBI>connect(DBI:mysql:database=testdb;host=localhost,'test,'test123);
my $query=select * from name ;
my $sth=$dbh->prepare($query) or die could not prepare $query\n;
$sth->execute();
while (($id,$name,$age)=$sth->fetchrow_array()){
print id=$id name=$name age=$age\n;
}
$sth->finish();
$dbh->disconnect()

Objective 2.
Insert a record accepting input from terminal
Here is the code to insert a row into name table.
Step 1:
Establishing connection with database. For explanation see previous
example
use DBI;
my $dbh=DBI>connect(DBI:mysql:database=testdb;host=localhost,'test,'test123);
Step 2
Accept input from keyboard
print Enter id:;
$id=<STDIN>;

print Enter Name:;


$name=<STDIN>;

print Enter age;


$age=<STDIN>;
use chomp to remove any newlines
chomp $id;
chomp $age;
chomp $name;
Explanation : The print statement is simple just shows message on the
screen.
$id=<STDIN> means accept value from standard input (by default
keyboard) and store the value in the variable $id;
Step 3
Create the Sql statement
$query=sprintf insert into name(id,name,age) values(%d,%s,%d),$id,$dbh>quote($name),$age;

Explanation: Here we create a string using sprintf function, by variable


substitution.
The sprintf in perl is similar to sprintf in c.
$dbh->quote() function is used on string values, so that quotes are
properly taken care of -e.g names like DSilva. It is a best practice to use
this.
At the end of this line the $query variable will have an sql which is an
insert statement.
Step 4.
Run the query on the server and insert data.
$dbh->do($query) or die could not do $query\n;

The sql execution in the previous example was done in three stages
namely prepare, execute,fetchrow_array. In the case of insert statement
no rows are returned. Hence, we can use do(), which combines all three
stages into one. It will return number of rows affected.

Step 5.
Disconnect from the server
$dbh->disconnect();

For the sake of convenience the code is repeated here.


use DBI;
my $dbh=DBI>connect(DBI:mysql:database=testdb;host=localhost,'test,'test123);
print Enter id:;
$id=<STDIN>;
print Enter Name:;
$name=<STDIN>;
print Enter age;
$age=<STDIN>;
chomp $id;
chomp $age;
chomp $name;
$query=sprintf insert into name(id,name,age) values(%d,%s,%d),$id,$dbh>quote($name),$age;
$dbh->do($query) or die could not do $query\n;
$dbh->disconnect();

As you can see from the above examples dbi is pretty simple. Same code
can be used for any database. Only change required will be in connection
step.
The performance of dbi is very good, and it has lot features like fetching
column names, types etc.

MySQL Perl DBI Tutorial


By Deborah Lee Soltesz, eHow Contributor
One of the most powerful features of Perl is its ability to process, parse,
manipulate and format text and data, making it an ideal language for
developing database applications. The Perl Database Interface (DBI)
Module makes it easy to connect to and use a wide range of database
systems, including MySQL. In addition to Perl, the Perl::DBI module and
DBD::mysql database driver must be installed on the system where the
scripts are developed and executed. Most of the functionality of MySQL
can be accessed through the MySQL driver for Perl::DBI.
Connecting to the MySQL Server
Before you can execute queries and other statements on a database, your
script needs to establish a connection. Import the DBI module in your
script with "use DBI":
use DBI;

The DBI->connect function connects to a database and returns a


database handle. Establish a connection to a local database, providing the
name of your database in the source parameter, and the user name and
password for the MySQL user your script will use for the connection:
my $dbh = DBI->connect('DBI:mysql:dbname', 'user', 'password') or die
"Connection failed: $DBI::errstr";

Connecting to a remote database is similar to a local connection by


providing the remote host address in the source parameter. In the
following example, the RaiseError attribute is set to report errors via die()
in place of the "or die" manual error checking clause in the previous
example. The PrintError attribute is disabled. PrintError automatically
reports errors via warn() when enabled.
my $dbh = DBI->connect('DBI:mysql:dbname;host=db.server.edu', 'user',
'password', { PrintError => 0, RaiseError => 1 });

Before exiting the script, disconnect from the database using the
disconnect function.
$dbh->disconnect();

Basic Queries
The most common statement executed on a database is the SELECT
statement. Create a statement handle by calling the prepare function with
the SELECT statement. For example, this SELECT will query a table listing
of people for the first name field for all entries where the last name is
"Johnson":

my $sth = $dbh->prepare("SELECT firstname FROM people WHERE


lastname='Johnson'");

Execute the statement:

$sth->execute();

Retrieve one row of data at a time as a hash and print the results:
print "Query for last name Johnson: \n";
while (my $resultrow = $sth->fetchrow_hashref()) {
my $fn = $resultrow->{firstname};
print "$fn\n";
}

There are several functions for retrieving query results, such as


fetchrow_array to fetch the next row as an array and fetchall_hashref to
fetch all of the results at once into a hash.
Using Placeholders
Placeholders can be used in the statement prepare function. This is useful
in interactive scripts where query filter values are provided by the user,
particularly if a loop allows the user to submit multiple queries before
exiting.
For example, the placeholder (the question mark) provides the spot where
user input will be provided when the statement is executed:
my $sth = $dbh->prepare('SELECT * FROM people WHERE lastname = ?') or die
"Statement error: " . $dbh->errstr;

A while loop repeatedly prompts the user for a last name:


print "Search for last name: ";
while ($lastname = <>) {
chomp $lastname;
my @results;

The statement prepared earlier is executed, with $lastname provided as a


parameter. This parameter will be inserted into the query statement in
place of the question mark placeholder:
$sth->execute($lastname) or die "Statement error: " . $sth->errstr;
The results, if any, are printed out:

if ($sth->rows == 0) {
print "No matches for `$lastname'.\n\n";
}

while (@results = $sth->fetchrow_array()) {


my $firstname = $results[1];
my $age = $results[3];
print "$firstname $lastname ($age)\n";
}

The statement handle is tidied up with the finish method, and the loop
continues:
$sth->finish;
print "Search for last name: ";
}

Adding, Updating and Deleting Records


Updates, inserts and deletes can be executed simply by using the do
function. For example:
$dbh->do("INSERT INTO people(firstname, lastname, age) VALUES('Bob',
'Johnson', 32)");
$dbh->do("UPDATE people set firstname='Robert' where firstname=?", undef,
"Bob");
$dbh->do("DELETE FROM people WHERE lastname='Johnson'");

Building and Managing a Database


Database administration functions are executed with the func function
using the database handle obtained from the connection:
$dbh->func("createdb", $dbname, 'admin');
$dbh->func("dropdb", $dbname, 'admin');

The server can also be reloaded and shut down. This functionality is
useful for simplifying and automating database systems administration
tasks. Sufficient privileges are required for these actions.
Database table create and alter statements can be executed with the do
function. For example, this statement creates the people table:

$dbh->do("CREATE TABLE people (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(50), lastname VARCHAR(50), age INT)");

Creating and updating existing databases is useful for automating the


installation of distributed applications, such as discussion boards, photo
galleries and blogs.

You might also like