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

📄 dbi::dbd.3

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 3
📖 第 1 页 / 共 5 页
字号:
.Vb 10\&       while (1) {\&           my @tuple_batch;\&           for (my $i = 0; $i < $batch_size; $i++) {\&                push @tuple_batch, [ @{$fetch_tuple_sub\->() || last} ];\&           }\&           last unless @tuple_batch;\&           my $res = ora_execute_array($sth, \e@tuple_batch,\&              scalar(@tuple_batch), $tuple_batch_status);\&           push @$tuple_status, @$tuple_batch_status;\&       }.Ve.PPNote that \s-1DBI\s0's default \fIexecute_array()\fR/\fIexecute_for_fetch()\fR implementationrequires the use of positional (i.e., '?') placeholders. Driverswhich \fBrequire\fR named placeholders must either emulate positionalplaceholders (e.g., see DBD::Oracle), or must implement their own\&\fIexecute_array()\fR/\fIexecute_for_fetch()\fR methods to properly sequence boundparameter arrays..PPFetching data.IX Subsection "Fetching data".PPOnly one method needs to be written for fetching data, \f(CW\*(C`fetchrow_arrayref()\*(C'\fR.The other methods, \f(CW\*(C`fetchrow_array()\*(C'\fR, \f(CW\*(C`fetchall_arrayref()\*(C'\fR, etc, as wellas the database handle's \f(CW\*(C`select*\*(C'\fR methods are part of \fB\s-1DBI\s0\fR, and call\&\f(CW\*(C`fetchrow_arrayref()\*(C'\fR as necessary..PP.Vb 10\&  sub fetchrow_arrayref\&  {\&      my ($sth) = @_;\&      my $data = $sth\->{drv_data};\&      my $row = shift @$data;\&      if (!$row) {\&          $sth\->STORE(Active => 0); # mark as no longer active\&          return undef;\&      }\&      if ($sth\->FETCH(\*(AqChopBlanks\*(Aq)) {\&          map { $_ =~ s/\es+$//; } @$row;\&      }\&      return $sth\->_set_fbav($row);\&  }\&  *fetch = \e&fetchrow_arrayref; # required alias for fetchrow_arrayref.Ve.PPNote the use of the method \f(CW\*(C`_set_fbav()\*(C'\fR \*(-- this is required so that\&\f(CW\*(C`bind_col()\*(C'\fR and \f(CW\*(C`bind_columns()\*(C'\fR work..PPIf an error occurs which leaves the \fI\f(CI$sth\fI\fR in a state where remaining rowscan't be fetched then \fIActive\fR should be turned off before the method returns..PPThe \f(CW\*(C`rows()\*(C'\fR method for this driver can be implemented like this:.PP.Vb 1\&  sub rows { shift\->{drv_rows} }.Ve.PPbecause it knows in advance how many rows it has fetched.Alternatively you could delete that method and so fallbackto the \fB\s-1DBI\s0\fR's own method which does the right thing basedon the number of calls to \f(CW\*(C`_set_fbav()\*(C'\fR..PPThe more_results method.IX Subsection "The more_results method".PPIf your driver doesn't support multiple result sets, then don't even implement this method..PPOtherwise, this method needs to get the statement handle ready to fetch resultsfrom the next result set, if there is one. Typically you'd start with:.PP.Vb 1\&    $sth\->finish;.Ve.PPthen you should delete all the attributes from the attribute cache that may nolonger be relevant for the new result set:.PP.Vb 2\&    delete $sth\->{$_}\&        for qw(NAME TYPE PRECISION SCALE ...);.Ve.PPfor drivers written in C use:.PP.Vb 6\&    hv_delete((HV*)SvRV(sth), "NAME", 4, G_DISCARD);\&    hv_delete((HV*)SvRV(sth), "NULLABLE", 8, G_DISCARD);\&    hv_delete((HV*)SvRV(sth), "NUM_OF_FIELDS", 13, G_DISCARD);\&    hv_delete((HV*)SvRV(sth), "PRECISION", 9, G_DISCARD);\&    hv_delete((HV*)SvRV(sth), "SCALE", 5, G_DISCARD);\&    hv_delete((HV*)SvRV(sth), "TYPE", 4, G_DISCARD);.Ve.PPDon't forget to also delete, or update, any driver-private attributes that maynot be correct for the next resultset..PPThe \s-1NUM_OF_FIELDS\s0 attribute is a special case. It should be set using \s-1STORE:\s0.PP.Vb 2\&    $sth\->STORE(NUM_OF_FIELDS => 0); /* for DBI <= 1.53 */\&    $sth\->STORE(NUM_OF_FIELDS => $new_value);.Ve.PPfor drivers written in C use this incantation:.PP.Vb 5\&    /* Adjust NUM_OF_FIELDS \- which also adjusts the row buffer size */\&    DBIc_NUM_FIELDS(imp_sth) = 0; /* for DBI <= 1.53 */\&    DBIc_STATE(imp_xxh)\->set_attr_k(sth, sv_2mortal(newSVpvn("NUM_OF_FIELDS",13)), 0,\&        sv_2mortal(newSViv(mysql_num_fields(imp_sth\->result)))\&    );.Ve.PPFor \s-1DBI\s0 versions prior to 1.54 you'll also need to explicitly adjust thenumber of elements in the row buffer array (\f(CW\*(C`DBIc_FIELDS_AV(imp_sth)\*(C'\fR)to match the new result set. Fill any new values with \fInewSV\fR\|(0) not &sv_undef.Alternatively you could free DBIc_FIELDS_AV(imp_sth) and set it to null,but that would mean \fIbind_columns()\fR woudn't work across result sets..PPStatement attributes.IX Subsection "Statement attributes".PPThe main difference between \fIdbh\fR and \fIsth\fR attributes is, that youshould implement a lot of attributes here that are required bythe \fB\s-1DBI\s0\fR, such as \fI\s-1NAME\s0\fR, \fI\s-1NULLABLE\s0\fR, \fI\s-1TYPE\s0\fR, etc. See\&\*(L"Statement Handle Attributes\*(R" in \s-1DBI\s0 for a complete list..PPPay attention to attributes which are marked as read only, such as\&\fI\s-1NUM_OF_PARAMS\s0\fR. These attributes can only be set the first timea statement is executed. If a statement is prepared, then executedmultiple times, warnings may be generated..PPYou can protect against these warnings, and prevent the recalculationof attributes which might be expensive to calculate (such as the\&\fI\s-1NAME\s0\fR and \fINAME_*\fR attributes):.PP.Vb 3\&    my $storedNumParams = $sth\->FETCH(\*(AqNUM_OF_PARAMS\*(Aq);\&    if (!defined $storedNumParams or $storedNumFields < 0) {\&        $sth\->STORE(\*(AqNUM_OF_PARAMS\*(Aq) = $numParams;\&\&        # Set other useful attributes that only need to be set once\&        # for a statement, like $sth\->{NAME} and $sth\->{TYPE}\&    }.Ve.PPOne particularly important attribute to set correctly (mentioned in\&\*(L"\s-1ATTRIBUTES\s0 \s-1COMMON\s0 \s-1TO\s0 \s-1ALL\s0 \s-1HANDLES\s0\*(R" in \s-1DBI\s0 is \fIActive\fR. Many \fB\s-1DBI\s0\fR methods,including \f(CW\*(C`bind_columns()\*(C'\fR, depend on this attribute..PPBesides that the \f(CW\*(C`STORE()\*(C'\fR and \f(CW\*(C`FETCH()\*(C'\fR methods are mainly the sameas above for \fIdbh\fR's..PPOther statement methods.IX Subsection "Other statement methods".PPA trivial \f(CW\*(C`finish()\*(C'\fR method to discard stored data, reset any attributes(such as \fIActive\fR) and do \f(CW\*(C`$sth\->SUPER::finish()\*(C'\fR..PPIf you've defined a \f(CW\*(C`parse_trace_flag()\*(C'\fR method in \fB::db\fR you'll also wantit in \fB::st\fR, so just alias it in:.PP.Vb 1\&  *parse_trace_flag = \e&DBD::foo:db::parse_trace_flag;.Ve.PPAnd perhaps some other methods that are not part of the \fB\s-1DBI\s0\fRspecification, in particular to make metadata available.Remember that they must have names that begin with your driversregistered prefix so they can be installed using \f(CW\*(C`install_method()\*(C'\fR..PPIf \f(CW\*(C`DESTROY()\*(C'\fR is called on a statement handle that's still active(\f(CW\*(C`$sth\->{Active}\*(C'\fR is true) then it should effectively call \f(CW\*(C`finish()\*(C'\fR..PP.Vb 4\&    sub DESTROY {\&        my $sth = shift;\&        $sth\->finish if $sth\->FETCH(\*(AqActive\*(Aq);\&    }.Ve.Sh "Tests".IX Subsection "Tests"The test process should conform as closely as possibly to the Perlstandard test harness..PPIn particular, most (all) of the tests should be run in the \fIt\fR sub-directory,and should simply produce an \f(CW\*(C`ok\*(C'\fR when run under \f(CW\*(C`make test\*(C'\fR.For details on how this is done, see the Camel book and the section inChapter 7, \*(L"The Standard Perl Library\*(R" on Test::Harness..PPThe tests may need to adapt to the type of database which is being usedfor testing, and to the privileges of the user testing the driver. Forexample, the \fBDBD::Informix\fR test code has to adapt in a number ofplaces to the type of database to which it is connected as differentInformix databases have different capabilities: some of the tests arefor databases without transaction logs; others are for databases with atransaction log; some versions of the server have support for blobs, orstored procedures, or user-defined data types, and others do not..PPWhen a complete file of tests must be skipped, you can provide a reasonin a pseudo-comment:.PP.Vb 5\&    if ($no_transactions_available)\&    {\&        print "1..0 # Skip: No transactions available\en";\&        exit 0;\&    }.Ve.PPConsider downloading the \fBDBD::Informix\fR code and look at the code in\&\fIDBD/Informix/TestHarness.pm\fR which is used throughout the\&\fBDBD::Informix\fR tests in the \fIt\fR sub-directory..SH "CREATING A C/XS DRIVER".IX Header "CREATING A C/XS DRIVER"Creating 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..PPThe de facto reference driver has been the one for \fBDBD::Oracle\fR writtenby Tim Bunce, who is also the author of the \fB\s-1DBI\s0\fR package. The \fBDBD::Oracle\fRmodule is a good example of a driver implemented around a C\-level \s-1API\s0..PPNowadays it it seems better to base on \fB\s-1DBD::ODBC\s0\fR, another drivermaintained by Tim and Jeff Urlwin, because it offers a lot of metadataand seems to become the guideline for the future development. (Also as\&\fBDBD::Oracle\fR digs deeper into the Oracle 8 \s-1OCI\s0 interface it'll get evenmore hairy than it is now.).PPThe \fBDBD::Informix\fR driver is one driver implemented using embedded \s-1SQL\s0instead of a function-based \s-1API\s0.\&\fBDBD::Ingres\fR may also be worth a look..Sh "C/XS version of Driver.pm".IX Subsection "C/XS version of Driver.pm"A lot of the code in the \fIDriver.pm\fR 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:.IP "\(bu" 8The variables \fI\f(CI$DBD::Driver::\fI{dr|db|st}::imp_data_size\fR are not definedhere, but in the \s-1XS\s0 code, because they declare the size of certainC structures..IP "\(bu" 8Some methods are typically moved to the \s-1XS\s0 code, in particular\&\f(CW\*(C`prepare()\*(C'\fR, \f(CW\*(C`execute()\*(C'\fR, \f(CW\*(C`disconnect()\*(C'\fR, \f(CW\*(C`disconnect_all()\*(C'\fR and the\&\f(CW\*(C`STORE()\*(C'\fR and \f(CW\*(C`FETCH()\*(C'\fR methods..IP "\(bu" 8Other methods are still part of \fIDriver.pm\fR, but have callbacks tothe \s-1XS\s0 code..IP "\(bu" 8If the driver-specific parts of the \fIimp_drh_t\fR structure need to beformally initialized (which does not seem to be a common requirement),then you need to add a call to an appropriate \s-1XS\s0 function in the drivermethod of \f(CW\*(C`DBD::Driver::driver()\*(C'\fR, and you define the corresponding functionin \fIDriver.xs\fR, and you define the C code in \fIdbdimp.c\fR and the prototype in\&\fIdbdimp.h\fR..SpFor example, \fBDBD::Informix\fR has such a requirement, and adds thefollowing call after the call to \f(CW\*(C`_new_drh()\*(C'\fR in \fIInformix.pm\fR:.Sp.Vb 1\&  DBD::Informix::dr::driver_init($drh);.Ve.Spand the following code in \fIInformix.xs\fR:.Sp.Vb 6\&  # 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;.Ve.Spand the code in \fIdbdimp.h\fR declares:.Sp.Vb 1\&  extern int dbd_ix_dr_driver_init(SV *drh);.Ve.Spand the code in \fIdbdimp.ec\fR (equivalent to \fIdbdimp.c\fR) defines:.Sp.Vb 11\&  /* 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;\&  }.Ve.Sp\&\fBDBD::Oracle\fR 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..PPNow let's take a closer look at an excerpt from \fIOracle.pm\fR (revisedheavily to remove idiosyncrasies) as an example, ignoring things thatwere already discussed for pure Perl drivers..PP\fIThe connect method\fR.IX Subsection "The connect method".PPThe 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)..PPIf you ignore the connection attributes, then you omit all mention ofthe \fI\f(CI$auth\fI\fR variable (which is a reference to a hash of attributes), andthe \s-1XS\s0 system manages the differences for you..PP.Vb 3\&  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\*(Aqs legal to

⌨️ 快捷键说明

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