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