From 2b63ab6878e9ebf46a13054bf175c87aa1f9fe6e Mon Sep 17 00:00:00 2001 From: JT Smith Date: Mon, 5 Jul 2004 03:42:46 +0000 Subject: [PATCH] adding transactional support and preapred statements to WebGUI::SQL --- docs/changelog/6.x.x.txt | 7 +- lib/WebGUI/SQL.pm | 169 ++++++++++++++++++++++++++++++++------- 2 files changed, 145 insertions(+), 31 deletions(-) diff --git a/docs/changelog/6.x.x.txt b/docs/changelog/6.x.x.txt index 507b7769f..0e802fc4f 100644 --- a/docs/changelog/6.x.x.txt +++ b/docs/changelog/6.x.x.txt @@ -29,8 +29,8 @@ WSClient. - Adding form param WSClient_skipCache when posting to WSClient wobject allows us to ignore even good soap return caches (mostly for testing use) - - Moved to a compiled internationalization and help system. At a cost of 3 - megabytes of RAM, it provides a boost in performance of over 35%. More + - Moved to a compiled internationalization and help system. At a cost of 400 + kilobytes of RAM, it provides a boost in performance of over 35%. More importantly though, it cuts the number of database queries in half on an average page, which leads to much greater scalability. See docs/migration.txt for API changes. @@ -47,6 +47,9 @@ type in the same form. - Sped up the page editing page by 50% by rearranging the javascript on the page. + - Added prepared statement handlers to WebGUI::SQL. + - Added transaction handlers to WebGUI::SQL. + - Added additional debugging to WebGUI::SQL. 6.0.3 diff --git a/lib/WebGUI/SQL.pm b/lib/WebGUI/SQL.pm index 094246c3c..475db3f85 100644 --- a/lib/WebGUI/SQL.pm +++ b/lib/WebGUI/SQL.pm @@ -36,7 +36,10 @@ Package for interfacing with SQL databases. This package implements Perl DBI fun =head1 SYNOPSIS use WebGUI::SQL; - $sth = WebGUI::SQL->new($sql); + + my $sth = WebGUI::SQL->prepare($sql); + $sth->execute(@values); + $sth = WebGUI::SQL->read($sql); $sth = WebGUI::SQL->unconditionalRead($sql); @arr = $sth->array; @@ -46,6 +49,12 @@ Package for interfacing with SQL databases. This package implements Perl DBI fun $num = $sth->rows; $sth->finish; + WebGUI::SQL->write($sql); + + WebGUI::SQL->beginTransaction; + WebGUI::SQL->commit; + WebGUI::SQL->rollback; + @arr = WebGUI::SQL->buildArray($sql); $arrayRef = WebGUI::SQL->buildArrayRef($sql); %hash = WebGUI::SQL->buildHash($sql); @@ -56,8 +65,6 @@ Package for interfacing with SQL databases. This package implements Perl DBI fun $hashRef = WebGUI::SQL->quickHashRef($sql); $text = WebGUI::SQL->quickTab($sql); - WebGUI::SQL->write($sql); - $id = getNextId("wobjectId"); $string = quote($string); @@ -81,6 +88,29 @@ sub array { } +#------------------------------------------------------------------- + +=head2 beginTransaction ( [ dbh ]) + +Starts a transaction sequence. To be used with commit and rollback. Any writes after this point will not be applied to the database until commit is called. + +=over + +=item dbh + +A database handler. Defaults to the WebGUI default database handler. + +=back + +=cut + +sub beginTransaction { + my $class = shift; + my $dbh = shift; + $dbh->begin_work; +} + + #------------------------------------------------------------------- =head2 buildArray ( sql [, dbh ] ) @@ -200,6 +230,29 @@ sub buildHashRef { } +#------------------------------------------------------------------- + +=head2 commit ( [ dbh ]) + +Ends a transaction sequence. To be used with beginTransaction. Applies all of the writes since beginTransaction to the database. + +=over + +=item dbh + +A database handler. Defaults to the WebGUI default database handler. + +=back + +=cut + +sub commit { + my $class = shift; + my $dbh = shift; + $dbh->commit; +} + + #------------------------------------------------------------------- =head2 errorCode { @@ -226,11 +279,33 @@ sub errorMessage { } +#------------------------------------------------------------------- + +=head2 execute ( values ) + +Executes a prepared SQL statement. + +=over + +=item values + +A list of values to be used in the placeholders defined in the prepared statement. + +=back + +=cut + +sub execute { + my $self = shift; + $self->{_sth}->execute(@_) or WebGUI::ErrorHandler::fatalError("Couldn't execute prepared statement: ". DBI->errstr); +} + + #------------------------------------------------------------------- =head2 finish ( ) -Ends a query after calling the "new" or "read" methods. +Ends a query after calling the "read" method. =cut @@ -354,37 +429,37 @@ sub hashRef { #------------------------------------------------------------------- -=head2 new ( sql [, dbh ] ) +=head2 prepare ( sql [, dbh ] ) { -Constructor. Returns a statement handler. +Returns a statement handler. To be used in creating prepared statements. Use with the execute method. =over =item sql -An SQL query. +An SQL statement. Can use the "?" placeholder for maximum performance on multiple statements with the execute method. =item dbh -By default this method uses the WebGUI database handler. However, you may choose to pass in your own if you wish. +A database handler. Defaults to the WebGUI default database handler. =back =cut -sub new { - my $class = shift; - my $sql = shift; - my $dbh = shift || $WebGUI::Session::session{dbh}; +sub prepare { + my $class = shift; + my $sql = shift; + my $dbh = shift || $WebGUI::Session::session{dbh}; if ($WebGUI::Session::session{setting}{showDebug}) { push(@{$WebGUI::Session::session{SQLquery}},$sql); } my $sth = $dbh->prepare($sql) or WebGUI::ErrorHandler::fatalError("Couldn't prepare statement: ".$sql." : ". DBI->errstr); - $sth->execute or WebGUI::ErrorHandler::fatalError("Couldn't execute statement: ".$sql." : ". DBI->errstr); bless ({_sth => $sth}, $class); } + #------------------------------------------------------------------- =head2 quickArray ( sql [, dbh ] ) @@ -407,7 +482,7 @@ By default this method uses the WebGUI database handler. However, you may choose sub quickArray { my ($sth, @data); - $sth = WebGUI::SQL->new($_[1],$_[2]); + $sth = WebGUI::SQL->read($_[1],$_[2]); @data = $sth->array; $sth->finish; return @data; @@ -436,7 +511,7 @@ By default this method uses the WebGUI database handler. However, you may choose sub quickCSV { my ($sth, $output, @data); - $sth = WebGUI::SQL->new($_[1],$_[2]); + $sth = WebGUI::SQL->read($_[1],$_[2]); $output = join(",",$sth->getColumnNames)."\n"; while (@data = $sth->array) { makeArrayCommaSafe(\@data); @@ -469,7 +544,7 @@ By default this method uses the WebGUI database handler. However, you may choose sub quickHash { my ($sth, $data); - $sth = WebGUI::SQL->new($_[1],$_[2]); + $sth = WebGUI::SQL->read($_[1],$_[2]); $data = $sth->hashRef; $sth->finish; if (defined $data) { @@ -503,7 +578,7 @@ sub quickHashRef { my $self = shift; my $sql = shift; my $dbh = shift; - my $sth = WebGUI::SQL->new($sql,$dbh); + my $sth = WebGUI::SQL->read($sql,$dbh); my $data = $sth->hashRef; $sth->finish; if (defined $data) { @@ -535,7 +610,7 @@ By default this method uses the WebGUI database handler. However, you may choose sub quickTab { my ($sth, $output, @data); - $sth = WebGUI::SQL->new($_[1],$_[2]); + $sth = WebGUI::SQL->read($_[1],$_[2]); $output = join("\t",$sth->getColumnNames)."\n"; while (@data = $sth->array) { makeArrayTabSafe(\@data); @@ -573,7 +648,7 @@ sub quote { =head2 read ( sql [, dbh ] ) -An alias of the "new" method. Returns a statement handler. +Returns a statement handler. This is a utility method that runs both a prepare and execute all in one. =over @@ -590,7 +665,35 @@ By default this method uses the WebGUI database handler. However, you may choose =cut sub read { - return WebGUI::SQL->new($_[1],$_[2],$_[3]); + my $class = shift; + my $sql = shift; + my $dbh = shift; + my $sth = WebGUI::SQL->prepare($sql, $dbh); + $sth->execute; + return $sth; +} + + +#------------------------------------------------------------------- + +=head2 rollback ( [ dbh ]) + +Ends a transaction sequence. To be used with beginTransaction. Cancels all of the writes since beginTransaction. + +=over + +=item dbh + +A database handler. Defaults to the WebGUI default database handler. + +=back + +=cut + +sub rollback { + my $class = shift; + my $dbh = shift; + $dbh->rollback; } @@ -675,12 +778,16 @@ By default this method uses the WebGUI database handler. However, you may choose =cut sub unconditionalRead { - my ($sth,$dbh); - $dbh = $_[2] || $WebGUI::Session::session{dbh}; - $sth = $dbh->prepare($_[1]) or WebGUI::ErrorHandler::warn("Unconditional read failed: ".$_[1]." : ".DBI->errstr); + my $class = shift; + my $sql = shift; + my $dbh = shift || $WebGUI::Session::session{dbh}; + if ($WebGUI::Session::session{setting}{showDebug}) { + push(@{$WebGUI::Session::session{SQLquery}},$sql); + } + my $sth = $dbh->prepare($sql) or WebGUI::ErrorHandler::warn("Unconditional read failed: ".$sql." : ".DBI->errstr); if ($sth) { - $sth->execute or WebGUI::ErrorHandler::warn("Unconditional read failed: ".$_[1]." : ".DBI->errstr); - bless ({_sth => $sth}, $_[0]); + $sth->execute or WebGUI::ErrorHandler::warn("Unconditional read failed: ".$sql." : ".DBI->errstr); + bless ({_sth => $sth}, $class); } } @@ -689,7 +796,7 @@ sub unconditionalRead { =head2 write ( sql [, dbh ] ) -A method specifically designed for writing to the database in an efficient manner. Writing can be accomplished using the "new" method, but it is not as efficient. +A method specifically designed for writing to the database in an efficient manner. =over @@ -706,9 +813,13 @@ By default this method uses the WebGUI database handler. However, you may choose =cut sub write { - my ($dbh); - $dbh = $_[2] || $WebGUI::Session::session{dbh}; - $dbh->do($_[1]) or WebGUI::ErrorHandler::fatalError("Couldn't prepare statement: ".$_[1]." : ". DBI->errstr); + my $class = shift; + my $sql = shift; + my $dbh = shift || $WebGUI::Session::session{dbh}; + if ($WebGUI::Session::session{setting}{showDebug}) { + push(@{$WebGUI::Session::session{SQLquery}},$sql); + } + $dbh->do($sql) or WebGUI::ErrorHandler::fatalError("Couldn't write to the database: ".$sql." : ". DBI->errstr); }