gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC/gdl2] Postgres Adaptor


From: David Ayers
Subject: Re: [RFC/gdl2] Postgres Adaptor
Date: Mon, 23 Jun 2003 18:07:08 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030507

David Ayers wrote:

Thanks.  Patch is coming up...

Here it is:

   * EOControl/EONSAddOns.h/m:
   ([NSString -parsedFirstVersionSubstring]): New method.
   * EOAdaptors/Postgres95/Postgres95Adaptor.h/m: Added include of
   pg_config.h to access PG_VERSION.  Added databaseVersion to list
   of meaningful connectionDictionary keys.
   (postgresClientVersion): New function.
   * EOAdaptors/Postgres95/Postgres95Channel.h/m:  Added instance
   variable to hold the version of the database server.
   (pgResultDictionary): New static function for debuging.
   ([Postgres95Channel -_readServerVersion]): New method to set Server
   Version.
   ([Postgres95Channel -openChannel]): Call _readServerVersion method.
   ([Postgres95Channel -describeTableNames]): Adapt select statement
   according to database version.
   * Postgres95/Postgres95SQLExpression.m:
   ([Postgres95SQLExpression +dropTableStatementsForEntityGroup:]):
   Adapt select statement according to database version supplied in
   connectionDictionary of the entites model.

I think my NSString catagory -parsedFirstVersionSubstring is a bit clumsy.
I'm open to alternatives.  Otherwise I'll commit this soon.

Cheers,
David

Index: EOAdaptors/Postgres95/Postgres95Adaptor.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/dev-libs/gdl2/EOAdaptors/Postgres95/Postgres95Adaptor.h,v
retrieving revision 1.2
diff -u -r1.2 Postgres95Adaptor.h
--- EOAdaptors/Postgres95/Postgres95Adaptor.h   31 Mar 2003 00:24:15 -0000      
1.2
+++ EOAdaptors/Postgres95/Postgres95Adaptor.h   23 Jun 2003 15:50:25 -0000
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include <libpq-fe.h>
 #include <libpq/libpq-fs.h>
+#include <pg_config.h>
 #undef Assert
 
 @class NSMutableArray;
@@ -50,6 +51,8 @@
        (default getenv(PGHOST) or localhost)
     databaseName - the name of the database to use 
        (default getenv(PGDATABASE))
