mirror of
https://github.com/gnustep/libs-sqlclient.git
synced 2025-04-20 12:50:59 +00:00
Compare commits
15 commits
sqlclient-
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
db1ff663f6 | ||
|
9f90bdc755 | ||
|
1ec70f9323 | ||
|
f84f1f0487 | ||
|
78a66c1a75 | ||
|
2c9070cfd0 | ||
|
936410c7e6 | ||
|
848c1fa4ac | ||
|
aa3262a521 | ||
|
527735d95a | ||
|
c307374590 | ||
|
68678b864e | ||
|
3e35662803 | ||
|
16d56c5395 | ||
|
218578aa95 |
5 changed files with 590 additions and 373 deletions
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
|||
2024-01-26 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Postgres.m: Fix error in parsing milliseconds in timestamp.
|
||||
|
||||
2023-11-23 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* SQLClient.h: New instance variables for timing lock waits.
|
||||
* SQLClient.m: Record duration of waits for locks.
|
||||
* SQLClientPool.m: Tell client when pool was locked before query.
|
||||
Changes so that, the time spent waiting to obtain a lock to get a
|
||||
connection from a pool or to be able to execute a query on a
|
||||
connection used by another thread is recorded. When query duration
|
||||
logging is performed, report lock delays of over a millisecond.
|
||||
If debug is on or if the query logging duration is zero, then any
|
||||
lock delay (no matter how small) is reported.
|
||||
|
||||
2023-08-16 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Postgres.m: Implement support for connect_timeoout= option to
|
||||
control how long we allow for a connection attempt to a host.
|
||||
|
||||
2023-01-13 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* GNUmakefile: bumped version to 1.9.0.
|
||||
|
|
80
Postgres.m
80
Postgres.m
|
@ -118,7 +118,7 @@ newDateFromBuffer(const char *b, int l)
|
|||
{
|
||||
NSCalendarDate *d;
|
||||
NSTimeZone *zone = nil;
|
||||
int milliseconds = 0;
|
||||
int microseconds = 0;
|
||||
int day;
|
||||
int month;
|
||||
int year;
|
||||
|
@ -190,14 +190,18 @@ newDateFromBuffer(const char *b, int l)
|
|||
if (i < l && '.' == b[i])
|
||||
{
|
||||
i++;
|
||||
if (i >= l || !isdigit(b[i])) return nil;
|
||||
milliseconds = b[i++] - '0';
|
||||
milliseconds *=- 10;
|
||||
if (i < l && isdigit(b[i]))
|
||||
milliseconds += b[i++] - '0';
|
||||
milliseconds *=- 10;
|
||||
if (i < l && isdigit(b[i]))
|
||||
milliseconds += b[i++] - '0';
|
||||
if (i >= l || !isdigit(b[i])) return nil;
|
||||
microseconds = b[i++] - '0';
|
||||
microseconds *= 10;
|
||||
if (i < l && isdigit(b[i])) microseconds += b[i++] - '0';
|
||||
microseconds *= 10;
|
||||
if (i < l && isdigit(b[i])) microseconds += b[i++] - '0';
|
||||
microseconds *= 10;
|
||||
if (i < l && isdigit(b[i])) microseconds += b[i++] - '0';
|
||||
microseconds *= 10;
|
||||
if (i < l && isdigit(b[i])) microseconds += b[i++] - '0';
|
||||
microseconds *= 10;
|
||||
if (i < l && isdigit(b[i])) microseconds += b[i++] - '0';
|
||||
while (i < l && isdigit(b[i]))
|
||||
i++;
|
||||
}
|
||||
|
@ -277,15 +281,23 @@ newDateFromBuffer(const char *b, int l)
|
|||
second: second
|
||||
timeZone: zone];
|
||||
|
||||
if (milliseconds > 0)
|
||||
/* Postgres support six digits precision, but the ObjC APIs tend
|
||||
* to use milliseconds. For now, truncate.
|
||||
*/
|
||||
if (microseconds > 0)
|
||||
{
|
||||
NSTimeInterval ti;
|
||||
int milliseconds = microseconds / 1000;
|
||||
|
||||
ti = milliseconds;
|
||||
ti /= 1000.0;
|
||||
ti += [d timeIntervalSinceReferenceDate];
|
||||
d = [d initWithTimeIntervalSinceReferenceDate: ti];
|
||||
[d setTimeZone: zone];
|
||||
if (milliseconds > 0)
|
||||
{
|
||||
NSTimeInterval ti;
|
||||
|
||||
ti = milliseconds;
|
||||
ti /= 1000.0;
|
||||
ti += [d timeIntervalSinceReferenceDate];
|
||||
d = [d initWithTimeIntervalSinceReferenceDate: ti];
|
||||
[d setTimeZone: zone];
|
||||
}
|
||||
}
|
||||
}
|
||||
[d setCalendarFormat: @"%Y-%m-%d %H:%M:%S %z"];
|
||||
|
@ -393,7 +405,8 @@ connectQuote(NSString *str)
|
|||
NSString *host = nil;
|
||||
NSString *port = nil;
|
||||
NSString *dbase = [self database];
|
||||
NSString *sslmode = [options objectForKey: @"sslmode"];
|
||||
NSString *sslmode;
|
||||
int timeout;
|
||||
NSString *str;
|
||||
NSRange r;
|
||||
NSRange pwRange = NSMakeRange(NSNotFound, 0);
|
||||
|
@ -457,6 +470,8 @@ connectQuote(NSString *str)
|
|||
[m appendString: @" application_name="];
|
||||
[m appendString: str];
|
||||
}
|
||||
|
||||
sslmode = [options objectForKey: @"sslmode"];
|
||||
if ([sslmode isEqual: @"require"])
|
||||
{
|
||||
str = connectQuote(@"require");
|
||||
|
@ -467,6 +482,12 @@ connectQuote(NSString *str)
|
|||
}
|
||||
}
|
||||
|
||||
timeout = [[options objectForKey: @"connect_timeout"] intValue];
|
||||
if (timeout > 0)
|
||||
{
|
||||
[m appendFormat: @" connect_timeout=%d", timeout];
|
||||
}
|
||||
|
||||
if ([self debugging] > 0)
|
||||
{
|
||||
[self debug: @"Connect to '%@' as %@ (%@)",
|
||||
|
@ -1293,8 +1314,24 @@ static inline unsigned int trim(char *str, unsigned len)
|
|||
|
||||
if (d > 1)
|
||||
{
|
||||
[self debug: @"%@ type:%d mod:%d size: %d\n",
|
||||
keys[j], ftype[j], fmod[j], size];
|
||||
#if 0
|
||||
/* For even more debug we can write some of the
|
||||
* data retrieved, but that may be a security
|
||||
* issue.
|
||||
*/
|
||||
if (0 == fformat[j] && size <= 100)
|
||||
{
|
||||
[self debug:
|
||||
@"%@ type:%d mod:%d size: %d %*.*s\n",
|
||||
keys[j], ftype[j], fmod[j], size,
|
||||
size, size, p];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
[self debug: @"%@ type:%d mod:%d size: %d\n",
|
||||
keys[j], ftype[j], fmod[j], size];
|
||||
}
|
||||
}
|
||||
/* Often many rows will contain the same data in
|
||||
* one or more columns, so we check to see if the
|
||||
|
@ -1834,7 +1871,8 @@ static inline unsigned int trim(char *str, unsigned len)
|
|||
type: ET_RDESC
|
||||
forMode: NSDefaultRunLoopMode
|
||||
all: YES];
|
||||
[self debug: @"Listen event on disconnected client, desc: %d", (int)data];
|
||||
[self debug: @"Listen event on disconnected client, desc: %d",
|
||||
(int)(intptr_t)data];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1846,7 +1884,7 @@ static inline unsigned int trim(char *str, unsigned len)
|
|||
strncpy(msg, PQerrorMessage(connection), sizeof(msg)-1);
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
if (PQstatus(connection) != CONNECTION_OK
|
||||
|| PQsocket(connection) != (int)data)
|
||||
|| PQsocket(connection) != (int)(intptr_t)data)
|
||||
{
|
||||
/* The connection has been lost, so we must disconnect,
|
||||
* which will stop us receiving events on the descriptor.
|
||||
|
|
|
@ -521,6 +521,8 @@ SQLCLIENT_PRIVATE
|
|||
NSTimeInterval _lastOperation;
|
||||
NSTimeInterval _lastConnect; /** Last successful connect */
|
||||
NSTimeInterval _lastStart; /** Last op start or connect */
|
||||
NSTimeInterval _waitLock; /** When we blocked for locking */
|
||||
NSTimeInterval _waitPool; /** When we blocked for pool access */
|
||||
NSTimeInterval _duration; /** Duration logging threshold */
|
||||
uint64_t _committed; /** Count of committed transactions */
|
||||
unsigned int _debugging; /** The current debugging level */
|
||||
|
@ -2254,7 +2256,8 @@ SQLCLIENT_PRIVATE
|
|||
/** Creates and returns a copy of aString as a literal,
|
||||
* whether or not aString is already a literal string.
|
||||
*/
|
||||
extern SQLLiteral * SQLClientCopyLiteral(NSString *aString);
|
||||
extern SQLLiteral * SQLClientCopyLiteral(NSString *aString)
|
||||
NS_RETURNS_RETAINED;
|
||||
|
||||
/** Function to test an object to see if it is considered to be a literal
|
||||
* string by SQLClient. Use this rather than trying to chewck the class
|
||||
|
@ -2275,7 +2278,8 @@ extern SQLLiteral * SQLClientMakeLiteral(NSString *aString);
|
|||
* from a UTF8 or ASCII C string whose length (not including any nul
|
||||
* terminator) is the specified count.
|
||||
*/
|
||||
extern SQLLiteral * SQLClientNewLiteral(const char *bytes, unsigned count);
|
||||
extern SQLLiteral * SQLClientNewLiteral(const char *bytes, unsigned count)
|
||||
NS_RETURNS_RETAINED;
|
||||
|
||||
/** Creates and returns an autoreleased proxy to aString, recording the
|
||||
* fact that the programmer considers the string to be a valid literal
|
||||
|
|
338
SQLClient.m
338
SQLClient.m
|
@ -326,7 +326,8 @@ SQLClientMakeLiteral(NSString *aString)
|
|||
if (c != LitStringClass && c != TinyStringClass && c != SQLStringClass)
|
||||
{
|
||||
/* The SQLString class uses utf8 and can be very inefficient
|
||||
* if it's too long. For long strings we use a proxy instead.
|
||||
* if it's too long. For long strings we use a proxy to a
|
||||
* copy of the original string.
|
||||
*/
|
||||
if ([aString length] > 64)
|
||||
{
|
||||
|
@ -1195,6 +1196,15 @@ static NSArray *rollbackStatement = nil;
|
|||
|
||||
@interface SQLClient (Private)
|
||||
|
||||
/* Takes the timestamp of the end of the operation and checks how long
|
||||
* the operation took, returning a string containing a message to be
|
||||
* logged if the threshold was exceeded.
|
||||
* The message contains the total duration with a separate breakdown
|
||||
* of connection and pool lock wait times if they are a millisecond
|
||||
* or longer.
|
||||
*/
|
||||
- (NSMutableString*) _checkDuration: (NSTimeInterval)end;
|
||||
|
||||
/**
|
||||
* Internal method to handle configuration using the notification object.
|
||||
* This object may be either a configuration front end or a user defaults
|
||||
|
@ -1643,14 +1653,6 @@ static int poolConnections = 0;
|
|||
{
|
||||
NSNotificationCenter *nc;
|
||||
|
||||
[clientsLock lock];
|
||||
NSHashRemove(clientsHash, (void*)self);
|
||||
if (_name != nil
|
||||
&& (SQLClient*)NSMapGet(clientsMap, (void*)_name) == self)
|
||||
{
|
||||
NSMapRemove(clientsMap, (void*)_name);
|
||||
}
|
||||
[clientsLock unlock];
|
||||
nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver: self];
|
||||
if (YES == connected) [self disconnect];
|
||||
|
@ -2576,14 +2578,21 @@ static int poolConnections = 0;
|
|||
* from grabbing this object while we are checking it.
|
||||
*/
|
||||
[clientsLock lock];
|
||||
if (nil != _pool && [self retainCount] == 1)
|
||||
if ([self retainCount] > 1)
|
||||
{
|
||||
[super release];
|
||||
[clientsLock unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pool)
|
||||
{
|
||||
/* This is the only reference to a client associated with
|
||||
* a connection pool we put this client back to the pool.
|
||||
*
|
||||
* That being the case, we know that this thread 'owns'
|
||||
* the client and it's not going to be deallocated and not
|
||||
* going to have the _pool iinstance variable changed, so it
|
||||
* going to have the _pool instance variable changed, so it
|
||||
* is safe to unlock clientsLock before returning the client
|
||||
* to the pool. This avoids a possible deadlock when a pool
|
||||
* is being purged.
|
||||
|
@ -2600,8 +2609,18 @@ static int poolConnections = 0;
|
|||
}
|
||||
else
|
||||
{
|
||||
[super release];
|
||||
/* As we are going to deallocate the object, we first remove
|
||||
* it from global tables so that no other thread will find it
|
||||
* and try to use it while it is being deallocated.
|
||||
*/
|
||||
NSHashRemove(clientsHash, (void*)self);
|
||||
if (_name != nil
|
||||
&& (SQLClient*)NSMapGet(clientsMap, (void*)_name) == self)
|
||||
{
|
||||
NSMapRemove(clientsMap, (void*)_name);
|
||||
}
|
||||
[clientsLock unlock];
|
||||
[super release];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2795,12 +2814,13 @@ static int poolConnections = 0;
|
|||
|
||||
- (NSInteger) simpleExecute: (id)info
|
||||
{
|
||||
NSInteger result;
|
||||
NSString *debug = nil;
|
||||
BOOL done = NO;
|
||||
BOOL isCommit = NO;
|
||||
BOOL isRollback = NO;
|
||||
NSString *statement;
|
||||
NSInteger result;
|
||||
NSString *debug = nil;
|
||||
BOOL done = NO;
|
||||
BOOL isCommit = NO;
|
||||
BOOL isRollback = NO;
|
||||
NSString *statement;
|
||||
NSTimeInterval wait = 0.0;
|
||||
|
||||
if ([info isKindOfClass: NSArrayClass] == NO)
|
||||
{
|
||||
|
@ -2815,7 +2835,12 @@ static int poolConnections = 0;
|
|||
info = [NSMutableArray arrayWithObject: info];
|
||||
}
|
||||
|
||||
[lock lock];
|
||||
if (NO == [lock tryLock])
|
||||
{
|
||||
wait = GSTickerTimeNow();
|
||||
[lock lock];
|
||||
}
|
||||
_waitLock = wait;
|
||||
|
||||
statement = [info objectAtIndex: 0];
|
||||
|
||||
|
@ -2823,6 +2848,8 @@ static int poolConnections = 0;
|
|||
*/
|
||||
if ([self connect] == NO)
|
||||
{
|
||||
_waitPool = 0.0;
|
||||
_waitLock = 0.0;
|
||||
[lock unlock];
|
||||
[NSException raise: SQLConnectionException
|
||||
format: @"Unable to connect to '%@' to run statement %@",
|
||||
|
@ -2844,60 +2871,51 @@ static int poolConnections = 0;
|
|||
done = YES;
|
||||
NS_DURING
|
||||
{
|
||||
NSMutableString *m;
|
||||
|
||||
_lastStart = GSTickerTimeNow();
|
||||
result = [self backendExecute: info];
|
||||
_lastOperation = GSTickerTimeNow();
|
||||
[_statements addObject: statement];
|
||||
if (_duration >= 0)
|
||||
m = [self _checkDuration: _lastOperation];
|
||||
if (m)
|
||||
{
|
||||
NSTimeInterval d;
|
||||
if (isCommit || isRollback)
|
||||
{
|
||||
NSEnumerator *e = [_statements objectEnumerator];
|
||||
|
||||
d = _lastOperation - _lastStart;
|
||||
if (d >= _duration)
|
||||
{
|
||||
NSMutableString *m;
|
||||
|
||||
if (isCommit || isRollback)
|
||||
{
|
||||
NSEnumerator *e = [_statements objectEnumerator];
|
||||
|
||||
if (isCommit)
|
||||
{
|
||||
m = [NSMutableString stringWithFormat:
|
||||
@"Duration %g for transaction commit ...\n", d];
|
||||
}
|
||||
else
|
||||
{
|
||||
m = [NSMutableString stringWithFormat:
|
||||
@"Duration %g for transaction rollback ...\n", d];
|
||||
}
|
||||
while ((statement = [e nextObject]) != nil)
|
||||
{
|
||||
[m appendFormat: @" %@;\n", statement];
|
||||
}
|
||||
[m appendFormat: @" affected %"PRIdPTR" record%s\n",
|
||||
result, ((1 == result) ? "" : "s")];
|
||||
}
|
||||
else if ([self debugging] > 1)
|
||||
{
|
||||
/*
|
||||
* For higher debug levels, we log data objects as well
|
||||
* as the query string, otherwise we omit them.
|
||||
*/
|
||||
m = [NSMutableString stringWithFormat:
|
||||
@"Duration %g for statement %@;", d, info];
|
||||
[m appendFormat: @" affected %"PRIdPTR" record%s",
|
||||
result, ((1 == result) ? "" : "s")];
|
||||
}
|
||||
else
|
||||
{
|
||||
m = [NSMutableString stringWithFormat:
|
||||
@"Duration %g for statement %@;", d, statement];
|
||||
[m appendFormat: @" affected %"PRIdPTR" record%s",
|
||||
result, ((1 == result) ? "" : "s")];
|
||||
}
|
||||
debug = m;
|
||||
}
|
||||
if (isCommit)
|
||||
{
|
||||
[m appendString: @" for transaction commit ...\n"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[m appendString: @" for transaction rollback ...\n"];
|
||||
}
|
||||
while ((statement = [e nextObject]) != nil)
|
||||
{
|
||||
[m appendFormat: @" %@;\n", statement];
|
||||
}
|
||||
[m appendFormat: @" affected %"PRIdPTR" record%s\n",
|
||||
result, ((1 == result) ? "" : "s")];
|
||||
}
|
||||
else if ([self debugging] > 1)
|
||||
{
|
||||
/*
|
||||
* For higher debug levels, we log data objects as well
|
||||
* as the query string, otherwise we omit them.
|
||||
*/
|
||||
[m appendFormat: @" for statement %@;", info];
|
||||
[m appendFormat: @" affected %"PRIdPTR" record%s",
|
||||
result, ((1 == result) ? "" : "s")];
|
||||
}
|
||||
else
|
||||
{
|
||||
[m appendFormat: @" for statement %@;", statement];
|
||||
[m appendFormat: @" affected %"PRIdPTR" record%s",
|
||||
result, ((1 == result) ? "" : "s")];
|
||||
}
|
||||
debug = m;
|
||||
}
|
||||
if (_inTransaction == NO)
|
||||
{
|
||||
|
@ -2952,10 +2970,17 @@ static int poolConnections = 0;
|
|||
NSMutableArray *result = nil;
|
||||
NSString *debug = nil;
|
||||
BOOL done = NO;
|
||||
NSTimeInterval wait = 0.0;
|
||||
|
||||
if (rtype == 0) rtype = rClass;
|
||||
if (ltype == 0) ltype = aClass;
|
||||
[lock lock];
|
||||
if (NO == [lock tryLock])
|
||||
{
|
||||
wait = GSTickerTimeNow();
|
||||
[lock lock];
|
||||
}
|
||||
_waitLock = wait;
|
||||
|
||||
if ([self connect] == NO)
|
||||
{
|
||||
[lock unlock];
|
||||
|
@ -2968,22 +2993,19 @@ static int poolConnections = 0;
|
|||
done = YES;
|
||||
NS_DURING
|
||||
{
|
||||
NSMutableString *m;
|
||||
|
||||
_lastStart = GSTickerTimeNow();
|
||||
result = [self backendQuery: stmt recordType: rtype listType: ltype];
|
||||
_lastOperation = GSTickerTimeNow();
|
||||
if (_duration >= 0)
|
||||
m = [self _checkDuration: _lastOperation];
|
||||
if (m)
|
||||
{
|
||||
NSTimeInterval d;
|
||||
NSUInteger count = [result count];
|
||||
|
||||
d = _lastOperation - _lastStart;
|
||||
if (d >= _duration)
|
||||
{
|
||||
NSUInteger count = [result count];
|
||||
|
||||
debug = [NSString stringWithFormat:
|
||||
@"Duration %g for query %@; produced %"PRIuPTR" record%s",
|
||||
d, stmt, count, ((1 == count) ? "" : "s")];
|
||||
}
|
||||
[m appendFormat: @" for query %@; produced %"PRIuPTR" record%s",
|
||||
stmt, count, ((1 == count) ? "" : "s")];
|
||||
debug = m;
|
||||
}
|
||||
if (_inTransaction == NO)
|
||||
{
|
||||
|
@ -3027,8 +3049,25 @@ static int poolConnections = 0;
|
|||
{
|
||||
if (NO == connected)
|
||||
{
|
||||
[lock lock];
|
||||
if (NO == connected)
|
||||
NSTimeInterval wait = 0.0;
|
||||
NSString *msg;
|
||||
|
||||
if (NO == [lock tryLock])
|
||||
{
|
||||
wait = GSTickerTimeNow();
|
||||
[lock lock];
|
||||
}
|
||||
_waitLock = wait;
|
||||
_lastStart = GSTickerTimeNow();
|
||||
if (connected)
|
||||
{
|
||||
msg = [self _checkDuration: _lastStart];
|
||||
if (msg)
|
||||
{
|
||||
[self debug: @"%@ for existing connection.", msg];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
|
@ -3052,7 +3091,6 @@ static int poolConnections = 0;
|
|||
}
|
||||
}
|
||||
|
||||
_lastStart = GSTickerTimeNow();
|
||||
if (YES == [self backendConnect])
|
||||
{
|
||||
/* On establishing a new connection, we must restore any
|
||||
|
@ -3071,43 +3109,39 @@ static int poolConnections = 0;
|
|||
}
|
||||
}
|
||||
_lastConnect = GSTickerTimeNow();
|
||||
msg = [self _checkDuration: _lastConnect];
|
||||
_connectFails = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastOperation = GSTickerTimeNow();
|
||||
msg = [self _checkDuration: _lastOperation];
|
||||
_connectFails++;
|
||||
}
|
||||
|
||||
if (_duration >= 0)
|
||||
if (msg)
|
||||
{
|
||||
NSTimeInterval d;
|
||||
NSString *s;
|
||||
NSString *s;
|
||||
|
||||
if (0 == _connectFails)
|
||||
{
|
||||
s = @"success";
|
||||
d = _lastConnect - _lastStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = @"failure";
|
||||
d = _lastOperation - _lastStart;
|
||||
}
|
||||
|
||||
if (d >= _duration)
|
||||
if (_lastListen > 0.0)
|
||||
{
|
||||
if (_lastListen > 0.0)
|
||||
{
|
||||
[self debug: @"Duration %g for connection (%@)"
|
||||
@", of which %g adding observers.",
|
||||
d, s, _lastOperation - _lastListen];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self debug: @"Duration %g for connection (%@).",
|
||||
d, s];
|
||||
}
|
||||
[self debug: @"%@ for connection (%@)"
|
||||
@", of which %g adding observers.",
|
||||
msg, s, _lastOperation - _lastListen];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self debug: @"%@ for connection (%@).",
|
||||
msg, s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3222,6 +3256,7 @@ static int poolConnections = 0;
|
|||
unsigned char *buf;
|
||||
unsigned char *ptr;
|
||||
const unsigned char *from = (const unsigned char*)statement;
|
||||
const unsigned char *end = from + strlen((const char*)statement);
|
||||
|
||||
/*
|
||||
* Calculate length of buffer needed.
|
||||
|
@ -3240,10 +3275,10 @@ static int poolConnections = 0;
|
|||
* Merge quoted data objects into statement.
|
||||
*/
|
||||
i = 1;
|
||||
from = (unsigned char*)statement;
|
||||
while (*from != 0)
|
||||
while (from < end)
|
||||
{
|
||||
if (*from == *(unsigned char*)marker
|
||||
&& (from + mLength) < end
|
||||
&& memcmp(from, marker, mLength) == 0)
|
||||
{
|
||||
NSData *d = [blobs objectAtIndex: i++];
|
||||
|
@ -3274,6 +3309,80 @@ static int poolConnections = 0;
|
|||
|
||||
@implementation SQLClient (Private)
|
||||
|
||||
- (NSMutableString*) _checkDuration: (NSTimeInterval)end
|
||||
{
|
||||
NSMutableString *m = nil;
|
||||
NSTimeInterval ti = _lastStart;
|
||||
|
||||
if (_waitLock > 0.0 && _waitLock < ti)
|
||||
{
|
||||
ti = _waitLock;
|
||||
}
|
||||
if (_waitPool > 0.0 && _waitPool < ti)
|
||||
{
|
||||
ti = _waitPool;
|
||||
}
|
||||
ti = end - ti; // Total duration
|
||||
|
||||
if (ti > _duration)
|
||||
{
|
||||
BOOL additional = NO;
|
||||
NSTimeInterval threshold = 0.001;
|
||||
|
||||
/* The threshold for reporting lock information is set to zero if
|
||||
* we have debug turned on or if the logging threshold is set to
|
||||
* zero (to log every query). A level of zero means that any
|
||||
* locjk which was not obtained immediately is recorded.
|
||||
*/
|
||||
if (_duration <= 0.0 || _debugging > 0.0)
|
||||
{
|
||||
threshold = 0.0;
|
||||
}
|
||||
|
||||
m = [NSMutableString stringWithCapacity: 1000];
|
||||
[m appendFormat: @"Duration %g", ti];
|
||||
if (_waitPool > 0.0)
|
||||
{
|
||||
if (_waitLock > 0.0)
|
||||
{
|
||||
ti = _waitLock - _waitPool;
|
||||
}
|
||||
else
|
||||
{
|
||||
ti = _lastStart - _waitPool;
|
||||
}
|
||||
if (ti >= threshold)
|
||||
{
|
||||
[m appendFormat: @" (%g waiting for connection pool", ti];
|
||||
additional = YES;
|
||||
}
|
||||
}
|
||||
if (_waitLock > 0.0)
|
||||
{
|
||||
ti = _lastStart - _waitLock;
|
||||
if (ti >= threshold)
|
||||
{
|
||||
if (additional)
|
||||
{
|
||||
[m appendFormat: @", %g waiting for connection lock", ti];
|
||||
}
|
||||
else
|
||||
{
|
||||
[m appendFormat: @" (%g waiting for connection lock", ti];
|
||||
}
|
||||
additional = YES;
|
||||
}
|
||||
}
|
||||
if (additional)
|
||||
{
|
||||
[m appendString: @")"];
|
||||
}
|
||||
}
|
||||
_waitPool = 0.0;
|
||||
_waitLock = 0.0;
|
||||
return m;
|
||||
}
|
||||
|
||||
- (void) _configure: (NSNotification*)n
|
||||
{
|
||||
NSDictionary *o;
|
||||
|
@ -3746,6 +3855,8 @@ static int poolConnections = 0;
|
|||
GSCache *c;
|
||||
id toCache;
|
||||
BOOL cacheHit;
|
||||
NSTimeInterval start;
|
||||
NSString *s;
|
||||
|
||||
if (rtype == 0) rtype = rClass;
|
||||
if (ltype == 0) ltype = aClass;
|
||||
|
@ -3753,7 +3864,7 @@ static int poolConnections = 0;
|
|||
md = [[NSThread currentThread] threadDictionary];
|
||||
[md setObject: rtype forKey: @"SQLClientRecordType"];
|
||||
[md setObject: ltype forKey: @"SQLClientListType"];
|
||||
_lastStart = GSTickerTimeNow();
|
||||
start = GSTickerTimeNow();
|
||||
c = [self cache];
|
||||
toCache = nil;
|
||||
|
||||
|
@ -3821,17 +3932,12 @@ static int poolConnections = 0;
|
|||
result = [[result mutableCopy] autorelease];
|
||||
}
|
||||
|
||||
_lastStart = start;
|
||||
_lastOperation = GSTickerTimeNow();
|
||||
if (_duration >= 0)
|
||||
if ((s = [self _checkDuration: _lastOperation]) != nil)
|
||||
{
|
||||
NSTimeInterval d;
|
||||
|
||||
d = _lastOperation - _lastStart;
|
||||
if (d >= _duration)
|
||||
{
|
||||
[self debug: @"Duration %g for cache-%@ query %@",
|
||||
d, (YES == cacheHit) ? @"hit" : @"miss", stmt];
|
||||
}
|
||||
[self debug: @"%@ for cache-%@ query %@",
|
||||
s, (YES == cacheHit) ? @"hit" : @"miss", stmt];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -5238,6 +5344,11 @@ nextUTF8(const uint8_t *p, unsigned l, unsigned *o, unichar *n)
|
|||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)z
|
||||
{
|
||||
return RETAIN(self);
|
||||
}
|
||||
|
||||
- (NSData*) dataUsingEncoding: (NSStringEncoding)encoding
|
||||
allowLossyConversion: (BOOL)flag
|
||||
{
|
||||
|
@ -5484,11 +5595,6 @@ nextUTF8(const uint8_t *p, unsigned l, unsigned *o, unichar *n)
|
|||
return range;
|
||||
}
|
||||
|
||||
- (id) copyWithZone: (NSZone*)z
|
||||
{
|
||||
return RETAIN(self);
|
||||
}
|
||||
|
||||
- (NSZone*) zone
|
||||
{
|
||||
return NSDefaultMallocZone();
|
||||
|
|
516
SQLClientPool.m
516
SQLClientPool.m
|
@ -48,6 +48,7 @@ struct _SQLClientPoolItem {
|
|||
|
||||
@interface SQLClient(Pool)
|
||||
- (void) _clearPool: (SQLClientPool*)p;
|
||||
- (void) _waitPool: (NSTimeInterval)ti;
|
||||
@end
|
||||
|
||||
@implementation SQLClient(Pool)
|
||||
|
@ -57,6 +58,10 @@ struct _SQLClientPoolItem {
|
|||
|
||||
_pool = nil;
|
||||
}
|
||||
- (void) _waitPool: (NSTimeInterval)ti
|
||||
{
|
||||
_waitPool = ti;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface SQLClientPool (Adjust)
|
||||
|
@ -65,6 +70,10 @@ struct _SQLClientPoolItem {
|
|||
|
||||
@interface SQLClientPool (Private)
|
||||
- (void) _lock;
|
||||
- (SQLClient*) _provideClientBeforeDate: (NSDate*)when
|
||||
exclusive: (BOOL)isLocal
|
||||
blocked: (NSTimeInterval*)ti;
|
||||
- (SQLClient*) _provide;
|
||||
- (NSString*) _rc: (SQLClient*)o;
|
||||
- (void) _unlock;
|
||||
@end
|
||||
|
@ -239,223 +248,9 @@ static Class cls = Nil;
|
|||
|
||||
- (SQLClient*) provideClientBeforeDate: (NSDate*)when exclusive: (BOOL)isLocal
|
||||
{
|
||||
NSThread *thread = [NSThread currentThread];
|
||||
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
|
||||
NSTimeInterval now = start;
|
||||
SQLClient *client = nil;
|
||||
int preferred = -1;
|
||||
int found = -1;
|
||||
int cond = 0;
|
||||
int index;
|
||||
|
||||
/* If this is a request for a non-exclusive connection, we can simply
|
||||
* check to see if there's already such a connection available.
|
||||
*/
|
||||
if (NO == isLocal)
|
||||
{
|
||||
[_lock lock];
|
||||
for (index = 0; index < _max; index++)
|
||||
{
|
||||
if (_items[index].o == thread && _items[index].u < NSNotFound
|
||||
&& NO == [_items[index].c isInTransaction])
|
||||
{
|
||||
preferred = index; // Ignore any other connected client
|
||||
break;
|
||||
}
|
||||
if (nil == _items[index].o && 0 == _items[index].u)
|
||||
{
|
||||
if (preferred < 0 && YES == [_items[index].c connected])
|
||||
{
|
||||
preferred = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (preferred >= 0)
|
||||
{
|
||||
found = preferred; // Prefer a connected client.
|
||||
}
|
||||
if (found >= 0)
|
||||
{
|
||||
_items[found].t = now;
|
||||
if (0 == _items[found].u++)
|
||||
{
|
||||
ASSIGN(_items[found].o, thread);
|
||||
client = [_items[found].c autorelease];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have already provided this client, so we must retain it
|
||||
* before we autorelease it, to keep retain counts in sync.
|
||||
*/
|
||||
client = [[_items[found].c retain] autorelease];
|
||||
}
|
||||
_immediate++;
|
||||
}
|
||||
[self _unlock];
|
||||
if (nil != client)
|
||||
{
|
||||
if (_debugging > 2)
|
||||
{
|
||||
NSLog(@"%@ provides %p%@",
|
||||
self, _items[found].c, [self _rc: client]);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we haven't been given a timeout, we should wait for a client
|
||||
* indefinitely ... so we set the timeout to be in the distant future.
|
||||
*/
|
||||
if (nil == when)
|
||||
{
|
||||
static NSDate *future = nil;
|
||||
|
||||
if (nil == future)
|
||||
{
|
||||
future = RETAIN([NSDate distantFuture]);
|
||||
}
|
||||
when = future;
|
||||
}
|
||||
|
||||
/* We want to log stuff if we don't get a client quickly.
|
||||
* Ideally we get the lock straight away,
|
||||
* but if not we want to log every ten seconds (and possibly
|
||||
* when we begin waiting).
|
||||
*/
|
||||
if (YES == [_lock tryLockWhenCondition: 1])
|
||||
{
|
||||
_immediate++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSTimeInterval end = [when timeIntervalSinceReferenceDate];
|
||||
NSTimeInterval dif = 0.0;
|
||||
NSDate *until;
|
||||
BOOL locked;
|
||||
|
||||
if (_debugging > 1)
|
||||
{
|
||||
NSLog(@"%@ has no clients available", self);
|
||||
}
|
||||
until = [[NSDate alloc]
|
||||
initWithTimeIntervalSinceReferenceDate: now + 10.0];
|
||||
locked = NO;
|
||||
while (NO == locked && now < end)
|
||||
{
|
||||
if (now >= end)
|
||||
{
|
||||
/* End date is passed ... try to get the lock immediately.
|
||||
*/
|
||||
locked = [_lock tryLockWhenCondition: 1];
|
||||
}
|
||||
else if ([when earlierDate: until] == until)
|
||||
{
|
||||
locked = [_lock lockWhenCondition: 1 beforeDate: until];
|
||||
}
|
||||
else
|
||||
{
|
||||
locked = [_lock lockWhenCondition: 1 beforeDate: when];
|
||||
}
|
||||
now = [NSDate timeIntervalSinceReferenceDate];
|
||||
dif = now - start;
|
||||
if (NO == locked && now < end)
|
||||
{
|
||||
if (_debugging > 0 || dif > 30.0
|
||||
|| (_duration >= 0.0 && dif > _duration))
|
||||
{
|
||||
NSLog(@"%@ still waiting after %g seconds:\n%@",
|
||||
self, dif, [self status]);
|
||||
}
|
||||
[until release];
|
||||
until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
|
||||
}
|
||||
}
|
||||
[until release];
|
||||
if (dif > _longest)
|
||||
{
|
||||
_longest = dif;
|
||||
}
|
||||
if (NO == locked)
|
||||
{
|
||||
if (_debugging > 0 || dif > 30.0
|
||||
|| (_duration >= 0.0 && dif > _duration))
|
||||
{
|
||||
NSLog(@"%@ abandoned wait after %g seconds:\n%@",
|
||||
self, dif, [self status]);
|
||||
}
|
||||
_failed++;
|
||||
_failWaits += dif;
|
||||
return nil;
|
||||
}
|
||||
if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
|
||||
{
|
||||
NSLog(@"%@ provided client after %g seconds",
|
||||
self, dif);
|
||||
}
|
||||
_delayed++;
|
||||
_delayWaits += dif;
|
||||
}
|
||||
|
||||
for (index = 0; index < _max && 0 == cond; index++)
|
||||
{
|
||||
if (0 == _items[index].u)
|
||||
{
|
||||
if (preferred >= 0 || found >= 0)
|
||||
{
|
||||
/* There's at least one more client available to be
|
||||
* provided, so we want to re-lock with condition 1.
|
||||
*/
|
||||
cond = 1;
|
||||
}
|
||||
if (preferred < 0 && YES == [_items[index].c connected])
|
||||
{
|
||||
preferred = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = index;
|
||||
}
|
||||
}
|
||||
else if (NO == isLocal
|
||||
&& _items[index].o == thread
|
||||
&& _items[index].u < NSNotFound
|
||||
&& NO == [_items[index].c isInTransaction])
|
||||
{
|
||||
/* We are allowed to re-use connections in the current thread,
|
||||
* so if we have found one, treat it as the preferred choice.
|
||||
*/
|
||||
preferred = index;
|
||||
}
|
||||
}
|
||||
|
||||
/* We prefer to use a client which is already connected, so we
|
||||
* avoid opening unnecessary connections.
|
||||
*/
|
||||
if (preferred >= 0)
|
||||
{
|
||||
found = preferred;
|
||||
}
|
||||
if (YES == isLocal)
|
||||
{
|
||||
_items[found].u = NSNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
_items[found].u++;
|
||||
}
|
||||
_items[found].t = now;
|
||||
ASSIGN(_items[found].o, thread);
|
||||
[self _unlock];
|
||||
client = [_items[found].c autorelease];
|
||||
if (_debugging > 2)
|
||||
{
|
||||
NSLog(@"%@ provides %p%@", self, _items[found].c, [self _rc: client]);
|
||||
}
|
||||
return client;
|
||||
return [self _provideClientBeforeDate: when
|
||||
exclusive: isLocal
|
||||
blocked: (NSTimeInterval*)NULL];
|
||||
}
|
||||
|
||||
- (SQLClient*) provideClientExclusive
|
||||
|
@ -703,6 +498,7 @@ static Class cls = Nil;
|
|||
for (index = 0; index < _max; index++)
|
||||
{
|
||||
SQLClient *client = _items[index].c;
|
||||
NSThread *owner = _items[index].o;
|
||||
NSUInteger rc = [client retainCount];
|
||||
NSUInteger uc = _items[index].u;
|
||||
|
||||
|
@ -716,15 +512,15 @@ static Class cls = Nil;
|
|||
if (NSNotFound == uc)
|
||||
{
|
||||
tmp = [NSString stringWithFormat: @" Client '%@'"
|
||||
@" provided exclusively (retained:%"PRIuPTR,
|
||||
[client name], rc];
|
||||
@" provided to %@ exclusively (retained:%"PRIuPTR,
|
||||
[client name], owner, rc];
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = [NSString stringWithFormat: @" Client '%@'"
|
||||
@" provided %"PRIuPTR
|
||||
@" provided to %@ %"PRIuPTR
|
||||
@" time%s (retained:%"PRIuPTR,
|
||||
[client name], uc, ((1 == uc) ? "" : "s"), rc];
|
||||
[client name], owner, uc, ((1 == uc) ? "" : "s"), rc];
|
||||
}
|
||||
|
||||
#if defined(GNUSTEP)
|
||||
|
@ -970,6 +766,258 @@ static Class cls = Nil;
|
|||
[_lock lock];
|
||||
}
|
||||
|
||||
- (SQLClient*) _provideClientBeforeDate: (NSDate*)when
|
||||
exclusive: (BOOL)isLocal
|
||||
blocked: (NSTimeInterval*)ti
|
||||
{
|
||||
NSThread *thread = [NSThread currentThread];
|
||||
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
|
||||
NSTimeInterval now = start;
|
||||
NSTimeInterval block = 0.0;
|
||||
NSTimeInterval dif = 0.0;
|
||||
SQLClient *client = nil;
|
||||
int preferred = -1;
|
||||
int found = -1;
|
||||
int cond = 0;
|
||||
int index;
|
||||
|
||||
/* If this is a request for a non-exclusive connection, we can simply
|
||||
* check to see if there's already such a connection available.
|
||||
*/
|
||||
if (NO == isLocal)
|
||||
{
|
||||
if (NO == [_lock tryLock])
|
||||
{
|
||||
[_lock lock];
|
||||
block = start;
|
||||
}
|
||||
for (index = 0; index < _max; index++)
|
||||
{
|
||||
if (_items[index].o == thread && _items[index].u < NSNotFound
|
||||
&& NO == [_items[index].c isInTransaction])
|
||||
{
|
||||
preferred = index; // Ignore any other connected client
|
||||
break;
|
||||
}
|
||||
if (nil == _items[index].o && 0 == _items[index].u)
|
||||
{
|
||||
if (preferred < 0 && YES == [_items[index].c connected])
|
||||
{
|
||||
preferred = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (preferred >= 0)
|
||||
{
|
||||
found = preferred; // Prefer a connected client.
|
||||
}
|
||||
if (found >= 0)
|
||||
{
|
||||
_items[found].t = now;
|
||||
if (0 == _items[found].u++)
|
||||
{
|
||||
ASSIGN(_items[found].o, thread);
|
||||
client = [_items[found].c autorelease];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have already provided this client, so we must retain it
|
||||
* before we autorelease it, to keep retain counts in sync.
|
||||
*/
|
||||
client = [[_items[found].c retain] autorelease];
|
||||
}
|
||||
_immediate++;
|
||||
}
|
||||
[self _unlock];
|
||||
if (nil != client)
|
||||
{
|
||||
if (_debugging > 2)
|
||||
{
|
||||
NSLog(@"%@ provides %p%@",
|
||||
self, _items[found].c, [self _rc: client]);
|
||||
}
|
||||
if (ti)
|
||||
{
|
||||
*ti = block;
|
||||
}
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we haven't been given a timeout, we should wait for a client
|
||||
* indefinitely ... so we set the timeout to be in the distant future.
|
||||
*/
|
||||
if (nil == when)
|
||||
{
|
||||
static NSDate *future = nil;
|
||||
|
||||
if (nil == future)
|
||||
{
|
||||
future = RETAIN([NSDate distantFuture]);
|
||||
}
|
||||
when = future;
|
||||
}
|
||||
|
||||
/* We want to log stuff if we don't get a client quickly.
|
||||
* Ideally we get the lock straight away,
|
||||
* but if not we want to log every ten seconds (and possibly
|
||||
* when we begin waiting).
|
||||
*/
|
||||
if ([_lock tryLockWhenCondition: 1])
|
||||
{
|
||||
_immediate++;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSTimeInterval end = [when timeIntervalSinceReferenceDate];
|
||||
NSDate *until;
|
||||
BOOL locked;
|
||||
|
||||
block = start;
|
||||
if (_debugging > 1)
|
||||
{
|
||||
NSLog(@"%@ has no clients available", self);
|
||||
}
|
||||
until = [[NSDate alloc]
|
||||
initWithTimeIntervalSinceReferenceDate: now + 10.0];
|
||||
locked = NO;
|
||||
while (NO == locked && now < end)
|
||||
{
|
||||
if (now >= end)
|
||||
{
|
||||
/* End date is passed ... try to get the lock immediately.
|
||||
*/
|
||||
locked = [_lock tryLockWhenCondition: 1];
|
||||
}
|
||||
else if ([when earlierDate: until] != when)
|
||||
{
|
||||
locked = [_lock lockWhenCondition: 1 beforeDate: until];
|
||||
}
|
||||
else
|
||||
{
|
||||
locked = [_lock lockWhenCondition: 1 beforeDate: when];
|
||||
}
|
||||
now = [NSDate timeIntervalSinceReferenceDate];
|
||||
dif = now - start;
|
||||
if (NO == locked && now < end)
|
||||
{
|
||||
if (_debugging > 0 || dif > 30.0
|
||||
|| (_duration >= 0.0 && dif > _duration))
|
||||
{
|
||||
NSLog(@"%@ still waiting after %g seconds:\n%@%@\n",
|
||||
self, dif, [self status], [NSThread callStackSymbols]);
|
||||
}
|
||||
[until release];
|
||||
until = [[NSDate alloc] initWithTimeIntervalSinceNow: 10.0];
|
||||
}
|
||||
}
|
||||
[until release];
|
||||
if (dif > _longest)
|
||||
{
|
||||
_longest = dif;
|
||||
}
|
||||
if (NO == locked)
|
||||
{
|
||||
if (_debugging > 0 || dif > 30.0
|
||||
|| (_duration >= 0.0 && dif > _duration))
|
||||
{
|
||||
NSLog(@"%@ abandoned wait after %g seconds:\n%@",
|
||||
self, dif, [self status]);
|
||||
}
|
||||
_failed++;
|
||||
_failWaits += dif;
|
||||
if (ti)
|
||||
{
|
||||
*ti = block;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
_delayed++;
|
||||
_delayWaits += dif;
|
||||
}
|
||||
|
||||
for (index = 0; index < _max && 0 == cond; index++)
|
||||
{
|
||||
if (0 == _items[index].u)
|
||||
{
|
||||
if (preferred >= 0 || found >= 0)
|
||||
{
|
||||
/* There's at least one more client available to be
|
||||
* provided, so we want to re-lock with condition 1.
|
||||
*/
|
||||
cond = 1;
|
||||
}
|
||||
if (preferred < 0 && YES == [_items[index].c connected])
|
||||
{
|
||||
preferred = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = index;
|
||||
}
|
||||
}
|
||||
else if (NO == isLocal
|
||||
&& _items[index].o == thread
|
||||
&& _items[index].u < NSNotFound
|
||||
&& NO == [_items[index].c isInTransaction])
|
||||
{
|
||||
/* We are allowed to re-use connections in the current thread,
|
||||
* so if we have found one, treat it as the preferred choice.
|
||||
*/
|
||||
preferred = index;
|
||||
}
|
||||
}
|
||||
|
||||
/* We prefer to use a client which is already connected, so we
|
||||
* avoid opening unnecessary connections.
|
||||
*/
|
||||
if (preferred >= 0)
|
||||
{
|
||||
found = preferred;
|
||||
}
|
||||
if (YES == isLocal)
|
||||
{
|
||||
_items[found].u = NSNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
_items[found].u++;
|
||||
}
|
||||
_items[found].t = now;
|
||||
ASSIGN(_items[found].o, thread);
|
||||
[self _unlock];
|
||||
client = [_items[found].c autorelease];
|
||||
if (_debugging > 0 || (_duration >= 0.0 && dif > _duration))
|
||||
{
|
||||
NSLog(@"%@ provided client %p after %g seconds", self, client, dif);
|
||||
}
|
||||
if (_debugging > 2)
|
||||
{
|
||||
NSLog(@"%@ provides %p %@", self, client, [self _rc: client]);
|
||||
}
|
||||
if (ti)
|
||||
{
|
||||
*ti = block;
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
- (SQLClient*) _provide
|
||||
{
|
||||
NSTimeInterval start;
|
||||
SQLClient *db;
|
||||
|
||||
db = [self _provideClientBeforeDate: nil
|
||||
exclusive: NO
|
||||
blocked: &start];
|
||||
[db _waitPool: start];
|
||||
return db;
|
||||
}
|
||||
|
||||
- (NSString*) _rc: (SQLClient*)o
|
||||
{
|
||||
#if defined(GNUSTEP)
|
||||
|
@ -1083,7 +1131,7 @@ static Class cls = Nil;
|
|||
query = [[_items[0].c prepare: stmt args: ap] objectAtIndex: 0];
|
||||
va_end (ap);
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db cache: seconds simpleQuery: query];
|
||||
NS_HANDLER
|
||||
|
@ -1101,7 +1149,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSMutableArray *result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db cache: seconds query: stmt with: values];
|
||||
NS_HANDLER
|
||||
|
@ -1117,7 +1165,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSMutableArray *result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db cache: seconds simpleQuery: stmt];
|
||||
NS_HANDLER
|
||||
|
@ -1136,7 +1184,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSMutableArray *result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db cache: seconds
|
||||
simpleQuery: stmt
|
||||
|
@ -1165,7 +1213,7 @@ static Class cls = Nil;
|
|||
va_start (ap, stmt);
|
||||
info = [_items[0].c prepare: stmt args: ap];
|
||||
va_end (ap);
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleExecute: info];
|
||||
NS_HANDLER
|
||||
|
@ -1181,7 +1229,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSInteger result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db execute: stmt with: values];
|
||||
NS_HANDLER
|
||||
|
@ -1233,7 +1281,7 @@ static Class cls = Nil;
|
|||
query = [[_items[0].c prepare: stmt args: ap] objectAtIndex: 0];
|
||||
va_end (ap);
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleQuery: query];
|
||||
NS_HANDLER
|
||||
|
@ -1250,7 +1298,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSMutableArray *result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db query: stmt with: values];
|
||||
NS_HANDLER
|
||||
|
@ -1273,7 +1321,7 @@ static Class cls = Nil;
|
|||
query = [[_items[0].c prepare: stmt args: ap] objectAtIndex: 0];
|
||||
va_end (ap);
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleQuery: query];
|
||||
NS_HANDLER
|
||||
|
@ -1308,7 +1356,7 @@ static Class cls = Nil;
|
|||
query = [[_items[0].c prepare: stmt args: ap] objectAtIndex: 0];
|
||||
va_end (ap);
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleQuery: query];
|
||||
NS_HANDLER
|
||||
|
@ -1422,7 +1470,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSInteger result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleExecute: info];
|
||||
NS_HANDLER
|
||||
|
@ -1438,7 +1486,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSMutableArray *result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleQuery: stmt];
|
||||
NS_HANDLER
|
||||
|
@ -1456,7 +1504,7 @@ static Class cls = Nil;
|
|||
SQLClient *db;
|
||||
NSMutableArray *result;
|
||||
|
||||
db = [self provideClient];
|
||||
db = [self _provide];
|
||||
NS_DURING
|
||||
result = [db simpleQuery: stmt
|
||||
recordType: rtype
|
||||
|
|
Loading…
Reference in a new issue