4 Copyright (C) 1996 Free Software Foundation, Inc.
6 Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
9 This file is part of the GNUstep Database Library.
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Library General Public
13 License as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Library General Public License for more details.
21 You should have received a copy of the GNU Library General Public
22 License along with this library; see the file COPYING.LIB.
23 If not, write to the Free Software Foundation,
24 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #import "EOAdaptorChannel.h"
29 #import "EOAttribute.h"
31 #import "EOAdaptorContext.h"
32 #import "EOSQLExpression.h"
33 #import "EOFExceptions.h"
35 @interface EOAdaptorChannel(Internals)
36 - (NSArray *)_sortAttributesForSelectExpression:(NSArray *)_attrs;
37 @end /* EOAdaptorChannel(Internals) */
39 @implementation EOAdaptorChannel
41 + (NSCalendarDate*)dateForAttribute:(EOAttribute*)attr
42 year:(int)year month:(unsigned)month day:(unsigned)day
43 hour:(unsigned)hour minute:(unsigned)minute second:(unsigned)second
46 NSTimeZone *serverTimeZone = [attr serverTimeZone];
47 NSTimeZone *clientTimeZone = [attr clientTimeZone];
51 if (serverTimeZone == nil) serverTimeZone = [NSTimeZone localTimeZone];
52 if (clientTimeZone == nil) clientTimeZone = [NSTimeZone localTimeZone];
54 date = AUTORELEASE([[NSCalendarDate allocWithZone:zone]
55 initWithYear:year month:month day:day hour:hour
56 minute:minute second:second timeZone:serverTimeZone]);
57 [date setTimeZone:clientTimeZone];
58 fmt = [attr calendarFormat];
59 [date setCalendarFormat:fmt ? fmt : [EOAttribute defaultCalendarFormat]];
63 - (id)initWithAdaptorContext:(EOAdaptorContext*)_adaptorContext {
64 ASSIGN(self->adaptorContext, _adaptorContext);
67 [self->adaptorContext channelDidInit:self];
70 [localException raise];
78 [self->adaptorContext channelWillDealloc:self];
79 RELEASE(self->adaptorContext);
83 /* open/close channel */
93 - (void)closeChannel {
94 if ([self isFetchInProgress])
101 - (Class)_adaptorExpressionClass {
102 return [[self->adaptorContext adaptor] expressionClass];
105 - (BOOL)_isNoRaiseOnModificationException:(NSException *)_exception {
106 /* for compatibility with non-X methods, translate some errors to a bool */
109 n = [_exception name];
110 if ([n isEqualToString:@"EOEvaluationError"])
112 if ([n isEqualToString:@"EODelegateRejects"])
118 - (NSException *)insertRowX:(NSDictionary *)row forEntity:(EOEntity *)entity {
119 EOSQLExpression *sqlexpr;
120 NSMutableDictionary *mrow = (id)row;
124 return [[ChannelIsNotOpenedException new] autorelease];
126 if ((row == nil) || (entity == nil)) {
127 return [NSException exceptionWithName:NSInvalidArgumentException
128 reason:@"row and entity arguments for "
129 @"insertRow:forEntity: must not be the nil object"
133 if ([self isFetchInProgress])
134 return [AdaptorIsFetchingException exceptionWithAdaptor:self];
136 if ([self->adaptorContext transactionNestingLevel] == 0)
137 return [NoTransactionInProgressException exceptionWithAdaptor:self];
139 if (delegateRespondsTo.willInsertRow) {
140 EODelegateResponse response;
142 mrow = AUTORELEASE([row mutableCopyWithZone:[row zone]]);
143 response = [delegate adaptorChannel:self
146 if (response == EODelegateRejects) {
147 return [NSException exceptionWithName:@"EODelegateRejects"
148 reason:@"delegate rejected insert"
151 if (response == EODelegateOverrides)
155 sqlexpr = [[[self->adaptorContext adaptor]
157 insertExpressionForRow:mrow
161 ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
165 if(delegateRespondsTo.didInsertRow)
166 [delegate adaptorChannel:self didInsertRow:mrow forEntity:entity];
171 - (NSException *)updateRowX:(NSDictionary *)row
172 describedByQualifier:(EOSQLQualifier *)qualifier
174 EOSQLExpression *sqlexpr = nil;
175 NSMutableDictionary *mrow = (id)row;
179 return [[ChannelIsNotOpenedException new] autorelease];
182 return [NSException exceptionWithName:NSInvalidArgumentException
184 @"row argument for updateRow:describedByQualifier: "
185 @"must not be the nil object"
189 if ([self isFetchInProgress])
190 return [AdaptorIsFetchingException exceptionWithAdaptor:self];
192 if ([self->adaptorContext transactionNestingLevel] == 0)
193 return [NoTransactionInProgressException exceptionWithAdaptor:self];
195 if (delegateRespondsTo.willUpdateRow) {
196 EODelegateResponse response;
198 mrow = AUTORELEASE([row mutableCopyWithZone:[row zone]]);
199 response = [delegate adaptorChannel:self
201 describedByQualifier:qualifier];
202 if (response == EODelegateRejects) {
203 return [NSException exceptionWithName:@"EODelegateRejects"
204 reason:@"delegate rejected update"
207 if (response == EODelegateOverrides)
211 sqlexpr = [[self _adaptorExpressionClass]
212 updateExpressionForRow:mrow
216 ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
217 if (ex != nil) return ex;
219 if (delegateRespondsTo.didUpdateRow) {
220 [delegate adaptorChannel:self
222 describedByQualifier:qualifier];
227 - (NSException *)deleteRowsDescribedByQualifierX:(EOSQLQualifier *)qualifier {
228 EOSQLExpression *sqlexpr = nil;
232 return [[ChannelIsNotOpenedException new] autorelease];
234 if ([self isFetchInProgress])
235 return [AdaptorIsFetchingException exceptionWithAdaptor:self];
237 if ([self->adaptorContext transactionNestingLevel] == 0)
238 return [NoTransactionInProgressException exceptionWithAdaptor:self];
240 if (delegateRespondsTo.willDeleteRows) {
241 EODelegateResponse response;
243 response = [delegate adaptorChannel:self
244 willDeleteRowsDescribedByQualifier:qualifier];
245 if (response == EODelegateRejects) {
246 return [NSException exceptionWithName:@"EODelegateRejects"
247 reason:@"delegate rejected delete"
250 if (response == EODelegateOverrides)
254 sqlexpr = [[self _adaptorExpressionClass]
255 deleteExpressionWithQualifier:qualifier
258 ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
259 if (ex != nil) return ex;
261 if (delegateRespondsTo.didDeleteRows)
262 [delegate adaptorChannel:self didDeleteRowsDescribedByQualifier:qualifier];
267 /* compatibility methods (DEPRECATED, use the ...X methods */
269 - (BOOL)selectAttributes:(NSArray *)attributes
270 describedByQualifier:(EOSQLQualifier *)qualifier
271 fetchOrder:(NSArray *)fetchOrder
276 ex = [self selectAttributesX:attributes describedByQualifier:qualifier
277 fetchOrder:fetchOrder lock:lockFlag];
280 if ([self _isNoRaiseOnModificationException:ex])
286 - (BOOL)insertRow:(NSDictionary *)_row forEntity:(EOEntity *)_entity {
289 ex = [self insertRowX:_row forEntity:_entity];
292 if ([self _isNoRaiseOnModificationException:ex])
298 - (BOOL)updateRow:(NSDictionary *)_row
299 describedByQualifier:(EOSQLQualifier *)_q
303 ex = [self updateRowX:_row describedByQualifier:_q];
306 if ([self _isNoRaiseOnModificationException:ex])
312 - (BOOL)deleteRowsDescribedByQualifier:(EOSQLQualifier *)_qualifier {
315 ex = [self deleteRowsDescribedByQualifierX:_qualifier];
318 if ([self _isNoRaiseOnModificationException:ex])
324 /* fetch operations */
326 - (NSException *)selectAttributesX:(NSArray *)attributes
327 describedByQualifier:(EOSQLQualifier *)qualifier
328 fetchOrder:(NSArray *)fetchOrder
332 EOSQLExpression *sqlexpr = nil;
333 NSMutableArray *mattrs = (NSMutableArray *)attributes;
334 NSMutableArray *mfetch = (NSMutableArray *)fetchOrder;
337 return [[ChannelIsNotOpenedException new] autorelease];
339 if (attributes == nil) {
340 return [NSException exceptionWithName:NSInvalidArgumentException
342 @"attributes argument for selectAttributes:"
343 @"describedByQualifier:fetchOrder:lock: "
344 @"must not be the nil object"
348 if ([self isFetchInProgress])
349 return [AdaptorIsFetchingException exceptionWithAdaptor:self];
351 if ([self->adaptorContext transactionNestingLevel] == 0)
352 return [NoTransactionInProgressException exceptionWithAdaptor:self];
354 if (delegateRespondsTo.willSelectAttributes) {
355 EODelegateResponse response;
357 mattrs = [[attributes mutableCopy] autorelease];
358 mfetch = [[fetchOrder mutableCopy] autorelease];
360 response = [delegate adaptorChannel:self
361 willSelectAttributes:mattrs
362 describedByQualifier:qualifier
365 if (response == EODelegateRejects) {
366 return [NSException exceptionWithName:@"EODelegateRejects"
367 reason:@"delegate rejected select"
370 if (response == EODelegateOverrides)
375 #warning DEBUG LOG, REMOVE!
376 [self logWithFormat:@"fetch qualifier: %@", qualifier];
379 sqlexpr = [[[self->adaptorContext adaptor]
381 selectExpressionForAttributes:attributes
384 fetchOrder:fetchOrder
387 ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
391 if (delegateRespondsTo.didSelectAttributes) {
392 [delegate adaptorChannel:self
393 didSelectAttributes:mattrs
394 describedByQualifier:qualifier
401 - (NSArray *)describeResults:(BOOL)_beautifyNames {
402 [self subclassResponsibility:_cmd];
405 - (NSArray *)describeResults {
406 return [self describeResults:YES];
409 - (NSMutableDictionary *)fetchAttributes:(NSArray *)attributes
410 withZone:(NSZone *)_zone
412 NSMutableDictionary *row = nil;
415 [[ChannelIsNotOpenedException new] raise];
418 _zone = NSDefaultMallocZone();
420 if(![self isFetchInProgress])
421 [[AdaptorIsNotFetchingException exceptionWithAdaptor:self] raise];
423 if(delegateRespondsTo.willFetchAttributes) {
424 row = [delegate adaptorChannel:self
425 willFetchAttributes:attributes
429 /* NOTE: primaryFetchAttributes:withZone: have to set the isFetchInProgress
432 row = [self primaryFetchAttributes:attributes withZone:_zone];
435 if(delegateRespondsTo.didFetchAttributes)
436 row = [delegate adaptorChannel:self
437 didFetchAttributes:row
439 if(delegateRespondsTo.didChangeResultSet)
440 [delegate adaptorChannelDidChangeResultSet:self];
443 /* Do not set here the isFetchInProgress status since only subclasses
444 can know whether there are more SELECT commands to be executed.
445 Setting the status here to NO will overwrite the adaptor subclass
447 if(delegateRespondsTo.didFinishFetching)
448 [delegate adaptorChannelDidFinishFetching:self];
453 - (BOOL)isFetchInProgress {
454 return self->isFetchInProgress;
457 - (void)cancelFetch {
459 [[ChannelIsNotOpenedException new] raise];
461 self->isFetchInProgress = NO;
464 - (NSMutableDictionary *)dictionaryWithObjects:(id *)objects
465 forAttributes:(NSArray *)attributes zone:(NSZone *)zone
467 [self notImplemented:_cmd];
471 - (NSMutableDictionary*)primaryFetchAttributes:(NSArray *)attributes
472 withZone:(NSZone *)zone
474 [self subclassResponsibility:_cmd];
478 - (BOOL)evaluateExpression:(NSString *)anExpression {
479 [self subclassResponsibility:_cmd];
482 - (NSException *)evaluateExpressionX:(NSString *)_sql {
489 ok = [self evaluateExpression:_sql];
491 ex = [localException retain];
494 if (ex) return [ex autorelease];
497 return [NSException exceptionWithName:@"EOEvaluationError"
498 reason:@"could not evaluate SQL expression"
502 - (EOAdaptorContext *)adaptorContext {
503 return self->adaptorContext;
506 - (EOModel *)describeModelWithTableNames:(NSArray *)tableNames {
507 [self subclassResponsibility:_cmd];
511 - (NSArray *)describeTableNames {
512 [self subclassResponsibility:_cmd];
516 - (BOOL)readTypesForEntity:(EOEntity*)anEntity {
517 [self subclassResponsibility:_cmd];
521 - (BOOL)readTypeForAttribute:(EOAttribute*)anAttribute {
522 [self subclassResponsibility:_cmd];
529 return self->delegate;
532 - (void)setDelegate:(id)_delegate {
533 self->delegate = _delegate;
535 delegateRespondsTo.willInsertRow =
536 [delegate respondsToSelector:
537 @selector(adaptorChannel:willInsertRow:forEntity:)];
538 delegateRespondsTo.didInsertRow =
539 [delegate respondsToSelector:
540 @selector(adaptorChannel:didInsertRow:forEntity:)];
541 delegateRespondsTo.willUpdateRow =
542 [delegate respondsToSelector:
543 @selector(adaptorChannel:willUpdateRow:describedByQualifier:)];
544 delegateRespondsTo.didUpdateRow =
545 [delegate respondsToSelector:
546 @selector(adaptorChannel:didUpdateRow:describedByQualifier:)];
547 delegateRespondsTo.willDeleteRows =
548 [delegate respondsToSelector:
549 @selector(adaptorChannel:willDeleteRowsDescribedByQualifier:)];
550 delegateRespondsTo.didDeleteRows =
551 [delegate respondsToSelector:
552 @selector(adaptorChannel:didDeleteRowsDescribedByQualifier:)];
553 delegateRespondsTo.willSelectAttributes =
554 [delegate respondsToSelector:
555 @selector(adaptorChannel:willSelectAttributes:
556 describedByQualifier:fetchOrder:lock:)];
557 delegateRespondsTo.didSelectAttributes =
558 [delegate respondsToSelector:
559 @selector(adaptorChannel:didSelectAttributes:
560 describedByQualifier:fetchOrder:lock:)];
561 delegateRespondsTo.willFetchAttributes =
562 [delegate respondsToSelector:
563 @selector(adaptorChannel:willFetchAttributes:withZone:)];
564 delegateRespondsTo.didFetchAttributes =
565 [delegate respondsToSelector:
566 @selector(adaptorChannel:didFetchAttributes:withZone:)];
567 delegateRespondsTo.didChangeResultSet =
568 [delegate respondsToSelector:
569 @selector(adaptorChannelDidChangeResultSet:)];
570 delegateRespondsTo.didFinishFetching =
571 [delegate respondsToSelector:
572 @selector(adaptorChannelDidFinishFetching:)];
573 delegateRespondsTo.willEvaluateExpression =
574 [delegate respondsToSelector:
575 @selector(adaptorChannel:willEvaluateExpression:)];
576 delegateRespondsTo.didEvaluateExpression =
577 [delegate respondsToSelector:
578 @selector(adaptorChannel:didEvaluateExpression:)];
581 - (void)setDebugEnabled:(BOOL)flag {
582 self->debugEnabled = flag;
585 - (BOOL)isDebugEnabled {
586 return self->debugEnabled;
592 @end /* EOAdaptorChannel */
594 #import <EOControl/EOFetchSpecification.h>
596 @implementation EOAdaptorChannel(PrimaryKeyGeneration) // new in EOF2
598 - (NSDictionary *)primaryKeyForNewRowWithEntity:(EOEntity *)_entity {
602 @end /* EOAdaptorChannel(PrimaryKeyGeneration) */
604 @implementation EOAdaptorChannel(EOF2Additions)
606 - (void)selectAttributes:(NSArray *)_attributes
607 fetchSpecification:(EOFetchSpecification *)_fspec
609 entity:(EOEntity *)_entity
614 q = (EOSQLQualifier *)[_fspec qualifier];
616 isOk = [self selectAttributes:_attributes
617 describedByQualifier:q
618 fetchOrder:[_fspec sortOrderings]
621 [NSException raise:@"Select failed"
622 format:@"could not select attributes for fetch spec"];
626 - (void)setAttributesToFetch:(NSArray *)_attributes {
627 [self notImplemented:_cmd];
629 - (NSArray *)attributesToFetch {
630 NSLog(@"ERROR(%s): subclasses must override this method!",
631 __PRETTY_FUNCTION__);
635 - (NSMutableDictionary *)fetchRowWithZone:(NSZone *)_zone {
636 return [self fetchAttributes:[self attributesToFetch] withZone:_zone];
639 @end /* EOAdaptorChannel(EOF2Additions) */
641 @implementation EOAdaptorChannel(Internals)
643 - (NSArray *)_sortAttributesForSelectExpression:(NSArray *)_attrs {
647 @end /* EOAdaptorChannel(Internals) */