Tim Bunce wrote:
>
> On Mon, Nov 26, 2001 at 04:25:16PM +0100, Steffen Goeldner wrote:
> > >
> > else if (htype==DBIt_DB && strnEQ(key, "SQL_", 4)) {
> > /* XXX DBIt_ST ? */
> > valuesv = dbih_get_info(h, key, keylen);
>
> That presumes that _all_ attributes begining with SQL_ are
> 'get_info' attributes. That may not be the case. I'd suggest
>
> else if (htype==DBIt_DB && strnEQ(key, "SQL_", 4) && gi_code =
>get_info_name2code(key))
>
That's right! My brain was focused on get_info. However,
dbih_get_attr_k is big enough, I renamed dbih_get_info to
the more generic dbih_get_attr_k_sql_:
else if (htype==DBIt_DB && strnEQ(key, "SQL_", 4)) {
valuesv = dbih_get_attr_k_sql_(h, keysv, key, keylen);
and let it handle all SQL_* requests:
static SV *
dbih_get_attr_k_sql_(SV *h, SV *keysv, char *key, STRLEN keylen)
{
dPERINTERP;
dSP;
HV *hv;
char *meth_name;
SV *valuesv;
static bool loaded = FALSE;
if (!loaded) {
eval_pv("require DBI::Const", TRUE);
loaded = TRUE;
}
if ((hv = get_hv("DBI::Const::GetInfo", FALSE)) && hv_exists(hv, key, keylen)) {
meth_name = "get_info";
}
/*
other SQL_* requests:
else if ((hv = get_hv("DBI::Const::Get???", FALSE)) && hv_exists(hv, key, keylen))
{
meth_name = "get_???";
}
*/
else {
croak("Can't get %s->{%s}: unrecognised attribute", neatsvpv(h,0), key);
}
PUSHMARK(SP);
XPUSHs(h);
XPUSHs(keysv);
PUTBACK;
if (call_method(meth_name, G_SCALAR) != 1)
croak("Can't locate DBI object method \"%s\"", meth_name);
SPAGAIN;
valuesv = POPs;
PUTBACK;
return newSVsv(valuesv);
}
Comments are highly appreciated!
> > Of course, dbih_get_info needs to be written. I think, it should
> >
> > 1) map the symbolic name to the numeric code
> > (via %DBI::Const::GetInfo?)
> > 2) call $dbh->get_info($code)
>
> There's also the question of whether each particular item of 'info'
> can be cached for the handle it's being called on (see cacheit in
> dbih_get_attr_k).
>
Here I need further investigation ...
> Yeap. Though you could argue that using hash fetching should be the
> primary API to get_info and just not bother supporting importing
> numeric constants. And I don't think there's a good performance
> argument for numeric constants. So lets just skip the import :)
Great!
For testing purposes, I added a few more lines of code to DBI,
see my attachment.
Steffen
diff -Nrc DBI-1.20.orig/DBI.xs DBI-1.20/DBI.xs
*** DBI-1.20.orig/DBI.xs Sat Aug 25 00:10:48 2001
--- DBI-1.20/DBI.xs Wed Nov 28 10:33:59 2001
***************
*** 1243,1248 ****
--- 1243,1283 ----
static SV *
+ dbih_get_attr_k_sql_(SV *h, SV *keysv, char *key, STRLEN keylen)
+ {
+ dPERINTERP;
+ dSP;
+ HV *hv;
+ char *meth_name;
+ SV *valuesv;
+ static bool loaded = FALSE;
+
+ if (!loaded) {
+ eval_pv("require DBI::Const", TRUE);
+ loaded = TRUE;
+ }
+ if ((hv = get_hv("DBI::Const::GetInfo", FALSE)) && hv_exists(hv, key, keylen)) {
+ meth_name = "get_info";
+ }
+ else {
+ croak("Can't get %s->{%s}: unrecognised attribute", neatsvpv(h,0), key);
+ }
+
+ PUSHMARK(SP);
+ XPUSHs(h);
+ XPUSHs(keysv);
+ PUTBACK;
+ if (call_method(meth_name, G_SCALAR) != 1)
+ croak("Can't locate DBI object method \"%s\"", meth_name);
+ SPAGAIN;
+ valuesv = POPs;
+ PUTBACK;
+
+ return newSVsv(valuesv);
+ }
+
+
+ static SV *
dbih_get_attr_k(h, keysv, dbikey) /* XXX split into dr/db/st
funcs */
SV *h;
SV *keysv;
***************
*** 1406,1411 ****
--- 1441,1449 ----
}
else if (keylen==9 && strEQ(key, "BegunWork")) {
valuesv = boolSV(DBIc_has(imp_xxh,DBIcf_BegunWork));
+ }
+ else if (htype==DBIt_DB && strnEQ(key, "SQL_", 4)) {
+ valuesv = dbih_get_attr_k_sql_(h, keysv, key, keylen);
}
else { /* finally check the actual hash just in case */
svp = hv_fetch((HV*)SvRV(h), key, keylen, FALSE);
diff -Nrc DBI-1.20.orig/lib/DBD/NullP.pm DBI-1.20/lib/DBD/NullP.pm
*** DBI-1.20.orig/lib/DBD/NullP.pm Sat Aug 25 00:10:50 2001
--- DBI-1.20/lib/DBD/NullP.pm Wed Nov 28 10:30:41 2001
***************
*** 58,63 ****
--- 58,69 ----
$outer;
}
+ sub get_info {
+ my $dbh = shift;
+ my $git = shift;
+ return 'GetInfo: ' . $git;
+ }
+
sub FETCH {
my ($dbh, $attrib) = @_;
# In reality this would interrogate the database engine to
diff -Nrc DBI-1.20.orig/lib/DBI/Const.pm DBI-1.20/lib/DBI/Const.pm
*** DBI-1.20.orig/lib/DBI/Const.pm Thu Jan 01 01:00:00 1970
--- DBI-1.20/lib/DBI/Const.pm Wed Nov 28 10:28:48 2001
***************
*** 0 ****
--- 1,238 ----
+ package DBI::Const;
+
+ =head1 NAME
+
+ DBI::Const - DBI constants
+
+ =cut
+
+ $VERSION = '0.01';
+
+ %GetInfo =
+ ( # ODBC SQL
+ SQL_ACTIVE_CONNECTIONS => 0 # 0
+ , SQL_MAXIMUM_DRIVER_CONNECTIONS => 0 # 0 0
+ , SQL_MAX_DRIVER_CONNECTIONS => 0 # 0
+ , SQL_INFO_FIRST => 0 # 0
+ , SQL_ACTIVE_STATEMENTS => 1 # 1
+ , SQL_MAX_CONCURRENT_ACTIVITIES => 1 # 1
+ , SQL_MAXIMUM_CONCURRENT_ACTIVITIES => 1 # 1 1
+ , SQL_DATA_SOURCE_NAME => 2 # 2 2
+ , SQL_DRIVER_HDBC => 3 # 3
+ , SQL_DRIVER_HENV => 4 # 4
+ , SQL_DRIVER_HSTMT => 5 # 5
+ , SQL_DRIVER_NAME => 6 # 6
+ , SQL_DRIVER_VER => 7 # 7
+ , SQL_FETCH_DIRECTION => 8 # 8 8
+ , SQL_ODBC_API_CONFORMANCE => 9 # 9
+ , SQL_ODBC_VER => 10 # 10
+ , SQL_ROW_UPDATES => 11 # 11
+ , SQL_ODBC_SAG_CLI_CONFORMANCE => 12 # 12
+ , SQL_SERVER_NAME => 13 # 13 13
+ , SQL_SEARCH_PATTERN_ESCAPE => 14 # 14 14
+ , SQL_ODBC_SQL_CONFORMANCE => 15 # 15
+ , SQL_DBMS_NAME => 17 # 17 17
+ , SQL_DBMS_VER => 18 # 18
+ , SQL_DBMS_VERSION => 18 # 18
+ , SQL_ACCESSIBLE_TABLES => 19 # 19
+ , SQL_ACCESSIBLE_PROCEDURES => 20 # 20
+ , SQL_PROCEDURES => 21 # 21
+ , SQL_CONCAT_NULL_BEHAVIOR => 22 # 22
+ , SQL_CURSOR_COMMIT_BEHAVIOR => 23 # 23 23
+ , SQL_CURSOR_ROLLBACK_BEHAVIOR => 24 # 24
+ , SQL_DATA_SOURCE_READ_ONLY => 25 # 25 25
+ , SQL_DEFAULT_TXN_ISOLATION => 26 # 26
+ , SQL_DEFAULT_TRANSACTION_ISOLATION => 26 # 26
+ , SQL_EXPRESSIONS_IN_ORDERBY => 27 # 27
+ , SQL_IDENTIFIER_CASE => 28 # 28 28
+ , SQL_IDENTIFIER_QUOTE_CHAR => 29 # 29
+ , SQL_MAXIMUM_COLUMN_NAME_LENGTH => 30 # 30 30
+ , SQL_MAX_COLUMN_NAME_LEN => 30 # 30
+ , SQL_MAXIMUM_CURSOR_NAME_LENGTH => 31 # 31 31
+ , SQL_MAX_CURSOR_NAME_LEN => 31 # 31
+ , SQL_MAX_OWNER_NAME_LEN => 32 # 32
+ , SQL_MAXIMUM_SCHEMA_NAME_LENGTH => 32 # 32 32
+ , SQL_MAX_SCHEMA_NAME_LEN => 32 # 32
+ , SQL_MAX_PROCEDURE_NAME_LEN => 33 # 33
+ , SQL_MAX_CATALOG_NAME_LEN => 34 # 34
+ , SQL_MAXIMUM_CATALOG_NAME_LENGTH => 34 # 34 34
+ , SQL_MAX_QUALIFIER_NAME_LEN => 34 # 34
+ , SQL_MAX_TABLE_NAME_LEN => 35 # 35
+ , SQL_MAXIMUM_TABLE_NAME_LENGTH => 35 # 35
+ , SQL_MULT_RESULT_SETS => 36 # 36
+ , SQL_MULTIPLE_ACTIVE_TXN => 37 # 37
+ , SQL_OUTER_JOINS => 38 # 38
+ , SQL_OWNER_TERM => 39 # 39
+ , SQL_SCHEMA_TERM => 39 # 39
+ , SQL_PROCEDURE_TERM => 40 # 40
+ , SQL_CATALOG_NAME_SEPARATOR => 41 # 41
+ , SQL_QUALIFIER_NAME_SEPARATOR => 41 # 41
+ , SQL_QUALIFIER_TERM => 42 # 42
+ , SQL_CATALOG_TERM => 42 # 42
+ , SQL_SCROLL_CONCURRENCY => 43 # 43 43
+ , SQL_SCROLL_OPTIONS => 44 # 44
+ , SQL_TABLE_TERM => 45 # 45
+ , SQL_TXN_CAPABLE => 46 # 46
+ , SQL_TRANSACTION_CAPABLE => 46 # 46 46
+ , SQL_USER_NAME => 47 # 47 47
+ , SQL_CONVERT_FUNCTIONS => 48 # 48
+ , SQL_NUMERIC_FUNCTIONS => 49 # 49
+ , SQL_STRING_FUNCTIONS => 50 # 50
+ , SQL_SYSTEM_FUNCTIONS => 51 # 51
+ , SQL_TIMEDATE_FUNCTIONS => 52 # 52
+ , SQL_CONVERT_BIGINT => 53 # 53
+ , SQL_CONVERT_BINARY => 54 # 54
+ , SQL_CONVERT_BIT => 55 # 55
+ , SQL_CONVERT_CHAR => 56 # 56
+ , SQL_CONVERT_DATE => 57 # 57
+ , SQL_CONVERT_DECIMAL => 58 # 58
+ , SQL_CONVERT_DOUBLE => 59 # 59
+ , SQL_CONVERT_FLOAT => 60 # 60
+ , SQL_CONVERT_INTEGER => 61 # 61
+ , SQL_CONVERT_LONGVARCHAR => 62 # 62
+ , SQL_CONVERT_NUMERIC => 63 # 63
+ , SQL_CONVERT_REAL => 64 # 64
+ , SQL_CONVERT_SMALLINT => 65 # 65
+ , SQL_CONVERT_TIME => 66 # 66
+ , SQL_CONVERT_TIMESTAMP => 67 # 67
+ , SQL_CONVERT_TINYINT => 68 # 68
+ , SQL_CONVERT_VARBINARY => 69 # 69
+ , SQL_CONVERT_VARCHAR => 70 # 70
+ , SQL_CONVERT_LONGVARBINARY => 71 # 71
+ , SQL_TXN_ISOLATION_OPTION => 72 # 72
+ , SQL_TRANSACTION_ISOLATION_OPTION => 72 # 72 72
+ , SQL_INTEGRITY => 73 # 73 73
+ , SQL_ODBC_SQL_OPT_IEF => 73 # 73
+ , SQL_CORRELATION_NAME => 74 # 74
+ , SQL_NON_NULLABLE_COLUMNS => 75 # 75
+ , SQL_DRIVER_HLIB => 76 # 76
+ , SQL_DRIVER_ODBC_VER => 77 # 77
+ , SQL_LOCK_TYPES => 78 # 78
+ , SQL_POS_OPERATIONS => 79 # 79
+ , SQL_POSITIONED_STATEMENTS => 80 # 80
+ , SQL_GETDATA_EXTENSIONS => 81 # 81 81
+ , SQL_BOOKMARK_PERSISTENCE => 82 # 82
+ , SQL_STATIC_SENSITIVITY => 83 # 83
+ , SQL_FILE_USAGE => 84 # 84
+ , SQL_NULL_COLLATION => 85 # 85 85
+ , SQL_ALTER_TABLE => 86 # 86 86
+ , SQL_COLUMN_ALIAS => 87 # 87
+ , SQL_GROUP_BY => 88 # 88
+ , SQL_KEYWORDS => 89 # 89
+ , SQL_ORDER_BY_COLUMNS_IN_SELECT => 90 # 90 90
+ , SQL_OWNER_USAGE => 91 # 91
+ , SQL_SCHEMA_USAGE => 91 # 91
+ , SQL_QUALIFIER_USAGE => 92 # 92
+ , SQL_CATALOG_USAGE => 92 # 92
+ , SQL_QUOTED_IDENTIFIER_CASE => 93 # 93
+ , SQL_SPECIAL_CHARACTERS => 94 # 94 94
+ , SQL_SUBQUERIES => 95 # 95
+ , SQL_UNION_STATEMENT => 96 # 96
+ , SQL_UNION => 96 # 96
+ , SQL_MAXIMUM_COLUMNS_IN_GROUP_BY => 97 # 97 97
+ , SQL_MAX_COLUMNS_IN_GROUP_BY => 97 # 97
+ , SQL_MAXIMUM_COLUMNS_IN_INDEX => 98 # 98
+ , SQL_MAX_COLUMNS_IN_INDEX => 98 # 98
+ , SQL_MAX_COLUMNS_IN_ORDER_BY => 99 # 99
+ , SQL_MAXIMUM_COLUMNS_IN_ORDER_BY => 99 # 99 99
+ , SQL_MAX_COLUMNS_IN_SELECT => 100 # 100
+ , SQL_MAXIMUM_COLUMNS_IN_SELECT => 100 # 100 100
+ , SQL_MAXIMUM_COLUMNS_IN_TABLE => 101 # 101
+ , SQL_MAX_COLUMNS_IN_TABLE => 101 # 101
+ , SQL_MAXIMUM_INDEX_SIZE => 102 # 102
+ , SQL_MAX_INDEX_SIZE => 102 # 102
+ , SQL_MAX_ROW_SIZE_INCLUDES_LONG => 103 # 103
+ , SQL_MAX_ROW_SIZE => 104 # 104
+ , SQL_MAXIMUM_ROW_SIZE => 104 # 104
+ , SQL_MAX_STATEMENT_LEN => 105 # 105
+ , SQL_MAXIMUM_STATEMENT_LENGTH => 105 # 105
+ , SQL_MAXIMUM_TABLES_IN_SELECT => 106 # 106 106
+ , SQL_MAX_TABLES_IN_SELECT => 106 # 106
+ , SQL_MAX_USER_NAME_LEN => 107 # 107
+ , SQL_MAXIMUM_USER_NAME_LENGTH => 107 # 107 107
+ , SQL_MAX_CHAR_LITERAL_LEN => 108 # 108
+ , SQL_TIMEDATE_ADD_INTERVALS => 109 # 109
+ , SQL_TIMEDATE_DIFF_INTERVALS => 110 # 110
+ , SQL_NEED_LONG_DATA_LEN => 111 # 111
+ , SQL_MAX_BINARY_LITERAL_LEN => 112 # 112
+ , SQL_LIKE_ESCAPE_CLAUSE => 113 # 113
+ , SQL_INFO_LAST => 114 # 114
+ , SQL_QUALIFIER_LOCATION => 114 # 114
+ , SQL_CATALOG_LOCATION => 114 # 114
+ , SQL_OUTER_JOIN_CAPABILITIES => 115 # 115 115
+ , SQL_ACTIVE_ENVIRONMENTS => 116 # 116
+ , SQL_ALTER_DOMAIN => 117 # 117
+ , SQL_SQL_CONFORMANCE => 118 # 118
+ , SQL_DATETIME_LITERALS => 119 # 119
+ , SQL_BATCH_ROW_COUNT => 120 # 120
+ , SQL_BATCH_SUPPORT => 121 # 121
+ , SQL_CONVERT_WCHAR => 122 # 122
+ , SQL_CONVERT_INTERVAL_DAY_TIME => 123 # 123
+ , SQL_CONVERT_INTERVAL_YEAR_MONTH => 124 # 124
+ , SQL_CONVERT_WLONGVARCHAR => 125 # 125
+ , SQL_CONVERT_WVARCHAR => 126 # 126
+ , SQL_CREATE_ASSERTION => 127 # 127
+ , SQL_CREATE_CHARACTER_SET => 128 # 128
+ , SQL_CREATE_COLLATION => 129 # 129
+ , SQL_CREATE_DOMAIN => 130 # 130
+ , SQL_CREATE_SCHEMA => 131 # 131
+ , SQL_CREATE_TABLE => 132 # 132
+ , SQL_CREATE_TRANSLATION => 133 # 133
+ , SQL_CREATE_VIEW => 134 # 134
+ , SQL_DRIVER_HDESC => 135 # 135
+ , SQL_DROP_ASSERTION => 136 # 136
+ , SQL_DROP_CHARACTER_SET => 137 # 137
+ , SQL_DROP_COLLATION => 138 # 138
+ , SQL_DROP_DOMAIN => 139 # 139
+ , SQL_DROP_SCHEMA => 140 # 140
+ , SQL_DROP_TABLE => 141 # 141
+ , SQL_DROP_TRANSLATION => 142 # 142
+ , SQL_DROP_VIEW => 143 # 143
+ , SQL_DYNAMIC_CURSOR_ATTRIBUTES1 => 144 # 144
+ , SQL_DYNAMIC_CURSOR_ATTRIBUTES2 => 145 # 145
+ , SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 => 146 # 146
+ , SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 => 147 # 147
+ , SQL_INDEX_KEYWORDS => 148 # 148
+ , SQL_INFO_SCHEMA_VIEWS => 149 # 149
+ , SQL_KEYSET_CURSOR_ATTRIBUTES1 => 150 # 150
+ , SQL_KEYSET_CURSOR_ATTRIBUTES2 => 151 # 151
+ , SQL_ODBC_INTERFACE_CONFORMANCE => 152 # 152
+ , SQL_PARAM_ARRAY_ROW_COUNTS => 153 # 153
+ , SQL_PARAM_ARRAY_SELECTS => 154 # 154
+ , SQL_SQL92_DATETIME_FUNCTIONS => 155 # 155
+ , SQL_SQL92_FOREIGN_KEY_DELETE_RULE => 156 # 156
+ , SQL_SQL92_FOREIGN_KEY_UPDATE_RULE => 157 # 157
+ , SQL_SQL92_GRANT => 158 # 158
+ , SQL_SQL92_NUMERIC_VALUE_FUNCTIONS => 159 # 159
+ , SQL_SQL92_PREDICATES => 160 # 160
+ , SQL_SQL92_RELATIONAL_JOIN_OPERATORS => 161 # 161
+ , SQL_SQL92_REVOKE => 162 # 162
+ , SQL_SQL92_ROW_VALUE_CONSTRUCTOR => 163 # 163
+ , SQL_SQL92_STRING_FUNCTIONS => 164 # 164
+ , SQL_SQL92_VALUE_EXPRESSIONS => 165 # 165
+ , SQL_STANDARD_CLI_CONFORMANCE => 166 # 166
+ , SQL_STATIC_CURSOR_ATTRIBUTES1 => 167 # 167
+ , SQL_STATIC_CURSOR_ATTRIBUTES2 => 168 # 168
+ , SQL_AGGREGATE_FUNCTIONS => 169 # 169
+ , SQL_DDL_INDEX => 170 # 170
+ , SQL_DM_VER => 171 # 171
+ , SQL_INSERT_STATEMENT => 172 # 172
+ , SQL_CONVERT_GUID => 173 # 173
+ , SQL_INFO_DRIVER_START => 1000 # 1000
+ , SQL_XOPEN_CLI_YEAR => 10000 # 10000
+ , SQL_CURSOR_SENSITIVITY => 10001 # 10001 10001
+ , SQL_DESCRIBE_PARAMETER => 10002 # 10002 10002
+ , SQL_CATALOG_NAME => 10003 # 10003 10003
+ , SQL_COLLATING_SEQUENCE => 10004 # 10004
+ , SQL_COLLATION_SEQ => 10004 # 10004
+ , SQL_MAXIMUM_IDENTIFIER_LENGTH => 10005 # 10005 10005
+ , SQL_MAX_IDENTIFIER_LEN => 10005 # 10005
+ , SQL_ASYNC_MODE => 10021 # 10021
+ , SQL_MAX_ASYNC_CONCURRENT_STATEMENTS => 10022 # 10022
+ , SQL_MAXIMUM_STMT_OCTETS => 20000 # 20000
+ , SQL_MAXIMUM_STMT_OCTETS_DATA => 20001 # 20001
+ , SQL_MAXIMUM_STMT_OCTETS_SCHEMA => 20002 # 20002
+ , SQL_OJ_CAPABILITIES => 65003 # 65003
+ );
+
+ 1;
diff -Nrc DBI-1.20.orig/t/getinfo.t DBI-1.20/t/getinfo.t
*** DBI-1.20.orig/t/getinfo.t Thu Jan 01 01:00:00 1970
--- DBI-1.20/t/getinfo.t Wed Nov 28 11:08:48 2001
***************
*** 0 ****
--- 1,58 ----
+
+ $| = 1;
+
+ use strict;
+
+ use Test::More tests => 7;
+
+ BEGIN { use_ok('DBI') }
+
+ my $dbh;
+
+ # -----------------------------------------------------------------------------
+ {
+ $dbh = DBI->connect('dbi:NullP:') or die $DBI::errstr;
+ $dbh->{ RaiseError } = 1;
+ $dbh->{ PrintError } = 1;
+
+ ok( defined $dbh,'Database handle defined');
+
+ ok( $DBD::NullP::VERSION,'$DBD::NullP::VERSION');
+
+ is( $dbh->{ RaiseError }, 1,'$dbh->{ RaiseError }');
+ }
+ # -----------------------------------------------------------------------------
+ {
+ no strict 'subs';
+
+ eval { my $v = $dbh->{ SQL_XXX }; };
+ like( $@, qr/unrecognised attribute/
+ ,'unrecognised attribute');
+
+ # $dbh->trace( 9 );
+ is( $dbh->{ SQL_DBMS_VER },'GetInfo: SQL_DBMS_VER'
+ ,'Fetch: $dbh->{ SQL_DBMS_VER }');
+ # $dbh->trace( 0 );
+
+ is( $dbh->get_info( SQL_DBMS_NAME ),'GetInfo: SQL_DBMS_NAME'
+ ,'Call: $dbh->get_info( SQL_DBMS_NAME )');
+
+ }
+ # -----------------------------------------------------------------------------
+ __END__
+
+ # -----------------------------------------------------------------------------
+ {
+ local $\ = "\n";
+ use DBI::Const();
+ use Benchmark();
+ my $t0 = new Benchmark;
+ while ( my ( $k, $v ) = each %DBI::Const::GetInfo )
+ { # x86 200 MHz 64Mb
+ # $dbh->get_info( $k ); # 0 wallclock secs ( 0.04 usr + 0.00
+sys = 0.04 CPU)
+ # print $k, ' => ', $dbh->get_info( $k ); # 0 wallclock secs ( 0.09 usr + 0.06
+sys = 0.15 CPU)
+ # $dbh->{ $k }; # 0 wallclock secs ( 0.10 usr + 0.00
+sys = 0.10 CPU)
+ # print $k, ' => ', $dbh->{ $k }; # 0 wallclock secs ( 0.14 usr + 0.07
+sys = 0.21 CPU)
+ }
+ print Benchmark::timestr( Benchmark::timediff( Benchmark->new, $t0 ) );
+ }