Author: REHSACK
Date: Fri Aug 27 10:18:30 2010
New Revision: 14338

Added:
   dbi/trunk/lib/DBI/DBD/SqlEngine/
   dbi/trunk/lib/DBI/DBD/SqlEngine/Developer.pod
   dbi/trunk/lib/DBI/DBD/SqlEngine/HowTo.pod
Modified:
   dbi/trunk/lib/DBI/DBD/SqlEngine.pm

Log:
- add 2 phase initialization support to DBI::DBD::SqlEngine
- delete old code which's replacement has been proved in 1.612 and 1.613
- add Developers doc (splitted from DBD::File::Developers)
- add HowTo


Modified: dbi/trunk/lib/DBI/DBD/SqlEngine.pm
==============================================================================
--- dbi/trunk/lib/DBI/DBD/SqlEngine.pm  (original)
+++ dbi/trunk/lib/DBI/DBD/SqlEngine.pm  Fri Aug 27 10:18:30 2010
@@ -33,7 +33,7 @@
 use Carp;
 use vars qw( @ISA $VERSION $drh %methods_installed);
 
-$VERSION = "0.01";
+$VERSION = "0.02";
 
 $drh = undef;    # holds driver handle(s) once initialized
 
@@ -71,21 +71,24 @@
     $drh->{$class} = DBI::_new_drh( $class . "::dr", $attr );
     $drh->{$class}->STORE( ShowErrorStatement => 1 );
 
-    my $prefix  = DBI->driver_prefix($class);
-    my $dbclass = $class . "::db";
-    while ( my ( $accessor, $funcname ) = each %accessors )
-    {
-        my $method = $prefix . $accessor;
-        $dbclass->can($method) and next;
-        my $inject = sprintf <<'EOI', $dbclass, $method, $dbclass, $funcname;
+    my $prefix = DBI->driver_prefix($class);
+    if ($prefix)
+    {
+        my $dbclass = $class . "::db";
+        while ( my ( $accessor, $funcname ) = each %accessors )
+        {
+            my $method = $prefix . $accessor;
+            $dbclass->can($method) and next;
+            my $inject = sprintf <<'EOI', $dbclass, $method, $dbclass, 
$funcname;
 sub %s::%s
 {
     my $func = %s->can (q{%s});
     goto &$func;
     }
 EOI
-        eval $inject;
-        $dbclass->install_method($method);
+            eval $inject;
+            $dbclass->install_method($method);
+        }
     }
 
     # XXX inject DBD::XXX::Statement unless exists
@@ -117,19 +120,21 @@
     my ( $drh, $dbname, $user, $auth, $attr ) = @_;
 
     # create a 'blank' dbh
-    my $this = DBI::_new_dbh(
-                              $drh,
-                              {
-                                 Name         => $dbname,
-                                 USER         => $user,
-                                 CURRENT_USER => $user,
-                              }
-                            );
+    my $dbh = DBI::_new_dbh(
+                             $drh,
+                             {
+                                Name         => $dbname,
+                                USER         => $user,
+                                CURRENT_USER => $user,
+                             }
+                           );
 
-    if ($this)
+    if ($dbh)
     {
         # must be done first, because setting flags implicitly calls 
$dbdname::db->STORE
-        $this->func("init_default_attributes");
+        $dbh->func( 0, "init_default_attributes" );
+        my $two_phased_init = defined $dbh->{sql_init_phase};
+        my %second_phase_attrs;
 
         my ( $var, $val );
         while ( length $dbname )
@@ -147,21 +152,57 @@
             {
                 $var = $1;
                 ( $val = $2 ) =~ s/\\(.)/$1/g;
-                $this->{$var} = $val;
+                if ($two_phased_init)
+                {
+                    $@ = undef;
+                    eval { $dbh->STORE( $var, $val ); };
+                    $@ and $second_phase_attrs{$var} = $val;
+                }
+                else
+                {
+                    $dbh->STORE( $var, $val );
+                }
             }
             elsif ( $var =~ m/^(.+?)=>(.*)/s )
             {
                 $var = $1;
                 ( $val = $2 ) =~ s/\\(.)/$1/g;
                 my $ref = eval $val;
-                $this->$var($ref);
+                $dbh->$var($ref);
             }
         }
 
-        $this->STORE( Active => 1 );
+        if ($two_phased_init)
+        {
+            foreach $a (qw(Profile RaiseError PrintError AutoCommit))
+            {    # do these first
+                exists $attr->{$a} or next;
+                $@ = undef;
+                eval {
+                    $dbh->{$a} = $attr->{$a};
+                    delete $attr->{$a};
+                };
+                $@ and $second_phase_attrs{$a} = delete $attr->{$a};
+            }
+            while ( my ( $a, $v ) = each %$attr )
+            {
+                $@ = undef;
+                eval { $dbh->{$a} = $v };
+                $@ and $second_phase_attrs{$a} = $v;
+            }
+
+            $dbh->func( 1, "init_default_attributes" );
+            %$attr = %second_phase_attrs;
+        }
+        else
+        {
+            $dbh->func("init_done");
+        }
+
+        $dbh->STORE( Active => 1 );
     }
 
-    return $this;
+    return $dbh;
 }    # connect
 
 sub disconnect_all
