convenience methods

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@38249 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2014-12-11 17:26:32 +00:00
parent d985eb2650
commit 35eb805b78
6 changed files with 420 additions and 80 deletions

View file

@ -1,3 +1,11 @@
2014-12-11 Richard Frith-Macdonald <rfm@gnu.org>
* Postgres.m: Fix minor thread safety issue.
* SQLClient.h:
* SQLClient.m:
* SQLClientPool.m:
Convenience methods to let a pool act as a client for any one-off op.
2014-11-19 Richard Frith-Macdonald <rfm@gnu.org>
* GNUmakefile: bump version to 1.8.2 for bugfix release.

View file

@ -1032,8 +1032,20 @@ static unsigned int trim(char *str)
#ifdef HAVE_PQESCAPESTRINGCONN
int err;
[self connect];
l = PQescapeStringConn(connection, (char*)(to + 1), [d bytes], l, &err);
[lock lock];
NS_DURING
{
[self connect];
l = PQescapeStringConn(connection, (char*)(to + 1), [d bytes], l, &err);
}
NS_HANDLER
{
[lock unlock];
NSZoneFree(NSDefaultMallocZone(), to);
[localException raise];
}
NS_ENDHANDLER
[lock unlock];
#else
l = PQescapeString(to + 1, [d bytes], l);
#endif

View file

