2 PostgreSQL72Channel+Model.m
4 Copyright (C) 1999 MDlink online service center GmbH and Helge Hess
5 Copyright (C) 2000-2004 SKYRIX Software AG and Helge Hess
7 Author: Helge Hess (helge.hess@opengroupware.org)
9 This file is part of the PostgreSQL72 Adaptor Library
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.
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.
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.
27 #include "PostgreSQL72Channel.h"
28 #include "NSString+PostgreSQL72.h"
29 #include "EOAttribute+PostgreSQL72.h"
32 @interface EORelationship(FixMe)
33 - (void)addJoin:(id)_join;
36 @implementation PostgreSQL72Channel(ModelFetching)
38 static BOOL debugOn = NO;
40 - (NSArray *)_attributesForTableName:(NSString *)_tableName {
41 NSMutableArray *attributes;
43 NSArray *resultDescription;
46 if (![_tableName length])
49 attributes = [self->_attributesForTableName objectForKey:_tableName];
50 if (attributes != nil)
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 "
59 sqlExpr = [NSString stringWithFormat:sqlExpr, _tableName];
61 if (![self evaluateExpression:sqlExpr]) {
63 "Could not evaluate column-describe '%s' on table '%s'\n",
64 [sqlExpr cString], [_tableName cString]);
68 resultDescription = [self describeResults];
69 attributes = [NSMutableArray arrayWithCapacity:16];
71 while ((row = [self fetchAttributes:resultDescription withZone:NULL])) {
72 EOAttribute *attribute;
73 NSString *columnName, *externalType, *attrName;
75 columnName = [[row objectForKey:@"attname"] stringValue];
76 attrName = [columnName _pgModelMakeInstanceVarName];
77 externalType = [[row objectForKey:@"typname"] stringValue];
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;
87 [self->_attributesForTableName setObject:attributes forKey:_tableName];
88 if (debugOn) NSLog(@"%s: got attrs: %@", __PRETTY_FUNCTION__, attributes);
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;
100 if ([_tableName length] == 0)
104 [self->_primaryKeysNamesForTableName objectForKey:_tableName];
106 if (pkNameForTableName != nil)
107 return pkNameForTableName;
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 "
116 @"tablename = '%@') "
117 @"AND a.indisprimary)", _tableName];
119 if (![self evaluateExpression:selectExpression])
122 resultDescription = [self describeResults];
123 columnNameKey = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
124 primaryKeys = [NSMutableArray arrayWithCapacity:4];
126 while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
127 [primaryKeys addObject:[row objectForKey:columnNameKey]];
129 pkNameForTableName = primaryKeys;
130 [self->_primaryKeysNamesForTableName setObject:pkNameForTableName
132 return pkNameForTableName;
135 - (NSArray *)_foreignKeysForTableName:(NSString *)_tableName {
139 - (EOModel *)describeModelWithTableNames:(NSArray *)_tableNames {
140 NSMutableArray *buildRelShips = [NSMutableArray arrayWithCapacity:64];
141 EOModel *model = AUTORELEASE([EOModel new]);
142 int cnt, tc = [_tableNames count];
144 for (cnt = 0; cnt < tc; cnt++) {
145 NSMutableDictionary *relNamesUsed;
146 NSMutableArray *classProperties;
147 NSMutableArray *primaryKeyAttributes;
155 relNamesUsed = [NSMutableDictionary dictionaryWithCapacity:4];
156 classProperties = [NSMutableArray arrayWithCapacity:16];
157 primaryKeyAttributes = [NSMutableArray arrayWithCapacity:2];
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];
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];
176 for (cnt2 = 0; cnt2 < ac; cnt2++) {
177 EOAttribute *attribute = [attributes objectAtIndex:cnt2];
178 NSString *columnName = [attribute columnName];
180 attribute = [attributes objectAtIndex:cnt2];
181 columnName = [attribute columnName];
183 [entity addAttribute:attribute];
184 [classProperties addObject:attribute];
186 if ([pkeys containsObject:columnName])
187 [primaryKeyAttributes addObject:attribute];
189 [entity setClassProperties:classProperties];
190 [entity setPrimaryKeyAttributes:primaryKeyAttributes];
192 for (cnt2 = 0; cnt2 < fkc; cnt2++) {
194 NSMutableArray *classProperties;
195 NSString *sa, *da, *dt;
198 NSString *relName = nil;
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];
207 // TODO: do something about the join (just use rel?)
208 join = [[[NSClassFromString(@"EOJoin") alloc] init] autorelease];
210 if ([pkeys containsObject:sa])
211 relName = [@"to" stringByAppendingString:[dt _pgModelMakeClassName]];
213 relName = [@"to" stringByAppendingString:
214 [[sa _pgModelMakeInstanceVarName]
215 _pgStringWithCapitalizedFirstChar]];
216 if ([relName hasSuffix:@"Id"]) {
217 int cLength = [relName cStringLength];
219 relName = [relName substringToIndex:cLength - 2];
222 if ([relNamesUsed objectForKey:relName] != nil) {
223 int useCount = [[relNamesUsed objectForKey:relName] intValue];
225 [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)]
227 relName = [NSString stringWithFormat:@"%s%d",
228 [relName cString], useCount];
231 [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
233 [rel setName:relName];
234 //[rel setDestinationEntity:(EOEntity *)[dt _pgModelMakeClassName]];
237 // TODO: EOJoin is removed, fix this ...
238 [(id)join setSourceAttribute:
239 (EOAttribute *)[sa _pgModelMakeInstanceVarName]];
240 [(id)join setDestinationAttribute:
241 (EOAttribute *)[da _pgModelMakeInstanceVarName]];
244 [entity addRelationship:rel];
245 [classProperties addObjectsFromArray:[entity classProperties]];
246 [classProperties addObject:rel];
247 [entity setClassProperties:classProperties];
248 [buildRelShips addObject:rel];
251 [entity setAttributesUsedForLocking:[entity attributes]];
254 [buildRelShips makeObjectsPerformSelector:
255 @selector(replaceStringsWithObjects)];
257 // make reverse relations
259 int cnt, rc = [buildRelShips count];
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;
271 if ([pkeys containsObject:sa]
273 relName = [@"to" stringByAppendingString:
274 [(EOEntity *)[reverse destinationEntity] name]];
276 relName = [@"to" stringByAppendingString:
277 [[[sa name] _pgModelMakeInstanceVarName]
278 _pgStringWithCapitalizedFirstChar]];
279 if ([relName hasSuffix:@"Id"]) {
280 int cLength = [relName cStringLength];
282 relName = [relName substringToIndex:cLength - 2];
286 if ([entity relationshipNamed:relName]) {
290 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
291 while ([entity relationshipNamed:numName]) {
293 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
299 [reverse setName:relName];
301 [entity addRelationship:reverse];
303 [classProperties addObjectsFromArray:[entity classProperties]];
304 [classProperties addObject:reverse];
305 [entity setClassProperties:classProperties];
309 [model setAdaptorName:@"PostgreSQL72"];
310 [model setAdaptorClassName:@"PostgreSQL72Adaptor"];
311 [model setConnectionDictionary:
312 [[adaptorContext adaptor] connectionDictionary]];
317 - (NSArray *)_runSingleColumnQuery:(NSString *)_query {
318 NSMutableArray *names;
319 NSArray *resultDescription;
320 NSString *attributeName;
323 if (![self evaluateExpression:_query]) {
324 fprintf(stderr, "Could not evaluate expression: '%s'\n", [_query cString]);
328 resultDescription = [self describeResults];
329 attributeName = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
330 names = [NSMutableArray arrayWithCapacity:16];
332 while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
333 [names addObject:[row objectForKey:attributeName]];
338 - (NSArray *)describeTableNames {
344 @"WHERE (relkind='r') AND (relname !~ '^pg_') AND "
345 @"(relname !~ '^xinv[0-9]+') "
347 return [self _runSingleColumnQuery:sql];
350 - (NSArray *)describeDatabaseNames {
351 return [self _runSingleColumnQuery:
352 @"SELECT datname FROM pg_database ORDER BY datname"];
355 - (NSArray *)describeUserNames {
356 return [self _runSingleColumnQuery:@"SELECT usename FROM pg_user"];
359 @end /* PostgreSQL72Channel(ModelFetching) */
361 void __link_PostgreSQL72ChannelModel() {
362 // used to force linking of object file
363 __link_PostgreSQL72ChannelModel();