+    databaseVersion - the Version of the database
+       (default parsed from #define PG_VERSION)
     options - additional options sent to the POSTGRES95 backend
        (default getenv(PGOPTIONS))
     port - port to communicate with POSTGRES95 backend
@@ -63,6 +66,9 @@
           real user id of the user running the program and that user id
          is interpreted by the server (AFAIK)
 */
+
+extern int
+postgresClientVersion();
 
 @interface Postgres95Adaptor : EOAdaptor
 {
Index: EOAdaptors/Postgres95/Postgres95Adaptor.m
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/dev-libs/gdl2/EOAdaptors/Postgres95/Postgres95Adaptor.m,v
retrieving revision 1.7
diff -u -r1.7 Postgres95Adaptor.m
--- EOAdaptors/Postgres95/Postgres95Adaptor.m   31 Mar 2003 00:24:15 -0000      
1.7
+++ EOAdaptors/Postgres95/Postgres95Adaptor.m   23 Jun 2003 15:50:25 -0000
@@ -56,6 +56,7 @@
 #include <Foundation/Foundation.h>
 #endif
 
+#include <EOControl/EONSAddOns.h>
 #include <EOControl/EODebug.h>
 
 #include <EOAccess/EOAccess.h>
@@ -74,6 +75,18 @@
 NSString *Postgres95Exception = @"Postgres95Exception";
 static int pgConnTotalAllocated = 0;
 static int pgConnCurrentAllocated = 0;
+
+int
+postgresClientVersion()
+{
+  static int version = 0;
+  if (version == 0)
+    {
+      NSString *versionString = [NSString stringWithCString: PG_VERSION];
+      version = [versionString parsedFirstVersionSubstring];
+    }
+  return version;
+}
 
 
 @implementation Postgres95Adaptor
Index: EOAdaptors/Postgres95/Postgres95Channel.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/dev-libs/gdl2/EOAdaptors/Postgres95/Postgres95Channel.h,v
retrieving revision 1.2
diff -u -r1.2 Postgres95Channel.h
--- EOAdaptors/Postgres95/Postgres95Channel.h   31 Mar 2003 00:24:15 -0000      
1.2
+++ EOAdaptors/Postgres95/Postgres95Channel.h   23 Jun 2003 15:50:25 -0000
@@ -52,6 +52,7 @@
   BOOL _isFetchInProgress;
   BOOL _fetchBlobsOid;
   NSArray *_pkAttributeArray;
+  int _pgVersion;
 
   struct {
     unsigned int postgres95InsertedRowOid:1;
@@ -66,6 +67,7 @@
 
 - (void)_cancelResults;
 - (void)_describeResults;
+- (void)_readServerVersion;
 
 /* Private methods */
 - (char*)_readBinaryDataRow: (Oid)oid length: (int*)length zone: (NSZone*)zone;
Index: EOAdaptors/Postgres95/Postgres95Channel.m
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/dev-libs/gdl2/EOAdaptors/Postgres95/Postgres95Channel.m,v
retrieving revision 1.9
diff -u -r1.9 Postgres95Channel.m
--- EOAdaptors/Postgres95/Postgres95Channel.m   22 Jun 2003 16:36:40 -0000      
1.9
+++ EOAdaptors/Postgres95/Postgres95Channel.m   23 Jun 2003 15:50:25 -0000
@@ -57,6 +57,7 @@
 #include <EOControl/EONull.h>
 #include <EOControl/EOQualifier.h>
 #include <EOControl/EOFetchSpecification.h>
+#include <EOControl/EONSAddOns.h>
 #include <EOControl/EODebug.h>
 
 #include <EOAccess/EOAttribute.h>
@@ -77,6 +78,77 @@
   __dummy_function_used_for_linking();
 }
 
+#define NSS_SWF NSString stringWithFormat
+static NSDictionary *
+pgResultDictionary(PGresult *pgResult)
+{
+  int nfields, ntuples;
+  int i, j;
+  NSMutableArray *fields;
+  NSMutableArray *tuples;
+  ExecStatusType statusType;
+
+  nfields = PQnfields(pgResult);
+  ntuples = PQntuples(pgResult);
+
+  fields = [NSMutableArray arrayWithCapacity: nfields];
+  tuples = [NSMutableArray arrayWithCapacity: ntuples];
+
+  for (i = 1; i <= nfields; i++)
+    {
+      char *fname;
+      fname = PQfname(pgResult, i);
+      [fields addObject: [NSDictionary dictionaryWithObjectsAndKeys:
+       [NSS_SWF:@"%s",  fname], @"PQfname",
+       [NSS_SWF:@"%d",  PQfnumber(pgResult, fname)], @"PQfnumber",
+       [NSS_SWF:@"%ud", PQftype(pgResult, i)], @"PQftype",
+       [NSS_SWF:@"%d",  PQfsize(pgResult, i)], @"PQfsize",
+       [NSS_SWF:@"%d",  PQfmod(pgResult, i)], @"PQfmod",
+       nil]];
+    }
+
+  for (i = 1; i <= ntuples; i++)
+    {
+      NSMutableDictionary *tuple;
+      tuple = [NSMutableDictionary dictionaryWithCapacity: nfields];
+      for (j = 1; j <= nfields; j++)
+       {
+         NSString *tupleInfo;
+         NSString *tupleKey;
+         tupleKey = [NSS_SWF:@"%s", PQfname(pgResult, j)];
+         if (PQgetisnull(pgResult, i, j))
+           {
+             tupleInfo = @"NULL";
+           }
+         else
+           {
+             NSString *fmt;
+             fmt = [NSS_SWF: @"%%%ds", PQgetlength(pgResult, i, j)];
+             tupleInfo = [NSS_SWF: fmt, PQgetvalue(pgResult, i, j)];
+           }
+         [tuple setObject: tupleInfo forKey: tupleKey];
+       }
+      [tuples addObject: tuple];
+    }
+
+  statusType = PQresultStatus(pgResult);
+
+  return [NSDictionary dictionaryWithObjectsAndKeys:
+    [NSS_SWF:@"%d",  statusType], @"PQresultStatus",
+    [NSS_SWF:@"%s",  PQresStatus(statusType)], @"PQresStatus",
+    [NSS_SWF:@"%s",  PQresultErrorMessage(pgResult)], @"PQresultErrorMessage",
+    [NSS_SWF:@"%d",  ntuples], @"PQntuples",
+    [NSS_SWF:@"%d",  nfields], @"PQnfields",
+    [NSS_SWF:@"%d",  PQbinaryTuples(pgResult)], @"PQbinaryTuples",
+    [NSS_SWF:@"%s",  PQcmdStatus(pgResult)], @"PQcmdStatus",
+    [NSS_SWF:@"%s",  PQoidStatus(pgResult)], @"PQoidStatus",
+    [NSS_SWF:@"%d",  PQoidValue(pgResult)], @"PQoidValue",
+    [NSS_SWF:@"%s",  PQcmdTuples(pgResult)], @"PQcmdTuples",
+    tuples, @"tuples",
+    fields, @"fields",
+    nil];
+}
+
 @implementation Postgres95Channel
 
 - (id) initWithAdaptorContext: (EOAdaptorContext *)adaptorContext
@@ -129,7 +201,10 @@
   _pgConn = [(Postgres95Adaptor *)[[self adaptorContext] adaptor] newPGconn];
 
   if (_pgConn)
-    [self _describeDatabaseTypes];
+    {
+      [self _readServerVersion];
+      [self _describeDatabaseTypes];
+    }
 }
 
 - (void)closeChannel
@@ -1171,6 +1246,28 @@
   _pgResult = NULL;
 }
 