@ -1186,6 +1186,24 @@ SQLCLIENT_PRIVATE
*/
@interface SQLClient (Convenience)
/**
* Convenience method to deal with the results of a query converting the
* normal array of records into an array of record columns. Each column
* in the array is an array containing all the values from that column.
*/
+ (NSMutableArray*) columns: (NSMutableArray*)records;
/**
* Convenience method to deal with the results of a query where each
* record contains a single field ... it converts the array of records
* returned by the query to an array containing the fields.<br />
* NB. This does not check that the contents of the records array are
* actually instances of [SQLRecord], so you must ensure you don't
* call it more than once on the same array (something that may happen
* if you retrieve the array using a cache based query).
*/
+ (void) singletons: (NSMutableArray*)records;
/**
* Returns a transaction object configured to handle batching and
* execute part of a batch of statements if execution of the whole
@ -1196,10 +1214,7 @@ SQLCLIENT_PRIVATE
*/
- (SQLTransaction*) batch: (BOOL)stopOnFailure;
/**
* Convenience method to deal with the results of a query converting the
* normal array of records into an array of record columns. Each column
* in the array is an array containing all the values from that column.
/** The same as the [SQLClient+columns:] method.
*/
- (NSMutableArray*) columns: (NSMutableArray*)records;
@ -1218,14 +1233,7 @@ SQLCLIENT_PRIVATE
*/
- (NSString*) queryString: (NSString*)stmt,...;
/**
* Convenience method to deal with the results of a query where each
* record contains a single field ... it converts the array of records
* returned by the query to an array containing the fields.<br />
* NB. This does not check that the contents of the records array are
* actually instances of [SQLRecord], so you must ensure you don't
* call it more than once on the same array (something that may happen
* if you retrieve the array using a cache based query).
/** The same as the [SQLClient+singletons:] method.
*/
- (void) singletons: (NSMutableArray*)records;
@ -1531,6 +1539,47 @@ SQLCLIENT_PRIVATE
@end
/** This category lists the convenience methods provided by a pool instance
* for proxying messages to a one-off client instance in the pool.<br />
* The behavior of each method is, of course, as documentf for instances
* of the [SQLClient] class.
*/
@interface SQLClientPool (Convenience)
- (NSString*) buildQuery: (NSString*)stmt,...;
- (NSString*) buildQuery: (NSString*)stmt with: (NSDictionary*)values;
- (NSMutableArray*) cache: (int)seconds
query: (NSString*)stmt,...;
- (NSMutableArray*) cache: (int)seconds
query: (NSString*)stmt
with: (NSDictionary*)values;
- (NSMutableArray*) cache: (int)seconds simpleQuery: (NSString*)stmt;
- (NSMutableArray*) cache: (int)seconds
simpleQuery: (NSString*)stmt
recordType: (id)rtype
listType: (id)ltype;
- (NSMutableArray*) columns: (NSMutableArray*)records;
- (NSInteger) execute: (NSString*)stmt,...;
- (NSInteger) execute: (NSString*)stmt with: (NSDictionary*)values;
- (NSMutableArray*) query: (NSString*)stmt,...;
- (NSMutableArray*) query: (NSString*)stmt with: (NSDictionary*)values;
- (SQLRecord*) queryRecord: (NSString*)stmt,...;
- (NSString*) queryString: (NSString*)stmt,...;
- (NSString*) quote: (id)obj;
- (NSString*) quotef: (NSString*)fmt, ...;
- (NSString*) quoteBigInteger: (int64_t)i;
- (NSString*) quoteCString: (const char *)s;
- (NSString*) quoteChar: (char)c;
- (NSString*) quoteFloat: (float)f;
- (NSString*) quoteInteger: (int)i;
- (NSString*) quoteString: (NSString *)s;
- (NSInteger) simpleExecute: (NSArray*)info;
- (void) singletons: (NSMutableArray*)records;
- (NSMutableArray*) simpleQuery: (NSString*)stmt;
- (NSMutableArray*) simpleQuery: (NSString*)stmt
recordType: (id)rtype
listType: (id)ltype;
@end
/**
* The SQLTransaction transaction class provides a convenient mechanism
* for grouping together a series of SQL statements to be executed as a

View file

@ -2539,21 +2539,7 @@ static int poolConnections = 0;
@implementation SQLClient(Convenience)
- (SQLTransaction*) batch: (BOOL)stopOnFailure
{
SQLTransaction *transaction;
transaction = (SQLTransaction*)NSAllocateObject([SQLTransaction class], 0,
NSDefaultMallocZone());
transaction->_db = [self retain];
transaction->_info = [NSMutableArray new];
transaction->_batch = YES;
transaction->_stop = stopOnFailure;
return [(SQLTransaction*)transaction autorelease];
}
- (NSMutableArray*) columns: (NSMutableArray*)records
+ (NSMutableArray*) columns: (NSMutableArray*)records
{
SQLRecord *r = [records lastObject];
unsigned rowCount = [records count];
@ -2590,6 +2576,36 @@ static int poolConnections = 0;
return m;
}
+ (void) singletons: (NSMutableArray*)records
{
unsigned c = [records count];
while (c-- > 0)
{
[records replaceObjectAtIndex: c
withObject: [[records objectAtIndex: c] lastObject]];
}
}
- (SQLTransaction*) batch: (BOOL)stopOnFailure
{
SQLTransaction *transaction;
transaction = (SQLTransaction*)NSAllocateObject([SQLTransaction class], 0,
NSDefaultMallocZone());
transaction->_db = [self retain];
transaction->_info = [NSMutableArray new];
transaction->_batch = YES;
transaction->_stop = stopOnFailure;
return [(SQLTransaction*)transaction autorelease];
}
- (NSMutableArray*) columns: (NSMutableArray*)records
{
return [SQLClient columns: records];
}
- (SQLRecord*) queryRecord: (NSString*)stmt, ...
{
va_list ap;
@ -2649,13 +2665,7 @@ static int poolConnections = 0;
- (void) singletons: (NSMutableArray*)records
{
unsigned c = [records count];
while (c-- > 0)
{
[records replaceObjectAtIndex: c
withObject: [[records objectAtIndex: c] lastObject]];
}
[SQLClient singletons: records];
}
- (SQLTransaction*) transaction

View file

@ -542,60 +542,320 @@
@end
@implementation SQLClientPool (Proxying)
@interface SQLClient (Private)
- (NSMutableArray*) _prepare: (NSString*)stmt args: (va_list)args;
@end
static BOOL
selIsBad(SEL aSelector)
@implementation SQLClientPool (ConvenienceMethods)
- (NSString*) buildQuery: (NSString*)stmt, ...
{
const char *n = sel_getName(aSelector);
SQLClient *db = [self provideClient];
NSString *sql = nil;
va_list ap;
if (strncmp(n, "set", 3) == 0)
{
return YES;
}
if (strncmp(n, "backend", 7) == 0)
{
return YES;
}
if (strcmp(n, "begin") == 0)
{
return YES;
}
return NO;
}
- (void) forwardInvocation: (NSInvocation*)anInvocation
{
SQLClient *db;
db = [self provideClient];
[anInvocation invokeWithTarget: db];
/*
* First check validity and concatenate parts of the query.
*/
va_start (ap, stmt);
sql = [[db _prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap);
[self swallowClient: db];
return sql;
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
- (NSString*) buildQuery: (NSString*)stmt with: (NSDictionary*)values
{
NSMethodSignature *methodSig;
SQLClient *db = [self provideClient];
NSString *result = [db buildQuery: stmt with: values];
methodSig = [super methodSignatureForSelector: aSelector];
if (nil == methodSig && 0 != c && NO == selIsBad(aSelector))
{
methodSig = [c[0] methodSignatureForSelector: aSelector];
}
return methodSig;
}
- (BOOL) respondsToSelector: (SEL)aSelector
{
BOOL result;
result = [super respondsToSelector: aSelector];
if (NO == result && 0 != c && NO == selIsBad(aSelector))
{
result = [c[0] respondsToSelector: aSelector];
}
[self swallowClient: db];
return result;
}
- (NSMutableArray*) cache: (int)seconds
query: (NSString*)stmt,...
{
SQLClient *db = [self provideClient];
NSMutableArray *result;
va_list ap;
va_start (ap, stmt);
stmt = [[db _prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap);
result = [db cache: seconds simpleQuery: stmt];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) cache: (int)seconds
query: (NSString*)stmt
with: (NSDictionary*)values
{
SQLClient *db = [self provideClient];
NSMutableArray *result = [db cache: seconds query: stmt with: values];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) cache: (int)seconds simpleQuery: (NSString*)stmt;
{
SQLClient *db = [self provideClient];
NSMutableArray *result = [db cache: seconds simpleQuery: stmt];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) cache: (int)seconds
simpleQuery: (NSString*)stmt
recordType: (id)rtype
listType: (id)ltype
{
SQLClient *db = [self provideClient];
NSMutableArray *result;
result = [db cache: seconds
simpleQuery: stmt
recordType: rtype
listType: ltype];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) columns: (NSMutableArray*)records
{
return [SQLClient columns: records];
}
- (NSInteger) execute: (NSString*)stmt, ...
{
SQLClient *db = [self provideClient];
NSInteger result;
NSArray *info;
va_list ap;
va_start (ap, stmt);
info = [db _prepare: stmt args: ap];
va_end (ap);
result = [db simpleExecute: info];
[self swallowClient: db];
return result;
}
- (NSInteger) execute: (NSString*)stmt with: (NSDictionary*)values
{
SQLClient *db = [self provideClient];
NSInteger result = [db execute: stmt with: values];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) query: (NSString*)stmt, ...
{
SQLClient *db = [self provideClient];
NSMutableArray *result = nil;
va_list ap;
/*
* First check validity and concatenate parts of the query.
*/
va_start (ap, stmt);
stmt = [[db _prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap);
result = [db simpleQuery: stmt];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) query: (NSString*)stmt with: (NSDictionary*)values
{
SQLClient *db = [self provideClient];
NSMutableArray *result = [db query: stmt with: values];
[self swallowClient: db];
return result;
}
- (SQLRecord*) queryRecord: (NSString*)stmt, ...
{
SQLClient *db = [self provideClient];
NSArray *result = nil;
SQLRecord *record;
va_list ap;
va_start (ap, stmt);
stmt = [[db _prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap);
result = [db simpleQuery: stmt];
[self swallowClient: db];
if ([result count] > 1)
{
[NSException raise: NSInvalidArgumentException
format: @"Query returns more than one record -\n%@\n", stmt];
}
record = [result lastObject];
if (record == nil)
{
[NSException raise: SQLEmptyException
format: @"Query returns no data -\n%@\n", stmt];
}
return record;
}
- (NSString*) queryString: (NSString*)stmt, ...
{
SQLClient *db = [self provideClient];
NSArray *result = nil;
SQLRecord *record;
va_list ap;
va_start (ap, stmt);
stmt = [[db _prepare: stmt args: ap] objectAtIndex: 0];
va_end (ap);
result = [db simpleQuery: stmt];
[self swallowClient: db];
if ([result count] > 1)
{
[NSException raise: NSInvalidArgumentException
format: @"Query returns more than one record -\n%@\n", stmt];
}
record = [result lastObject];
if (record == nil)
{
[NSException raise: SQLEmptyException
format: @"Query returns no data -\n%@\n", stmt];
}
if ([record count] > 1)
{
[NSException raise: NSInvalidArgumentException
format: @"Query returns multiple fields -\n%@\n", stmt];
}
return [[record lastObject] description];
}
- (NSString*) quote: (id)obj
{
SQLClient *db = [self provideClient];
NSString *result = [db quote: obj];
[self swallowClient: db];
return result;
}
- (NSString*) quotef: (NSString*)fmt, ...
{
SQLClient *db = [self provideClient];
va_list ap;
NSString *str;
NSString *quoted;
va_start(ap, fmt);
str = [[NSString allocWithZone: NSDefaultMallocZone()]
initWithFormat: fmt arguments: ap];
va_end(ap);
quoted = [self quoteString: str];
[self swallowClient: db];
[str release];
return quoted;
}
- (NSString*) quoteBigInteger: (int64_t)i
{
SQLClient *db = [self provideClient];
NSString *result = [db quoteBigInteger: i];
[self swallowClient: db];
return result;
}
- (NSString*) quoteCString: (const char *)s
{
SQLClient *db = [self provideClient];
NSString *result = [db quoteCString: s];
[self swallowClient: db];
return result;
}
- (NSString*) quoteChar: (char)chr
{
SQLClient *db = [self provideClient];
NSString *result = [db quoteChar: chr];
[self swallowClient: db];
return result;
}
- (NSString*) quoteFloat: (float)f
{
SQLClient *db = [self provideClient];
NSString *result = [db quoteFloat: f];
[self swallowClient: db];
return result;
}
- (NSString*) quoteInteger: (int)i
{
SQLClient *db = [self provideClient];
NSString *result = [db quoteInteger: i];
[self swallowClient: db];
return result;
}
- (NSString*) quoteString: (NSString *)s
{
SQLClient *db = [self provideClient];
NSString *result = [db quoteString: s];
[self swallowClient: db];
return result;
}
- (NSInteger) simpleExecute: (NSArray*)info
{
SQLClient *db = [self provideClient];
NSInteger result = [db simpleExecute: info];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) simpleQuery: (NSString*)stmt
{
SQLClient *db = [self provideClient];
NSMutableArray *result = [db simpleQuery: stmt];
[self swallowClient: db];
return result;
}
- (NSMutableArray*) simpleQuery: (NSString*)stmt
recordType: (id)rtype
listType: (id)ltype
{
SQLClient *db = [self provideClient];
NSMutableArray *result;
result = [db simpleQuery: stmt
recordType: rtype
listType: ltype];
[self swallowClient: db];
return result;
}
- (void) singletons: (NSMutableArray*)records
{
[SQLClient singletons: records];
}
@end

View file

@ -95,6 +95,7 @@ main()
#endif
db = [sp provideClient];
[sp swallowClient: db];
[sp queryString: @"SELECT CURRENT_TIMESTAMP", nil];
db = [sp provideClient];
l = [Logger new];