diff -u DBI-1.14/Changes DBI-1.30/Changes --- DBI-1.14/Changes Wed Jun 14 21:04:11 2000 +++ DBI-1.30/Changes Thu Jul 18 15:24:02 2002 @@ -1,4 +1,413 @@ -Changes in DBI 1.14, 14th June 1999 +=head1 NAME + +DBI::Changes - List of significant changes to the DBI + +=cut + +Need to add docs for DbTypeSubclass (ala DBIx::AnyDBD) +Move FIRSTKEY/NEXTKEY/EXISTS/DELETE? to XS (and pureperl) + + Changes for driver authors, not required but strongly recommended: + Change DBIS to DBIc_DBISTATE(imp_xxh) [or imp_dbh, imp_sth etc] + Change DBILOGFP to DBIc_LOGPIO(imp_xxh) [or imp_dbh, imp_sth etc] + Any function from which all instances of DBIS and DBILOGFP are + removed can also probably have dPERLINTERP removed (a good thing). + +$dbh->{Statement} can be wrong because fetch doesn't update value +maybe imp_dbh holds imp_sth (or inner handle) of last sth method +called (if not DESTROY) and sth outer DESTROY clears it (to reduce ref count) +Then $dbh->{LastSth} would work (returning outer handle if valid). +Then $dbh->{Statement} would be the same as $dbh->{LastSth}->{Statement} +Also $dbh->{ParamValues} would be the same as $dbh->{LastSth}->{ParamValues}. + +=head1 CHANGES + +=head2 Changes in DBI 1.30, 18th July 2002 + + Fixed problems with selectrow_array, selectrow_arrayref, and + selectall_arrayref introduced in DBI 1.29. + Fixed FETCHing a handle attribute to not clear $DBI::err etc (broken in 1.29). + Fixed core dump at trace level 9 or above. + Fixed compilation with perl 5.6.1 + ithreads (i.e. Windows). + Changed definition of behaviour of selectrow_array when called in a scalar + context to match fetchrow_array. + Corrected selectrow_arrayref docs which showed selectrow_array thanks to Paul DuBois. + +=head2 Changes in DBI 1.29, 15th July 2002 + + NOTE: This release changes the specified behaviour for the + : fetchrow_array method when called in a scalar context: + : The DBI spec used to say that it would return the FIRST field. + : Which field it returns (i.e., the first or the last) is now undefined. + : This does not affect statements that only select one column, which is + : usually the case when fetchrow_array is called in a scalar context. + : FYI, this change was triggered by discovering that the fetchrow_array + : implementation in Driver.xst (used by most compiled drivers) + : didn't match the DBI specification. Rather than change the code + : to match, and risk breaking existing applications, I've changed the + : specification (that part was always of dubious value anyway). + + NOTE: Future versions of the DBI may not support for perl 5.5 much longer. + : If you are still using perl 5.005_03 you should be making plans to + : upgrade to at least perl 5.6.1, or 5.8.0. Perl 5.8.0 is due to be + : released in the next week or so. (Although it's a "point 0" release, + : it is the most throughly tested release ever.) + + Added XS/C implementations of selectrow_array, selectrow_arrayref, and + selectall_arrayref to Driver.xst. See DBI 1.26 Changes for more info. + Removed support for the old (fatally flawed) "5005" threading model. + Added support for new perl 5.8 iThreads thanks to Gerald Richter. + (Threading support and safety should still be regarded as beta + quality until further notice. But it's much better than it was.) + Updated the "Threads and Thread Safety" section of the docs. + The trace output can be sent to STDOUT instead of STDERR by using + "STDOUT" as the name of the file, i.e., $h->trace(..., "STDOUT") + Added pointer to perlreftut, perldsc, perllol, and perlboot manuals + into the intro section of the docs, suggested by Brian McCain. + Fixed DBI::Const::GetInfo::* pod docs thanks to Zack Weinberg. + Some changes to how $dbh method calls are treated by DBI::Profile: + Meta-data methods now clear $dbh->{Statement} on entry. + Some $dbh methods are now profiled as if $dbh->{Statement} was empty + (because thet're unlikely to actually relate to its contents). + Updated dbiport.h to ppport.h from perl 5.8.0. + Tested with perl 5.5.3 (vanilla, Solaris), 5.6.1 (vanilla, Solaris), and + perl 5.8.0 (RC3@17527 with iThreads & Multiplicity on Solaris and FreeBSD). + +=head2 Changes in DBI 1.28, 14th June 2002 + + Added $sth->{ParamValues} to return a hash of the most recent + values bound to placeholders via bind_param() or execute(). + Individual drivers need to be updated to support it. + Enhanced ShowErrorStatement to include ParamValues if available: + "DBD::foo::st execute failed: errstr [for statement ``...'' with params: 1='foo']" + Further enhancements to DBD::PurePerl accuracy. + +=head2 Changes in DBI 1.27, 13th June 2002 + + Fixed missing column in C implementation of fetchall_arrayref() + thanks to Philip Molter for the prompt reporting of the problem. + +=head2 Changes in DBI 1.26, 13th June 2002 + + Fixed t/40profile.t to work on Windows thanks to Smejkal Petr. + Fixed $h->{Profile} to return undef, not error, if not set. + Fixed DBI->available_drivers in scalar context thanks to Michael Schwern. + + Added C implementations of selectrow_arrayref() and fetchall_arrayref() + in Driver.xst. All compiled drivers using Driver.xst will now be + faster making those calls. Most noticable with fetchall_arrayref for + many rows or selectrow_arrayref with a fast query. For example, using + DBD::mysql a selectrow_arrayref for a single row using a primary key + is ~20% faster, and fetchall_arrayref for 20000 rows is twice as fast! + Drivers just need to be recompiled and reinstalled to enable it. + The fetchall_arrayref speed up only applies if $slice parameter is not used. + Added $max_rows parameter to fetchall_arrayref() to optionally limit + the number of rows returned. Can now fetch batches of rows. + Added MaxRows attribute to selectall_arrayref() + which then passes it to fetchall_arrayref(). + Changed selectrow_array to make use of selectrow_arrayref. + Trace level 1 now shows first two parameters of all methods + (used to only for that for some, like prepare,execute,do etc) + Trace indicator for recursive calls (first char on trace lines) + now starts at 1 not 2. + + Documented that $h->func() does not trigger RaiseError etc + so applications must explicitly check for errors. + DBI::Profile with DBI_PROFILE now shows percentage time inside DBI. + HandleError docs updated to show that handler can edit error message. + HandleError subroutine interface is now regarded as stable. + +=head2 Changes in DBI 1.25, 5th June 2002 + + Fixed build problem on Windows and some compiler warnings. + Fixed $dbh->{Driver} and $sth->{Statement} for driver internals + These are 'inner' handles as per behaviour prior to DBI 1.16. + Further minor improvements to DBI::PurePerl accuracy. + +=head2 Changes in DBI 1.24, 4th June 2002 + + Fixed reference loop causing a handle/memory leak + that was introduced in DBI 1.16. + Fixed DBI::Format to work with 'filehandles' from IO::Scalar + and similar modules thanks to report by Jeff Boes. + Fixed $h->func for DBI::PurePerl thanks to Jeff Zucker. + Fixed $dbh->{Name} for DBI::PurePerl thanks to Dean Arnold. + + Added DBI method call profiling and benchmarking. + This is a major new addition to the DBI. + See $h->{Profile} attribute and DBI::Profile module. + For a quick trial, set the DBI_PROFILE environment variable and + run your favourite DBI script. Try it with DBI_PROFILE set to 1, + then try 2, 4, 8, 10, and -10. Have fun! + + Added execute_array() and bind_param_array() documentation + with thanks to Dean Arnold. + Added notes about the DBI having not yet been tested with iThreads + (testing and patches for SvLOCK etc welcome). + Removed undocumented Handlers attribute (replaced by HandleError). + Tested with 5.5.3 and 5.8.0 RC1. + +=head2 Changes in DBI 1.23, 25th May 2002 + + Greatly improved DBI::PurePerl in performance and accuracy. + Added more detail to DBI::PurePerl docs about what's not supported. + Fixed undef warnings from t/15array.t and DBD::Sponge. + +=head2 Changes in DBI 1.22, 22nd May 2002 + + Added execute_array() and bind_param_array() with special thanks + to Dean Arnold. Not yet documented. See t/15array.t for examples. + All drivers now automatically support these methods. + Added DBI::PurePerl, a transparent DBI emulation for pure-perl drivers + with special thanks to Jeff Zucker. Perldoc DBI::PurePerl for details. + Added DBI::Const::GetInfo* modules thanks to Steffen Goeldner. + Added write_getinfo_pm utility to DBI::DBD thanks to Steffen Goeldner. + Added $allow_active==2 mode for prepare_cached() thanks to Stephen Clouse. + + Updated DBI::Format to Revision 11.4 thanks to Tom Lowery. + Use File::Spec in Makefile.PL (helps VMS etc) thanks to Craig Berry. + Extend $h->{Warn} to commit/rollback ineffective warning thanks to Jeff Baker. + Extended t/preparse.t and removed "use Devel::Peek" thanks to Scott Hildreth. + Only copy Changes to blib/lib/Changes.pm once thanks to Jonathan Leffler. + Updated internals for modern perls thanks to Jonathan Leffler and Jeff Urlwin. + Tested with perl 5.7.3 (just using default perl config). + + Documentation changes: + + Added 'Catalog Methods' section to docs thanks to Steffen Goeldner. + Updated README thanks to Michael Schwern. + Clarified that driver may choose not to start new transaction until + next use of $dbh after commit/rollback. + Clarified docs for finish method. + Clarified potentials problems with prepare_cached() thanks to Stephen Clouse. + + +=head2 Changes in DBI 1.21, 7th February 2002 + + The minimum supported perl version is now 5.005_03. + + Fixed DBD::Proxy support for AutoCommit thanks to Jochen Wiedmann. + Fixed DBI::ProxyServer bind_param(_inout) handing thanks to Oleg Mechtcheriakov. + Fixed DBI::ProxyServer fetch loop thanks to nobull@mail.com. + Fixed install_driver do-the-right-thing with $@ on error. It, and connect(), + will leave $@ empty on success and holding the error message on error. + Thanks to Jay Lawrence, Gavin Sherlock and others for the bug report. + Fixed fetchrow_hashref to assign columns to the hash left-to-right + so later fields with the same name overwrite earlier ones + as per DBI < 1.15, thanks to Kay Roepke. + + Changed tables() to use quote_indentifier() if the driver returns a + true value for $dbh->get_info(29) # SQL_IDENTIFIER_QUOTE_CHAR + Changed ping() so it no longer triggers RaiseError/PrintError. + Changed connect() to not call $class->install_driver unless needed. + Changed DESTROY to catch fatal exceptions and append to $@. + + Added ISO SQL/CLI & ODBCv3 data type definitions thanks to Steffen Goeldner. + Removed the definition of SQL_BIGINT data type constant as the value is + inconsistent between standards (ODBC=-5, SQL/CLI=25). + Added $dbh->column_info(...) thanks to Steffen Goeldner. + Added $dbh->foreign_key_info(...) thanks to Steffen Goeldner. + Added $dbh->quote_identifier(...) insipred by Simon Oliver. + Added $dbh->set_err(...) for DBD authors and DBI subclasses + (actually been there for a while, now expanded and documented). + Added $h->{HandleError} = sub { ... } addition and/or alternative + to RaiseError/PrintError. See the docs for more info. + Added $h->{TraceLevel} = N attribute to set/get trace level of handle + thus can set trace level via an (eg externally specified) DSN + using the embedded attribute syntax: + $dsn = 'dbi:DB2(PrintError=1,TraceLevel=2):dbname'; + Plus, you can also now do: local($h->{TraceLevel}) = N; + (but that leaks a little memory in some versions of perl). + Added some call tree information to trace output if trace level >= 3 + With thanks to Graham Barr for the stack walking code. + Added experimental undocumented $dbh->preparse(), see t/preparse.t + With thanks to Scott T. Hildreth for much of the work. + Added Fowler/Noll/Vo hash type as an option to DBI::hash(). + + Documentation changes: + + Added DBI::Changes so now you can "perldoc DBI::Changes", yeah! + Added selectrow_arrayref & selectrow_hashref docs thanks to Doug Wilson. + Added 'Standards Reference Information' section to docs to gather + together all references to relevant on-line standards. + Added link to poop.sourceforge.net into the docs thanks to Dave Rolsky. + Added link to hyperlinked BNF for SQL92 thanks to Jeff Zucker. + Added 'Subclassing the DBI' docs thanks to Stephen Clouse, and + then changed some of them to reflect the new approach to subclassing. + Added stronger wording to description of $h->{private_*} attributes. + Added docs for DBI::hash. + + Driver API changes: + + Now a COPY of the DBI->connect() attributes is passed to the driver + connect() method, so it can process and delete any elements it wants. + Deleting elements reduces/avoids the explicit + $dbh->{$_} = $attr->{$_} foreach keys %$attr; + that DBI->connect does after the driver connect() method returns. + + +=head2 Changes in DBI 1.20, 24th August 2001 + + WARNING: This release contains two changes that may affect your code. + : Any code using selectall_hashref(), which was added in March 2001, WILL + : need to be changed. Any code using fetchall_arrayref() with a non-empty + : hash slice parameter may, in a few rare cases, need to be changed. + : See the change list below for more information about the changes. + : See the DBI documentation for a description of current behaviour. + + Fixed memory leak thanks to Toni Andjelkovic. + Changed fetchall_arrayref({ foo=>1, ...}) specification again (sorry): + The key names of the returned hashes is identical to the letter case of + the names in the parameter hash, regardless of the L + attribute. The letter case is ignored for matching. + Changed fetchall_arrayref([...]) array slice syntax specification to + clarify that the numbers in the array slice are perl index numbers + (which start at 0) and not column numbers (which start at 1). + Added { Columns=>... } and { Slice =>... } attributes to selectall_arrayref() + which is passed to fetchall_arrayref() so it can fetch hashes now. + Added a { Columns => [...] } attribute to selectcol_arrayref() so that + the list it returns can be built from more than one column per row. + Why? Consider my %hash = @{$dbh->selectcol_arrayref($sql,{ Columns=>[1,2]})} + to return id-value pairs which can be used directly to build a hash. + Added $hash_ref = $sth->fetchall_hashref( $key_field ) + which returns a ref to a hash with, typically, one element per row. + $key_field is the name of the field to get the key for each row from. + The value of the hash for each row is a hash returned by fetchrow_hashref. + Changed selectall_hashref to return a hash ref (from fetchall_hashref) + and not an array of hashes as it has since DBI 1.15 (end March 2001). + WARNING: THIS CHANGE WILL BREAK ANY CODE USING selectall_hashref()! + Sorry, but I think this is an important regularization of the API. + To get previous selectall_hashref() behaviour (an array of hash refs) + change $ary_ref = $dbh->selectall_hashref( $statement, undef, @bind); + to $ary_ref = $dbh->selectall_arrayref($statement, { Columns=>{} }, @bind); + Added NAME_lc_hash, NAME_uc_hash, NAME_hash statement handle attributes. + which return a ref to a hash of field_name => field_index (0..n-1) pairs. + Fixed select_hash() example thanks to Doug Wilson. + Removed (unbundled) DBD::ADO and DBD::Multiplex from the DBI distribution. + The latest versions of those modules are available from CPAN sites. + Added $dbh->begin_work. This method causes AutoCommit to be turned + off just until the next commit() or rollback(). + Driver authors: if the DBIcf_BegunWork flag is set when your commit or + rollback method is called then please turn AutoCommit on and clear the + DBIcf_BegunWork flag. If you don't then the DBI will but it'll be much + less efficient and won't handle error conditions very cleanly. + Retested on perl 5.4.4, but the DBI won't support 5.4.x much longer. + Added text to SUPPORT section of the docs: + For direct DBI and DBD::Oracle support, enhancement, and related work + I am available for consultancy on standard commercial terms. + Added text to ACKNOWLEDGEMENTS section of the docs: + Much of the DBI and DBD::Oracle was developed while I was Technical + Director (CTO) of the Paul Ingram Group (www.ig.co.uk). So I'd + especially like to thank Paul for his generosity and vision in + supporting this work for many years. + +=head2 Changes in DBI 1.19, 20th July 2001 + + Made fetchall_arrayref({ foo=>1, ...}) be more strict to the specification + in relation to wanting hash slice keys to be lowercase names. + WARNING: If you've used fetchall_arrayref({...}) with a hash slice + that contains keys with uppercase letters then your code will break. + (As far as I recall the spec has always said don't do that.) + Fixed $sth->execute() to update $dbh->{Statement} to $sth->{Statement}. + Added row number to trace output for fetch method calls. + Trace level 1 no longer shows fetches with row>1 (to reduce output volume). + Added $h->{FetchHashKeyName} = 'NAME_lc' or 'NAME_uc' to alter + behaviour of fetchrow_hashref() method. See docs. + Added type_info quote caching to quote() method thanks to Dean Kopesky. + Makes using quote() with second data type param much much faster. + Added type_into_all() caching to type_info(), spotted by Dean Kopesky. + Added new API definition for table_info() and tables(), + driver authors please note! + Added primary_key_info() to DBI API thanks to Steffen Goeldner. + Added primary_key() to DBI API as simpler interface to primary_key_info(). + Indent and other fixes for DBI::DBD doc thanks to H.Merijn Brand. + Added prepare_cached() insert_hash() example thanks to Doug Wilson. + Removed false docs for fetchall_hashref(), use fetchall_arrayref({}). + +=head2 Changes in DBI 1.18, 4th June 2001 + + Fixed that altering ShowErrorStatement also altered AutoCommit! + Thanks to Jeff Boes for spotting that clanger. + Fixed DBD::Proxy to handle commit() and rollback(). Long overdue, sorry. + Fixed incompatibility with perl 5.004 (but no one's using that right? :) + Fixed connect_cached and prepare_cached to not be affected by the order + of elements in the attribute hash. Spotted by Mitch Helle-Morrissey. + Fixed version number of DBI::Shell + reported by Stuhlpfarrer Gerhard and others. + Defined and documented table_info() attribute semantics (ODBC compatible) + thanks to Olga Voronova, who also implemented then in DBD::Oracle. + Updated Win32::DBIODBC (Win32::ODBC emulation) thanks to Roy Lee. + +=head2 Changes in DBI 1.16, 30th May 2001 + + Reimplemented fetchrow_hashref in C, now fetches about 25% faster! + Changed behaviour if both PrintError and RaiseError are enabled + to simply do both (in that order, obviously :) + Slight reduction in DBI handle creation overhead. + Fixed $dbh->{Driver} & $sth->{Database} to return 'outer' handles. + Fixed execute param count check to honour RaiseError spotted by Belinda Giardie. + Fixed build for perl5.6.1 with PERLIO thanks to H.Merijn Brand. + Fixed client sql restrictions in ProxyServer.pm thanks to Jochen Wiedmann. + Fixed batch mode command parsing in Shell thanks to Christian Lemburg. + Fixed typo in selectcol_arrayref docs thanks to Jonathan Leffler. + Fixed selectrow_hashref to be available to callers thanks to T.J.Mather. + Fixed core dump if statement handle didn't define Statement attribute. + Added bind_param_inout docs to DBI::DBD thanks to Jonathan Leffler. + Added note to data_sources() method docs that some drivers may + require a connected database handle to be supplied as an attribute. + Trace of install_driver method now shows path of driver file loaded. + Changed many '||' to 'or' in the docs thanks to H.Merijn Brand. + Updated DBD::ADO again (improvements in error handling) from Tom Lowery. + Updated Win32::DBIODBC (Win32::ODBC emulation) thanks to Roy Lee. + Updated email and web addresses in DBI::FAQ thanks to Michael A Chase. + +=head2 Changes in DBI 1.15, 28th March 2001 + + Added selectrow_arrayref + Added selectrow_hashref + Added selectall_hashref thanks to Leon Brocard. + Added DBI->connect(..., { dbi_connect_method => 'method' }) + Added $dbh->{Statement} aliased to most recent child $sth->{Statement}. + Added $h->{ShowErrorStatement}=1 to cause the appending of the + relevant Statement text to the RaiseError/PrintError text. + Modified type_info to always return hash keys in uppercase and + to not require uppercase 'DATA_TYPE' key from type_info_all. + Thanks to Jennifer Tong and Rob Douglas. + Added \%attr param to tables() and table_info() methods. + Trace method uses warn() if it can't open the new file. + Trace shows source line and filename during global destruction. + Updated packages: + Updated Win32::DBIODBC (Win32::ODBC emulation) thanks to Roy Lee. + Updated DBD::ADO to much improved version 0.4 from Tom Lowery. + Updated DBD::Sponge to include $sth->{PRECISION} thanks to Tom Lowery. + Changed DBD::ExampleP to use lstat() instead of stat(). + Documentation: + Documented $DBI::lasth (which has been there since day 1). + Documented SQL_* names. + Clarified and extended docs for $h->state thanks to Masaaki Hirose. + Clarified fetchall_arrayref({}) docs (thanks to, er, someone!). + Clarified type_info_all re lettercase and index values. + Updated DBI::FAQ to 0.38 thanks to Alligator Descartes. + Added cute bind_columns example thanks to H.Merijn Brand. + Extended docs on \%attr arg to data_sources method. + Makefile.PL + Removed obscure potential 'rm -rf /' (thanks to Ulrich Pfeifer). + Removed use of glob and find (thanks to Michael A. Chase). + Proxy: + Removed debug messages from DBD::Proxy AUTOLOAD thanks to Brian McCauley. + Added fix for problem using table_info thanks to Tom Lowery. + Added better determination of where to put the pid file, and... + Added KNOWN ISSUES section to DBD::Proxy docs thanks to Jochen Wiedmann. + Shell: + Updated DBI::Format to include DBI::Format::String thanks to Tom Lowery. + Added describe command thanks to Tom Lowery. + Added columnseparator option thanks to Tom Lowery (I think). + Added 'raw' format thanks to, er, someone, maybe Tom again. + Known issues: + Perl 5.005 and 5.006 both leak memory doing local($handle->{Foo}). + Perl 5.004 doesn't. The leak is not a DBI or driver bug. + +=head2 Changes in DBI 1.14, 14th June 2000 NOTE: This version is the one the DBI book is based on. NOTE: This version requires at least Perl 5.004. @@ -15,7 +424,7 @@ Added prepare_cached() example to the docs. Added further DBD::ADO enhancements from Thomas Lowery. -Changes in DBI 1.13, 11th July 1999 +=head2 Changes in DBI 1.13, 11th July 1999 Fixed Win32 PerlEx IIS concurrency bugs thanks to Murray Nesbitt. Fixed problems with DBD::ExampleP long_list test mode. @@ -26,7 +435,7 @@ Actually documented connect_cached thanks to Michael Schwern. Fixed user/key/cipher bug in ProxyServer thanks to Joshua Pincus. -Changes in DBI 1.12, 29th June 1999 +=head2 Changes in DBI 1.12, 29th June 1999 Fixed significant DBD::ADO bug (fetch skipped first row). Fixed ProxyServer bug handling non-select statements. @@ -34,14 +443,14 @@ Trace only shows calls to trace_msg and _set_fbav at high levels. Modified t/examp.t to workaround Cygwin buffering bug. -Changes in DBI 1.11, 17th June 1999 +=head2 Changes in DBI 1.11, 17th June 1999 Fixed bind_columns argument checking to allow a single arg. Fixed problems with internal default_user method. Fixed broken DBD::ADO. Made default $DBI::rows more robust for some obscure cases. -Changes in DBI 1.10, 14th June 1999 +=head2 Changes in DBI 1.10, 14th June 1999 Fixed trace_msg.al error when using Apache. Fixed dbd_st_finish enhancement in Driver.xst (internals). @@ -49,7 +458,7 @@ and temporarily disabled warning added in 1.09. Thread safety optimised for single thread case. -Changes in DBI 1.09, 9th June 1999 +=head2 Changes in DBI 1.09, 9th June 1999 Added optional minimum trace level parameter to trace_msg(). Added warning in Makefile.PL that DBI will require 5.004 soon. @@ -68,7 +477,7 @@ Added portability fixes for MacOS from Chris Nandor. Updated mailing list address from fugue.com to isc.org. -Changes in DBI 1.08, 12th May 1999 +=head2 Changes in DBI 1.08, 12th May 1999 Much improved DBD::ADO driver thanks to Phlip Plumlee and others. Connect now allows you to specify attribute settings within the DSN @@ -82,7 +491,7 @@ Workaround for Cygwin32 build problem with help from Jong-Pork Park. bind_columns no longer needs undef or hash ref as first parameter. -Changes in DBI 1.07, 6th May 1999 +=head2 Changes in DBI 1.07, 6th May 1999 Trace output now shows contents of array refs returned by DBI. Changed names of some result columns from type_info, type_info_all, @@ -94,7 +503,7 @@ Added code for MULTIPLICITY/PERL_OBJECT contributed by ActiveState. Added $sth->more_results (undocumented for now). -Changes in DBI 1.06, 6th January 1999 +=head2 Changes in DBI 1.06, 6th January 1999 Fixed Win32 Makefile.PL problem in 1.04 and 1.05. Significant DBD::Proxy enhancements and fixes @@ -103,13 +512,13 @@ Added $sth->{NAME_uc} and $sth->{NAME_lc} attributes. Enhanced fetchrow_hashref to take an attribute name arg. -Changes in DBI 1.05, 4th January 1999 +=head2 Changes in DBI 1.05, 4th January 1999 Improved DBD::ADO connect (thanks to Phlip Plumlee). Improved thread safety (thanks to Jochen Wiedmann). [Quick release prompted by truncation of copies on CPAN] -Changes in DBI 1.04, 3rd January 1999 +=head2 Changes in DBI 1.04, 3rd January 1999 Fixed error in Driver.xst. DBI build now tests Driver.xst. Removed unused variable compiler warnings in Driver.xst. @@ -117,7 +526,7 @@ Further clarification in the DBI::DBD driver writers manual. Added optional name parameter to $sth->fetchrow_hashref. -Changes in DBI 1.03, 1st January 1999 +=head2 Changes in DBI 1.03, 1st January 1999 Now builds with Perl>=5.005_54 (PERL_POLLUTE in DBIXS.h) DBI trace trims path from "at yourfile.pl line nnn". @@ -145,13 +554,13 @@ Fixed DBD::Sponge to work with empty result sets. Complete rewrite of DBI::ProxyServer and DBD::Proxy. -Changes in DBI 1.02, 2nd September 1998 +=head2 Changes in DBI 1.02, 2nd September 1998 Fixed DBI::Shell including @ARGV and /current. Added basic DBI::Shell test. Renamed DBI::Shell /display to /format. -Changes in DBI 1.01, 2nd September 1998 +=head2 Changes in DBI 1.01, 2nd September 1998 Many enhancements to Shell (with many contributions from Jochen Wiedmann, Tom Lowery and Adam Marks). @@ -163,7 +572,7 @@ DBI->connect now honours PrintError=1 if connect fails. Assorted clarifications to the docs. -Changes in DBI 1.00, 14th August 1998 +=head2 Changes in DBI 1.00, 14th August 1998 The DBI is no longer 'alpha' software! Added $dbh->tables and $dbh->table_info. @@ -173,7 +582,7 @@ DBI::Shell now uses neat_list to print results It also escapes "'" chars and converts newlines to spaces. -Changes in DBI 0.95, 10th August 1998 +=head2 Changes in DBI 0.95, 10th August 1998 WARNING: THIS IS AN EXPERIMENTAL RELEASE! @@ -183,7 +592,7 @@ Improved connect error reporting by DBD::Proxy. All trace/debug messages from DBI now go to trace file. -Changes in DBI 0.94, 9th August 1998 +=head2 Changes in DBI 0.94, 9th August 1998 WARNING: THIS IS AN EXPERIMENTAL RELEASE! @@ -207,14 +616,14 @@ Added @bool = DBI::looks_like_number(@ary). Many assorted improvements to the DBI docs. -Changes in DBI 0.93, 13th February 1998 +=head2 Changes in DBI 0.93, 13th February 1998 Fixed DBI::DBD::dbd_postamble bug causing 'Driver.xsi not found' errors. Changes to handling of 'magic' values in neatsvpv (used by trace). execute (in Driver.xst) stops binding after first bind error. This release requires drivers to be rebuilt. -Changes in DBI 0.92, 3rd February 1998 +=head2 Changes in DBI 0.92, 3rd February 1998 Fixed per-handle memory leak (with many thanks to Irving Reid). Added $dbh->prepare_cached() caching variant of $dbh->prepare. @@ -232,7 +641,7 @@ Fixed small 'once per interpreter' leak. Assorted minor documentation fixes. -Changes in DBI 0.91, 10th December 1997 +=head2 Changes in DBI 0.91, 10th December 1997 NOTE: This fix may break some existing scripts: DBI->connect("dbi:...",$user,$pass) was not setting AutoCommit and PrintError! @@ -248,7 +657,7 @@ Fixed to build okay with 5.004_54 with or without USE_THREADS. Note that the DBI has not been tested for thread safety yet. -Changes in DBI 0.90, 6th September 1997 +=head2 Changes in DBI 0.90, 6th September 1997 Can once again be built with Perl 5.003. The DBI class can be subclassed more easily now. @@ -258,13 +667,13 @@ Note: 0.90, 0.89 and possibly some other recent versions have a small memory leak. This will be fixed in the next release. -Changes in DBI 0.89, 25th July 1997 +=head2 Changes in DBI 0.89, 25th July 1997 Minor fix to neatsvpv (mainly used for debug trace) to workaround bug in perl where SvPV removes IOK flag from an SV. Minor updates to the docs. -Changes in DBI 0.88, 22nd July 1997 +=head2 Changes in DBI 0.88, 22nd July 1997 Fixed build for perl5.003 and Win32 with Borland. Fixed documentation formatting. @@ -274,12 +683,12 @@ The DBI can now export SQL type values: use DBI ':sql_types'; Modified Driver.xst and renamed DBDI.h to dbd_xsh.h -Changes in DBI 0.87, 18th July 1997 +=head2 Changes in DBI 0.87, 18th July 1997 Fixed minor type clashes. Added more docs about placeholders and bind values. -Changes in DBI 0.86, 16th July 1997 +=head2 Changes in DBI 0.86, 16th July 1997 Fixed failed connect causing 'unblessed ref' and other errors. Drivers must handle AutoCommit FETCH and STORE else DBI croaks. @@ -302,7 +711,7 @@ that won't appear in drivers for some time. Driver writers might like to read perldoc DBI::DBD and comment on or apply the information given. -Changes in DBI 0.85, 25th June 1997 +=head2 Changes in DBI 0.85, 25th June 1997 NOTE: New-style connect now defaults to AutoCommit mode unless { AutoCommit => 0 } specified in connect attributes. See the docs. @@ -315,7 +724,7 @@ Fixed bug which set some attributes true when there value was fetched. Added new internal DBIc_set() macro for drivers to use. -Changes in DBI 0.84, 20th June 1997 +=head2 Changes in DBI 0.84, 20th June 1997 Added $h->{PrintError} attribute which, if set true, causes all errors to trigger a warn(). @@ -326,7 +735,7 @@ Renamed $h->debug to $h->trace() and added a trace filename arg. Assorted other minor tidy-ups. -Changes in DBI 0.83, 11th June 1997 +=head2 Changes in DBI 0.83, 11th June 1997 Added driver specification syntax to DBI->connect data_source parameter: DBI->connect('dbi:driver:...', $user, $passwd); @@ -348,7 +757,7 @@ Unknown driver specific attribute names no longer croak. Fixed problem with internal neatsvpv macro. -Changes in DBI 0.82, 23rd May 1997 +=head2 Changes in DBI 0.82, 23rd May 1997 Added $h->{RaiseError} attribute which, if set true, causes all errors to trigger a die(). This makes it much easier to implement robust applications @@ -364,12 +773,12 @@ changed (DBIXS_VERSION == 8 and DBISTATE_VERSION == 8) so drivers will have to be recompiled. -Changes in DBI 0.81, 7th May 1997 +=head2 Changes in DBI 0.81, 7th May 1997 Minor fix to let DBI build using less modern perls. Fixed a suprious typo warning. -Changes in DBI 0.80, 6th May 1997 +=head2 Changes in DBI 0.80, 6th May 1997 Builds with no changes on NT using perl5.003_99 (with thanks to Jeffrey Urlwin). Automatically supports Apache::DBI (with thanks to Edmund Mergl). @@ -383,13 +792,13 @@ Added more pod text. Fixed assorted bugs. -Changes in DBI 0.79, 7th Apr 1997 +=head2 Changes in DBI 0.79, 7th Apr 1997 Minor release. Tidied up pod text and added some more descriptions (especially disconnect). Minor changes to DBI.xs to remove compiler warnings. -Changes in DBI 0.78, 28th Mar 1997 +=head2 Changes in DBI 0.78, 28th Mar 1997 Greatly extended the pod documentation in DBI.pm, including the under used bind_columns method. Use 'perldoc DBI' to read after installing. @@ -401,7 +810,7 @@ DBI emulation layer for Win32::ODBC. Note that it's unsupported, your mileage will vary, and bug reports without fixes will probably be ignored. -Changes in DBI 0.77, 21st Feb 1997 +=head2 Changes in DBI 0.77, 21st Feb 1997 Removed erroneous $h->errstate and $h->errmsg methods from DBI.pm. Added $h->err, $h->errstr and $h->state default methods in DBI.xs. @@ -411,16 +820,16 @@ -I$(INSTALLSITEARCH)/auto/DBI -I$(INSTALLSITEARCH)/DBI) -Changes in DBI 0.76, 3rd Feb 1997 +=head2 Changes in DBI 0.76, 3rd Feb 1997 Fixed a compiler type warnings (pedantic IRIX again). -Changes in DBI 0.75, 27th Jan 1997 +=head2 Changes in DBI 0.75, 27th Jan 1997 Fix problem introduced by a change in Perl5.003_XX. Updated README and DBI.pm docs. -Changes in DBI 0.74, 14th Jan 1997 +=head2 Changes in DBI 0.74, 14th Jan 1997 Dispatch now sets dbi_debug to the level of the current handle (this makes tracing/debugging individual handles much easier). @@ -431,7 +840,7 @@ No longer sets perl_destruct_level unless debug set >= 4. Make compatible with PerlIO and sfio. -Changes in DBI 0.73, 10th Oct 1996 +=head2 Changes in DBI 0.73, 10th Oct 1996 Fixed some compiler type warnings (IRIX). Fixed DBI->internal->{DebugLog} = $filename. @@ -440,24 +849,24 @@ Usage: $dbh->bind_param_inout($param, \$value, $maxlen [, \%attribs ]) (only currently used by DBD::Oracle at this time.) -Changes in DBI 0.72, 23 Sep 1996 +=head2 Changes in DBI 0.72, 23 Sep 1996 Using an undefined value as a handle now gives a better error message (mainly useful for emulators like Oraperl). $dbh->do($sql, @params) now works for binding placeholders. -Changes in DBI 0.71, 10 July 1996 +=head2 Changes in DBI 0.71, 10 July 1996 Removed spurious abort() from invalid handle check. Added quote method to DBI interface and added test. -Changes in DBI 0.70, 16 June 1996 +=head2 Changes in DBI 0.70, 16 June 1996 Added extra invalid handle check (dbih_getcom) Fixed broken $dbh->quote method. Added check for old GCC in Makefile.PL -Changes in DBI 0.69 +=head2 Changes in DBI 0.69 Fixed small memory leak. Clarified the behaviour of DBI->connect. @@ -465,19 +874,19 @@ Fixed "Can't read $DBI::errstr, lost last handle" problem. -Changes in DBI 0.68, 2 Mar 1996 +=head2 Changes in DBI 0.68, 2 Mar 1996 Changes to suit perl5.002 and site_lib directories. Detects old versions ahead of new in @INC. -Changes in DBI 0.67, 15 Feb 1996 +=head2 Changes in DBI 0.67, 15 Feb 1996 Trivial change to test suite to fix a problem shown up by the Perl5.002gamma release Test::Harness. -Changes in DBI 0.66, 29 Jan 1996 +=head2 Changes in DBI 0.66, 29 Jan 1996 Minor changes to bring the DBI into line with 5.002 mechanisms, specifically the xs/pm VERSION checking mechanism. @@ -485,7 +894,7 @@ Requires 5.002 (beta2 or later). -Changes in DBI 0.65, 23 Oct 1995 +=head2 Changes in DBI 0.65, 23 Oct 1995 Added $DBI::state to hold SQL CLI / ODBC SQLSTATE value. SQLSTATE "00000" (success) is returned as "" (false), all else is true. @@ -517,7 +926,7 @@ should be ignored for now. -Changes in DBI 0.64, 23 Oct 1995 +=head2 Changes in DBI 0.64, 23 Oct 1995 Fixed 'disconnect invalidates 1 associated cursor(s)' problem. Drivers using DBIc_ACTIVE_on/off() macros should not need any changes @@ -525,14 +934,14 @@ Fixed possible core dump in dbih_clearcom during global destruction. -Changes in DBI 0.63, 1 Sep 1995 +=head2 Changes in DBI 0.63, 1 Sep 1995 Minor update. Fixed uninitialised memory bug in method attribute handling and streamlined processing and debugging. Revised usage definitions for bind_* methods and readblob. -Changes in DBI 0.62, 26 Aug 1995 +=head2 Changes in DBI 0.62, 26 Aug 1995 Added method redirection method $h->func(..., $method_name). This is now the official way to call private driver methods @@ -555,7 +964,7 @@ Faster startup via install_method/_add_dispatch changes. -Changes in DBI 0.61, 22 Aug 1995 +=head2 Changes in DBI 0.61, 22 Aug 1995 Added $sth->bind_col($column, \$var [, \%attribs ]); @@ -590,7 +999,7 @@ test.pl includes a trivial test of bind_param and bind_columns. -Changes in DBI 0.60, 17 Aug 1995 +=head2 Changes in DBI 0.60, 17 Aug 1995 This release has significant code changes but much less dramatic than the previous release. The new implementors data @@ -621,7 +1030,7 @@ as dramatic as these last two releases! (I hope :-) -Changes in DBI 0.59 15 Aug 1995 +=head2 Changes in DBI 0.59 15 Aug 1995 NOTE: THIS IS AN UNSTABLE RELEASE! @@ -633,7 +1042,7 @@ (Comparing parts of v0.21 with v0.20 may be useful.) -Changes in DBI 0.58 21 June 1995 +=head2 Changes in DBI 0.58 21 June 1995 Added DBI->internal->{DebugLog} = $filename; Reworked internal logging. @@ -641,11 +1050,13 @@ Made disconnect_all a compulsary method for drivers. -Some Key Dates in Ancient History +=head1 ANCIENT HISTORY -29th Sep 1992: DBperl project started. -19th Sep 1994: DBperl project renamed to DBI. 12th Oct 1994: First public release of the DBI module. (for Perl 5.000-beta-3h) -End. +19th Sep 1994: DBperl project renamed to DBI. + +29th Sep 1992: DBperl project started. + +=cut diff -u DBI-1.14/DBI.pm DBI-1.30/DBI.pm --- DBI-1.14/DBI.pm Wed Jun 14 21:04:14 2000 +++ DBI-1.30/DBI.pm Thu Jul 18 15:24:04 2002 @@ -1,14 +1,14 @@ -# $Id: DBI.pm,v 10.32 2000/06/14 20:04:03 timbo Exp $ +# $Id: DBI.pm,v 11.18 2002/07/18 14:23:44 timbo Exp $ # -# Copyright (c) 1994-2000 Tim Bunce England +# Copyright (c) 1994-2002 Tim Bunce Ireland # # See COPYRIGHT section in pod text below for usage and distribution rights. # -require 5.004; +require 5.005_03; BEGIN { -$DBI::VERSION = "1.14"; # ==> ALSO update the version in the pod text below! +$DBI::VERSION = "1.30"; # ==> ALSO update the version in the pod text below! } =head1 NAME @@ -20,7 +20,7 @@ use DBI; @driver_names = DBI->available_drivers; - @data_sources = DBI->data_sources($driver_name); + @data_sources = DBI->data_sources($driver_name, \%attr); $dbh = DBI->connect($data_source, $username, $auth, \%attr); @@ -28,20 +28,30 @@ $rv = $dbh->do($statement, \%attr); $rv = $dbh->do($statement, \%attr, @bind_values); - $ary_ref = $dbh->selectall_arrayref($statement); - @row_ary = $dbh->selectrow_array($statement); + $ary_ref = $dbh->selectall_arrayref($statement); + $hash_ref = $dbh->selectall_hashref($statement, $key_field); + $ary_ref = $dbh->selectcol_arrayref($statement); + $ary_ref = $dbh->selectcol_arrayref($statement, \%attr); + + @row_ary = $dbh->selectrow_array($statement); + $ary_ref = $dbh->selectrow_arrayref($statement); + $hash_ref = $dbh->selectrow_hashref($statement); $sth = $dbh->prepare($statement); $sth = $dbh->prepare_cached($statement); - $rv = $sth->bind_param($p_num, $bind_value); - $rv = $sth->bind_param($p_num, $bind_value, $bind_type); - $rv = $sth->bind_param($p_num, $bind_value, \%attr); + $rc = $sth->bind_param($p_num, $bind_value); + $rc = $sth->bind_param($p_num, $bind_value, $bind_type); + $rc = $sth->bind_param($p_num, $bind_value, \%attr); $rv = $sth->execute; $rv = $sth->execute(@bind_values); + $rc = $sth->bind_param_array($p_num, $bind_values, \%attr); + $rv = $sth->execute_array(\%attr); + $rv = $sth->execute_array(\%attr, @bind_values); + $rc = $sth->bind_col($col_num, \$col_variable); $rc = $sth->bind_columns(@list_of_refs_to_vars_to_bind); @@ -50,13 +60,17 @@ $hash_ref = $sth->fetchrow_hashref; $ary_ref = $sth->fetchall_arrayref; + $ary_ref = $sth->fetchall_arrayref( $slice, $max_rows ); + + $hash_ref = $sth->fetchall_hashref( $key_field ); $rv = $sth->rows; + $rc = $dbh->begin_work; $rc = $dbh->commit; $rc = $dbh->rollback; - $sql = $dbh->quote($string); + $quoted_string = $dbh->quote($string); $rc = $h->err; $str = $h->errstr; @@ -64,86 +78,71 @@ $rc = $dbh->disconnect; -I +I =head2 GETTING HELP If you have questions about DBI, you can get help from -the I mailing list. -You can subscribe to the list by visiting: +the I mailing list. +You can get help on subscribing and using the list by emailing: - http://www.isc.org/dbi-lists.html + dbi-users-help@perl.org Also worth a visit is the DBI home page at: - http://www.symbolstone.org/technology/perl/DBI + http://dbi.perl.org/ Before asking any questions, reread this document, consult the archives and read the DBI FAQ. The archives are listed -at the end of this document. -The FAQ is installed as a DBI::FAQ module so +at the end of this document and on the DBI home page. +The FAQ is installed as a L module so you can read it by executing C. +This document often uses terms like I, I, +I. If you're not familar with those terms then it would +be a good idea to read at least the following perl manuals first: +L, L, L, and L. + Please note that Tim Bunce does not maintain the mailing lists or the web page (generous volunteers do that). So please don't send mail directly to him; he just doesn't have the time to answer questions personally. The I mailing list has lots of experienced -people who should be able to help you if you need it. - -=head2 NOTE - -This is the DBI specification that corresponds to the DBI version 1.14 -(C<$Date: 2000/06/14 20:04:03 $>). - -The DBI specification is evolving at a steady pace, so it's -important to check that you have the latest copy. The RECENT CHANGES -section below has a summary of user-visible changes. The F -file supplied with the DBI holds more detailed change information. - -Note also that whenever the DBI changes, the drivers take some time to -catch up. Recent versions of the DBI have added new features -(marked I in the text) that may not yet be supported by the drivers -you use. Talk to the authors of those drivers if you need the features. - -Extensions to the DBI and other DBI related modules use the C -namespace. See L and: - - http://www.perl.com/CPAN/modules/by-module/DBIx/ - -=head2 RECENT CHANGES +people who should be able to help you if you need it. If you do email +Tim he's very likely to just forward it to the mailing list. -Here is a brief summary of significant user-visible changes in recent versions. -(If a recent version isn't mentioned, it simply means that there were no -significant user-visible changes in that version.) +=head2 NOTES -=over 4 +This is the DBI specification that corresponds to the DBI version 1.30 +(C<$Date: 2002/07/18 14:23:44 $>). -=item Between DBI 1.00 and DBI 1.09: +The DBI is evolving at a steady pace, so it's good to check that +you have the latest copy. - Added $dbh->selectcol_arrayref($statement) method. +The significant user-visible changes in each release are documented +in the L module so you can read them by executing +C. - Connect now allows you to specify attribute settings within the DSN. - For example: - dbi:Driver(RaiseError=>1,Taint=>1,AutoCommit=>0):dbname" +Some DBI changes require changes in the drivers, but the drivers +can take some time to catch up. Recent versions of the DBI have +added new features (generally marked I in the text) that may +not yet be supported by the drivers you use. Talk to the authors +of those drivers if you need the new features. - Added $h->{Taint}, $sth->{NAME_uc}, and $sth->{NAME_lc} attributes. +Extensions to the DBI API often use the C namespace. +See L and: -=back + http://search.cpan.org/search?mode=module&query=DBIx%3A%3A =cut # The POD text continues at the end of the file. -# DBI file-private variables -my %installed_rootclass; - { package DBI; -my $Revision = substr(q$Revision: 10.32 $, 10); - +my $Revision = substr(q$Revision: 11.18 $, 10); use Carp; use DynaLoader (); @@ -153,34 +152,98 @@ @ISA = qw(Exporter DynaLoader); # Make some utility functions available if asked for -@EXPORT = (); # we export nothing by default -@EXPORT_OK = ('%DBI'); # populated by export_ok_tags: +@EXPORT = (); # we export nothing by default +@EXPORT_OK = qw(%DBI %DBI_methods hash); # also populated by export_ok_tags: %EXPORT_TAGS = ( sql_types => [ qw( - SQL_ALL_TYPES - SQL_CHAR SQL_NUMERIC SQL_DECIMAL SQL_INTEGER SQL_SMALLINT - SQL_FLOAT SQL_REAL SQL_DOUBLE SQL_VARCHAR - SQL_DATE SQL_TIME SQL_TIMESTAMP - SQL_LONGVARCHAR SQL_BINARY SQL_VARBINARY SQL_LONGVARBINARY - SQL_BIGINT SQL_TINYINT - SQL_WCHAR SQL_WVARCHAR SQL_WLONGVARCHAR + SQL_GUID + SQL_WLONGVARCHAR + SQL_WVARCHAR + SQL_WCHAR SQL_BIT + SQL_TINYINT + SQL_LONGVARBINARY + SQL_VARBINARY + SQL_BINARY + SQL_LONGVARCHAR + SQL_UNKNOWN_TYPE + SQL_ALL_TYPES + SQL_CHAR + SQL_NUMERIC + SQL_DECIMAL + SQL_INTEGER + SQL_SMALLINT + SQL_FLOAT + SQL_REAL + SQL_DOUBLE + SQL_DATETIME + SQL_DATE + SQL_INTERVAL + SQL_TIME + SQL_TIMESTAMP + SQL_VARCHAR + SQL_BOOLEAN + SQL_UDT + SQL_UDT_LOCATOR + SQL_ROW + SQL_REF + SQL_BLOB + SQL_BLOB_LOCATOR + SQL_CLOB + SQL_CLOB_LOCATOR + SQL_ARRAY + SQL_ARRAY_LOCATOR + SQL_MULTISET + SQL_MULTISET_LOCATOR + SQL_TYPE_DATE + SQL_TYPE_TIME + SQL_TYPE_TIMESTAMP + SQL_TYPE_TIME_WITH_TIMEZONE + SQL_TYPE_TIMESTAMP_WITH_TIMEZONE + SQL_INTERVAL_YEAR + SQL_INTERVAL_MONTH + SQL_INTERVAL_DAY + SQL_INTERVAL_HOUR + SQL_INTERVAL_MINUTE + SQL_INTERVAL_SECOND + SQL_INTERVAL_YEAR_TO_MONTH + SQL_INTERVAL_DAY_TO_HOUR + SQL_INTERVAL_DAY_TO_MINUTE + SQL_INTERVAL_DAY_TO_SECOND + SQL_INTERVAL_HOUR_TO_MINUTE + SQL_INTERVAL_HOUR_TO_SECOND + SQL_INTERVAL_MINUTE_TO_SECOND ) ], utils => [ qw( neat neat_list dump_results looks_like_number ) ], + profile => [ qw( + dbi_profile dbi_profile_merge dbi_time + ) ], ); -Exporter::export_ok_tags('sql_types', 'utils'); $DBI::dbi_debug = $ENV{DBI_TRACE} || $ENV{PERL_DBI_DEBUG} || 0; # If you get an error here like "Can't find loadable object ..." # then you haven't installed the DBI correctly. Read the README # then install it again. -bootstrap DBI; +if ( $ENV{DBI_PUREPERL} ) { + eval { bootstrap DBI } if $ENV{DBI_PUREPERL} == 1; + require DBI::PurePerl if $@ or $ENV{DBI_PUREPERL} >= 2; + $DBI::PurePerl ||= 0; # just to silence "only used once" warnings +} +else { + bootstrap DBI; +} + +$EXPORT_TAGS{preparse_flags} = [ grep { /^DBIpp_\w\w_/ } keys %{__PACKAGE__."::"} ]; + +Exporter::export_ok_tags(keys %EXPORT_TAGS); } + *trace_msg = \&DBD::_::common::trace_msg; +*set_err = \&DBD::_::common::set_err; use strict; @@ -202,6 +265,7 @@ # digits (and equals) are stripped off and used as the level unshift @DBI::dbi_debug, 2; @DBI::dbi_debug = ($1,$2) if $DBI::dbi_debug =~ m/^(\d+)=(.*)/; + $DBI::dbi_debug = $DBI::dbi_debug[0]; } DBI->trace(@DBI::dbi_debug); } @@ -230,12 +294,11 @@ # --- Dynamically create the DBI Standard Interface -my $std = undef; -my $keeperr = { O=>0x04 }; +my $keeperr = { O=>0x0004 }; my @TieHash_IF = ( # Generic Tied Hash Interface - 'STORE' => { O=>0x10 }, - 'FETCH' => $keeperr, + 'STORE' => { O=>0x0410 }, + 'FETCH' => { O=>0x0404 }, 'FIRSTKEY'=> $keeperr, 'NEXTKEY' => $keeperr, 'EXISTS' => $keeperr, @@ -243,19 +306,20 @@ 'DESTROY' => undef, # hardwired internally ); my @Common_IF = ( # Interface functions common to all DBI classes - func => { O=>0x06 }, - event => { U =>[2,0,'$type, @args'], O=>0x04 }, - 'trace' => { U =>[1,3,'[$trace_level, [$filename]]'], O=>0x04 }, - trace_msg => { U =>[2,3,'$message_text [, $min_level ]' ], O=>0x04, T=>8 }, - debug => { U =>[1,2,'[$debug_level]'], O=>0x04 }, # old name for trace - private_data => { U =>[1,1], O=>0x04 }, + func => { O=>0x0006 }, + event => { U =>[2,0,'$type, @args'], O=>0x0004 }, + 'trace' => { U =>[1,3,'[$trace_level, [$filename]]'], O=>0x0004 }, + trace_msg => { U =>[2,3,'$message_text [, $min_level ]' ], O=>0x0004, T=>8 }, + debug => { U =>[1,2,'[$debug_level]'], O=>0x0004 }, # old name for trace + private_data => { U =>[1,1], O=>0x0004 }, err => $keeperr, errstr => $keeperr, - state => { U =>[1,1], O=>0x04 }, - _not_impl => $std, + state => { U =>[1,1], O=>0x0004 }, + set_err => { }, + _not_impl => undef, ); -my %DBI_IF = ( # Define the DBI Interface: +%DBI::DBI_methods = ( # Define the DBI interface methods per class: dr => { # Database Driver Interface @Common_IF, @@ -269,25 +333,35 @@ db => { # Database Session Class Interface @Common_IF, @TieHash_IF, - commit => { U =>[1,1] }, - rollback => { U =>[1,1] }, + connected => { O=>0x0100 }, + begin_work => { U =>[1,2,'[ \%attr ]'], O=>0x0400 }, + commit => { U =>[1,1], O=>0x0480 }, + rollback => { U =>[1,1], O=>0x0480 }, 'do' => { U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'] }, + preparse => { }, # XXX prepare => { U =>[2,3,'$statement [, \%attr]'] }, prepare_cached => { U =>[2,4,'$statement [, \%attr [, $allow_active ] ]'] }, selectrow_array => { U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'] }, + selectrow_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'] }, + selectrow_hashref=>{ U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'] }, selectall_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'] }, + selectall_hashref=>{ U =>[3,0,'$statement, $keyfield [, \%attr [, @bind_params ] ]'] }, selectcol_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'] }, - handler => { U =>[2,2,'\&handler'] }, - ping => { U =>[1,1] }, - disconnect => { U =>[1,1] }, - quote => { U =>[2,3, '$string [, $data_type ]' ], O=>0x30 }, + ping => { U =>[1,1], O=>0x0404 }, + disconnect => { U =>[1,1], O=>0x0400 }, + quote => { U =>[2,3, '$string [, $data_type ]' ], O=>0x0430 }, + quote_identifier=> { U =>[2,5, '$name [, ...]' ], O=>0x0430 }, rows => $keeperr, - tables => { U =>[1,2,'[ \%attr ]' ] }, - table_info => { U =>[1,2,'[ \%attr ]' ] }, - type_info_all => { U =>[1,1] }, - type_info => { U =>[1,2] }, - get_info => { U =>[2,2] }, + tables => { U =>[1,6,'$catalog, $schema, $table, $type [, \%attr ]' ], O=>0x0200 }, + table_info => { U =>[1,6,'$catalog, $schema, $table, $type [, \%attr ]' ], O=>0x0200 }, + column_info => { U =>[1,6,'$catalog, $schema, $table, $column [, \%attr ]' ], O=>0x0200 }, + primary_key_info=> { U =>[4,5,'$catalog, $schema, $table [, \%attr ]' ], O=>0x0200 }, + primary_key => { U =>[4,5,'$catalog, $schema, $table [, \%attr ]' ], O=>0x0200 }, + foreign_key_info=> { U =>[1,7,'$pk_catalog, $pk_schema, $pk_table, $fk_catalog, $fk_schema, $fk_table' ], O=>0x0200 }, + type_info_all => { U =>[1,1], O=>0x0200 }, + type_info => { U =>[1,2,'$data_type'], O=>0x0200 }, + get_info => { U =>[2,2,'$info_type'], O=>0x0200 }, }, st => { # Statement Class Interface @Common_IF, @@ -296,7 +370,11 @@ bind_columns => { U =>[2,0,'\\$var1 [, \\$var2, ...]'] }, bind_param => { U =>[3,4,'$parameter, $var [, \%attr]'] }, bind_param_inout=> { U =>[4,5,'$parameter, \\$var, $maxlen, [, \%attr]'] }, - execute => { U =>[1,0,'[@args]'] }, + execute => { U =>[1,0,'[@args]'], O=>0x40 }, + + bind_param_array => { U =>[3,4,'$parameter, $var [, \%attr]'] }, + bind_param_inout_array => { U =>[4,5,'$parameter, \\@var, $maxlen, [, \%attr]'] }, + execute_array => { U =>[2,0,'\\%attribs [, @args]'] }, fetch => undef, # alias for fetchrow_arrayref fetchrow_arrayref => undef, @@ -304,7 +382,8 @@ fetchrow_array => undef, fetchrow => undef, # old alias for fetchrow_array - fetchall_arrayref => { U =>[1,2] }, + fetchall_arrayref => { U =>[1,3] }, + fetchall_hashref => { U =>[2,2] }, blob_read => { U =>[4,5,'$field, $offset, $len [, \\$buf [, $bufoffset]]'] }, blob_copy_to_file => { U =>[3,3,'$field, $filename_or_handleref'] }, @@ -320,8 +399,8 @@ ); my($class, $method); -foreach $class (keys %DBI_IF){ - my %pkgif = %{$DBI_IF{$class}}; +foreach $class (keys %DBI::DBI_methods){ + my %pkgif = %{ $DBI::DBI_methods{$class} }; foreach $method (keys %pkgif){ DBI->_install_method("DBI::${class}::$method", 'DBI.pm', $pkgif{$method}); @@ -341,24 +420,36 @@ } +sub CLONE { + my $olddbis = $DBI::_dbistate; + _clone_dbis() unless $DBI::PurePerl; # clone the DBIS structure + %DBI::installed_drh = (); # clear loaded drivers so they have a chance to reinitialize + DBI->trace_msg(sprintf "CONE DBI for new thread %s\n", + $DBI::PurePerl ? "" : sprintf("(dbis %x -> %x)",$olddbis, $DBI::_dbistate)); +} + # --- The DBI->connect Front Door methods sub connect_cached { # XXX we expect Apache::DBI users to still call connect() - return shift->connect(@_[0..4], 'connect_cached'); + my ($class, $dsn, $user, $pass, $attr) = @_; + ($attr ||= {})->{dbi_connect_method} = 'connect_cached'; + return $class->connect($dsn, $user, $pass, $attr); } sub connect { my $class = shift; - my($dsn, $user, $pass, $attr, $old_driver, $connect_meth) = @_; - $connect_meth ||= $connect_via; # $connect_meth not user visible + my($dsn, $user, $pass, $attr, $old_driver) = @_; my $driver; my $dbh; # switch $old_driver<->$attr if called in old style ($old_driver, $attr) = ($attr, $old_driver) if $attr and !ref($attr); + my $connect_meth = (ref $attr) ? $attr->{dbi_connect_method} : undef; + $connect_meth ||= $connect_via; # fallback to default + $dsn ||= $ENV{DBI_DSN} || $ENV{DBI_DBNAME} || '' unless $old_driver; if ($DBI::dbi_debug) { @@ -386,28 +477,33 @@ DBI->trace_msg(" DBI_AUTOPROXY: dbi:$driver:$dsn\n"); } - unless ($old_driver) { # new-style connect so new default semantics - $driver_attrib_spec = { split /\s*=>?\s*|\s*,\s*/, $driver_attrib_spec } - if $driver_attrib_spec; - $attr = { - PrintError=>1, AutoCommit=>1, - ref $attr ? %$attr : (), - ref $driver_attrib_spec ? %$driver_attrib_spec : (), - }; - # XXX to be enabled for DBI v2.0 - #Carp::carp("AutoCommit attribute not specified in DBI->connect") + my %attr; # take a copy we can delete from + if ($old_driver) { + %attr = %$attr if $attr; + } + else { # new-style connect so new default semantics + %attr = ( + PrintError => 1, + AutoCommit => 1, + ref $attr ? %$attr : (), + $driver_attrib_spec ? (split /\s*=>?\s*|\s*,\s*/, $driver_attrib_spec) : (), + ); + # XXX to be enabled for DBI v2.0? + #Carp::carp("AutoCommit attribute not specified in $class->connect") # if $^W && !defined($attr->{AutoCommit}); } + $attr = \%attr; # now set $attr at our local copy - my $drh = $class->install_driver($driver) - || die "panic: install_driver($driver) failed"; + my $drh = $DBI::installed_drh{$driver} || $class->install_driver($driver) + or die "panic: $class->install_driver($driver) failed"; ($user, $pass) = $drh->default_user($user, $pass, $attr) if !(defined $user && defined $pass); unless ($dbh = $drh->$connect_meth($dsn, $user, $pass, $attr)) { my $msg = "$class->connect($dsn) failed: ".$drh->errstr; - if (ref $attr) { + if (%attr) { + # XXX add $attr{HandleError} logic here? Carp::croak($msg) if $attr->{RaiseError}; Carp::carp ($msg) if $attr->{PrintError}; } @@ -416,30 +512,49 @@ return undef; } - # XXX this is inelegant but practical in the short term, sigh. - if ($installed_rootclass{$class}) { - $dbh->{RootClass} = $class; - bless $dbh => $class.'::db'; - my ($outer, $inner) = DBI::_handles($dbh); - bless $inner => $class.'::db'; + + # handle basic RootClass subclassing: + my $rebless_class = $attr->{RootClass} || ($class ne 'DBI' ? $class : ''); + if ($rebless_class) { + if ($attr->{RootClass}) { # explicit attribute (rather than static call) + delete $attr->{RootClass}; + DBI::_load_module($rebless_class); + } + no strict 'refs'; + unless (@{"$rebless_class\::db::ISA"}) { + Carp::carp("DBI subclass '$rebless_class\::db' isn't setup, ignored"); + $rebless_class = undef; + $class = 'DBI'; + } + else { + $dbh->{RootClass} = $rebless_class; # $dbh->STORE called via plain DBI::db + DBI::_set_isa([$rebless_class], 'DBI'); # sets up both '::db' and '::st' + DBI::_rebless($dbh, $rebless_class); # appends '::db' + } } - if (ref $attr) { - my %a = %$attr; + + if (%$attr) { + + DBI::_rebless_dbtype_subclass($dbh, $rebless_class||$class, delete $attr->{DbTypeSubclass}, $attr) + if $attr->{DbTypeSubclass}; + my $a; - # handle these attributes first - foreach $a (qw(RaiseError PrintError AutoCommit)) { - next unless exists $a{$a}; - $dbh->{$a} = $a{$a}; - delete $a{$a}; + foreach $a (qw(RaiseError PrintError AutoCommit)) { # do these first + next unless exists $attr->{$a}; + $dbh->{$a} = delete $attr->{$a}; } - foreach $a (keys %a) { - $dbh->{$a} = $a{$a}; + foreach $a (keys %$attr) { + $dbh->{$a} = $attr->{$a}; } } + + # if we've been subclassed then let the subclass know that we're connected + $dbh->connected($dsn, $user, $pass, \%attr) if ref $dbh ne 'DBI::db'; + DBI->trace_msg(" <- connect= $dbh\n") if $DBI::dbi_debug; - $dbh; + return $dbh; } @@ -452,11 +567,15 @@ } +sub disconnect { # a regular beginners bug + Carp::croak("DBI->disconnect is not a DBI method. Read the DBI manual."); +} + + sub install_driver { # croaks on failure my $class = shift; my($driver, $attr) = @_; my $drh; - local $@; $driver ||= $ENV{DBI_DRIVER} || ''; @@ -470,7 +589,7 @@ return $drh if $drh = $DBI::installed_drh{$driver}; DBI->trace_msg(" -> $class->install_driver($driver" - .") for perl=$] pid=$$ ruid=$< euid=$>\n") + .") for $^O perl=$] pid=$$ ruid=$< euid=$>\n") if $DBI::dbi_debug; # --- load the code @@ -500,8 +619,10 @@ } if ($DBI::dbi_debug) { no strict 'refs'; + (my $driver_file = $driver_class) =~ s/::/\//g; my $dbd_ver = ${"$driver_class\::VERSION"} || "undef"; - DBI->trace_msg(" install_driver: $driver_class loaded (version $dbd_ver)\n") + DBI->trace_msg(" install_driver: $driver_class version $dbd_ver" + ." loaded from $INC{qq($driver_file.pm)}\n"); } # --- do some behind-the-scenes checks and setups on the driver @@ -532,25 +653,140 @@ my $class = $driver_class."::$type"; no strict 'refs'; push @{"${class}::ISA"}, "DBD::_::$type"; - push @{"${class}_mem::ISA"}, "DBD::_mem::$type"; + push @{"${class}_mem::ISA"}, "DBD::_mem::$type" unless $DBI::PurePerl; } } -sub init_rootclass { - my $rootclass = shift; - no strict 'refs'; - croak("Can't init '$rootclass' without '$rootclass\::db' class.") - unless defined ${"$rootclass\::db::"}{ISA}; +sub _rebless { + my $dbh = shift; + my ($outer, $inner) = DBI::_handles($dbh); + my $class = shift(@_).'::db'; + bless $inner => $class; + bless $outer => $class; # outer last for return +} + + +sub _set_isa { + my ($classes, $topclass) = @_; + my $trace = DBI->trace_msg(" _set_isa([@$classes])\n"); + foreach my $suffix ('::db','::st') { + my $previous = $topclass || 'DBI'; # trees are rooted here + foreach my $class (@$classes) { + my $base_class = $previous.$suffix; + my $sub_class = $class.$suffix; + my $sub_class_isa = "${sub_class}::ISA"; + no strict 'refs'; + if (@$sub_class_isa) { + DBI->trace_msg(" $sub_class_isa skipped (already set to @$sub_class_isa)\n") + if $trace; + } + else { + @$sub_class_isa = ($base_class) unless @$sub_class_isa; + DBI->trace_msg(" $sub_class_isa = $base_class\n") + if $trace; + } + $previous = $class; + } + } +} + + +sub _rebless_dbtype_subclass { + my ($dbh, $rootclass, $DbTypeSubclass, $attr) = @_; + # determine the db type names for class hierarchy + my @hierarchy = DBI::_dbtype_names($dbh, $DbTypeSubclass, $attr); + # add the rootclass prefix to each ('DBI::' or 'MyDBI::' etc) + $_ = $rootclass.'::'.$_ foreach (@hierarchy); + # load the modules from the 'top down' + DBI::_load_module($_) foreach (reverse @hierarchy); + # setup class hierarchy if needed, does both '::db' and '::st' + DBI::_set_isa(\@hierarchy, $rootclass); + # finally bless the handle into the subclass + DBI::_rebless($dbh, $hierarchy[0]); +} + + +sub _dbtype_names { # list dbtypes for hierarchy, ie Informix=>ADO=>ODBC + my ($dbh, $DbTypeSubclass, $attr) = @_; + + if ($DbTypeSubclass && $DbTypeSubclass ne '1' && ref $DbTypeSubclass ne 'CODE') { + # treat $DbTypeSubclass as a comma separated list of names + my @dbtypes = split /\s*,\s*/, $DbTypeSubclass; + $dbh->trace_msg(" DbTypeSubclass($DbTypeSubclass)=@dbtypes (explicit)\n"); + return @dbtypes; + } + + # XXX will call $dbh->get_info(17) (=SQL_DBMS_NAME) in future? + + my $driver = $dbh->{Driver}->{Name}; + if ( $driver eq 'Proxy' ) { + # XXX Looking into the internals of DBD::Proxy is questionable! + ($driver) = $dbh->{proxy_client}->{application} =~ /^DBI:(.+?):/i + or die "Can't determine driver name from proxy"; + } + + my @dbtypes = (ucfirst($driver)); + if ($driver eq 'ODBC' || $driver eq 'ADO') { + # XXX will move these out and make extensible later: + my $_dbtype_name_regexp = 'Oracle'; # eg 'Oracle|Foo|Bar' + my %_dbtype_name_map = ( + 'Microsoft SQL Server' => 'MSSQL', + 'SQL Server' => 'Sybase', + 'Adaptive Server Anywhere' => 'ASAny', + 'ADABAS D' => 'AdabasD', + ); + + my $name; + $name = $dbh->func(17, 'GetInfo') # SQL_DBMS_NAME + if $driver eq 'ODBC'; + $name = $dbh->{ado_conn}->Properties->Item('DBMS Name')->Value + if $driver eq 'ADO'; + die "Can't determine driver name! ($DBI::errstr)\n" + unless $name; + + my $dbtype; + if ($_dbtype_name_map{$name}) { + $dbtype = $_dbtype_name_map{$name}; + } + else { + if ($name =~ /($_dbtype_name_regexp)/) { + $dbtype = lc($1); + } + else { # generic mangling for other names: + $dbtype = lc($name); + } + $dbtype =~ s/\b(\w)/\U$1/g; + $dbtype =~ s/\W+/_/g; + } + # add ODBC 'behind' ADO + push @dbtypes, 'ODBC' if $driver eq 'ADO'; + # add discovered dbtype in front of ADO/ODBC + unshift @dbtypes, $dbtype; + } + @dbtypes = &$DbTypeSubclass($dbh, \@dbtypes) + if (ref $DbTypeSubclass eq 'CODE'); + $dbh->trace_msg(" DbTypeSubclass($DbTypeSubclass)=@dbtypes\n"); + return @dbtypes; +} + +sub _load_module { + (my $module = shift) =~ s!::!/!g; + eval { + require $module.'.pm'; + }; + return 1 unless $@; + return 0 if $@ =~ /^\b\@INC\b/; + die; # propagate $@; +} - $installed_rootclass{$rootclass} = 1; - # may do checks on ::db and ::st classes later + +sub init_rootclass { # deprecated return 1; } *internal = \&DBD::Switch::dr::driver; -#sub internal { return DBD::Switch::dr::driver(@_); } sub available_drivers { @@ -582,7 +818,9 @@ } closedir(DBI::DIR); } - return sort @drivers; + + # "return sort @drivers" will not DWIM in scalar context. + return wantarray ? sort @drivers : @drivers; } sub data_sources { @@ -664,22 +902,23 @@ # --- Private Internal Function for Creating New DBI Handles sub _new_handle { - my($class, $parent, $attr, $imp_data) = @_; + my ($class, $parent, $attr, $imp_data, $imp_class) = @_; Carp::croak('Usage: DBI::_new_handle' .'($class_name, parent_handle, \%attr, $imp_data)'."\n" .'got: ('.join(", ",$class, $parent, $attr, $imp_data).")\n") - unless(@_ == 4 and (!$parent or ref $parent) - and ref $attr eq 'HASH'); + unless (@_ == 5 and (!$parent or ref $parent) + and ref $attr eq 'HASH' + and $imp_class); - my $imp_class = $attr->{ImplementorClass} or - Carp::croak("_new_handle($class): 'ImplementorClass' attribute not given"); + $attr->{ImplementorClass} = $imp_class + or Carp::croak("_new_handle($class): 'ImplementorClass' attribute not given"); DBI->trace_msg(" New $class (for $imp_class, parent=$parent, id=".($imp_data||'').")\n") if $DBI::dbi_debug >= 3; # This is how we create a DBI style Object: - my(%hash, $i, $h); + my (%hash, $i, $h); $i = tie %hash, $class, $attr; # ref to inner hash (for driver) $h = bless \%hash, $class; # ref to outer hash (for application) # The above tie and bless may migrate down into _setup_handle()... @@ -689,14 +928,16 @@ return $h unless wantarray; ($h, $i); } -# minimum constructors for the tie's (alias to XS version) +# XXX minimum constructors for the tie's (alias to XS version) sub DBI::st::TIEHASH { bless $_[1] => $_[0] }; *DBI::dr::TIEHASH = \&DBI::st::TIEHASH; *DBI::db::TIEHASH = \&DBI::st::TIEHASH; # These three special constructors are called by the drivers -# The way they are called is likey to change. +# The way they are called is likely to change. + +my $profile; sub _new_drh { # called by DBD::::driver() my ($class, $initial_attr, $imp_data) = @_; @@ -705,49 +946,53 @@ # State must be undef to get automatic faking in DBI::var::FETCH my ($h_state_store, $h_err_store, $h_errstr_store) = (undef, 0, ''); my $attr = { - 'ImplementorClass' => $class, # these attributes get copied down to child handles by default 'Handlers' => [], 'State' => \$h_state_store, # Holder for DBI::state 'Err' => \$h_err_store, # Holder for DBI::err 'Errstr' => \$h_errstr_store, # Holder for DBI::errstr 'Debug' => 0, + FetchHashKeyName=> 'NAME', %$initial_attr, - 'Type'=>'dr', }; - _new_handle('DBI::dr', '', $attr, $imp_data); + my ($h, $i) = _new_handle('DBI::dr', '', $attr, $imp_data, $class); + + # XXX DBI_PROFILE unless DBI::PurePerl because for some reason + # it kills the t/zz_*_pp.t tests (they silently exit early) + if ($ENV{DBI_PROFILE} && !$DBI::PurePerl) { + # The profile object created here when the first driver is loaded + # is shared by all drivers so we end up with just one set of profile + # data and thus the 'total time in DBI' is really the true total. + if (!$profile) { # first time + $h->{Profile} = $ENV{DBI_PROFILE}; + $profile = $h->{Profile}; + } + else { + $h->{Profile} = $profile; + } + } + return $h unless wantarray; + ($h, $i); } sub _new_dbh { # called by DBD::::dr::connect() - my ($drh, $initial_attr, $imp_data) = @_; + my ($drh, $attr, $imp_data) = @_; my $imp_class = $drh->{ImplementorClass} - || Carp::croak("DBI _new_dbh: $drh has no ImplementorClass"); + or Carp::croak("DBI _new_dbh: $drh has no ImplementorClass"); substr($imp_class,-4,4) = '::db'; - my $app_class = ref $drh; + my $app_class = ref $drh; substr($app_class,-4,4) = '::db'; - my $attr = { - 'ImplementorClass' => $imp_class, - %$initial_attr, - 'Type' => 'db', - 'Driver' => (DBI::_handles($drh))[0], - }; - _new_handle($app_class, $drh, $attr, $imp_data); + _new_handle($app_class, $drh, $attr||{}, $imp_data, $imp_class); } sub _new_sth { # called by DBD::::db::prepare) - my ($dbh, $initial_attr, $imp_data) = @_; + my ($dbh, $attr, $imp_data) = @_; my $imp_class = $dbh->{ImplementorClass} - || Carp::croak("DBI _new_sth: $dbh has no ImplementorClass"); + or Carp::croak("DBI _new_sth: $dbh has no ImplementorClass"); substr($imp_class,-4,4) = '::st'; - my $app_class = ref $dbh; + my $app_class = ref $dbh; substr($app_class,-4,4) = '::st'; - my $attr = { - 'ImplementorClass' => $imp_class, - %$initial_attr, - 'Type' => 'st', - 'Database' => $dbh, - }; - _new_handle($app_class, $dbh, $attr, $imp_data); + _new_handle($app_class, $dbh, $attr, $imp_data, $imp_class); } @@ -773,8 +1018,7 @@ ($drh, $inner) = DBI::_new_drh('DBD::Switch::dr', { 'Name' => 'Switch', 'Version' => $DBI::VERSION, - # the Attribution is defined as a sub as an example - 'Attribution' => sub { "DBI $DBI::VERSION by Tim Bunce" }, + 'Attribution' => "DBI $DBI::VERSION by Tim Bunce", }, \$err); Carp::croak("DBD::Switch init failed!") unless ($drh && $inner); return $drh; @@ -822,6 +1066,8 @@ sub NEXTKEY { } sub EXISTS { defined($_[0]->FETCH($_[1])) } # XXX undef? sub CLEAR { Carp::carp "Can't CLEAR $_[0] (DBI)" } + + *dump_handle = \&DBI::dump_handle; } @@ -864,11 +1110,13 @@ my $cache = $drh->FETCH('CachedKids'); $drh->STORE('CachedKids', $cache = {}) unless $cache; - my $key = join "~", $dsn, $user||'', $auth||'', $attr ? %$attr : (); + my @attr_keys = $attr ? sort keys %$attr : (); + my $key = join "~~", $dsn, $user||'', $auth||'', + $attr ? (@attr_keys,@{$attr}{@attr_keys}) : (); my $dbh = $cache->{$key}; - return $dbh if $dbh && $dbh->FETCH('Active') && $dbh->ping; + return $dbh if $dbh && $dbh->FETCH('Active') && eval { $dbh->ping }; $dbh = $drh->connect(@_); - $cache->{$key} = $dbh; # replace, even if it failed + $cache->{$key} = $dbh; # replace prev entry, even if connect failed return $dbh; } @@ -896,25 +1144,59 @@ # Drivers are required to implement *::db::DESTROY to encourage tidy-up sub DESTROY { Carp::croak("Driver has not implemented DESTROY for @_") } + sub quote_identifier { + my ($dbh, @id) = @_; + my $attr = (@id > 3) ? pop @id : undef; + + my $info = $dbh->{dbi_quote_identifier_cache} ||= [ + $dbh->get_info(29) || '"', # SQL_IDENTIFIER_QUOTE_CHAR + $dbh->get_info(41) || '.', # SQL_CATALOG_NAME_SEPARATOR + $dbh->get_info(114) || 1, # SQL_CATALOG_LOCATION + ]; + + my $quote = $info->[0]; + foreach (@id) { # quote the elements + next unless defined; + s/$quote/$quote$quote/g; # escape embedded quotes + $_ = qq{$quote$_$quote}; + } + + # strip out catalog if present for special handling + my $catalog = (@id >= 3) ? shift @id : undef; + + # join the dots, ignoring any null/undef elements (ie schema) + my $quoted_id = join '.', grep { defined } @id; + + if ($catalog) { # add catalog correctly + $quoted_id = ($info->[2] == 2) # SQL_CL_END + ? $quoted_id . $info->[1] . $catalog + : $catalog . $info->[1] . $quoted_id; + } + return $quoted_id; + } + sub quote { my ($dbh, $str, $data_type) = @_; + return "NULL" unless defined $str; unless ($data_type) { $str =~ s/'/''/g; # ISO SQL2 return "'$str'"; } - # Optimise for standard numerics which need no quotes - return $str if $data_type == DBI::SQL_INTEGER - || $data_type == DBI::SQL_SMALLINT - || $data_type == DBI::SQL_DECIMAL - || $data_type == DBI::SQL_FLOAT - || $data_type == DBI::SQL_REAL - || $data_type == DBI::SQL_DOUBLE - || $data_type == DBI::SQL_NUMERIC; - my $ti = $dbh->type_info($data_type); - # XXX needs checking - my $lp = $ti ? $ti->{LITERAL_PREFIX} || "" : "'"; - my $ls = $ti ? $ti->{LITERAL_SUFFIX} || "" : "'"; + + my $dbi_literal_quote_cache = $dbh->{'dbi_literal_quote_cache'} ||= [ {} , {} ]; + my ($prefixes, $suffixes) = @$dbi_literal_quote_cache; + + my $lp = $prefixes->{$data_type}; + my $ls = $suffixes->{$data_type}; + + if ( ! defined $lp || ! defined $ls ) { + my $ti = $dbh->type_info($data_type); + $lp = $prefixes->{$data_type} = $ti ? $ti->{LITERAL_PREFIX} || "" : "'"; + $ls = $suffixes->{$data_type} = $ti ? $ti->{LITERAL_SUFFIX} || "" : "'"; + } + return $str unless $lp || $ls; # no quoting required + # XXX don't know what the standard says about escaping # in the 'general case' (where $lp != "'"). # So we just do this and hope: @@ -933,39 +1215,65 @@ ($rows == 0) ? "0E0" : $rows; } + sub _do_selectrow { + my ($method, $dbh, $stmt, $attr, @bind) = @_; + my $sth = ((ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr)) + or return; + $sth->execute(@bind) + or return; + my $row = $sth->$method() + and $sth->finish; + return $row; + } + + sub selectrow_hashref { return _do_selectrow('fetchrow_hashref', @_); } + + # XXX selectrow_array/ref also have C implementations in Driver.xst + sub selectrow_arrayref { return _do_selectrow('fetchrow_arrayref', @_); } sub selectrow_array { - my ($dbh, $stmt, $attr, @bind) = @_; - my $sth = (ref $stmt) ? $stmt - : $dbh->prepare($stmt, $attr); - return unless $sth; - $sth->execute(@bind) || return; - my @row = $sth->fetchrow_array; - $sth->finish; - return $row[0] unless wantarray; - return @row; + my $row = _do_selectrow('fetchrow_arrayref', @_) or return; + return $row->[0] unless wantarray; + return @$row; } + # XXX selectall_arrayref also has C implementation in Driver.xst + # which fallsback to this if a slice is given sub selectall_arrayref { my ($dbh, $stmt, $attr, @bind) = @_; - my $sth = (ref $stmt) ? $stmt - : $dbh->prepare($stmt, $attr); + my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr) + or return; + $sth->execute(@bind) || return; + my $slice = $attr->{Slice}; # typically undef, else hash or array ref + if (!$slice and $slice=$attr->{Columns}) { + if (ref $slice eq 'ARRAY') { # map col idx to perl array idx + $slice = [ @{$attr->{Columns}} ]; # take a copy + for (@$slice) { $_-- } + } + } + return $sth->fetchall_arrayref($slice, $attr->{MaxRows}); + } + + sub selectall_hashref { + my ($dbh, $stmt, $key_field, $attr, @bind) = @_; + my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr); return unless $sth; $sth->execute(@bind) || return; - my $slice = $attr->{dbi_fetchall_arrayref_attr}; # typically undef - return $sth->fetchall_arrayref($slice); + return $sth->fetchall_hashref($key_field); } sub selectcol_arrayref { my ($dbh, $stmt, $attr, @bind) = @_; - my $sth = (ref $stmt) ? $stmt - : $dbh->prepare($stmt, $attr); + my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr); return unless $sth; $sth->execute(@bind) || return; - my $column = 1; - my $value; - $sth->bind_col($column, \$value) || return; + my @columns = ($attr->{Columns}) ? @{$attr->{Columns}} : (1); + my @values = (undef) x @columns; + my $idx = 0; + for (@columns) { + $sth->bind_col($_, \$values[$idx++]) || return; + } my @col; - push @col, $value while $sth->fetch; + push @col, @values while $sth->fetch; return \@col; } @@ -976,10 +1284,11 @@ # the template must handle clearing the cache themselves. my $cache = $dbh->FETCH('CachedKids'); $dbh->STORE('CachedKids', $cache = {}) unless $cache; - my $key = ($attr) ? join(" | ", $statement, %$attr) : $statement; + my @attr_keys = ($attr) ? sort keys %$attr : (); + my $key = ($attr) ? join("~~", $statement, @attr_keys, @{$attr}{@attr_keys}) : $statement; my $sth = $cache->{$key}; if ($sth) { - if ($sth->FETCH('Active')) { + if ($sth->FETCH('Active') && ($allow_active||0) != 2) { Carp::carp("prepare_cached($statement) statement handle $sth was still active") if !$allow_active; $sth->finish; @@ -996,6 +1305,13 @@ "0 but true"; # special kind of true 0 } + sub begin_work { + my $dbh = shift; + return $dbh->DBI::set_err(1, "Already in a transaction") + unless $dbh->FETCH('AutoCommit'); + $dbh->STORE('AutoCommit', 0); # will croak if driver doesn't support it + $dbh->STORE('BegunWork', 1); # trigger post commit/rollback action + } sub commit { shift->_not_impl('commit'); } @@ -1011,20 +1327,47 @@ shift->_not_impl('table_info'); } + sub column_info { + shift->_not_impl('column_info'); + } + + sub primary_key_info { + shift->_not_impl('primary_key_info'); + } + + sub primary_key { + my ($dbh, @args) = @_; + my $sth = $dbh->primary_key_info(@args) or return; + my ($row, @col); + push @col, $row->[3] while ($row = $sth->fetch); + croak("primary_key method not called in list context") + unless wantarray; # leave us some elbow room + return @col; + } + + sub foreign_key_info { + shift->_not_impl('foreign_key_info'); + } + sub tables { my ($dbh, @args) = @_; - my $sth = $dbh->table_info(@args); - return unless $sth; - my ($row, @tables); - while($row = $sth->fetch) { - my $name = $row->[2]; - if ($row->[1]) { - my $schema = $row->[1]; - # a little hack - my $quote = ($schema eq uc($schema)) ? '' : '"'; - $name = "$quote$schema$quote.$name" - } - push @tables, $name; + my $sth = $dbh->table_info(@args) or return; + my $tables = $sth->fetchall_arrayref or return; + my @tables; + if ($dbh->get_info(29)) { # SQL_IDENTIFIER_QUOTE_CHAR + @tables = map { $dbh->quote_identifier( @{$_}[0,1,2] ) } @$tables; + } + else { # temporary old style hack (yeach) + @tables = map { + my $name = $_->[2]; + if ($_->[1]) { + my $schema = $_->[1]; + # a sad hack (mostly for Informix I recall) + my $quote = ($schema eq uc($schema)) ? '' : '"'; + $name = "$quote$schema$quote.$name" + } + $name; + } @$tables; } return @tables; } @@ -1038,11 +1381,21 @@ sub type_info { my ($dbh, $data_type) = @_; - my $tia = $dbh->type_info_all; - return unless @$tia; - my $idx_hash = shift @$tia; - my $dt_idx = $idx_hash->{DATA_TYPE} - or Carp::croak("No DATA_TYPE field in type_info_all result"); + my $idx_hash; + my $tia = $dbh->{dbi_type_info_row_cache}; + if ($tia) { + $idx_hash = $dbh->{dbi_type_info_idx_cache}; + } + else { + my $temp = $dbh->type_info_all; + return unless $temp && @$temp; + $tia = $dbh->{dbi_type_info_row_cache} = $temp; + $idx_hash = $dbh->{dbi_type_info_idx_cache} = shift @$tia; + } + + my $dt_idx = $idx_hash->{DATA_TYPE} || $idx_hash->{data_type}; + Carp::croak("type_info_all returned non-standard DATA_TYPE index value ($dt_idx != 1)") + if $dt_idx && $dt_idx != 1; # --- simple DATA_TYPE match filter my @ti; @@ -1058,13 +1411,12 @@ } # --- format results into list of hash refs - my $idx_fields = keys %$idx_hash; - my @idx_names = keys %$idx_hash; + my $idx_fields = keys %$idx_hash; + my @idx_names = map { uc($_) } keys %$idx_hash; my @idx_values = values %$idx_hash; + Carp::croak "type_info_all result has $idx_fields keys but ".(@{$ti[0]})." fields" + if @ti && @{$ti[0]} != $idx_fields; my @out = map { - Carp::croak - "type_info_all result has $idx_fields keys but ".(@$_)." fields" - if @$_ != $idx_fields; my %h; @h{@idx_names} = @{$_}[ @idx_values ]; \%h; } @ti; return $out[0] unless wantarray; @@ -1080,44 +1432,153 @@ sub cancel { undef } sub bind_param { Carp::croak("Can't bind_param, not implement by driver") } - sub fetchrow_hashref { +# +# ******************************************************** +# +# BEGIN ARRAY BINDING +# +# Array binding support for drivers which don't support +# array binding, but have sufficient interfaces to fake it. +# NOTE: mixing scalars and arrayrefs requires using bind_param_array +# for *all* params...unless we modify bind_param for the default +# case... +# +# 2002-Apr-10 D. Arnold + + sub bind_param_array { + my $sth = shift; + my ($p_id, $value_array, $attr) = @_; + + return $sth->DBI::set_err(1, "Value for parameter $p_id must be a scalar or an arrayref, not a ".ref($value_array)) + if defined $value_array and ref $value_array and ref $value_array ne 'ARRAY'; + + return $sth->DBI::set_err(1, "Can't use named placeholders for non-driver supported bind_param_array") + unless DBI::looks_like_number($p_id); # because we rely on execute(@ary) here + + # get/create arrayref to hold params + my $hash_of_arrays = $sth->{ParamArrays} ||= { }; + + if (ref $value_array eq 'ARRAY') { + # check that input has same length as existing + # find first arrayref entry (if any) + foreach (keys %$hash_of_arrays) { + my $v = $$hash_of_arrays{$_}; + next unless ref $v eq 'ARRAY'; + return $sth->DBI::set_err(1, + "Arrayref for parameter $p_id has ".@$value_array." elements" + ." but parameter $_ has ".@$v) + if @$value_array != @$v; + } + } + + # If the bind has attribs then we rely on the driver conforming to + # the DBI spec in that a single bind_param() call with those attribs + # makes them 'sticky' and apply to all later execute(@values) calls. + # Since we only call bind_param() if we're given attribs then + # applications using drivers that don't support bind_param can still + # use bind_param_array() so long as they don't pass any attribs. + + $$hash_of_arrays{$p_id} = $value_array; + return $sth->bind_param($p_id, undef, $attr) + if $attr; + 1; + } + + sub bind_param_inout_array { my $sth = shift; - my $name = shift || 'NAME'; - # This may be recoded in XS. It could work with fb_av and bind_col. - # Probably best to add an AV*fields_hvav to dbih_stc_t and set it up - # on the first call to fetchhash which alternate name/value pairs. - # This implementation is just rather simple and not very optimised. - # Notes for XS implementation: since apps may add entries to the hash - # before the next fetch we need to check the key count and, if changed, - # scan the hash and delete inappropriate keys. - my $row = $sth->fetch or return undef; - my %hash; - @hash{ @{ $sth->FETCH($name) } } = @$row; - return \%hash; + # XXX not supported so we just call bind_param_array instead + # and then return an error + my ($p_num, $value_array, $attr) = @_; + $sth->bind_param_array($p_num, $value_array, $attr); + return $sth->DBI::set_err(1, "bind_param_inout_array not supported"); } - sub fetchall_arrayref { + sub execute_array { my $sth = shift; - my $slice= shift || []; - my $mode = ref $slice; + my ($attribs, @array_of_arrays) = @_; + + # get tuple status array or hash attribute (if any) + my $tuple_sts = $attribs->{ArrayTupleStatus}; + return $sth->DBI::set_err(1, "ArrayTupleStatus attribute must be an arrayref") + if $tuple_sts and ref $tuple_sts ne 'ARRAY'; + + # bind all supplied arrays + if (@array_of_arrays) { + $sth->{ParamArrays} = { }; # clear out old params + my $NUM_OF_PARAMS = $sth->FETCH('NUM_OF_PARAMS'); + return $sth->DBI::set_err(1, @array_of_arrays." bind values supplied but $NUM_OF_PARAMS expected") + if @array_of_arrays != $NUM_OF_PARAMS; + $sth->bind_param_array($_, $array_of_arrays[$_-1]) or return + foreach (1..@array_of_arrays); + } + + # no binds, no args, why did they call us ? just toss it to execute() + return $sth->execute + unless $sth->{ParamArrays}; + + # get the length of a bound array + my $len = 1; # in case all are scalars + my %hash_of_arrays = %{$sth->{ParamArrays}}; + foreach (keys(%hash_of_arrays)) { + my $ary = $hash_of_arrays{$_}; + $len = @$ary if ref $ary eq 'ARRAY'; + } + my @bind_ids = 1..keys(%hash_of_arrays); + + my ($errcount, $rowcount); + my %errstr_cache; + @$tuple_sts = () if $tuple_sts; # reset the status array + $tuple_sts->[$len-1] = undef; # presize array + for (my $i=0; $i < $len; ++$i) { # for each tuple + + my @tuple = map { + my $a = $hash_of_arrays{$_}; + ref($a) ? $a->[$i] : $a + } @bind_ids; + my $rc = $sth->execute(@tuple); + if ($rc) { + $rowcount += $tuple_sts->[$i] = $rc; + next; + } + + return unless $tuple_sts; # return error if no status provided + $errcount++; + my $err = $sth->err; + $tuple_sts->[$i] = [ $err, $errstr_cache{$err} ||= $sth->errstr ]; + } + return ($errcount) ? undef : $rowcount; + } + + + sub fetchall_arrayref { # ALSO IN Driver.xst + my ($sth, $slice, $max_rows) = @_; + $max_rows = -1 unless defined $max_rows; + my $mode = ref($slice) || 'ARRAY'; my @rows; my $row; if ($mode eq 'ARRAY') { # we copy the array here because fetch (currently) always # returns the same array ref. XXX - if (@$slice) { - push @rows, [ @{$row}[ @$slice] ] while($row = $sth->fetch); + if ($slice && @$slice) { + $max_rows = -1 unless defined $max_rows; + push @rows, [ @{$row}[ @$slice] ] + while($max_rows-- and $row = $sth->fetch); + } + elsif (defined $max_rows) { + $max_rows = -1 unless defined $max_rows; + push @rows, [ @$row ] + while($max_rows-- and $row = $sth->fetch); } else { - push @rows, [ @$row ] while($row = $sth->fetch); + push @rows, [ @$row ] while($row = $sth->fetch); } } elsif ($mode eq 'HASH') { - my @o_keys = keys %$slice; - if (@o_keys) { - my %i_names = map { (lc($_)=>$_) } @{ $sth->FETCH('NAME') }; - my @i_keys = map { $i_names{lc($_)} } @o_keys; - while ($row = $sth->fetchrow_hashref) { + $max_rows = -1 unless defined $max_rows; + if (keys %$slice) { + my @o_keys = keys %$slice; + my @i_keys = map { lc } keys %$slice; + while ($max_rows-- and $row = $sth->fetchrow_hashref('NAME_lc')) { my %hash; @hash{@o_keys} = @{$row}{@i_keys}; push @rows, \%hash; @@ -1125,13 +1586,33 @@ } else { # XXX assumes new ref each fetchhash - push @rows, $row while ($row = $sth->fetchrow_hashref); + push @rows, $row + while ($max_rows-- and $row = $sth->fetchrow_hashref()); } } else { Carp::croak("fetchall_arrayref($mode) invalid") } return \@rows; } + sub fetchall_hashref { # XXX may be better to fetchall_arrayref then convert to hashes + my ($sth, $key_field) = @_; + + my $hash_key_name = $sth->{FetchHashKeyName}; + my $names_hash = $sth->FETCH("${hash_key_name}_hash"); + my $index = $names_hash->{$key_field}; # perl index not column number + ++$index if defined $index; # convert to column number + $index ||= $key_field if DBI::looks_like_number($key_field) && $key_field>=1; + return $sth->DBI::set_err(1, "Field '$key_field' does not exist (not one of @{[keys %$names_hash]})") + unless defined $index; + my $key_value; + $sth->bind_col($index, \$key_value) or return; + my %rows; + while (my $row = $sth->fetchrow_hashref($hash_key_name)) { + $rows{ $key_value } = $row; + } + return \%rows; + } + *dump_results = \&DBI::dump_results; sub blob_copy_to_file { # returns length or undef on error @@ -1160,7 +1641,7 @@ sub DESTROY { Carp::croak("Driver has not implemented DESTROY for @_") } } -{ # See install_driver +unless ($DBI::PurePerl) { # See install_driver { package DBD::_mem::dr; @ISA = qw(DBD::_mem::common); } { package DBD::_mem::db; @ISA = qw(DBD::_mem::common); } { package DBD::_mem::st; @ISA = qw(DBD::_mem::common); } @@ -1176,7 +1657,7 @@ a set of methods, variables, and conventions that provide a consistent database interface, independent of the actual database being used. -It is important to remember that the DBI is just an interface. +It is important to remember that the DBI is just an interface. The DBI is a layer of "glue" between an application and one or more database I modules. It is the driver modules which do most of the real work. The DBI @@ -1198,7 +1679,7 @@ `-------' | |... `-' -The API, or Application Programming Interface, defines the +The API, or Application Programming Interface, defines the call interface and variables for Perl scripts to use. The API is implemented by the Perl DBI extension. @@ -1207,7 +1688,7 @@ of drivers, error checking and handling, providing default implementations for methods, and many other non-database specific duties. -Each driver +Each driver contains implementations of the DBI methods using the private interface functions of the corresponding database engine. Only authors of sophisticated/multi-database applications or generic library @@ -1235,7 +1716,7 @@ =head2 Outline Usage -To use DBI, +To use DBI, first you need to load the DBI module: use DBI; @@ -1291,7 +1772,7 @@ $sth = $dbh->prepare("INSERT INTO table(foo,bar,baz) VALUES (?,?,?)"); while() { - chop; + chomp; my ($foo,$bar,$baz) = split /,/; $sth->execute( $foo, $bar, $baz ); } @@ -1322,9 +1803,9 @@ handled without loss of accuracy. Beware that Perl may not preserve the same accuracy when the string is used as a number. -Dates and times are returned as character strings in the native format -of the corresponding database engine. Time zone effects are -database/driver dependent. +Dates and times are returned as character strings in the current +default format of the corresponding database engine. Time zone effects +are database/driver dependent. Perl supports binary data in Perl strings, and the DBI will pass binary data to and from the driver without change. It is up to the driver @@ -1389,6 +1870,7 @@ Driver Specific Prefix Registry: + ad_ DBD::AnyData ado_ DBD::ADO best_ DBD::BestWins csv_ DBD::CSV @@ -1404,15 +1886,20 @@ ora_ DBD::Oracle pg_ DBD::Pg proxy_ DBD::Proxy + rdb_ DBD::RDB + sapdb_ DBD::SAP_DB solid_ DBD::Solid syb_ DBD::Sybase + sql_ SQL::Statement (used by some drivers) + tdat_ DBD::Teradata tuber_ DBD::Tuber + uni_ DBD::Unify xbase_ DBD::XBase =head2 SQL - A Query Language -Most DBI drivers require applications to use a dialect of SQL +Most DBI drivers require applications to use a dialect of SQL (Structured Query Language) to interact with the database engine. The following links provide useful information and further links about SQL: @@ -1438,7 +1925,7 @@ =head2 Placeholders and Bind Values -Some drivers support placeholders and bind values. +Some drivers support placeholders and bind values. I, also called parameter markers, are used to indicate values in a database statement that will be supplied later, before the prepared statement is executed. For example, an application @@ -1489,13 +1976,13 @@ my $sth = $dbh->prepare(q{ INSERT INTO sales (product_code, qty, price) VALUES (?, ?, ?) - }) || die $dbh->errstr; + }) or die $dbh->errstr; while (<>) { - chop; + chomp; my ($product_code, $qty, $price) = split /,/; - $sth->execute($product_code, $qty, $price) || die $dbh->errstr; + $sth->execute($product_code, $qty, $price) or die $dbh->errstr; } - $dbh->commit || die $dbh->errstr; + $dbh->commit or die $dbh->errstr; See L and L for more details. @@ -1507,11 +1994,35 @@ See also the L method, which is used to associate Perl variables with the output columns of a C statements that either cannot be prepared in advance (due to a limitation of the @@ -2181,7 +2877,7 @@ my $rows_deleted = $dbh->do(q{ DELETE FROM table WHERE status = ? - }, undef, 'DONE') || die $dbh->errstr; + }, undef, 'DONE') or die $dbh->errstr; Using placeholders and C<@bind_values> with the C method can be useful because it avoids the need to correctly quote any variables @@ -2202,19 +2898,51 @@ This utility method combines L, L and L into a single call. If called in a list context, it -returns the first row of data from the statement. If called in a scalar -context, it returns the first field of the first row. The C<$statement> +returns the first row of data from the statement. The C<$statement> parameter can be a previously prepared statement handle, in which case the C is skipped. If any method fails, and L is not set, C will return an empty list. -In a scalar context, C returns the value of the first -field. An C is returned if there are no matching rows or an error -occurred. Since that C can't be distinguished from an C returned -because the first field value was NULL, calling C in -a scalar context should be used with caution. +If called in a scalar context for a statement handle that has more +than one column, it is undefined whether the driver will return +the value of the first column or the last. So don't do that. +Also, in a scalar context, an C is returned if there are no +more rows or if an error occurred. That C can't be distinguished +from an C returned because the first field value was NULL. +For these reasons you should exercise some caution if you use +C in a scalar context. + + +=item C + + $ary_ref = $dbh->selectrow_arrayref($statement); + $ary_ref = $dbh->selectrow_arrayref($statement, \%attr); + $ary_ref = $dbh->selectrow_arrayref($statement, \%attr, @bind_values); + +This utility method combines L, L and +L into a single call. It returns the first row of +data from the statement. The C<$statement> parameter can be a previously +prepared statement handle, in which case the C is skipped. + +If any method fails, and L is not set, C +will return undef. + + +=item C + + $hash_ref = $dbh->selectrow_hashref($statement); + $hash_ref = $dbh->selectrow_hashref($statement, \%attr); + $hash_ref = $dbh->selectrow_hashref($statement, \%attr, @bind_values); + +This utility method combines L, L and +L into a single call. It returns the first row of +data from the statement. The C<$statement> parameter can be a previously +prepared statement handle, in which case the C is skipped. + +If any method fails, and L is not set, C +will return undef. =item C @@ -2231,10 +2959,47 @@ in which case the C is skipped. This is recommended if the statement is going to be executed many times. -If any method except C fails, and L is not set, -C will return C. If C fails and +If L is not set and any method except C +fails then C will return C; if +C fails then it will return with whatever data +has been fetched thus far. You should check C<$sth->EC +afterwards (or use the C attribute) to discover if the data is +complete or was truncated due to an error. + +The L method called by C +supports a $max_rows parameter. You can specify a value for $max_rows +by including a 'C' attribute in \%attr. + +The L method called by C +also supports a $slice parameter. You can specify a value for $slice by +including a 'C' or 'C' attribute in \%attr. The only +difference between the two is that if C is not defined and +C is an array ref, then the array is assumed to contain column +index values (which count from 1), rather than perl array index values. +In which case the array is copied and each value decremented before +passing to C. + + +=item C + + $hash_ref = $dbh->selectall_hashref($statement, $key_field); + $hash_ref = $dbh->selectall_hashref($statement, $key_field, \%attr); + $hash_ref = $dbh->selectall_hashref($statement, $key_field, \%attr, @bind_values); + +This utility method combines L, L and +L into a single call. It returns a reference to a +hash containing one entry for each row. The key for each row entry is +specified by $key_field. The value is a reference to a hash returned by +C. + +The C<$statement> parameter can be a previously prepared statement handle, +in which case the C is skipped. This is recommended if the +statement is going to be executed many times. + +If any method except C fails, and L is not set, +C will return C. If C fails and L is not set, then it will return with whatever data it -has fetched thus far. +has fetched thus far. $DBI::err should be checked to catch that. =item C @@ -2252,15 +3017,26 @@ statement is going to be executed many times. If any method except C fails, and L is not set, -C will return C. If C fails and +C will return C. If C fails and L is not set, then it will return with whatever data it -has fetched thus far. +has fetched thus far. $DBI::err should be checked to catch that. + +The C method defaults to pushing a single column +value (the first) from each row into the result array. However, it can +also push another column, or even multiple columns per row, into the +result array. This behaviour can be specified via a 'C' +attribute which must be a ref to an array containing the column number +or numbers to use. For example: + + # get array of id and name pairs: + my $ary_ref = $dbh->selectcol_arrayref("select id, name from table", { Columns=>[1,2] }); + my %hash = @$ary_ref; # build hash from key-value pairs so $hash{$id} => name =item C - $sth = $dbh->prepare($statement) || die $dbh->errstr; - $sth = $dbh->prepare($statement, \%attr) || die $dbh->errstr; + $sth = $dbh->prepare($statement) or die $dbh->errstr; + $sth = $dbh->prepare($statement, \%attr) or die $dbh->errstr; Prepares a single statement for later execution by the database engine and returns a reference to a statement handle object. @@ -2304,29 +3080,81 @@ corresponding cached C<$sth> will be returned without contacting the database server. -This caching can be useful in some applications, but it can also cause -problems and should be used with care. If the cached C<$sth> being -returned is active (i.e., is a C statement without further -qualification. +Simple interface to table_info(). Returns a list of matching +table names, possibly including a catalog/schema prefix. -Note that C might not return records for all tables. -Applications can use any valid table regardless of whether it's -returned by tables. See also L. +See L for a description of the parameters. +If C<$dbh->EC returns true (29 is SQL_IDENTIFIER_QUOTE_CHAR) +then the table names are constructed and quoted by L +to ensure they are usable even if they contain whitespace or reserved +words etc. -=item C I + +=item C B This method is experimental and may change. @@ -2473,10 +3679,11 @@ type variant supported by the database and driver. The array and its contents should be treated as read-only. -The first item is a reference to a hash of CE C pairs. The -following items are references to arrays, one per supported data type -variant. The leading hash defines the names and order of the fields -within the following list of arrays. For example: +The first item is a reference to an 'index' hash of CE C pairs. +The items following that are references to arrays, one per supported data +type variant. The leading index hash defines the names and order of the +fields within the arrays that follow it. +For example: $type_info_all = [ { TYPE_NAME => 0, @@ -2520,22 +3727,33 @@ This method is not normally used directly. The L method provides a more useful interface to the data. -=item C I +Even though an 'index' hash is provided, all the field names in the +index hash defined above will always have the index values defined +above. This is defined behaviour so that you don't need to rely on the +index hash, which is handy because the lettercase of the keys is not +defined. It is usually uppercase, as show here, but drivers are free to +return names with any lettercase. Drivers are also free to return extra +driver-specific columns of information - though it's recommended that +they start at column index 50 to leave room for expansion of the +DBI/ODBC specification. + + +=item C B This method is experimental and may change. @type_info = $dbh->type_info($data_type); Returns a list of hash references holding information about one or more -variants of C<$data_type>. The list is ordered by C first and +variants of $data_type. The list is ordered by C first and then by how closely each type maps to the corresponding ODBC SQL data type, closest first. If called in a scalar context then only the first (best) element is returned. -If C<$data_type> is undefined or C, then the list will +If $data_type is undefined or C, then the list will contain hashes for all data type variants supported by the database and driver. -If C<$data_type> is an array reference then C returns the +If $data_type is an array reference then C returns the information for the I type in the array that has any matches. The keys of the hash follow the same letter case conventions as the @@ -2611,7 +3829,7 @@ =item FIXED_PREC_SCALE (boolean) Indicates whether the data type always has the same precision and scale -(such as a money type). NULL (C) is returned for data types +(such as a money type). NULL (C) is returned for data types for which this is not applicable. @@ -2657,7 +3875,7 @@ =item NUM_PREC_RADIX (integer) -The radix value of the data type. For approximate numeric types, +The radix value of the data type. For approximate numeric types, C contains the value 2 and C holds the number of bits. For exact numeric types, C contains the value 10 and C holds @@ -2672,6 +3890,11 @@ =back +For example, to find the type name for the fields in a select statement +you can do: + + @names = map { scalar $dbh->type_info($_)->{TYPE_NAME} } @{ $sth->{TYPE} } + Since DBI and ODBC drivers vary in how they map their types into the ISO standard types you may need to search for more than one type. Here's an example looking for a usable type to store a date: @@ -2681,25 +3904,8 @@ Similarly, to more reliably find a type to store small integers, you could use a list starting with C, C, C, etc. -For more detailed information about these fields and their meanings, you -can refer to: - - http://msdn.microsoft.com/library/psdk/dasdk/odch6yy7.htm - -If that URL ceases to work then use the MSDN search facility at - - http://search.microsoft.com/us/dev/ - -and search the MSDN Library for C using the exact phrase option. -The link you want will probably just be called C (there -may be more than one). - -The individual data types are currently described here: +See also L. - http://msdn.microsoft.com/library/psdk/dasdk/odap8fcj.htm - -If that URL ceases to work, or to get more general information, use the -MSDN search facility as described above and search for C. =item C @@ -2718,7 +3924,7 @@ outer quotation marks). An undefined C<$value> value will be returned as the string C (without -quotation marks) to match how NULLs are represented in SQL. +single quotation marks) to match how NULLs are represented in SQL. If C<$data_type> is supplied, it is used to try to determine the required quoting behavior by using the information returned by L. @@ -2730,6 +3936,32 @@ any way with escaping or quoting shell meta-characters. There is no need to quote values being used with L. +=item C + + $sql = $dbh->quote_identifier( $name ); + $sql = $dbh->quote_identifier( $name1, $name2, $name3, \%attr ); + +Quote an identifier (table name etc.) for use in an SQL statement, +by escaping any special characters (such as double quotation marks) +it contains and adding the required type of outer quotation marks. + +Undefined names are ignored and the remainder are quoted and then +joined together, typically with a dot (C<.>) character. For example: + + $id = $dbh->quote_identifier( undef, 'Her schema', 'My table' ); + +would, for most database types, return C<"Her schema"."My table"> +(including all the double quotation marks). + +If three names are supplied then the first is assumed to be a catalog +name and special rules may be applied based on what L +returns for SQL_CATALOG_NAME_SEPARATOR (41) and SQL_CATALOG_LOCATION (114). +For example, for Oracle: + + $id = $dbh->quote_identifier( 'link', 'schema', 'table' ); + +would return C<"schema"."table"@"link">. + =back @@ -2764,7 +3996,7 @@ Attempting to set C to an unsupported value is a fatal error. This is an important feature of the DBI. Applications that need full transaction behavior can set C<$dbh->EC<{AutoCommit} = 0> (or -set C to 0 via L) +set C to 0 via L) without having to check that the value was assigned successfully. For the purposes of this description, we can divide databases into three @@ -2789,15 +4021,13 @@ L). If L is called then any changes since the last commit are undone. -If C is on, then the effect is the same as if the DBI +If C is on, then the effect is the same as if the DBI called C automatically after every successful database -operation. In other words, calling C or C explicitly while +operation. So calling C or C explicitly while C is on would be ineffective because the changes would have already been commited. -Changing C from off to on should issue a L in most drivers. - -Changing C from on to off should have no immediate effect. +Changing C from off to on will trigger a L. For databases which don't support a specific auto-commit mode, the driver has to commit each statement automatically using an explicit @@ -2811,13 +4041,16 @@ For these databases, the intention is to have them act like databases in which a transaction is always active (as described above). -To do this, the DBI driver will automatically begin a transaction when -C is turned off (from the default "on" state) and will -automatically begin another transaction after a L or L. -In this way, the application does not have to treat these databases as a -special case. +To do this, the driver will automatically begin an explicit transaction +when C is turned off, or after a L or +L (or when the application issues the next database +operation after one of those events). -See L for other important notes about transactions. +In this way, the application does not have to treat these databases +as a special case. + +See L, L and L for other important +notes about transactions. =item C (handle) @@ -2835,7 +4068,15 @@ but with the leading "C" removed. -=item C (integer) I +=item C (string, read-only) + +Returns the statement string passed to the most recent L method +called in this database handle, even if that method failed. This is especially +useful where C is enabled and the exception handler checks $@ +and sees that a 'prepare' method call failed. + + +=item C (integer) A hint to the driver indicating the size of the local row cache that the application would like the driver to use for future C statement, the driver -should automatically call C for you. So you should not normally -need to call it explicitly. +is rarely needed, but can sometimes be helpful in very specific +situations to allow the server to free up resources (such as sort +buffers). + +When all the data has been fetched from a C statement handle that's a child +of the same database handle. A typical way round this is to connect the +the database twice and use one connection for C