Using Perl and DBIDBD With Informix Databases Darryl
Using Perl and DBI/DBD With Informix Databases Darryl Priest Piper Rudnick LLP darryl. priest@piperrudnick. com Using Perl & DBI/DBD: : Informix
Agenda • • • What is DBI & DBD: : Informix? Why Perl? Why DBI/DBD: : Informix? Perl Basics Database Connections Static SQLs Fetching Data Other SQLs Putting It All Together Supported, But Not Covered Using Perl & DBI/DBD: : Informix 2
Why Perl? • • • Easy To Start Many Modules Available Autovivification Garbage Collection Text Manipulation & Regular Expressions Portability Easy Access And Interaction With System Commands Hashes CGI Speed Code Reusability Using Modules Using Perl & DBI/DBD: : Informix 3
Why DBI/DBD: : Informix? • • • Very well tested Data Fetch Method Choices IBM/Informix Support Portability Database Connections Using Perl & DBI/DBD: : Informix 4
Perl Basics • • #!/usr/bin/perl -w Variable Types (scalars, arrays, hashes, references) use DBI; use strict; Variable Scope TMTOWTDI q# and qq# Using Perl & DBI/DBD: : Informix 5
DBI Generalizations • Database connections are referred to as database handles usually named $dbh, etc. • Select SQLs usually follow the pattern prepare, execute, fetch, fetch … • Non-select SQLs usually follow the pattern prepare, execute, Using Perl & DBI/DBD: : Informix 6
Database Connections $dbh = DBI->connect($data_source, $username, $auth, %attr); $dbh = DBI->connect(“DBI: Informix: $database", '', { Auto. Commit => 0, Print. Error => 1 }); my $pm_dbh = DBI->connect("DBI: Informix: pmdata") or die "PMDatabase Open Error: $DBI: : errstrn"; $pm_dbh->{Chop. Blanks} = 1; $pm_dbh->{Auto. Commit} = 1; $pm_dbh->{Print. Error} = 1; $pm_dbh->{Raise. Error} = 1; my $ps_dbh = DBI->connect("DBI: Informix: hrdb@remote_tcp") or die "People. Soft Database Open Error: $DBI: : errstrn"; $dbh->disconnect(); Using Perl & DBI/DBD: : Informix 7
Code Notes • use strict pragma is most likely in use although variables may not be defined in the code shown. • Most SQLs are from either an Elite or People. Soft database. • Where error checking is not shown it is being handled automatically by DBI and DBD: : Informix. (Raise. Error and Print. Error). Using Perl & DBI/DBD: : Informix 8
Static SQLs $el_dbh->do("set isolation to dirty read; "); $sql = qq#create temp table temp_teamleader (tkinit char(5), teamleader char(5) ) with no log in tempdbs; #; $el_dbh->do($sql); $sql = qq#insert into temp_teamleader(tkinit, teamleader) select udjoin, udvalue from udf where udf. udtype = "TK" and udfindex = 55; #; my $ins_teamleader_sth = $el_dbh->prepare($sql); $ins_teamleader_sth->execute(); $el_dbh->do("create index teamldr_idx 1 on temp_teamleader(tkinit); "); $el_dbh->do("update statistics high for table temp_teamleader; "); Using Perl & DBI/DBD: : Informix 9
Fetching Data (Static Declarations) $sql = qq#select rttype, rtdesc from crltype order by 1; #; my $get_party_type_sth = $el_dbh->prepare($sql) or die "Preparing get_party_type_sth, Error: $DBI: : errstrn"; Using Perl & DBI/DBD: : Informix 10
Fetching Data (Declarations With Placeholders) $sql = qq#select emplid, primary_contact, contact_name, relationship, phone from ps_emergency_cntct where emplid = ? order by primary_contact desc, contact_name; #; my $get_emerg_contact_sth = $ps_dbh->prepare_cached($sql) or die "Preparing get_emerg_contact_sth, Error: $DBI: : errstrn"; Using Perl & DBI/DBD: : Informix 11
Fetching Data (Static Execution) $sql = qq#select rttype, rtdesc from crltype order by 1; #; my $get_party_type_sth = $el_dbh->prepare($sql) or die "Preparing get_party_type_sth, Error: $DBI: : errstrn"; $get_party_type_sth->execute(); Using Perl & DBI/DBD: : Informix 12
Fetching Data (Execution With Placeholders) $sql = qq#select emplid, primary_contact, contact_name, relationship, phone from ps_emergency_cntct where emplid = ? order by primary_contact desc, contact_name; #; my $get_emerg_contact_sth = $ps_dbh->prepare_cached($sql) or die "Preparing get_emerg_contact_sth, Error: $DBI: : errstrn"; $get_emerg_contact_sth->execute(“ 12345”) or die "Executing get_emerg_contact_sth, Error: $DBI: : errstrn"; • Or even better, using a scalar my $In. Emplid = “ 12345”; $get_emerg_contact_sth->execute($In. Emplid) or die "Executing get_emerg_contact_sth, Error: $DBI: : errstrn"; Using Perl & DBI/DBD: : Informix 13
Processing Fetched Data $sql = qq#select rttype, rtdesc from crltype order by 1; #; my $get_party_type_sth = $el_dbh->prepare($sql); $get_party_type_sth->execute(); my (@Row, $Party. Types); while ( @Row = $get_party_type_sth->fetchrow_array() ) { $Party. Types{$Row[0]} = $Row[1]; } • Same thing using hash references my ($Row, %Party. Types); while ( $Row = $get_party_type_sth->fetchrow_hashref() ) { $Party. Types{$Row->{rttype}} = $Row->{rtdesc}; } Using Perl & DBI/DBD: : Informix 14
Processing Fetched Data, continued $sql = qq#select count(*), sum(lamount) from ledger where linvoice = ? and lzero != "Y"; #; my $check_sth = $dbh->prepare($sql); $check_sth->execute($Invoice. Number); ($Not. Paid, $Amount) = $check_sth->fetchrow_array(); if ( $Not. Paid > 0 ) { print "Not Paid, $Not. Paid Ledger Items"; } else { print "Paid, Moving. . . "; } Using Perl & DBI/DBD: : Informix 15
Processing Fetched Data, continued $sql = qq#select fieldname, fieldvalue, xlatlongname, xlatshortname from xlattable x where effdt = ((select max(effdt) from xlattable x 1 where x 1. fieldname = x. fieldname and x 1. fieldvalue = x. fieldvalue and x 1. effdt <= TODAY and x 1. language_ cd = "ENG")) and x. fieldname in ("COMP_FREQUENCY", "EMPL_TYPE", "REG_TEMP", "ACTION", "MILITARY_STATUS", "ETHNIC_GROUP", "REFERRAL_SOURCE", "FULL_PART_TIME", "OFFICER_CD", "FLSA_STATUS", "SEX", "MAR_STATUS", "EMPL_STATUS", "HIGHEST_EDUC_LVL", "PHONE_TYPE") and x. language_ cd = "ENG" order by 1, 2; #; my $get_xlat_sth = $ps_dbh->prepare($sql); $get_xlat_sth->execute(); my ($Xlat. Row); while ($Xlat. Row = $get_xlat_sth->fetchrow_hashref()) { $Xlat. Row->{fieldname} } { $Xlat. Row->{fieldvalue} } = { longname => $Xlat. Row->{xlatlongname}, shortname => $Xlat. Row->{xlatshortname} }; } Using Perl & DBI/DBD: : Informix 16
Processing Fetched Data, continued • Previous example loads the %Xlat hash with values such as: – – – $Xlat{MAR_STATUS}->{A}->{longname} = “Head of Household” $Xlat{MAR_STATUS}->{A}->{shortname} = “Hd Hsehld” $Xlat{MAR_STATUS}->{M}->{longname} = “Married”; $Xlat{MAR_STATUS}->{M}->{shortname} = “Married”; $Xlat{SEX}->{F}->{longname} = “Female”; $Xlat{SEX}->{M}->{shortname} = “Male”; • Hash values are referenced with: – – $Xlat{SEX}->{$Active->{sex}}->{shortname} $Xlat{MAR_STATUS}->{$Active->{mar_status}}->{longname} Using Perl & DBI/DBD: : Informix 17
Binding Columns To Fetch Data $sql = qq#select pcode, pdesc from praccode where pdesc is not null order by 1; #; my $get_praccodes_sth = $el_dbh->prepare($sql); $get_praccodes_sth->execute(); my ($b_pcode, $b_pdesc); $get_praccodes_sth->bind_columns(undef, $b_pcode, $b_pdesc); while ( $get_praccodes_sth->fetch ) { $Prac. Codes{$b_pcode} = $b_pdesc; } Using Perl & DBI/DBD: : Informix 18
Binding Columns Continued $sql = qq#select cmatter, to_char(cdisbdt, '%m/%d/%Y') cdisbdt, cbillamt from cost where cmatter is not null; #; my $get_cost_sth = $el_dbh->prepare($sql); my (%Cost. Row); $get_cost_sth->bind_columns(undef, $Cost. Row{cmatter}, $Cost. Row{cdisbdt}, $Cost. Row{cbillamt}); while ( $get_cost_sth->fetch() ) { … Do Something With %Cost. Row Hash Values … } Alternate syntax $sth->bind_col($col_num, $col_variable); $sth->bind_columns(@list_of_refs_to_vars_to_bind); Using Perl & DBI/DBD: : Informix 19
Inserting Rows • Declare The Insert Statement Handle $sql = qq#insert into winoutstat(wouser, wouser 1, woreport, wotitle, wofile, wodate 0, wotime 0, wostat 1, wopid) values(? , ? , ? ); #; my $ins_win_sth = $el_dbh->prepare_cached($sql); • Do The Insert $ins_win_sth->execute($Logon, "Reminders", $Title, $File. Name, $Out. Date, $Out. Time, "RUNNING", $$); my @Errd = @{$ins_win_sth->{ix_sqlerrd}}; $Hold{woindex} = $Errd[1]; Alternate syntax $Hold{woindex} = $ins_win_sth->{ix_sqlerrd}[1]; Using Perl & DBI/DBD: : Informix 20
Deleting Data • Declare The Delete Statement Handle $sql = qq#delete from pm_reminders where matter_num = ? and location = ? and run_date = TODAY and run_by = ? ; #; my $del_remind_sth = $el_dbh->prepare($sql); • Delete Row(s) Based On Passed Parameters $del_remind_sth->execute($Mat. Row->{mmatter}, $Hold{location}, $This. Logon); Using Perl & DBI/DBD: : Informix 21
Using DBI With CGI sub show_elite_files { print header(), start_html(-title=>"User File Manager", -style=>{'src'=>'/styles/in. Site_Style. css'}); $sql = qq#select woindex, woreport, wotitle, wodate 0, wotime 0, wodate 1, wotime 1, wodesc 1 from winoutstat where (wostat 1 = "COMPLETE" or wostat 2 = "COMPLETE") and wouser = ? order by wodate 0 desc, wotime 0; #; my $get_files_sth = $el_dbh->prepare($sql); $get_files_sth->execute($This. Logon); my ($File. Row, $View. Link, $Show. Date, $Count); $Count = 0; while ( $File. Row = $get_files_sth->fetchrow_hashref() ) { $View. Link = a({-href=>“getfiles. cgi? Session=${In. Session}&File. Num=$File. Row->{woindex}"}, "Archive"); $Show. Date = "$File. Row->{wodate 0} $File. Row->{wotime 0}"; if ( $File. Row->{wodate 0} ne $File. Row->{wodate 1} ) { $Show. Date. = " - ". $File. Row->{wodate 1}. " ". $File. Row->{wotime 1}; } elsif ( $File. Row->{wotime 0} ne $File. Row->{wotime 1} ) { $Show. Date. = "-". $File. Row->{wotime 1}; } Using Perl & DBI/DBD: : Informix 22
Using DBI With CGI, continued ### If This Is The First File Printed, Print The Headers First if ( $Count == 0 ) { my $This. Name = get_user_name($This. Logon); print start_table({-width=>'100%%', -border=>1, -cellpadding=>'5'}), $New. Line, Tr ( th ({-colspan=>'5'}, h 4("Elite Report Files For User $This. Name") ) ), Tr ( th ( " " ), th ( h 4("Report") ), th ( h 4("Title") ), th ( h 4("Report Date") ), th ( h 4("Report Description") ) ); } ### Print Information For This File print Tr ( td ({-align=>'center'}, "$View. Link"), td ({-align=>'left'}, "$File. Row->{woreport}"), td ({-align=>'left'}, "$File. Row->{wotitle}"), td ({-align=>'center'}, "$Show. Date"), td ({-align=>'left'}, "$File. Row->{wodesc 1}") ); $Count++; } Using Perl & DBI/DBD: : Informix 23
Using DBI With CGI, continued ### If No File Rows Found Show Error & Back Button, Otherwise ### Print The End Of The Table if ( $Count == 0 ) { print br, textfield(-name=>'Process. Message', -size=>'80', -style=>$Error. Style, -maxlength=>'80', -value=>"No Files Were Found In Your Elite File Manager!"), br; print_back(); return; } else { print end_table(); } print end_html(); } ### End Of Sub. Routine show_elite_files Using Perl & DBI/DBD: : Informix 24
Using DBI With CGI, continued <HTML><HEAD><TITLE>User File Manager</TITLE> <LINK REL="stylesheet" HREF="/styles/in. Site_Style. css"> </HEAD><BODY> <TABLE BORDER="1" CELLPADDING="5" WIDTH="100%%"> <TR><TH COLSPAN="5"><H 4>Elite Report Files For User Darryl Priest</H 4></TH></TR> <TR><TH> </TH> <TH><H 4>Report</H 4></TH><H 4>Title</H 4></TH> <TH><H 4>Report Date</H 4></TH> <TH><H 4>Report Description</H 4></TH> </TR> <TR><TD ALIGN="center"><A HREF=" getfiles. cgi? Session=? &File. Num=? ">Archive</A></TD> <TD ALIGN="left">Time Batch Report</TD> <TD ALIGN="left"></TD> <TD ALIGN="center">10/01/2002 09: 09</TD> <TD ALIGN="left">1 batches processed. 1 reported. </TD></TR> <TR><TD ALIGN="center"> <A HREF="getfiles. cgi? Session=? &File. Num=? ">Archive</A></TD> <TD ALIGN="left">Time Batch Finalization</TD> <TD ALIGN="left"></TD> <TD ALIGN="center">10/01/2002 09: 09</TD> <TD ALIGN="left">1 batches processed. 1 finalized. </TD></TR> </TABLE></BODY></HTML> Using Perl & DBI/DBD: : Informix 25
Using DBI With CGI, continued Using Perl & DBI/DBD: : Informix 26
Defining Reusable Code #!/usr/bin/perl package PMData_Lib; use strict; require Exporter; use vars qw($VERSION @ISA @EXPORT); $VERSION = 0. 01; @ISA = qw(Exporter); @EXPORT = qw(get_names); sub get_names { my ($Use. Dbh, $Emplid) = @_; my (@Ret. Vals); my $sql = qq#select name_first 2 last, name_last 2 first_s, first_name, last_name, short_name from pm_employees_v where emplid_s = ? ; #; my $get_names_sth = $Use. Dbh->prepare_cached($sql); $get_names_sth->execute($Emplid); @Ret. Vals = $get_names_sth->fetchrow_array(); return @Ret. Vals; } 1; Using Perl & DBI/DBD: : Informix 27
Using Your Module #!/usr/bin/perl –w use DBI; use strict; use lib q{/custom/perl/modules/}; use PMData_Lib; ………… if ( defined $Emplid ) { my (@Ret. Names) = PMData_Lib: : get_names($pm_dbh, $Emplid); if ( defined $Ret. Names[0] ) { $Name = $Ret. Names[0]; } else { $Name = “Name Unknown”; } } Using Perl & DBI/DBD: : Informix 28
Copy Table Example dbschema -d son_db -t praccode -p all DBSCHEMA Schema Utility INFORMIX-SQL Version 7. 31. UC 2 X 3 Copyright (C) Informix Software, Inc. , 1984 -1998 Software Serial Number AAC#J 741761 grant dba to "elite"; grant dba to "public"; { TABLE "elite". praccode row size = 114 number of columns = 3 index size = 9 } create table "elite". praccode ( pcode smallint, pdesc char(48), pglmask char(64) ); revoke all on "elite". praccode from "public"; create unique index "elite". i_pra 1 on "elite". praccode (pcode); grant grant select on "elite". praccode to "public" as "elite"; update on "elite". praccode to "public" as "elite"; insert on "elite". praccode to "public" as "elite"; delete on "elite". praccode to "public" as "elite"; index on "elite". praccode to "public" as "elite"; Using Perl & DBI/DBD: : Informix 29
Copy Table Example, continued #!/usr/bin/perl -w ############################## ### Program Name: copy_table. pl ### Author: Darryl Priest ### Description: This script will copy a table from ### one database to another. ############################## $| =1; use DBI; use Getopt: : Std; use strict; use vars qw($opt_d $opt_n $opt_o $opt_s $opt_t); my $Usage = qq# Usage: copy_table. pl [ -d DBSpace -n New DB -o Old DB < -s Suffix > -t Table ] -d -n -o -s -t DBSpace In Which To Write The New Table Database To Which The New Table Will Be Copied Database From Which The Table Will Be Copied Optional Suffix To Append To The New Table Name To Be Copied #; ############################## ### Define Usage Variables And Get From Passed Options ############################## my ($Old. DB, $New. DB, $Old. Table, $Suffix, $New. Table, $DBSpace); getopts('d: n: o: s: t: '); if ( defined $opt_o ) { $Old. DB = $opt_o; } else { print $Usage; exit; } Using Perl & DBI/DBD: : Informix 30
Copy Table Example, continued if ( defined $opt_n ) { $New. DB = $opt_n; } else { print $Usage; exit; } if ( defined $opt_t ) { $Old. Table = $opt_t; } else { print $Usage; exit; } if ( defined $opt_d ) { $DBSpace = $opt_d; } else { print $Usage; exit; } if ( defined $opt_s ) { $Suffix = $opt_s; } else { $Suffix = ""; } if ( length($Suffix) > 0 ) { $New. Table = "${Old. Table}_${Suffix}"; } else { $New. Table = $Old. Table; } print '>' x 60, "n"; print "Will Move $Old. DB: $Old. Table -> $New. DB: $New. Tablen"; ############################## ### Use DBSchema To Get The Schema Of The Old Table ############################## print "n. Getting DBSchema For $Old. DB: $Old. Table At ", `date +'%D %r'`; if ( ! $ENV{INFORMIXDIR} ) { $ENV{INFORMIXDIR} = "/usr/informix"; } open (SCHEMA, "$ENV{INFORMIXDIR}/bin/dbschema -d $Old. DB -t $Old. Table -p all |") or die "Error Opening DBSchema, $!"; Using Perl & DBI/DBD: : Informix 31
Copy Table Example, continued ############################## ### Read Past The Beginning Headers Returned By DBSchema ############################## while (<SCHEMA>) { last if ( $_ =~ /}/ ); } ############################## ### Get The SQL From DBSchema That Needs To Be Executed ############################## my @Sqls = ( ); my $Run. Sql = ""; while (<SCHEMA>) { ############################# ### Skip Blank Lines ############################# next if /^$/; ############################# ### Replace All Occurances Of Old Table With New Table ############################# s/$Old. Table/$New. Table/g; ############################# ### Append This Line From DBSchema To The Current SQL ############################# $Run. Sql. = " $_"; Using Perl & DBI/DBD: : Informix 32
Copy Table Example, continued ############################# ### If This Line Ends A SQL Statement ############################# if ( /; / ) { ########################### ### If This Statement Is A Create Table, Append ### DBSpace And Lock Mode ########################### if ( $Run. Sql =~ /createstable/ ) { $Run. Sql =~ s/)s*; /) in $DBSpace lock mode row; /; } ########################### ### If This Statement Is A Create Index, Change The ### Index Name To Reflect The New Table Name ########################### if ( $Run. Sql =~ /creates*(unique)*s*index/ ) { $Run. Sql =~ s/idx([1 -9]+)/idx$1${Suffix}/; } ########################### ### Save This SQL To Later Execution ########################### push (@Sqls, $Run. Sql); $Run. Sql = ""; } } close SCHEMA; Using Perl & DBI/DBD: : Informix 33
Copy Table Example, continued ############################## ### Open Connection To The New Database ############################## my $to_dbh = DBI->connect("DBI: Informix: $New. DB") or die "$New. DB Database Open Error: $DBI: : errstrn"; $to_dbh->{Chop. Blanks} = 1; $to_dbh->{Auto. Commit} = 1; $to_dbh->{Print. Error} = 1; $to_dbh->{Raise. Error} = 1; ############################## ### Open Connection To The Old Database ############################## my $Informix. TCP = $ENV{INFORMIXSERVER}; $Informix. TCP =~ s/_shm/_tcp/; my $from_dbh = DBI->connect("DBI: Informix: $Old. DB@$Informix. TCP") or die "$Old. DB Database Open Error: $DBI: : errstrn"; $from_dbh->{Chop. Blanks} = 1; $from_dbh->{Auto. Commit} = 1; $from_dbh->{Print. Error} = 1; $from_dbh->{Raise. Error} = 1; ############################## ### Drop The New Table From The New Database, Just In Case ############################## print "n. Dropping New Table(Just In Case) At ". `date +'%D %r'`; eval { $to_dbh->do("drop table $New. Table; "); }; Using Perl & DBI/DBD: : Informix 34
Copy Table Example, continued ############################## ### Build The New Table In The New Database ############################## print "n. Building New Table At ". `date +'%D %r'`; print "Create Table SQL: n$Sqls[0]n"; $to_dbh->do($Sqls[0]); ############################## ### Build Statement Handle To Select From Old Table ############################## $Run. Sql = qq#select * from $Old. Table; #; my $get_rows_sth = $from_dbh->prepare($Run. Sql); $get_rows_sth->execute(); ############################## ### Build Statement Handle To Insert Into New Table ############################## $Run. Sql = "insert into $New. Table values (". "? , " x $get_rows_sth->{NUM_OF_FIELDS}; chop($Run. Sql); $Run. Sql. = ")"; my $ins_rows_sth = $to_dbh->prepare($Run. Sql); ############################## ### Copy Rows From Old To New Table ############################## print "n. Copying Rows From Old Table To New Table At ". `date +'%D %r'`; Using Perl & DBI/DBD: : Informix 35
Copy Table Example, continued my ($Row); my $Count = 1; while ( $Row = $get_rows_sth->fetchrow_arrayref() ) { if ( ($Count % 10000) == 0 ) { print "Copied $Count Rows At ". `date +'%D %r'`; } $ins_rows_sth->execute(@$Row); $Count++; } ############################## ### Build Indexes And Grant Permissions On New Table ############################## my ($x); for ( $x = 1; $x <= $#Sqls; $x++ ) { print "n. Running SQL At ". `date +'%D %r'`; print "$Sqls[$x]n"; $to_dbh->do($Sqls[$x]); } ############################## ### Update Statistics For New Table ############################## print "Starting Updating Statistics For $New. Table At ", `date +'%D %r'`; $to_dbh->do("update statistics low for table $New. Table; "); $from_dbh->disconnect(); $to_dbh->disconnect(); print "n. Finished Moving $Old. DB: $Old. Table -> $New. DB: $New. Table At ", `date +'%D %r'`; print '<' x 60, "n"; Using Perl & DBI/DBD: : Informix 36
Supported, But Not Covered • Accessing The Informix SQLCA Values – – – $sqlcode $sqlerrm $sqlerrp @sqlerrd @sqlwarn = = = $sth->{ix_sqlcode}; $sth->{ix_sqlerrm}; $sth->{ix_sqlerrp}; @{$sth->{ix_sqlerrd}}; @{$sth->{ix_sqlwarn}}; • Transactions using $dbh->commit(); and $dbh->rollback(); • Do With Parameters – $dbh->do($stmt, undef, @parameters); – $dbh->do($stmt, undef, $param 1, $param 2); • $dbh->quote($string) • $sth->finish and undef $sth • Blob fields. Using Perl & DBI/DBD: : Informix 37
Supported, But Not Covered, continued • • • $sth attributes, NUM_OF_FIELDS, NAME, etc. DBI->trace($level, $tracefile); Fetch methods selectrow_array() & selectall_array() $dbh->func() Statement Handles For Update $st 1 = $dbh->prepare("SELECT * FROM Some. Table FOR UPDATE"); $wc = "WHERE CURRENT OF $st 1 ->{ Cursor. Name}"; $st 2 = $dbh->prepare("UPDATE Some. Table SET Some. Column = ? $wc"); $st 1 ->execute; $row = $st 1 ->fetch; $st 2 ->execute("New Value"); • $sth->rows(); Using Perl & DBI/DBD: : Informix 38
Additional Information • dbi. perl. org/ - DBI Home Page • www. perl. com - Perl – www. perl. com/lpt/a/1999/10/DBI. html • www. perl. org • www. cpan. org/ - Comprehensive Perl Archive Network • www. activestate. com • perldoc DBI – DBI Man Pages • perldoc DBD: : Informix – DBD: : Informix Man Pages • Programming Perl by Larry Wall, Tom Christiansen & Randal Schwartz • Programming the Perl DBI, by Alligator Descartes and Tim Bunce • Learning Perl by Randal Schwartz Using Perl & DBI/DBD: : Informix 39
Thanks! • To the authors who brought us: – Perl • Larry Wall – DBI • Tim Bunce • Alligator Descartes – DBD: : Informix • Jonathan Leffler Using Perl & DBI/DBD: : Informix 40
- Slides: 40