+- (void)_readServerVersion
+{
+  NSString *version;
+
+  _pgResult = PQexec(_pgConn, 
+                    "SELECT version()");
+
+  if (_pgResult == NULL || PQresultStatus(_pgResult) != PGRES_TUPLES_OK)
+    {
+      _pgResult = NULL;
+      [NSException raise: Postgres95Exception
+                  format: @"cannot read type name informations from database. "
+                  @"bad response from server"];
+    }
+
+  version = [NSString stringWithCString: PQgetvalue(_pgResult, 0, 0)];
+  _pgVersion = [version parsedFirstVersionSubstring];
+
+  PQclear(_pgResult);
+  _pgResult = NULL;
+}
+
 - (NSArray *)attributesToFetch
 {
   return _attributes;
@@ -1320,11 +1417,22 @@
 {
   int i, count;
   NSMutableArray *results = [NSMutableArray array];
+  char *tableSelect;
+
+  if (_pgVersion < 70300)
+    {
+      tableSelect = "SELECT tablename FROM pg_tables WHERE tableowner != 
'postgres' OR tablename NOT LIKE 'pg_%'";
+    }
+  else
+    {
+      tableSelect = "SELECT tablename FROM pg_tables WHERE 
pg_tables.schemaname = 'public'";
+    }
+
 
   NSAssert(_pgConn, @"Channel not opened");
 
-  _pgResult = PQexec(_pgConn,
-                    "SELECT tablename FROM pg_tables WHERE 
pg_tables.schemaname = 'public'");
+  _pgResult = PQexec(_pgConn, tableSelect);
+                    
 
   if (_pgResult == NULL
       || PQresultStatus(_pgResult) != PGRES_TUPLES_OK)
Index: EOAdaptors/Postgres95/Postgres95SQLExpression.m
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/dev-libs/gdl2/EOAdaptors/Postgres95/Postgres95SQLExpression.m,v
retrieving revision 1.7
diff -u -r1.7 Postgres95SQLExpression.m
--- EOAdaptors/Postgres95/Postgres95SQLExpression.m     22 May 2003 14:06:35 
-0000      1.7
+++ EOAdaptors/Postgres95/Postgres95SQLExpression.m     23 Jun 2003 15:50:25 
-0000
@@ -44,10 +44,12 @@
 #endif
 
 #include <EOControl/EONull.h>
+#include <EOControl/EONSAddOns.h>
 #include <EOControl/EODebug.h>
 
 #include <EOAccess/EOAttribute.h>
 #include <EOAccess/EOEntity.h>
+#include <EOAccess/EOModel.h>
 #include <EOAccess/EOSchemaGeneration.h>
 
 #include <Postgres95EOAdaptor/Postgres95SQLExpression.h>
@@ -305,18 +307,30 @@
 
 + (NSArray *)dropTableStatementsForEntityGroup:(NSArray *)entityGroup
 {
-  // We redefine this method to add the CASCADE: it is needed to delete
-  // associated foreign key constraints when dropping a table.
-  // Q: shouldn't we move this into EOSQLExpression.m?
-  NSArray *newArray = nil;
+  EOEntity *entity;
+  NSArray  *newArray;
+  int       version;
 
   EOFLOGClassFnStartOrCond(@"EOSQLExpression");
 
-  newArray = [NSArray arrayWithObject:
-                       [self expressionForString:
-                               [NSString stringWithFormat: @"DROP TABLE %@ 
CASCADE",
-                                         [[entityGroup objectAtIndex: 0]
-                                           externalName]]]];
+  entity = [entityGroup objectAtIndex: 0];
+  version = [[[[entity model] connectionDictionary]
+             objectForKey: @"databaseVersion"] parsedFirstVersionSubstring];
+  if (version == 0)
+    {
+      version = postgresClientVersion();
+    }
+
+  if (version < 70300)
+    {
+      newArray = [super dropTableStatementsForEntityGroup: entityGroup];
+    }
+  else
+    {
+      newArray = [NSArray arrayWithObject: [self expressionForString:
+       [NSString stringWithFormat: @"DROP TABLE %@ CASCADE",
+                 [entity externalName]]]];
+    }
 
   EOFLOGClassFnStopOrCond(@"EOSQLExpression");
 
Index: EOControl/EONSAddOns.h
===================================================================
RCS file: /cvsroot/gnustep/gnustep/dev-libs/gdl2/EOControl/EONSAddOns.h,v
retrieving revision 1.3
diff -u -r1.3 EONSAddOns.h
--- EOControl/EONSAddOns.h      31 Mar 2003 00:24:15 -0000      1.3
+++ EOControl/EONSAddOns.h      23 Jun 2003 15:50:25 -0000
@@ -28,7 +28,7 @@
 #define __EONSAddOns_h__
 
 #ifndef NeXT_Foundation_LIBRARY
-#include <Foundation/NSObject.h>
+#include <Foundation/NSArray.h>
 #include <Foundation/NSString.h>
 #else
 #include <Foundation/Foundation.h>
@@ -36,7 +36,6 @@
 
 #include <EOControl/EODefines.h>
 
address@hidden NSArray;
 @class NSLock;
 @class NSRecursiveLock;
 
@@ -88,6 +87,10 @@
 
 @interface NSString (YorYes)
 - (BOOL)isYorYES;
address@hidden
+
address@hidden NSString (VersionParsing)
+- (int)parsedFirstVersionSubstring;
 @end
 
 #endif /* __EONSAddOns_h__ */
Index: EOControl/EONSAddOns.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/dev-libs/gdl2/EOControl/EONSAddOns.m,v
retrieving revision 1.6
diff -u -r1.6 EONSAddOns.m
--- EOControl/EONSAddOns.m      2 May 2003 17:00:23 -0000       1.6
+++ EOControl/EONSAddOns.m      23 Jun 2003 15:50:25 -0000
@@ -38,6 +38,8 @@
 #ifndef NeXT_Foundation_LIBRARY
 #include <Foundation/NSString.h>
 #include <Foundation/NSArray.h>
+#include <Foundation/NSScanner.h>
+#include <Foundation/NSCharacterSet.h>
 #include <Foundation/NSLock.h>
 #include <Foundation/NSUserDefaults.h>
 #include <Foundation/NSNotification.h>
@@ -507,6 +509,39 @@
 }
 
 @end
+
address@hidden NSString (VersionParsing)
+- (int)parsedFirstVersionSubstring
+{
+  NSString       *shortVersion;
+  NSScanner      *scanner;
+  NSCharacterSet *characterSet;
+  NSArray        *versionComponents;
+  NSString       *component;
+  int             count, i;
+  int             version = 0;
+  int             factor[] = { 10000, 100, 1 };
+
+  scanner = [NSScanner scannerWithString: self];
+  characterSet 
+    = [NSCharacterSet characterSetWithCharactersInString: @"0123456789."];
+
+  [scanner setCharactersToBeSkipped: [characterSet invertedSet]];
+  [scanner scanCharactersFromSet: characterSet intoString: &shortVersion];
+
+  versionComponents = [shortVersion componentsSeparatedByString:@"."];
+  count = [versionComponents count];
+
+  for (i = 0; (i < count) && (i < 3); i++)
+    {
+      component = [versionComponents objectAtIndex: i];
+      version += [component intValue] * factor[i];
+    }
+
+  return version;
+}
address@hidden
+
 
 @interface GDL2GlobalLockVendor (private)
 + (void) _setupLocks: (NSNotification *)notif;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]