mirror of
https://github.com/gnustep/libs-gdl2.git
synced 2025-04-23 13:10:48 +00:00
* EOAccess/EOSQLExpression.m
fix include for less warnings on mac * EOAccess/EOEntity.m fix include for less warnings on mac isPrimaryKeyValidInObject: 0 is NOT a valid PK value * EOAccess/EOAdaptor.m fix include for less warnings on mac isDroppedConnectionException add comment and remove logs * EOAccess/EOSQLQualifier.m * EOAccess/EODatabaseDataSource.m * EOAccess/EOAdaptorContext.m * EOAccess/EORelationship.m * EOAccess/EOUtilities.m * EOAccess/EOSchemaGeneration.m * EOAccess/EOAdaptorChannel.m * EOAccess/EODatabaseChannel.m fix include for less warnings on mac * EOAccess/EODatabaseContext.h add support for shouldHandleDatabaseException (WO 4.5) * EOAccess/EODatabaseContext.m add support for shouldHandleDatabaseException add [newRow addEntriesFromDictionary:objectPK] to merge PKValues into the values of the EO. without that it is impossible to work. relayPrimaryKey: object: entity: Hopefully fixed. add _delegateHandledDatabaseException: fixed _primaryKeyForObject: raiseException: (we raise always for now) * EOAccess/EOAdaptorChannel.h add comment * EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m fix include for less warnings on mac numberOfAffectedRows: search reverse to cover "INSERT 0 1" case. The first zero is the OID number refactored primaryKeyForNewRowWithEntity: * EOAdaptors/PostgreSQLAdaptor/PostgreSQLContext.h/m disabled _primaryKeySequenceNameFormat * EOAdaptors/PostgreSQLAdaptor/PostgreSQLExpression.m fixed formatValue: forAttribute: * EOControl/EOEditingContext.m * EOControl/EOFaultHandler.m * EOControl/EOKeyValueQualifier.m * EOControl/EOUndoManager.m * EOControl/EOClassDescription.m * EOControl/EOQualifier.m * EOControl/EOOrQualifier.m fix include for less warnings on mac * EOControl/EOCustomObject.m use getCString:maxLength:encoding instead of getCString use setValue: forKey instead of takeValue: forKey: change text in exceptions a bit * EOControl/EOPrivate.h use setValue: forKey instead of takeValue: forKey: git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@30633 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
b1dba74b03
commit
4878a85bbe
28 changed files with 561 additions and 619 deletions
57
ChangeLog
57
ChangeLog
|
@ -1,3 +1,60 @@
|
|||
2010-06-09 David Wetzel <dave@turbocat.de>
|
||||
* EOAccess/EOSQLExpression.m
|
||||
fix include for less warnings on mac
|
||||
* EOAccess/EOEntity.m
|
||||
fix include for less warnings on mac
|
||||
isPrimaryKeyValidInObject: 0 is NOT a valid PK value
|
||||
* EOAccess/EOAdaptor.m
|
||||
fix include for less warnings on mac
|
||||
isDroppedConnectionException
|
||||
add comment and remove logs
|
||||
* EOAccess/EOSQLQualifier.m
|
||||
* EOAccess/EODatabaseDataSource.m
|
||||
* EOAccess/EOAdaptorContext.m
|
||||
* EOAccess/EORelationship.m
|
||||
* EOAccess/EOUtilities.m
|
||||
* EOAccess/EOSchemaGeneration.m
|
||||
* EOAccess/EOAdaptorChannel.m
|
||||
* EOAccess/EODatabaseChannel.m
|
||||
fix include for less warnings on mac
|
||||
* EOAccess/EODatabaseContext.h
|
||||
add support for shouldHandleDatabaseException (WO 4.5)
|
||||
* EOAccess/EODatabaseContext.m
|
||||
add support for shouldHandleDatabaseException
|
||||
add [newRow addEntriesFromDictionary:objectPK]
|
||||
to merge PKValues into the values of the EO.
|
||||
without that it is impossible to work.
|
||||
relayPrimaryKey: object: entity:
|
||||
Hopefully fixed.
|
||||
add _delegateHandledDatabaseException:
|
||||
fixed _primaryKeyForObject: raiseException:
|
||||
(we raise always for now)
|
||||
* EOAccess/EOAdaptorChannel.h
|
||||
add comment
|
||||
* EOAdaptors/PostgreSQLAdaptor/PostgreSQLChannel.m
|
||||
fix include for less warnings on mac
|
||||
numberOfAffectedRows: search reverse to cover "INSERT 0 1" case.
|
||||
The first zero is the OID number
|
||||
refactored primaryKeyForNewRowWithEntity:
|
||||
* EOAdaptors/PostgreSQLAdaptor/PostgreSQLContext.h/m
|
||||
disabled _primaryKeySequenceNameFormat
|
||||
* EOAdaptors/PostgreSQLAdaptor/PostgreSQLExpression.m
|
||||
fixed formatValue: forAttribute:
|
||||
* EOControl/EOEditingContext.m
|
||||
* EOControl/EOFaultHandler.m
|
||||
* EOControl/EOKeyValueQualifier.m
|
||||
* EOControl/EOUndoManager.m
|
||||
* EOControl/EOClassDescription.m
|
||||
* EOControl/EOQualifier.m
|
||||
* EOControl/EOOrQualifier.m
|
||||
fix include for less warnings on mac
|
||||
* EOControl/EOCustomObject.m
|
||||
use getCString:maxLength:encoding instead of getCString
|
||||
use setValue: forKey instead of takeValue: forKey:
|
||||
change text in exceptions a bit
|
||||
* EOControl/EOPrivate.h
|
||||
use setValue: forKey instead of takeValue: forKey:
|
||||
|
||||
2010-06-07 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* EOMultiReaderLock.m (-tryLockForWriting, -unlockForReading):
|
||||
|
|
|
@ -69,6 +69,8 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSString+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <GNUstepBase/GSMime.h>
|
||||
|
@ -728,11 +730,17 @@ NSString *EOAdministrativeConnectionDictionaryKey
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns YES if the exception is one that the adaptor can attempt to recover from by reconnecting.
|
||||
* NO otherwise.
|
||||
* The default implementation returns NO.
|
||||
*
|
||||
* Subclasses that support database reconnection should override this
|
||||
* to allow for automatic database reconnection.
|
||||
*/
|
||||
|
||||
- (BOOL)isDroppedConnectionException: (NSException *)exception
|
||||
{
|
||||
EOFLOGObjectFnStartOrCond2(@"AdaptorLevel", @"EOAdaptor");
|
||||
EOFLOGObjectFnStopOrCond2(@"AdaptorLevel", @"EOAdaptor");
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
|
|
@ -142,6 +142,9 @@ inRowDescribedByQualifier: (EOQualifier *)qualifier
|
|||
|
||||
- (void)cancelFetch;
|
||||
|
||||
/**
|
||||
* Database adaptors need to override this
|
||||
*/
|
||||
- (NSDictionary *)primaryKeyForNewRowWithEntity: (EOEntity *)entity;
|
||||
|
||||
- (NSArray *)describeTableNames;
|
||||
|
|
|
@ -51,6 +51,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOMutableKnownKeyDictionary.h>
|
||||
|
@ -298,10 +299,8 @@ inRowDescribedByQualifier: (EOQualifier *)qualifier
|
|||
|
||||
- (NSDictionary *)primaryKeyForNewRowWithEntity: (EOEntity *)entity
|
||||
{
|
||||
|
||||
|
||||
|
||||
return nil;//no or subclass respo ?
|
||||
[self subclassResponsibility: _cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray *)describeTableNames
|
||||
|
|
|
@ -48,6 +48,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EODebug.h>
|
||||
|
|
|
@ -54,6 +54,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOEditingContext.h>
|
||||
|
|
|
@ -113,7 +113,8 @@ struct _EOTransactionScope;
|
|||
unsigned int didFetchObjects:1;
|
||||
unsigned int shouldFetchObjectFault:1;
|
||||
unsigned int shouldFetchArrayFault:1;
|
||||
unsigned int _reserved:21;
|
||||
unsigned int shouldHandleDatabaseException:1;
|
||||
unsigned int _reserved:20;
|
||||
} _delegateRespondsTo;
|
||||
|
||||
NSRecursiveLock *_lock; //TODO: not lock object !
|
||||
|
@ -427,6 +428,14 @@ shouldRaiseExceptionForLockFailure: (NSException *)exception;
|
|||
- (BOOL)databaseContext: (EODatabaseContext *)databaseContext
|
||||
shouldFetchArrayFault: (id)fault;
|
||||
|
||||
/**
|
||||
* If the delegate returns NO, it is responsible for doing the right thing
|
||||
* This is new in WO 4.5
|
||||
*/
|
||||
|
||||
- (BOOL)databaseContext: (EODatabaseContext *)databaseContext
|
||||
shouldHandleDatabaseException: (NSException *)exception;
|
||||
|
||||
@end
|
||||
|
||||
GDL2ACCESS_EXPORT NSString *EOCustomQueryExpressionHintKey;
|
||||
|
|
|
@ -637,6 +637,8 @@ May raise an exception if transaction has began or if you want pessimistic lock
|
|||
[delegate respondsToSelector: @selector(databaseContext:shouldFetchObjectsWithFetchSpecification:editingContext:)];
|
||||
_delegateRespondsTo.shouldFetchArrayFault =
|
||||
[delegate respondsToSelector: @selector(databaseContext:shouldFetchArrayFault:)];
|
||||
_delegateRespondsTo.shouldHandleDatabaseException =
|
||||
[delegate respondsToSelector: @selector(databaseContext:shouldHandleDatabaseException:)];
|
||||
|
||||
while ((channel = GDL2_NextObjectWithImpPtr(channelsEnum,&enumNO)))
|
||||
[channel setDelegate: delegate];
|
||||
|
@ -646,8 +648,6 @@ May raise an exception if transaction has began or if you want pessimistic lock
|
|||
{
|
||||
NSUInteger i;
|
||||
|
||||
EOFLOGObjectFnStartOrCond2(@"DatabaseLevel", @"EODatabaseContext");
|
||||
|
||||
DESTROY(_adaptorContext);
|
||||
|
||||
for (i = [_registeredChannels count] - 1; i >= 0; i--)
|
||||
|
@ -661,7 +661,6 @@ May raise an exception if transaction has began or if you want pessimistic lock
|
|||
_adaptorContext = RETAIN([[[self database] adaptor] createAdaptorContext]);
|
||||
_registeredChannels = [NSMutableArray new];
|
||||
|
||||
EOFLOGObjectFnStopOrCond2(@"DatabaseLevel", @"EODatabaseContext");
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -2538,7 +2537,7 @@ forDatabaseOperation:(EODatabaseOperation *)op
|
|||
object,dbOpe);
|
||||
|
||||
newRow=[dbOpe newRow];
|
||||
|
||||
[newRow addEntriesFromDictionary:objectPK];
|
||||
|
||||
[self relayPrimaryKey: objectPK
|
||||
object: object
|
||||
|
@ -4662,128 +4661,105 @@ Raises an exception is the adaptor is unable to perform the operations.
|
|||
object: (id)object
|
||||
entity: (EOEntity*)entity
|
||||
{
|
||||
//TODO finish
|
||||
//TODO check
|
||||
NSArray *relationships = nil;
|
||||
NSArray *classPropertyNames = nil;
|
||||
EODatabaseOperation *dbOpe = nil;
|
||||
NSDictionary *dbSnapshot = nil;
|
||||
int i, count;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int i, count=0;
|
||||
|
||||
relationships = [entity relationships]; //OK
|
||||
classPropertyNames = [entity classPropertyNames];
|
||||
dbOpe = [self databaseOperationForObject: object];
|
||||
|
||||
|
||||
|
||||
dbSnapshot = [dbOpe dbSnapshot]; //OK
|
||||
|
||||
|
||||
count = [relationships count];
|
||||
|
||||
|
||||
if (!dbOpe) {
|
||||
dbSnapshot = [NSDictionary dictionary];
|
||||
} else {
|
||||
dbSnapshot = [dbOpe dbSnapshot];
|
||||
}
|
||||
|
||||
if (relationships) {
|
||||
count = [relationships count];
|
||||
}
|
||||
|
||||
if (count>0)
|
||||
{
|
||||
IMP oaiIMP=[relationships methodForSelector: @selector(objectAtIndex:)];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
IMP oaiIMP=[relationships methodForSelector: @selector(objectAtIndex:)];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i);
|
||||
EORelationship *substRelationship = nil;
|
||||
NSString *relName;
|
||||
id storedValue;
|
||||
id value = nil;
|
||||
id snapshot = nil;
|
||||
id comSnapshotValue = nil;
|
||||
|
||||
substRelationship = [relationship _substitutionRelationshipForRow: dbSnapshot];
|
||||
|
||||
if (!substRelationship) {
|
||||
continue;
|
||||
}
|
||||
|
||||
relName = [substRelationship name];
|
||||
|
||||
if ((![substRelationship propagatesPrimaryKey]) ||
|
||||
(![classPropertyNames containsObject:relName]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
storedValue = [object storedValueForKey:relName];
|
||||
if (!storedValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
snapshot = [self _currentCommittedSnapshotForObject: object];
|
||||
comSnapshotValue = [snapshot objectForKey:relName];
|
||||
|
||||
// or use == ?
|
||||
if ([storedValue isEqual:comSnapshotValue])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([substRelationship isToMany])
|
||||
{
|
||||
// or use == ?
|
||||
if ([comSnapshotValue isEqual: (NSArray*)storedValue] == NO)
|
||||
{
|
||||
EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i);
|
||||
EORelationship *substRelationship = nil;
|
||||
BOOL propagatesPrimaryKey = NO;
|
||||
#warning check!!
|
||||
NSArray * storedValueArray = (NSArray*)storedValue;
|
||||
NSUInteger x;
|
||||
for (x = [storedValueArray count]; x > 0; x--)
|
||||
{
|
||||
[self relayPrimaryKey: pk
|
||||
sourceObject: object
|
||||
destObject: [storedValueArray objectAtIndex:x-1]
|
||||
relationship: substRelationship];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
substRelationship
|
||||
= [relationship _substitutionRelationshipForRow: dbSnapshot];
|
||||
propagatesPrimaryKey = [substRelationship propagatesPrimaryKey]; //substRelationship or relationship?
|
||||
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"object=%p relationship name=%@ ==> "
|
||||
@"propagatesPrimaryKey=%s",
|
||||
object,
|
||||
[relationship name],
|
||||
(propagatesPrimaryKey ? "YES" : "NO"));
|
||||
|
||||
if (propagatesPrimaryKey)
|
||||
{
|
||||
NSString *relName = [substRelationship name]; //this one ??
|
||||
|
||||
|
||||
|
||||
if ([classPropertyNames containsObject: relName])
|
||||
{
|
||||
id value = nil;
|
||||
id snapshot = nil;
|
||||
id snapshotValue = nil;
|
||||
BOOL isToMany = NO;
|
||||
|
||||
value = [object storedValueForKey: relName];
|
||||
|
||||
|
||||
snapshot = [self _currentCommittedSnapshotForObject: object];
|
||||
|
||||
|
||||
snapshotValue = [snapshot objectForKey:relName];//ret nil
|
||||
NSDebugMLLog(@"EODatabaseContext", @"snapshotValue=%@",
|
||||
snapshotValue);
|
||||
|
||||
isToMany = [substRelationship isToMany]; //this one ??
|
||||
NSDebugMLLog(@"EODatabaseContext", @"isToMany=%s",
|
||||
(isToMany ? "YES" : "NO"));
|
||||
|
||||
if (isToMany)
|
||||
{
|
||||
int valueValuesCount = 0;
|
||||
|
||||
value = [((NSArray*)value) shallowCopy];
|
||||
valueValuesCount = [value count];
|
||||
if (valueValuesCount>0)
|
||||
{
|
||||
int iValueValue = 0;
|
||||
IMP vObjectAtIndexIMP=[value methodForSelector: @selector(objectAtIndex:)];
|
||||
|
||||
for (iValueValue = 0;
|
||||
iValueValue < valueValuesCount;
|
||||
iValueValue++)
|
||||
{
|
||||
id valueValue = GDL2_ObjectAtIndexWithImp(value,vObjectAtIndexIMP,iValueValue);
|
||||
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"valueValue=%@", valueValue);
|
||||
|
||||
[self relayPrimaryKey: pk
|
||||
sourceObject: object
|
||||
destObject: valueValue
|
||||
relationship: substRelationship]; //this one ??
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
// 1:1 relationships may be optional so we may have no value here
|
||||
if (value)
|
||||
{
|
||||
[self relayPrimaryKey: pk
|
||||
sourceObject: object
|
||||
destObject: value
|
||||
relationship: substRelationship]; //this one ??
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
// 1:1 relationships may be optional so we may have no value here
|
||||
[self relayPrimaryKey: pk
|
||||
sourceObject: object
|
||||
destObject: value
|
||||
relationship: substRelationship]; //this one ??
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) createAdaptorOperationsForDatabaseOperation: (EODatabaseOperation*)dbOpe
|
||||
attributes: (NSArray*)attributes
|
||||
{
|
||||
|
@ -7089,6 +7065,23 @@ Raises an exception is the adaptor is unable to perform the operations.
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to check if our delegate handles database exceptions
|
||||
* or if we have to do it ourself.
|
||||
*/
|
||||
|
||||
- (BOOL) _delegateHandledDatabaseException:(NSException *) exception
|
||||
{
|
||||
if (_delegateRespondsTo.shouldHandleDatabaseException)
|
||||
{
|
||||
|
||||
return ([_delegate databaseContext:self
|
||||
shouldHandleDatabaseException:exception] == NO);
|
||||
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) _cleanUpAfterSave
|
||||
{
|
||||
// TODO -- dw
|
||||
|
@ -7160,263 +7153,168 @@ Raises an exception is the adaptor is unable to perform the operations.
|
|||
- (NSDictionary*)_primaryKeyForObject: (id)object
|
||||
raiseException: (BOOL)raiseException
|
||||
{
|
||||
//NEAR OK
|
||||
//Ayers: Review
|
||||
NSDictionary *pk = nil;
|
||||
EOEntity *entity = nil;
|
||||
NSArray *pkNames = nil;
|
||||
BOOL shouldGeneratePrimaryKey = NO;
|
||||
|
||||
|
||||
|
||||
|
||||
NSAssert(!_isNilOrEONull(object), @"No object");
|
||||
|
||||
entity = [_database entityForObject: object];
|
||||
shouldGeneratePrimaryKey = [self _shouldGeneratePrimaryKeyForEntityName:
|
||||
[entity name]];
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"object=%p shouldGeneratePrimaryKey=%d",
|
||||
object, shouldGeneratePrimaryKey);
|
||||
|
||||
/*
|
||||
if (shouldGeneratePrimaryKey)
|
||||
*/
|
||||
{
|
||||
|
||||
BOOL isPKValid = NO;
|
||||
EOGlobalID *gid = EODatabaseContext_globalIDForObjectWithImpPtr(self,NULL,object);
|
||||
|
||||
|
||||
|
||||
pk = [entity primaryKeyForGlobalID: (EOKeyGlobalID*)gid]; //OK
|
||||
|
||||
|
||||
{
|
||||
NSDictionary *pk2 = nil;
|
||||
pkNames = [entity primaryKeyAttributeNames];
|
||||
|
||||
pk2 = [self valuesForKeys: pkNames
|
||||
object: object];
|
||||
|
||||
|
||||
|
||||
if (pk)
|
||||
{
|
||||
//merge pk2 into pk
|
||||
NSEnumerator *pk2Enum = [pk2 keyEnumerator];
|
||||
IMP pk2EnumNO=NULL; // nextObject
|
||||
NSMutableDictionary *realPK
|
||||
= [NSMutableDictionary dictionaryWithDictionary: pk];//revoir
|
||||
id key = nil;
|
||||
|
||||
while ((key = GDL2_NextObjectWithImpPtr(pk2Enum,&pk2EnumNO)))
|
||||
{
|
||||
[realPK setObject: [pk2 objectForKey: key]
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
pk = realPK;
|
||||
}
|
||||
else
|
||||
pk=pk2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
isPKValid = [entity isPrimaryKeyValidInObject: pk];
|
||||
NSDebugMLLog(@"EODatabaseContext",@"object=%p isPKValid=%d",
|
||||
object, isPKValid);
|
||||
if (isPKValid == NO)
|
||||
pk = nil;
|
||||
|
||||
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"object=%p isPKValid=%d shouldGeneratePrimaryKey=%d",
|
||||
object, isPKValid, shouldGeneratePrimaryKey);
|
||||
|
||||
if (isPKValid == NO && shouldGeneratePrimaryKey)
|
||||
{
|
||||
pk = nil;
|
||||
|
||||
if (_delegateRespondsTo.newPrimaryKey == YES)
|
||||
pk = [_delegate databaseContext: self
|
||||
newPrimaryKeyForObject: object
|
||||
entity: entity];
|
||||
|
||||
if (!pk)
|
||||
{
|
||||
NSArray *pkAttributes = nil;
|
||||
EOAdaptorChannel *channel = nil;
|
||||
EOStoredProcedure *nextPKProcedure = nil;
|
||||
|
||||
nextPKProcedure = [entity storedProcedureForOperation:
|
||||
EONextPrimaryKeyProcedureOperation];
|
||||
#if 0 // TODO execute storedProcedure and fetch results;
|
||||
|
||||
if (nextPKProcedure)
|
||||
[[[self _obtainOpenChannel] adaptorChannel]
|
||||
executeStoredProcedure: nextPKProcedure
|
||||
withValues:];
|
||||
#endif
|
||||
|
||||
pkAttributes = [entity primaryKeyAttributes];
|
||||
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"object=%p pk=%@ [pkAttributes count]=%d",
|
||||
object, pk, [pkAttributes count]);
|
||||
|
||||
if (pk == nil && [pkAttributes count] == 1)
|
||||
{
|
||||
EOAttribute *pkAttr = [pkAttributes objectAtIndex: 0];
|
||||
//TODO attr: adaptorValueType //returned EOAdaptorNumberType
|
||||
//TODO [entity rootParent];//so what
|
||||
|
||||
if (channel == nil)
|
||||
{
|
||||
channel = [[self _obtainOpenChannel] adaptorChannel];
|
||||
|
||||
if ([[channel adaptorContext]
|
||||
transactionNestingLevel] == 0)
|
||||
[[channel adaptorContext] beginTransaction];
|
||||
|
||||
if (_flags.beganTransaction == NO)
|
||||
{
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"BEGAN TRANSACTION FLAG==>NO");
|
||||
_flags.beganTransaction = YES;
|
||||
}
|
||||
}
|
||||
|
||||
pk = [channel primaryKeyForNewRowWithEntity: entity];
|
||||
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"** prepare pk %@", pk);
|
||||
|
||||
|
||||
if (pk == nil && [[pkAttr valueClassName]
|
||||
isEqual:@"NSData"] == YES)
|
||||
{
|
||||
unsigned char data[EOUniqueBinaryKeyLength];
|
||||
|
||||
[EOTemporaryGlobalID assignGloballyUniqueBytes: data];
|
||||
|
||||
pk = [NSDictionary dictionaryWithObject:
|
||||
[NSData dataWithBytes: data
|
||||
length:
|
||||
EOUniqueBinaryKeyLength]
|
||||
forKey: [pkAttr name]];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!pk && raiseException)
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"%@ -- %@ 0x%x: cannot generate primary key for object '%@'",
|
||||
NSStringFromSelector(_cmd),
|
||||
NSStringFromClass([self class]),
|
||||
self, object];
|
||||
}
|
||||
}
|
||||
/*
|
||||
else // !shouldGeneratePrimaryKey
|
||||
*/
|
||||
if (!pk)
|
||||
{
|
||||
// MG
|
||||
// Here we'll find if there is a "parent" objects which relay pk
|
||||
// I'm not sure if we could do it here but it's handle this case:
|
||||
// object is a new child of a previous existing object.
|
||||
// if we don't generate it's pk here, the chld object
|
||||
// will relay it's pk to parent which is not good
|
||||
NSDictionary *objectSnapshot=nil;
|
||||
NSArray *relationships=nil;
|
||||
NSUInteger relationshipsCount=0;
|
||||
|
||||
|
||||
|
||||
// get object snapshot
|
||||
objectSnapshot = [object snapshot];
|
||||
NSDebugMLLog(@"EODatabaseContext", @"objectSnapshot=%@",
|
||||
objectSnapshot);
|
||||
|
||||
// Get object relationships
|
||||
relationships = [entity relationships];
|
||||
|
||||
|
||||
relationshipsCount = [relationships count];
|
||||
|
||||
if (relationshipsCount>0)
|
||||
{
|
||||
IMP oaiIMP=[relationships methodForSelector: @selector(objectAtIndex:)];
|
||||
NSUInteger i = 0;
|
||||
|
||||
for (i = 0; i < relationshipsCount; i++)
|
||||
{
|
||||
EORelationship *inverseRelationship = nil;
|
||||
|
||||
EORelationship *relationship = GDL2_ObjectAtIndexWithImp(relationships,oaiIMP,i);
|
||||
NSDebugMLLog(@"EODatabaseContext", @"relationship=%@",
|
||||
relationship);
|
||||
|
||||
inverseRelationship = [relationship inverseRelationship];
|
||||
NSDebugMLLog(@"EODatabaseContext", @"inverseRelationship=%@",
|
||||
inverseRelationship);
|
||||
|
||||
// if there's inverse relationship with propagates primary key
|
||||
if ([inverseRelationship propagatesPrimaryKey])
|
||||
{
|
||||
NSString *relationshipName= [relationship name];
|
||||
NSDictionary *relationshipValuePK = nil;
|
||||
|
||||
// get object value for the relationship
|
||||
id relationshipValue
|
||||
= [objectSnapshot valueForKey:relationshipName];
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"entity name=%@ relationship name=%@ Value=%@",
|
||||
[entity name],
|
||||
relationshipName, relationshipValue);
|
||||
|
||||
// get relationshipValue pk
|
||||
NSAssert2(!_isNilOrEONull(relationshipValue),
|
||||
@"No relationshipValue for relationship %@ in objectSnapshot %@ ",
|
||||
relationshipName,
|
||||
objectSnapshot);
|
||||
|
||||
relationshipValuePK
|
||||
= [self _primaryKeyForObject: relationshipValue];
|
||||
NSDebugMLLog(@"EODatabaseContext",
|
||||
@"relationshipValuePK=%@",
|
||||
relationshipValuePK);
|
||||
|
||||
// force object to relay pk now !
|
||||
[self relayPrimaryKey: relationshipValuePK
|
||||
object: relationshipValue
|
||||
entity: [_database entityForObject: relationshipValue]];
|
||||
};
|
||||
};
|
||||
};
|
||||
pk = [self valuesForKeys: pkNames
|
||||
object: object];
|
||||
|
||||
if (![entity isPrimaryKeyValidInObject: pk])
|
||||
pk=nil;
|
||||
};
|
||||
|
||||
if (pk)
|
||||
{
|
||||
EODatabaseOperation *dbOpe = [self databaseOperationForObject: object];
|
||||
NSMutableDictionary *newRow = [dbOpe newRow];
|
||||
|
||||
[newRow addEntriesFromDictionary: pk];// VERIFY Here we replace
|
||||
// previous key
|
||||
}
|
||||
NSDictionary *pk2 = nil;
|
||||
|
||||
NSAssert(!_isNilOrEONull(object), @"No object");
|
||||
|
||||
entity = [_database entityForObject: object];
|
||||
|
||||
EOGlobalID *gid = EODatabaseContext_globalIDForObjectWithImpPtr(self,NULL,object);
|
||||
|
||||
pk = [entity primaryKeyForGlobalID: (EOKeyGlobalID*)gid]; //OK
|
||||
|
||||
pkNames = [entity primaryKeyAttributeNames];
|
||||
|
||||
pk2 = [self valuesForKeys: pkNames
|
||||
object: object];
|
||||
|
||||
if ([pk2 count] > 0)
|
||||
{
|
||||
if (pk)
|
||||
{
|
||||
//merge pk2 into pk
|
||||
NSEnumerator *pk2Enum = [pk2 keyEnumerator];
|
||||
IMP pk2EnumNO=NULL; // nextObject
|
||||
NSMutableDictionary *realPK;
|
||||
|
||||
realPK = [NSMutableDictionary dictionaryWithDictionary: pk];
|
||||
id key = nil;
|
||||
|
||||
while ((key = GDL2_NextObjectWithImpPtr(pk2Enum,&pk2EnumNO)))
|
||||
{
|
||||
id value = [pk2 objectForKey: key];
|
||||
|
||||
if (((value) && (value != GDL2_EONull)) &&
|
||||
(([value isKindOfClass:[NSNumber class]] == NO) || ([value intValue] != 0)))
|
||||
{
|
||||
[realPK setObject: value
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
pk = realPK;
|
||||
}
|
||||
else
|
||||
pk=pk2;
|
||||
}
|
||||
|
||||
if (([entity isPrimaryKeyValidInObject: pk] == NO)) {
|
||||
pk = nil;
|
||||
}
|
||||
|
||||
// no PK? Ask the delegate to make one for us.
|
||||
if ((pk == nil))
|
||||
{
|
||||
if (_delegateRespondsTo.newPrimaryKey == YES)
|
||||
pk = [_delegate databaseContext: self
|
||||
newPrimaryKeyForObject: object
|
||||
entity: entity];
|
||||
}
|
||||
|
||||
// still no PK?
|
||||
if ((pk == nil))
|
||||
{
|
||||
EOAdaptorChannel *channel = nil;
|
||||
EOStoredProcedure *nextPKProcedure = nil;
|
||||
|
||||
nextPKProcedure = [entity storedProcedureForOperation:
|
||||
EONextPrimaryKeyProcedureOperation];
|
||||
|
||||
if (nextPKProcedure)
|
||||
{
|
||||
NS_DURING {
|
||||
|
||||
channel = [[self _obtainOpenChannel] adaptorChannel];
|
||||
|
||||
[channel executeStoredProcedure:nextPKProcedure
|
||||
withValues:nil];
|
||||
|
||||
pk = [channel returnValuesForLastStoredProcedureInvocation];
|
||||
|
||||
} NS_HANDLER {
|
||||
// if the delegate took care about the exception
|
||||
// or we lost connection, try it again.
|
||||
if (([self _delegateHandledDatabaseException:localException]) ||
|
||||
([[_database adaptor] isDroppedConnectionException:localException]))
|
||||
{
|
||||
channel = [[self _obtainOpenChannel] adaptorChannel];
|
||||
|
||||
[channel executeStoredProcedure:nextPKProcedure
|
||||
withValues:nil];
|
||||
|
||||
pk = [channel returnValuesForLastStoredProcedureInvocation];
|
||||
} else {
|
||||
[localException raise];
|
||||
}
|
||||
}
|
||||
} NS_ENDHANDLER;
|
||||
}
|
||||
|
||||
if (pk)
|
||||
{
|
||||
pk = [entity primaryKeyForRow:pk];
|
||||
}
|
||||
|
||||
if (!pk) {
|
||||
EOAttribute * pkAttr = nil;
|
||||
NSArray * pkAttributes = [entity primaryKeyAttributes];
|
||||
|
||||
if ((pkAttributes) && ([pkAttributes count] == 1)) {
|
||||
pkAttr = [pkAttributes objectAtIndex: 0];
|
||||
}
|
||||
if ((pkAttr) && (([pkAttr adaptorValueType] == EOAdaptorBytesType) &&
|
||||
([pkAttr width] == 24)))
|
||||
{
|
||||
unsigned char bytes[24];
|
||||
id byteValue = nil;
|
||||
|
||||
bzero(&bytes, sizeof(bytes));
|
||||
|
||||
[EOTemporaryGlobalID assignGloballyUniqueBytes:&bytes[0]];
|
||||
|
||||
byteValue = [pkAttr newValueForBytes: &bytes
|
||||
length:sizeof(bytes)];
|
||||
pk = [NSDictionary dictionaryWithObject:byteValue
|
||||
forKey:[pkAttr name]];
|
||||
}
|
||||
}
|
||||
|
||||
if (!pk) {
|
||||
EOAdaptorChannel *channel = nil;
|
||||
|
||||
NS_DURING {
|
||||
channel = [[self _obtainOpenChannel] adaptorChannel];
|
||||
|
||||
pk = [channel primaryKeyForNewRowWithEntity:entity];
|
||||
|
||||
} NS_HANDLER {
|
||||
// if the delegate took care about the exception
|
||||
// or we lost connection, try it again.
|
||||
if (([self _delegateHandledDatabaseException:localException]) ||
|
||||
([[_database adaptor] isDroppedConnectionException:localException]))
|
||||
{
|
||||
channel = [[self _obtainOpenChannel] adaptorChannel];
|
||||
|
||||
pk = [channel primaryKeyForNewRowWithEntity:entity];
|
||||
|
||||
} else {
|
||||
[localException raise];
|
||||
}
|
||||
} NS_ENDHANDLER;
|
||||
}
|
||||
// TODO: The reference does not raise here I suppose -- dw.
|
||||
// if (!pk) {
|
||||
// [NSException raise: NSInvalidArgumentException
|
||||
// format: @"%@ -- %@ 0x%x: cannot generate primary key for object '%@'",
|
||||
// NSStringFromSelector(_cmd),
|
||||
// NSStringFromClass([self class]),
|
||||
// self, object];
|
||||
// }
|
||||
|
||||
|
||||
|
||||
NSDebugMLog(@"object %p=%@\npk=%@",object, object, pk);
|
||||
|
||||
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,12 +50,10 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSDebug.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOEditingContext.h>
|
||||
|
|
|
@ -57,12 +57,9 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSZone.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/GSCategories.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
|
@ -1425,32 +1422,29 @@ static void performSelectorOnArrayWithEachObjectOfClass(NSArray *arr, SEL select
|
|||
NSArray *primaryKeyAttributeNames = nil;
|
||||
NSString *key = nil;
|
||||
id value = nil;
|
||||
int i, count;
|
||||
NSUInteger i, count;
|
||||
BOOL isValid = YES;
|
||||
IMP pkanOAI=NULL;
|
||||
IMP objectVFK=NULL;
|
||||
|
||||
|
||||
primaryKeyAttributeNames = [self primaryKeyAttributeNames];
|
||||
count = [primaryKeyAttributeNames count];
|
||||
|
||||
for (i = 0; isValid && i < count; i++)
|
||||
{
|
||||
key = GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributeNames,&pkanOAI,i);
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
value = GDL2_ValueForKeyWithImpPtr(object,&objectVFK,key);
|
||||
if (_isNilOrEONull(value))
|
||||
isValid = NO;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
isValid = NO;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
key = GDL2_ObjectAtIndexWithImpPtr(primaryKeyAttributeNames,&pkanOAI,i);
|
||||
|
||||
value = GDL2_ValueForKeyWithImpPtr(object,&objectVFK,key);
|
||||
|
||||
|
||||
// a 0 is NOT a valid PK value! -- dw
|
||||
if ((_isNilOrEONull(value)) || (([value isKindOfClass:[NSNumber class]]) &&
|
||||
([value intValue] == 0))) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isValidClassProperty: (id)property
|
||||
|
|
|
@ -44,12 +44,10 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSDebug.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOObserver.h>
|
||||
|
|
|
@ -57,6 +57,7 @@ RCS_ID("$Id$")
|
|||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOFetchSpecification.h>
|
||||
|
|
|
@ -46,11 +46,10 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSDebug.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSString+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOAccess/EOSQLQualifier.h>
|
||||
|
|
|
@ -50,6 +50,7 @@ RCS_ID("$Id: EOSchemaGeneration.m 23653 2006-09-28 15:25:30Z ratmice $")
|
|||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EODebug.h>
|
||||
|
|
|
@ -50,6 +50,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOKeyGlobalID.h>
|
||||
|
|
|
@ -59,12 +59,10 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSTimeZone.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSString+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EONull.h>
|
||||
|
@ -95,6 +93,8 @@ static BOOL attrRespondsToValueTypeChar = NO;
|
|||
#define EOAdaptorDebugLog(format, args...) \
|
||||
do { if ([self isDebugEnabled]) { NSLog(format , ## args); } } while (0)
|
||||
|
||||
#warning Check this. Is this unused code? -- dw
|
||||
|
||||
static NSDictionary *
|
||||
pgResultDictionary(PGresult *pgResult)
|
||||
{
|
||||
|
@ -812,13 +812,14 @@ newValueForBytesLengthAttribute (const void *bytes,
|
|||
NSString *tmpstr = [NSString stringWithCString:PQcmdStatus(_pgResult)
|
||||
encoding:NSASCIIStringEncoding];
|
||||
NSUInteger num = 0;
|
||||
|
||||
|
||||
if ([tmpstr isEqualToString:@"SELECT"]) {
|
||||
num=PQntuples(_pgResult);
|
||||
|
||||
return num;
|
||||
} else {
|
||||
NSRange spaceRange = [tmpstr rangeOfString:@" "];
|
||||
NSRange spaceRange = [tmpstr rangeOfString:@" "
|
||||
options:NSBackwardsSearch];
|
||||
if (spaceRange.location != NSNotFound) {
|
||||
NSString * numStr = [tmpstr substringFromIndex:spaceRange.location];
|
||||
num = [numStr integerValue];
|
||||
|
@ -878,7 +879,7 @@ newValueForBytesLengthAttribute (const void *bytes,
|
|||
[_sqlExpression statement], errorString);
|
||||
|
||||
[NSException raise: PostgreSQLException
|
||||
format: @"unexpected result returned by PQresultStatus(): %@",errorString];
|
||||
format: @"SQL expression '%@' caused %@",[_sqlExpression statement], errorString];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
@ -2192,69 +2193,66 @@ each key
|
|||
|
||||
- (NSDictionary *)primaryKeyForNewRowWithEntity:(EOEntity *)entity
|
||||
{
|
||||
//entity primaryKeyAttributes
|
||||
//self adaptorContext
|
||||
//on each attr attr: adaptorValueType
|
||||
//entty externalName
|
||||
//context autoBeginTransaction
|
||||
//self cleanupFetch######
|
||||
//attr name
|
||||
//dictionary with...
|
||||
NSDictionary *pk = nil;
|
||||
NSString *sqlString;
|
||||
NSString *key = nil;
|
||||
NSNumber *pkValue = nil;
|
||||
const char *string = NULL;
|
||||
NSArray *primaryKeyAttributes = [entity primaryKeyAttributes];
|
||||
EOAttribute *primAttribute;
|
||||
NSString *sqlString;
|
||||
NSNumber *pkValue = nil;
|
||||
const char *string = NULL;
|
||||
int length = 0;
|
||||
NSString *primaryKeySequenceNameFormat;
|
||||
NSString *sequenceName;
|
||||
EOSQLExpression *expr;
|
||||
|
||||
primaryKeySequenceNameFormat
|
||||
= [(PostgreSQLContext*)[self adaptorContext] primaryKeySequenceNameFormat];
|
||||
NSAssert(primaryKeySequenceNameFormat, @"No primary sequence name format");
|
||||
|
||||
expr = AUTORELEASE([[[_adaptorContext adaptor] expressionClass] new]);
|
||||
sequenceName = [NSString stringWithFormat: primaryKeySequenceNameFormat,
|
||||
[entity primaryKeyRootName]];
|
||||
sequenceName = [expr sqlStringForSchemaObjectName: sequenceName];
|
||||
sqlString = [NSString stringWithFormat: @"SELECT nextval('%@')",
|
||||
sequenceName];
|
||||
[expr setStatement: sqlString];
|
||||
|
||||
[self _cancelResults];
|
||||
[_adaptorContext autoBeginTransaction: NO];
|
||||
|
||||
[self _evaluateExpression: expr
|
||||
withAttributes: _pkAttributeArray];
|
||||
|
||||
if ([self isFetchInProgress] == NO
|
||||
|| [self advanceRow] == NO)
|
||||
{
|
||||
[self _cancelResults];
|
||||
[_adaptorContext autoCommitTransaction];
|
||||
}
|
||||
else
|
||||
{
|
||||
EOAttribute *attr;
|
||||
string = PQgetvalue(_pgResult, _currentResultRow, 0);
|
||||
length = PQgetlength(_pgResult, _currentResultRow, 0);
|
||||
|
||||
attr = [_pkAttributeArray objectAtIndex: 0];
|
||||
pkValue = AUTORELEASE(newValueForBytesLengthAttribute(string,length,attr,_encoding));
|
||||
|
||||
NSAssert(pkValue, @"no pk value");
|
||||
key = [[entity primaryKeyAttributeNames] objectAtIndex: 0];
|
||||
NSAssert(key, @"pk key");
|
||||
|
||||
[self _cancelResults];
|
||||
[_adaptorContext autoCommitTransaction];
|
||||
|
||||
pk = [NSDictionary dictionaryWithObject: pkValue
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
|
||||
if([primaryKeyAttributes count] != 1)
|
||||
{
|
||||
return nil; // We support only simple primary keys
|
||||
}
|
||||
primAttribute = [primaryKeyAttributes objectAtIndex:0];
|
||||
|
||||
if([primAttribute adaptorValueType] != EOAdaptorNumberType)
|
||||
{
|
||||
return nil; // We support only number keys
|
||||
}
|
||||
|
||||
sqlString = [NSString stringWithFormat: @"SELECT nextval('%@_SEQ')",
|
||||
[entity primaryKeyRootName]];
|
||||
|
||||
if ([self isDebugEnabled])
|
||||
{
|
||||
NSLog(@"PostgreSQLAdaptor: '%@'", sqlString);
|
||||
}
|
||||
|
||||
_pgResult = PQexec(_pgConn,[sqlString cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
|
||||
if (PQresultStatus(_pgResult) != PGRES_TUPLES_OK)
|
||||
{
|
||||
|
||||
NSString* errorString=[NSString stringWithCString:PQerrorMessage(_pgConn)
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
[self _cancelResults];
|
||||
|
||||
[NSException raise: PostgreSQLException
|
||||
format: @"SQL expression '%@' caused %@", sqlString, errorString];
|
||||
}
|
||||
|
||||
string = PQgetvalue(_pgResult, 0, 0);
|
||||
length = PQgetlength(_pgResult, 0, 0);
|
||||
|
||||
|
||||
pkValue = newValueForBytesLengthAttribute(string,
|
||||
length,
|
||||
primAttribute,
|
||||
_encoding);
|
||||
// frees the memory
|
||||
[self _cancelResults];
|
||||
|
||||
NSAssert(pkValue, @"no pk value");
|
||||
|
||||
[_adaptorContext autoCommitTransaction];
|
||||
|
||||
pk = [NSDictionary dictionaryWithObject: pkValue
|
||||
forKey: [primAttribute name]];
|
||||
RELEASE(pkValue);
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
@interface PostgreSQLContext : EOAdaptorContext
|
||||
{
|
||||
NSString* _primaryKeySequenceNameFormat;
|
||||
// NSString* _primaryKeySequenceNameFormat;
|
||||
struct
|
||||
{
|
||||
unsigned int didAutoBegin:1;
|
||||
|
@ -57,8 +57,8 @@
|
|||
- (BOOL)autoCommitTransaction;
|
||||
|
||||
// format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name
|
||||
- (void)setPrimaryKeySequenceNameFormat: (NSString*)format;
|
||||
- (NSString*)primaryKeySequenceNameFormat;
|
||||
//- (void)setPrimaryKeySequenceNameFormat: (NSString*)format;
|
||||
//- (NSString*)primaryKeySequenceNameFormat;
|
||||
|
||||
- (BOOL)autoBeginTransaction: (BOOL)force;
|
||||
- (BOOL)autoCommitTransaction;
|
||||
|
|
|
@ -70,9 +70,9 @@ RCS_ID("$Id$")
|
|||
{
|
||||
if ((self = [super initWithAdaptor: adaptor]))
|
||||
{
|
||||
if (adaptor)
|
||||
[self setPrimaryKeySequenceNameFormat:
|
||||
[(PostgreSQLAdaptor*)adaptor primaryKeySequenceNameFormat]];
|
||||
// if (adaptor)
|
||||
// [self setPrimaryKeySequenceNameFormat:
|
||||
// [(PostgreSQLAdaptor*)adaptor primaryKeySequenceNameFormat]];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -306,15 +306,15 @@ RCS_ID("$Id$")
|
|||
}
|
||||
|
||||
/** format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name **/
|
||||
- (void)setPrimaryKeySequenceNameFormat: (NSString*)format
|
||||
{
|
||||
ASSIGN(_primaryKeySequenceNameFormat, format);
|
||||
}
|
||||
|
||||
- (NSString*)primaryKeySequenceNameFormat
|
||||
{
|
||||
return _primaryKeySequenceNameFormat;
|
||||
}
|
||||
//- (void)setPrimaryKeySequenceNameFormat: (NSString*)format
|
||||
//{
|
||||
// ASSIGN(_primaryKeySequenceNameFormat, format);
|
||||
//}
|
||||
//
|
||||
//- (NSString*)primaryKeySequenceNameFormat
|
||||
//{
|
||||
// return _primaryKeySequenceNameFormat;
|
||||
//}
|
||||
|
||||
@end /* PostgreSQLContext */
|
||||
/*
|
||||
|
|
|
@ -113,29 +113,13 @@ RCS_ID("$Id$")
|
|||
|
||||
externalType = [attribute externalType];
|
||||
|
||||
if (!value)
|
||||
{
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"NULL case - value=%@ class=%@",
|
||||
value, [value class]);
|
||||
|
||||
formatted = @"NULL";
|
||||
}
|
||||
else if ([value isEqual: [EONull null]])
|
||||
{
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"EONULL case - value=%@ class=%@",
|
||||
value, [value class]);
|
||||
|
||||
formatted = [value sqlString];
|
||||
}
|
||||
if ((!value) || ((value==[EONull null])))
|
||||
{
|
||||
return @"NULL";
|
||||
}
|
||||
else if ([externalType hasPrefix: @"int"]
|
||||
|| [externalType hasPrefix: @"bigint"])
|
||||
{
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"int case - value=%@ class=%@",
|
||||
value, [value class]);
|
||||
|
||||
formatted = [NSString stringWithFormat: @"%@", value];
|
||||
|
||||
// value was for example 0 length string
|
||||
|
@ -143,95 +127,74 @@ RCS_ID("$Id$")
|
|||
formatted = @"NULL";
|
||||
}
|
||||
else if ([externalType hasPrefix: @"float"])
|
||||
{
|
||||
/*
|
||||
* 12345.67 has a precision of 7 and a scale of 2.
|
||||
*/
|
||||
return [NSString stringWithFormat:@"%@",value];
|
||||
/*
|
||||
unsigned short precision=[attribute precision];
|
||||
int scale=[attribute scale];
|
||||
// As far as I understand, we need to try to do complex things if precision!=0 or scale!=0
|
||||
if (precision==0 && scale==0)
|
||||
{
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"float case - value=%@ class=%@",
|
||||
value, [value class]);
|
||||
|
||||
if (_isNilOrEONull(value))
|
||||
formatted=@"NULL";
|
||||
else
|
||||
{
|
||||
unsigned short precision=[attribute precision];
|
||||
short scale=[attribute scale];
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"float case - value=%@ class=%@ precision=%d scale=%d",
|
||||
value, [value class],precision,scale);
|
||||
// As far as I understand, we need to try to do complex things if precision!=0 or scale!=0
|
||||
if (precision==0 && scale==0)
|
||||
{
|
||||
// just convert it to string...
|
||||
formatted = [NSString stringWithFormat: @"%@", value];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDecimalNumber* decimalValue=nil;
|
||||
if ([value isKindOfClass: PSQLA_NSDecimalNumberClass] == NO)
|
||||
{
|
||||
if ([value isKindOfClass: PSQLA_NSStringClass] == YES)
|
||||
{
|
||||
decimalValue
|
||||
= AUTORELEASE([PSQLA_alloc(NSDecimalNumber) initWithString:value]);
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"float case - value [%@]=%@ ==> decimalValue=%@",
|
||||
value,[value class],decimalValue);
|
||||
}
|
||||
else if ([value respondsToSelector: @selector(doubleValue)])
|
||||
{
|
||||
decimalValue
|
||||
= AUTORELEASE([PSQLA_alloc(NSDecimalNumber) initWithDouble:[value doubleValue]]);
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"float case - value [%@]=%@ ==> decimalValue=%@",
|
||||
value,[value class],decimalValue);
|
||||
}
|
||||
else if ([value respondsToSelector: @selector(floatValue)])
|
||||
{
|
||||
decimalValue
|
||||
= AUTORELEASE([PSQLA_alloc(NSDecimalNumber) initWithFloat:[value floatValue]]);
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"float case - value [%@]=%@ ==> decimalValue=%@",
|
||||
value,[value class],decimalValue);
|
||||
}
|
||||
else if ([value respondsToSelector: @selector(intValue)])
|
||||
{
|
||||
decimalValue
|
||||
= AUTORELEASE([PSQLA_alloc(NSDecimalNumber) initWithInt:[value intValue]]);
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"float case - value [%@]=%@ ==> decimalValue=%@",
|
||||
value,[value class],decimalValue);
|
||||
};
|
||||
if (decimalValue)
|
||||
{
|
||||
NSDecimal decimal;
|
||||
NSDecimalNumberHandler* handler=[NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain // Is Plain OK ?
|
||||
scale:scale
|
||||
raiseOnExactness:YES
|
||||
raiseOnOverflow:YES
|
||||
raiseOnUnderflow:YES
|
||||
raiseOnDivideByZero:YES];
|
||||
decimalValue=[decimalValue decimalNumberByRoundingAccordingToBehavior:handler];
|
||||
decimal=[decimalValue decimalValue];
|
||||
formatted=NSDecimalString(&decimal,nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported type: just convert it to string...
|
||||
formatted = [NSString stringWithFormat: @"%@", value];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// value was for example 0 length string
|
||||
if ([formatted length] == 0)
|
||||
formatted=@"NULL";
|
||||
// just convert it to string...
|
||||
formatted = [NSString stringWithFormat: @"%@", value];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDecimalNumber* decimalValue=nil;
|
||||
if ([value isKindOfClass: PSQLA_NSDecimalNumberClass] == NO)
|
||||
{
|
||||
if ([value isKindOfClass: PSQLA_NSStringClass] == YES)
|
||||
{
|
||||
decimalValue = AUTORELEASE([PSQLA_alloc(NSDecimalNumber)
|
||||
initWithString:value]);
|
||||
}
|
||||
else if ([value respondsToSelector: @selector(doubleValue)])
|
||||
{
|
||||
decimalValue = AUTORELEASE([PSQLA_alloc(NSDecimalNumber)
|
||||
initWithDouble:[value doubleValue]]);
|
||||
}
|
||||
else if ([value respondsToSelector: @selector(floatValue)])
|
||||
{
|
||||
decimalValue = AUTORELEASE([PSQLA_alloc(NSDecimalNumber)
|
||||
initWithFloat:[value floatValue]]);
|
||||
}
|
||||
else if ([value respondsToSelector: @selector(intValue)])
|
||||
{
|
||||
decimalValue = AUTORELEASE([PSQLA_alloc(NSDecimalNumber)
|
||||
initWithInt:[value intValue]]);
|
||||
}
|
||||
if (decimalValue)
|
||||
{
|
||||
NSDecimal decimal;
|
||||
|
||||
NSDecimalNumberHandler* handler=[NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain // Is Plain OK ?
|
||||
scale:scale
|
||||
raiseOnExactness:YES
|
||||
raiseOnOverflow:YES
|
||||
raiseOnUnderflow:YES
|
||||
raiseOnDivideByZero:YES];
|
||||
decimalValue=[decimalValue decimalNumberByRoundingAccordingToBehavior:handler];
|
||||
decimal=[decimalValue decimalValue];
|
||||
formatted=NSDecimalString(&decimal,nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not supported type: just convert it to string...
|
||||
formatted = [NSString stringWithFormat: @"%@", value];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// value was for example 0 length string
|
||||
if ([formatted length] == 0)
|
||||
formatted=@"NULL";
|
||||
*/
|
||||
}
|
||||
else if ([externalType hasPrefix: @"bool"])
|
||||
{
|
||||
EOFLOGObjectLevelArgs(@"EOSQLExpression",
|
||||
@"BOOL case - value=%@ class=%@",
|
||||
value, [value class]);
|
||||
|
||||
if ([value isKindOfClass: PSQLA_NSNumberClass] == YES)
|
||||
{
|
||||
BOOL boolValue = [value boolValue];
|
||||
|
|
|
@ -59,6 +59,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <GNUstepBase/GSLock.h>
|
||||
|
|
|
@ -47,6 +47,7 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include "EOCustomObject.h"
|
||||
|
@ -217,7 +218,7 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
if (size < 1)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"storedValueForKey: ... empty key"];
|
||||
format: @"%s: empty key", __PRETTY_FUNCTION__];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -226,7 +227,11 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
char buf[length + 10];
|
||||
|
||||
strcpy(buf, "validate");
|
||||
[key getCString: &buf[8]];
|
||||
|
||||
[key getCString:&buf[8]
|
||||
maxLength:length
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
buf[8] = toupper((int)buf[8]);
|
||||
buf[length + 8] = ':';
|
||||
buf[length + 9] = 0;
|
||||
|
@ -240,7 +245,6 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return exception;
|
||||
}
|
||||
|
||||
|
@ -302,7 +306,7 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
if (nval != oval &&
|
||||
((nval == nil || oval == nil) || [nval isEqual: oval] == NO))
|
||||
{
|
||||
[self takeValue:nval forKey: path];
|
||||
[self setValue:nval forKey: path];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -429,7 +433,7 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
if (size < 1)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"addObject:toPropertyWithKey: ... empty key"];
|
||||
format: @"%s: empty key", __PRETTY_FUNCTION__];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -440,7 +444,11 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
// Test addToKey:
|
||||
|
||||
strcpy(buf, "addTo");
|
||||
[key getCString: &buf[5]];
|
||||
|
||||
[key getCString:&buf[5]
|
||||
maxLength:size
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
buf[5] = toupper(buf[5]);
|
||||
buf[size+5] = ':';
|
||||
buf[size+6] = '\0';
|
||||
|
@ -479,16 +487,16 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
|
||||
[relArray addObject: object];
|
||||
|
||||
[self takeValue: relArray
|
||||
forKey: key];
|
||||
[self setValue: relArray
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
[self takeValue: object
|
||||
forKey: key];
|
||||
[self setValue: object
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -501,7 +509,7 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
if (size < 1)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"removeObject:fromPropertyWithKey: ... empty key"];
|
||||
format: @"%s: empty key", __PRETTY_FUNCTION__];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -512,7 +520,11 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
// Test removeFromKey:
|
||||
|
||||
strcpy(buf, "removeFrom");
|
||||
[key getCString: &buf[10]];
|
||||
|
||||
[key getCString:&buf[10]
|
||||
maxLength:size
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
buf[10] = toupper(buf[10]);
|
||||
buf[size+10] = ':';
|
||||
buf[size+11] = '\0';
|
||||
|
@ -546,15 +558,15 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
relArray = AUTORELEASE([val mutableCopy]);
|
||||
|
||||
[relArray removeObject: object];
|
||||
[self takeValue: relArray
|
||||
forKey: key];
|
||||
[self setValue: relArray
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self takeValue: nil
|
||||
forKey: key];
|
||||
[self setValue: nil
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -585,8 +597,8 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
}
|
||||
}
|
||||
|
||||
[self takeValue: object
|
||||
forKey: key];
|
||||
[self setValue: object
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -640,8 +652,8 @@ RCS_ID("$Id: EOGenericRecord.m 30111 2010-04-09 10:09:41Z ayers $")
|
|||
}
|
||||
|
||||
// Just set self into object relationship property
|
||||
[object takeValue: self
|
||||
forKey: inverseKey];
|
||||
[object setValue: self
|
||||
forKey: inverseKey];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
|
|
@ -46,11 +46,9 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSInvocation.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOFault.h>
|
||||
|
|
|
@ -53,6 +53,7 @@ RCS_ID("$Id$")
|
|||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOQualifier.h>
|
||||
|
|
|
@ -44,12 +44,10 @@ RCS_ID("$Id$")
|
|||
#include <Foundation/NSDebug.h>
|
||||
#else
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EOQualifier.h>
|
||||
|
|
|
@ -264,8 +264,8 @@ static inline void GDL2_TakeValueForKeyWithImpPtr(id object,IMP* impPtr,id value
|
|||
if (object)
|
||||
{
|
||||
if (!*impPtr)
|
||||
*impPtr=[object methodForSelector:@selector(takeValue:forKey:)];
|
||||
(**impPtr)(object,@selector(takeValue:forKey:),value,key);
|
||||
*impPtr=[object methodForSelector:@selector(setValue:forKey:)];
|
||||
(**impPtr)(object,@selector(setValue:forKey:),value,key);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/NSDebug+GNUstepBase.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <GNUstepBase/GSObjCRuntime.h>
|
||||
|
|
|
@ -38,6 +38,7 @@ RCS_ID("$Id$")
|
|||
#ifndef GNUSTEP
|
||||
#include <GNUstepBase/GNUstep.h>
|
||||
#include <GNUstepBase/GSCategories.h>
|
||||
#include <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#endif
|
||||
|
||||
#include <EOControl/EODeprecated.h>
|
||||
|
|
Loading…
Reference in a new issue