]> err.no Git - sope/commitdiff
added some fetch support
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Tue, 12 Apr 2005 21:23:15 +0000 (21:23 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Tue, 12 Apr 2005 21:23:15 +0000 (21:23 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@735 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-gdl1/MySQL4/ChangeLog
sope-gdl1/MySQL4/MySQL4Channel.h
sope-gdl1/MySQL4/MySQL4Channel.m
sope-gdl1/MySQL4/Version

index 0728516d5dbecc1ae8bdb16026a1f1e67c13d063..399b05c285141beca9e08bce6ebacc455dec2b9f 100644 (file)
@@ -1,3 +1,7 @@
+2005-04-12  Helge Hess  <helge.hess@opengroupware.org>
+
+       * MySQL4Channel.m: added some fetch result processing (v4.5.3)
+
 2005-04-12  Helge Hess  <helge.hess@skyrix.com>
 
        * MySQL4Channel.m: implemented query (v4.5.2)
index 93b8d0eb78955e5b69522c6b45119ee07e77e11c..1a8cebb6aebb56fb19964a35c805808a69f5c073 100644 (file)
 {
   // connection is valid after an openChannel call
   void *_connection;
-  
-  // valid during -evaluateExpression:
-  BOOL     hasPendingRow;
-  BOOL     isDone;
-  
-  void     *results;
+  void *results;
+  void *fields;
+  int  fieldCount;
+
 #if 0
   int      tupleCount;
-  int      fieldCount;
   BOOL     containsBinaryData;
   NSString *cmdStatus;
   NSString *cmdTuples;
index 96fd947624c14a5cd64afee7a02f18bbfc40ef9d..7ae346265904c0c4af259ef2973d2448fdd89586 100644 (file)
@@ -201,6 +201,9 @@ static int openConnectionCount = 0;
 }
 
 - (void)primaryCloseChannel {
+  if ([self isFetchInProgress])
+    [self cancelFetch];
+  
   if (self->_connection != NULL) {
     mysql_close(self->_connection);
 #if 0
@@ -225,66 +228,32 @@ static int openConnectionCount = 0;
 
 /* fetching rows */
 
-- (NSException *)_makeMySQL4Step {
-  NSString *r;
-  const char *em;
-  int rc;
-  
-#if 1
-#  warning IMPLEMENT ME
-#else
-  rc = sqlite3_step(self->statement);
-#endif
-#if 0
-  NSLog(@"STEP: %i (row=%i, done=%i, mis=%i)", rc,
-       SQLITE_ROW, SQLITE_DONE, SQLITE_MISUSE);
-#endif
-  
-#if 1
-#  warning IMPLEMENT ME
-#else
-  if (rc == SQLITE_ROW) {
-    self->hasPendingRow = YES;
-    self->isDone        = NO;
-    return nil /* no error */;
-  }
-  if (rc == SQLITE_DONE) {
-    self->hasPendingRow = NO;
-    self->isDone        = YES;
-    return nil /* no error */;
-  }
-
-  if (rc == SQLITE_ERROR)
-    r = [NSString stringWithUTF8String:sqlite3_errmsg(self->_connection)];
-  else if (rc == SQLITE_MISUSE)
-    r = @"The MySQL4 step function was called in an incorrect way";
-  else if (rc == SQLITE_BUSY)
-    r = @"The MySQL4 is busy.";
-  else
-    r = [NSString stringWithFormat:@"Unexpected MySQL4 error: %i", rc];
-
-  if ((em = sqlite3_errmsg(self->_connection)) != NULL)
-    r = [r stringByAppendingFormat:@": %s", em];
-#endif
-  
-  return [MySQL4Exception exceptionWithName:@"FetchFailed"
-                         reason:r userInfo:nil];
-}
-
 - (void)cancelFetch {
+  self->fields = NULL; /* apparently we do not need to free those */
+  
   if (self->results != NULL) {
     mysql_free_result(self->results);
     self->results = NULL;
   }
-  
-  self->isDone        = NO;
-  self->hasPendingRow = NO;
   [super cancelFetch];
 }
 
+- (MYSQL_FIELD *)_fetchFields {
+  if (self->results == NULL)
+    return NULL;
+  
+  if (self->fields != NULL)
+    return self->fields;
+  
+  self->fields     = mysql_fetch_fields(self->results);
+  self->fieldCount = mysql_num_fields(self->results);
+  return self->fields;
+}
+
 - (NSArray *)describeResults {
   // TODO: make exception-less method
-  int                 cnt, fieldCount;
+  MYSQL_FIELD         *mfields;
+  int                 cnt;
   NSMutableArray      *result    = nil;
   NSMutableDictionary *usedNames = nil;
   NSNumber            *yesObj;
@@ -294,29 +263,14 @@ static int openConnectionCount = 0;
   if (![self isFetchInProgress]) {
     [MySQL4Exception 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 _makeMySQL4Step]) != nil) {
-      [self cancelFetch];
-      [error raise]; // raise error, TODO: make exception-less method
-      return nil;
-    }
-  }
-  if (!self->hasPendingRow) /* no rows available */
     return nil;
+  }
   
-#if 1
-#  warning IMPLEMENT ME
-#else
-  fieldCount = sqlite3_column_count(self->statement);
-#endif
-  
-  /* old code below */
+  if ((mfields = [self _fetchFields]) == NULL) {
+    [MySQL4Exception raise:@"NoFieldInfo"
+                    format:@"Failed to fetch field info (channel=%@)", self];
+    return nil;
+  }
   
   result    = [[NSMutableArray      alloc] initWithCapacity:fieldCount];
   usedNames = [[NSMutableDictionary alloc] initWithCapacity:fieldCount];
@@ -326,12 +280,7 @@ static int openConnectionCount = 0;
     NSString    *columnName = nil;
     NSString    *attrName   = nil;
     
-#if 1
-#  warning IMPLEMENT ME
-#else
-    columnName = [NSString stringWithCString:
-                            sqlite3_column_name(self->statement, cnt)];
-#endif
+    columnName = [NSString stringWithUTF8String:mfields[cnt].name];
     attrName   = [columnName _mySQL4ModelMakeInstanceVarName];
     
     if ([[usedNames objectForKey:attrName] boolValue]) {
@@ -360,6 +309,114 @@ static int openConnectionCount = 0;
     [attribute setName:attrName];
     [attribute setColumnName:columnName];
     
+    [attribute setAllowsNull:
+                (mfields[cnt].flags & NOT_NULL_FLAG) ? NO : YES];
+    
+    /*
+      We also know whether a field:
+        is primary
+        is unique
+       is auto-increment
+       is zero-fill
+       is unsigned
+    */
+    if (mfields[cnt].flags & UNSIGNED_FLAG) {
+      NSLog(@"ERROR: MySQL4 field is marked unsigned (unsupported): %@",
+           attribute);
+    }
+    
+    switch (mfields[cnt].type) {
+    case FIELD_TYPE_STRING:
+      [attribute setExternalType:@"CHAR"];
+      [attribute setValueClassName:@"NSString"];
+      // TODO: length etc
+      break;
+    case FIELD_TYPE_VAR_STRING:
+      [attribute setExternalType:@"VARCHAR"];
+      [attribute setValueClassName:@"NSString"];
+      // TODO: length etc
+      break;
+      
+    case FIELD_TYPE_TINY:
+      [attribute setExternalType:@"TINY"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"c"];
+      break;
+    case FIELD_TYPE_SHORT:
+      [attribute setExternalType:@"SHORT"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"s"];
+      break;
+    case FIELD_TYPE_LONG:
+      [attribute setExternalType:@"LONG"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"l"];
+      break;
+    case FIELD_TYPE_INT24:
+      [attribute setExternalType:@"INT"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"i"]; // bumped
+      break;
+    case FIELD_TYPE_LONGLONG:
+      [attribute setExternalType:@"LONGLONG"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"q"];
+      break;
+    case FIELD_TYPE_DECIMAL:
+      [attribute setExternalType:@"DECIMAL"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"f"]; // TODO: need NSDecimalNumber here ...
+      break;
+    case FIELD_TYPE_FLOAT:
+      [attribute setExternalType:@"FLOAT"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"f"];
+      break;
+    case FIELD_TYPE_DOUBLE:
+      [attribute setExternalType:@"DOUBLE"];
+      [attribute setValueClassName:@"NSNumber"];
+      [attribute setValueType:@"d"];
+      break;
+
+    case FIELD_TYPE_TIMESTAMP:
+      [attribute setExternalType:@"TIMESTAMP"];
+      [attribute setValueClassName:@"NSCalendarDate"];
+      break;
+    case FIELD_TYPE_DATE:
+      [attribute setExternalType:@"DATE"];
+      [attribute setValueClassName:@"NSCalendarDate"];
+      break;
+    case FIELD_TYPE_DATETIME:
+      [attribute setExternalType:@"DATETIME"];
+      [attribute setValueClassName:@"NSCalendarDate"];
+      break;
+      
+    case FIELD_TYPE_BLOB:
+    case FIELD_TYPE_TINY_BLOB:
+    case FIELD_TYPE_MEDIUM_BLOB:
+    case FIELD_TYPE_LONG_BLOB:
+      // TODO: length etc
+      if (mfields[cnt].flags & BINARY_FLAG) {
+       [attribute setExternalType:@"BLOB"];
+       [attribute setValueClassName:@"NSData"];
+      }
+      else {
+       [attribute setExternalType:@"TEXT"];
+       [attribute setValueClassName:@"NSString"];
+      }
+      break;
+      
+    case FIELD_TYPE_NULL: // TODO: whats that?
+    case FIELD_TYPE_TIME:
+    case FIELD_TYPE_YEAR:
+    case FIELD_TYPE_SET:
+    case FIELD_TYPE_ENUM:
+    default:
+       NSLog(@"ERROR(%s): unexpected MySQL4 type at column %i: %@", 
+             __PRETTY_FUNCTION__, cnt, attribute);
+       break;
+    }
+    
 #if 1
 #  warning IMPLEMENT ME
 #else
@@ -390,9 +447,6 @@ static int openConnectionCount = 0;
        [attribute setValueClassName:@"NSNull"];
        break;
       default:
-       NSLog(@"ERROR(%s): unexpected MySQL4 type at column %i", 
-             __PRETTY_FUNCTION__, cnt);
-       break;
     }
 #endif    
     [result addObject:attribute];
@@ -429,33 +483,35 @@ static int openConnectionCount = 0;
          schema)
   */
   // TODO: add a primaryFetchAttributesX method?
+  MYSQL_ROW rawRow;
   NSMutableDictionary *row = nil;
   NSException *error;
   unsigned attrCount = [_attributes count];
   unsigned cnt;
-
-#if 0  
-  if (self->statement == NULL) {
-    NSLog(@"ERROR: no fetch in progress?");
+  
+  if (self->results == NULL) {
+    NSLog(@"ERROR(%s): no fetch in progress?", __PRETTY_FUNCTION__);
     [self cancelFetch];
     return nil;
   }
-#endif
+
+  /* raw fetch */
   
-  if (!self->hasPendingRow && !self->isDone) {
-    if ((error = [self _makeMySQL4Step]) != nil) {
-      [self cancelFetch];
-      [error raise]; // raise error, TODO: make exception-less method
+  if ((rawRow = mysql_fetch_row(self->results)) == NULL) {
+    // TODO: might need to close channel on connect exceptions
+    const char *error;
+    
+    if ((error = mysql_error(self->_connection)) != NULL) {
+      [MySQL4Exception raise:@"FetchFailed" 
+                      format:@"%@",[NSString stringWithUTF8String:error]];
       return nil;
     }
-  }
-  if (self->isDone) { /* step was fine, but we are at the end */
+    
+    /* regular end of result set */
     [self cancelFetch];
     return nil;
   }
   
-  self->hasPendingRow = NO; /* consume the row */
-  
   /* build row */
   
   row = [NSMutableDictionary dictionaryWithCapacity:attrCount];
@@ -580,14 +636,12 @@ static int openConnectionCount = 0;
                            reason:@"MySQL4 connection is not open"
                            userInfo:nil];
   }
-#if 0
-  if (self->statement != NULL) {
+  if (self->results != NULL) {
     return [MySQL4Exception exceptionWithName:@"CommandInProgressException"
                            reason:@"an evaluation is in progress"
                            userInfo:nil];
     return NO;
   }
-#endif
   
   if ([self isFetchInProgress]) {
     NSLog(@"WARNING: a fetch is still in progress: %@", self);
@@ -600,8 +654,6 @@ static int openConnectionCount = 0;
   /* reset environment */
   
   self->isFetchInProgress = NO;
-  self->isDone        = NO;
-  self->hasPendingRow = NO;
   
   /* start query */
   
index 648edbe20adf383833080c4544f0380bae83d496..f7ead5f24d21968b0b1702cfd9aaaefc23443c32 100644 (file)
@@ -1,3 +1,3 @@
 # Version file
 
-SUBMINOR_VERSION:=2
+SUBMINOR_VERSION:=3