Author: spadkins
Date: Mon Aug 20 08:36:37 2007
New Revision: 9863
Modified:
p5ee/trunk/App-Repository/CHANGES
p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm
p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm
p5ee/trunk/App-Repository/t/DBI-insert.t
Log:
better logging of SQL errors to include the SQL statement
Modified: p5ee/trunk/App-Repository/CHANGES
==============================================================================
--- p5ee/trunk/App-Repository/CHANGES (original)
+++ p5ee/trunk/App-Repository/CHANGES Mon Aug 20 08:36:37 2007
@@ -2,6 +2,25 @@
# CHANGE LOG
#########################################
+0.966 (not yet released)
+ x App::Repository::evaluate_expression(): can now supply defaults for null
columns
+ x App::Repository::evaluate_expression(): added column defaults
+ x App::Repository::evaluate_expression(): fixed to be more efficient and to
handle defaults on columns which are expressions themselves
+ x App::Repository::evaluate_expression(): fixed a bug when evaluating
expressions of columns that end in digits
+ x App::Repository::evaluate_expression(): fixed a bug where using a hashref
instead of arrayref
+ x App::Repository::evaluate_constant_expression(): fix for div 0 and sci
notation
+ x App::Repository::summarize_rows(): can now summarize columns which have
alternate aggregate levels
+ x App::Repository::summarize_rows(): produce an undef if all values that are
summed are undef
+ x App::Repository::last_inserted_id($table): new method (without underscore)
now takes $table param, works on redirects
+ x App::Repository - changed begin_work(), commit(), rollback() to consult an
{in_transaction} attribute
+ This does something sensible if begin_work() is called within a transaction
or a commit()/rollback() is outside a transaction
+ x App::Repository - get_table_def(): enable the 'table_def' option in
get_rows() to override or supplement table_def entries already in the config
+ x App::Repository::* - change debug_sql and all other debug-style output to
obey the debug_file option
+ x App::Repository::DBI - get_phys_column_names(): new method
+ x App::Repository::ValueDomain - use App::Repository::DBI::_do instead of DBI
methods
+ x App::Repository::_insert_row(): handle update on duplicate
+ x App::Repository::* - improved logging of database errors when they occur
(includes the SQL statement that failed)
+
0.965
x can now configure multiple databases (App::Repository::DBI) from app.conf
(xyz.dbhost, xyz.dbname, ... for rep "xyz")
x full redirection to other tables or other tables in other repositories is
done
Modified: p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository/DBI.pm Mon Aug 20 08:36:37 2007
@@ -186,11 +186,11 @@
if ($@) {
delete $self->{dbh};
if ($@ =~ /Lost connection/ || $@ =~ /server has gone away/) {
- $self->{context}->log("DBI Exception (retrying) in
_connect(): $@");
+ $self->{context}->log({level=>1},"DBI Exception (retrying)
in _connect(): $@");
sleep(1);
}
else {
- $self->{context}->log("DBI Exception (fail) in _connect():
$@");
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_connect(): $@");
die $@;
}
}
@@ -416,14 +416,14 @@
if ($@) {
$row = undef;
if ($@ =~ /Lost connection/ || $@ =~ /server has gone away/) {
- $self->{context}->log("DBI Exception (retrying) in _get_row():
$@");
+ $self->{context}->log({level=>1},"DBI Exception (retrying) in
_get_row(): $@");
$self->_disconnect();
sleep(1);
$self->_connect();
$dbh = $self->{dbh};
}
else {
- $self->{context}->log("DBI Exception (fail) in _get_row():
$@");
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_get_rows(): [EMAIL PROTECTED]");
die $@;
}
}
@@ -485,13 +485,13 @@
if ($@) {
$rows = [];
if ($@ =~ /Lost connection/ || $@ =~ /server has gone away/) {
- $self->{context}->log("DBI Exception (retrying) in
_get_rows(): $@");
+ $self->{context}->log({level=>1},"DBI Exception (retrying) in
_get_rows(): $@");
$self->_disconnect();
sleep(1);
$self->_connect();
}
else {
- $self->{context}->log("DBI Exception (fail) in _get_rows():
$@");
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_get_rows(): [EMAIL PROTECTED]");
die $@;
}
}
@@ -2177,6 +2177,7 @@
my $context_options = $self->{context}{options};
my $debug_sql = $context_options->{debug_sql};
my ($timer, $elapsed_time);
+ my $loglevel = 1;
if ($debug_sql) {
$timer = $self->_get_timer();
print $App::DEBUG_FILE "DEBUG_SQL: insert()\n";
@@ -2186,7 +2187,18 @@
if ($context_options->{explain_sql}) {
$self->explain_sql($sql);
}
- $retval = $dbh->do($sql, undef, @$row) if (defined $dbh);
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql, undef, @$row);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ };
+ if ($@) { # Log the error message with the SQL and rethrow the
exception
+ my $bind_values = join("|", map { defined $_ ? $_ : "undef" }
@$row);
+ $loglevel = 3 if ($@ =~ /duplicate/i);
+ $self->{context}->log({level=>$loglevel}, "DBI Exception (fail) in
_insert_row(): [EMAIL PROTECTED] VALUES: [$bind_values]\nSQL: $sql");
+ die $@;
+ }
+ }
if ($debug_sql && $debug_sql >= 2) {
$elapsed_time = $self->_read_timer($timer);
print $App::DEBUG_FILE "DEBUG_SQL: retval [$retval] ($elapsed_time
sec) $DBI::errstr\n";
@@ -2213,6 +2225,7 @@
my $debug_sql = $context_options->{debug_sql};
my $explain_sql = $context_options->{explain_sql};
my ($timer, $elapsed_time);
+ my $loglevel = 1;
if ($debug_sql) {
$timer = $self->_get_timer();
}
@@ -2227,7 +2240,18 @@
if ($explain_sql) {
$self->explain_sql($sql);
}
- $retval = $dbh->do($sql, undef, @$row);
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql, undef, @$row);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old
"0"
+ };
+ if ($@) { # Log the error message with the SQL and rethrow
the exception
+ $loglevel = ($@ =~ /duplicate/i) ? 3 : 1;
+ my $bind_values = join("|", map { defined $_ ? $_ :
"undef" } @$row);
+ $self->{context}->log({level=>$loglevel}, "DBI Exception
(fail) in _insert_rows() [ARRAY]: [EMAIL PROTECTED] VALUES:
[$bind_values]\nSQL: $sql");
+ die $@;
+ }
+ }
if ($debug_sql) {
print $App::DEBUG_FILE "DEBUG_SQL: retval [$retval]
$DBI::errstr\n";
print $App::DEBUG_FILE "\n";
@@ -2261,7 +2285,18 @@
if ($context_options->{explain_sql}) {
$self->explain_sql($sql);
}
- $retval = $dbh->do($sql, undef, @$row);
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql, undef, @$row);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain
old "0"
+ };
+ if ($@) { # Log the error message with the SQL and
rethrow the exception
+ $loglevel = ($@ =~ /duplicate/i) ? 3 : 1;
+ my $bind_values = join("|", map { defined $_ ? $_ :
"undef" } @$row);
+ $self->{context}->log({level=>$loglevel}, "DBI
Exception (fail) in _insert_rows() [FILE]: [EMAIL PROTECTED] VALUES:
[$bind_values]\nSQL: $sql");
+ die $@;
+ }
+ }
if ($debug_sql) {
print $App::DEBUG_FILE "DEBUG_SQL: retval [$retval]
$DBI::errstr\n";
print $App::DEBUG_FILE "\n";
@@ -2305,8 +2340,18 @@
if ($context_options->{explain_sql}) {
$self->explain_sql($sql);
}
- my $retval = $self->{dbh}->do($sql);
- $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ my $retval = 0;
+ my $dbh = $self->{dbh};
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ };
+ if ($@) { # Log the error message with the SQL and rethrow the
exception
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_delete(): [EMAIL PROTECTED]: $sql");
+ die $@;
+ }
+ }
if ($debug_sql) {
$elapsed_time = $self->_read_timer($timer);
print $App::DEBUG_FILE "DEBUG_SQL: retval [$retval] ($elapsed_time
sec) $DBI::errstr\n";
@@ -2340,8 +2385,18 @@
if ($context_options->{explain_sql}) {
$self->explain_sql($sql);
}
- my $retval = $self->{dbh}->do($sql);
- $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ my $retval = 0;
+ my $dbh = $self->{dbh};
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ };
+ if ($@) { # Log the error message with the SQL and rethrow the
exception
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_update(): [EMAIL PROTECTED]: $sql");
+ die $@;
+ }
+ }
if ($debug_sql) {
$elapsed_time = $self->_read_timer($timer);
print $App::DEBUG_FILE "DEBUG_SQL: retval [$retval] ($elapsed_time
sec) $DBI::errstr\n";
@@ -2359,8 +2414,6 @@
$self->{error} = "";
my $sql = $self->_mk_delete_row_sql(@_);
$self->{sql} = $sql;
- my $dbh = $self->{dbh};
- my $retval = 0;
my $context_options = $self->{context}{options};
my $debug_sql = $context_options->{debug_sql};
@@ -2373,8 +2426,18 @@
if ($context_options->{explain_sql}) {
$self->explain_sql($sql);
}
- $retval = $dbh->do($sql) if (defined $dbh);
- $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ my $retval = 0;
+ my $dbh = $self->{dbh};
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ };
+ if ($@) { # Log the error message with the SQL and rethrow the
exception
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_delete_row(): [EMAIL PROTECTED]: $sql");
+ die $@;
+ }
+ }
if ($debug_sql) {
$elapsed_time = $self->_read_timer($timer);
print $App::DEBUG_FILE "DEBUG_SQL: retval [$retval] ($elapsed_time
sec) $DBI::errstr\n";
@@ -2392,8 +2455,6 @@
$self->{error} = "";
my $sql = $self->_mk_delete_rows_sql(@_);
$self->{sql} = $sql;
- my $dbh = $self->{dbh};
- my $retval = 0;
my $context_options = $self->{context}{options};
my $debug_sql = $context_options->{debug_sql};
@@ -2406,7 +2467,18 @@
if ($context_options->{explain_sql}) {
$self->explain_sql($sql);
}
- $retval = $dbh->do($sql) if (defined $dbh);
+ my $retval = 0;
+ my $dbh = $self->{dbh};
+ if (defined $dbh) {
+ eval {
+ $retval = $dbh->do($sql);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ };
+ if ($@) { # Log the error message with the SQL and rethrow the
exception
+ $self->{context}->log({level=>1},"DBI Exception (fail) in
_delete_rows(): [EMAIL PROTECTED]: $sql");
+ die $@;
+ }
+ }
$retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
if ($debug_sql) {
$elapsed_time = $self->_read_timer($timer);
@@ -2439,14 +2511,20 @@
$self->explain_sql($sql);
}
if (defined $dbh) {
- if ($sql =~ /^select/i) {
- $retval = $dbh->selectall_arrayref($sql);
- }
- else {
- $retval = $dbh->do($sql);
- $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
- }
$self->{sql} = $sql;
+ eval {
+ if ($sql =~ /^select/i) {
+ $retval = $dbh->selectall_arrayref($sql);
+ }
+ else {
+ $retval = $dbh->do($sql);
+ $retval = 0 if ($retval == 0); # turn "0E0" into plain old "0"
+ }
+ };
+ if ($@) { # Log the error message with the SQL and rethrow the
exception
+ $self->{context}->log({level=>1},"DBI Exception (fail) in _do():
[EMAIL PROTECTED]");
+ die $@;
+ }
}
if ($debug_sql) {
my $nrows = 0;
Modified: p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm
==============================================================================
--- p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm (original)
+++ p5ee/trunk/App-Repository/lib/App/Repository/MySQL.pm Mon Aug 20
08:36:37 2007
@@ -283,7 +283,7 @@
&App::sub_entry if ($App::trace);
my ($self, $table, $cols, $rows, $options) = @_;
$self->{error} = "";
- my ($sql, $retval);
+ my ($sql, $retval, $nrows_this_insert);
my $dbh = $self->{dbh};
return 0 if (!defined $dbh);
@@ -306,6 +306,7 @@
$rownum2 = $rownum + $maxrows - 1;
$rownum2 = $#$rows if ($rownum2 > $#$rows);
@current_rows = @{$rows}[($rownum .. $rownum2)];
+ $nrows_this_insert = $#current_rows + 1;
$sql = $self->_mk_insert_rows_sql($table, $cols, [EMAIL
PROTECTED], $options);
if ($debug_sql) {
@@ -318,6 +319,16 @@
print $App::DEBUG_FILE "\n";
}
+ # The MySQL "insert ... on duplicate key update ..." statement
returns 2 rows affected
+ # when the insert gets a collision and causes an update. So we
have to make this
+ # adjustment. I don't know if it affects the "replace ..."
statement in a similar way,
+ # but I figure this can't hurt.
+ if ($options->{update} || $options->{replace}) {
+ if ($retval > $nrows_this_insert) {
+ $retval = $nrows_this_insert;
+ }
+ }
+
$nrows += $retval;
$rownum += $maxrows;
}
Modified: p5ee/trunk/App-Repository/t/DBI-insert.t
==============================================================================
--- p5ee/trunk/App-Repository/t/DBI-insert.t (original)
+++ p5ee/trunk/App-Repository/t/DBI-insert.t Mon Aug 20 08:36:37 2007
@@ -243,13 +243,13 @@
$nrows = $db->insert_rows("test_person",
["age","first_name","gender","state"], $new_rows);
is($nrows, 7, "insert_rows(): 7 rows, bulk insert");
$nrows = $db->insert_rows("test_person",
["person_id","age","first_name","gender","state"], $dup_rows, { replace => 1 });
-is($nrows, 14, "insert_rows(): 7 rows (14 affected), bulk replace");
+is($nrows, 7, "insert_rows(): 7 rows, bulk replace");
$nrows = $db->insert_rows("test_person", ["person_id",
"age","first_name","gender","state"], $dup_rows, { update => 1 });
-is($nrows, 14, "insert_rows(): 7 rows (14 affected), bulk insert/update");
+is($nrows, 7, "insert_rows(): 7 rows, bulk insert/update");
$nrows = $db->insert_rows("test_person",
["person_id","age","first_name","gender","state"], $dup_rows, { replace => 1,
maxrows => 4 });
-is($nrows, 14, "insert_rows(): 7 rows (14 affected), bulk replace (4 at a
time)");
+is($nrows, 7, "insert_rows(): 7 rows, bulk replace (4 at a time)");
$nrows = $db->insert_rows("test_person", ["person_id",
"age","first_name","gender","state"], $dup_rows, { update => 1, maxrows => 4 });
-is($nrows, 14, "insert_rows(): 7 rows (14 affected), bulk insert/update (4 at
a time)");
+is($nrows, 7, "insert_rows(): 7 rows, bulk insert/update (4 at a time)");
}