PERL Programming Database
PERL Programming Database
Viswanatha Yarasi
[email protected]
[email protected]
(9849743894)
PERL Programming
• Objectives
– Introduction to PERL for databases.
– Why Perl for Databases?
– Perl ODBC
– What is Perl DBI?
– Why Perl DBI?
– Design, Architecture & Examples
– Safety
Intro. To Perl for Databases
Perl Application
DBI Module
• ### Disconnect
• $db->Close();
A Simple Example - DBI (2)
• #!perl -w
• # works on BSD-LPT0037 where DBI.pm is working
• ### Attributes to pass to DBI->connect( )
• my %attr = (
• PrintError => 1,
• RaiseError => 1
• );
• print "\n\n";
Example for Insert/Update
1: #!/usr/bin/perl -w
2:
3: use DBI;
4: # assume user name and password are all defined
5: my $dbh = DBI->connect("dbi:$db_type:$db:$host", "$db_user", "$db_password", {
PrintError => 0,
RaiseError => 0
} ) or die "Can't connect to the database: $DBI::errstr\n";
6:
7: $upd = $dbh->prepare("UPDATE prices SET price=? WHERE
product=?");
8: $ins = $dbh->prepare("INSERT INTO prices (product,price)
VALUES(?,?)");
9: $rows = $upd->execute(42, "Widgets");
10: $ins->execute("Widgets", 42) if $rows == 0;
11:
12: $dbh->disconnect;
A Simple Example - ODBC
• #! perl
• # works on BSD-LPT0037 where ODBC driver for MySQL is installed
• use Win32::ODBC;
• $DSN = "perl_demo";
• $UID = "simanta";
• $PWD = "simanta";
• $table = "megaliths";
❍ with
$sth->bind_columns(\$key, \$value);
while($sth->fetchrow_arrayref) {
print “$key: $value\n”;
}
• But if it is
– Alternative behaviors are available via the $is_active
parameter
prepare_cached($sql, \%attr, $if_active)
– See the docs for details
Keep a handle on your databases
• Connecting to a database can be slow
• Oracle especially so
❍ with...
sub lookup_foo_2 {
my ($id) = @_;
my $dbh = DBI->connect_cached(…);
$sth = $dbh->prepare_cached("select foo from table
where id=?");
return $dbh->selectrow_array($sth, $id);s
Some connect_cached() issues
• Because connect_cached() may return a new connection...
– it’s important to specify all significant attributes within the connect() call
– e.g., AutoCommit, RaiseError, PrintError
– So pass the same set of attributes into all connect calls
• or before execute:
$sth->bind_param(1, $p1);
$sth->bind_param(2, $p2);
$sth->execute;
Then, some more detail...
• If $sth->execute(…) specifies any values, it must
specify them all
• DBI now says using a date/time TYPE mandates ISO 9075 format
$sth->bind_param(1, "2004-12-31", SQL_DATE);
$sth->bind_param(2, "2004-12-31 23:59:59", SQL_DATETIME);
$sth->bind_col(1, \$foo, SQL_DATETIME); # for selecting data
$h->{RaiseError} = 1;
$h->method;
$h->method;
$h->method;
Handling errors the smart way
• Setting RaiseError make the DBI call die for you
• Buzzwords:
• Need to catch the error exception being thrown by RaiseError
Catching the Exception
• Life after death
$h->{RaiseError} = 1;
eval {
foo();
$h->method; # if it fails then the
DBI calls die
bar($h); # may also call DBI methods
};
if ($@) { # $@ holds error message
... handle the error here …
}
• Bonus
• Other, non-DBI, code within the eval block may also raise an
exception
• that will also be caught and can be handled cleanly
Picking up the Pieces
• So, what went wrong?
$@
• holds the text of the error message
if ($DBI::err && $@ =~ /^(\S+) (\S+) failed: /)
• then it was probably a DBI error
• and $1 is the driver class (e.g. DBD::foo::db), $2 is the name of the method (e.g.
prepare)
$DBI::lasth
• holds last DBI handle used (not recommended for general use)
$h->{Statement}
• holds the statement text associated with the handle (even if it’s a database handle)
• $h->{ShowErrorStatement} = 1
• appends $h->{Statement} to RaiseError/PrintError messages:
• DBD::foo::execute failed: duplicate key [for ``insert
…’’]
• for statement handles it also includes the $h->{ParamValues} if available.
• Makes error messages much more useful. Better than using $DBI::lasth
• Many drivers should enable it by default. Inherited by child handles.
Custom Error Handling
• Don’t want to just Print or Raise an Error?
– Now you can Handle it as well…
$h->{HandleError} = sub { … };
• The HandleError code
– is called just before PrintError/RaiseError are handled
– it’s passed
• the error message string that RaiseError/PrintError would use
• the DBI handle being used
• the first value being returned by the method that failed (typically undef)
– if it returns false then RaiseError/PrintError are checked and acted upon
as normal
$h->{HandleError} = sub {
my ($errmsg, $h) = @_;
return 0 unless $errmsg =~ /^\S+ fetchrow_arrayref failed:/;
return 0 unless $h->err == 1234; # the error to 'hide'
$h->set_err(0,""); # turn off the error
$_[2] = [ ... ]; # supply alternative return value by altering
parameter
return 1;
};
• Only works for methods which return a single value and is hard to make
reliable (avoiding infinite loops, for example) and so isn't recommended for
general use!
• If you find a good use for it then please let me know.
Information and Warnings
• Drivers can indicate Information and Warning states in addition to Error states
– Uses false-but-defined values of $h->err and $DBI::err
– Zero "0" indicates a "warning"
– Empty "" indicates "success with information" or other messages from database
• Drivers should use $h->set_err(…) method to record info/warn/error states
– implements logic to correctly merge multiple info/warn/error states
– info/warn/error messages are appended to errstr with a newline
– $h->{ErrCount} attribute is incremented whenever an error is recorded
• The $h->{HandleSetErr} attribute can be used to influence $h->set_err()
– A code reference that's called by set_err and can edit its parameters
– So can promote warnings/info to errors or demote/hide errors etc.
– Called at point of error from within driver, unlike $h->{HandleError}
• The $h->{PrintWarn} attribute acts like $h->{PrintError} but for warnings
– Default is on
Transactions - Eh?
• Far more than just locking
• The A.C.I.D. test
• Atomicity - Consistency - Isolation - Durability
• True transactions give true safety
• even from power failures and system crashes!
• Incomplete transactions are automatically rolled-back by the
database server when it's restarted.
• Also removes burden of undoing incomplete changes
• Hard to implement (for the vendor)
• and can have significant performance cost
• A very large topic worthy of an entire tutorial
Transactions - Life Preservers
• Text Book:
• system crash between one bank account being debited and another being credited.
• Dramatic:
• power failure during update on 3 million rows when only part way through.
• Real-world:
• complex series of inter-related updates, deletes and inserts on many separate tables
fails at the last step due to a duplicate unique key on an insert.
• Other points:
• Always explicitly commit or rollback before disconnect
• Destroying a connected $dbh should always rollback
• END blocks can catch exit-without-disconnect to rollback and disconnect
cleanly
• You can use ($dbh && $dbh->{Active}) to check if still connected
Bulk Operations
• Execute a statement for multiple values
$sth = $dbh->prepare("insert into table (foo,bar) values
(?,?)");
$tuples = $sth->execute_array(\%attr,
\@list_of_param_array_refs);
• returns count of executions, even ones that failed, and not rows-affected
• Inserting LONGs
– The limitations of string literals
– The benefits of placeholders
“Power”
Sybase::DBlib Native API
ODBC/
DBI Win32::ODBC JDBC
and and
Drivers Precompilers drivers
Command Line
TCL
(oratcl, sybtcl)
Please note: This chart is correct only for some values of correct! “Effort”