]> err.no Git - sope/blob - sope-gdl1/PostgreSQL/PostgreSQL72Channel+Model.m
fixed gcc 4.0 warnings
[sope] / sope-gdl1 / PostgreSQL / PostgreSQL72Channel+Model.m
1 /* 
2    PostgreSQL72Channel+Model.m
3
4    Copyright (C) 1999 MDlink online service center GmbH and Helge Hess
5    Copyright (C) 2000-2004 SKYRIX Software AG and Helge Hess
6
7    Author: Helge Hess (helge.hess@opengroupware.org)
8    
9    This file is part of the PostgreSQL72 Adaptor 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 // $Id: PostgreSQL72Channel+Model.m 1 2004-08-20 10:38:46Z znek $
27
28 #include "PostgreSQL72Channel.h"
29 #include "NSString+PostgreSQL72.h"
30 #include "EOAttribute+PostgreSQL72.h"
31 #import "common.h"
32
33 @interface EORelationship(FixMe)
34 - (void)addJoin:(id)_join;
35 @end
36
37 @implementation PostgreSQL72Channel(ModelFetching)
38
39 static BOOL debugOn = NO;
40
41 - (NSArray *)_attributesForTableName:(NSString *)_tableName {
42   NSMutableArray *attributes;
43   NSString       *sqlExpr;
44   NSArray        *resultDescription;
45   NSDictionary   *row;
46   
47   if (![_tableName length])
48     return nil;
49   
50   attributes = [self->_attributesForTableName objectForKey:_tableName];
51   if (attributes != nil)
52     return attributes;
53
54   sqlExpr = 
55     @"SELECT a.attnum, a.attname, t.typname, a.attlen, a.attnotnull "
56     @"FROM pg_class c, pg_attribute a, pg_type t "
57     @"WHERE c.relname='%@' AND a.attnum>0 AND a.attrelid=c.oid AND "
58     @"a.atttypid=t.oid "
59     @"ORDER BY attnum;";
60   sqlExpr = [NSString stringWithFormat:sqlExpr, _tableName];
61   
62   if (![self evaluateExpression:sqlExpr]) {
63     fprintf(stderr,
64             "Could not evaluate column-describe '%s' on table '%s'\n",
65             [sqlExpr cString], [_tableName cString]);
66     return nil;
67   }
68   
69   resultDescription = [self describeResults];
70   attributes = [NSMutableArray arrayWithCapacity:16];
71   
72   while ((row = [self fetchAttributes:resultDescription withZone:NULL])) {
73       EOAttribute *attribute;
74       NSString    *columnName, *externalType, *attrName;
75       
76       columnName   = [[row objectForKey:@"attname"] stringValue];
77       attrName     = [columnName _pgModelMakeInstanceVarName];
78       externalType = [[row objectForKey:@"typname"] stringValue];
79     
80       attribute = [[EOAttribute alloc] init];
81       [attribute setColumnName:columnName];
82       [attribute setName:attrName];
83       [attribute setExternalType:externalType];
84       [attribute loadValueClassForExternalPostgreSQLType:externalType];
85       [attributes addObject:attribute];
86       [attribute release]; attribute = nil;
87   }
88   [self->_attributesForTableName setObject:attributes forKey:_tableName];
89   if (debugOn) NSLog(@"%s: got attrs: %@", __PRETTY_FUNCTION__, attributes);
90   return attributes;
91 }
92
93 - (NSArray *)_primaryKeysNamesForTableName:(NSString *)_tableName {
94   NSArray *pkNameForTableName = nil;
95   NSMutableArray *primaryKeys       = nil;
96   NSString       *selectExpression;
97   NSArray        *resultDescription = nil;
98   NSString       *columnNameKey     = nil;
99   NSDictionary   *row               = nil;
100   
101   if ([_tableName length] == 0)
102     return nil;
103
104   pkNameForTableName =
105     [self->_primaryKeysNamesForTableName objectForKey:_tableName];
106   
107   if (pkNameForTableName != nil)
108     return pkNameForTableName;
109   
110   selectExpression = [NSString stringWithFormat:
111                                  @"SELECT attname FROM pg_attribute WHERE "
112                                  @"attrelid IN (SELECT a.indexrelid FROM "
113                                  @"pg_index a, pg_class b WHERE "
114                                  @"a.indexrelid = b.oid AND "
115                                  @"b.relname in (SELECT indexname FROM "
116                                  @"pg_indexes WHERE "
117                                  @"tablename = '%@') "
118                                  @"AND a.indisprimary)", _tableName];
119
120   if (![self evaluateExpression:selectExpression])
121     return nil;
122     
123   resultDescription = [self describeResults];
124   columnNameKey = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
125   primaryKeys   = [NSMutableArray arrayWithCapacity:4];
126     
127   while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
128     [primaryKeys addObject:[row objectForKey:columnNameKey]];
129
130   pkNameForTableName = primaryKeys;
131   [self->_primaryKeysNamesForTableName setObject:pkNameForTableName
132                                        forKey:_tableName];
133   return pkNameForTableName;
134 }
135
136 - (NSArray *)_foreignKeysForTableName:(NSString *)_tableName {
137   return nil;
138 }
139
140 - (EOModel *)describeModelWithTableNames:(NSArray *)_tableNames {
141   NSMutableArray *buildRelShips = [NSMutableArray arrayWithCapacity:64];
142   EOModel *model = AUTORELEASE([EOModel new]);
143   int cnt, tc = [_tableNames count];
144
145   for (cnt = 0; cnt < tc; cnt++) {
146     NSMutableDictionary *relNamesUsed;
147     NSMutableArray      *classProperties;
148     NSMutableArray      *primaryKeyAttributes;
149     NSString *tableName;
150     NSArray  *attributes;
151     NSArray  *pkeys;
152     NSArray  *fkeys;
153     EOEntity *entity;
154     int      cnt2, ac, fkc;
155     
156     relNamesUsed         = [NSMutableDictionary dictionaryWithCapacity:4];
157     classProperties      = [NSMutableArray arrayWithCapacity:16];
158     primaryKeyAttributes = [NSMutableArray arrayWithCapacity:2];
159     
160     tableName  = [_tableNames objectAtIndex:cnt];
161     attributes = [self _attributesForTableName:tableName];
162     pkeys      = [self _primaryKeysNamesForTableName:tableName];
163     fkeys      = [self _foreignKeysForTableName:tableName];
164     entity     = [[EOEntity new] autorelease];
165     ac         = [attributes count];
166     fkc        = [fkeys      count];
167     
168     [entity setName:[tableName _pgModelMakeClassName]];
169     [entity setClassName:
170               [@"EO" stringByAppendingString:
171                   [tableName _pgModelMakeClassName]]];
172     [entity setExternalName:tableName];
173     [classProperties addObjectsFromArray:[entity classProperties]];
174     [primaryKeyAttributes addObjectsFromArray:[entity primaryKeyAttributes]];
175     [model addEntity:entity];
176
177     for (cnt2 = 0; cnt2 < ac; cnt2++) {
178       EOAttribute *attribute  = [attributes objectAtIndex:cnt2];
179       NSString    *columnName = [attribute columnName];
180
181       attribute  = [attributes objectAtIndex:cnt2];
182       columnName = [attribute columnName];
183       
184       [entity addAttribute:attribute];
185       [classProperties addObject:attribute];
186
187       if ([pkeys containsObject:columnName])
188         [primaryKeyAttributes addObject:attribute];
189     }
190     [entity setClassProperties:classProperties];
191     [entity setPrimaryKeyAttributes:primaryKeyAttributes];
192     
193     for (cnt2 = 0; cnt2 < fkc; cnt2++) {
194       NSDictionary   *fkey;
195       NSMutableArray *classProperties;
196       NSString       *sa, *da, *dt;
197       EORelationship *rel;
198       EOJoin         *join;
199       NSString       *relName = nil;
200       
201       fkey             = [fkeys objectAtIndex:cnt2];
202       classProperties  = [NSMutableArray arrayWithCapacity:16];
203       sa               = [fkey objectForKey:@"sourceAttr"];
204       da               = [fkey objectForKey:@"targetAttr"];
205       dt               = [fkey objectForKey:@"targetTable"];
206       rel              = [[[EORelationship alloc] init] autorelease];
207
208       // TODO: do something about the join (just use rel?)
209       join = [[[NSClassFromString(@"EOJoin") alloc] init] autorelease];
210       
211       if ([pkeys containsObject:sa])
212         relName = [@"to" stringByAppendingString:[dt _pgModelMakeClassName]];
213       else {
214         relName = [@"to" stringByAppendingString:
215                     [[sa _pgModelMakeInstanceVarName]
216                          _pgStringWithCapitalizedFirstChar]];
217         if ([relName hasSuffix:@"Id"]) {
218           int cLength = [relName cStringLength];
219
220           relName = [relName substringToIndex:cLength - 2];
221         }
222       }
223       if ([relNamesUsed objectForKey:relName] != nil) {
224         int useCount = [[relNamesUsed objectForKey:relName] intValue];
225         
226         [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)] 
227                       forKey:relName];
228         relName = [NSString stringWithFormat:@"%s%d",
229                               [relName cString], useCount];
230       }
231       else
232         [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
233       
234       [rel setName:relName];
235       //[rel setDestinationEntity:(EOEntity *)[dt _pgModelMakeClassName]];
236       [rel setToMany:NO];
237
238       // TODO: EOJoin is removed, fix this ...
239       [(id)join setSourceAttribute:
240              (EOAttribute *)[sa _pgModelMakeInstanceVarName]];
241       [(id)join setDestinationAttribute:
242              (EOAttribute *)[da _pgModelMakeInstanceVarName]];
243       [rel addJoin:join];
244       
245       [entity addRelationship:rel];
246       [classProperties addObjectsFromArray:[entity classProperties]];
247       [classProperties addObject:rel];
248       [entity setClassProperties:classProperties];
249       [buildRelShips addObject:rel];
250     }
251
252     [entity setAttributesUsedForLocking:[entity attributes]];
253   }
254
255   [buildRelShips makeObjectsPerformSelector:
256                    @selector(replaceStringsWithObjects)];
257   /*
258   // make reverse relations
259   {
260     int cnt, rc = [buildRelShips count];
261
262     for (cnt = 0; cnt < rc; cnt++) {
263       EORelationship *rel     = [buildRelShips objectAtIndex:cnt];
264       NSMutableArray *classProperties  = [NSMutableArray new];   
265       EORelationship *reverse = [rel reversedRelationShip];
266       EOEntity       *entity  = [rel destinationEntity];
267       NSArray        *pkeys   = [entity primaryKeyAttributes];
268       BOOL           isToMany = [reverse isToMany];
269       EOAttribute    *sa      = [[[reverse joins] lastObject] sourceAttribute];
270       NSString       *relName = nil;
271
272       if ([pkeys containsObject:sa]
273           || isToMany)
274         relName = [@"to" stringByAppendingString:
275                     [(EOEntity *)[reverse destinationEntity] name]];
276       else {
277         relName = [@"to" stringByAppendingString:
278                     [[[sa name] _pgModelMakeInstanceVarName]
279                           _pgStringWithCapitalizedFirstChar]];
280         if ([relName hasSuffix:@"Id"]) {
281           int cLength = [relName cStringLength];
282
283           relName = [relName substringToIndex:cLength - 2];
284         }
285       }
286
287       if ([entity relationshipNamed:relName]) {
288         int cnt = 1;
289         NSString *numName;
290
291         numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
292         while ([entity relationshipNamed:numName]) {
293           cnt++;
294           numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
295         }
296
297         relName = numName;
298       }
299
300       [reverse setName:relName];
301
302       [entity addRelationship:reverse];
303       
304       [classProperties addObjectsFromArray:[entity classProperties]];
305       [classProperties addObject:reverse];
306       [entity setClassProperties:classProperties];
307     }
308   }
309   */
310   [model setAdaptorName:@"PostgreSQL72"];
311   [model setAdaptorClassName:@"PostgreSQL72Adaptor"];
312   [model setConnectionDictionary:
313            [[adaptorContext adaptor] connectionDictionary]];
314   
315   return model;
316 }
317
318 - (NSArray *)_runSingleColumnQuery:(NSString *)_query {
319   NSMutableArray *names;
320   NSArray        *resultDescription;
321   NSString       *attributeName;
322   NSDictionary   *row;
323   
324   if (![self evaluateExpression:_query]) {
325     fprintf(stderr, "Could not evaluate expression: '%s'\n", [_query cString]);
326     return nil;
327   }
328   
329   resultDescription = [self describeResults];
330   attributeName    = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
331   names            = [NSMutableArray arrayWithCapacity:16];
332   
333   while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
334     [names addObject:[row objectForKey:attributeName]];
335   
336   return names;
337 }
338
339 - (NSArray *)describeTableNames {
340   NSString *sql;
341   
342   sql = 
343     @"SELECT relname "
344     @"FROM pg_class "
345     @"WHERE (relkind='r') AND (relname !~ '^pg_') AND "
346     @"(relname !~ '^xinv[0-9]+') "
347     @"ORDER BY relname";
348   return [self _runSingleColumnQuery:sql];
349 }
350
351 - (NSArray *)describeDatabaseNames {
352   return [self _runSingleColumnQuery:
353                  @"SELECT datname FROM pg_database ORDER BY datname"];
354 }
355
356 - (NSArray *)describeUserNames {
357   return [self _runSingleColumnQuery:@"SELECT usename FROM pg_user"];
358 }
359
360 @end /* PostgreSQL72Channel(ModelFetching) */
361
362 void __link_PostgreSQL72ChannelModel() {
363   // used to force linking of object file
364   __link_PostgreSQL72ChannelModel();
365 }