libs-gdl2/EOAccess/EOSQLExpression.m
Dave Wetzel 4878a85bbe * 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
2010-06-09 12:48:33 +00:00

2552 lines
74 KiB
Objective-C

/**
EOSQLExpression.m <title>EOSQLExpression Class</title>
Copyright (C) 2000-2002,2003,2004,2005 Free Software Foundation, Inc.
Author: Mirko Viviani <mirko.viviani@gmail.com>
Date: February 2000
Author: Manuel Guesdon <mguesdon@orange-concept.com>
Date: November 2001
$Revision$
$Date$
<abstract></abstract>
This file is part of the GNUstep Database Library.
<license>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
</license>
**/
#include "config.h"
RCS_ID("$Id$")
#include <string.h>
#ifdef GNUSTEP
#include <Foundation/NSDebug.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSException.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSString.h>
#include <Foundation/NSUserDefaults.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/EOFetchSpecification.h>
#include <EOControl/EOQualifier.h>
#include <EOControl/EOSortOrdering.h>
#include <EOControl/EODebug.h>
#include <EOControl/EONull.h>
#include <EOAccess/EOModel.h>
#include <EOAccess/EOEntity.h>
#include <EOAccess/EOAttribute.h>
#include <EOAccess/EORelationship.h>
#include <EOAccess/EOAdaptor.h>
#include <EOAccess/EOAdaptorContext.h>
#include <EOAccess/EOAdaptorChannel.h>
#include <EOAccess/EOJoin.h>
#include <EOAccess/EOSQLExpression.h>
#include <EOAccess/EOSQLQualifier.h>
#include <EOAccess/EOExpressionArray.h>
#include "EOPrivate.h"
#include "EOEntityPriv.h"
#include "EOAttributePriv.h"
#include "EOSQLExpressionPriv.h"
NSString *EOBindVariableNameKey = @"EOBindVariableNameKey";
NSString *EOBindVariableAttributeKey = @"EOBindVariableAttributeKey";
NSString *EOBindVariableValueKey = @"EOBindVariableValueKey";
NSString *EOBindVariablePlaceHolderKey = @"EOBindVariablePlaceHolderKey";
NSString *EOBindVariableColumnKey = @"EOBindVariableColumnKey";
@interface EOSQLExpression(Private)
+ (id)sqlExpressionWithEntity: (EOEntity *)entity;
@end
@implementation EOSQLExpression
+ (void) initialize
{
static BOOL initialized=NO;
if (!initialized)
{
GDL2_EOAccessPrivateInit();
};
};
+ (id)sqlExpressionWithEntity: (EOEntity *)entity
{
return [[[self alloc] initWithEntity: entity] autorelease];
}
- (id) initWithEntity: (EOEntity *)entity
{
if ((self = [self init]))
{
ASSIGN(_entity, entity);
_aliasesByRelationshipPath = [NSMutableDictionary new];
[_aliasesByRelationshipPath setObject: @"t0"
forKey: @""];
_contextStack = [NSMutableArray new];
[_contextStack addObject: @""];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"added '%@' (t0) in contextStack => %@",
@"",_contextStack);
/*NOT now _listString = [NSMutableString new];
_valueListString = [NSMutableString new];
_joinClauseString = [NSMutableString new];
_orderByString = [NSMutableString new];
_bindings = [NSMutableArray new];
*/
_alias++;
}
return self;
}
- (void)dealloc
{
DESTROY(_aliasesByRelationshipPath);
DESTROY(_entity);
DESTROY(_listString);
DESTROY(_valueListString);
DESTROY(_whereClauseString);
DESTROY(_joinClauseString);
DESTROY(_orderByString);
DESTROY(_bindings);
DESTROY(_contextStack);
DESTROY(_statement);
[super dealloc];
}
+ (EOSQLExpression *)expressionForString: (NSString *)string
{
EOSQLExpression *exp = [self sqlExpressionWithEntity: nil];
ASSIGN(exp->_statement, string);
return exp;
}
+ (EOSQLExpression *)insertStatementForRow: (NSDictionary *)row
entity: (EOEntity *)entity
{
EOSQLExpression *sqlExpression;
if (!entity)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Entity of insertStatementForRow:entity: can't be the nil object"];
sqlExpression = [self sqlExpressionWithEntity: entity];
NSAssert(sqlExpression, @"No SQLExpression");
[sqlExpression setUseAliases: NO];
[sqlExpression prepareInsertExpressionWithRow: row];
return sqlExpression;
}
+ (EOSQLExpression *)updateStatementForRow: (NSDictionary *)row
qualifier: (EOQualifier *)qualifier
entity: (EOEntity *)entity
{
EOSQLExpression *sqlExpression;
if(!row || ![row count])
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Row of updateStatementForRow:qualifier:entity: "
@"can't be the nil object or empty dictionary"];
if (!qualifier)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Qualifier of updateStatementForRow:qualifier:entity: "
@"can't be the nil object"];
if (!entity)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Entity of updateStatementForRow:qualifier:entity: "
@"can't be the nil object"];
sqlExpression = [self sqlExpressionWithEntity: entity];
NSAssert(sqlExpression, @"No SQLExpression");
[sqlExpression setUseAliases: NO];
[sqlExpression prepareUpdateExpressionWithRow: row
qualifier: qualifier];
return sqlExpression;
}
+ (EOSQLExpression *)deleteStatementWithQualifier: (EOQualifier *)qualifier
entity: (EOEntity *)entity
{
EOSQLExpression *sqlExpression;
if (!qualifier)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Qualifier of deleteStatementWithQualifier:entity: "
@"can't be the nil object"];
if (!entity)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Entity of deleteStatementWithQualifier:entity: "
@"can't be the nil object"];
sqlExpression = [self sqlExpressionWithEntity: entity];
[sqlExpression prepareDeleteExpressionForQualifier: qualifier];
return sqlExpression;
}
+ (EOSQLExpression *)selectStatementForAttributes: (NSArray *)attributes
lock: (BOOL)flag
fetchSpecification: (EOFetchSpecification *)fetchSpecification
entity: (EOEntity *)entity
{
EOSQLExpression *sqlExpression;
if (!attributes || ![attributes count])
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Attributes of selectStatementForAttributes:lock:fetchSpecification:entity: "
@"can't be the nil object or empty array"];
if (!fetchSpecification)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: FetchSpecification of selectStatementForAttributes:lock:fetchSpecification:entity: "
@"can't be the nil object"];
if (!entity)
[NSException raise: NSInvalidArgumentException
format: @"EOSQLExpression: Entity of selectStatementForAttributes:lock:fetchSpecification:entity: "
@"can't be the nil object"];
sqlExpression = [self sqlExpressionWithEntity: entity];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlExpression=%@",
sqlExpression);
[sqlExpression setUseAliases: YES];
[sqlExpression prepareSelectExpressionWithAttributes: attributes
lock: flag
fetchSpecification: fetchSpecification];
return sqlExpression;
}
- (NSMutableDictionary *)aliasesByRelationshipPath
{
return _aliasesByRelationshipPath;
}
- (EOEntity *)entity
{
return _entity;
}
- (NSMutableString *)listString
{
//OK
if (!_listString)
_listString = [NSMutableString new];
return _listString;
}
- (NSMutableString *)valueList
{
if (!_valueListString)
_valueListString = [NSMutableString new];
return _valueListString;
}
- (NSMutableString *)joinClauseString
{
if (!_joinClauseString)
_joinClauseString = [NSMutableString new];
return _joinClauseString;
}
- (NSMutableString *)orderByString
{
//OK
if (!_orderByString)
_orderByString = [NSMutableString new];
return _orderByString;
}
- (NSString *)whereClauseString
{
if (!_whereClauseString)
_whereClauseString = [NSMutableString new];
return _whereClauseString;
}
- (NSString *)statement
{
return _statement;
}
- (void)setStatement:(NSString *)statement
{
ASSIGN(_statement, statement);
}
- (NSString *)lockClause
{
[self subclassResponsibility: _cmd];
return nil;
}
- (NSString *)tableListWithRootEntity: (EOEntity*)entity
{
//self useAliases //ret 1 for select,0 for insert
//enity externalName
//self sqlStringForSchemaObjectName:eznti extnam//not always
// insert: ret quotation_place ?? / select: ret quotation_place t0
NSMutableString *entitiesString = [NSMutableString string];
IMP entitiesStringAppendStringIMP = NULL;
NSEnumerator *relationshipEnum = nil;
NSString *relationshipPath = nil;
EOEntity *currentEntity = nil;
int i = 0;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"entity=%@", entity);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_aliasesByRelationshipPath=%@",
_aliasesByRelationshipPath);
relationshipEnum = [_aliasesByRelationshipPath keyEnumerator];
while ((relationshipPath = [relationshipEnum nextObject]))
{
currentEntity = entity;
if (i)
GDL2_AppendStringWithImp(entitiesString,
entitiesStringAppendStringIMP,@", ");
else
entitiesStringAppendStringIMP = [entitiesString methodForSelector:@selector(appendString:)];
if ([relationshipPath isEqualToString: @""])
{
NSString *tableName = [currentEntity externalName];
tableName = [self sqlStringForSchemaObjectName: tableName];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"entity %p named %@: "
@"externalName=%@ tableName=%@",
currentEntity, [currentEntity name],
[currentEntity externalName], tableName);
NSAssert1([[currentEntity externalName] length]>0,
@"No external name for entity %@",
[currentEntity name]);
GDL2_AppendStringWithImp(entitiesString,
entitiesStringAppendStringIMP,tableName);
if (_flags.useAliases)
[entitiesString appendFormat: @" %@",
[_aliasesByRelationshipPath
objectForKey: relationshipPath]];
}
else
{
NSEnumerator *defEnum = nil;
NSArray *defArray = nil;
NSString *relationshipString = nil;
NSString *tableName = nil;
defArray = [relationshipPath componentsSeparatedByString: @"."];
defEnum = [defArray objectEnumerator];
while ((relationshipString = [defEnum nextObject]))
{
// use anyRelationshipNamed: to find hidden relationship too
EORelationship *relationship=[currentEntity
anyRelationshipNamed: relationshipString];
NSAssert2(relationship,@"No relationship named %@ in entity %@",
relationshipString,
[currentEntity name]);
NSAssert2(currentEntity,@"No destination entity. Entity %@ relationship = %@",
[currentEntity name],
relationship);
currentEntity = [relationship destinationEntity];
}
tableName = [currentEntity externalName];
tableName = [self sqlStringForSchemaObjectName: tableName];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"entity %p named %@: "
@"externalName=%@ tableName=%@",
currentEntity, [currentEntity name],
[currentEntity externalName], tableName);
NSAssert1([[currentEntity externalName] length]>0,
@"No external name for entity %@",
[currentEntity name]);
GDL2_AppendStringWithImp(entitiesString,
entitiesStringAppendStringIMP,tableName);
if (_flags.useAliases)
{
NSString *alias = [_aliasesByRelationshipPath
objectForKey: relationshipPath];
GDL2_AppendStringWithImp(entitiesString,
entitiesStringAppendStringIMP,@" ");
GDL2_AppendStringWithImp(entitiesString,
entitiesStringAppendStringIMP,alias);
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"appending alias %@ in entitiesString",
alias);
}
}
i++;
}
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"entitiesString=%@",
entitiesString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return entitiesString;
}
- (void)prepareInsertExpressionWithRow: (NSDictionary *)row
{
//OK
EOEntity *rootEntity = nil;
NSString *tableList = nil;
NSEnumerator *rowEnum;
NSString *attributeName;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"row=%@", row);
NS_DURING //Debugging Purpose
{
rowEnum = [row keyEnumerator];
while ((attributeName = [rowEnum nextObject]))
{
EOAttribute *attribute = [_entity anyAttributeNamed: attributeName];
id rowValue = [row objectForKey: attributeName];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute name=%@",
attributeName);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rowValue=%@", rowValue);
/*NO: in addInsertListAttribute id value=[self sqlStringForValue:rowValue
attributeNamed:attributeName];*/
[self addInsertListAttribute: attribute
value: rowValue];
}
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
NS_DURING //Debugging Purpose
{
rootEntity = [self _rootEntityForExpression];
tableList = [self tableListWithRootEntity: _entity];
ASSIGN(_statement, [self assembleInsertStatementWithRow: row
tableList: tableList
columnList: _listString
valueList: _valueListString]);
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_statement=%@", _statement);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
- (void)prepareUpdateExpressionWithRow: (NSDictionary *)row
qualifier: (EOQualifier *)qualifier
{
//OK
EOEntity *rootEntity = nil;
NSString *whereClauseString = nil;
NSString *tableList = nil;
NSString *statement = nil;
NSEnumerator *rowEnum;
NSString *attributeName;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
rowEnum = [row keyEnumerator];
while ((attributeName = [rowEnum nextObject]))
{
id attribute = [_entity attributeNamed: attributeName];
id value = [row objectForKey: attributeName];
[self addUpdateListAttribute: attribute
value: value];
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"qualifier=%@", qualifier);
whereClauseString = [(id <EOQualifierSQLGeneration>)qualifier sqlStringForSQLExpression: self];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"whereClauseString=%@",
whereClauseString);
ASSIGN(_whereClauseString, whereClauseString);
rootEntity = [self _rootEntityForExpression];
tableList = [self tableListWithRootEntity: rootEntity];
statement = [self assembleUpdateStatementWithRow: row
qualifier: qualifier
tableList: tableList
updateList: _listString
whereClause: whereClauseString];
ASSIGN(_statement, statement);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
- (void)prepareDeleteExpressionForQualifier: (EOQualifier *)qualifier
{
ASSIGN(_whereClauseString, [(id)qualifier sqlStringForSQLExpression: self]);
ASSIGN(_statement, [self assembleDeleteStatementWithQualifier: qualifier
tableList: [self tableListWithRootEntity: _entity]
whereClause: ([_whereClauseString length] ?
_whereClauseString : nil)]);
}
/*
//TC:
- (void)prepareSelectExpressionWithAttributes:(NSArray *)attributes
lock:(BOOL)flag
fetchSpecification:(EOFetchSpecification *)fetchSpecification
{
NSEnumerator *attrEnum, *sortEnum;
EOAttribute *attribute;
EOSortOrdering *sort;
NSString *tableList;
NSString *lockClause = nil;
NSArray *sortOrderings;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
// Turbocat (RawRow Additions)
if ([fetchSpecification rawRowKeyPaths]) {
// fill _aliasesByRelationshipPath before calling addSelectListAttribute
NSEnumerator *keyPathEnum = [[fetchSpecification rawRowKeyPaths] objectEnumerator];
NSString *keyPath;
EOExpressionArray *expressionArray;
while (keyPath = [keyPathEnum nextObject]) {
if([keyPath isNameOfARelationshipPath]) {
// get relationships
NSString *newKeyPath = [keyPath stringByDeletingPathExtension]; // cut attributename
if (![_aliasesByRelationshipPath objectForKey:newKeyPath]) {
//int count = [[_aliasesByRelationshipPath allKeys] count];
NSString *prefix = [NSString stringWithFormat:@"t%d",_alias++];
[_aliasesByRelationshipPath setObject:prefix forKey:newKeyPath];
}
}
}
//NSLog(@"_aliasesByRelationshipPath = %@", _aliasesByRelationshipPath);
} // Turbocat (RawRow Additions)
attrEnum = [attributes objectEnumerator];
while((attribute = [attrEnum nextObject]))
{
[self addSelectListAttribute:attribute];
}
ASSIGN(_whereClauseString, [(id)[fetchSpecification qualifier]
sqlStringForSQLExpression:self]);
sortOrderings = [fetchSpecification sortOrderings];
sortEnum = [sortOrderings objectEnumerator];
while((sort = [sortEnum nextObject]))
[self addOrderByAttributeOrdering:sort];
[self joinExpression];
tableList = [self tableListWithRootEntity:_entity];
if(flag) lockClause = [self lockClause];
ASSIGN(_statement, [self assembleSelectStatementWithAttributes:attributes
lock:flag
qualifier:[fetchSpecification qualifier]
fetchOrder:sortOrderings
selectString:nil //TODO
columnList:_listString
tableList:tableList
whereClause:([_whereClauseString length] ?
_whereClauseString : nil)
joinClause:([_joinClauseString length] ?
_joinClauseString : nil)
orderByClause:([_orderByString length] ?
_orderByString : nil)
lockClause:lockClause]);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
*/
- (void)prepareSelectExpressionWithAttributes: (NSArray *)attributes
lock: (BOOL)flag
fetchSpecification: (EOFetchSpecification *)fetchSpecification
{
EOQualifier *fetchQualifier = nil;
EOQualifier *restrictingQualifier = nil;
NSString *whereClauseString = nil;
NSArray *sortOrderings = nil;
EOEntity *rootEntity = nil;
NSString *tableList = nil;
NSString *lockClauseString = nil;
BOOL usesDistinct = NO;
NSString *statement = nil;
NSString *selectCommand = nil;
//Add Attributes to listString
int i, count = [attributes count];
EOFLOGObjectFnStartCond(@"EOSQLExpression");
//OK
for (i = 0; i < count; i++)
{
EOAttribute *attribute = [attributes objectAtIndex: i];
/* Add non-relationship definitions such as aggregates. */
if ([attribute isFlattened])
{
NSMutableString *listString = [self listString];
NSString *definition = [attribute definition];
if (definition)
{
NSRange range = [definition rangeOfString:@"."];
if (range.length == 0)
{
[self appendItem: definition
toListString: listString];
}
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"flattened attribute=%@",
attribute);
}
else
[self addSelectListAttribute: attribute];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_listString=%@",
_listString);
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_listString=%@", _listString);
fetchQualifier = [fetchSpecification qualifier]; //OK
//call fetchSpecification -isDeep
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"fetchQualifier=%@",
fetchQualifier);
restrictingQualifier = [_entity restrictingQualifier];
if (fetchQualifier && restrictingQualifier)
{
fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers:fetchQualifier, restrictingQualifier, nil];
AUTORELEASE(fetchQualifier);
}
else
{
fetchQualifier = fetchQualifier ? fetchQualifier : restrictingQualifier;
}
//Build Where Clause
whereClauseString = [(id<EOQualifierSQLGeneration>)fetchQualifier sqlStringForSQLExpression: self];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"whereClauseString=%@",
whereClauseString);
ASSIGN(_whereClauseString, whereClauseString);
//Build Ordering Clause
sortOrderings = [fetchSpecification sortOrderings];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sortOrderings=%@",
sortOrderings);
if ([sortOrderings count] > 0)
{
int i, count = [sortOrderings count];
for (i = 0; i < count; i++)
{
EOSortOrdering *order = [sortOrderings objectAtIndex: i];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"order=%@", order);
NSAssert3([order isKindOfClass: [EOSortOrdering class]],
@"order is not a EOSortOrdering but a %@: %p %@",
[order class],
order,
order);
[self addOrderByAttributeOrdering: order];
}
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_listString=%@", _listString);
[self joinExpression];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_joinClauseString=%@",
_joinClauseString);
rootEntity = [self _rootEntityForExpression];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rootEntity=%@",
[rootEntity name]);
//Build Table List
tableList = [self tableListWithRootEntity: rootEntity];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"tableList=%@", tableList);
//Build LockClause
if (flag)
lockClauseString = [self lockClause];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"lockClauseString=%@",
lockClauseString);
//Build UseDistinct Clause
usesDistinct = [fetchSpecification usesDistinct];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"usesDistinct=%d", usesDistinct);
if (usesDistinct)
selectCommand = @"SELECT distinct ";
else
selectCommand = @"SELECT ";
//Now Build Statement
statement = [self assembleSelectStatementWithAttributes: attributes
lock: flag
qualifier: fetchQualifier
fetchOrder: sortOrderings
selectString: selectCommand
columnList: _listString
tableList: tableList
whereClause: ([_whereClauseString length] > 0
? _whereClauseString : nil)
joinClause: ([_joinClauseString length] > 0
? _joinClauseString : nil)
orderByClause: ([_orderByString length] > 0
? _orderByString : nil)
lockClause: lockClauseString];
ASSIGN(_statement, statement);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
- (NSString *)assembleJoinClauseWithLeftName: (NSString *)leftName
rightName: (NSString *)rightName
joinSemantic: (EOJoinSemantic)semantic
{
NSString *op = nil;
NSString *joinClause = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"join parts=%@ %d %@",
leftName,
(int)semantic,
rightName);
//call [self _sqlStringForJoinSemantic:semantic matchSemantic:2
//[self _sqlStringForJoinSemantic:semantic matchSemantic:3
//the 2 ret nil
switch (semantic)
{
case EOInnerJoin:
op = @"=";
break;
case EOLeftOuterJoin:
op = @"*=";
break;
case EORightOuterJoin:
op = @"=*";
break;
case EOFullOuterJoin:
break;
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"op= '%@'", op);
if (op)
joinClause = [NSString stringWithFormat: @"%@ %@ %@",
leftName,
op,
rightName]; //TODO
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joinClause=%@", joinClause);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return joinClause;
}
- (void)addJoinClauseWithLeftName: (NSString *)leftName
rightName: (NSString *)rightName
joinSemantic: (EOJoinSemantic)semantic
{
NSString *joinClause = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"join parts=%@ %d %@",
leftName,
(int)semantic,
rightName);
joinClause = [self assembleJoinClauseWithLeftName: leftName
rightName: rightName
joinSemantic: semantic];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joinClause=%@",
joinClause);
if (joinClause)
{
NSMutableString *joinClauseString = [self joinClauseString];
if (![joinClauseString isEqualToString: @""])
[joinClauseString appendString: @" AND "];
[joinClauseString appendString: joinClause];
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_joinClauseString=%@",
_joinClauseString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
/** Build join expression for all used relationships (call this) after all other query parts construction) **/
- (void)joinExpression
{
EOEntity *entity = nil;
NSEnumerator *relationshipEnum;
NSString *relationshipPath;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_aliasesByRelationshipPath=%@",
_aliasesByRelationshipPath);
// Iterate on each used relationship
relationshipEnum = [_aliasesByRelationshipPath keyEnumerator];
while((relationshipPath = [relationshipEnum nextObject]))
{
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"relationshipPath=%@",
relationshipPath);
// If this is not the base (root) one
if (![relationshipPath isEqualToString: @""])
{
EOQualifier *auxiliaryQualifier = nil;
EORelationship *rel = nil;
NSArray *joins = nil;
int i, count=0;
//Get the root entity if we haven't got it before
if (!entity)
entity=[self entity];
// Get the relationship for this path (non flattened by design)
rel = [entity relationshipForPath: relationshipPath];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rel=%@", rel);
NSAssert2(rel, @"No relationship for path %@ in entity %@",
relationshipPath,
[entity name]);
//Get the auxiliary qualifier for this relationship
auxiliaryQualifier = [rel auxiliaryQualifier];
if (auxiliaryQualifier)
{
NSEmitTODO(); //TODO
[self notImplemented:_cmd];
}
// Get relationship joins
joins = [rel joins];
count = [joins count];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joins=%@", joins);
// Iterate on each join
for (i = 0; i < count; i++)
{
NSString *sourceRelationshipPath = nil;
NSArray *sourceRelationshipPathArray;
//Get the join
EOJoin *join=[joins objectAtIndex:i];
// Get source and destination attributes
EOAttribute *sourceAttribute = [join sourceAttribute];
EOAttribute *destinationAttribute = [join destinationAttribute];
NSString *sourceAttributeAlias = nil;
NSString *destinationAttributeAlias = nil;
// Build the source relationshipPath
sourceRelationshipPathArray =
[relationshipPath componentsSeparatedByString: @"."];
sourceRelationshipPathArray =
[sourceRelationshipPathArray
subarrayWithRange:
NSMakeRange(0,[sourceRelationshipPathArray count] - 1)];
sourceRelationshipPath = [sourceRelationshipPathArray
componentsJoinedByString: @"."];
// Get the alias for sourceAttribute
sourceAttributeAlias = [self
_aliasForRelatedAttribute:
sourceAttribute
relationshipPath:
sourceRelationshipPath];
// Get the alias for destinationAttribute
destinationAttributeAlias =
[self _aliasForRelatedAttribute: destinationAttribute
relationshipPath: relationshipPath];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"addJoin=%@ %d %@",
sourceAttributeAlias,
(int)[rel joinSemantic],
destinationAttributeAlias);
// Add to join clause
[self addJoinClauseWithLeftName: sourceAttributeAlias
rightName: destinationAttributeAlias
joinSemantic: [rel joinSemantic]];
}
}
}
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
- (NSString *)assembleInsertStatementWithRow: (NSDictionary *)row
tableList: (NSString *)tableList
columnList: (NSString *)columnList
valueList: (NSString *)valueList
{
//OK
if (columnList)
return [NSString stringWithFormat: @"INSERT INTO %@ (%@) VALUES (%@)",
tableList, columnList, valueList];
else
return [NSString stringWithFormat: @"INSERT INTO %@ VALUES (%@)",
tableList, valueList];
}
- (NSString *)assembleUpdateStatementWithRow: (NSDictionary *)row
qualifier: (EOQualifier *)qualifier
tableList: (NSString *)tableList
updateList: (NSString *)updateList
whereClause: (NSString *)whereClause
{
return [NSString stringWithFormat: @"UPDATE %@ SET %@ WHERE %@",
tableList, updateList, whereClause];
}
- (NSString *)assembleDeleteStatementWithQualifier: (EOQualifier *)qualifier
tableList: (NSString *)tableList
whereClause: (NSString *)whereClause
{
return [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@",
tableList, whereClause];
}
- (NSString *)assembleSelectStatementWithAttributes: (NSArray *)attributes
lock: (BOOL)lock
qualifier: (EOQualifier *)qualifier
fetchOrder: (NSArray *)fetchOrder
selectString: (NSString *)selectString
columnList: (NSString *)columnList
tableList: (NSString *)tableList
whereClause: (NSString *)whereClause
joinClause: (NSString *)joinClause
orderByClause: (NSString *)orderByClause
lockClause: (NSString *)lockClause
{ //TODO selectString ??
NSMutableString *sqlString;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributes=%@", attributes);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"qualifier=%@", qualifier);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"fetchOrder=%@", fetchOrder);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectString=%@", selectString);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"columnList=%@", columnList);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"tableList=%@", tableList);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"whereClause=%@", whereClause);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"joinClause=%@", joinClause);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"orderByClause=%@", orderByClause);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"lockClause=%@", lockClause);
sqlString = [NSMutableString stringWithFormat: @"SELECT %@ FROM %@",
columnList, tableList];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
if ([lockClause length] > 0)
[sqlString appendFormat: @" %@", lockClause];
if ([whereClause length] == 0)
whereClause = nil;
if ([joinClause length] == 0)
joinClause = nil;
if (whereClause && joinClause)
[sqlString appendFormat: @" WHERE (%@) AND (%@)",
whereClause, joinClause];
else if (whereClause || joinClause)
[sqlString appendFormat: @" WHERE %@",
(whereClause
? whereClause
: joinClause)];
if ([orderByClause length] > 0)
[sqlString appendFormat: @" ORDER BY %@", orderByClause];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (void)addSelectListAttribute: (EOAttribute *)attribute
{
//OK
NSMutableString *listString;
NSString *string;
NSString *sqlStringForAttribute = [self sqlStringForAttribute:attribute];
NSAssert1(sqlStringForAttribute,@"No sqlString for attribute: %@",attribute);
string = [[self class] formatSQLString: sqlStringForAttribute
format: [attribute readFormat]];
listString = [self listString];
[self appendItem: string
toListString: listString];
}
- (void)addInsertListAttribute: (EOAttribute *)attribute
value: (NSString *)value
{
//OK
NSMutableString *valueList=nil;
NSString *writeFormat=nil;
NSString *valueSQLString=nil;
NSMutableString *listString;
NSString *attributeSQLString=nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute name=%@",
[attribute name]);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@", value);
listString = [self listString];
NS_DURING // debug purpose
{
attributeSQLString = [self sqlStringForAttribute: attribute];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeSQLString=%@",
attributeSQLString);
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
NS_DURING // debug purpose
{
[self appendItem: attributeSQLString
toListString: listString];
valueSQLString = [self sqlStringForValue: value
attributeNamed: [attribute name]];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@",
valueSQLString);
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
NS_DURING // debug purpose
{
writeFormat = [attribute writeFormat];
if ([writeFormat length] > 0)
{
NSEmitTODO(); //TODO
NSDebugMLog(@"writeFormat '%@' not yet handled",writeFormat);
}
valueList = [self valueList];
[self appendItem: valueSQLString
toListString: valueList];
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
- (void)addUpdateListAttribute: (EOAttribute *)attribute
value: (NSString *)value
{
//OK
NSString *sqlStringToAdd;
NSMutableString *listString;
NSString *attributeSQLString;
NSString *valueSQLString;
NSString *writeFormat;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
attributeSQLString = [self sqlStringForAttribute: attribute];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeSQLString=%@",
attributeSQLString);
valueSQLString = [self sqlStringForValue: value
attributeNamed: [attribute name]];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@",
valueSQLString);
writeFormat = [attribute writeFormat];
if ([writeFormat length] > 0)
{
NSEmitTODO(); //TODO
NSDebugMLog(@"writeFormat '%@' not yet handled",writeFormat);
}
listString = [self listString];
sqlStringToAdd = [NSString stringWithFormat: @"%@ = %@",
attributeSQLString,
valueSQLString];
[self appendItem: sqlStringToAdd
toListString: listString];
EOFLOGObjectFnStopCond(@"EOSQLExpression");
}
+ (NSString *)formatStringValue: (NSString *)string
{
NSString *formatted;
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" string=%@", string);
if (string == nil)
[NSException raise: NSInternalInconsistencyException
format: @"EOSQLExpression: Argument of formatStringValue: "
@"can't be a nil object"];
formatted = [NSString stringWithFormat: @"%@%@%@", @"'", string, @"'"];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" formatted=%@", formatted);
return formatted;
}
+ (NSString *)formatValue: (id)value
forAttribute: (EOAttribute *)attribute
{
//mirko new:return [value sqlString];
NSString *formattedValue = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" value=%@ class=%@",
value, [value class]);
NS_DURING //debug purpose
{
if (!value)
formattedValue = @"NULL";
else
{
NSString *string;
string = [value sqlString];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" value %p=%@ null %p=%@",
value, value, GDL2_EONull, GDL2_EONull);
if (value == GDL2_EONull)
formattedValue = string;
else
formattedValue = [self formatSQLString: [self formatStringValue:
string]
format: [attribute readFormat]];
}
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return formattedValue;
}
+ (NSString *)formatSQLString: (NSString *)sqlString
format: (NSString *)format
{
NSString *formatted = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" sqlString=%@ format=%@",
sqlString, format);
NSAssert1([sqlString length] > 0, @"No sqlString (%p)", sqlString);
NS_DURING //debug purpose
{
if (!format)
formatted = sqlString;
else
{
const char *p = [format cString];
char *s;
NSMutableString *str = [NSMutableString stringWithCapacity:
[format length]];
IMP appendStringIMP = [str methodForSelector:@selector(appendString:)];
while ((s = strchr(p, '%')))
{
switch (*(s + 1))
{
case '%':
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p+1));
break;
case 'P':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
[str appendString: sqlString];
break;
default:
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
break;
}
p = s + 2;
}
if (*p)
GDL2_AppendStringWithImp(str,appendStringIMP,[NSString stringWithCString: p]);
formatted = str;
}
}
NS_HANDLER
{
NSDebugMLog(@"EXCEPTION %@", localException);
[localException raise];
}
NS_ENDHANDLER;
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" formatted=%@", formatted);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return formatted;
}
//operation must have space before and after. Example: @" AND "
- (NSString*) sqlStringForArrayOfQualifiers: (NSArray*)qualifiers
operation: (NSString*)operation
{
//OK
NSMutableString *sqlString = nil;
int i, count;
int nb=0;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"operation=%@ qualifiers=%@",
operation, qualifiers);
count = [qualifiers count];
for (i = 0; i < count; i++)
{
NSString *tmpSqlString=nil;
EOQualifier<EOQualifierSQLGeneration> *qualifier
= [qualifiers objectAtIndex: i];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"qualifier=%@",
qualifier);
tmpSqlString=[qualifier sqlStringForSQLExpression:self];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"qualifier=%@ tmpSqlString=%@",
qualifier, tmpSqlString);
if (tmpSqlString)
{
if (!sqlString)
sqlString = (NSMutableString*)[NSMutableString string];
if (nb > 0)
[sqlString appendString: operation];
[sqlString appendString: tmpSqlString];
nb++;
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@",
sqlString);
}
}
if (nb > 1)
{
[sqlString insertString: @"(" atIndex: 0];
[sqlString appendString: @")"];
}
else if (nb == 0)
sqlString = nil;
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"operation=%@ qualifiers=%@ count=%d nb=%d sqlString=%@",
operation, qualifiers, count, nb, sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (NSString *)sqlStringForConjoinedQualifiers: (NSArray *)qualifiers
{
//OK
NSString *sqlString;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
sqlString = [self sqlStringForArrayOfQualifiers: qualifiers
operation: @" AND "];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (NSString *)sqlStringForDisjoinedQualifiers: (NSArray *)qualifiers
{
//OK
NSString *sqlString;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
sqlString = [self sqlStringForArrayOfQualifiers: qualifiers
operation: @" OR "];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (NSString *)sqlStringForNegatedQualifier:(EOQualifier *)qualifier
{
NSString *sqlQual = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
sqlQual = [(id)qualifier sqlStringForSQLExpression: self];
if (sqlQual)
sqlQual = [NSString stringWithFormat:@"not (%@)", sqlQual];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlQual=%@", sqlQual);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlQual;
}
- (NSString *)sqlStringForKeyValueQualifier: (EOKeyValueQualifier *)qualifier
{
//Near OK
NSString* sqlString=nil;
NSString* valueSQLString=nil;
NSString* selectorSQLString=nil;
NSString *key = nil;
id value=nil;
NSString* attributeSQLString=nil;
EOAttribute* attribute=nil;
NSString* readFormat=nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"qualifier=%@", qualifier);
NSAssert2([qualifier isKindOfClass:[EOKeyValueQualifier class]],
@"qualifier is not a EOKeyValueQualifier but a %@: %@",
[qualifier class],
qualifier);
key = [qualifier key];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"key=%@", key);
NSAssert1([key length]>0,
@"No key in EOKeyValueQualifier: %@",qualifier);
value = [qualifier value];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@", value);
attributeSQLString = [self sqlStringForAttributeNamed: key];
NSAssert1(attributeSQLString, @"No sqlStringForAttributeNamed:%@", key);
EOFLOGObjectLevelArgs(@"EOSQLExpression",@"attributeSQLString=%@",
attributeSQLString);
attribute = [_entity attributeForPath: key];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute);
NSAssert3(attribute,
@"No attribute forKeyPath: '%@' in entity named '%@' in EOKeyValueQualifier: %@",
key,_entity,qualifier);
readFormat = [attribute readFormat];
if (readFormat)
{
NSEmitTODO(); //TODO
NSDebugMLog(@"readFormat '%@' not yet handled",readFormat);
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@ qualifier=%@ [qualifier selector]=%p %@",
valueSQLString,
qualifier,
[qualifier selector],
NSStringFromSelector([qualifier selector]));
selectorSQLString = [self sqlStringForSelector: [qualifier selector]
value: value];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectorSQLString=%@",
selectorSQLString);
if (sel_isEqual([qualifier selector], EOQualifierOperatorLike))
{
value = [[self class] sqlPatternFromShellPattern: value];
valueSQLString = [self sqlStringForValue: value
attributeNamed: key];
}
else if (sel_isEqual([qualifier selector], EOQualifierOperatorCaseInsensitiveLike))
{
value = [[self class] sqlPatternFromShellPattern: value];
valueSQLString = [self sqlStringForValue: value
attributeNamed: key];
attributeSQLString = [NSString stringWithFormat: @"UPPER(%@)",
attributeSQLString];
valueSQLString = [NSString stringWithFormat: @"UPPER(%@)",
valueSQLString];
}
else
valueSQLString = [self sqlStringForValue: value
attributeNamed: key];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeSQLString=%@",
attributeSQLString);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"selectorSQLString=%@",
selectorSQLString);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"valueSQLString=%@",
valueSQLString);
sqlString = [NSString stringWithFormat: @"%@ %@ %@",
attributeSQLString,
selectorSQLString,
valueSQLString];
/*
NSString* sqlString = [NSString stringWithFormat: @"%@ %@ %@",
[[self class] formatSQLString:
[self sqlStringForAttributeNamed:key]
format:
[[_entity attributeNamed:key]
readFormat]],
selString,
valueString];
*/
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString; //return someting like t1.label = 'XXX'
}
- (NSString *)sqlStringForKeyComparisonQualifier: (EOKeyComparisonQualifier *)qualifier
{
return [NSString stringWithFormat:@"%@ %@ %@",
[[self class] formatSQLString:
[self sqlStringForAttributeNamed:
[qualifier leftKey]]
format:
[[_entity attributeNamed:
[qualifier leftKey]]
readFormat]],
[self sqlStringForSelector:[qualifier selector] value:nil],
[[self class] formatSQLString:
[self sqlStringForAttributeNamed:
[qualifier rightKey]]
format:[[_entity attributeNamed:
[qualifier rightKey]]
readFormat]]];
}
- (NSString *)sqlStringForValue:(NSString *)valueString
caseInsensitiveLikeKey:(NSString *)keyString
{
[self notImplemented:_cmd]; //TODO
return nil;
}
- (void)addOrderByAttributeOrdering:(EOSortOrdering *)sortOrdering
{
SEL orderSelector = NULL;
NSString *orderStringFormat = nil;
NSString *keyString = nil;
id key = nil;
orderSelector = [sortOrdering selector];
if (sel_isEqual(orderSelector, EOCompareAscending))
orderStringFormat = @"(%@) asc";
else if (sel_isEqual(orderSelector, EOCompareDescending))
orderStringFormat = @"(%@) desc";
else if (sel_isEqual(orderSelector, EOCompareCaseInsensitiveAscending))
orderStringFormat = @"upper(%@) asc";
else if (sel_isEqual(orderSelector, EOCompareCaseInsensitiveDescending))
orderStringFormat = @"upper(%@) desc";
key = [sortOrdering key];
NSAssert1(key,
@"Key in sort ordering",
sortOrdering);
keyString = [self sqlStringForAttributeNamed: key];//TODO VERIFY
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"keyString=%@", keyString);
NSAssert1(keyString,
@"No sql string for key named \"%@\"",
key);
[self appendItem: [NSString stringWithFormat: orderStringFormat,
keyString]
toListString: [self orderByString]];
}
+ (BOOL)useQuotedExternalNames
{
return [[NSUserDefaults standardUserDefaults]
boolForKey: @"EOAdaptorQuotesExternalNames"];
}
+ (void)setUseQuotedExternalNames:(BOOL)flag
{
NSString *yn = (flag ? @"YES" : @"NO");
[[NSUserDefaults standardUserDefaults]
setObject: yn forKey: @"EOAdaptorQuotesExternalNames"];
}
- (NSString *)externalNameQuoteCharacter
{
if ([[self class] useQuotedExternalNames])
return @"\"";
return @"";
}
- (void)setUseAliases: (BOOL)useAliases
{
_flags.useAliases = useAliases;
}
- (BOOL)useAliases
{
return _flags.useAliases;
}
- (NSString *)sqlStringForSchemaObjectName: (NSString *)name
{
//OK
NSString *quote = [self externalNameQuoteCharacter];
return [NSString stringWithFormat:@"%@%@%@", quote, name, quote];
}
- (NSString *)sqlStringForAttributeNamed: (NSString *)name
{
//OK
EOAttribute *attribute = nil;
NSString *sqlString = nil;
NSArray *keyParts = nil;
NSString *key = nil;
EOEntity *entity=_entity;
NSMutableArray *attributePath = nil;
int i, count;
EORelationship *rel = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
NSAssert(entity,@"no entity");
NSAssert(name,@"no attribute name");
NSAssert([name length]>0,@"attribute name is empty");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"name=%@", name);
keyParts = [name componentsSeparatedByString:@"."];
count = [keyParts count];
for (i = 0; i < count - 1; i++)
{
key = [keyParts objectAtIndex: i];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"keyPart=%@", key);
rel = [entity anyRelationshipNamed: key];
NSAssert2(rel,
@"no relationship named %@ in entity %@",
key,
[entity name]);
if (attributePath)
[attributePath addObject: rel];
else
attributePath = [NSMutableArray arrayWithObject: rel];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"rel=%@", rel);
entity = [rel destinationEntity];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"entity name=%@",
[entity name]);
}
key = [keyParts lastObject];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"key=%@", key);
attribute = [entity anyAttributeNamed: key];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute);
if (!attribute)
{
rel = [entity anyRelationshipNamed: key];
if (rel)
NSAssert4(attribute,
@"no attribute named %@ (only a relationship) in entity %@\nAttributesByName=%@\nattributes=%@",
key,
[entity name],
[entity attributesByName],
[entity attributes]);
else
NSAssert4(attribute,
@"no attribute nor relationship named %@ in entity %@\nAttributesByName=%@\nattributes=%@",
key,
[entity name],
[entity attributesByName],
[entity attributes]);
};
if (attributePath)
{
[attributePath addObject: attribute];
sqlString = [self sqlStringForAttributePath: attributePath];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
NSAssert1(sqlString,
@"no sql string for attribute path %@",
attributePath);
NSAssert1([sqlString length],
@"empty sql string for attribute path %@",
attributePath);
}
else
{
sqlString = [self sqlStringForAttribute: attribute];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
NSAssert1(sqlString,
@"no sql string for attribute %@",
attribute);
NSAssert1([sqlString length],
@"empty sql string for attribute %@",
attribute);
}
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (NSString *)sqlStringForSelector: (SEL)selector
value: (id)value
{
//seems OK
if (sel_isEqual(selector, EOQualifierOperatorEqual))
{
if (value==GDL2_EONull)
return @"is";
else
return @"=";
}
else if (sel_isEqual(selector, EOQualifierOperatorNotEqual))
{
if (value==GDL2_EONull)
return @"is not";
else
return @"<>";
}
else if (sel_isEqual(selector, EOQualifierOperatorLessThan))
return @"<";
else if (sel_isEqual(selector, EOQualifierOperatorGreaterThan))
return @">";
else if (sel_isEqual(selector, EOQualifierOperatorLessThanOrEqualTo))
return @"<=";
else if (sel_isEqual(selector, EOQualifierOperatorGreaterThanOrEqualTo))
return @">=";
else if (sel_isEqual(selector, EOQualifierOperatorLike))
return @"like";
else if (sel_isEqual(selector, EOQualifierOperatorCaseInsensitiveLike))
return @"like"; //same as sensitive
/* //TODO else if(sel_isEqual(selector, EOQualifierOperatorContains))
return @"like";*/
else
{
[NSException raise: NSInternalInconsistencyException
format: @"EOSQLExpression: Unknown selector of sqlStringForSelector:value: '%@'",NSStringFromSelector(selector)];
}
return nil;
}
- (NSString *)sqlStringForValue: (id)value
attributeNamed: (NSString*)attributeName
{
EOAttribute *attribute;
NSString *sqlString = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"value=%@", value);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attributeName=%@",
attributeName);
attribute = [_entity attributeForPath: attributeName];
NSAssert2(attribute,
@"No attribute for path \"%@\" in entity \"%@\"",
attributeName,
[_entity name]);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute);
if ([self shouldUseBindVariableForAttribute: attribute]
|| [self mustUseBindVariableForAttribute: attribute])
{
//TODO verify
NSDictionary *binding;
binding = [self bindVariableDictionaryForAttribute: attribute
value: value];
[_bindings addObject: binding];
sqlString = [binding objectForKey: EOBindVariablePlaceHolderKey];
}
else
{
//attr externalType
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" value=%@ class=%@",
value, [value class]);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" self %@ class=%@",
self, [self class]);
//call attribute entity
//call entity model
sqlString = [[self class] formatValue: value
forAttribute: attribute]; //??
EOFLOGObjectLevelArgs(@"EOSQLExpression", @" sqlString=%@", sqlString);
NSAssert4([sqlString length] > 0,
@"No sqlString (%p) for value '%@' (class %@) for Attribute '%@'",
sqlString, value, [value class], attribute);
//??? Mirko:
sqlString = [[self class] formatSQLString: sqlString
format: [attribute readFormat]];
}
EOFLOGObjectFnStopCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
return sqlString;
}
- (NSString *)sqlStringForAttribute: (EOAttribute *)attribute
{
NSString *sqlString = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@",
attribute);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sFlattened=%s",
([attribute isFlattened] ? "YES" : "NO"));
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_definitionArray=%@",
[attribute _definitionArray]);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"_definitionArray count=%d",
[[attribute _definitionArray]count]);
if ([attribute isFlattened])
{
sqlString = [self sqlStringForAttributePath:
[attribute _definitionArray]];
NSAssert1(sqlString, @"No sqlString for flattened attribute: %@",
attribute);
}
//mirko:
/*
else if([attribute isDerived] == YES)
return [attribute definition];
*/
else
{
if (![self useAliases])//OK
{
sqlString = [attribute columnName];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
}
else
{
//TODO VERIFY en select: return t0.abbrev
NSEnumerator *relationshipEnum;
NSEnumerator *defEnum = nil;
NSArray *defArray, *attrArray = nil;
NSString *relationshipPath;
NSString *relationshipString = nil;
EOEntity *currentEntity = nil;
relationshipEnum = [_aliasesByRelationshipPath keyEnumerator];
while ((relationshipPath = [relationshipEnum nextObject]))
{
currentEntity = _entity;
EOFLOGObjectLevelArgs(@"EOSQLExpression",@"relationshipPath=%@",relationshipPath);
if (![relationshipPath isEqualToString: @""])
{
defArray = [relationshipPath componentsSeparatedByString:
@"."];
defEnum = [defArray objectEnumerator];
while ((relationshipString = [defEnum nextObject]))
{
// use anyRelationshipNamed: to find hidden relationship too
EORelationship *relationship=[currentEntity
anyRelationshipNamed: relationshipString];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"relationshipString=%@",
relationshipString);
NSAssert2(relationship,
@"No relationship named %@ in entity %@",
relationshipString,
[currentEntity name]);
NSAssert2(currentEntity,
@"No destination entity. Entity %@ relationship = %@",
[currentEntity name],
relationship);
currentEntity = [relationship destinationEntity];
} // TODO entity
}
attrArray = [currentEntity attributes];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attrArray=%@",
attrArray);
if (attrArray)
{
if ([attrArray containsObject: attribute])
{
NSString *columnName = [attribute columnName];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"columnName=%@", columnName);
if (!columnName)
{
NSEmitTODO(); //TODO what to do when there's no column name (definition only like "((firstName || ' ') || lastName)") ?
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"attribute=%@",
attribute);
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"columnName=%@", columnName);
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"attrArray=%@", attrArray);
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"relationshipPath=%@",
relationshipPath);
}
NSAssert1(columnName, @"No columnName for attribute %@",
attribute);
sqlString = [NSString stringWithFormat: @"%@.%@",
[_aliasesByRelationshipPath
objectForKey: relationshipPath],
columnName];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"sqlString=%@", sqlString);
}
}
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@",
sqlString);
}
NSAssert1(sqlString, @"No SQLString for attribute %@", attribute);
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"sqlString=%@", sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (NSString *)sqlStringForAttributePath: (NSArray *)path
{
NSString *sqlString = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"path=%@", path);
if (!_flags.useAliases)
{
sqlString = [(EOAttribute *)[path lastObject] columnName];
NSAssert2(sqlString,
@"No sqlString for path: %@ (lastObject=%@) (!_useAliases)",
path,
[path lastObject]);
}
else
{
NSMutableString *relationshipPathString = [NSMutableString string];
int i, count = [path count];
if (count > 1)
{
for (i = 0; i < (count - 1); i++)
{
EORelationship* relationship = nil;
if (i > 0)
[relationshipPathString appendString: @"."];
relationship = [path objectAtIndex:i];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"[path objectAtIndex:%d]=%@",
i, relationship);
NSAssert2([relationship isKindOfClass:[EORelationship class]],
@"'%@' is not a relationship but a %@",
relationship,
[relationship class]);
[relationshipPathString appendString: [relationship name]];
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"[path lastObject]=%@",
[path lastObject]);
//TODO
if ([[path lastObject] isDerived])
{
//call attribute _definitionArray
NSEmitTODO(); //TODO
[self notImplemented:_cmd];
};
sqlString = [self _aliasForRelatedAttribute: [path lastObject]
relationshipPath: relationshipPathString];
NSAssert2(sqlString,
@"No sqlString for path: %@ (lastObject=%@) (_useAliases)",
path,
[path lastObject]);
}
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"path=%@ sqlString=%@",
path, sqlString);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return sqlString;
}
- (void)appendItem: (NSString *)itemString
toListString: (NSMutableString *)listString
{
//OK
NSAssert1(listString,@"No list string when appending %@",itemString);
if (listString)
{
#if 0
str = [listString cString];
while (*str)
{
if (!isspace(*str++))
[listString appendString: @", "];
}
#endif
if ([listString length])
[listString appendString: @", "];
[listString appendString: itemString];
}
}
+ (NSString *)sqlPatternFromShellPattern: (NSString *)pattern
{
NSString* sqlPattern=nil;
int patternLength=[pattern length];
if (patternLength==0)
sqlPattern=pattern;
else
{
const char *s, *p, *init = [pattern cString];
NSMutableString *str = [NSMutableString stringWithCapacity:
patternLength];
IMP appendStringIMP = [str methodForSelector:@selector(appendString:)];
for (s = p = init; *s; s++)
{
switch (*s)
{
case '*':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
[str appendString: @"%"];
p = s+1;
break;
case '?':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
GDL2_AppendStringWithImp(str,appendStringIMP,@"_");
p = s+1;
break;
case '%':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
if (s != init && *(s-1) == '[' && *(s+1) == ']')
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"%]");
p = s+2; s++;
}
else
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"[%]");
p = s+1;
}
break;
case '_':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
if (s != init && *(s-1) == '[' && *(s+1) == ']')
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"_]");
p = s+2; p++;
}
else
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"[_]");
p = s+1;
}
break;
}
}
if (*p)
GDL2_AppendStringWithImp(str,appendStringIMP,[NSString stringWithCString: p]);
sqlPattern=str;
};
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"pattern=%@ => %@",
pattern,sqlPattern);
return sqlPattern;
}
+ (NSString *)sqlPatternFromShellPattern: (NSString *)pattern
withEscapeCharacter: (unichar)escapeCharacter
{
const char *s, *p, *init = [pattern cString];
NSMutableString *str = [NSMutableString stringWithCapacity:
[pattern length]];
IMP appendStringIMP = [str methodForSelector:@selector(appendString:)];
for (s = p = init; *s; s++)
{
switch (*s)
{
case '*':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
GDL2_AppendStringWithImp(str,appendStringIMP,@"%");
p = s+1;
break;
case '?':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
GDL2_AppendStringWithImp(str,appendStringIMP,@"_");
p = s+1;
break;
case '%':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
if (s != init && *(s-1) == '[' && *(s+1) == ']')
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"%]");
p = s+2; s++;
}
else
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"[%]");
p = s+1;
}
break;
case '_':
if (s != p)
GDL2_AppendStringWithImp(str,appendStringIMP,
GDL2_StringWithCStringAndLength(p,s-p));
if (s != init && *(s-1) == '[' && *(s+1) == ']')
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"_]");
p = s+2; p++;
}
else
{
GDL2_AppendStringWithImp(str,appendStringIMP,@"[_]");
p = s+1;
}
break;
}
}
if (*p)
GDL2_AppendStringWithImp(str,appendStringIMP,[NSString stringWithCString:p]);
return str;
}
- (NSMutableDictionary *)bindVariableDictionaryForAttribute: (EOAttribute *)attribute
value: (id)value
{
[self subclassResponsibility: _cmd];
return nil;
}
- (BOOL)shouldUseBindVariableForAttribute: (EOAttribute *)att
{
return NO;
}
- (BOOL)mustUseBindVariableForAttribute: (EOAttribute *)att
{
return NO;
}
+ (BOOL)useBindVariables
{
return [[NSUserDefaults standardUserDefaults]
boolForKey: @"EOAdaptorUseBindVariables"];
}
+ (void)setUseBindVariables:(BOOL)flag
{
NSString *yn = (flag ? @"YES" : @"NO");
[[NSUserDefaults standardUserDefaults]
setObject:yn forKey:@"EOAdaptorUseBindVariables"];
}
- (NSArray *)bindVariableDictionaries
{
return _bindings;
}
- (void)addBindVariableDictionary:(NSMutableDictionary *)binding
{
[_bindings addObject:binding];
}
@end /* EOSQLExpression */
@implementation EOSQLExpression (EOSQLExpressionPrivate)
- (EOEntity*)_rootEntityForExpression
{
//return [self notImplemented:_cmd]; //TODO
return _entity;
};
/** Return the alias (t0,t1,...) for the relationshipPath
This add a new alias if there not already one
This also add alias for all relationships used by relationshipPath (so joinExpression can build join expressions for really all used relationships)
All relationshipPaths in _aliasesByRelationshipPath are direct paths **/
- (NSString*) _aliasForRelationshipPath:(NSString*)relationshipPath
{
//OK ?
NSString *flattenRelPath;
NSMutableString *mutableFlattenRelPath;
NSString *alias = nil;
NSMutableArray *pathElements;
int count = 0;
int contextStackCurrentIndex = 0;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
contextStackCurrentIndex = [_contextStack count];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"relationshipPath=%@",
relationshipPath);
NSAssert(relationshipPath, @"No relationshipPath");
if ([relationshipPath length] == 0) // "" relationshipPath is handled by _aliasesByRelationshipPath lookup
flattenRelPath = relationshipPath;
else
// Find real path
flattenRelPath = [self _flattenRelPath: relationshipPath
entity: _entity];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"flattenRelPath=\"%@\"",
flattenRelPath);
mutableFlattenRelPath = [[flattenRelPath mutableCopy] autorelease];
pathElements = [[[mutableFlattenRelPath componentsSeparatedByString: @"."]
mutableCopy] autorelease];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"pathElements=%@", pathElements);
count = [pathElements count];
while (count > 0)
{
NSString *tmpAlias = nil;
EOFLOGObjectLevelArgs(@"EOSQLExpression",@"count=%d flattenRelPath=%@",
count,
mutableFlattenRelPath);
tmpAlias = [_aliasesByRelationshipPath objectForKey:
mutableFlattenRelPath];
if (!tmpAlias)
{
NSString* tmpRelPath=nil;
tmpAlias = [NSString stringWithFormat: @"t%d", _alias++];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"add alias %@ for %@",
tmpAlias, mutableFlattenRelPath);
tmpRelPath = [[mutableFlattenRelPath copy]
autorelease]; //immuable key !
[_aliasesByRelationshipPath setObject: tmpAlias
forKey: tmpRelPath];
// Insert to ensure logical order (i.e. xx BEFORE xx.yy)
[_contextStack insertObject:tmpRelPath
atIndex:contextStackCurrentIndex];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"inserted '%@' (%@) in contextStack => %@",
tmpRelPath,tmpAlias,_contextStack);
}
if (!alias)
alias = tmpAlias;
if (count > 0)
{
NSString *part = [pathElements lastObject];
if (count > 1 || [part length] > 0) //we may have only "" as original path
[mutableFlattenRelPath deleteSuffix: part];
if (count > 1)
[mutableFlattenRelPath deleteSuffix: @"."];
[pathElements removeLastObject];
}
count--;
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"alias=%@", alias);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return alias;
}
- (NSString*) _flattenRelPath: (NSString*)relationshipPath
entity: (EOEntity*)entity
{
// near OK
NSMutableString *flattenRelPath = [NSMutableString string];
EORelationship *relationship = nil;
NSArray *pathElements = nil;
int i, count;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
NSAssert(relationshipPath, @"No relationshipPath");
NSAssert([relationshipPath length] > 0, @"Empty relationshipPath");
pathElements = [relationshipPath componentsSeparatedByString: @"."];
count = [pathElements count];
for (i = 0; i < count; i++)
{
NSString *relPath = nil;
NSString *part = [pathElements objectAtIndex: i];
// use anyRelationshipNamed: to find hidden relationship too
relationship = [entity anyRelationshipNamed: part];
NSAssert2(relationship,
@"no relationship named %@ in entity %@",
part,
[entity name]);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"i=%d part=%@ rel=%@",
i, part, relationship);
// We check if there's outer join has some adaptors may buld things
// differently in this case
if (!_flags.hasOuterJoin && [relationship joinSemantic]!=EOInnerJoin)
_flags.hasOuterJoin=YES;
if ([relationship isFlattened])
{
NSString *definition = [relationship definition];
EOFLOGObjectLevelArgs(@"EOSQLExpression",
@"definition=%@ relationship=%@",
definition,
relationship);
relPath = [self _flattenRelPath: definition
entity: entity];
}
else
relPath = [relationship name];
if (i > 0)
[flattenRelPath appendString: @"."];
[flattenRelPath appendString: relPath];
entity = [relationship destinationEntity];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"entity name=%@",
[entity name]);
}
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"flattenRelPath=%@",
flattenRelPath);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return flattenRelPath;
}
- (NSString*) _sqlStringForJoinSemantic: (EOJoinSemantic)joinSemantic
matchSemantic: (int)param1
{
return [self notImplemented: _cmd]; //TODO
}
- (NSString*) _aliasForRelatedAttribute: (EOAttribute*)attribute
relationshipPath: (NSString*)relationshipPath
{
NSString *alias = nil;
NSString *relPathAlias = nil;
NSString *attributeColumnName = nil;
EOFLOGObjectFnStartCond(@"EOSQLExpression");
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"attribute=%@", attribute);
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"relationshipPath=%@",
relationshipPath);
relPathAlias = [self _aliasForRelationshipPath: relationshipPath]; //ret "t1"
attributeColumnName = [attribute columnName]; // ret "label"
attributeColumnName = [self sqlStringForSchemaObjectName:
attributeColumnName]; // ret quoted columnName
NSAssert1([relPathAlias length]>0,@"no relPathAlias or empty relPathAlias ('%@')",
relPathAlias);
NSAssert1([attributeColumnName length]>0,@"no attributeColumnName or empty attributeColumnName ('%@')",
attributeColumnName);
alias = [NSString stringWithFormat: @"%@.%@",
relPathAlias,
attributeColumnName];
EOFLOGObjectLevelArgs(@"EOSQLExpression", @"alias=%@", alias);
EOFLOGObjectFnStopCond(@"EOSQLExpression");
return alias;//Like t1.label
}
- (id) _entityForRelationshipPath: (id)param0
origin: (id)param1
{
return [self notImplemented: _cmd]; //TODO
}
@end
@implementation NSString (EOSQLFormatting)
- (NSString *)sqlString
{
return self;
}
@end
@implementation NSNumber (EOSQLFormatting)
- (NSString *)sqlString
{
return [self stringValue];
}
@end
@implementation NSObject (EOSQLFormatting)
- (NSString *)sqlString
{
return [self description];
}
@end