* EOAccess/EOAttribute.m

added attributeWithParent: definition: convenience method
* EOAccess/EOAdaptorContext.m
  _channelDidInit: setDelegate
* EOAccess/EODatabaseContext.m
  availableChannel: call registerChannel
  new method _fetchRawRowKeyPaths:fetchSpecification:entity:editingContext:
* EOAccess/EODatabaseChannel.m
  raise NSInvalidArgumentException in init.
  initWithDatabaseContext: more checks
* EOAdaptors/PostgreSQLAdaptor/PostgreSQLContext.m
  beginTransaction: more checks, raise NSInternalInconsistencyException



git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@30494 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Dave Wetzel 2010-05-30 18:24:14 +00:00
parent fb061e0a13
commit 021d9c6759
6 changed files with 389 additions and 217 deletions

View file

@ -113,11 +113,11 @@ NSString *EOAdaptorContextRollbackTransactionNotification = @"EOAdaptorContextRo
- (BOOL)hasOpenChannels
{
int i, count = [_channels count];
for (i = 0; i < count; i++)
if ([[[_channels objectAtIndex: i] nonretainedObjectValue] isOpen])
return YES;
return NO;
}
@ -277,23 +277,22 @@ NSString *EOAdaptorContextRollbackTransactionNotification = @"EOAdaptorContextRo
{
[_channels addObject: [NSValue valueWithNonretainedObject: channel]];
[channel setDebugEnabled: [self isDebugEnabled]];
//call self delegate
//call channel setDelegate: returned ?
[channel setDebugEnabled: [self isDebugEnabled]]; // not done on reference -- dw
[channel setDelegate:_delegate];
}
- (void)_channelWillDealloc:channel
{
int i;
for (i = [_channels count] - 1; i >= 0; i--)
{
if ([[_channels objectAtIndex: i] nonretainedObjectValue] == channel)
{
if ([[_channels objectAtIndex: i] nonretainedObjectValue] == channel)
{
[_channels removeObjectAtIndex: i];
break;
}
[_channels removeObjectAtIndex: i];
break;
}
}
}
@end

View file

