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.
26 // $Id: PostgreSQL72Channel+Model.m 1 2004-08-20 10:38:46Z znek $
28 #include "PostgreSQL72Channel.h"
29 #include "NSString+PostgreSQL72.h"
30 #include "EOAttribute+PostgreSQL72.h"
33 @interface EORelationship(FixMe)
34 - (void)addJoin:(id)_join;
37 @implementation PostgreSQL72Channel(ModelFetching)
39 static BOOL debugOn = NO;
41 - (NSArray *)_attributesForTableName:(NSString *)_tableName {
42 NSMutableArray *attributes;
44 NSArray *resultDescription;
47 if (![_tableName length])
50 attributes = [self->_attributesForTableName objectForKey:_tableName];
51 if (attributes != nil)
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 "
60 sqlExpr = [NSString stringWithFormat:sqlExpr, _tableName];
62 if (![self evaluateExpression:sqlExpr]) {
64 "Could not evaluate column-describe '%s' on table '%s'\n",
65 [sqlExpr cString], [_tableName cString]);
69 resultDescription = [self describeResults];
70 attributes = [NSMutableArray arrayWithCapacity:16];
72 while ((row = [self fetchAttributes:resultDescription withZone:NULL])) {
73 EOAttribute *attribute;
74 NSString *columnName, *externalType, *attrName;
76 columnName = [[row objectForKey:@"attname"] stringValue];
77 attrName = [columnName _pgModelMakeInstanceVarName];
78 externalType = [[row objectForKey:@"typname"] stringValue];
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;
88 [self->_attributesForTableName setObject:attributes forKey:_tableName];
89 if (debugOn) NSLog(@"%s: got attrs: %@", __PRETTY_FUNCTION__, attributes);
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;
101 if ([_tableName length] == 0)
105 [self->_primaryKeysNamesForTableName objectForKey:_tableName];
107 if (pkNameForTableName != nil)
108 return pkNameForTableName;
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 "
117 @"tablename = '%@') "
118 @"AND a.indisprimary)", _tableName];
120 if (![self evaluateExpression:selectExpression])
123 resultDescription = [self describeResults];
124 columnNameKey = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
125 primaryKeys = [NSMutableArray arrayWithCapacity:4];
127 while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
128 [primaryKeys addObject:[row objectForKey:columnNameKey]];
130 pkNameForTableName = primaryKeys;
131 [self->_primaryKeysNamesForTableName setObject:pkNameForTableName
133 return pkNameForTableName;
136 - (NSArray *)_foreignKeysForTableName:(NSString *)_tableName {
140 - (EOModel *)describeModelWithTableNames:(NSArray *)_tableNames {
141 NSMutableArray *buildRelShips = [NSMutableArray arrayWithCapacity:64];
142 EOModel *model = AUTORELEASE([EOModel new]);
143 int cnt, tc = [_tableNames count];
145 for (cnt = 0; cnt < tc; cnt++) {
146 NSMutableDictionary *relNamesUsed;
147 NSMutableArray *classProperties;
148 NSMutableArray *primaryKeyAttributes;
156 relNamesUsed = [NSMutableDictionary dictionaryWithCapacity:4];
157 classProperties = [NSMutableArray arrayWithCapacity:16];
158 primaryKeyAttributes = [NSMutableArray arrayWithCapacity:2];
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];
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];
177 for (cnt2 = 0; cnt2 < ac; cnt2++) {
178 EOAttribute *attribute = [attributes objectAtIndex:cnt2];
179 NSString *columnName = [attribute columnName];
181 attribute = [attributes objectAtIndex:cnt2];
182 columnName = [attribute columnName];
184 [entity addAttribute:attribute];
185 [classProperties addObject:attribute];
187 if ([pkeys containsObject:columnName])
188 [primaryKeyAttributes addObject:attribute];
190 [entity setClassProperties:classProperties];
191 [entity setPrimaryKeyAttributes:primaryKeyAttributes];
193 for (cnt2 = 0; cnt2 < fkc; cnt2++) {
195 NSMutableArray *classProperties;
196 NSString *sa, *da, *dt;
199 NSString *relName = nil;
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];
209 if ([pkeys containsObject:sa])
210 relName = [@"to" stringByAppendingString:[dt _pgModelMakeClassName]];
212 relName = [@"to" stringByAppendingString:
213 [[sa _pgModelMakeInstanceVarName]
214 _pgStringWithCapitalizedFirstChar]];
215 if ([relName hasSuffix:@"Id"]) {
216 int cLength = [relName cStringLength];
218 relName = [relName substringToIndex:cLength - 2];
221 if ([relNamesUsed objectForKey:relName] != nil) {
222 int useCount = [[relNamesUsed objectForKey:relName] intValue];
224 [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)]
226 relName = [NSString stringWithFormat:@"%s%d",
227 [relName cString], useCount];
230 [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
232 [rel setName:relName];
233 //[rel setDestinationEntity:(EOEntity *)[dt _pgModelMakeClassName]];
236 // TODO: EOJoin is removed, fix this ...
237 [(id)join setSourceAttribute:
238 (EOAttribute *)[sa _pgModelMakeInstanceVarName]];
239 [(id)join setDestinationAttribute:
240 (EOAttribute *)[da _pgModelMakeInstanceVarName]];
243 [entity addRelationship:rel];
244 [classProperties addObjectsFromArray:[entity classProperties]];
245 [classProperties addObject:rel];
246 [entity setClassProperties:classProperties];
247 [buildRelShips addObject:rel];
250 [entity setAttributesUsedForLocking:[entity attributes]];
253 [buildRelShips makeObjectsPerformSelector:
254 @selector(replaceStringsWithObjects)];
256 // make reverse relations
258 int cnt, rc = [buildRelShips count];
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;
270 if ([pkeys containsObject:sa]
272 relName = [@"to" stringByAppendingString:
273 [(EOEntity *)[reverse destinationEntity] name]];
275 relName = [@"to" stringByAppendingString:
276 [[[sa name] _pgModelMakeInstanceVarName]
277 _pgStringWithCapitalizedFirstChar]];
278 if ([relName hasSuffix:@"Id"]) {
279 int cLength = [relName cStringLength];
281 relName = [relName substringToIndex:cLength - 2];
285 if ([entity relationshipNamed:relName]) {
289 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
290 while ([entity relationshipNamed:numName]) {
292 numName = [NSString stringWithFormat:@"%s%d", [relName cString], cnt];
298 [reverse setName:relName];
300 [entity addRelationship:reverse];
302 [classProperties addObjectsFromArray:[entity classProperties]];
303 [classProperties addObject:reverse];
304 [entity setClassProperties:classProperties];
308 [model setAdaptorName:@"PostgreSQL72"];
309 [model setAdaptorClassName:@"PostgreSQL72Adaptor"];
310 [model setConnectionDictionary:
311 [[adaptorContext adaptor] connectionDictionary]];
316 - (NSArray *)_runSingleColumnQuery:(NSString *)_query {
317 NSMutableArray *names;
318 NSArray *resultDescription;
319 NSString *attributeName;
322 if (![self evaluateExpression:_query]) {
323 fprintf(stderr, "Could not evaluate expression: '%s'\n", [_query cString]);
327 resultDescription = [self describeResults];
328 attributeName = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
329 names = [NSMutableArray arrayWithCapacity:16];
331 while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
332 [names addObject:[row objectForKey:attributeName]];
337 - (NSArray *)describeTableNames {
343 @"WHERE (relkind='r') AND (relname !~ '^pg_') AND "
344 @"(relname !~ '^xinv[0-9]+') "
346 return [self _runSingleColumnQuery:sql];
349 - (NSArray *)describeDatabaseNames {
350 return [self _runSingleColumnQuery:
351 @"SELECT datname FROM pg_database ORDER BY datname"];
354 - (NSArray *)describeUserNames {
355 return [self _runSingleColumnQuery:@"SELECT usename FROM pg_user"];
358 @end /* PostgreSQL72Channel(ModelFetching) */
360 void __link_PostgreSQL72ChannelModel() {
361 // used to force linking of object file
362 __link_PostgreSQL72ChannelModel();