⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbd.pm

📁 SinFP是一种新的识别对方计算机操作系统类型的工具
💻 PM
📖 第 1 页 / 共 5 页
字号:
Besides that the STORE and FETCH methods are mainly the sameas above for dbh's.=head4 Other statement methodsA trivial C<finish> method to discard the stored data and do$sth->SUPER::finish;If you've defined a parse_trace_flag() method in ::db you'll also wantit in ::st, so just alias it in:  *parse_trace_flag = \&DBD::foo:db::parse_trace_flag;And perhaps some other methods that are not part of the DBIspecification, in particular to make metadata available.Remember that they must have names that begin with your driversregistered prefix so they can be installed using install_method().If DESTROY() is called on a statement handle that's still active($sth->{Active} is true) then it should effectively call finish().    sub DESTROY {        my $sth = shift;        $sth->finish if $sth->FETCH('Active');    }=head2 TestsThe test process should conform as closely as possibly to the Perlstandard test harness.In particular, most (all) of the tests should be run in the t sub-directory,and should simply produce an 'ok' when run under 'make test'.For details on how this is done, see the Camel book and the section inChapter 7, "The Standard Perl Library" on L<Test::Harness>.The tests may need to adapt to the type of database which is beingused for testing, and to the privileges of the user testing thedriver.The DBD::Informix test code has to adapt in a number of places to thetype of database to which it is connected as different Informixdatabases have different capabilities.For example, some of the tests are for databases without transactionlogs; others are for databases with a transaction log.Some versions of the server have support for blobs, or storedprocedures, or user-defined data types, and others do not.When a complete file of tests must be skipped, you can provide a reasonin a pseudo-comment:    if ($no_transactions_available)    {        print "1..0 # Skip: No transactions available\n";        exit 0;    }Consider downloading the DBD::Informix code and look at the code inDBD/Informix/TestHarness.pm which is used throughout theDBD::Informix tests in the t sub-directory.=head1 CREATING A C/XS DRIVERCreating a new C/XS driver from scratch will always be a daunting task.You can and should greatly simplify your task by taking a goodreference driver implementation and modifying that to match thedatabase product for which you are writing a driver.The de facto reference driver has been the one for DBD::Oracle writtenby Tim Bunce, who is also the author of the DBI package. The DBD::Oraclemodule is a good example of a driver implemented around a C-level API.Nowadays it it seems better to base on DBD::ODBC, another drivermaintained by Tim and Jeff Urlwin, because it offers a lot of metadataand seems to become the guideline for the future development. (Also asDBD::Oracle digs deeper into the Oracle 8 OCI interface it'll get evenmore hairy than it is now.)The DBD::Informix driver is one driver implemented using embedded SQLinstead of a function-based API.DBD::Ingres may also be worth a look.=head2 C/XS version of Driver.pmA lot of the code in the Driver.pm file is very similar to the code for pure Perl modules- see above.  However,there are also some subtle (and not so subtle) differences, including:=over 8=item *The variables $DBD::File::{dr|db|st}::imp_data_size are not definedhere, but in the XS code, because they declare the size of certainC structures.=item *Some methods are typically moved to the XS code, in particularI<prepare>, I<execute>, I<disconnect>, I<disconnect_all> and the STOREand FETCH methods.=item *Other methods are still part of C<Driver.pm>, but have callbacks tothe XS code.=item *If the driver-specific parts of the imp_drh_t structure need to beformally initialized (which does not seem to be a common requirement),then you need to add a call to an appropriate XS function in the drivermethod of DBD::Driver::driver, and you define the corresponding functionin Driver.xs, and you define the C code in dbdimp.c and the prototype indbdimp.h.For example, DBD::Informix has such a requirement, and adds thefollowing call after the call to _new_drh in Informix.pm:  DBD::Informix::dr::driver_init($drh);and the following code in Informix.xs:  # Initialize the DBD::Informix driver data structure  void  driver_init(drh)      SV *drh      CODE:      ST(0) = dbd_ix_dr_driver_init(drh) ? &sv_yes : &sv_no;and the code in dbdimp.h declares:  extern int dbd_ix_dr_driver_init(SV *drh);and the code in dbdimp.ec (equivalent to dbdimp.c) defines:  /* Formally initialize the DBD::Informix driver structure */  int  dbd_ix_dr_driver(SV *drh)  {      D_imp_drh(drh);      imp_drh->n_connections = 0;       /* No active connections */      imp_drh->current_connection = 0;  /* No current connection */      imp_drh->multipleconnections = (ESQLC_VERSION >= 600) ? True : False;      dbd_ix_link_newhead(&imp_drh->head);  /* Empty linked list of connections */      return 1;  }DBD::Oracle has a similar requirement but gets around it by checkingwhether the private data part of the driver handle is all zeroed out,rather than add extra functions.=backNow let's take a closer look at an excerpt from Oracle.pm (revisedheavily to remove idiosyncrasies) as an example.We also ignore things that are already discussed for pure Perl drivers.=head3 The connect methodThe connect method is the database handle constructor.You could write either of two versions of this method: either one whichtakes connection attributes (new code) and one which ignores them (oldcode only).If you ignore the connection attributes, then you omit all mention ofthe $auth variable (which is a reference to a hash of attributes), andthe XS system manages the differences for you.  sub connect  {      my ($drh, $dbname, $user, $auth, $attr) = @_;      # Some database specific verifications, default settings      # and the like following here. This should only include      # syntax checks or similar stuff where it's legal to      # 'die' in case of errors.      my $dbh = DBI::_new_dbh($drh, {              'Name'   => $dbname,          })          or return undef;      # Call the driver-specific function _login in Driver.xs file which      # calls the DBMS-specific function(s) to connect to the database,      # and populate internal handle data.      DBD::Driver::db::_login($dbh, $dbname, $user, $auth, $attr)          or return undef;      $dbh;  }This is mostly the same as in the pure Perl case, the exception beingthe use of the private I<_login> callback, which is the function thatwill really connect to the database.It is implemented in Driver.xst (you should not implement it) and callsI<dbd_db_login6> from I<dbdimp.c>.See below for details. *FIX ME* Discuss removing attributes from hash reference as an optimization to skip later calls to $dbh->STORE made by DBI->connect. *FIX ME* Discuss removing attributes in Perl code. *FIX ME* Discuss removing attributes in C code.=head3 The disconnect_all method *FIX ME* T.B.S=head3 The data_sources methodIf your I<data_sources> method can be implemented in pure Perl, then doso because it is easier than doing it in XS code (see the section abovefor pure Perl drivers).If your I<data_sources> method must call onto compiled functions, thenyou will need to define dbd_dr_data_sources in your dbdimp.h file, whichwill trigger Driver.xst (in DBI v1.33 or greater) to generate the XScode that calls your actual C function (see the discussion below fordetails) and you do not code anything in Driver.pm to handle it.=head3 The prepare methodThe prepare method is the statement handle constructor, and most of itis not new.Like the I<connect> method, it now has a C callback:  package DBD::Driver::db; # ====== DATABASE ======  use strict;  sub prepare  {      my ($dbh, $statement, $attribs) = @_;      # create a 'blank' sth      my $sth = DBI::_new_sth($dbh, {          'Statement' => $statement,          })          or return undef;      # Call the driver-specific function _prepare in Driver.xs file      # which calls the DBMS-specific function(s) to prepare a statement      # and populate internal handle data.      DBD::Driver::st::_prepare($sth, $statement, $attribs)          or return undef;      $sth;  }=head3 The execute method *FIX ME* T.B.S=head3 The fetchrow_arrayref method *FIX ME* T.B.S=head3 Other methods? *FIX ME* T.B.S=head2 Driver.xsDriver.xs should look something like this:  #include "Driver.h"  DBISTATE_DECLARE;  INCLUDE: Driver.xsi  MODULE = DBD::Driver    PACKAGE = DBD::Driver::dr  /* Non-standard drh XS methods following here, if any.       */  /* If none (the usual case), omit the MODULE line above too. */  MODULE = DBD::Driver    PACKAGE = DBD::Driver::db  /* Non-standard dbh XS methods following here, if any.       */  /* Currently this includes things like _list_tables from     */  /* DBD::mSQL and DBD::mysql.                                 */  MODULE = DBD::Driver    PACKAGE = DBD::Driver::st  /* Non-standard sth XS methods following here, if any.       */  /* In particular this includes things like _list_fields from */  /* DBD::mSQL and DBD::mysql for accessing metadata.          */Note especially the include of I<Driver.xsi> here: DBI inserts stubfunctions for almost all private methods here which will typically domuch work for you.Wherever you really have to implement something, it will call a privatefunction in I<dbdimp.c>, and this is what you have to implement.You need to set up an extra routine if your driver needs to exportconstants of its own, analogous to the SQL types available when you say:  use DBI qw(:sql_types); *FIX ME* T.B.S=head2 Driver.hDriver.h is very simple and the operational contents should look like this:  #ifndef DRIVER_H_INCLUDED  #define DRIVER_H_INCLUDED  #define NEED_DBIXS_VERSION 93    /* 93 for DBI versions 1.00 to 1.32 */  #include <DBIXS.h>      /* installed by the DBI module  */  #include "dbdimp.h"  #include "dbivport.h"   /* see below                    */  #include <dbd_xsh.h>    /* installed by the DBI module  */  #endif /* DRIVER_H_INCLUDED */The C<DBIXS.h> header defines most of the interesting information thatthe writer of a driver needs.The file C<dbd_xsh.h> header provides prototype declarations for the Cfunctions that you might decide to implement.Note that you should normally only define one of I<dbd_db_login> andI<dbd_db_login6> unless you are intent on supporting really old versions ofDBI (prior to DBI 1.06) as well as modern versions.The only standard, DBI-mandated functions that you need write are thosespecified in the dbd_xsh.h header.You might also add extra driver-specific functions in Driver.xs.The dbivport.h file should be I<copied> from the latest DBI release intoyour distribution each time you enhance your driver to use new featuresfor which the DBI is offering backwards compatibility via dbivport.h.Its job is to allow you to enhance your code to work with the latestDBI API while still allowing your driver to be compiled and usedwith older versions of the DBI. For example, when the DBIh_SET_ERR_CHARmacro was added to DBI 1.41 in an emulation of it was added to dbivport.h.Copying dbivport.h into your driver distribution and #including itin Driver.h, as shown above, lets you enhance your driver to usethe new DBIh_SET_ERR_CHAR macro even with versions of the DBI earlierthan 1.41. This makes users happy and your life easier.Always read the notes in dbivport.h to check for any limitationsin the emulation that you should be aware of.=head2 Implementation header dbdimp.hThis header file has two jobs:First it defines data structures for your private part of the handles.Second it defines macros that rename the generic names likeI<dbd_db_login> to database specific names like I<ora_db_login>. Thisavoids name clashes and enables use of different drivers when you workwith a statically linked perl.It also will have the important task of disabling XS methods that youdon't want to implement.Finally, the macros will also be used to select alternateimplementations of some functions.For example, the I<dbd_db_login> function is not passed the attributehash.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -