]> err.no Git - sope/commitdiff
basic implementation is working now
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 20 Feb 2005 20:14:11 +0000 (20:14 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 20 Feb 2005 20:14:11 +0000 (20:14 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@577 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

15 files changed:
sope-gdl1/SQLite3/ChangeLog
sope-gdl1/SQLite3/NSData+SQLiteVal.m
sope-gdl1/SQLite3/NSNumber+SQLiteVal.m
sope-gdl1/SQLite3/NSString+SQLite.h
sope-gdl1/SQLite3/NSString+SQLite.m
sope-gdl1/SQLite3/NSString+SQLiteVal.m
sope-gdl1/SQLite3/README
sope-gdl1/SQLite3/SQLiteChannel+Model.m
sope-gdl1/SQLite3/SQLiteChannel.h
sope-gdl1/SQLite3/SQLiteChannel.m
sope-gdl1/SQLite3/SQLiteContext.m
sope-gdl1/SQLite3/SQLiteValues.h
sope-gdl1/SQLite3/SQLiteValues.m
sope-gdl1/SQLite3/Version
sope-gdl1/SQLite3/gdltest.m

index 7a2b9a7cc0aa3570c2140d196dbced2b09901b00..157a64c933a2a8471083360b031b29be0c43da10 100644 (file)
@@ -1,3 +1,7 @@
+2005-02-20  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * most SQL operations based on models are implemented now (v4.5.9)
+       
 2005-02-20  Helge Hess  <helge.hess@opengroupware.org>
 
        * made gdltest work again
index ec01f757aa47bb80289358c84b4c0bcff321069e..a3e044b0c85ba97ace2f6473bdbb38135d5bb716 100644 (file)
 
 @implementation NSData(SQLiteValues)
 
-static NSData *EmptyData = nil;
-
-+ (id)valueFromCString:(const char *)_cstr length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel
-{
-  if (_length == 0) {
-    if (EmptyData == nil) EmptyData = [[NSData alloc] init];
-    return EmptyData;
-  }
-  return [[[self alloc] initWithBytes:_cstr length:_length] autorelease];
+- (id)initWithSQLiteInt:(int)_value {
+  return [self initWithBytes:&_value length:sizeof(int)];
 }
-
-+ (id)valueFromBytes:(const void *)_bytes length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel
-{
-  if (_length == 0) {
-    if (EmptyData == nil) EmptyData = [[NSData alloc] init];
-    return EmptyData;
-  }
-  return [[[self alloc] initWithBytes:_bytes length:_length] autorelease];
+- (id)initWithSQLiteDouble:(double)_value {
+  return [self initWithBytes:&_value length:sizeof(double)];
+}
+- (id)initWithSQLiteText:(const unsigned char *)_value {
+  return [self initWithBytes:_value length:strlen(_value)];
+}
+- (id)initWithSQLiteData:(const void *)_value length:(int)_length {
+  return [self initWithBytes:_value length:_length];
 }
 
 - (NSString *)stringValueForSQLite3Type:(NSString *)_type
index fbedbb4cbf5569486ca81743ba46a1c8437a8538..92118b235ebb268c8a510504a7cdbc58d74823be 100644 (file)
 
 @implementation NSNumber(SQLiteValues)
   
-static Class    NSNumberClass = Nil;
-static NSNumber *yesNum = nil;
-static NSNumber *noNum  = nil;
-
-+ (id)valueFromCString:(const char *)_cstr length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel
-{
-  // TODO: can we avoid the lowercaseString?
-  unsigned len;
-  unichar  c1;
-
-  if ((len = [_type length]) == 0)
-    return nil;
+- (id)initWithSQLiteInt:(int)_value {
+  return [self initWithInt:_value];
+}
+- (id)initWithSQLiteDouble:(double)_value {
+  return [self initWithDouble:_value];
+}
+- (id)initWithSQLiteText:(const unsigned char *)_value {
+  return index(_value, '.') != NULL
+    ? [self initWithDouble:atof(_value)]
+    : [self initWithInt:atoi(_value)];
+}
 
-  if (NSNumberClass == Nil) NSNumberClass = [NSNumber class];
-  
-  c1 = [_type characterAtIndex:0];
-  switch (c1) {
-  case 'f': case 'F': {
-    if (len < 5)
-      break;
-    if ([[_type lowercaseString] hasPrefix:@"float"])
-      return [NSNumberClass numberWithDouble:atof(_cstr)];
-    break;
-  }
-  case 's': case 'S': {
-    if (len < 8)
-      break;
-    if ([[_type lowercaseString] hasPrefix:@"smallint"])
-      return [NSNumberClass numberWithShort:atoi(_cstr)];
-    break;
-  }
-  case 'i': case 'I': {
-    if (len < 3)
-      break;
-    if ([[_type lowercaseString] hasPrefix:@"int"])
-      return [NSNumberClass numberWithInt:atoi(_cstr)];
-  }
-  case 'b': case 'B': {
-    if (len < 4)
-      break;
-    if (![[_type lowercaseString] hasPrefix:@"bool"])
-      break;
-    
-    if (yesNum == nil) yesNum = [[NSNumberClass numberWithBool:YES] retain];
-    if (noNum  == nil) noNum  = [[NSNumberClass numberWithBool:NO]  retain];
-    
-    if (_length == 0)
-      return noNum;
-    
-    switch (*_cstr) {
-    case 't': case 'T':
-    case 'y': case 'Y':
-    case '1':
-      return yesNum;
-    default:
-      return noNum;
-    }
-  }
+- (id)initWithSQLiteData:(const void *)_value length:(int)_length {
+  switch (_length) {
+  case 1: return [self initWithUnsignedChar:*(char *)_value];
+  case 2: return [self initWithShort:*(short *)_value];
+  case 4: return [self initWithInt:*(int *)_value];
+  case 8: return [self initWithDouble:*(double *)_value];
   }
+  
+  [self release];
   return nil;
 }
 
-+ (id)valueFromBytes:(const void *)_bytes length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel
-{
-  return [self notImplemented:_cmd];
-}
-
 - (NSString *)stringValueForSQLite3Type:(NSString *)_type
   attribute:(EOAttribute *)_attribute
 {
index 4bc327fc7009771263be9efd1c0e7e4fcafc502c..4de73577bb87071928537a3735256983c4338779 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    NSString+SQLite.h
 
-   Copyright (C) 1999 MDlink online service center GmbH and Helge Hess
+   Copyright (C) 1999-2005 MDlink online service center GmbH and Helge Hess
 
    Author: Helge Hess (helge@mdlink.de)
 
@@ -22,7 +22,6 @@
    If not, write to the Free Software Foundation,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
-// $Id: NSString+SQLite.h,v 1.1 2004/06/14 14:27:44 helge Exp $
 
 #ifndef ___SQLite_NSString_H___
 #define ___SQLite_NSString_H___
 
 @interface NSString(SQLiteMiscStrings)
 
-- (NSString *)_pgModelMakeInstanceVarName;
-- (NSString *)_pgModelMakeClassName;
-- (NSString *)_pgStringWithCapitalizedFirstChar;
-- (NSString *)_pgStripEndSpaces;
+- (NSString *)_sqlite3ModelMakeInstanceVarName;
+- (NSString *)_sqlite3ModelMakeClassName;
+- (NSString *)_sqlite3StringWithCapitalizedFirstChar;
+- (NSString *)_sqlite3StripEndSpaces;
 
 @end
 
-#endif
+#endif /* ___SQLite_NSString_H___ */
index 530b2bd8c6b527e2e67ec34cb127332e8ab1e6fb..3d729b38fa61bc0180a69cd518d28523a10b2702 100644 (file)
@@ -34,7 +34,7 @@
 
 @implementation NSString(SQLiteMiscStrings)
 
-- (NSString *)_pgModelMakeInstanceVarName {
+- (NSString *)_sqlite3ModelMakeInstanceVarName {
   if ([self length] == 0)
     return @"";
   else {
@@ -69,7 +69,7 @@
   }
 }
 
-- (NSString *)_pgModelMakeClassName {
+- (NSString *)_sqlite3ModelMakeClassName {
   if ([self length] == 0)
     return @"";
   else {
   }
 }
 
-- (NSString *)_pgStringWithCapitalizedFirstChar {
+- (NSString *)_sqlite3StringWithCapitalizedFirstChar {
   NSCharacterSet *upperSet = [NSCharacterSet uppercaseLetterCharacterSet];
   
   if ([self length] == 0)
   }
 }
 
-- (NSString *)_pgStripEndSpaces {
+- (NSString *)_sqlite3StripEndSpaces {
   if ([self length] > 0) {
     NSCharacterSet  *spaceSet = [NSCharacterSet whitespaceCharacterSet];
     NSMutableString *str      = [NSMutableString stringWithCapacity:[self length]];
index 9e76bcc70a720b3ab21622a57fe24aeb1a44e5a7..290c9d44cd78cd3085be53ddba0bf33c9fb64d61 100644 (file)
 
 @implementation NSString(SQLiteValues)
 
-static Class NSStringClass = Nil;
-static Class EOExprClass   = Nil;
+static Class EOExprClass = Nil;
 
-+ (id)valueFromCString:(const char *)_cstr length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel
-{
-  if (_cstr  == NULL) return nil;
-  if (*_cstr == '\0') return @"";
-  if (NSStringClass == Nil) NSStringClass = [NSString class];
+- (id)initWithSQLiteInt:(int)_value {
+  char buf[256];
+  sprintf(buf, "%i", _value);
+  return [self initWithCString:buf];
+}
+- (id)initWithSQLiteDouble:(double)_value {
+  char buf[256];
+  sprintf(buf, "%g", _value);
+  return [self initWithCString:buf];
+}
 
-  // TODO: cache IMP of selector
-  return [NSStringClass stringWithCString:_cstr];
+- (id)initWithSQLiteText:(const unsigned char *)_value {
+  return [self initWithUTF8String:_value];
 }
 
-+ (id)valueFromBytes:(const void *)_bytes length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel
-{
-  return [self notImplemented:_cmd];
+- (id)initWithSQLiteData:(const void *)_value length:(int)_length {
+  NSData *d;
+  
+  d = [[NSData alloc] initWithBytes:_value length:_length];
+  self = [self initWithData:d encoding:NSUTF8StringEncoding];
+  [d release];
+  return self;
 }
 
 - (NSString *)stringValueForSQLite3Type:(NSString *)_type
index 6563b13983f009bfa9aa2686a6366fa96127ab48..96673f5fe10ad1c2f4ad095cf4b3c6801c0075e8 100644 (file)
@@ -5,11 +5,12 @@ Note: this is far from being complete! The adaptor is currently a fork of
 
 TODO
 ====
-- rename methods with 'pg' in the name
 - check EOAttribute+SQLite:
   -loadValueClassAndTypeUsingSQLiteType:...
 - SQLiteChannel.m:
   -primaryFetchAttributes => check field name processing
+- rewrite for exception less operation
+- implement more methods in SQLiteChannel+Model (hard with SQLite though)
 
 Basics
 ======
index a3b26401bf34eb5d4551b1e794675ece13954141..1932633b5bd5819f40ec0349e1e8180d6f9f66ce 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    SQLiteChannel+Model.m
 
-   Copyright (C) 2003 SKYRIX Software AG
+   Copyright (C) 2003-2005 SKYRIX Software AG
 
    Author: Helge Hess (helge.hess@skyrix.com)
 
    If not, write to the Free Software Foundation,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
-// $Id: SQLiteChannel+Model.m,v 1.1 2004/06/14 14:27:44 helge Exp $
 
 #include "SQLiteChannel.h"
 #include "NSString+SQLite.h"
 #include "EOAttribute+SQLite.h"
-#import "common.h"
+#include "common.h"
 
 @interface EORelationship(FixMe)
 - (void)addJoin:(id)_join;
   NSArray        *resultDescription;
   NSDictionary   *row;
   
-  if (![_tableName length])
+  if ([_tableName length] == 0)
     return nil;
   
-  if (!(attributes = [self->_attributesForTableName
-                          objectForKey:_tableName])) {
-    sqlExpr = 
-      @"SELECT a.attnum, a.attname, t.typname, a.attlen, a.attnotnull "
-      @"FROM pg_class c, pg_attribute a, pg_type t "
-      @"WHERE c.relname='%@' AND a.attnum>0 AND a.attrelid=c.oid AND a.atttypid=t.oid "
-      @"ORDER BY attnum;";
+  attributes = [self->_attributesForTableName objectForKey:_tableName];
+  if (attributes == nil) {
+#if 1
+    // TODO: we would need to parse the SQL field of 'sqlite_master'?
+    NSLog(@"ERROR(%s): operation not supported on SQLite!",
+         __PRETTY_FUNCTION__);
+    return nil;
+#else
     sqlExpr = [NSString stringWithFormat:sqlExpr, _tableName];
+#endif
   
     if (![self evaluateExpression:sqlExpr]) {
       fprintf(stderr,
@@ -70,7 +71,7 @@
       NSString    *attrName     = nil;
 
       columnName   = [[row objectForKey:@"attname"] stringValue];
-      attrName     = [columnName _pgModelMakeInstanceVarName];
+      attrName     = [columnName _sqlite3ModelMakeInstanceVarName];
       externalType = [[row objectForKey:@"typname"] stringValue];
     
       attribute = [[EOAttribute alloc] init];
@@ -79,7 +80,7 @@
       [attribute setExternalType:externalType];
       [attribute loadValueClassForExternalSQLiteType:externalType];
       [attributes addObject:attribute];
-      RELEASE(attribute);
+      [attribute release];
     }
     [self->_attributesForTableName setObject:attributes forKey:_tableName];
     //NSLog(@"got attrs: %@", attributes);
 }
 
 - (NSArray *)_primaryKeysNamesForTableName:(NSString *)_tableName {
-  NSArray *pkNameForTableName = nil;
+  //NSArray *pkNameForTableName = nil;
 
   if ([_tableName length] == 0)
     return nil;
   
-  NSLog(@"%s: not supported on SQLite!", __PRETTY_FUNCTION__);
+  NSLog(@"ERROR(%s): operation not supported on SQLite!", __PRETTY_FUNCTION__);
   return nil;
 }
 
 
   for (cnt = 0; cnt < tc; cnt++) {
     NSMutableDictionary *relNamesUsed         =
-      AUTORELEASE([NSMutableDictionary new]);
+      [NSMutableDictionary dictionaryWithCapacity:16];
     NSMutableArray      *classProperties      =
-      AUTORELEASE([NSMutableArray new]);
+      [NSMutableArray arrayWithCapacity:16];
     NSMutableArray      *primaryKeyAttributes =
-      AUTORELEASE([NSMutableArray new]);
+      [NSMutableArray arrayWithCapacity:2];
     NSString *tableName  = [_tableNames objectAtIndex:cnt];
     NSArray  *attributes = [self _attributesForTableName:tableName];
     NSArray  *pkeys      = [self _primaryKeysNamesForTableName:tableName];
     NSArray  *fkeys      = [self _foreignKeysForTableName:tableName];
-    EOEntity *entity     = AUTORELEASE([EOEntity new]);
+    EOEntity *entity     = [[EOEntity new] autorelease];
     int      cnt2;
     int      ac  = [attributes count];
     int      fkc = [fkeys      count];
 
-    [entity setName:[tableName _pgModelMakeClassName]];
+    [entity setName:[tableName _sqlite3ModelMakeClassName]];
     [entity setClassName:
-              [@"EO" stringByAppendingString:[tableName _pgModelMakeClassName]]];
+              [@"EO" stringByAppendingString:[tableName _sqlite3ModelMakeClassName]]];
     [entity setExternalName:tableName];
     [classProperties addObjectsFromArray:[entity classProperties]];
     [primaryKeyAttributes addObjectsFromArray:[entity primaryKeyAttributes]];
       NSString       *da               = [fkey objectForKey:@"targetAttr"];
       NSString       *dt               = [fkey objectForKey:@"targetTable"];
       EORelationship *rel              = 
-        AUTORELEASE([[EORelationship alloc] init]);
+        [[[EORelationship alloc] init] autorelease];
       EOJoin         *join             = 
-        AUTORELEASE([[EOJoin alloc] init]);
+        [[[EOJoin alloc] init] autorelease];
       NSString       *relName          = nil;
 
-      if ([pkeys containsObject:sa])
-        relName = [@"to" stringByAppendingString:[dt _pgModelMakeClassName]];
+      if ([pkeys containsObject:sa]) {
+        relName = [@"to" stringByAppendingString:
+                     [dt _sqlite3ModelMakeClassName]];
+      }
       else {
         relName = [@"to" stringByAppendingString:
-                    [[sa _pgModelMakeInstanceVarName]
-                         _pgStringWithCapitalizedFirstChar]];
+                    [[sa _sqlite3ModelMakeInstanceVarName]
+                         _sqlite3StringWithCapitalizedFirstChar]];
         if ([relName hasSuffix:@"Id"]) {
           int cLength = [relName cStringLength];
 
       if ([relNamesUsed objectForKey:relName]) {
         int useCount = [[relNamesUsed objectForKey:relName] intValue];
         
-        [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)] forKey:relName];
+        [relNamesUsed setObject:[NSNumber numberWithInt:(useCount++)] 
+                     forKey:relName];
         relName = [NSString stringWithFormat:@"%s%d",
                               [relName cString], useCount];
       }
         [relNamesUsed setObject:[NSNumber numberWithInt:0] forKey:relName];
 
       [rel setName:relName];
-      //[rel setDestinationEntity:(EOEntity *)[dt _pgModelMakeClassName]];
+      //[rel setDestinationEntity:(EOEntity *)[dt _sqlite3ModelMakeClassName]];
       [rel setToMany:NO];
 
       // TODO: EOJoin is removed, fix this ...
       [(id)join setSourceAttribute:
-            (EOAttribute *)[sa _pgModelMakeInstanceVarName]];
+            (EOAttribute *)[sa _sqlite3ModelMakeInstanceVarName]];
       [(id)join setDestinationAttribute:
-            (EOAttribute *)[da _pgModelMakeInstanceVarName]];
+            (EOAttribute *)[da _sqlite3ModelMakeInstanceVarName]];
       [rel addJoin:join];
       
       [entity addRelationship:rel];
                     [(EOEntity *)[reverse destinationEntity] name]];
       else {
         relName = [@"to" stringByAppendingString:
-                    [[[sa name] _pgModelMakeInstanceVarName]
-                          _pgStringWithCapitalizedFirstChar]];
+                    [[[sa name] _sqlite3ModelMakeInstanceVarName]
+                          _sqlite3StringWithCapitalizedFirstChar]];
         if ([relName hasSuffix:@"Id"]) {
           int cLength = [relName cStringLength];
 
   NSDictionary   *row               = nil;
   NSString       *selectExpression  = nil;
   
-  selectExpression = 
-    @"SELECT relname "
-    @"FROM pg_class "
-    @"WHERE (relkind='r') AND relname !~ '^pg_' AND relname !~ '^xinv[0-9]+' "
-    @"ORDER BY relname";
-  
+  selectExpression = @"SELECT name FROM sqlite_master WHERE type='table'";
   if (![self evaluateExpression:selectExpression]) {
-    fprintf(stderr, "Couldn`t evaluate table-describe expression '%s'\n",
+    fprintf(stderr, "Could not evaluate table-describe expression '%s'\n",
             [selectExpression cString]);
     return nil;
   }
   
   resultDescription = [self describeResults];
-  attributeName     = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
-  tableNames        = [NSMutableArray arrayWithCapacity:16];
-
-  while ((row = [self fetchAttributes:resultDescription withZone:NULL]))
+  attributeName = [(EOAttribute *)[resultDescription objectAtIndex:0] name];
+  tableNames    = [NSMutableArray arrayWithCapacity:16];
+  
+  while ((row = [self fetchAttributes:resultDescription withZone:NULL])!=nil)
     [tableNames addObject:[row objectForKey:attributeName]];
   
   return tableNames;
index c38f9243685f8ce84643d7aaee44742d10469e93..29323b220f6cd7906155c37a21f7649710f31865 100644 (file)
   void *_connection;
   
   // valid during -evaluateExpression:
+  void     *statement;
+  BOOL     hasPendingRow;
+  
   void     *results;
+#if 0
   int      tupleCount;
   int      fieldCount;
   BOOL     containsBinaryData;
@@ -45,6 +49,7 @@
   NSString *cmdTuples;
   NSString *oidStatus;
   int      currentTuple;
+#endif
 
   // turns on/off channel debugging
   BOOL isDebuggingEnabled;
index 47649fa0c9a866ee22d49adb85e09a0632c9809f..8db9b5b9622f03d8f67c1de6895f864f3e1ac4cc 100644 (file)
@@ -52,8 +52,9 @@ static EONull *null = nil;
   if ((self = [super initWithAdaptorContext:_adaptorContext])) {
     [self setDebugEnabled:[[NSUserDefaults standardUserDefaults]
                                            boolForKey:@"SQLiteDebugEnabled"]];
-    self->_attributesForTableName = [[NSMutableDictionary alloc]
-                                                          initWithCapacity:16];
+    
+    self->_attributesForTableName = 
+      [[NSMutableDictionary alloc] initWithCapacity:16];
     self->_primaryKeysNamesForTableName =
       [[NSMutableDictionary alloc] initWithCapacity:16];
   }
@@ -99,23 +100,23 @@ static int openConnectionCount = 0;
 }
 
 - (int)maxOpenConnectionCount {
-    static int MaxOpenConnectionCount = -1;
+  static int MaxOpenConnectionCount = -1;
     
-    if (MaxOpenConnectionCount == -1) {
-      MaxOpenConnectionCount =
-        [[NSUserDefaults standardUserDefaults]
-                         integerForKey:@"SQLiteMaxOpenConnectionCount"];
-      if (MaxOpenConnectionCount == 0) {
-        MaxOpenConnectionCount = 15;
-      }
-    }
+  if (MaxOpenConnectionCount != -1)
     return MaxOpenConnectionCount;
+
+  MaxOpenConnectionCount =
+    [[NSUserDefaults standardUserDefaults]
+                     integerForKey:@"SQLiteMaxOpenConnectionCount"];
+  if (MaxOpenConnectionCount == 0)
+    MaxOpenConnectionCount = 15;
+  return MaxOpenConnectionCount;
 }
 
 - (BOOL)openChannel {
   SQLiteAdaptor *adaptor;
   int rc;
-
+  
   if (self->_connection) {
     NSLog(@"%s: Connection already open !!!", __PRETTY_FUNCTION__);
     return NO;
@@ -126,17 +127,11 @@ static int openConnectionCount = 0;
   if (![super openChannel])
     return NO;
 
-#if 0
-  NSLog(@"+++++++++ %s: openConnectionCount %d", __PRETTY_FUNCTION__,
-        openConnectionCount);
-#endif
-  {
-    if (openConnectionCount > [self maxOpenConnectionCount]) {
-      [SQLiteCouldNotOpenChannelException 
+  if (openConnectionCount > [self maxOpenConnectionCount]) {
+    [SQLiteCouldNotOpenChannelException 
        raise:@"NoMoreConnections"
        format:@"cannot open a additional connection !"];
-      return NO;
-    }
+    return NO;
   }
   
   rc = sqlite3_open([[adaptor databaseName] UTF8String],
@@ -173,19 +168,11 @@ static int openConnectionCount = 0;
 }
 
 - (void)primaryCloseChannel {
-  self->tupleCount = 0;
-  self->fieldCount = 0;
-  self->containsBinaryData = NO;
-    
-  if (self->results) {
-    free(self->results);
-    self->results = NO;
+  if (self->statement != NULL) {
+    sqlite3_finalize(self->statement);
+    self->statement = NULL;
   }
-
-  RELEASE(self->cmdStatus); self->cmdStatus = nil;
-  RELEASE(self->cmdTuples); self->cmdTuples = nil;
-  RELEASE(self->oidStatus); self->oidStatus = nil;
-
+  
   if (self->_connection != NULL) {
     sqlite3_close(self->_connection);
 #if 0
@@ -210,37 +197,45 @@ static int openConnectionCount = 0;
 
 /* fetching rows */
 
-- (void)cancelFetch {
-  if (![self isOpen]) {
-    [SQLiteException raise:@"ChannelNotOpenException"
-                         format:@"No fetch in progress, connection is not open"
-                           @" (channel=%@)", self];
-  }
-
-#if 0
-  NSLog(@"canceling fetch (%i tuples remaining).",
-        (self->tupleCount - self->currentTuple));
-#endif
+- (NSException *)_makeSQLiteStep {
+  NSString *r;
+  int rc;
   
-  self->tupleCount   = 0;
-  self->currentTuple = 0;
-  self->fieldCount   = 0;
-  self->containsBinaryData = NO;
-    
-  if (self->results) {
-    free(self->results);
-    self->results = NO;
+  rc = sqlite3_step(self->statement);
+  
+  if (rc == SQLITE_ROW) {
+    self->hasPendingRow = YES;
+    return nil /* no error */;
+  }
+  if (rc == SQLITE_DONE) {
+    self->hasPendingRow = NO;
+    return nil /* no error */;
   }
 
-  RELEASE(self->cmdStatus); self->cmdStatus = nil;
-  RELEASE(self->cmdTuples); self->cmdTuples = nil;
-  RELEASE(self->oidStatus); self->oidStatus = nil;
+  if (rc == SQLITE_ERROR)
+    r = [NSString stringWithUTF8String:sqlite3_errmsg(self->_connection)];
+  else if (rc == SQLITE_MISUSE)
+    r = @"Somehow the SQLite method was called in an incorrect way.";
+  else if (rc == SQLITE_BUSY)
+    r = @"The SQLite is busy.";
+  else
+    r = [NSString stringWithFormat:@"Unexpected SQLite error: %i", rc];
+  
+  return [SQLiteException exceptionWithName:@"FetchFailed"
+                         reason:r userInfo:nil];
+}
 
+- (void)cancelFetch {
+  if (self->statement != NULL) {
+    sqlite3_finalize(self->statement);
+    self->statement = NULL;
+  }
   [super cancelFetch];
 }
 
 - (NSArray *)describeResults {
-  int                 cnt;
+  // TODO: make exception-less method
+  int                 cnt, fieldCount;
   NSMutableArray      *result    = nil;
   NSMutableDictionary *usedNames = nil;
   NSNumber            *yesObj;
@@ -251,21 +246,40 @@ static int openConnectionCount = 0;
     [SQLiteException raise:@"NoFetchInProgress"
                     format:@"No fetch in progress (channel=%@)", self];
   }
+
+  /* we need to fetch a row to get the info */
+
+  if (!self->hasPendingRow) {
+    NSException *error;
+    
+    if ((error = [self _makeSQLiteStep]) != nil) {
+      [self cancelFetch];
+      [error raise]; // raise error, TODO: make exception-less method
+      return nil;
+    }
+  }
+  if (!self->hasPendingRow) /* no rows available */
+    return nil;
+  
+  fieldCount = sqlite3_column_count(self->statement);
+  
+#warning TODO: describe row
+  // allowsNull, columnName, externType, name, valueClassName, valueType
+  NSLog(@"%s: TODO describe current row ...", __PRETTY_FUNCTION__);
+  
+  /* old code below */
   
-  result    = [[NSMutableArray      alloc] initWithCapacity:self->fieldCount];
-  usedNames = [[NSMutableDictionary alloc] initWithCapacity:self->fieldCount];
+  result    = [[NSMutableArray      alloc] initWithCapacity:fieldCount];
+  usedNames = [[NSMutableDictionary alloc] initWithCapacity:fieldCount];
 
-  for (cnt = 0; cnt < self->fieldCount; cnt++) {
+  for (cnt = 0; cnt < fieldCount; cnt++) {
     EOAttribute *attribute  = nil;
     NSString    *columnName = nil;
     NSString    *attrName   = nil;
-
-#if 1
-#  warning TODO, columnName
-#else
-    columnName = [NSString stringWithCString:self->fieldInfo[cnt].name];
-#endif
-    attrName   = [columnName _pgModelMakeInstanceVarName];
+    
+    columnName = [NSString stringWithCString:
+                            sqlite3_column_name(self->statement, cnt)];
+    attrName   = [columnName _sqlite3ModelMakeInstanceVarName];
     
     if ([[usedNames objectForKey:attrName] boolValue]) {
       int      cnt2 = 0;
@@ -273,11 +287,13 @@ static int openConnectionCount = 0;
       NSString *newAttrName = nil;
 
       for (cnt2 = 2; cnt2 < 100; cnt2++) {
+       NSString *s;
         sprintf(buf, "%i", cnt2);
-        
+       
        // TODO: unicode
-        newAttrName = [attrName stringByAppendingString:
-                                  [NSString stringWithCString:buf]];
+       s = [[NSString alloc] initWithCString:buf];
+        newAttrName = [attrName stringByAppendingString:s];
+       [s release];
         
         if (![[usedNames objectForKey:newAttrName] boolValue]) {
           attrName = newAttrName;
@@ -314,72 +330,72 @@ static int openConnectionCount = 0;
   return [result autorelease];
 }
 
+- (BOOL)isColumnNullInCurrentRow:(int)_column {
+  /* 
+     Note: NULL is SQLite is represented as empty strings ..., don't know
+           what to do about that?
+          At least Sybase 10 doesn't support empty strings strings as well
+          and converts them to a single space. So maybe it is reasonable to
+          map empty strings to NSNull?
+          
+          Or is this column-type SQLITE_NULL? If so, thats rather weird,
+          since the type query does not take a row.
+  */
+  return NO;
+}
+
 - (NSMutableDictionary *)primaryFetchAttributes:(NSArray *)_attributes
   withZone:(NSZone *)_zone
 {
+  /*
+    Note: we expect that the attributes match the generated SQL. This is
+          because auto-generated SQL can contain SQL table prefixes (like
+         alias.column-name which cannot be detected using the attributes
+         schema)
+  */
+  // TODO: add a primaryFetchAttributesX method?
   NSMutableDictionary *row = nil;
+  NSException *error;
   unsigned attrCount = [_attributes count];
-  int      indices[attrCount];
   unsigned cnt;
   
-  if (self->currentTuple == self->tupleCount) {
-    if (self->results) [self cancelFetch];
+  if (self->statement == NULL) {
+    NSLog(@"ERROR: no fetch in progress?");
+    [self cancelFetch];
     return nil;
   }
-  {
-#if 1
-#  warning TODO: field name processing
-    NSMutableArray *fieldNames;
-    //unsigned       nFields, i;
-    
-    // TODO: we could probably cache the field-name array for much more speed !
-    fieldNames = [[NSMutableArray alloc] initWithCapacity:32];
-#else
-    nFields    = PQnfields(self->results);
-    for (i = 0; i < nFields; i++) {
-      NSString *s;
-      
-      s = [[NSString alloc] initWithCString:PQfname(self->results, i)];
-      [fieldNames addObject:s];
-      [s release];
-    }
-#endif
-    
-    for (cnt = 0; cnt < attrCount; cnt++) {
-      EOAttribute *attribute = [_attributes objectAtIndex:cnt];
-    
-      indices[cnt] = [fieldNames indexOfObject:[attribute columnName]];
-      
-      if (indices[cnt] == NSNotFound) {
-        [SQLiteException raiseWithFormat:
-                           @"attribute %@ not covered by query", attribute];
-      }
-      [fieldNames replaceObjectAtIndex:indices[cnt] withObject:[EONull null]];
+  
+  if (!self->hasPendingRow) {
+    if ((error = [self _makeSQLiteStep]) != nil) {
+      [self cancelFetch];
+      [error raise]; // raise error, TODO: make exception-less method
+      return nil;
     }
-    [fieldNames release]; fieldNames = nil;
+  }
+  if (!self->hasPendingRow) { /* step was fine, but we are at the end */
+    [self cancelFetch];
+    return nil;
   }
   
-
+  self->hasPendingRow = NO; /* consume the row */
+  
+  /* build row */
+  
   row = [NSMutableDictionary dictionaryWithCapacity:attrCount];
 
   for (cnt = 0; cnt < attrCount; cnt++) {
     EOAttribute *attribute;
     NSString    *attrName;
     id          value      = nil;
-
+    
     attribute = [_attributes objectAtIndex:cnt];
     attrName  = [attribute name];
 
-#if 1
-#  warning TODO: value creation
-#else
-    if (PQgetisnull(self->results, self->currentTuple, indices[cnt])) {
-      value = null;
+    if ([self isColumnNullInCurrentRow:cnt]) {
+      value = [null retain];
     }
     else {
-      Class       valueClass = Nil;
-      const char *pvalue;
-      int         vallen;
+      Class valueClass;
       
       valueClass = NSClassFromString([attribute valueClassName]);
       if (valueClass == Nil) {
@@ -391,25 +407,36 @@ static int openConnectionCount = 0;
        continue;
       }
       
-      pvalue = PQgetvalue(self->results, self->currentTuple, indices[cnt]);
-      vallen = PQgetlength(self->results, self->currentTuple, indices[cnt]);
-
-      if (self->containsBinaryData) {
-        // pvalue is stored in internal representation
-
-        value = [valueClass valueFromBytes:pvalue length:vallen
-                            sqlite3Type:[attribute externalType]
-                            attribute:attribute
-                            adaptorChannel:self];
-      }
-      else {
-        // pvalue is ASCII string
-
-        value = [valueClass valueFromCString:pvalue length:vallen
-                            sqlite3Type:[attribute externalType]
-                            attribute:attribute
-                            adaptorChannel:self];
+      switch (sqlite3_column_type(self->statement, cnt)) {
+      case SQLITE_INTEGER:
+       value = [[valueClass alloc] 
+                 initWithSQLiteInt:sqlite3_column_int(self->statement, cnt)];
+       break;
+      case SQLITE_FLOAT:
+       value = [[valueClass alloc] 
+                 initWithSQLiteDouble:
+                   sqlite3_column_double(self->statement, cnt)];
+       break;
+      case SQLITE_TEXT:
+       value = [[valueClass alloc] 
+                 initWithSQLiteText:
+                   sqlite3_column_text(self->statement, cnt)];
+       break;
+      case SQLITE_BLOB:
+       value = [[valueClass alloc] 
+                 initWithSQLiteData:
+                   sqlite3_column_blob(self->statement, cnt)
+                 length:sqlite3_column_bytes(self->statement, cnt)];
+       break;
+      case SQLITE_NULL:
+       value = [null retain];
+       break;
+      default:
+       NSLog(@"ERROR(%s): unexpected SQLite type at column %i", 
+             __PRETTY_FUNCTION__, cnt);
+       continue;
       }
+      
       if (value == nil) {
         NSLog(@"ERROR(%s): %@: got no value for column:\n"
               @"  attribute=%@\n  valueClass=%@\n  type=%@",
@@ -419,107 +446,139 @@ static int openConnectionCount = 0;
        continue;
       }
     }
-#endif
-
-    [row setObject:value forKey:attrName];
+    
+    if (value != nil) {
+      [row setObject:value forKey:attrName];
+      [value release];
+    }
   }
-
-  self->currentTuple++;
-
+  
   return row;
 }
 
 /* sending SQL to server */
 
-static int sqlite_result_callback
-(void *userdata, int columnCount, char **columns, char **columnNames)
-{
-  /* need to load into array ... */
-  SQLiteChannel *self = userdata;
-  
-  NSLog(@"%@: SQLite callback, %i columns ...", self, columnCount);
-  return 0;
-}
-
-- (BOOL)evaluateExpression:(NSString *)_expression {
-  char *zErrMsg = NULL;
-  BOOL result;
+- (NSException *)evaluateExpressionX:(NSString *)_expression {
+  NSMutableString *sql;
+  NSException *error;
+  char       *zErrMsg = NULL;
+  BOOL       result;
+  const char *s;
+  const char *tails = NULL;
   int  rc;
 
   *(&result) = YES;
-
+  
   if (_expression == nil) {
     [NSException raise:@"InvalidArgumentException"
                 format:@"parameter for evaluateExpression: "
                         @"must not be null (channel=%@)", self];
   }
   
-  *(&_expression) = [[_expression mutableCopy] autorelease];
+  sql = [[_expression mutableCopy] autorelease];
 
+  /* ask delegate */
+  
   if (delegateRespondsTo.willEvaluateExpression) {
     EODelegateResponse response;
-
-    response =
-      [delegate adaptorChannel:self
-                willEvaluateExpression:(NSMutableString *)_expression];
     
-    if (response == EODelegateRejects)
-      return NO;
+    response = [delegate adaptorChannel:self willEvaluateExpression:sql];
+    
+    if (response == EODelegateRejects) {
+      return [NSException exceptionWithName:@"EODelegateRejects"
+                         reason:@"delegate rejected insert"
+                         userInfo:nil];
+    }
     if (response == EODelegateOverrides)
-      return YES;
+      return nil;
   }
+
+  /* check some preconditions */
   
   if (![self isOpen]) {
-    [SQLiteException raise:@"ChannelNotOpenException"
-                    format:@"SQLite connection is not open (channel=%@)",
-                    self];
-    return NO;
+    return [SQLiteException exceptionWithName:@"ChannelNotOpenException"
+                           reason:@"SQLite connection is not open"
+                           userInfo:nil];
   }
-  if (self->results != NULL) {
-    [SQLiteException raise:@"CommandInProgressException"
-                    format:@"an evaluation is in progress (channel=%@)",self];
+  if (self->statement != NULL) {
+    return [SQLiteException exceptionWithName:@"CommandInProgressException"
+                           reason:@"an evaluation is in progress"
+                           userInfo:nil];
     return NO;
   }
-
+  
+  if ([self isFetchInProgress]) {
+    NSLog(@"WARNING: a fetch is still in progress: %@", self);
+    [self cancelFetch];
+  }
+  
   if (isDebuggingEnabled)
-    NSLog(@"%@ sql: %@", self, _expression);
+    NSLog(@"%@ SQL: %@", self, sql);
 
+  /* reset environment */
+  
   self->isFetchInProgress = NO;
-  self->tupleCount   = 0;
-  self->fieldCount   = 0;
-  self->currentTuple = 0;
-  self->containsBinaryData = NO;
-  
-  rc = sqlite3_exec(self->_connection,
-                   [_expression UTF8String],
-                   sqlite_result_callback,
-                   self /* userdata */,
-                   &zErrMsg);
+  
+  s  = [sql UTF8String];
+  rc = sqlite3_prepare(self->_connection, s, strlen(s), 
+                      (void *)&(self->statement), &tails);
+  
   if (rc != SQLITE_OK) {
-    NSString *err;
-    
-    if (zErrMsg) {
-      err = [NSString stringWithCString:zErrMsg];
-      free(zErrMsg);
+    [self cancelFetch];
+    // TODO: improve error
+    return [SQLiteException exceptionWithName:@"ExecutionFailed" 
+                           reason:@"could not parse SQL statement" 
+                           userInfo:nil];
+  }
+  
+  /* step to first row */
+  
+  if ([sql hasPrefix:@"SELECT"] || [sql hasPrefix:@"select"]) {
+    self->isFetchInProgress = YES;
+    NSAssert(self->statement, @"missing statement");
+  }
+  else {
+    if ((error = [self _makeSQLiteStep]) != nil) {
+      [self cancelFetch];
+      return error;
+    }
+  
+    self->isFetchInProgress = self->hasPendingRow;
+    if (!self->isFetchInProgress) {
+      sqlite3_finalize(self->statement); 
+      self->statement = NULL;
     }
-    else
-      err = nil;
-    
-    [SQLiteException raise:@"ExecutionFailed"
-                     format:
-                       @"the sqlite_exec(%@) call failed (channel=%@): %s",
-                       _expression, self, err];
-    return NO;
   }
-  if (zErrMsg) {
-    NSLog(@"WARNING(%@): pending error message: '%s'", self, zErrMsg);
+  
+  /* check whether there are pending errors */
+  
+  if (zErrMsg != NULL) {
+    NSLog(@"WARNING(%s): %@ pending error message: '%s'", 
+         __PRETTY_FUNCTION__, self, zErrMsg);
     free(zErrMsg);
   }
-
+  
   /* only on empty results? */
   if (delegateRespondsTo.didEvaluateExpression)
-    [delegate adaptorChannel:self didEvaluateExpression:_expression];
+    [delegate adaptorChannel:self didEvaluateExpression:sql];
   
+  return nil /* everything is OK */;
+}
+- (BOOL)evaluateExpression:(NSString *)_sql {
+  NSException *e;
+  NSString *n;
+  
+  if ((e = [self evaluateExpressionX:_sql]) == nil)
+    return YES;
+  
+  /* for compatibility with non-X methods, translate some errors to a bool */
+  n = [e name];
+  if ([n isEqualToString:@"EOEvaluationError"])
+    return NO;
+  if ([n isEqualToString:@"EODelegateRejects"])
+    return NO;
+  
+  [e raise];
   return NO;
 }
 
@@ -553,39 +612,23 @@ static int sqlite_result_callback
   pkey    = nil;
   seq     = nil;
   
-  if ([seqName length] > 0)
-    seq = [NSString stringWithFormat:@"SELECT NEXTVAL ('%@')", seqName];
-  else
-    seq = [adaptor newKeyExpression];
+  seq = ([seqName length] > 0)
+    ? [NSString stringWithFormat:@"SELECT NEXTVAL ('%@')", seqName]
+    : [adaptor newKeyExpression];
   
   NS_DURING {
     if ([self evaluateExpression:seq]) {
       id key = nil;
-#if 0
-      if (self->tupleCount > 0) {
-        if (PQgetisnull(self->results, 0, 0))
-          key = null;
-        else {
-          const char *pvalue;
-          int         vallen;
-          
-          if (self->containsBinaryData) {
-            [self notImplemented:_cmd];
-          }
-          
-          pvalue = PQgetvalue(self->results, 0, 0);
-          vallen = PQgetlength(self->results, 0, 0);
-
-          if (pvalue)
-            key = [NSNumber numberWithInt:atoi(pvalue)];
-        }
+      
+      NSLog(@"ERROR: new key creation is not implemented in SQLite yet!");
+      if ([self isFetchInProgress]) {
+       NSLog(@"Primary key eval returned results ..");
       }
-#endif
       // TODO
       NSLog(@"%s: PKEY GEN NOT IMPLEMENTED!", __PRETTY_FUNCTION__);
       [self cancelFetch];
 
-      if (key) {
+      if (key != nil) {
         pkey = [NSDictionary dictionaryWithObject:key
                              forKey:[pkeys objectAtIndex:0]];
       }
index 18bdaf6c64c144592780c39bbf1350e59679e85e..31604f3d20c41bf9a72784553d50901caaa1c746 100644 (file)
 
 - (BOOL)primaryBeginTransaction {
   BOOL result;
-
+  
   result = [[[channels lastObject]
                        nonretainedObjectValue]
                        evaluateExpression:@"BEGIN TRANSACTION"];
-
+  
   return result;
 }
 
index 0f40a88cbf1c066d2961dde98837f70bd002a4e1..1372816b5e167bc9d0f1ec35ccbbe24db1d6595f 100644 (file)
 
 @protocol SQLiteValues
 
-+ (id)valueFromCString:(const char *)_cstr length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel;
-
-+ (id)valueFromBytes:(const void *)_bytes length:(int)_length
-  sqlite3Type:(NSString *)_type
-  attribute:(EOAttribute *)_attribute
-  adaptorChannel:(SQLiteChannel *)_channel;
-
 - (NSString *)stringValueForSQLite3Type:(NSString *)_type
   attribute:(EOAttribute *)_attribute;
 
 @end
 
+@interface NSObject(SQLiteValues)
+
+- (id)initWithSQLiteInt:(int)_value;
+- (id)initWithSQLiteText:(const unsigned char *)_value;
+- (id)initWithSQLiteDouble:(double)_value;
+- (id)initWithSQLiteData:(const void *)_data length:(int)_length;
+
+@end
+
 @interface NSString(SQLiteValues) < SQLiteValues >
 @end
 
index 19ac4f112b2f9dcbdc6e242253eb48bf766df5e9..fdbe6c0509a73a26d57e857b9eb21226d345a17a 100644 (file)
 
 @end /* NSNull(SQLiteValues) */
 
+@implementation NSObject(SQLiteValues)
+
+- (id)initWithSQLiteInt:(int)_value {
+  if ([self respondsToSelector:@selector(initWithInt:)])
+    return [(NSNumber *)self initWithInt:_value];
+  
+  if ([self respondsToSelector:@selector(initWithDouble:)])
+    return [(NSNumber *)self initWithDouble:_value];
+  
+  if ([self respondsToSelector:@selector(initWithString:)]) {
+    NSString *s;
+    char buf[256];
+
+    sprintf(buf, "%i", _value);
+    s = [[NSString alloc] initWithCString:buf];
+    self = [(NSString *)self initWithString:s];
+    [s release];
+    return self;
+  }
+  
+  [self release];
+  return nil;
+}
+
+- (id)initWithSQLiteDouble:(double)_value {
+  if ([self respondsToSelector:@selector(initWithDouble:)])
+    return [(NSNumber *)self initWithDouble:_value];
+  
+  [self release];
+  return nil;
+}
+
+- (id)initWithSQLiteText:(const unsigned char *)_value {
+  if ([self respondsToSelector:@selector(initWithString:)]) {
+    NSString *s;
+    
+    s = [[NSString alloc] initWithUTF8String:_value];
+    self = [(NSString *)self initWithString:s];
+    [s release];
+    return self;
+  }
+  
+  [self release];
+  return nil;
+}
+
+- (id)initWithSQLiteData:(const void *)_data length:(int)_length {
+  if ([self respondsToSelector:@selector(initWithBytes:length:)])
+    return [(NSData *)self initWithBytes:_data length:_length];
+  
+  if ([self respondsToSelector:@selector(initWithData:)]) {
+    NSData *d;
+    
+    d = [[NSData alloc] initWithBytes:_data length:_length];
+    self = [(NSData *)self initWithData:d];
+    [d release];
+    return self;
+  }
+  
+  [self release];
+  return nil;
+}
+
+@end /* NSObject(SQLiteValues) */
 
 void __link_SQLiteValues() {
   // used to force linking of object file
index f5da07a49caa87a912d53bc163c7c93e87a589cd..b191a15e76dac3e66bcd9f3cefe22e3b7ade21f4 100644 (file)
@@ -1,3 +1,3 @@
-# $Id: Version,v 1.1 2004/06/14 14:27:44 helge Exp $
+# Version file
 
-SUBMINOR_VERSION:=8
+SUBMINOR_VERSION:=9
index cad5fdb8baf225de96611b104ab9f520cb25cf4e..a8ac58af45c8e0c0be8fbfcfada9f541f942395d 100644 (file)
 #import <GDLAccess/GDLAccess.h>
 #include <NGExtensions/NGExtensions.h>
 
+static void fetchExprInChannel(NSString *expr, EOAdaptorChannel *ch) {
+  NSArray      *attrs;
+  NSDictionary *record;
+  
+  if (![expr isNotNull]) return;
+
+  if (![ch evaluateExpression:expr]) {
+    NSLog(@"ERROR: failed to evaluate: %@", expr);
+    return;
+  }
+
+  attrs = [ch describeResults];
+  NSLog(@"results: %@", attrs);
+    
+  while ((record = [ch fetchAttributes:attrs withZone:nil]) != nil)
+    NSLog(@"fetched %@", record);
+}
+
+static void fetchSomePersonRecord(EOEntity *e, EOAdaptorChannel *ch) {
+  EOSQLQualifier *q;
+  NSArray *attrs;
+
+    attrs = [e attributes];
+    q = [[EOSQLQualifier alloc]
+         initWithEntity:e
+         qualifierFormat:@"%A='helge'", @"login"];
+    [q autorelease];
+
+    if ([ch selectAttributes:attrs
+           describedByQualifier:q
+           fetchOrder:nil
+           lock:NO]) {
+      NSDictionary *record;
+
+      record = [ch fetchAttributes:attrs withZone:nil];
+    }
+    else
+      NSLog(@"Could not select ..");
+}
+
+static void fetchSomeTeamRecords(EOEntity *e, EOAdaptorChannel *ch) {
+  EOSQLQualifier *q;
+  NSArray *attrs;
+
+  q     = [e qualifier];
+  attrs = [e attributes];
+
+  if ([ch selectAttributes:attrs describedByQualifier:q fetchOrder:nil
+         lock:NO]) {
+    NSDictionary *record;
+      
+    while ((record = [ch fetchAttributes:attrs withZone:NULL]) != nil) {
+       NSLog(@"fetched %@ birthday %@",
+             [record valueForKey:@"description"],
+             [record valueForKey:@"companyId"]);
+    }
+  }
+  else
+    NSLog(@"Could not select team records ..");
+}
+
 static void runtestInOpenChannel(EOAdaptorChannel *ch) {
+  NSAutoreleasePool *pool = [NSAutoreleasePool new];
+  EOEntity *e;
+  EOSQLQualifier *q;
+  NSArray *attrs;
   EOAdaptorContext *ctx;
   EOModel  *m;
   NSString *expr;
@@ -38,109 +103,61 @@ static void runtestInOpenChannel(EOAdaptorChannel *ch) {
   expr = [[NSUserDefaults standardUserDefaults] stringForKey:@"sql"];
 
   NSLog(@"channel is open");
-    
-  if ([ctx beginTransaction]) {
-      NSLog(@"began tx ..");
+  
+  if (![ctx beginTransaction]) {
+    NSLog(@"ERROR: could not begin transaction ...");
+    return;
+  }
 
-      /* do something */
-      {
-        NSAutoreleasePool *pool = [NSAutoreleasePool new];
-        EOEntity *e;
-        EOSQLQualifier *q;
-        NSArray *attrs;
+  NSLog(@"began tx ..");
 
+  /* do something */
+  pool = [[NSAutoreleasePool alloc] init];
 #if 1
-        /* fetch some expr */
-
-        if (expr) {
-          if ([ch evaluateExpression:expr]) {
-            NSDictionary *record;
-
-            attrs = [ch describeResults];
-            NSLog(@"results: %@", attrs);
-           
-            while ((record = [ch fetchAttributes:attrs withZone:nil]))
-              NSLog(@"fetched %@", record);
-          }
-        }
+  fetchExprInChannel(expr, ch);
 #endif
-        /* fetch some doof records */
-
-        e = [m entityNamed:@"MyEntity"];
-        NSLog(@"entity: %@", e);
-        if (e == nil)
-          exit(1);
-        
-        q = [e qualifier];
-        attrs = [e attributes];
-
-        if ([ch selectAttributes:attrs
-                describedByQualifier:q
-                fetchOrder:nil
-                lock:NO]) {
-          NSDictionary *record;
-
-          while ((record = [ch fetchAttributes:attrs withZone:nil])) {
-            NSLog(@"fetched %@ birthday %@",
-                  [record valueForKey:@"pkey"],
-                  [record valueForKey:@"companyId"]);
-          }
-        }
-        else
-          NSLog(@"Could not select ..");
-
-        /* fetch some team records */
-
-        if ((e = [m entityNamed:@"Team"])) {
-          q = [e qualifier];
-          attrs = [e attributes];
-
-          if ([ch selectAttributes:attrs
-                  describedByQualifier:q
-                  fetchOrder:nil
-                  lock:NO]) {
-            NSDictionary *record;
-
-            while ((record = [ch fetchAttributes:attrs withZone:nil])) {
-              NSLog(@"fetched %@ birthday %@",
-                    [record valueForKey:@"description"],
-                    [record valueForKey:@"companyId"]);
-            }
-          }
-          else
-            NSLog(@"Could not select ..");
-        }
+  
+  /* fetch some MyEntity records */
+  
+  e = [m entityNamed:@"MyEntity"];
+  NSLog(@"entity: %@", e);
+  if (e == nil)
+    exit(1);
         
-        /* do some update */
-
-        if ((e = [m entityNamed:@"Person"])) {
-          attrs = [e attributes];
-          q = [[EOSQLQualifier alloc]
-                               initWithEntity:e
-                               qualifierFormat:@"%A='helge'", @"login"];
-          AUTORELEASE(q);
-
-          if ([ch selectAttributes:attrs
-                  describedByQualifier:q
-                  fetchOrder:nil
-                  lock:NO]) {
-            NSDictionary *record;
-
-            record = [ch fetchAttributes:attrs withZone:nil];
-          }
-          else
-            NSLog(@"Could not select ..");
-        }
-
-        RELEASE(pool);
-      }
+  q     = [e qualifier];
+  attrs = [e attributes];
+  
+  // NSLog(@"ATTRS: %@", attrs);
+  
+  if ([ch selectAttributes:attrs
+         describedByQualifier:q
+         fetchOrder:nil
+         lock:NO]) {
+    NSDictionary *record;
+
+    while ((record = [ch fetchAttributes:attrs withZone:nil]) != nil)
+      NSLog(@"fetched record: %@", record);
+  }
+  else
+    NSLog(@"Could not select ..");
+
+  /* some OGo fetches */
+  
+  if ((e = [m entityNamed:@"Team"]) != nil)
+    fetchSomeTeamRecords(e, ch);
+  
+  if ((e = [m entityNamed:@"Person"]) != nil)
+    fetchSomePersonRecord(e, ch);
+
+  /* tear down */
+  
+  [pool release];
       
-      NSLog(@"committing tx ..");
-      if ([ctx commitTransaction])
-        NSLog(@"  could commit.");
-      else
-        NSLog(@"  commit failed.");
-    }
+  NSLog(@"committing tx ..");
+  if ([ctx commitTransaction])
+    NSLog(@"  could commit.");
+  else
+    NSLog(@"  commit failed.");
 }
 
 static void runtest(void) {