Threading/notification improvments

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@38447 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2015-04-01 11:32:49 +00:00
parent 2250d65fc0
commit bb8284b4fe
5 changed files with 75 additions and 18 deletions

View file

@ -1,11 +1,28 @@
2015-04-01 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClient.h:
* Postgres.m:
Fixup notification posting to be asynchronous using the default
notification queue for the thread so that the notifications do
not get delivered while the query/statement at which they were
detected is still in progress.
Add method to explicitly grab/release the client for the current
thread.
2015-03-11 Richard Frith-Macdonald <rfm@gnu.org> 2015-03-11 Richard Frith-Macdonald <rfm@gnu.org>
* SQLClientPool.m: Fixup for ewxposing prepare method
* SQLClientPool.m: Fixup for exposing prepare method
* SQLClient.h: * SQLClient.h:
* SQLClient.m: * SQLClient.m:
* Postgres.m: * Postgres.m:
* testPostgres.m: * testPostgres.m:
Add simple array support for char/varchar/text, integer/real, Add simple array support for char/varchar/text, integer/real,
timestamp, bool and bytea. timestamp, bool and bytea. When a query returns an array of
one of these types, the resulting object is an NSArray containing
the database array elements rather than an NSString containing the
string literal representation of the database array.
Also added a method to convert an NSArray to a string literal
representation of a database array.
2015-03-02 Richard Frith-Macdonald <rfm@gnu.org> 2015-03-02 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -35,6 +35,7 @@
#import <Foundation/NSFileHandle.h> #import <Foundation/NSFileHandle.h>
#import <Foundation/NSProcessInfo.h> #import <Foundation/NSProcessInfo.h>
#import <Foundation/NSNotification.h> #import <Foundation/NSNotification.h>
#import <Foundation/NSNotificationQueue.h>
#import <Foundation/NSUserDefaults.h> #import <Foundation/NSUserDefaults.h>
#import <Foundation/NSMapTable.h> #import <Foundation/NSMapTable.h>
#import <Foundation/NSLock.h> #import <Foundation/NSLock.h>
@ -279,8 +280,8 @@ connectQuote(NSString *str)
- (void) _checkNotifications - (void) _checkNotifications
{ {
static NSNotificationCenter *nc; NSNotificationQueue *nq = nil;
PGnotify *notify; PGnotify *notify;
while ((notify = PQnotifies(connection)) != 0) while ((notify = PQnotifies(connection)) != 0)
{ {
@ -328,11 +329,14 @@ connectQuote(NSString *str)
userInfo: (NSDictionary*)userInfo]; userInfo: (NSDictionary*)userInfo];
[name release]; [name release];
[userInfo release]; [userInfo release];
if (nil == nc)
if (nil == nq)
{ {
nc = [[NSNotificationCenter defaultCenter] retain]; nq = [NSNotificationQueue defaultQueue];
} }
[nc postNotification: n]; /* Post asynchronously
*/
[nq enqueueNotification: n postingStyle: NSPostASAP];
} }
NS_HANDLER NS_HANDLER
{ {
@ -523,9 +527,9 @@ static unsigned int trim(char *str)
} }
if ('\"' == *p) if ('\"' == *p)
{ {
*p++ = '\0'; *p = '\0';
} }
if (len == (p - start + 1)) if (len == (p - start))
{ {
v = [[NSString alloc] initWithUTF8String: start]; v = [[NSString alloc] initWithUTF8String: start];
} }
@ -562,6 +566,7 @@ static unsigned int trim(char *str)
freeWhenDone: YES]; freeWhenDone: YES];
} }
} }
*p++ = '\"';
} }
else else
{ {
@ -677,6 +682,7 @@ static unsigned int trim(char *str)
case 1002: // CHAR ARRAY case 1002: // CHAR ARRAY
case 1009: // TEXT ARRAY case 1009: // TEXT ARRAY
case 1015: // VARCHAR ARRAY case 1015: // VARCHAR ARRAY
case 1263: // CSTRING ARRAY
if ('{' == *p) if ('{' == *p)
{ {
NSMutableArray *a; NSMutableArray *a;
@ -1212,7 +1218,7 @@ static unsigned int trim(char *str)
else if ([o isKindOfClass: [NSDate class]]) else if ([o isKindOfClass: [NSDate class]])
{ {
[s appendString: [self quote: (NSString*)o]]; [s appendString: [self quote: (NSString*)o]];
[s appendString: @"::timestamp"]; [s appendString: @"::timestamp with time zone"];
} }
else if ([o isKindOfClass: [NSData class]]) else if ([o isKindOfClass: [NSData class]])
{ {

View file

@ -488,6 +488,13 @@ SQLCLIENT_PRIVATE
*/ */
- (void) begin; - (void) begin;
/** This grabs the receiver for use by the current thread.<br />
* If limit is nil or in the past, makes a single immediate attempt.<br />
* Returns NO if it fails to obtain a lock by the specified date.<br />
* Must be matched by an -unlock if it succeeds.
*/
- (BOOL) lockBeforeDate: (NSDate*)limit;
/** /**
* <p>Build an sql query string using the supplied arguments. * <p>Build an sql query string using the supplied arguments.
* </p> * </p>
@ -787,7 +794,12 @@ SQLCLIENT_PRIVATE
* YYYY-MM-DD hh:mm:ss.mmm ?ZZZZ<br /> * YYYY-MM-DD hh:mm:ss.mmm ?ZZZZ<br />
* NSData objects are not quoted ... they must not appear in queries, and * NSData objects are not quoted ... they must not appear in queries, and
* where used for insert/update operations, they need to be passed to the * where used for insert/update operations, they need to be passed to the
* -backendExecute: method unchanged. * -backendExecute: method unchanged.<br />
* NSArray and NSSet objects are quoted as sets containing the quoted
* elements from the array/set. If you want to use SQL arrays (and your
* database backend supports it) you must explicitly use the
* -quoteArray:toString:quotingString: to convert an NSArray to a literal
* database array representation.
*/ */
- (NSString*) quote: (id)obj; - (NSString*) quote: (id)obj;
@ -928,6 +940,10 @@ SQLCLIENT_PRIVATE
recordType: (id)rtype recordType: (id)rtype
listType: (id)ltype; listType: (id)ltype;
/** Releases a lock previously obtained using -lockbeforeDate:
*/
- (void) unlock;
/** /**
* Return the database user for this instance (or nil). * Return the database user for this instance (or nil).
*/ */
@ -1088,7 +1104,8 @@ SQLCLIENT_PRIVATE
* which don't support asynchronous notifications.<br /> * which don't support asynchronous notifications.<br />
* If a backend <em>does</em> support asynchronous notifications, * If a backend <em>does</em> support asynchronous notifications,
* it should do so by posting NSNotification instances to * it should do so by posting NSNotification instances to
* [NSNotificationCenter defaultCenter] using the SQLClient instance as * [NSNotificationQueue defaultQueue] with the posting style NSPostASAP
* (to post asynchronously) and using the SQLClient instance as
* the notification object and supplying any payload as a string using * the notification object and supplying any payload as a string using
* the 'Payload' key in the NSNotification userInfo dictionary. * the 'Payload' key in the NSNotification userInfo dictionary.
* The userInfo dictionary should also contain a boolean (NSNumber) value, * The userInfo dictionary should also contain a boolean (NSNumber) value,
@ -1182,11 +1199,14 @@ SQLCLIENT_PRIVATE
* as an action by this SQLClient instance.<br /> * as an action by this SQLClient instance.<br />
* If the 'Payload' value is not nil, then it is a string providing extra * If the 'Payload' value is not nil, then it is a string providing extra
* information about the notification.<br /> * information about the notification.<br />
* NB. At the point when the observer is notified about an event the * Notifications are posted asynchronously using the default notification
* database client object will be locked and may not be used to query * queue for the current thread, so they should be delivered to the
* or modify the database (typically a database query will already be * observer after the database statement in which they were detected
* in progress). The method handling the notification must therefore * has completed. However, delivery of the notification could still
* handle any database operations in a later timeout. * occur inside a transaction is the -begin and -commit statements
* are used. For this reason, observing code may want to use the
* -lockBeforeDate: -isInTransaction and -unlock methods to ensure
* that they don't interfere with ongoing transactions.
*/ */
- (void) addObserver: (id)anObserver - (void) addObserver: (id)anObserver
selector: (SEL)aSelector selector: (SEL)aSelector

View file

@ -1341,6 +1341,15 @@ static int poolConnections = 0;
return nil; return nil;
} }
- (BOOL) lockBeforeDate: (NSDate*)limit
{
if (nil == limit)
{
return [lock tryLock];
}
return [lock lockBeforeDate: limit];
}
- (SQLClient*) longestIdle: (SQLClient*)other - (SQLClient*) longestIdle: (SQLClient*)other
{ {
NSTimeInterval t0; NSTimeInterval t0;
@ -2015,6 +2024,11 @@ static int poolConnections = 0;
return result; return result;
} }
- (void) unlock
{
[lock unlock];
}
- (NSString*) user - (NSString*) user
{ {
return _user; return _user;

View file

@ -260,7 +260,7 @@ main()
@"extra2 varchar[]," @"extra2 varchar[],"
@"extra3 bytea[]," @"extra3 bytea[],"
@"extra4 boolean[]," @"extra4 boolean[],"
@"extra5 timestamp[]" @"extra5 timestamp with time zone[]"
@")", @")",
nil]; nil];