]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EODatabaseFaultResolver.m
renamed PostgreSQL72 to PostgreSQL, install in Library/GDLAdaptors-1.1
[sope] / sope-gdl1 / GDLAccess / EODatabaseFaultResolver.m
1 /* 
2    EODatabaseFaultResolver.m
3
4    Copyright (C) 1996 Free Software Foundation, Inc.
5
6    Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
7    Date: 1996
8
9    Author: Helge Hess <helge.hess@mdlink.de>
10    Date: 1999
11
12    This file is part of the GNUstep Database Library.
13
14    This library is free software; you can redistribute it and/or
15    modify it under the terms of the GNU Library General Public
16    License as published by the Free Software Foundation; either
17    version 2 of the License, or (at your option) any later version.
18
19    This library is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22    Library General Public License for more details.
23
24    You should have received a copy of the GNU Library General Public
25    License along with this library; see the file COPYING.LIB.
26    If not, write to the Free Software Foundation,
27    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30 #import "common.h"
31 #import "EODatabaseFaultResolver.h"
32 #import "EODatabaseChannel.h"
33 #import "EODatabaseContext.h"
34 #import "EOEntity.h"
35 #import "EODatabaseFault.h"
36 #import "EOSQLQualifier.h"
37 #import "EOGenericRecord.h"
38
39 @implementation EODatabaseFaultResolver
40
41 - (id)initWithDatabaseChannel:(EODatabaseChannel *)aChannel
42   zone:(NSZone *)aZone  
43   targetClass:(Class)_targetClass 
44 {
45   if ((self = [super init])) {
46     self->channel         = aChannel;
47     self->targetClass     = _targetClass;
48     self->zone            = aZone;
49     self->faultReferences = 0;
50   }
51   return self;
52 }
53
54 - (BOOL)fault {
55   return NO;
56 }
57
58 - (EODatabaseChannel *)databaseChannel {
59   return self->channel;
60 }
61
62 - (Class)targetClass; {
63   return self->targetClass;
64 }
65
66 - (NSDictionary *)primaryKey {
67   return nil;
68 }
69 - (EOEntity *)entity {
70   return nil;
71 }
72 - (EOSQLQualifier *)qualifier {
73   return nil;
74 }
75 - (NSArray *)fetchOrder {
76   return nil;
77 }
78
79 @end /* EODatabaseFaultResolver */
80
81 @implementation EOArrayFault
82
83 - (id)initWithQualifier:(EOSQLQualifier *)aQualifier
84   fetchOrder:(NSArray *)aFetchOrder 
85   databaseChannel:(EODatabaseChannel *)aChannel 
86   zone:(NSZone *)aZone  
87   targetClass:(Class)_targetClass 
88 {
89   
90   if ((self = [super initWithDatabaseChannel:aChannel zone:aZone 
91                      targetClass:_targetClass])) {
92     self->qualifier  = RETAIN(aQualifier);
93     self->fetchOrder = RETAIN(aFetchOrder);
94
95     NSAssert([self->targetClass isKindOfClass:[NSArray class]],
96              @"target class of an array fault is not an array class");
97   }
98   return self;
99 }
100
101 - (void)dealloc {
102   RELEASE(self->qualifier);
103   RELEASE(self->fetchOrder);
104   [super dealloc];
105 }
106
107 - (EOEntity *)entity {
108   return [self->qualifier entity];
109 }
110
111 - (EOSQLQualifier *)qualifier {
112   return self->qualifier;
113 }
114
115 - (NSArray *)fetchOrder {
116   return self->fetchOrder;
117 }
118
119 - (void)completeInitializationOfObject:(id)_fault {
120   unsigned int oldRetainCount;
121   BOOL         inTransaction;
122
123   NSAssert([self->targetClass isKindOfClass:[NSArray class]],
124            @"target class of an array fault is not an array class");
125   
126   oldRetainCount = [_fault retainCount];
127     
128   [EOFault clearFault:_fault];
129   NSAssert([(id)_fault init] == _fault, @"init modified fault reference ..");
130
131   NSAssert([_fault isKindOfClass:[NSArray class]],
132            @"resolved-object of an array fault is not of an array class");
133   
134   if ([self->channel isFetchInProgress]) {
135     [NSException raise:NSInvalidArgumentException
136                  format:@"attempt to fault with busy channel: %@", self];
137   }
138     
139   inTransaction = [[self->channel databaseContext] transactionNestingLevel] > 0;
140   if (!inTransaction) {
141     if (![[self->channel databaseContext] beginTransaction]) {
142       [NSException raise:@"DBFaultResolutionException"
143                    format:@"could not begin transaction to resolve fault !"];
144     }
145   }
146     
147   if (![self->channel selectObjectsDescribedByQualifier:self->qualifier
148                       fetchOrder:self->fetchOrder]) {
149     if (!inTransaction)
150       [[self->channel databaseContext] rollbackTransaction];
151     [NSException raise:@"DBFaultResolutionException"
152                  format:@"select for fault failed !"];
153   }
154
155   { // fetch objects
156     id object;
157     
158     while ((object = [self->channel fetchWithZone:zone])) {
159       if (![object isKindOfClass:[EOGenericRecord class]]) {
160         NSLog(@"Object is of class %@", NSStringFromClass([object class]));
161         abort();
162       }
163       NSAssert([object isKindOfClass:[EOGenericRecord class]],
164                @"fetched object is not a EOGenericRecord ..");
165       [(id)_fault addObject:object];
166     }
167
168     object = nil;
169   }
170     
171   [self->channel cancelFetch];
172
173   if (!inTransaction) {
174     if (![[self->channel databaseContext] commitTransaction]) {
175       NSLog(@"WARNING: could not commit fault's transaction !");
176       [NSException raise:@"DBFaultResolutionException"
177                    format:@"could not commit fault's transaction !"];
178     }
179   }
180
181 #if MOF2_DEBUG
182   if ([fault retainCount] != oldRetainCount) {
183     NSLog(@"fault retain count does not match replacement (old=%d, new=%d)",
184           oldRetainCount, [fault retainCount]);
185   }
186 #endif
187
188   NSAssert([_fault retainCount] == oldRetainCount,
189            @"fault retain count does not match replacement's retain count");
190 }
191
192 - (NSString *)descriptionForObject:(id)_fault {
193   return [NSString stringWithFormat:
194                    @"<Array fault 0x%x (qualifier=%@, order=%@, channel=%@)>",
195                    _fault, qualifier, fetchOrder, channel];
196 }
197
198 @end /* EOArrayFault */
199
200 @implementation EOObjectFault
201
202 - (id)initWithPrimaryKey:(NSDictionary *)_key
203   entity:(EOEntity *)anEntity 
204   databaseChannel:(EODatabaseChannel *)aChannel 
205   zone:(NSZone *)aZone  
206   targetClass:(Class)_targetClass 
207 {
208   [super initWithDatabaseChannel:aChannel
209          zone:aZone 
210          targetClass:_targetClass];
211   self->entity     = RETAIN(anEntity);
212   self->primaryKey = RETAIN(_key);
213   return self;
214 }
215
216 - (void)dealloc {
217   RELEASE(self->entity);
218   RELEASE(self->primaryKey);
219   [super dealloc];
220 }
221
222 - (NSDictionary*)primaryKey {
223   return self->primaryKey;
224 }
225
226 - (EOEntity *)entity {
227   return self->entity;
228 }
229
230 - (void)completeInitializationOfObject:(id)_fault {
231   EOSQLQualifier *qualifier = nil;
232   BOOL        channelIsOpen = YES;
233   BOOL        inTransaction = YES;
234   id          object = nil;
235     
236   if ([self->channel isFetchInProgress]) {
237     [NSException raise:NSInvalidArgumentException
238                  format:@"attempt to fault with busy channel: %@", self];
239   }
240   
241   qualifier =
242     [EOSQLQualifier qualifierForPrimaryKey:primaryKey entity:self->entity];
243   if (qualifier == nil) {
244     [NSException raise:NSInvalidArgumentException
245                  format:@"could not build qualifier for fault: %@", self];
246   }
247
248   channelIsOpen = [self->channel isOpen];
249   if (!channelIsOpen) {
250     if (![self->channel openChannel])
251       goto done;
252   }
253
254   inTransaction = [[self->channel databaseContext] transactionNestingLevel] != 0;
255   if (!inTransaction) {
256     if (![[self->channel databaseContext] beginTransaction]) {
257       if (!channelIsOpen) [self->channel closeChannel];
258       goto done;
259     }
260   }
261     
262   if (![self->channel selectObjectsDescribedByQualifier:qualifier fetchOrder:nil]) {
263     if (!inTransaction) {
264       [[self->channel databaseContext] rollbackTransaction];
265       if (!channelIsOpen) [self->channel closeChannel];
266     }
267     goto done;
268   }
269
270   // Fetch the object
271   object = [self->channel fetchWithZone:zone];
272
273   // The fetch failed!
274   if (object == nil) {
275     [self->channel cancelFetch];
276     if (!inTransaction) [[self->channel databaseContext] rollbackTransaction];
277     if (!channelIsOpen) [self->channel closeChannel];
278     goto done;
279   }
280
281   // Make sure we only fetched one object
282   if ([self->channel fetchWithZone:zone])
283     object = nil;
284     
285   [self->channel cancelFetch];
286     
287   if (!inTransaction) {
288     if (![[self->channel databaseContext] commitTransaction]) object = nil;
289     if (!channelIsOpen) [self->channel closeChannel];
290   }
291
292  done:
293   if (object != _fault) {
294     if ([EOFault isFault:_fault])
295       [EOFault clearFault:_fault];
296     
297     [(id)_fault unableToFaultWithPrimaryKey:primaryKey 
298                 entity:self->entity
299                 databaseChannel:self->channel];
300   }
301 }
302
303 - (NSString *)descriptionForObject:(id)_fault {
304   return [NSString stringWithFormat:
305                      @"<Object fault 0x%X "
306                      @"(class=%@, entity=%@, key=%@, channel=%@)>",
307                      _fault,
308                      NSStringFromClass(targetClass), 
309                      [entity name], 
310                      [primaryKey description], 
311                      [channel description]];
312 }
313
314 @end /* EOObjectFault */