@ -116,6 +116,11 @@ typedef enum {
+ (id)attributeWithPropertyList: (NSDictionary *)propertyList
owner: (id)owner;
/** returns an autoreleased attribute **/
+ (id) attributeWithParent:(EOEntity *) parent
definition:(NSString*) def;
/* Accessing the entity */
- (NSString *)name;

View file

@ -101,6 +101,20 @@ RCS_ID("$Id$")
owner: owner] autorelease];
}
+ (id) attributeWithParent:(EOEntity *) parent
definition:(NSString*) def
{
EOAttribute * attr = [[[self alloc] init] autorelease];
if (attr) {
[attr setName: def];
[attr setParent: parent];
[attr setDefinition: def];
}
return attr;
}
- (id) initWithPropertyList: (NSDictionary *)propertyList
owner: (id)owner
{

View file

@ -112,20 +112,30 @@ RCS_ID("$Id$")
return [[[self alloc] initWithDatabaseContext: databaseContext] autorelease];
}
- (id) init
{
[NSException raise: NSInvalidArgumentException
format: @"Use initWithDatabaseContext to init an instance of class %@",
NSStringFromClass([self class])];
return nil;
}
- (id) initWithDatabaseContext:(EODatabaseContext *)databaseContext
{
if ((self = [super init]))
{
ASSIGN(_databaseContext, databaseContext);
ASSIGN(_adaptorChannel, [[_databaseContext adaptorContext]
ASSIGN(_adaptorChannel, [[databaseContext adaptorContext]
createAdaptorChannel]);
//TODO NO<<<<
[_adaptorChannel openChannel];
_fetchProperties = [NSMutableArray new];
_fetchSpecifications = [NSMutableArray new];
//NO>>>>>>>
[_databaseContext registerChannel: self];//should be in caller
if (!_adaptorChannel)
{
[NSException raise: NSInternalInconsistencyException
format: @"EODatabaseChannel is unable to obtain new channel from %@",
[databaseContext adaptorContext]];
} else {
ASSIGN(_databaseContext, databaseContext);
}
}
return self;

View file

@ -537,8 +537,14 @@ static Class _contextClass = Nil;
}
}
if (!channel)
if ((!channel) && ([_registeredChannels count] < 1)) {
channel = [EODatabaseChannel databaseChannelWithDatabaseContext: self];
if (channel)
{
[self registerChannel:channel];
}
}
return channel;
}
@ -1260,8 +1266,8 @@ userInfo = {
}
- (void)_fetchRelationship: (EORelationship *)relationship
withObjects: (NSArray *)objsArray
editingContext: (EOEditingContext *)context
withObjects: (NSArray *)objsArray
editingContext: (EOEditingContext *)context
{
NSMutableArray *qualArray = nil;
NSEnumerator *objEnum = nil;
@ -1322,8 +1328,154 @@ userInfo = {
EOFLOGObjectFnStop();
}
- (NSArray*) _fetchRawRowKeyPaths:(NSArray *) rawRowKeyPaths
fetchSpecification: (EOFetchSpecification*) fetchSpecification
entity: (EOEntity *) entity
editingContext: (EOEditingContext *) context
{
EOAdaptorChannel * adaptorChannel = [[self availableChannel] adaptorChannel];
NSMutableArray * results = [NSMutableArray array];
NSUInteger fetchLimit = 0;
NSUInteger rowsFetched = 0;
NSUInteger keyCount = [rawRowKeyPaths count];
id messageHandler = nil; // used to prompt the user after the fetch limit is reached.
NSString * hintKey = nil;
BOOL continueFetch = NO;
NSUInteger k;
NSArray * attributesToFetch;
if (keyCount == 0)
{
attributesToFetch = [entity attributesToFetch];
} else {
// Populate an array with the attributes we need
attributesToFetch = [NSMutableArray arrayWithCapacity:keyCount];
BOOL hasNonFlattenedAttributes = NO;
for (k = 0; k < keyCount; k++)
{
NSString * keyName = [rawRowKeyPaths objectAtIndex:k];
EOAttribute * attr = [entity attributeNamed:keyName];
if (!attr)
{
attr = [EOAttribute attributeWithParent:entity
definition:keyName];
} else {
if ((!hasNonFlattenedAttributes) && (![attr isFlattened]))
{
hasNonFlattenedAttributes = YES;
}
}
[attributesToFetch addObject:attr];
}
if (!hasNonFlattenedAttributes)
{
// check if lastObject is enouth.
// the reference however does only checks the lastObject.
EOAttribute * attr = [attributesToFetch lastObject];
EORelationship * relationship;
if ([attr isFlattened])
{
relationship = [[attr _definitionArray] objectAtIndex:0];
} else {
NSString * s1 = [rawRowKeyPaths lastObject];
NSString * relName = [[s1 componentsSeparatedByString:@"."] objectAtIndex:0];
relationship = [entity relationshipNamed:relName];
if ([relationship isFlattened])
{
relationship = [[relationship _definitionArray] objectAtIndex:0];
}
}
EOJoin * join = [[relationship joins] lastObject];
EOAttribute * attr2 = [join sourceAttribute];
[attributesToFetch addObject:attr2];
}
// our channel does not support this.
//[adaptorChannel _setRawDictionaryInitializerForAttributes:attributesToFetch];
}
if ((hintKey = [[fetchSpecification hints] objectForKey:@"EOCustomQueryExpressionHintKey"]))
{
if ([hintKey isKindOfClass:[NSString class]])
{
hintKey = [[[_adaptorContext adaptor] expressionClass] expressionForString:hintKey];
} else {
NSLog(@"%s - %@ is not an NSString but a %@",__PRETTY_FUNCTION__, hintKey, NSStringFromClass([hintKey class]));
}
} else {
EOQualifier * qualifier = [[fetchSpecification qualifier] schemaBasedQualifierWithRootEntity:entity];
if (qualifier != [fetchSpecification qualifier])
{
[fetchSpecification setQualifier:qualifier];
}
}
if (![adaptorChannel isOpen])
{
[adaptorChannel openChannel];
}
if (hintKey)
{
[adaptorChannel evaluateExpression:hintKey];
[adaptorChannel setAttributesToFetch:attributesToFetch];
} else {
[adaptorChannel selectAttributes:attributesToFetch
fetchSpecification:fetchSpecification
lock:NO
entity:entity];
}
// 0 is no fetch limit
fetchLimit = [fetchSpecification fetchLimit];
// TODO: check if we need to check for protocol EOMessageHandlers
if (([fetchSpecification promptsAfterFetchLimit]) && ([context messageHandler]))
{
messageHandler = [context messageHandler];
}
do {
do {
NSMutableDictionary * dict = [adaptorChannel fetchRowWithZone:NULL];
if (!dict) {
break;
}
[results addObject:dict];
rowsFetched++;
} while ((fetchLimit == 0) || (rowsFetched < fetchLimit));
if (!messageHandler) {
break;
}
continueFetch = [messageHandler editingContext:context
shouldContinueFetchingWithCurrentObjectCount:rowsFetched
originalLimit:fetchLimit
objectStore:self];
} while (continueFetch);
[adaptorChannel cancelFetch];
if (_delegate)
{
[_delegate databaseContext: self
didFetchObjects: results
fetchSpecification: fetchSpecification
editingContext: context];
}
return results;
}
- (NSArray *)objectsWithFetchSpecification: (EOFetchSpecification *)fetchSpecification
editingContext: (EOEditingContext *)context
editingContext: (EOEditingContext *)context
{ // TODO
EODatabaseChannel *channel = nil;
NSMutableArray *array = nil;
@ -1348,6 +1500,7 @@ userInfo = {
NSDebugMLLog(@"EODatabaseContext", @"fetchSpecification=%@", fetchSpecification);
#warning fix this method! -- dw
channel = [self _obtainOpenChannel];
if (_flags.beganTransaction == NO)
{
@ -1399,192 +1552,187 @@ userInfo = {
*/
rawRowKeyPaths = [fetchSpecification rawRowKeyPaths];//OK
if (rawRowKeyPaths)
#if 0
{
NSEmitTODO();
[self notImplemented: _cmd]; //TODO
}
#else
// (stephane@sente.ch) Adapted implementation of non raw rows
{
//cachesObject
//fetchspe isDeep ret 1
channel = [self _obtainOpenChannel];
if (!channel)
{
NSEmitTODO();
[self notImplemented: _cmd];//TODO
}
else
{
NSDebugMLLog(@"EODatabaseContext",
@"channel class %@ [channel isFetchInProgress]=%s",
[channel class],
([channel isFetchInProgress] ? "YES" : "NO"));
//mirko:
#if 0
if (_flags.beganTransaction == NO
&& _updateStrategy == EOUpdateWithPessimisticLocking)
{
[_adaptorContext beginTransaction];
NSDebugMLLog(@"EODatabaseContext",
@"BEGAN TRANSACTION FLAG==>YES");
_flags.beganTransaction = YES;
}
#endif
if ([entity isAbstractEntity] == NO) //Mirko ???
// (stephane@sente) Should we test deepInheritanceFetch?
{
int autoreleaseSteps = 20;
int autoreleaseStep = autoreleaseSteps;
BOOL promptsAfterFetchLimit = NO;
NSAutoreleasePool *arp = nil;//To avoid too much memory use when fetching a lot of objects
int limit = 0;
[channel selectObjectsWithFetchSpecification: fetchSpecification
editingContext: context];//OK
NSDebugMLLog(@"EODatabaseContext",
@"[channel isFetchInProgress]=%s",
([channel isFetchInProgress] ? "YES" : "NO"));
limit = [fetchSpecification fetchLimit];//OK
promptsAfterFetchLimit = [fetchSpecification promptsAfterFetchLimit];
NSDebugMLLog(@"EODatabaseContext", @"Will Fetch");
NS_DURING
{
IMP channelFetchObjectIMP=
[channel methodForSelector:@selector(fetchObject)];
IMP arrayAddObjectIMP=
[array methodForSelector:@selector(addObject:)];
GDL2IMP_UINT arrayIndexOfObjectIdenticalToIMP=
(GDL2IMP_UINT)[array methodForSelector:@selector(indexOfObjectIdenticalTo:)];
arp = GDL2_NSAutoreleasePool_new();
NSDebugMLLog(@"EODatabaseContext",
@"[channel isFetchInProgress]=%s",
([channel isFetchInProgress] ? "YES" : "NO"));
while ((obj = (*channelFetchObjectIMP)(channel,@selector(fetchObject))))
{
NSDebugMLLog(@"EODatabaseContext",
@"fetched an object");
NSDebugMLLog(@"EODatabaseContext",
@"FETCH OBJECT object=%@\n", obj);
NSDebugMLLog(@"EODatabaseContext",
@"%d usesDistinct: %s", num,
(usesDistinct ? "YES" : "NO"));
NSDebugMLLog(@"EODatabaseContext",
@"object=%@\n\n", obj);
if (usesDistinct == YES
&& num > 0
&& GDL2_IndexOfObjectIdenticalToWithImp(array,arrayIndexOfObjectIdenticalToIMP,obj)!=NSNotFound)
// (stephane@sente) I thought that DISTINCT was done on server-side?!?
{
obj = nil;
}
else
{
NSDebugMLLog(@"EODatabaseContext", @"AFTER FETCH");
GDL2_AddObjectWithImp(array,arrayAddObjectIMP,obj);
NSDebugMLLog(@"EODatabaseContext", @"array count=%d",
[array count]);
num++;
if (limit > 0 && num >= limit)
{
if ([[context messageHandler]
editingContext: context
shouldContinueFetchingWithCurrentObjectCount: num
originalLimit: limit
objectStore: self] == YES)
limit = 0;//??
else
{
DESTROY(arp);
break;
};
};
};
if (autoreleaseStep <= 0)
{
DESTROY(arp);
autoreleaseStep = autoreleaseSteps;
arp = GDL2_NSAutoreleasePool_new();
}
else
autoreleaseStep--;
NSDebugMLLog(@"EODatabaseContext",
@"WILL FETCH NEXT OBJECT");
NSDebugMLLog(@"EODatabaseContext",
@"[channel isFetchInProgress]=%s",
([channel isFetchInProgress]
? "YES" : "NO"));
}
NSDebugMLLog(@"EODatabaseContext",
@"finished fetch");
NSDebugMLLog(@"EODatabaseContext",
@"array=%@", array);
NSDebugMLLog(@"EODatabaseContext",
@"step 0 channel is busy=%d",
(int)[channel isFetchInProgress]);
[channel cancelFetch]; //OK
NSDebugMLLog(@"EODatabaseContext",
@"step 1 channel is busy=%d",
(int)[channel isFetchInProgress]);
NSDebugMLLog(@"EODatabaseContext", @"array=%@", array);
//TODO
/*
handle exceptio in fetchObject
channel fetchObject
if eception:
if ([editcontext handleError:localException])
{
//TODO
}
else
{
//TODO
};
*/
DESTROY(arp);
}
NS_HANDLER
{
NSDebugMLLog(@"EODatabaseContext", @"AN EXCEPTION: %@",
localException);
RETAIN(localException);
DESTROY(arp);
AUTORELEASE(localException);
[localException raise];
}
NS_ENDHANDLER;
}
}
NSDebugMLLog(@"EODatabaseContext",
@"step 2 channel is busy=%d",
(int)[channel isFetchInProgress]);
}
#endif
else if ([entity cachesObjects] == YES)//OK
NSArray * rawRows = [self _fetchRawRowKeyPaths:rawRowKeyPaths
fetchSpecification:fetchSpecification
entity:entity
editingContext:context];
return rawRows;
} else {
// (stephane@sente.ch) Adapted implementation of non raw rows
//cachesObject
//fetchspe isDeep ret 1
if (!channel)
{
channel = [self _obtainOpenChannel];
}
else
{
NSDebugMLLog(@"EODatabaseContext",
@"channel class %@ [channel isFetchInProgress]=%s",
[channel class],
([channel isFetchInProgress] ? "YES" : "NO"));
//mirko:
//#if 0
// if (_flags.beganTransaction == NO
// && _updateStrategy == EOUpdateWithPessimisticLocking)
// {
// [_adaptorContext beginTransaction];
//
// NSDebugMLLog(@"EODatabaseContext",
// @"BEGAN TRANSACTION FLAG==>YES");
// _flags.beganTransaction = YES;
// }
//#endif
if ([entity isAbstractEntity] == NO) //Mirko ???
// (stephane@sente) Should we test deepInheritanceFetch?
{
int autoreleaseSteps = 20;
int autoreleaseStep = autoreleaseSteps;
BOOL promptsAfterFetchLimit = NO;
NSAutoreleasePool *arp = nil;//To avoid too much memory use when fetching a lot of objects
int limit = 0;
[channel selectObjectsWithFetchSpecification: fetchSpecification
editingContext: context];//OK
NSDebugMLLog(@"EODatabaseContext",
@"[channel isFetchInProgress]=%s",
([channel isFetchInProgress] ? "YES" : "NO"));
limit = [fetchSpecification fetchLimit];//OK
promptsAfterFetchLimit = [fetchSpecification promptsAfterFetchLimit];
NSDebugMLLog(@"EODatabaseContext", @"Will Fetch");
NS_DURING
{
IMP channelFetchObjectIMP=
[channel methodForSelector:@selector(fetchObject)];
IMP arrayAddObjectIMP=
[array methodForSelector:@selector(addObject:)];
GDL2IMP_UINT arrayIndexOfObjectIdenticalToIMP=
(GDL2IMP_UINT)[array methodForSelector:@selector(indexOfObjectIdenticalTo:)];
arp = GDL2_NSAutoreleasePool_new();
NSDebugMLLog(@"EODatabaseContext",
@"[channel isFetchInProgress]=%s",
([channel isFetchInProgress] ? "YES" : "NO"));
while ((obj = (*channelFetchObjectIMP)(channel,@selector(fetchObject))))
{
NSDebugMLLog(@"EODatabaseContext",
@"fetched an object");
NSDebugMLLog(@"EODatabaseContext",
@"FETCH OBJECT object=%@\n", obj);
NSDebugMLLog(@"EODatabaseContext",
@"%d usesDistinct: %s", num,
(usesDistinct ? "YES" : "NO"));
NSDebugMLLog(@"EODatabaseContext",
@"object=%@\n\n", obj);
if (usesDistinct == YES
&& num > 0
&& GDL2_IndexOfObjectIdenticalToWithImp(array,arrayIndexOfObjectIdenticalToIMP,obj)!=NSNotFound)
// (stephane@sente) I thought that DISTINCT was done on server-side?!?
{
obj = nil;
}
else
{
NSDebugMLLog(@"EODatabaseContext", @"AFTER FETCH");
GDL2_AddObjectWithImp(array,arrayAddObjectIMP,obj);
NSDebugMLLog(@"EODatabaseContext", @"array count=%d",
[array count]);
num++;
if (limit > 0 && num >= limit)
{
if ([[context messageHandler]
editingContext: context
shouldContinueFetchingWithCurrentObjectCount: num
originalLimit: limit
objectStore: self] == YES)
limit = 0;//??
else
{
DESTROY(arp);
break;
};
};
};
if (autoreleaseStep <= 0)
{
DESTROY(arp);
autoreleaseStep = autoreleaseSteps;
arp = GDL2_NSAutoreleasePool_new();
}
else
autoreleaseStep--;
NSDebugMLLog(@"EODatabaseContext",
@"WILL FETCH NEXT OBJECT");
NSDebugMLLog(@"EODatabaseContext",
@"[channel isFetchInProgress]=%s",
([channel isFetchInProgress]
? "YES" : "NO"));
}
NSDebugMLLog(@"EODatabaseContext",
@"finished fetch");
NSDebugMLLog(@"EODatabaseContext",
@"array=%@", array);
NSDebugMLLog(@"EODatabaseContext",
@"step 0 channel is busy=%d",
(int)[channel isFetchInProgress]);
[channel cancelFetch]; //OK
NSDebugMLLog(@"EODatabaseContext",
@"step 1 channel is busy=%d",
(int)[channel isFetchInProgress]);
NSDebugMLLog(@"EODatabaseContext", @"array=%@", array);
//TODO
/*
handle exceptio in fetchObject
channel fetchObject
if eception:
if ([editcontext handleError:localException])
{
//TODO
}
else
{
//TODO
};
*/
DESTROY(arp);
}
NS_HANDLER
{
NSDebugMLLog(@"EODatabaseContext", @"AN EXCEPTION: %@",
localException);
RETAIN(localException);
DESTROY(arp);
AUTORELEASE(localException);
[localException raise];
}
NS_ENDHANDLER;
}
}
}
if ([entity cachesObjects] == YES)//OK
{
///TODO MG!!!
NSMutableArray *cache;
EOQualifier *qualifier;

View file

@ -82,8 +82,6 @@ RCS_ID("$Id$")
{
PostgreSQLChannel *channel = nil;
EOFLOGObjectFnStart();
if ([self transactionNestingLevel])
[NSException raise: NSInternalInconsistencyException
format: @"%@ -- %@ 0x%x: attempted to begin a transaction within a transaction",
@ -101,8 +99,13 @@ RCS_ID("$Id$")
self];
}
if ((!_channels) || ([_channels count] < 1)) {
[NSException raise:NSInternalInconsistencyException
format:@"%s: No open channel found. CreateAdaptorChannel first!",
__PRETTY_FUNCTION__];
}
channel = [[_channels objectAtIndex: 0] nonretainedObjectValue];
if ([channel isOpen] == NO)
[NSException raise: PostgreSQLException
format: @"cannot execute SQL expression. Channel is not opened."];
@ -117,13 +120,6 @@ RCS_ID("$Id$")
if (_delegateRespondsTo.didBegin)
[_delegate adaptorContextDidBegin: self];
NSDebugMLLog(@"gsdb", @"_flags.didBegin=%s",
(_flags.didBegin ? "YES" : "NO"));
NSDebugMLLog(@"gsdb", @"_flags.didAutoBegin=%s",
(_flags.didAutoBegin ? "YES" : "NO"));
EOFLOGObjectFnStop();
}
- (void)commitTransaction