Add SQLTransaction to perform easy, efficient combining of multiple

statements into a single transaction.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@19775 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2004-07-26 08:56:26 +00:00
parent 058155c245
commit 69be0270db
3 changed files with 176 additions and 2 deletions

View file

@ -1,4 +1,11 @@
Thy Jul 15 09:40:00 2004 Richard Frith-Macdonald <rfm@gnu.org>
Mon Jul 26 09:50:00 2004 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClient.h: Add -transaction method and SQLTransaction class
* SQLClient.m: Implement -transaction method and SQLTransaction class
to provide a simple convenient mechanism for executing a sequence
of statements as a single transaction.
Thu Jul 15 09:40:00 2004 Richard Frith-Macdonald <rfm@gnu.org>
* WebServer.m: ([_didRead:]) more informative logging upon reading
an unexpected end-of-file

View file

@ -167,6 +167,7 @@
@class NSDate;
@class NSRecursiveLock;
@class NSString;
@class SQLTransaction;
/**
* An enhanced array to represent a record returned from a query.
@ -351,7 +352,7 @@ extern NSString *SQLUniqueException;
/**
* Perform arbitrary operation <em>which does not return any value.</em><br />
* This arguments to this method are a nil terminated list which are
* concatenated in the manner of the * -prepare:args: method.<br />
* concatenated in the manner of the -query:,... method.<br />
* Any string arguments are assumed to have been quoted appropriately
* already, but non-string arguments are automatically quoted using the
* -quote: method.
@ -772,6 +773,12 @@ extern NSString *SQLUniqueException;
* returned by the query to an array containing the fields.
*/
- (void) singletons: (NSMutableArray*)records;
/**
* Creates and returns an autoreleased SQLTransaction instance which will
* use the receiver as the database connection to perform transactions.
*/
- (SQLTransaction*) transaction;
@end
@ -835,5 +842,54 @@ extern NSString *SQLUniqueException;
- (void) setDurationLogging: (NSTimeInterval)threshold;
@end
/**
* The SQLTransaction transaction class provides a convenient mechanism
* for grouping together a series of SQL statements to be executed as a
* single transaction. It avoids the need for handling begin/commit,
* and shouldbe as efficient as reasonably possible.<br />
* You obtain an instance by calling [SQLClient-transaction], add SQL
* statements to it using the -add:,... and/or -add:with: methods, and
* then use the -execute method to perform all the statements as a
* single operation.<br />
* Any exception is caught and re-raised in the -execute method after any
* tidying up to leave the database in a consistent state.
*/
@interface SQLTransaction : NSObject
{
SQLClient *_db;
NSMutableArray *_info;
unsigned _count;
}
/**
* Adds an SQL statement to the transaction. This is similar to
* [SQLClient-execute:,...] but does not cause any database operation
* until -execute is called, so it will not raise a database exception.
*/
- (void) add: (NSString*)stmt,...;
/**
* Adds an SQL statement to the transaction. This is similar to
* [SQLClient-execute:with:] but does not cause any database operation
* until -execute is called, so it will not raise a database exception.
*/
- (void) add: (NSString*)stmt with: (NSDictionary*)values;
/**
* Performs any statements added to the transaction as a single operation.
* If any problem occurs, an NSException is raised, but the database connection
* is left in a consistent state and a partially completed operation is
* rolled back.
*/
- (void) execute;
/**
* Resets the transaction, removing all previously added statements.
* This allows the transaction object to be re-used for multiple
* transactions.
*/
- (void) reset;
@end
#endif

View file

@ -47,6 +47,10 @@
#include "SQLClient.h"
typedef struct {
@defs(SQLTransaction);
} *TDefs;
@implementation SQLRecord
+ (id) allocWithZone: (NSZone*)aZone
{
@ -1497,5 +1501,112 @@ static unsigned int maxConnections = 8;
}
}
- (SQLTransaction*) transaction
{
TDefs transaction;
transaction = (TDefs)NSAllocateObject([SQLTransaction class], 0,
NSDefaultMallocZone());
transaction->_db = RETAIN(self);
transaction->_info = [NSMutableArray new];
return AUTORELEASE((SQLTransaction*)transaction);
}
@end
@implementation SQLTransaction
- (void) dealloc
{
DESTROY(_db);
DESTROY(_info);
[super dealloc];
}
- (void) _addInfo: (NSArray*)info
{
if (_count == 0)
{
NSMutableString *ms = [[info objectAtIndex: 0] mutableCopy];
[_info addObjectsFromArray: info];
[_info replaceObjectAtIndex: 0 withObject: ms];
RELEASE(ms);
}
else
{
NSMutableString *ms = [_info objectAtIndex: 0];
unsigned c = [info count];
unsigned i = 1;
[ms appendString: @";"];
[ms appendString: [info objectAtIndex: 0]];
while (i < c)
{
[_info addObject: [info objectAtIndex: i++]];
}
}
_count++;
}
- (void) add: (NSString*)stmt,...
{
va_list ap;
va_start (ap, stmt);
[self _addInfo: [_db _prepare: stmt args: ap]];
va_end (ap);
}
- (void) add: (NSString*)stmt with: (NSDictionary*)values
{
[self _addInfo: [_db _substitute: stmt with: values]];
}
- (void) execute
{
if (_count > 0)
{
BOOL transaction = NO;
NS_DURING
{
if (_count > 1)
{
[_db begin];
transaction = YES;
}
[_db simpleExecute: _info];
if (transaction == YES)
{
transaction = NO;
[_db commit];
}
}
NS_HANDLER
{
if (transaction == YES)
{
NS_DURING
{
[_db rollback];
}
NS_HANDLER
{
NSLog(@"Exception rolling back transaction: %@",
localException);
}
NS_ENDHANDLER
}
[localException raise];
}
NS_ENDHANDLER
}
}
- (void) reset
{
[_info removeAllObjects];
_count = 0;
}
@end