@@ -245,8 +286,8 @@
             $sth->STORE( "sql_stmt", $stmt );
             $sth->STORE( "sql_params", [] );
             $sth->STORE( "NUM_OF_PARAMS", scalar( $stmt->params() ) );
-           my @colnames = $sth->sql_get_colnames();
-           $sth->STORE( "NUM_OF_FIELDS", scalar @colnames );
+            my @colnames = $sth->sql_get_colnames();
+            $sth->STORE( "NUM_OF_FIELDS", scalar @colnames );
         }
     }
     return $sth;
@@ -255,7 +296,7 @@
 sub set_versions
 {
     my $dbh = $_[0];
-    $dbh->{sql_version} = $DBI::DBD::SqlEngine::VERSION;
+    $dbh->{sql_engine_version} = $DBI::DBD::SqlEngine::VERSION;
     for (qw( nano_version statement_version ))
     {
         defined $DBI::SQL::Nano::versions->{$_} or next;
@@ -274,28 +315,28 @@
     my $dbh = $_[0];
 
     $dbh->{sql_valid_attrs} = {
-                                sql_version                => 1,    # 
DBI::DBD::SqlEngine version
-                                sql_handler                => 1,    # Nano or 
S:S
-                                sql_nano_version           => 1,    # Nano 
version
-                                sql_statement_version      => 1,    # S:S 
version
-                                sql_flags                  => 1,    # flags 
for SQL::Parser
-                                sql_quoted_identifier_case => 1,    # case for 
quoted identifiers
-                                sql_identifier_case        => 1,    # case for 
non-quoted identifiers
-                                sql_parser_object          => 1,    # 
SQL::Parser instance
-                                sql_sponge_driver          => 1,    # Sponge 
driver for table_info ()
-                                sql_valid_attrs            => 1,    # SQL 
valid attributes
-                                sql_readonly_attrs         => 1,    # SQL 
readonly attributes
+                               sql_engine_version         => 1,    # 
DBI::DBD::SqlEngine version
+                               sql_handler                => 1,    # Nano or 
S:S
+                               sql_nano_version           => 1,    # Nano 
version
+                               sql_statement_version      => 1,    # S:S 
version
+                               sql_flags                  => 1,    # flags for 
SQL::Parser
+                               sql_quoted_identifier_case => 1,    # case for 
quoted identifiers
+                               sql_identifier_case        => 1,    # case for 
non-quoted identifiers
+                               sql_parser_object          => 1,    # 
SQL::Parser instance
+                               sql_sponge_driver          => 1,    # Sponge 
driver for table_info ()
+                               sql_valid_attrs            => 1,    # SQL valid 
attributes
+                               sql_readonly_attrs         => 1,    # SQL 
readonly attributes
                               };
     $dbh->{sql_readonly_attrs} = {
-                                   sql_version                => 1,    # 
DBI::DBD::SqlEngine version
-                                   sql_handler                => 1,    # Nano 
or S:S
-                                   sql_nano_version           => 1,    # Nano 
version
-                                   sql_statement_version      => 1,    # S:S 
version
-                                   sql_quoted_identifier_case => 1,    # case 
for quoted identifiers
-                                   sql_parser_object          => 1,    # 
SQL::Parser instance
-                                   sql_sponge_driver          => 1,    # 
Sponge driver for table_info ()
-                                   sql_valid_attrs            => 1,    # SQL 
valid attributes
-                                   sql_readonly_attrs         => 1,    # SQL 
readonly attributes
+                               sql_engine_version         => 1,    # 
DBI::DBD::SqlEngine version
+                               sql_handler                => 1,    # Nano or 
S:S
+                               sql_nano_version           => 1,    # Nano 
version
+                               sql_statement_version      => 1,    # S:S 
version
+                               sql_quoted_identifier_case => 1,    # case for 
quoted identifiers
+                               sql_parser_object          => 1,    # 
SQL::Parser instance
+                               sql_sponge_driver          => 1,    # Sponge 
driver for table_info ()
+                               sql_valid_attrs            => 1,    # SQL valid 
attributes
+                               sql_readonly_attrs         => 1,    # SQL 
readonly attributes
                                  };
 
     return $dbh;
@@ -303,38 +344,60 @@
 
 sub init_default_attributes
 {
-    my $dbh = shift;
+    my ( $dbh, $phase ) = @_;
+    my $given_phase = $phase;
+
+    unless ( defined($phase) )
+    {
+        # we have an "old" driver here
+        $phase = defined $dbh->{sql_init_phase};
+    }
+
+    if ( 0 == $phase )
+    {
+        # must be done first, because setting flags implicitly calls 
$dbdname::db->STORE
+        $dbh->func("init_valid_attributes");
+
+        $dbh->func("set_versions");
 
-    # must be done first, because setting flags implicitly calls 
$dbdname::db->STORE
-    $dbh->func("init_valid_attributes");
+        $dbh->{sql_identifier_case}        = 2;    # SQL_IC_LOWER
+        $dbh->{sql_quoted_identifier_case} = 3;    # SQL_IC_SENSITIVE
 
-    $dbh->func("set_versions");
+        $dbh->{sql_init_phase} = $given_phase;
+
+        # complete derived attributes, if required
+        ( my $drv_class = $dbh->{ImplementorClass} ) =~ s/::db$//;
+        my $drv_prefix  = DBI->driver_prefix($drv_class);
+        my $valid_attrs = $drv_prefix . "valid_attrs";
+        my $ro_attrs    = $drv_prefix . "readonly_attrs";
 
-    $dbh->{sql_identifier_case}        = 2;    # SQL_IC_LOWER
-    $dbh->{sql_quoted_identifier_case} = 3;    # SQL_IC_SENSITIVE
+        my @comp_attrs = qw(valid_attrs version readonly_attrs);
 
-    # complete derived attributes, if required
-    ( my $drv_class = $dbh->{ImplementorClass} ) =~ s/::db$//;
-    my $drv_prefix  = DBI->driver_prefix($drv_class);
-    my $valid_attrs = $drv_prefix . "valid_attrs";
-    my $ro_attrs    = $drv_prefix . "readonly_attrs";
-
-    my @comp_attrs = qw(valid_attrs version readonly_attrs);
-
-    foreach my $comp_attr (@comp_attrs)
-    {
-        my $attr = $drv_prefix . $comp_attr;
-        defined $dbh->{$valid_attrs}
-          and !defined $dbh->{$valid_attrs}{$attr}
-          and $dbh->{$valid_attrs}{$attr} = 1;
-        defined $dbh->{$ro_attrs}
-          and !defined $dbh->{$ro_attrs}{$attr}
-          and $dbh->{$ro_attrs}{$attr} = 1;
+        foreach my $comp_attr (@comp_attrs)
+        {
+            my $attr = $drv_prefix . $comp_attr;
+            defined $dbh->{$valid_attrs}
+              and !defined $dbh->{$valid_attrs}{$attr}
+              and $dbh->{$valid_attrs}{$attr} = 1;
+            defined $dbh->{$ro_attrs}
+              and !defined $dbh->{$ro_attrs}{$attr}
+              and $dbh->{$ro_attrs}{$attr} = 1;
+        }
+    }
+    else
+    {
+        delete $dbh->{sql_init_phase};
     }
 
     return $dbh;
 }    # init_default_attributes
 
+sub init_done
+{
+    delete $_[0]->{sql_init_phase};
+    return;
+}
+
 sub sql_parser_object
 {
     my $dbh = $_[0];
@@ -464,7 +527,7 @@
         my $ro_attrs    = $attr_prefix . "readonly_attrs";
 
         ( $attrib, $value ) = $dbh->func( $attrib, $value, 
"validate_STORE_attr" );
-       $attrib or return;
+        $attrib or return;
 
         exists $dbh->{$valid_attrs}
           and ( $dbh->{$valid_attrs}{$attrib}
@@ -472,7 +535,8 @@
         exists $dbh->{$ro_attrs}
           and $dbh->{$ro_attrs}{$attrib}
           and defined $dbh->{$attrib}
-          and return $dbh->set_err( $DBI::stderr, "attribute '$attrib' is 
readonly and must not be modified" );
+          and return $dbh->set_err( $DBI::stderr,
+                                    "attribute '$attrib' is readonly and must 
not be modified" );
 
         $dbh->{$attrib} = $value;
         return 1;
@@ -493,7 +557,7 @@
 
     my $sql_engine_verinfo =
       join " ",
-      $dbh->{sql_version}, "using", $dbh->{sql_handler},
+      $dbh->{sql_engine_version}, "using", $dbh->{sql_handler},
       $dbh->{sql_handler} eq "SQL::Statement"
       ? $dbh->{sql_statement_version}
       : $dbh->{sql_nano_version};
@@ -512,7 +576,8 @@
         my $drv_prefix  = DBI->driver_prefix($drv_class);
         my $ddgv        = 
$dbh->{ImplementorClass}->can("get_${drv_prefix}versions");
         my $drv_version = $ddgv ? &$ddgv( $dbh, $table ) : $dbh->{ $drv_prefix 
. "version" };
-        $drv_version ||= eval "\$" . $derived . "::VERSION";;    # XXX access 
$drv_class::VERSION via symbol table
+        $drv_version ||= eval "\$" . $derived . "::VERSION";
+        ;    # XXX access $drv_class::VERSION via symbol table
         $vsn{$drv_class} = $drv_version;
         $indent and $vmp{$drv_class} = " " x $indent . $drv_class;
         $indent += 2;
@@ -563,13 +628,13 @@
           MINIMUM_SCALE      => 13,
           MAXIMUM_SCALE      => 14,
        },
-       [ "VARCHAR", DBI::SQL_VARCHAR(),       undef, "'", "'", undef, 0, 1, 1, 
0, 0, 0, undef, 1, 999999, ],
-       [ "CHAR",    DBI::SQL_CHAR(),          undef, "'", "'", undef, 0, 1, 1, 
0, 0, 0, undef, 1, 999999, ],
-       [ "INTEGER", DBI::SQL_INTEGER(),       undef, "",  "",  undef, 0, 0, 1, 
0, 0, 0, undef, 0, 0, ],
-       [ "REAL",    DBI::SQL_REAL(),          undef, "",  "",  undef, 0, 0, 1, 
0, 0, 0, undef, 0, 0, ],
-       [ "BLOB",    DBI::SQL_LONGVARBINARY(), undef, "'", "'", undef, 0, 1, 1, 
0, 0, 0, undef, 1, 999999, ],
-       [ "BLOB",    DBI::SQL_LONGVARBINARY(), undef, "'", "'", undef, 0, 1, 1, 
0, 0, 0, undef, 1, 999999, ],
-       [ "TEXT",    DBI::SQL_LONGVARCHAR(),   undef, "'", "'", undef, 0, 1, 1, 
0, 0, 0, undef, 1, 999999, ]
+       [ "VARCHAR", DBI::SQL_VARCHAR(), undef, "'", "'", undef, 0, 1, 1, 0, 0, 
0, undef, 1, 999999, ],
+       [ "CHAR", DBI::SQL_CHAR(), undef, "'", "'", undef, 0, 1, 1, 0, 0, 0, 
undef, 1, 999999, ],
+       [ "INTEGER", DBI::SQL_INTEGER(), undef, "", "", undef, 0, 0, 1, 0, 0, 
0, undef, 0, 0, ],
+       [ "REAL",    DBI::SQL_REAL(),    undef, "", "", undef, 0, 0, 1, 0, 0, 
0, undef, 0, 0, ],
+       [ "BLOB", DBI::SQL_LONGVARBINARY(), undef, "'", "'", undef, 0, 1, 1, 0, 
0, 0, undef, 1, 999999, ],
+       [ "BLOB", DBI::SQL_LONGVARBINARY(), undef, "'", "'", undef, 0, 1, 1, 0, 
0, 0, undef, 1, 999999, ],
+       [ "TEXT", DBI::SQL_LONGVARCHAR(), undef, "'", "'", undef, 0, 1, 1, 0, 
0, 0, undef, 1, 999999, ],
     ];
 }    # type_info_all
 
@@ -760,8 +825,10 @@
     my $data = $sth->{sql_stmt}{data};
     if ( !$data || ref $data ne "ARRAY" )
     {
-        $sth->set_err( $DBI::stderr,
-                       "Attempt to fetch row without a preceeding execute () 
call or from a non-SELECT statement" );
+        $sth->set_err(
+            $DBI::stderr,
+            "Attempt to fetch row without a preceeding execute () call or from 
a non-SELECT statement"
+        );
         return;
     }
     my $dav = shift @$data;
@@ -770,8 +837,8 @@
         $sth->finish;
         return;
     }
-    if ( $sth->FETCH("ChopBlanks") )   # XXX: (TODO) Only chop on CHAR fields,
-    {                                  # not on VARCHAR or NUMERIC (see DBI 
docs)
+    if ( $sth->FETCH("ChopBlanks") )    # XXX: (TODO) Only chop on CHAR fields,
+    {                                   # not on VARCHAR or NUMERIC (see DBI 
docs)
         $_ && $_ =~ s/ +$// for @$dav;
     }
     return $sth->_set_fbav($dav);
@@ -789,19 +856,19 @@
     # DBI::SQL::Nano::Statement_ does not offer an interface to the
     # required data
     my @colnames;
-    if( $sth->{sql_stmt}->{NAME} and "ARRAY" eq ref($sth->{sql_stmt}->{NAME}) )
+    if ( $sth->{sql_stmt}->{NAME} and "ARRAY" eq ref( $sth->{sql_stmt}->{NAME} 
) )
     {
-       @colnames = @{$sth->{sql_stmt}->{NAME}};
+        @colnames = @{ $sth->{sql_stmt}->{NAME} };
     }
     elsif ( $sth->{sql_stmt}->isa('SQL::Statement') )
     {
-        my $stmt    = $sth->{sql_stmt} || {};
-       my @coldefs = @{ $stmt->{column_defs} || [] };
-          @colnames = map { $_->{name} || $_->{value} } @coldefs;
+        my $stmt = $sth->{sql_stmt} || {};
+        my @coldefs = @{ $stmt->{column_defs} || [] };
+        @colnames = map { $_->{name} || $_->{value} } @coldefs;
     }
     @colnames = $sth->{sql_stmt}->column_names() unless (@colnames);
 
-    @colnames = () if( grep { m/\*/ } @colnames );
+    @colnames = () if ( grep { m/\*/ } @colnames );
 
     return @colnames;
 }
@@ -810,29 +877,11 @@
 {
     my ( $sth, $attrib ) = @_;
 
-=pod
-
-    if ( $attrib =~ m/^NAME(?:|_lc|_uc)$/ )
-    {
-       my @cn = $sth->sql_get_colnames();
-       return [ $attrib eq "NAME_lc" ? map { lc $_ } @cn
-              : $attrib eq "NAME_uc" ? map { uc $_ } @cn
-              : @cn ];
-    }
-
-=cut
-
     $attrib eq "NAME" and return [ $sth->sql_get_colnames() ];
 
     $attrib eq "TYPE"      and return [ ("CHAR") x scalar 
$sth->sql_get_colnames() ];
     $attrib eq "PRECISION" and return [ (0) x scalar $sth->sql_get_colnames() 
];
     $attrib eq "NULLABLE"  and return [ (1) x scalar $sth->sql_get_colnames() 
];
-#   if ( $attrib eq "NULLABLE" )
-#   {
-#       my @colnames = ;
-#       @colnames or return;
-#       return [ (1) x @colnames ];
-#   }
 
     if ( $attrib eq lc $attrib )
     {
@@ -847,7 +896,7 @@
 sub STORE ($$$)
 {
     my ( $sth, $attrib, $value ) = @_;
-    if ( $attrib eq lc $attrib ) # Private driver attributes are lower cased
+    if ( $attrib eq lc $attrib )    # Private driver attributes are lower cased
     {
         $sth->{$attrib} = $value;
         return 1;

Added: dbi/trunk/lib/DBI/DBD/SqlEngine/Developer.pod
==============================================================================
--- (empty file)
+++ dbi/trunk/lib/DBI/DBD/SqlEngine/Developer.pod       Fri Aug 27 10:18:30 2010
@@ -0,0 +1,352 @@
+=head1 NAME
+
+DBI::DBD::SqlEngine::Developers - Developers documentation for 
DBI::DBD::SqlEngine
+
+=head1 SYNOPSIS
+
+  perldoc DBI::DBD::SqlEngine::Developers
+
+=head1 DESCRIPTION
+
+This document describes the interface of DBI::DBD::SqlEngine for DBD
+developers who write DBI::DBD::SqlEngine based DBI drivers. It supplements
+L<DBI::DBD> and L<DBI::DBD::SqlEngine::HowTo>, which you should read first.
+
+=head1 CLASSES
+
+Each DBI driver must provide a package global C<< driver >> method and
+three DBI related classes:
+
+=over 4
+
+=item DBI::DBD::SqlEngine::dr
+
+Driver package, contains the methods DBI calls indirectly via DBI
+interface:
+
+  DBI->connect ('DBI:DBM:', undef, undef, {})
+
+  # invokes
+  package DBD::DBM::dr;
+  @DBD::DBM::dr::ISA = qw(DBI::DBD::SqlEngine::dr);
+
+  sub connect ($$;$$$)
+  {
+      ...
+  }
+
+Similar for C<< data_sources () >> and C<< disconnect_all() >>.
+
+Pure Perl DBI drivers derived from DBI::DBD::SqlEngine do not usually need to
+override any of the methods provided through the DBD::XXX::dr package
+however if you need additional initialization in the connect method
+you may need to.
+
+=item DBI::DBD::SqlEngine::db
+
+Contains the methods which are called through DBI database handles
+(C<< $dbh >>). e.g.,
+
+  $sth = $dbh->prepare ("select * from foo");
+  # returns the f_encoding setting for table foo
+  $dbh->csv_get_meta ("foo", "f_encoding");
+
+DBI::DBD::SqlEngine provides the typical methods required here. Developers who
+write DBI drivers based on DBI::DBD::SqlEngine need to override the methods
+C<< set_versions >> and C<< init_valid_attributes >>.
+
+=item DBI::DBD::SqlEngine::st
+
+Contains the methods to deal with prepared statement handles. e.g.,
+
+  $sth->execute () or die $sth->errstr;
+
+=back
+
+=head2 DBI::DBD::SqlEngine
+
+This is the main package containing the routines to initialize
+DBI::DBD::SqlEngine based DBI drivers. Primarily the
+C<< DBI::DBD::SqlEngine::driver >> method is invoked, either directly
+from DBI when the driver is initialized or from the derived class.
+
+  package DBD::DBM;
+
+  use base qw( DBI::DBD::SqlEngine );
+
+  sub driver
+  {
+      my ( $class, $attr ) = @_;
+      ...
+      my $drh = $class->SUPER::driver( $attr );
+      ...
+      return $drh;
+  }
+
+It is not necessary to implement your own driver method as long as
+additional initialization (e.g. installing more private driver
+methods) is not required.  You do not need to call C<< setup_driver >>
+as DBI::DBD::SqlEngine takes care of it.
+
+=head2 DBI::DBD::SqlEngine::dr
+
+The driver package contains the methods DBI calls indirectly via the DBI
+interface (see L<DBI/DBI Class Methods>).
+
+DBI::DBD::SqlEngine based DBI drivers usually do not need to implement 
anything here,
+it is enough to do the basic initialization:
+
+  package DBD:XXX::dr;
+
+  @DBD::XXX::dr::ISA = qw (DBI::DBD::SqlEngine::dr);
+  $DBD::XXX::dr::imp_data_size     = 0;
+  $DBD::XXX::dr::data_sources_attr = undef;
+  $DBD::XXX::ATTRIBUTION = "DBD::XXX $DBD::XXX::VERSION by Hans Mustermann";
+
+=head2 DBI::DBD::SqlEngine::db
+
+This package defines the database methods, which are called via the DBI
+database handle C<< $dbh >>.
+
+Methods provided by DBI::DBD::SqlEngine:
+
+=over 4
+
+=item ping
+
+Simply returns the content of the C<< Active >> attribute. Override
+when your driver needs more complicated actions here.
+
+=item prepare
+
+Prepares a new SQL statement to execute. Returns a statement handle,
+C<< $sth >> - instance of the DBD:XXX::st. It is neither required nor
+recommended to override this method.
+
+=item FETCH
+
+Fetches an attribute of a DBI database object. Private handle attributes
+must have a prefix (this is mandatory). If a requested attribute is
+detected as a private attribute without a valid prefix, the driver prefix
+(written as C<$drv_prefix>) is added.
+
+The driver prefix is extracted from the attribute name and verified against
+C<< $dbh->{ $drv_prefix . "valid_attrs" } >> (when it exists). If the
+requested attribute value is not listed as a valid attribute, this method
+croaks. If the attribute is valid and readonly (listed in C<< $dbh->{
+$drv_prefix . "readonly_attrs" } >> when it exists), a real copy of the
+attribute value is returned. So it's not possible to modify
+C<f_valid_attrs> from outside of DBI::DBD::SqlEngine::db or a derived class.
+
+=item STORE
+
+Stores a database private attribute. Private handle attributes must have a
+prefix (this is mandatory). If a requested attribute is detected as a private
+attribute without a valid prefix, the driver prefix (written as
+C<$drv_prefix>) is added. If the database handle has an attribute
+C<${drv_prefix}_valid_attrs> - for attribute names which are not listed in
+that hash, this method croaks. If the database handle has an attribute
+C<${drv_prefix}_readonly_attrs>, only attributes which are not listed there
+can be stored (once they are initialized). Trying to overwrite such an
+immutable attribute forces this method to croak.
+
+An example of a valid attributes list can be found in
+C<< DBI::DBD::SqlEngine::db::init_valid_attributes >>.
+
+=item set_versions
+
+This method sets the attributes C<< f_version >>, C<< sql_nano_version >>,
+C<< sql_statement_version >> and (if not prohibited by a restrictive
+C<< ${prefix}_valid_attrs >>) C<< ${prefix}_version >>.
+
+This method is called at the end of the C<< connect () >> phase.
+
+When overriding this method, do not forget to invoke the superior one.
+
+=item init_valid_attributes
+
+This method is called after the database handle is instantiated as the
+first attribute initialization.
+
+C<< DBI::DBD::SqlEngine::db::init_valid_attributes >> initializes the
+attributes C<sql_valid_attrs> and C<sql_readonly_attrs>.
+
+When overriding this method, do not forget to invoke the superior one,
+preferably before doing anything else.
+
+=item init_default_attributes
+
+This method is called after the database handle is instantiated to
+initialize the default attributes.
+
+C<< DBI::DBD::SqlEngine::db::init_default_attributes >> initializes the
+attributes C<sql_identifier_case>, C<sql_quoted_identifier_case>,
+C<sql_handler>, C<sql_engine_version>, C<sql_nano_version> and
+C<sql_statement_version> when L<SQL::Statement> is available.
+
+When the derived implementor class provides the attribute to validate
+attributes (e.g. C<< $dbh->{dbm_valid_attrs} = {...}; >>) or the attribute
+containing the immutable attributes (e.g.  C<< $dbh->{dbm_readonly_attrs}
+= {...}; >>), the attributes C<drv_valid_attrs>, C<drv_readonly_attrs> and
+C<drv_version> are added (when available) to the list of valid and
+immutable attributes (where C<drv_> is interpreted as the driver prefix).
+
+=item get_versions
+
+This method is called by the code injected into the instantiated driver to
+provide the user callable driver method C<< ${prefix}versions >> (e.g.
+C<< dbm_versions >>, C<< csv_versions >>, ...).
+
+The DBI::DBD::SqlEngine implementation returns all version information known by
+DBI::DBD::SqlEngine (e.g. DBI version, Perl version, DBI::DBD::SqlEngine 
version and
+the SQL handler version).
+
+C<get_versions> takes the C<$dbh> as the first argument and optionally a
+second argument containing a table name. The second argument is not
+evaluated in C<< DBI::DBD::SqlEngine::db::get_versions >> itself - but
+might be in the future.
+
+If the derived implementor class provides a method named
+C<get_${drv_prefix}versions>, this is invoked and the return value of
+it is associated to the derived driver name:
+
+    if (my $dgv = $dbh->{ImplementorClass}->can ("get_" . $drv_prefix . 
"versions") {
+       (my $derived_driver = $dbh->{ImplementorClass}) =~ s/::db$//;
+       $versions{$derived_driver} = &$dgv ($dbh, $table);
+    }
+
+Override it to add more version information about your module, (e.g.
+some kind of parser version in case of DBD::CSV, ...), if one line is not
+enough room to provide all relevant information.
+
+=item sql_parser_object
+
+Returns a L<SQL::Parser> instance, when C<< sql_handler >> is set to
+"SQL::Statement". The parser instance is stored in C<< sql_parser_object >>.
+
+It is not recommended to override this method.
+
+=item disconnect
+
+Disconnects from a database. All local table information is discarded and
+the C<< Active >> attribute is set to 0.
+
+=item type_info_all
+
+Returns information about all the types supported by DBI::DBD::SqlEngine.
+
+=item table_info
+
+Returns a statement handle which is prepared to deliver information about
+all known tables.
+
+=item list_tables
+
+Returns a list of all known table names.
+
+=item quote
+
+Quotes a string for use in SQL statements.
+
+=item commit
+
+Warns about a useless call (if warnings enabled) and returns.
+DBI::DBD::SqlEngine is typically a driver which commits every action instantly 
when
+executed.
+
+=item rollback
+
+Warns about a useless call (if warnings enabled) and returns.
+DBI::DBD::SqlEngine is typically a driver which commits every action instantly 
when
+executed.
+
+=back
+
+=head2 DBI::DBD::SqlEngine::st
+
+Contains the methods to deal with prepared statement handles:
+
+=over 4
+
+=item bind_param
+
+Common routine to bind placeholders to a statement for execution. It
+is dangerous to override this method without detailed knowledge about
+the DBI::DBD::SqlEngine internal storage structure.
+
+=item execute
+
+Executes a previously prepared statement (with placeholders, if any).
+
+=item finish
+
+Finishes a statement handle, discards all buffered results. The prepared
+statement is not discarded so the statement can be executed again.
+
+=item fetch
+
+Fetches the next row from the result-set. This method may be rewritten
+in a later version and if it's overridden in a derived class, the
+derived implementation should not rely on the storage details.
+
+=item fetchrow_arrayref
+
+Alias for C<< fetch >>.
+
+=item FETCH
+
+Fetches statement handle attributes. Supported attributes (for full overview
+see L<DBI/Statement Handle Attributes>) are C<NAME>, C<TYPE>, C<PRECISION>
+and C<NULLABLE>. Each column is returned as C<NULLABLE> which might be wrong
+depending on the derived backend storage.  If the statement handle has
+private attributes, they can be fetched using this method, too. B<Note> that
+statement attributes are not associated with any table used in this statement.
+
+This method usually requires extending in a derived implementation.
+See L<DBD::CSV> or L<DBD::DBM> for some example.
+
+=item STORE
+
+Allows storing of statement private attributes. No special handling is
+currently implemented here.
+
+=item rows
+
+Returns the number of rows affected by the last execute. This method might
+return C<undef>.
+
+=back
+
+=head2 DBI::DBD::SqlEngine::Statement
+
+Derives from DBI::SQL::Nano::Statement for unified naming when deriving
+new drivers. No additional feature is provided from here.
+
+=head2 DBI::DBD::SqlEngine::Table
+
+Derives from DBI::SQL::Nano::Table for unified naming when deriving
+new drivers. No additional feature is provided from here.
+
+You should consult the documentation of C<< SQL::Eval::Table >> (see
+L<SQL::Eval>) to get more information about the abstract methods of the
+table's base class you have to override and a description of the table
+meta information expected by the SQL engines.
+
+=head1 AUTHOR
+
+The module DBI::DBD::SqlEngine is currently maintained by
+
+H.Merijn Brand < h.m.brand at xs4all.nl > and
+Jens Rehsack  < rehsack at googlemail.com >
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2010 by H.Merijn Brand & Jens Rehsack
+
+All rights reserved.
+
+You may freely distribute and/or modify this module under the terms of
+either the GNU General Public License (GPL) or the Artistic License, as
+specified in the Perl README file.
+
+=cut

Added: dbi/trunk/lib/DBI/DBD/SqlEngine/HowTo.pod
==============================================================================
--- (empty file)
+++ dbi/trunk/lib/DBI/DBD/SqlEngine/HowTo.pod   Fri Aug 27 10:18:30 2010
@@ -0,0 +1,206 @@
+=head1 NAME
+
+DBI::DBD::SqlEngine::Developers - Developers documentation for 
DBI::DBD::SqlEngine
+
+=head1 SYNOPSIS
+
+  perldoc DBI::DBD::SqlEngine::Developers
+
+=head1 DESCRIPTION
+
+This document provides a step-by-step guide, how to create a new
+C<DBI::DBD::SqlEngine> based DBD. It expects that you carefully read the
+L<DBI> documentation and that you're familiar with L<DBI::DBI> and had
+read and understood L<DBD::ExampleP>.
+
+This document addresses experienced developers who are really sure that
+they need to invest time when writing a new DBI Driver. Writing a DBI
+Driver is neither a weekend project nor an easy job for hobby coders
+after work. Expect one or two man-month of time for the first start.
+
+Those who are still reading, should be able to sing the rules of
+L<DBI::DBD/CREATING A NEW DRIVER>.
+
+=head1 CREATING DRIVER CLASSES
+
+Do you have an entry in DBI's DBD registry?
+
+=head2 Sample Skeleton
+
+    package DBD::Foo;
+
+    use strict;
+    use warnings;
+    use vars qw(@ISA $VERSION);
+
+    use DBI ();
+
+    @ISA = qw(DBI::DBD::SqlEngine);
+    $VERSION = "0.001";
+
+    package DBD::Foo::dr;
+
+    use vars qw(@ISA $imp_data_size);
+
+    @ISA = qw(DBI::DBD::SqlEngine::dr);
+    $imp_data_size = 0;
+
+    package DBD::Foo::db;
+
+    use vars qw(@ISA $imp_data_size);
+
+    @ISA = qw(DBI::DBD::SqlEngine::db);
+    $imp_data_size = 0;
+
+    package DBD::Foo::st;
+
+    use vars qw(@ISA $imp_data_size);
+
+    @ISA = qw(DBI::DBD::SqlEngine::st);
+    $imp_data_size = 0;
+
+    package DBD::Foo::Statement;
+
+    use vars qw(@ISA);
+
+    @ISA = qw(DBI::DBD::SqlEngine::Statement);
+
+    package DBD::Foo::Table;
+
+    use vars qw(@ISA);
+
+    @ISA = qw(DBI::DBD::SqlEngine::Table);
+
+    1;
+
+Tiny, eh? And all you have now is a DBD named foo which will is able to
+deal with temporary tables, as long as you use L<SQL::Statement>. In
+L<DBI::SQL::Nano> environments, this DBD can do nothing.
+
+=head2 Deal with own attributes
+
+Before we start doing usable stuff with our DBI driver, we need to think
+about what we want to do and how we want to do it.
+
+Do we need tunable knobs accessible by users? Do we need status
+information? All this is handled in attributes of the database handles (be
+careful when your DBD is running "behind" a L<DBD::Gofer> proxy).
+
+How come the attributes into the DBD and how are they fetchable by the
+user? Good question, but you should know because you've read the L<DBI>
+documentation.
+
+C<DBI::DBD::SqlEngine::db::FETCH> and C<DBI::DBD::SqlEngine::db::STORE>
+taking care for you - all they need to know is which attribute names
+are valid and mutable or immutable. Tell them by adding
+C<init_valid_attributes> to your db class:
+
+    sub init_valid_attributes
+    {
+       my $dbh = $_[0];
+
+       $dbh->SUPER::init_valid_attributes ();
+
+       $dbh->{foo_valid_attrs} = {
+           foo_version         => 1,   # contains version of this driver
+           foo_valid_attrs     => 1,   # contains the valid attributes of foo 
drivers
+           foo_readonly_attrs  => 1,   # contains immutable attributes of foo 
drivers
+           foo_bar             => 1,   # contains the bar attribute
+           foo_baz             => 1,   # contains the baz attribute
+           foo_manager         => 1,   # contains the manager of the driver 
instance
+           foo_manager_type    => 1,   # contains the manager class of the 
driver instance
+       };
+       $dbh->{foo_readonly_attrs} = {
+           foo_version         => 1,   # contains version of this driver
+           foo_valid_attrs     => 1,   # contains the valid attributes of foo 
drivers
+           foo_readonly_attrs  => 1,   # contains immutable attributes of foo 
drivers
+           foo_manager         => 1,   # contains the manager of the driver 
instance
+       };
+
+       return $dbh;
+    }
+
+
+Woooho - but now the user cannot assign new managers? This is intended,
+overwrite C<STORE> to handle it!
+
+    sub STORE ($$$)
+    {
+       my ( $dbh, $attrib, $value ) = @_;
+
+       $dbh->SUPER::STORE( $attrib, $value );
+
+       # we're still alive, so no exception is thrown ...
+       # by DBI::DBD::SqlEngine::db::STORE
+       if ( $attrib eq "foo_manager_type" )
+       {
+           $dbh->{foo_manager} = $dbh->{foo_manager_type}->new();
+           # ... probably correct some states based on the new
+           # foo_manager_type - see DBD::Sys for an example
+       }
+    }
+
+But ... my driver runs without a manager until someone first assignes
+a C<foo_manager_type>. Well, no - there're two places where you can
+initialize defaults:
+
+    sub init_default_attributes
+    {
+       my ($dbh, $phase) = @_;
+
+       $dbh->SUPER::init_default_attributes($phase);
+
+       if( 0 == $phase )
+       {
+           # init all attributes which have no knowledge about
+           # user settings from DSN or the attribute hash
+           $dbh->{foo_manager_type} = "DBD::Foo::Manager";
+       }
+       elsif( 1 == $phase )
+       {
+           # init phase with more knowledge from DSN or attribute
+           # hash
+           $dbh->{foo_manager} = $dbh->{foo_manager_type}->new();
+       }
+
+       return $dbh;
+    }
+
+So far we can prevent the users to use our database driver as data
+storage for anything and everything. We care only about the real important
+stuff for peace on earth and alike attributes. But in fact, the driver
+still can't do anything. It can do less than nothing - meanwhile it's
+not a stupid storage area anymore.
+
+=head2 Dealing with Tables
+
+Let's put some life into it - it's going to be time for it.
+
+This is a good point where a quick side step to L<SQL::Statement::Embed>
+will help to shorten the next paragraph. The documentation in
+SQL::Statement::Embed regarding embedding in own DBD's works pretty
+fine with SQL::Statement and DBI::SQL::Nano.
+
+=head2 Testing
+
+Now you should have your first own DBD. Was easy, wasn't it?
+
+
+=head1 AUTHOR
+
+The module DBI::DBD::SqlEngine is currently maintained by
+
+H.Merijn Brand < h.m.brand at xs4all.nl > and
+Jens Rehsack  < rehsack at googlemail.com >
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2010 by H.Merijn Brand & Jens Rehsack
+
+All rights reserved.
+
+You may freely distribute and/or modify this module under the terms of
+either the GNU General Public License (GPL) or the Artistic License, as
+specified in the Perl README file.
+
+=cut

Reply via email to