Committed by Tim Bunce <[email protected]>

Subject: [DBD::Pg 1/2] Make get_info much more efficient and slightly simpler.

Previously on every call get_info copied a large hash into another hash,
then added more keys to the new hash, then discarded the new hash.
I've moved the hash out from the method and made it static.
There's no longer any hash copying.

Also there's a long elsif chain to handle special cases (which has a
poor-failure mode). I've added two new general mechanisms to remove the
need for many of the special cases: A code ref in the hash is called
with the dbh and the return value returned.  A scalar ref is treated as
a ref to an SQL statement which is executed and the first value returned.

The same mechanisms should be extended to the other special cases but I
stopped here to keep the patch reasonably clear.
---
 Pg.pm          | 56 ++++++++++++++++++++++++--------------------------------
 t/03dbmethod.t | 11 ++++++++++-
 2 files changed, 34 insertions(+), 33 deletions(-)

diff --git a/Pg.pm b/Pg.pm
index 948db96..5687d57 100644
--- a/Pg.pm
+++ b/Pg.pm
@@ -1322,13 +1322,7 @@ use 5.008001;
         DBI::SQL_INTEGER, DBI::SQL_SMALLINT, DBI::SQL_BIGINT, DBI::SQL_DECIMAL,
         DBI::SQL_FLOAT, DBI::SQL_REAL, DBI::SQL_DOUBLE, DBI::SQL_NUMERIC;
 
