/** Postgres95Adaptor.m Postgres95Adaptor Copyright (C) 2000 Free Software Foundation, Inc. Author: Mirko Viviani Date: February 2000 based on the Postgres95 adaptor written by Mircea Oancea Author: Manuel Guesdon Date: October 2000 $Revision$ $Date$ This file is part of the GNUstep Database Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. **/ #include "config.h" RCS_ID("$Id$") #ifndef NeXT_Foundation_LIBRARY #include #include #include #include #include #include #include #include #include #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include NSString *Postgres95Exception = @"Postgres95Exception"; static int pgConnTotalAllocated = 0; static int pgConnCurrentAllocated = 0; @implementation Postgres95Adaptor - init { return [self initWithName: @"Postgres95"]; } - initWithName: (NSString *)name { if ((self = [super initWithName: name])) { _pgConnPool = [NSMutableArray new]; } return self; } - (void)dealloc { NSEnumerator *enumerator; PGconn *pgConn; enumerator = [_pgConnPool objectEnumerator]; while ((pgConn = [[enumerator nextObject] pointerValue])) [self releasePGconn: pgConn force: YES]; [_pgConnPool release]; [super dealloc]; } - (void)privateReportError: (PGconn*)pgConn { char *message = "NULL pgConn in privateReportError:"; EOFLOGObjectFnStart(); if (pgConn) message = PQerrorMessage(pgConn); NSLog(@"%s", message); EOFLOGObjectFnStop(); } - (void)setCachePGconn: (BOOL)flag { _flags.cachePGconn = flag; } - (BOOL)cachePGconn { return _flags.cachePGconn; } - (void)setPGconnPoolLimit: (int)value { _pgConnPoolLimit = value; } - (int)pgConnPoolLimit { return _pgConnPoolLimit; } /*+ (NSDictionary *)defaultConnectionDictionary { static NSDictionary *dict = nil; if (!dict) dict = [[NSDictionary dictionaryWithObjectsAndKeys:NSHomeDirectory(), FlatFilePathKey, [self defaultRowSeparator], FlatFileRowSeparatorKey, [self defaultColumnSeparator], FlatFileColumnSeparatorKey, @"Y", FlatFileUseHeadersKey, nil] retain]; return dict; }*/ static NSString *externalTypeNames[] = { #warning (stephane@sente.ch) Needs to be updated!!! @"boolean", @"bool", @"char", @"char2", @"char4", @"char8", @"char16", @"filename", @"date", @"reltime", @"time", @"tinterval", @"abstime", @"timestamp", @"real", @"double precision", @"float4", @"float8", @"int4", @"int2", @"oid", @"oid8", @"oidint2", @"oidint4", @"oidchar16", @"varchar", @"bpchar", @"numeric", @"decimal", @"cid", @"tid", @"xid", nil }; static NSString *internalTypeNames[] = { @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", @"NSCalendarDate", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSNumber", @"NSString", @"NSString", @"NSDecimalNumber", @"NSDecimalNumber", @"NSDecimalNumber", @"NSDecimalNumber", @"NSDecimalNumber", nil }; + (NSDictionary *)externalToInternalTypeMap { static NSDictionary *externalToInternalTypeMap = nil; if (!externalToInternalTypeMap) { int i; for (i = 0; externalTypeNames[i]; i++); externalToInternalTypeMap = [[NSDictionary alloc] initWithObjects: internalTypeNames forKeys: externalTypeNames count: i]; } return externalToInternalTypeMap; } + (NSString *)internalTypeForExternalType: (NSString *)extType model: (EOModel *)model { return [[self externalToInternalTypeMap] objectForKey: extType]; } + (NSArray *)externalTypesWithModel:(EOModel *)model { return [[self externalToInternalTypeMap] allKeys]; } + (void)assignExternalInfoForAttribute: (EOAttribute *)attribute { // TODO EOAdaptorValueType value = [attribute adaptorValueType]; [attribute setExternalType: externalTypeNames[value]]; } + (void)assignExternalInfoForEntity: (EOEntity *)entity { NSEnumerator *attributeEnumerator = [[entity attributes] objectEnumerator]; EOAttribute *attribute; while ((attribute = [attributeEnumerator nextObject])) [self assignExternalInfoForAttribute: attribute]; } /* Inherited methods */ - (EOAdaptorContext *)createAdaptorContext { //OK return [Postgres95Context adaptorContextWithAdaptor: self]; } - (Class)defaultExpressionClass { Class expressionClass; EOFLOGObjectFnStart(); expressionClass = [Postgres95SQLExpression class]; EOFLOGObjectFnStop(); return expressionClass; } - (BOOL)isValidQualifierType: (NSString *)typeName model: (EOModel *)model { int i; for (i = 0; externalTypeNames[i]; i++) { //TODO REMOVE NSDebugMLog(@"externalTypeNames[i]=%@", externalTypeNames[i]); if ([externalTypeNames[i] isEqualToString: typeName]) return YES; } //TODO REMOVE NSDebugMLog(@"typeName=%@", typeName); return NO; } - (void)assertConnectionDictionaryIsValid { NSException *exception = nil; EOAdaptorContext *adaptorContext; EOAdaptorChannel *adaptorChannel; if (![self hasOpenChannels]) { adaptorContext = [self createAdaptorContext]; adaptorChannel = [adaptorContext createAdaptorChannel]; NS_DURING [adaptorChannel openChannel]; NS_HANDLER exception = localException; NS_ENDHANDLER; [adaptorChannel closeChannel]; if (exception) [exception raise]; } } /* -(NSString *)formatValue:(id)value forAttribute:(EOAttribute*)attribute { return [value stringValueForPostgres95Type:[attribute externalType] attribute:attribute]; } */ - (NSString *)fetchedValueForString: (NSString *)value attribute: (EOAttribute *)attribute { return value; } //TODO: don't need to be overriden ?? - (NSNumber *)fetchedValueForNumberValue: (NSNumber *)value attribute: (EOAttribute *)attribute { return value; // TODO scale and precision } - (NSCalendarDate *)fetchedValueForDateValue: (NSCalendarDate *)value attribute: (EOAttribute *)attribute { return value; } - (NSData *)fetchedValueForDataValue: (NSData *)value attribute: (EOAttribute *)attribute { return value; } - (void)createDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)connectionDictionary { } - (void)dropDatabaseWithAdministrativeConnectionDictionary: (NSDictionary *)connectionDictionary { } /* Private methods for Postgres Adaptor */ - (PGconn *)createPGconn { char *pg_host = NULL; char *pg_database = NULL; char *pg_port = NULL; char *pg_options = NULL; char *pg_tty = NULL; char *pg_user = NULL; char *pg_pwd = NULL; PGconn *pgConn = NULL; PGresult *pgResult = NULL; NSString *str = nil; EOFLOGObjectFnStart(); //OK str = [_connectionDictionary objectForKey: @"databaseServer"]; if (!str) str = [_connectionDictionary objectForKey: @"hostName"]; pg_host = (char*)[str cString]; pg_database = (char*)[[_connectionDictionary objectForKey: @"databaseName"] cString]; pg_port = (char*)[[_connectionDictionary objectForKey: @"port"] cString]; if (!pg_port) pg_port = (char*)[[_connectionDictionary objectForKey: @"hostPort"] cString]; pg_options = (char*)[[_connectionDictionary objectForKey: @"options"] cString]; pg_tty = (char*)[[_connectionDictionary objectForKey: @"debugTTY"] cString]; pg_user = (char*)[[_connectionDictionary objectForKey: @"userName"] cString]; pg_pwd = (char*)[[_connectionDictionary objectForKey: @"password"] cString]; NSDebugMLog(@"%s %s %s %s %s", pg_host, pg_port, pg_database, pg_user, pg_pwd); // Try to connect to the Postgres95 server if (pg_user) pgConn = PQsetdbLogin(pg_host, pg_port, pg_options, pg_tty, pg_database,pg_user,pg_pwd); else pgConn = PQsetdb(pg_host, pg_port, pg_options, pg_tty, pg_database); NSDebugMLog(@"%s %s %s %s %s", pg_host, pg_port, pg_database, pg_user, pg_pwd); // Check connection if (PQstatus(pgConn) == CONNECTION_BAD) { //TODO: report error in an exception ? [self privateReportError: pgConn]; PQfinish(pgConn); pgConn = NULL; } if (pgConn) { pgResult = PQexec(pgConn, "SET DATESTYLE TO 'SQL'"); PQclear(pgResult); pgResult = NULL; if (pgConn) { pgConnTotalAllocated++; pgConnCurrentAllocated++; } } EOFLOGObjectFnStop(); return pgConn; } - (PGconn *)newPGconn { PGconn *pgConn = NULL; if(_flags.cachePGconn && [_pgConnPool count]) { NSDebugMLog(@"newPGconn cached %p (pgConn=%p) total=%d current=%d", self, pgConn, pgConnTotalAllocated, pgConnCurrentAllocated); pgConn = [[_pgConnPool lastObject] pointerValue]; [_pgConnPool removeLastObject]; } else { pgConn = [self createPGconn]; NSDebugMLog(@"newPGconn not cached %p (pgConn=%p) total=%d current=%d", self, pgConn, pgConnTotalAllocated, pgConnCurrentAllocated); } return pgConn; } - (void)releasePGconn: (PGconn *)pgConn force: (BOOL)flag { if (!flag && _flags.cachePGconn && (PQstatus(pgConn) == CONNECTION_OK) && [_pgConnPool count] < _pgConnPoolLimit) { NSDebugMLog(@"releasePGconn -> in pool %p (pgConn=%p) total=%d current=%d", self, pgConn, pgConnTotalAllocated, pgConnCurrentAllocated); [_pgConnPool addObject: [NSValue value: pgConn withObjCType: @encode(PGconn*)]]; } else { NSDebugMLog(@"releasePGconn really %p (pgConn=%p) total=%d current=%d", self, pgConn, pgConnTotalAllocated, pgConnCurrentAllocated); pgConnCurrentAllocated--; PQfinish(pgConn); } } // format is something like @"%@_SEQ" or @"EOSEQ_%@", "%@" is replaced by external table name - (void)setPrimaryKeySequenceNameFormat: (NSString*)format { ASSIGN(_primaryKeySequenceNameFormat, format); } - (NSString*)primaryKeySequenceNameFormat { if (!_primaryKeySequenceNameFormat) _primaryKeySequenceNameFormat = [_connectionDictionary objectForKey: @"primaryKeySequenceNameFormat"]; if (!_primaryKeySequenceNameFormat) _primaryKeySequenceNameFormat = @"%@_SEQ"; return _primaryKeySequenceNameFormat; } @end /* Postgres95Adaptor */ /* //TODO databaseEncoding { self connectionDictionary call dict obj for key databaseEncoding return 2 par defaut }; */