]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EOAdaptorChannel.m
minor changes to Xcode project layout
[sope] / sope-gdl1 / GDLAccess / EOAdaptorChannel.m
1 /* 
2    EOAdaptorChannel.m
3
4    Copyright (C) 1996 Free Software Foundation, Inc.
5
6    Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
7    Date: October 1996
8
9    This file is part of the GNUstep Database Library.
10
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.
15
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.
20
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.
25 */
26
27 #import "common.h"
28 #import "EOAdaptorChannel.h"
29 #import "EOAttribute.h"
30 #import "EOAdaptor.h"
31 #import "EOAdaptorContext.h"
32 #import "EOSQLExpression.h"
33 #import "EOFExceptions.h"
34
35 @interface EOAdaptorChannel(Internals)
36 - (NSArray *)_sortAttributesForSelectExpression:(NSArray *)_attrs;
37 @end /* EOAdaptorChannel(Internals) */
38
39 @implementation EOAdaptorChannel
40
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 
44   zone:(NSZone*)zone
45 {
46   NSTimeZone     *serverTimeZone = [attr serverTimeZone];
47   NSTimeZone     *clientTimeZone = [attr clientTimeZone];
48   NSCalendarDate *date;
49   NSString       *fmt;
50
51   if (serverTimeZone == nil) serverTimeZone = [NSTimeZone localTimeZone];
52   if (clientTimeZone == nil) clientTimeZone = [NSTimeZone localTimeZone];
53     
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]];
60   return date;
61 }
62
63 - (id)initWithAdaptorContext:(EOAdaptorContext*)_adaptorContext {
64     ASSIGN(self->adaptorContext, _adaptorContext);
65     
66     NS_DURING
67         [self->adaptorContext channelDidInit:self];
68     NS_HANDLER {
69       AUTORELEASE(self);
70       [localException raise];
71     }
72     NS_ENDHANDLER;
73     
74     return self;
75 }
76
77 - (void)dealloc {
78   [self->adaptorContext channelWillDealloc:self];
79   RELEASE(self->adaptorContext);
80   [super dealloc];
81 }
82
83 /* open/close channel */
84
85 - (BOOL)openChannel {
86   if(self->isOpen)
87     return NO;
88   self->isOpen = YES;
89
90   return YES;
91 }
92
93 - (void)closeChannel {
94   if ([self isFetchInProgress])
95     [self cancelFetch];
96   self->isOpen = NO;
97 }
98
99 /* modifications */
100
101 - (Class)_adaptorExpressionClass {
102   return [[self->adaptorContext adaptor] expressionClass];
103 }
104
105 - (BOOL)_isNoRaiseOnModificationException:(NSException *)_exception {
106   /* for compatibility with non-X methods, translate some errors to a bool */
107   NSString *n;
108   
109   n = [_exception name];
110   if ([n isEqualToString:@"EOEvaluationError"])
111     return YES;
112   if ([n isEqualToString:@"EODelegateRejects"])
113     return YES;
114
115   return NO;
116 }
117
118 - (NSException *)insertRowX:(NSDictionary *)row forEntity:(EOEntity *)entity {
119   EOSQLExpression     *sqlexpr;
120   NSMutableDictionary *mrow = (id)row;
121   NSException         *ex;
122     
123   if (!isOpen)
124     return [[ChannelIsNotOpenedException new] autorelease];
125   
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"
130                         userInfo:nil];
131   }
132     
133   if ([self isFetchInProgress])
134     return [AdaptorIsFetchingException exceptionWithAdaptor:self];
135   
136   if ([self->adaptorContext transactionNestingLevel] == 0)
137     return [NoTransactionInProgressException exceptionWithAdaptor:self];
138   
139   if (delegateRespondsTo.willInsertRow) {
140     EODelegateResponse response;
141         
142     mrow = AUTORELEASE([row mutableCopyWithZone:[row zone]]);
143     response = [delegate adaptorChannel:self
144                          willInsertRow:mrow
145                          forEntity:entity];
146     if (response == EODelegateRejects) {
147       return [NSException exceptionWithName:@"EODelegateRejects"
148                           reason:@"delegate rejected insert"
149                           userInfo:nil];
150     }
151     if (response == EODelegateOverrides)
152       return nil;
153   }
154
155   sqlexpr = [[[self->adaptorContext adaptor]
156                               expressionClass]
157                               insertExpressionForRow:mrow
158                               entity:entity
159                               channel:self];
160   
161   ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
162   if (ex != nil)
163     return ex;
164
165   if(delegateRespondsTo.didInsertRow)
166     [delegate adaptorChannel:self didInsertRow:mrow forEntity:entity];
167
168   return nil;
169 }
170
171 - (NSException *)updateRowX:(NSDictionary *)row
172   describedByQualifier:(EOSQLQualifier *)qualifier
173 {
174   EOSQLExpression     *sqlexpr = nil;
175   NSMutableDictionary *mrow    = (id)row;
176   NSException *ex;
177
178   if (!isOpen)
179     return [[ChannelIsNotOpenedException new] autorelease];
180
181   if (row == nil) {
182     return [NSException exceptionWithName:NSInvalidArgumentException
183                         reason:
184                           @"row argument for updateRow:describedByQualifier: "
185                           @"must not be the nil object"
186                         userInfo:nil];
187   }
188   
189   if ([self isFetchInProgress])
190     return [AdaptorIsFetchingException exceptionWithAdaptor:self];
191
192   if ([self->adaptorContext transactionNestingLevel] == 0)
193     return [NoTransactionInProgressException exceptionWithAdaptor:self];
194
195   if (delegateRespondsTo.willUpdateRow) {
196     EODelegateResponse response;
197     
198     mrow = AUTORELEASE([row mutableCopyWithZone:[row zone]]);
199     response = [delegate adaptorChannel:self
200                          willUpdateRow:mrow
201                          describedByQualifier:qualifier];
202     if (response == EODelegateRejects) {
203       return [NSException exceptionWithName:@"EODelegateRejects"
204                           reason:@"delegate rejected update"
205                           userInfo:nil];
206     }
207     if (response == EODelegateOverrides)
208       return nil;
209   }
210
211   sqlexpr = [[self _adaptorExpressionClass]
212                    updateExpressionForRow:mrow
213                    qualifier:qualifier
214                    channel:self];
215   
216   ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
217   if (ex != nil) return ex;
218   
219   if (delegateRespondsTo.didUpdateRow) {
220     [delegate adaptorChannel:self
221               didUpdateRow:mrow
222               describedByQualifier:qualifier];
223   }
224   return nil;
225 }
226
227 - (NSException *)deleteRowsDescribedByQualifierX:(EOSQLQualifier *)qualifier {
228   EOSQLExpression *sqlexpr = nil;
229   NSException *ex;
230   
231   if (!isOpen)
232     return [[ChannelIsNotOpenedException new] autorelease];
233   
234   if ([self isFetchInProgress])
235     return [AdaptorIsFetchingException exceptionWithAdaptor:self];
236   
237   if ([self->adaptorContext transactionNestingLevel] == 0)
238     return [NoTransactionInProgressException exceptionWithAdaptor:self];
239   
240   if (delegateRespondsTo.willDeleteRows) {
241     EODelegateResponse response;
242     
243     response = [delegate adaptorChannel:self
244                          willDeleteRowsDescribedByQualifier:qualifier];
245     if (response == EODelegateRejects) {
246       return [NSException exceptionWithName:@"EODelegateRejects"
247                           reason:@"delegate rejected delete"
248                           userInfo:nil];
249     }
250     if (response == EODelegateOverrides)
251       return nil;
252   }
253   
254   sqlexpr = [[self _adaptorExpressionClass]
255                    deleteExpressionWithQualifier:qualifier
256                    channel:self];
257   
258   ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
259   if (ex != nil) return ex;
260   
261   if (delegateRespondsTo.didDeleteRows)
262     [delegate adaptorChannel:self didDeleteRowsDescribedByQualifier:qualifier];
263   
264   return nil;
265 }
266
267 /* compatibility methods (DEPRECATED, use the ...X methods  */
268
269 - (BOOL)selectAttributes:(NSArray *)attributes
270   describedByQualifier:(EOSQLQualifier *)qualifier
271   fetchOrder:(NSArray *)fetchOrder
272   lock:(BOOL)lockFlag
273 {
274   NSException *ex;
275   
276   ex = [self selectAttributesX:attributes describedByQualifier:qualifier
277              fetchOrder:fetchOrder lock:lockFlag];
278   if (ex == nil)
279     return YES;
280   if ([self _isNoRaiseOnModificationException:ex])
281     return NO;
282   [ex raise];
283   return NO;
284 }
285
286 - (BOOL)insertRow:(NSDictionary *)_row forEntity:(EOEntity *)_entity {
287   NSException *ex;
288   
289   ex = [self insertRowX:_row forEntity:_entity];
290   if (ex == nil)
291     return YES;
292   if ([self _isNoRaiseOnModificationException:ex])
293     return NO;
294   [ex raise];
295   return NO;
296 }
297
298 - (BOOL)updateRow:(NSDictionary *)_row 
299   describedByQualifier:(EOSQLQualifier *)_q
300 {
301   NSException *ex;
302   
303   ex = [self updateRowX:_row describedByQualifier:_q];
304   if (ex == nil)
305     return YES;
306   if ([self _isNoRaiseOnModificationException:ex])
307     return NO;
308   [ex raise];
309   return NO;
310 }
311
312 - (BOOL)deleteRowsDescribedByQualifier:(EOSQLQualifier *)_qualifier {
313   NSException *ex;
314   
315   ex = [self deleteRowsDescribedByQualifierX:_qualifier];
316   if (ex == nil)
317     return YES;
318   if ([self _isNoRaiseOnModificationException:ex])
319     return NO;
320   [ex raise];
321   return NO;
322 }
323
324 /* fetch operations */
325
326 - (NSException *)selectAttributesX:(NSArray *)attributes
327   describedByQualifier:(EOSQLQualifier *)qualifier
328   fetchOrder:(NSArray *)fetchOrder
329   lock:(BOOL)lockFlag
330 {
331   NSException     *ex;
332   EOSQLExpression *sqlexpr = nil;
333   NSMutableArray  *mattrs  = (NSMutableArray *)attributes;
334   NSMutableArray  *mfetch  = (NSMutableArray *)fetchOrder;
335
336   if (!isOpen)
337     return [[ChannelIsNotOpenedException new] autorelease];
338
339   if (attributes == nil) {
340     return [NSException exceptionWithName:NSInvalidArgumentException
341                         reason:
342                           @"attributes argument for selectAttributes:"
343                           @"describedByQualifier:fetchOrder:lock: "
344                           @"must not be the nil object"
345                         userInfo:nil];
346   }
347   
348   if ([self isFetchInProgress])
349     return [AdaptorIsFetchingException exceptionWithAdaptor:self];
350   
351   if ([self->adaptorContext transactionNestingLevel] == 0)
352     return [NoTransactionInProgressException exceptionWithAdaptor:self];
353   
354   if (delegateRespondsTo.willSelectAttributes) {
355     EODelegateResponse response;
356         
357     mattrs = [[attributes mutableCopy] autorelease];
358     mfetch = [[fetchOrder mutableCopy] autorelease];
359
360     response = [delegate adaptorChannel:self
361                          willSelectAttributes:mattrs
362                          describedByQualifier:qualifier
363                          fetchOrder:mfetch
364                          lock:lockFlag];
365     if (response == EODelegateRejects) {
366       return [NSException exceptionWithName:@"EODelegateRejects"
367                           reason:@"delegate rejected select"
368                           userInfo:nil];
369     }
370     if (response == EODelegateOverrides)
371       return nil;
372   }
373
374 #if 0
375 #warning DEBUG LOG, REMOVE!
376   [self logWithFormat:@"fetch qualifier: %@", qualifier];
377 #endif
378
379   sqlexpr = [[[self->adaptorContext adaptor]
380                                 expressionClass]
381                                 selectExpressionForAttributes:attributes
382                                 lock:lockFlag
383                                 qualifier:qualifier
384                                 fetchOrder:fetchOrder
385                                 channel:self];
386     
387   ex = [self evaluateExpressionX:[sqlexpr expressionValueForContext:nil]];
388   if (ex != nil)
389     return ex;
390   
391   if (delegateRespondsTo.didSelectAttributes) {
392     [delegate adaptorChannel:self
393               didSelectAttributes:mattrs
394               describedByQualifier:qualifier
395               fetchOrder:mfetch
396               lock:lockFlag];
397   }
398   return nil;
399 }
400
401 - (NSArray *)describeResults:(BOOL)_beautifyNames {
402   [self subclassResponsibility:_cmd];
403   return nil;
404 }
405 - (NSArray *)describeResults {
406   return [self describeResults:YES];
407 }
408
409 - (NSMutableDictionary *)fetchAttributes:(NSArray *)attributes
410   withZone:(NSZone *)_zone
411 {
412     NSMutableDictionary *row = nil;
413
414     if (!self->isOpen)
415       [[ChannelIsNotOpenedException new] raise];
416
417     if (_zone == NULL)
418         _zone = NSDefaultMallocZone();
419
420     if(![self isFetchInProgress])
421       [[AdaptorIsNotFetchingException exceptionWithAdaptor:self] raise];
422
423     if(delegateRespondsTo.willFetchAttributes) {
424         row = [delegate adaptorChannel:self
425                         willFetchAttributes:attributes
426                         withZone:_zone];
427     }
428
429     /* NOTE: primaryFetchAttributes:withZone: have to set the isFetchInProgress
430        status */
431     if(row == nil)
432         row = [self primaryFetchAttributes:attributes withZone:_zone];
433
434     if(row) {
435         if(delegateRespondsTo.didFetchAttributes)
436             row = [delegate adaptorChannel:self
437                             didFetchAttributes:row
438                             withZone:_zone];
439         if(delegateRespondsTo.didChangeResultSet)
440             [delegate adaptorChannelDidChangeResultSet:self];
441     }
442     else {
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
446            intention. */
447         if(delegateRespondsTo.didFinishFetching)
448             [delegate adaptorChannelDidFinishFetching:self];
449     }
450     return row;
451 }
452
453 - (BOOL)isFetchInProgress {
454     return self->isFetchInProgress;
455 }
456
457 - (void)cancelFetch {
458     if (!isOpen)
459       [[ChannelIsNotOpenedException new] raise];
460
461     self->isFetchInProgress = NO;
462 }
463
464 - (NSMutableDictionary *)dictionaryWithObjects:(id *)objects 
465   forAttributes:(NSArray *)attributes zone:(NSZone *)zone
466 {
467     [self notImplemented:_cmd];
468     return nil;
469 }
470
471 - (NSMutableDictionary*)primaryFetchAttributes:(NSArray *)attributes 
472   withZone:(NSZone *)zone
473 {
474   [self subclassResponsibility:_cmd];
475   return nil;
476 }
477
478 - (BOOL)evaluateExpression:(NSString *)anExpression {
479   [self subclassResponsibility:_cmd];
480   return NO;
481 }
482 - (NSException *)evaluateExpressionX:(NSString *)_sql {
483   NSException *ex;
484   BOOL ok;
485   
486   ex = nil;
487   ok = NO;
488   NS_DURING
489     ok = [self evaluateExpression:_sql];
490   NS_HANDLER
491     ex = [localException retain];
492   NS_ENDHANDLER;
493   
494   if (ex) return [ex autorelease];
495   if (ok) return nil;
496   
497   return [NSException exceptionWithName:@"EOEvaluationError"
498                       reason:@"could not evaluate SQL expression"
499                       userInfo:nil];
500 }
501
502 - (EOAdaptorContext *)adaptorContext {
503   return self->adaptorContext;
504 }
505
506 - (EOModel *)describeModelWithTableNames:(NSArray *)tableNames {
507   [self subclassResponsibility:_cmd];
508   return nil;
509 }
510
511 - (NSArray *)describeTableNames {
512   [self subclassResponsibility:_cmd];
513   return nil;
514 }
515
516 - (BOOL)readTypesForEntity:(EOEntity*)anEntity {
517   [self subclassResponsibility:_cmd];
518   return NO;
519 }
520
521 - (BOOL)readTypeForAttribute:(EOAttribute*)anAttribute {
522   [self subclassResponsibility:_cmd];
523   return NO;
524 }
525
526 // delegate
527
528 - (id)delegate {
529     return self->delegate;
530 }
531
532 - (void)setDelegate:(id)_delegate {
533     self->delegate = _delegate;
534
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:)];
579 }
580
581 - (void)setDebugEnabled:(BOOL)flag {
582     self->debugEnabled = flag;
583 }
584
585 - (BOOL)isDebugEnabled {
586     return self->debugEnabled;
587 }
588 - (BOOL)isOpen {
589     return self->isOpen;
590 }
591
592 @end /* EOAdaptorChannel */
593
594 #import <EOControl/EOFetchSpecification.h>
595
596 @implementation EOAdaptorChannel(PrimaryKeyGeneration) // new in EOF2
597
598 - (NSDictionary *)primaryKeyForNewRowWithEntity:(EOEntity *)_entity {
599   return nil;
600 }
601
602 @end /* EOAdaptorChannel(PrimaryKeyGeneration) */
603
604 @implementation EOAdaptorChannel(EOF2Additions)
605
606 - (void)selectAttributes:(NSArray *)_attributes
607   fetchSpecification:(EOFetchSpecification *)_fspec
608   lock:(BOOL)_flag
609   entity:(EOEntity *)_entity
610 {
611   EOSQLQualifier *q;
612   BOOL isOk;
613   
614   q = (EOSQLQualifier *)[_fspec qualifier];
615   
616   isOk = [self selectAttributes:_attributes
617                describedByQualifier:q
618                fetchOrder:[_fspec sortOrderings]
619                lock:_flag];
620   if (!isOk) {
621     [NSException raise:@"Select failed"
622                  format:@"could not select attributes for fetch spec"];
623   }
624 }
625
626 - (void)setAttributesToFetch:(NSArray *)_attributes {
627   [self notImplemented:_cmd];
628 }
629 - (NSArray *)attributesToFetch {
630   NSLog(@"ERROR(%s): subclasses must override this method!", 
631         __PRETTY_FUNCTION__);
632   return nil;
633 }
634
635 - (NSMutableDictionary *)fetchRowWithZone:(NSZone *)_zone {
636   return [self fetchAttributes:[self attributesToFetch] withZone:_zone];
637 }
638
639 @end /* EOAdaptorChannel(EOF2Additions) */
640
641 @implementation EOAdaptorChannel(Internals)
642
643 - (NSArray *)_sortAttributesForSelectExpression:(NSArray *)_attrs {
644   return _attrs;
645 }
646
647 @end /* EOAdaptorChannel(Internals) */