-    sub get_info {
-
-        my ($dbh,$type) = @_;
-
-        return undef unless defined $type and length $type;
-
-        my %type = (
+    my %get_info_type = (
 
 ## Driver information:
 
@@ -1336,7 +1330,7 @@ use 5.008001;
    10021 => ['SQL_ASYNC_MODE',                      2                         
], ## SQL_AM_STATEMENT
      120 => ['SQL_BATCH_ROW_COUNT',                 2                         
], ## SQL_BRC_EXPLICIT
      121 => ['SQL_BATCH_SUPPORT',                   3                         
], ## 12 SELECT_PROC + ROW_COUNT_PROC
-       2 => ['SQL_DATA_SOURCE_NAME',                "dbi:Pg:$dbh->{Name}"     
],
+       2 => ['SQL_DATA_SOURCE_NAME',                sub { sprintf "dbi:Pg:%", 
shift->{Name} } ],
        3 => ['SQL_DRIVER_HDBC',                     0                         
], ## not applicable
      135 => ['SQL_DRIVER_HDESC',                    0                         
], ## not applicable
        4 => ['SQL_DRIVER_HENV',                     0                         
], ## not applicable
@@ -1356,21 +1350,21 @@ use 5.008001;
      150 => ['SQL_KEYSET_CURSOR_ATTRIBUTES1',       0                         
], ## applies to us?
      151 => ['SQL_KEYSET_CURSOR_ATTRIBUTES2',       0                         
], ## see above
    10022 => ['SQL_MAX_ASYNC_CONCURRENT_STATEMENTS', 0                         
], ## unlimited, probably
-       0 => ['SQL_MAX_DRIVER_CONNECTIONS',          'MAXCONNECTIONS'          
], ## magic word
+       0 => ['SQL_MAX_DRIVER_CONNECTIONS',          \'SHOW max_connections'   
],
      152 => ['SQL_ODBC_INTERFACE_CONFORMANCE',      1                         
], ## SQL_OIC_LEVEL_1
       10 => ['SQL_ODBC_VER',                        '03.00.0000'              
],
      153 => ['SQL_PARAM_ARRAY_ROW_COUNTS',          2                         
], ## correct?
      154 => ['SQL_PARAM_ARRAY_SELECTS',             3                         
], ## PAS_NO_SELECT
       11 => ['SQL_ROW_UPDATES',                     'N'                       
],
       14 => ['SQL_SEARCH_PATTERN_ESCAPE',           '\\'                      
],
-      13 => ['SQL_SERVER_NAME',                     'CURRENTDB'               
], ## magic word
+      13 => ['SQL_SERVER_NAME',                     \'SELECT 
pg_catalog.current_database()' ],
      166 => ['SQL_STANDARD_CLI_CONFORMANCE',        2                         
], ## ??
      167 => ['SQL_STATIC_CURSOR_ATTRIBUTES1',       519                       
], ## ??
      168 => ['SQL_STATIC_CURSOR_ATTRIBUTES2',       5209                      
], ## ??
 
 ## DBMS Information
 
-      16 => ['SQL_DATABASE_NAME',                   'CURRENTDB'               
], ## magic word
+      16 => ['SQL_DATABASE_NAME',                   \'SELECT 
pg_catalog.current_database()' ],
       17 => ['SQL_DBMS_NAME',                       'PostgreSQL'              
],
       18 => ['SQL_DBMS_VERSION',                    'ODBCVERSION'             
], ## magic word
 
@@ -1380,7 +1374,7 @@ use 5.008001;
       19 => ['SQL_ACCESSIBLE_TABLES',               'Y'                       
], ## is this really true?
       82 => ['SQL_BOOKMARK_PERSISTENCE',            0                         
],
       42 => ['SQL_CATALOG_TERM',                    ''                        
], ## empty = catalogs are not supported
-   10004 => ['SQL_COLLATION_SEQ',                   'ENCODING'                
], ## magic word
+   10004 => ['SQL_COLLATION_SEQ',                   \'SHOW server_encoding'   
],
       22 => ['SQL_CONCAT_NULL_BEHAVIOR',            0                         
], ## SQL_CB_NULL
       23 => ['SQL_CURSOR_COMMIT_BEHAVIOR',          1                         
], ## SQL_CB_CLOSE
       24 => ['SQL_CURSOR_ROLLBACK_BEHAVIOR',        1                         
], ## SQL_CB_CLOSE
@@ -1398,7 +1392,7 @@ use 5.008001;
       45 => ['SQL_TABLE_TERM',                      'table'                   
],
       46 => ['SQL_TXN_CAPABLE',                     2                         
], ## SQL_TC_ALL
       72 => ['SQL_TXN_ISOLATION_OPTION',            10                        
], ## 2+8
-      47 => ['SQL_USER_NAME',                       $dbh->{CURRENT_USER}      
],
+      47 => ['SQL_USER_NAME',                       sub { 
shift->{CURRENT_USER} } ],
 
 ## Supported SQL
 
@@ -1509,21 +1503,28 @@ use 5.008001;
      122  => ['SQL_CONVERT_WCHAR',                  0                          
],
      125  => ['SQL_CONVERT_WLONGVARCHAR',           0                          
],
      126  => ['SQL_CONVERT_WVARCHAR',               0                          
],
+    ); ## end of %get_info_type
+    ## Add keys for names into the hash
+    for (keys %get_info_type) {
+        $get_info_type{$get_info_type{$_}->[0]} = $get_info_type{$_};
+    }
 
-        ); ## end of %type
+    sub get_info {
 
-        ## Put both numbers and names into a hash
-        my %t;
-        for (keys %type) {
-            $t{$_} = $type{$_}->[1];
-            $t{$type{$_}->[0]} = $type{$_}->[1];
-        }
+        my ($dbh,$type) = @_;
 
-        return undef unless exists $t{$type};
+        return undef unless defined $type;
+        return undef unless exists $get_info_type{$type};
 
-        my $ans = $t{$type};
+        my $ans = $get_info_type{$type}->[1];
 
-        if ($ans eq 'NAMEDATALEN') {
+        if (ref $ans eq 'CODE') {
+            $ans = $ans->($dbh);
+        }
+        elsif (ref $ans eq 'SCALAR') { # SQL
+            return $dbh->selectall_arrayref($$ans)->[0][0];
+        }
+        elsif ($ans eq 'NAMEDATALEN') {
             return $dbh->selectall_arrayref('SHOW 
max_identifier_length')->[0][0];
         }
         elsif ($ans eq 'ODBCVERSION') {
@@ -1536,21 +1537,12 @@ use 5.008001;
             $simpleversion =~ s/_/./g;
             return sprintf '%02d.%02d.%1d%1d%1d%1d', split (/\./, 
"$simpleversion.0.0.0.0.0.0");
         }
-         elsif ($ans eq 'MAXCONNECTIONS') {
-             return $dbh->selectall_arrayref('SHOW max_connections')->[0][0];
-         }
-         elsif ($ans eq 'ENCODING') {
-             return $dbh->selectall_arrayref('SHOW server_encoding')->[0][0];
-         }
          elsif ($ans eq 'KEYWORDS') {
             ## 
http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
             ## Basically, we want ones that are 'reserved' for PostgreSQL but 
not 'reserved' in SQL:2003
             ## 
             return join ',' => (qw(ANALYSE ANALYZE ASC DEFERRABLE DESC DO 
FREEZE ILIKE INITIALLY ISNULL LIMIT NOTNULL OFF OFFSET PLACING RETURNING 
VERBOSE));
          }
-         elsif ($ans eq 'CURRENTDB') {
-             return $dbh->selectall_arrayref('SELECT 
pg_catalog.current_database()')->[0][0];
-         }
          elsif ($ans eq 'READONLY') {
              my $SQL = q{SELECT CASE WHEN setting = 'on' THEN 'Y' ELSE 'N' END 
FROM pg_settings WHERE name = 'transaction_read_only'};
              my $info = $dbh->selectall_arrayref($SQL);
diff --git a/t/03dbmethod.t b/t/03dbmethod.t
index 0e5d94e..3f29ca6 100644
--- a/t/03dbmethod.t
+++ b/t/03dbmethod.t
@@ -444,6 +444,10 @@ my %get_info = (
   SQL_IDENTIFIER_QUOTE_CHAR  => 29,
   SQL_CATALOG_NAME_SEPARATOR => 41,
   SQL_USER_NAME              => 47,
+  # this also tests the dynamic attributes that run SQL
+  SQL_COLLATION_SEQ          => 10004,
+  SQL_DATABASE_NAME          => 16,
+  SQL_SERVER_NAME            => 13,
 );
 
 for (keys %get_info) {
@@ -459,6 +463,11 @@ for (keys %get_info) {
        is ($back, $forth, $t);
 }
 
+# Make sure SQL_MAX_COLUMN_NAME_LEN looks normal
+$t='DB handle method "get_info" returns a valid looking 
SQL_MAX_COLUMN_NAME_LEN string}';
+my $namedatalen = $dbh->get_info('SQL_MAX_COLUMN_NAME_LEN');
+cmp_ok ($namedatalen, '>=', 63, $t);
+
 # Make sure odbcversion looks normal
 $t='DB handle method "get_info" returns a valid looking ODBCVERSION string}';
 my $odbcversion = $dbh->get_info(18);
@@ -466,7 +475,7 @@ like ($odbcversion, qr{^([1-9]\d|\d[1-9])\.\d\d\.\d\d00$}, 
$t);
 
 # Testing max connections is good as this info is dynamic
 $t='DB handle method "get_info" returns a number for 
SQL_MAX_DRIVER_CONNECTIONS';
-my $maxcon = $dbh->get_info(0);
+my $maxcon = $dbh->get_info('SQL_MAX_DRIVER_CONNECTIONS');
 like ($maxcon, qr{^\d+$}, $t);
 
 $t='DB handle method "get_info" returns correct string for 
SQL_DATA_SOURCE_READ_ONLY when "on"';
-- 
1.8.4

Reply via email to