]> err.no Git - sope/blob - sope-gdl1/PostgreSQL/PostgreSQL72Channel+Model.m
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@20 e4a50df8-12e2-0310-a44c-efbce7...
[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       join             = [[[EOJoin alloc] init] autorelease];
208       
209       if ([pkeys containsObject:sa])
210         relName = [@"to" stringByAppendingString:[dt _pgModelMakeClassName]];
211       else {
212         relName = [@"to" stringByAppendingString:
213                     [[sa _pgModelMakeInstanceVarName]
214                          _pgStringWithCapitalizedFirstChar]];
215         if ([relName hasSuffix:@"Id"]) {
216           int cLength = [relName cStringLength];
217
218           relName = [relName substringToIndex:cLength - 2];
219         }
220       }
221       if ([relNamesUsed objectForKey:relName] != nil) {
222         int useCount = [[relNamesUsed objectForKey:relName] intValue];
223         
224         [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)] 
225                       forKey:relName];
226         relName = [NSString stringWithFormat:@"%s%d",
227                               [relName cString], useCount];
228       }
229       else
230         [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
231       
232       [rel setName:relName];
233       //[rel setDestinationEntity:(EOEntity *)[dt _pgModelMakeClassName]];
234       [rel setToMany:NO];
235
236       // TODO: EOJoin is removed, fix this ...
237       [(id)join setSourceAttribute:
238              (EOAttribute *)[sa _pgModelMakeInstanceVarName]];
239       [(id)join setDestinationAttribute:
240              (EOAttribute *)[da _pgModelMakeInstanceVarName]];
241       [rel addJoin:join];
242       
243       [entity addRelationship:rel];
244       [classProperties addObjectsFromArray:[entity classProperties]];
245       [classProperties addObject:rel];
246       [entity setClassProperties:classProperties];
247       [buildRelShips addObject:rel];
248     }
249
250     [entity setAttributesUsedForLocking:[entity attributes]];
251   }
252
253   [buildRelShips makeObjectsPerformSelector:
254                    @selector(replaceStringsWithObjects)];
255   /*
256   // make reverse relations
257   {
258     int cnt, rc = [buildRelShips count];
259
260     for (cnt = 0; cnt < rc; cnt++) {
261       EORelationship *rel     = [buildRelShips objectAtIndex:cnt];
262       NSMutableArray *classProperties  = [NSMutableArray new];   
263       EORelationship *reverse = [rel reversedRelationShip];
264       EOEntity       *entity  = [rel destinationEntity];
265       NSArray        *pkeys   = [entity primaryKeyAttributes];
266       BOOL           isToMany = [reverse isToMany];
267       EOAttribute    *sa      = [[[reverse joins] lastObject] sourceAttribute];
268       NSString       *relName = nil;
269
270       if ([pkeys containsObject:sa]
271           || isToMany)
272         relName = [@"to" stringByAppendingString:
273                     [(EOEntity *)[reverse destinationEntity] name]];
274       else {
275         relName = [@"to" stringByAppendingString:
276                     [[[sa name] _pgModelMakeInstanceVarName]
277                           _pgStringWithCapitalizedFirstChar]];
278         if ([relName hasSuffix:@"Id"]) {
279           int cLength = [relName cStringLength];
280
281           relName = [relName substringToIndex:cLength - 2];
282         }
283       }
284
285       if ([entity relationshipNamed:relName]) {
286         int cnt = 1;
287         NSString *numName;
288
289         numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
290         while ([entity relationshipNamed:numName]) {
291           cnt++;
292           numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
293         }
294
295         relName = numName;
296       }
297
298       [reverse setName:relName];
299
300       [entity addRelationship:reverse];
301       
302       [classProperties addObjectsFromArray:[entity classProperties]];
303       [classProperties addObject:reverse];
304       [entity setClassProperties:classProperties];
305     }
306   }
307   */
308   [model setAdaptorName:@"PostgreSQL72"];
309   [model setAdaptorClassName:@"PostgreSQL72Adaptor"];
310   [model setConnectionDictionary:
311            [[adaptorContext adaptor] connectionDictionary]];
312   
313   return model;
314 }
315
316 - (NSArray *)_runSingleColumnQuery:(NSString *)_query {
317   NSMutableArray *names;
318   NSArray        *resultDescription;
319   NSString       *attributeName;
320   NSDictionary   *row;
321   
322   if (![self evaluateExpression:_query]) {
323     fprintf(stderr, "Could not evaluate expression: '%s'\n", [_query cString]);
324     return nil;
325   }
326   
327   resultDescription = [self describeResults];
328   attributeName    = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
329   names            = [NSMutableArray arrayWithCapacity:16];
330   
331   while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
332     [names addObject:[row objectForKey:attributeName]];
333   
334   return names;
335 }
336
337 - (NSArray *)describeTableNames {
338   NSString *sql;
339   
340   sql = 
341     @"SELECT relname "
342     @"FROM pg_class "
343     @"WHERE (relkind='r') AND (relname !~ '^pg_') AND "
344     @"(relname !~ '^xinv[0-9]+') "
345     @"ORDER BY relname";
346   return [self _runSingleColumnQuery:sql];
347 }
348
349 - (NSArray *)describeDatabaseNames {
350   return [self _runSingleColumnQuery:
351                  @"SELECT datname FROM pg_database ORDER BY datname"];
352 }
353
354 - (NSArray *)describeUserNames {
355   return [self _runSingleColumnQuery:@"SELECT usename FROM pg_user"];
356 }
357
358 @end /* PostgreSQL72Channel(ModelFetching) */
359
360 void __link_PostgreSQL72ChannelModel() {
361   // used to force linking of object file
362   __link_PostgreSQL72ChannelModel();
363 }