aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
diff options
context:
space:
mode:
Diffstat (limited to 'Frameworks/MCPKit/MCPFoundationKit/MCPResult.m')
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPResult.m1360
1 files changed, 1360 insertions, 0 deletions
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
new file mode 100644
index 00000000..f8158f7c
--- /dev/null
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
@@ -0,0 +1,1360 @@
+//
+// $Id: MCPResult.m 1065 2009-07-19 10:58:17Z stuart02 $
+//
+// MCPResult.m
+// MCPKit
+//
+// Created by Serge Cohen (serge.cohen@m4x.org) on 08/12/2002.
+// Copyright (c) 2001 Serge Cohen. All rights reserved.
+//
+// Forked by the Sequel Pro team (sequelpro.com), April 2009
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://mysql-cocoa.sourceforge.net/>
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "MCPConnection.h"
+#import "MCPNull.h"
+#import "MCPNumber.h"
+#import "MCPResult.h"
+
+NSCalendarDate *MCPYear0000;
+
+const OUR_CHARSET our_charsets60[] =
+{
+ {1, "big5","big5_chinese_ci", 1, 2},
+ {3, "dec8", "dec8_swedisch_ci", 1, 1},
+ {4, "cp850", "cp850_general_ci", 1, 1},
+ {6, "hp8", "hp8_english_ci", 1, 1},
+ {7, "koi8r", "koi8r_general_ci", 1, 1},
+ {8, "latin1", "latin1_swedish_ci", 1, 1},
+ {9, "latin2", "latin2_general_ci", 1, 1},
+ {10, "swe7", "swe7_swedish_ci", 1, 1},
+ {11, "ascii", "ascii_general_ci", 1, 1},
+ {12, "ujis", "ujis_japanese_ci", 1, 3},
+ {13, "sjis", "sjis_japanese_ci", 1, 2},
+ {16, "hebrew", "hebrew_general_ci", 1, 1},
+ {18, "tis620", "tis620_thai_ci", 1, 1},
+ {19, "euckr", "euckr_korean_ci", 1, 2},
+ {22, "koi8u", "koi8u_general_ci", 1, 1},
+ {24, "gb2312", "gb2312_chinese_ci", 1, 2},
+ {25, "greek", "greek_general_ci", 1, 1},
+ {26, "cp1250", "cp1250_general_ci", 1, 1},
+ {28, "gbk", "gbk_chinese_ci", 1, 2},
+ {30, "latin5", "latin5_turkish_ci", 1, 1},
+ {32, "armscii8", "armscii8_general_ci", 1, 1},
+ {33, "utf8", "utf8_general_ci", 1, 3},
+ {35, "ucs2", "ucs2_general_ci", 2, 2},
+ {36, "cp866", "cp866_general_ci", 1, 1},
+ {37, "keybcs2", "keybcs2_general_ci", 1, 1},
+ {38, "macce", "macce_general_ci", 1, 1},
+ {39, "macroman", "macroman_general_ci", 1, 1},
+ {40, "cp852", "cp852_general_ci", 1, 1},
+ {41, "latin7", "latin7_general_ci", 1, 1},
+ {51, "cp1251", "cp1251_general_ci", 1, 1},
+ {57, "cp1256", "cp1256_general_ci", 1, 1},
+ {59, "cp1257", "cp1257_general_ci", 1, 1},
+ {63, "binary", "binary", 1, 1},
+ {92, "geostd8", "geostd8_general_ci", 1, 1},
+ {95, "cp932", "cp932_japanese_ci", 1, 2},
+ {97, "eucjpms", "eucjpms_japanese_ci", 1, 3},
+ {2, "latin2", "latin2_czech_cs", 1, 1},
+ {5, "latin1", "latin1_german_ci", 1, 1},
+ {14, "cp1251", "cp1251_bulgarian_ci", 1, 1},
+ {15, "latin1", "latin1_danish_ci", 1, 1},
+ {17, "filename", "filename", 1, 5},
+ {20, "latin7", "latin7_estonian_cs", 1, 1},
+ {21, "latin2", "latin2_hungarian_ci", 1, 1},
+ {23, "cp1251", "cp1251_ukrainian_ci", 1, 1},
+ {27, "latin2", "latin2_croatian_ci", 1, 1},
+ {29, "cp1257", "cp1257_lithunian_ci", 1, 1},
+ {31, "latin1", "latin1_german2_ci", 1, 1},
+ {34, "cp1250", "cp1250_czech_cs", 1, 1},
+ {42, "latin7", "latin7_general_cs", 1, 1},
+ {43, "macce", "macce_bin", 1, 1},
+ {44, "cp1250", "cp1250_croatian_ci", 1, 1},
+ {45, "utf8", "utf8_general_ci", 1, 1},
+ {46, "utf8", "utf8_bin", 1, 1},
+ {47, "latin1", "latin1_bin", 1, 1},
+ {48, "latin1", "latin1_general_ci", 1, 1},
+ {49, "latin1", "latin1_general_cs", 1, 1},
+ {50, "cp1251", "cp1251_bin", 1, 1},
+ {52, "cp1251", "cp1251_general_cs", 1, 1},
+ {53, "macroman", "macroman_bin", 1, 1},
+ {58, "cp1257", "cp1257_bin", 1, 1},
+ {60, "armascii8", "armascii8_bin", 1, 1},
+ {65, "ascii", "ascii_bin", 1, 1},
+ {66, "cp1250", "cp1250_bin", 1, 1},
+ {67, "cp1256", "cp1256_bin", 1, 1},
+ {68, "cp866", "cp866_bin", 1, 1},
+ {69, "dec8", "dec8_bin", 1, 1},
+ {70, "greek", "greek_bin", 1, 1},
+ {71, "hebew", "hebrew_bin", 1, 1},
+ {72, "hp8", "hp8_bin", 1, 1},
+ {73, "keybcs2", "keybcs2_bin", 1, 1},
+ {74, "koi8r", "koi8r_bin", 1, 1},
+ {75, "koi8u", "koi8u_bin", 1, 1},
+ {77, "latin2", "latin2_bin", 1, 1},
+ {78, "latin5", "latin5_bin", 1, 1},
+ {79, "latin7", "latin7_bin", 1, 1},
+ {80, "cp850", "cp850_bin", 1, 1},
+ {81, "cp852", "cp852_bin", 1, 1},
+ {82, "swe7", "swe7_bin", 1, 1},
+ {93, "geostd8", "geostd8_bin", 1, 1},
+ {83, "utf8", "utf8_bin", 1, 3},
+ {84, "big5", "big5_bin", 1, 2},
+ {85, "euckr", "euckr_bin", 1, 2},
+ {86, "gb2312", "gb2312_bin", 1, 2},
+ {87, "gbk", "gbk_bin", 1, 2},
+ {88, "sjis", "sjis_bin", 1, 2},
+ {89, "tis620", "tis620_bin", 1, 1},
+ {90, "ucs2", "ucs2_bin", 2, 2},
+ {91, "ujis", "ujis_bin", 1, 3},
+ {94, "latin1", "latin1_spanish_ci", 1, 1},
+ {96, "cp932", "cp932_bin", 1, 2},
+ {99, "cp1250", "cp1250_polish_ci", 1, 1},
+ {98, "eucjpms", "eucjpms_bin", 1, 3},
+ {128, "ucs2", "ucs2_unicode_ci", 2, 2},
+ {129, "ucs2", "ucs2_icelandic_ci", 2, 2},
+ {130, "ucs2", "ucs2_latvian_ci", 2, 2},
+ {131, "ucs2", "ucs2_romanian_ci", 2, 2},
+ {132, "ucs2", "ucs2_slovenian_ci", 2, 2},
+ {133, "ucs2", "ucs2_polish_ci", 2, 2},
+ {134, "ucs2", "ucs2_estonian_ci", 2, 2},
+ {135, "ucs2", "ucs2_spanish_ci", 2, 2},
+ {136, "ucs2", "ucs2_swedish_ci", 2, 2},
+ {137, "ucs2", "ucs2_turkish_ci", 2, 2},
+ {138, "ucs2", "ucs2_czech_ci", 2, 2},
+ {139, "ucs2", "ucs2_danish_ci", 2, 2},
+ {140, "ucs2", "ucs2_lithunian_ci", 2, 2},
+ {141, "ucs2", "ucs2_slovak_ci", 2, 2},
+ {142, "ucs2", "ucs2_spanish2_ci", 2, 2},
+ {143, "ucs2", "ucs2_roman_ci", 2, 2},
+ {144, "ucs2", "ucs2_persian_ci", 2, 2},
+ {145, "ucs2", "ucs2_esperanto_ci", 2, 2},
+ {146, "ucs2", "ucs2_hungarian_ci", 2, 2},
+ {147, "ucs2", "ucs2_sinhala_ci", 2, 2},
+ {192, "utf8mb3", "utf8mb3_general_ci", 1, 3},
+ {193, "utf8mb3", "utf8mb3_icelandic_ci", 1, 3},
+ {194, "utf8mb3", "utf8mb3_latvian_ci", 1, 3},
+ {195, "utf8mb3", "utf8mb3_romanian_ci", 1, 3},
+ {196, "utf8mb3", "utf8mb3_slovenian_ci", 1, 3},
+ {197, "utf8mb3", "utf8mb3_polish_ci", 1, 3},
+ {198, "utf8mb3", "utf8mb3_estonian_ci", 1, 3},
+ {119, "utf8mb3", "utf8mb3_spanish_ci", 1, 3},
+ {200, "utf8mb3", "utf8mb3_swedish_ci", 1, 3},
+ {201, "utf8mb3", "utf8mb3_turkish_ci", 1, 3},
+ {202, "utf8mb3", "utf8mb3_czech_ci", 1, 3},
+ {203, "utf8mb3", "utf8mb3_danish_ci", 1, 3},
+ {204, "utf8mb3", "utf8mb3_lithunian_ci", 1, 3},
+ {205, "utf8mb3", "utf8mb3_slovak_ci", 1, 3},
+ {206, "utf8mb3", "utf8mb3_spanish2_ci", 1, 3},
+ {207, "utf8mb3", "utf8mb3_roman_ci", 1, 3},
+ {208, "utf8mb3", "utf8mb3_persian_ci", 1, 3},
+ {209, "utf8mb3", "utf8mb3_esperanto_ci", 1, 3},
+ {210, "utf8mb3", "utf8mb3_hungarian_ci", 1, 3},
+ {211, "utf8mb3", "utf8mb3_sinhala_ci", 1, 3},
+ {224, "utf8", "utf8_unicode_ci", 1, 3},
+ {225, "utf8", "utf8_icelandic_ci", 1, 3},
+ {226, "utf8", "utf8_latvian_ci", 1, 3},
+ {227, "utf8", "utf8_romanian_ci", 1, 3},
+ {228, "utf8", "utf8_slovenian_ci", 1, 3},
+ {229, "utf8", "utf8_polish_ci", 1, 3},
+ {230, "utf8", "utf8_estonian_ci", 1, 3},
+ {231, "utf8", "utf8_spanish_ci", 1, 3},
+ {232, "utf8", "utf8_swedish_ci", 1, 3},
+ {233, "utf8", "utf8_turkish_ci", 1, 3},
+ {234, "utf8", "utf8_czech_ci", 1, 3},
+ {235, "utf8", "utf8_danish_ci", 1, 3},
+ {236, "utf8", "utf8_lithuanian_ci", 1, 3},
+ {237, "utf8", "utf8_slovak_ci", 1, 3},
+ {238, "utf8", "utf8_spanish2_ci", 1, 3},
+ {239, "utf8", "utf8_roman_ci", 1, 3},
+ {240, "utf8", "utf8_persian_ci", 1, 3},
+ {241, "utf8", "utf8_esperanto_ci", 1, 3},
+ {242, "utf8", "utf8_hungarian_ci", 1, 3},
+ {243, "utf8", "utf8_sinhala_ci", 1, 3},
+ {254, "utf8mb3", "utf8mb3_general_cs", 1, 3},
+ {0, NULL, NULL, 0, 0}
+};
+
+@implementation MCPResult
+
+/**
+ * Hold the results of a query to a MySQL database server. It correspond to the MYSQL_RES structure of the C API, and to the statement handle of the PERL DBI/DBD.
+ *
+ * Uses the !{mysql_store_result()} function from the C API.
+ *
+ * This object is generated only by a MCPConnection object, in this way (see #{MCPConnection} documentation):
+ *
+ * MCPConnection *theConnec = [MCPConnection alloc];
+ * MCPResult *theRes;
+ * NSDictionary *theDict;
+ * NSArray *theColNames;
+ * int i, j;
+ *
+ * theConnec = [theConnec initToHost:@"albert.com" withLogin:@"toto" password:@"albert" usingPort:0];
+ * [theConnec selectDB:@"db1"];
+ * theRes = [theConnec queryString:@"select * from table1"];
+ * theColNames = [theRes fetchFiedlsName];
+ * i = 0;
+ *
+ * while (theDict = [theRes fetchRowAsDictionary]) {
+ * NSLog(@"Row : %d\n", i);
+ * for (j=0; j<[theColNames count]; j++) {
+ * NSLog(@" Field : %@, contain : %@\n", [theColNames objectAtIndex:j], [theDict objectForKey:[theColNames objectAtIndex:j]]);
+ * }
+ * i++;
+ * }
+ */
+
+/**
+ * Initialize the class version to 3.0.1
+ */
++ (void)initialize
+{
+ if (self = [MCPResult class]) {
+ [self setVersion:030001]; // Ma.Mi.Re -> MaMiRe
+ MCPYear0000 = [[NSCalendarDate dateWithTimeIntervalSinceReferenceDate:-63146822400.0] retain];
+ [MCPYear0000 setCalendarFormat:@"%Y"];
+ }
+}
+
+#pragma mark -
+#pragma mark Initialisation
+
+/**
+ * Empty init, normaly of NO use to the user, again, MCPResult should be made through calls to MCPConnection
+ */
+- (id)init
+{
+ if ((self = [super init])) {
+ mEncoding = [MCPConnection defaultMySQLEncoding];
+
+ if (mResult) {
+ mysql_free_result(mResult);
+ mResult = NULL;
+ }
+
+ if (mNames) {
+ [mNames release];
+ mNames = NULL;
+ }
+
+ if (mMySQLLocales == NULL) {
+ mMySQLLocales = [[MCPConnection getMySQLLocales] retain];
+ }
+
+ mNumOfFields = 0;
+ }
+
+ return self;
+}
+
+/**
+ * Initialise a MCPResult, it is used internally by MCPConnection !{queryString:} method: the only proper
+ * way to get a running MCPResult object.
+ */
+- (id)initWithMySQLPtr:(MYSQL *)mySQLPtr encoding:(NSStringEncoding)iEncoding timeZone:(NSTimeZone *)iTimeZone
+{
+ if ((self = [super init])) {
+ mEncoding = iEncoding;
+ mTimeZone = [iTimeZone retain];
+
+ if (mResult) {
+ mysql_free_result(mResult);
+ mResult = NULL;
+ }
+
+ if (mNames) {
+ [mNames release];
+ mNames = NULL;
+ }
+
+ mResult = mysql_store_result(mySQLPtr);
+
+ if (mResult) {
+ mNumOfFields = mysql_num_fields(mResult);
+ }
+ else {
+ mNumOfFields = 0;
+ }
+
+ if (mMySQLLocales == NULL) {
+ mMySQLLocales = [[MCPConnection getMySQLLocales] retain];
+ }
+ }
+
+ return self;
+}
+
+/**
+ * This metod is used internally by MCPConnection object when it have already a MYSQL_RES object to initialise
+ * MCPResult object. Initialise a MCPResult with the MYSQL_RES pointer (returned by such a function as mysql_list_dbs).
+ * NB: MCPResult should be made by using one of the method of MCPConnection.
+ */
+- (id)initWithResPtr:(MYSQL_RES *)mySQLResPtr encoding:(NSStringEncoding)iEncoding timeZone:(NSTimeZone *)iTimeZone
+{
+ if ((self = [super init])) {
+ mEncoding = iEncoding;
+ mTimeZone = [iTimeZone retain];
+
+ if (mResult) {
+ mysql_free_result(mResult);
+ mResult = NULL;
+ }
+
+ if (mNames) {
+ [mNames release];
+ mNames = NULL;
+ }
+
+ mResult = mySQLResPtr;
+
+ if (mResult) {
+ mNumOfFields = mysql_num_fields(mResult);
+ }
+ else {
+ mNumOfFields = 0;
+ }
+
+ if (mMySQLLocales == NULL) {
+ mMySQLLocales = [[MCPConnection getMySQLLocales] retain];
+ }
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Result info
+
+/**
+ * Return the number of rows selected by the query.
+ */
+- (my_ulonglong)numOfRows
+{
+ if (mResult) {
+ return mysql_num_rows(mResult);
+ }
+
+ return 0;
+}
+
+/**
+ * Return the number of fields selected by the query. As a side effect it forces an update of the number of fields.
+ */
+- (unsigned int)numOfFields
+{
+ if (mResult) {
+ return mNumOfFields = mysql_num_fields(mResult);
+ }
+
+ return mNumOfFields = 0;
+}
+
+#pragma mark -
+#pragma mark Rows
+
+/**
+ * Go to a precise row in the selected result. 0 is the very first row.
+ */
+- (void)dataSeek:(my_ulonglong)row
+{
+ my_ulonglong theRow = (row < 0)? 0 : row;
+ theRow = (theRow < [self numOfRows]) ? theRow : ([self numOfRows] - 1);
+ mysql_data_seek(mResult,theRow);
+}
+
+/**
+ *
+ */
+- (id)fetchRowAsType:(MCPReturnType)aType
+{
+ MYSQL_ROW theRow;
+ unsigned long *theLengths;
+ MYSQL_FIELD *theField;
+ int i;
+ id theReturn;
+
+ if (mResult == NULL) {
+ // If there is no results, returns nil, as after the last row...
+ return nil;
+ }
+
+ theRow = mysql_fetch_row(mResult);
+
+ if (theRow == NULL) {
+ return nil;
+ }
+
+ switch (aType) {
+ case MCPTypeArray:
+ theReturn = [NSMutableArray arrayWithCapacity:mNumOfFields];
+ break;
+ case MCPTypeDictionary:
+ if (mNames == nil) {
+ [self fetchFieldNames];
+ }
+ theReturn = [NSMutableDictionary dictionaryWithCapacity:mNumOfFields];
+ break;
+ default :
+ NSLog (@"Unknown type : %d, will return an Array!\n", aType);
+ theReturn = [NSMutableArray arrayWithCapacity:mNumOfFields];
+ break;
+ }
+
+ theLengths = mysql_fetch_lengths(mResult);
+ theField = mysql_fetch_fields(mResult);
+
+ for (i=0; i<mNumOfFields; i++) {
+ id theCurrentObj;
+
+ if (theRow[i] == NULL) {
+ theCurrentObj = [NSNull null];
+ } else {
+ char *theData = calloc(sizeof(char),theLengths[i]+1);
+ //char *theUselLess;
+ memcpy(theData, theRow[i],theLengths[i]);
+ theData[theLengths[i]] = '\0';
+
+ switch (theField[i].type) {
+ case FIELD_TYPE_TINY:
+ case FIELD_TYPE_SHORT:
+ case FIELD_TYPE_INT24:
+ case FIELD_TYPE_LONG:
+ case FIELD_TYPE_LONGLONG:
+ case FIELD_TYPE_DECIMAL:
+ case FIELD_TYPE_NEWDECIMAL:
+ case FIELD_TYPE_FLOAT:
+ case FIELD_TYPE_DOUBLE:
+ case FIELD_TYPE_TIMESTAMP:
+ case FIELD_TYPE_DATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_YEAR:
+ case FIELD_TYPE_VAR_STRING:
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_SET:
+ case FIELD_TYPE_ENUM:
+ case FIELD_TYPE_NEWDATE: // Don't know what the format for this type is...
+ theCurrentObj = [self stringWithCString:theData];
+ break;
+
+ case FIELD_TYPE_BIT:
+ theCurrentObj = [NSString stringWithFormat:@"%u", theData[0]];
+ break;
+
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ theCurrentObj = [NSData dataWithBytes:theData length:theLengths[i]];
+ if (!(theField[i].flags & BINARY_FLAG)) { // It is TEXT and NOT BLOB...
+ theCurrentObj = [self stringWithText:theCurrentObj];
+ } // #warning Should check for TEXT (using theField[i].flag BINARY_FLAG)
+ break;
+
+ case FIELD_TYPE_NULL:
+ theCurrentObj = [NSNull null];
+ break;
+
+ default:
+ NSLog (@"in fetchRowAsType : Unknown type : %d for column %d, send back a NSData object", (int)theField[i].type, (int)i);
+ theCurrentObj = [NSData dataWithBytes:theData length:theLengths[i]];
+ break;
+ }
+
+ free(theData);
+
+ // Some of the creators return nil object...
+ if (theCurrentObj == nil) {
+ theCurrentObj = [NSNull null];
+ }
+ }
+
+ switch (aType) {
+ case MCPTypeDictionary :
+ [theReturn setObject:theCurrentObj forKey:[mNames objectAtIndex:i]];
+ break;
+
+ case MCPTypeArray :
+ default :
+ [theReturn addObject:theCurrentObj];
+ break;
+ }
+ }
+
+ return theReturn;
+}
+
+/**
+ * Return the next row of the result as an array, the index in select field order, the object a proper object
+ * for handling the information in the field (NSString, NSNumber ...).
+ *
+ * Just a #{typed} wrapper for method !{fetchRosAsType:} (with arg MCPTypeArray).
+ *
+ * NB: Returned object is immutable.
+ */
+- (NSArray *)fetchRowAsArray
+{
+ NSMutableArray *theArray = [self fetchRowAsType:MCPTypeArray];
+
+ return (theArray) ? [NSArray arrayWithArray:theArray] : nil;
+}
+
+/**
+ * Return the next row of the result as a dictionary, the key being the field name, the object a proper object
+ * for handling the information in the field (NSString, NSNumber ...).
+ *
+ * Just a #{typed} wrapper for method !{fetchRosAsType:} (with arg MCPTypeDictionary).
+ *
+ * NB: Returned object is immutable.
+ */
+- (NSDictionary *)fetchRowAsDictionary
+{
+ NSMutableDictionary *theDict = [self fetchRowAsType:MCPTypeDictionary];
+
+ return (theDict) ? [NSDictionary dictionaryWithDictionary:theDict] : nil;
+}
+
+#pragma mark -
+#pragma mark Columns
+
+/**
+ * Generate the mNames if not already generated, and return it.
+ *
+ * mNames is a NSArray holding the names of the fields(columns) of the results.
+ */
+- (NSArray *)fetchFieldNames
+{
+ int i;
+ unsigned int theNumFields;
+ NSMutableArray *theNamesArray;
+ MYSQL_FIELD *theField;
+
+ if (mNames) {
+ return mNames;
+ }
+
+ if (mResult == NULL) {
+ // If no results, give an empty array. Maybe it's better to give a nil pointer?
+ return (mNames = [[NSArray array] retain]);
+ }
+
+ theNumFields = [self numOfFields];
+ theNamesArray = [NSMutableArray arrayWithCapacity: theNumFields];
+ theField = mysql_fetch_fields(mResult);
+
+ for (i=0; i<theNumFields; i++) {
+ NSString *theName = [self stringWithCString:theField[i].name];
+ if ((theName) && (![theName isEqualToString:@""])) {
+ [theNamesArray addObject:theName];
+ }
+ else {
+ [theNamesArray addObject:[NSString stringWithFormat:@"Column %d", i]];
+ }
+ }
+
+ return (mNames = [[NSArray arrayWithArray:theNamesArray] retain]);
+}
+
+/**
+ * Return a collection of the fields's type. The type of collection is choosen by the aType variable
+ * (MCPTypeArray or MCPTypeDictionary).
+ *
+ * This method returned directly the #{mutable} object generated while going through all the columns
+ */
+- (id)fetchTypesAsType:(MCPReturnType)aType
+{
+ int i;
+ id theTypes;
+ MYSQL_FIELD *theField;
+
+ if (mResult == NULL) {
+ // If no results, give an empty array. Maybe it's better to give a nil pointer?
+ return nil;
+ }
+
+ switch (aType) {
+ case MCPTypeArray:
+ theTypes = [NSMutableArray arrayWithCapacity:mNumOfFields];
+ break;
+ case MCPTypeDictionary:
+ if (mNames == nil) {
+ [self fetchFieldNames];
+ }
+ theTypes = [NSMutableDictionary dictionaryWithCapacity:mNumOfFields];
+ break;
+ default :
+ NSLog (@"Unknown type : %d, will return an Array!\n", aType);
+ theTypes = [NSMutableArray arrayWithCapacity:mNumOfFields];
+ break;
+ }
+
+ theField = mysql_fetch_fields(mResult);
+
+ for (i=0; i<mNumOfFields; i++) {
+ NSString *theType;
+ switch (theField[i].type) {
+ case FIELD_TYPE_TINY:
+ theType = @"tiny";
+ break;
+ case FIELD_TYPE_SHORT:
+ theType = @"short";
+ break;
+ case FIELD_TYPE_LONG:
+ theType = @"long";
+ break;
+ case FIELD_TYPE_INT24:
+ theType = @"int24";
+ break;
+ case FIELD_TYPE_LONGLONG:
+ theType = @"longlong";
+ break;
+ case FIELD_TYPE_DECIMAL:
+ theType = @"decimal";
+ break;
+ case FIELD_TYPE_FLOAT:
+ theType = @"float";
+ break;
+ case FIELD_TYPE_DOUBLE:
+ theType = @"double";
+ break;
+ case FIELD_TYPE_TIMESTAMP:
+ theType = @"timestamp";
+ break;
+ case FIELD_TYPE_DATE:
+ theType = @"date";
+ break;
+ case FIELD_TYPE_TIME:
+ theType = @"time";
+ break;
+ case FIELD_TYPE_DATETIME:
+ theType = @"datetime";
+ break;
+ case FIELD_TYPE_YEAR:
+ theType = @"year";
+ break;
+ case FIELD_TYPE_VAR_STRING:
+ theType = @"varstring";
+ break;
+ case FIELD_TYPE_STRING:
+ theType = @"string";
+ break;
+ case FIELD_TYPE_TINY_BLOB:
+ theType = @"tinyblob";
+ break;
+ case FIELD_TYPE_BLOB:
+ theType = @"blob";
+ break;
+ case FIELD_TYPE_MEDIUM_BLOB:
+ theType = @"mediumblob";
+ break;
+ case FIELD_TYPE_LONG_BLOB:
+ theType = @"longblob";
+ break;
+ case FIELD_TYPE_SET:
+ theType = @"set";
+ break;
+ case FIELD_TYPE_ENUM:
+ theType = @"enum";
+ break;
+ case FIELD_TYPE_NULL:
+ theType = @"null";
+ break;
+ case FIELD_TYPE_NEWDATE:
+ theType = @"newdate";
+ break;
+ default:
+ theType = @"unknown";
+ NSLog (@"in fetchTypesAsArray : Unknown type for column %d of the MCPResult, type = %d", (int)i, (int)theField[i].type);
+ break;
+ }
+
+ switch (aType) {
+ case MCPTypeArray :
+ [theTypes addObject:theType];
+ break;
+ case MCPTypeDictionary :
+ [theTypes setObject:theType forKey:[mNames objectAtIndex:i]];
+ break;
+ default :
+ [theTypes addObject:theType];
+ break;
+ }
+ }
+
+ return theTypes;
+}
+
+/**
+ * Return an array of the fields' types.
+ *
+ * NB: Returned object is immutable.
+ */
+- (NSArray *)fetchTypesAsArray
+{
+ NSMutableArray *theArray = [self fetchTypesAsType:MCPTypeArray];
+
+ return (theArray) ? [NSArray arrayWithArray:theArray] : nil;
+}
+
+/**
+ * Return a dictionnary of the fields' types (keys are the fields' names).
+ *
+ * NB: Returned object is immutable.
+ */
+- (NSDictionary*) fetchTypesAsDictionary
+{
+ NSMutableDictionary *theDict = [self fetchTypesAsType:MCPTypeDictionary];
+
+ return (theDict) ? [NSDictionary dictionaryWithDictionary:theDict] : nil;
+}
+
+/**
+ * Return an array of dicts containg column data of the last executed query
+ */
+- (NSArray *)fetchResultFieldsStructure
+{
+ MYSQL_FIELD *theField;
+
+ NSMutableArray *structureResult = [NSMutableArray array];
+
+ unsigned int i;
+ unsigned int numFields = mysql_num_fields(mResult);
+
+ if (mResult == NULL) return nil;
+
+ theField = mysql_fetch_fields(mResult);
+
+ for (i=0; i < numFields; i++)
+ {
+ NSMutableDictionary *fieldStructure = [NSMutableDictionary dictionaryWithCapacity:39];
+
+ /* Original column position */
+ [fieldStructure setObject:[NSNumber numberWithInt:i] forKey:@"datacolumnindex"];
+
+ /* Name of column */
+ [fieldStructure setObject:[self stringWithCString:theField[i].name] forKey:@"name"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].name_length] forKey:@"name_length"];
+
+ /* Original column name, if an alias */
+ [fieldStructure setObject:[self stringWithCString:theField[i].org_name] forKey:@"org_name"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].org_name_length] forKey:@"org_name_length"];
+
+ /* Table of column if column was a field */
+ [fieldStructure setObject:[self stringWithCString:theField[i].table] forKey:@"table"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].table_length] forKey:@"table_length"];
+
+ /* Org table name, if table was an alias */
+ [fieldStructure setObject:[self stringWithCString:theField[i].org_table] forKey:@"org_table"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].org_table_length] forKey:@"org_table_length"];
+
+ /* Database for table */
+ [fieldStructure setObject:[self stringWithCString:theField[i].db] forKey:@"db"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].db_length] forKey:@"db_length"];
+
+ /* Catalog for table */
+ // [fieldStructure setObject:[self stringWithCString:theField[i].catalog] forKey:@"catalog"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].catalog_length] forKey:@"catalog_length"];
+
+ /* Default value (set by mysql_list_fields) */
+ // [fieldStructure setObject:[self stringWithCString:theField[i].def] forKey:@"def"];
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].def_length] forKey:@"def_length"];
+
+ /* Width of column (real length in bytes) */
+ [fieldStructure setObject:[NSNumber numberWithUnsignedLongLong:theField[i].length] forKey:@"byte_length"];
+ /* Width of column (as in create)*/
+ [fieldStructure setObject:[NSNumber numberWithUnsignedLongLong:theField[i].length/[self findCharsetMaxByteLengthPerChar:theField[i].charsetnr]]
+ forKey:@"char_length"];
+ /* Max width (bytes) for selected set */
+ [fieldStructure setObject:[NSNumber numberWithUnsignedLongLong:theField[i].max_length] forKey:@"max_byte_length"];
+ /* Max width (chars) for selected set */
+ // [fieldStructure setObject:[NSNumber numberWithUnsignedLongLong:theField[i].max_length/[self find_charsetMaxByteLengthPerChar:theField[i].charsetnr]]
+ // forKey:@"max_char_length"];
+
+ /* Div flags */
+ [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].flags] forKey:@"flags"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & NOT_NULL_FLAG) ? YES : NO] forKey:@"null"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & PRI_KEY_FLAG) ? YES : NO] forKey:@"PRI_KEY_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & UNIQUE_KEY_FLAG) ? YES : NO] forKey:@"UNIQUE_KEY_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & MULTIPLE_KEY_FLAG) ? YES : NO] forKey:@"MULTIPLE_KEY_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & BLOB_FLAG) ? YES : NO] forKey:@"BLOB_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & UNSIGNED_FLAG) ? YES : NO] forKey:@"UNSIGNED_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & ZEROFILL_FLAG) ? YES : NO] forKey:@"ZEROFILL_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & BINARY_FLAG) ? YES : NO] forKey:@"BINARY_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & ENUM_FLAG) ? YES : NO] forKey:@"ENUM_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & AUTO_INCREMENT_FLAG) ? YES : NO] forKey:@"AUTO_INCREMENT_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & SET_FLAG) ? YES : NO] forKey:@"SET_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & NUM_FLAG) ? YES : NO] forKey:@"NUM_FLAG"];
+ [fieldStructure setObject:[NSNumber numberWithBool:(theField[i].flags & PART_KEY_FLAG) ? YES : NO] forKey:@"PART_KEY_FLAG"];
+ // [fieldStructure setObject:[NSNumber numberWithInt:(theField[i].flags & GROUP_FLAG) ? 1 : 0] forKey:@"GROUP_FLAG"];
+ // [fieldStructure setObject:[NSNumber numberWithInt:(theField[i].flags & UNIQUE_FLAG) ? 1 : 0] forKey:@"UNIQUE_FLAG"];
+ // [fieldStructure setObject:[NSNumber numberWithInt:(theField[i].flags & BINCMP_FLAG) ? 1 : 0] forKey:@"BINCMP_FLAG"];
+
+ /* Number of decimals in field */
+ [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].decimals] forKey:@"decimals"];
+
+ /* Character set */
+ [fieldStructure setObject:[NSNumber numberWithUnsignedInt:theField[i].charsetnr] forKey:@"charsetnr"];
+ [fieldStructure setObject:[self findCharsetName:theField[i].charsetnr] forKey:@"charset_name"];
+ [fieldStructure setObject:[self findCharsetCollation:theField[i].charsetnr] forKey:@"charset_collation"];
+
+ /* Table type */
+ [fieldStructure setObject:[self mysqlTypeToStringForType:theField[i].type
+ withCharsetNr:theField[i].charsetnr
+ withFlags:theField[i].flags
+ withLength:theField[i].length
+ ] forKey:@"type"];
+
+ /* Table type group*/
+ [fieldStructure setObject:[self mysqlTypeToGroupForType:theField[i].type
+ withCharsetNr:theField[i].charsetnr
+ withFlags:theField[i].flags
+ ] forKey:@"typegrouping"];
+
+ [structureResult addObject:fieldStructure];
+
+ }
+
+ return structureResult;
+
+}
+
+/**
+ * Return the MySQL flags of the column at the given index... Can be used to check if a number is signed or not...
+ */
+- (unsigned int)fetchFlagsAtIndex:(unsigned int)index
+{
+ unsigned int theRet;
+ unsigned int theNumFields;
+ MYSQL_FIELD *theField;
+
+ if (mResult == NULL) {
+ // If no results, give an empty array. Maybe it's better to give a nil pointer?
+ return (0);
+ }
+
+ theNumFields = [self numOfFields];
+ theField = mysql_fetch_fields(mResult);
+
+ if (index >= theNumFields) {
+ // Out of range... should raise an exception
+ theRet = 0;
+ }
+ else {
+ theRet = theField[index].flags;
+ }
+
+ return theRet;
+}
+
+/**
+ *
+ */
+- (unsigned int)fetchFlagsForKey:(NSString *)key
+{
+ unsigned int theRet;
+ unsigned int theNumFields, index;
+ MYSQL_FIELD *theField;
+
+ if (mResult == NULL) {
+ // If no results, give an empty array. Maybe it's better to give a nil pointer?
+ return (0);
+ }
+
+ if (mNames == NULL) {
+ [self fetchFieldNames];
+ }
+
+ theNumFields = [self numOfFields];
+ theField = mysql_fetch_fields(mResult);
+
+ if ([mNames indexOfObject:key] == NSNotFound) {
+ // Non existent key... should raise an exception
+ theRet = 0;
+ }
+ else {
+ index = [mNames indexOfObject:key];
+
+ theRet = theField[index].flags;
+ }
+
+ return theRet;
+}
+
+/**
+ * Return YES if the field with the given index is a BLOB. It should be used to discriminates between BLOBs
+ * and TEXTs.
+ *
+ * #{DEPRECATED}, This method is not consistent with the C API which is supposed to return YES for BOTH
+ * text and blob (and BTW is also deprecated)...
+ *
+ * #{NOTE} That the current version handles properly TEXT, and returns those as NSString (and not NSData as
+ * it used to be).
+ */
+- (BOOL)isBlobAtIndex:(unsigned int)index
+{
+ BOOL theRet;
+ unsigned int theNumFields;
+ MYSQL_FIELD *theField;
+
+ if (mResult == NULL) {
+ // If no results, give an empty array. Maybe it's better to give a nil pointer?
+ return (NO);
+ }
+
+ theNumFields = [self numOfFields];
+ theField = mysql_fetch_fields(mResult);
+
+ if (index >= theNumFields) {
+ // Out of range... should raise an exception
+ theRet = NO;
+ }
+ else {
+ switch(theField[index].type) {
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ theRet = (theField[index].flags & BINARY_FLAG);
+ break;
+ default:
+ theRet = NO;
+ break;
+ }
+ }
+
+ return theRet;
+}
+
+/**
+ * Return YES if the field (by name) with the given index is a BLOB. It should be used to discriminates
+ * between BLOBs and TEXTs.
+ *
+ * #{DEPRECATED}, This method is not consistent with the C API which is supposed to return YES for BOTH
+ * text and blob (and BTW is also deprecated)...
+ *
+ * #{NOTE} That the current version handles properly TEXT, and returns those as NSString (and not NSData
+ * as it used to be).
+ */
+- (BOOL)isBlobForKey:(NSString *)key
+{
+ BOOL theRet;
+ unsigned int theNumFields, index;
+ MYSQL_FIELD *theField;
+
+ if (mResult == NULL) {
+ // If no results, give an empty array. Maybe it's better to give a nil pointer?
+ return (NO);
+ }
+
+ if (mNames == NULL) {
+ [self fetchFieldNames];
+ }
+
+ theNumFields = [self numOfFields];
+ theField = mysql_fetch_fields(mResult);
+
+ if ([mNames indexOfObject:key] == NSNotFound) {
+ // Non existent key... should raise an exception
+ theRet = NO;
+ }
+ else {
+ index = [mNames indexOfObject:key];
+
+ switch(theField[index].type) {
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ theRet = (theField[index].flags & BINARY_FLAG);
+ break;
+ default:
+ theRet = NO;
+ break;
+ }
+ }
+
+ return theRet;
+}
+
+#pragma mark -
+#pragma mark Conversion
+
+/**
+ * Use the string encoding to convert the returned NSData to a string (for a TEXT field).
+ */
+- (NSString *)stringWithText:(NSData *)theTextData
+{
+ NSString *theString;
+
+ if (theTextData == nil) {
+ return nil;
+ }
+
+ theString = [[NSString alloc] initWithData:theTextData encoding:mEncoding];
+
+ if (theString) {
+ [theString autorelease];
+ }
+
+ return theString;
+}
+
+/**
+ * Return a (long) string containing the table of results, first line being the fields name, next line(s)
+ * the row(s). Useful to have NSLog logging a MCPResult (example).
+ */
+- (NSString *)description
+{
+ if (mResult == NULL) {
+ return @"This is an empty MCPResult\n";
+ }
+ else {
+ NSMutableString *theString = [NSMutableString stringWithCapacity:0];
+ int i;
+ NSArray *theRow;
+ MYSQL_ROW_OFFSET thePosition;
+ BOOL trunc = [MCPConnection truncateLongField];
+
+ // First line, saying we are displaying a MCPResult
+ [theString appendFormat:@"MCPResult: (encoding : %d, dim %d x %d)\n", (long)mEncoding, (long)mNumOfFields, (long)[self numOfRows]];
+ // Second line: the field names, tab separated
+ [self fetchFieldNames];
+
+ for (i=0; i<(mNumOfFields-1); i++) {
+ [theString appendFormat:@"%@\t", [mNames objectAtIndex:i]];
+ }
+
+ [theString appendFormat:@"%@\n", [mNames objectAtIndex:i]];
+ // Next lines, the records (saving current position to put it back after the full display)
+ thePosition = mysql_row_tell(mResult);
+ [self dataSeek:0];
+
+ while (theRow = [self fetchRowAsArray])
+ {
+ id theField = [theRow objectAtIndex:i];
+
+ if (trunc) {
+ if (([theField isKindOfClass:[NSString class]]) && (kLengthOfTruncationForLog < [(NSString *)theField length])) {
+ theField = [theField substringToIndex:kLengthOfTruncationForLog];
+ }
+ else if (([theField isKindOfClass:[NSData class]]) && (kLengthOfTruncationForLog < [(NSData *)theField length])) {
+ theField = [NSData dataWithBytes:[theField bytes] length:kLengthOfTruncationForLog];
+ }
+ }
+
+ for (i=0; i<(mNumOfFields - 1); i++)
+ {
+ [theString appendFormat:@"%@\t", theField];
+ }
+
+ [theString appendFormat:@"%@\n", theField];
+ }
+
+ // Returning to the proper row
+ mysql_row_seek(mResult, thePosition);
+
+ return theString;
+ }
+}
+
+/**
+ * For internal use only. Transform a NSString to a C type string (ended with \0) using ethe character set
+ * from the MCPConnection. Lossy conversions are enabled.
+ */
+- (const char *)cStringFromString:(NSString *)theString
+{
+ NSMutableData *theData;
+
+ if (!theString) {
+ return (const char *)NULL;
+ }
+
+ theData = [NSMutableData dataWithData:[theString dataUsingEncoding:mEncoding allowLossyConversion:YES]];
+ [theData increaseLengthBy:1];
+
+ return (const char *)[theData bytes];
+}
+
+/**
+ * Return a NSString from a C style string encoded with the character set of theMCPConnection.
+ */
+- (NSString *)stringWithCString:(const char *)theCString
+{
+ NSData *theData;
+ NSString *theString;
+
+ if (theCString == NULL) {
+ return @"";
+ }
+
+ theData = [NSData dataWithBytes:theCString length:(strlen(theCString))];
+ theString = [[NSString alloc] initWithData:theData encoding:mEncoding];
+
+ if (theString) {
+ [theString autorelease];
+ }
+
+ return theString;
+}
+
+#pragma mark -
+#pragma mark Other
+
+/**
+ * Convert a mysql_type to a string
+ */
+- (NSString *)mysqlTypeToStringForType:(unsigned int)type withCharsetNr:(unsigned int)charsetnr withFlags:(unsigned int)flags withLength:(unsigned long long)length
+{
+ // BOOL isUnsigned = (flags & UNSIGNED_FLAG) != 0;
+ // BOOL isZerofill = (flags & ZEROFILL_FLAG) != 0;
+
+ switch (type) {
+ case FIELD_TYPE_BIT:
+ return @"BIT";
+ case MYSQL_TYPE_DECIMAL:
+ //return isUnsigned ? (isZerofill? @"DECIMAL UNSIGNED ZEROFILL" : @"DECIMAL UNSIGNED"):
+ return @"DECIMAL";
+ case MYSQL_TYPE_TINY:
+ // return isUnsigned ? (isZerofill? @"TINYINT UNSIGNED ZEROFILL" : @"TINYINT UNSIGNED"):
+ return @"TINYINT";
+ case MYSQL_TYPE_SHORT:
+ // return isUnsigned ? (isZerofill? @"SMALLINT UNSIGNED ZEROFILL" : @"SMALLINT UNSIGNED"):
+ return @"SMALLINT";
+ case MYSQL_TYPE_LONG:
+ // return isUnsigned ? (isZerofill? @"INT UNSIGNED ZEROFILL" : @"INT UNSIGNED"):
+ return @"INT";
+ case MYSQL_TYPE_FLOAT:
+ // return isUnsigned ? (isZerofill? @"FLOAT UNSIGNED ZEROFILL" : @"FLOAT UNSIGNED"):
+ return @"FLOAT";
+ case MYSQL_TYPE_DOUBLE:
+ // return isUnsigned ? (isZerofill? @"DOUBLE UNSIGNED ZEROFILL" : @"DOUBLE UNSIGNED"):
+ return @"DOUBLE";
+ case MYSQL_TYPE_NULL:
+ return @"NULL";
+ case MYSQL_TYPE_TIMESTAMP:
+ return @"TIMESTAMP";
+ case MYSQL_TYPE_LONGLONG:
+ // return isUnsigned ? (isZerofill? @"BIGINT UNSIGNED ZEROFILL" : @"BIGINT UNSIGNED") :
+ return @"BIGINT";
+ case MYSQL_TYPE_INT24:
+ // return isUnsigned ? (isZerofill? @"MEDIUMINT UNSIGNED ZEROFILL" : @"MEDIUMINT UNSIGNED") :
+ return @"MEDIUMINT";
+ case MYSQL_TYPE_DATE:
+ return @"DATE";
+ case MYSQL_TYPE_TIME:
+ return @"TIME";
+ case MYSQL_TYPE_DATETIME:
+ return @"DATETIME";
+ case MYSQL_TYPE_TINY_BLOB:// should no appear over the wire
+ case MYSQL_TYPE_MEDIUM_BLOB:// should no appear over the wire
+ case MYSQL_TYPE_LONG_BLOB:// should no appear over the wire
+ case MYSQL_TYPE_BLOB:
+ {
+ BOOL isBlob = (charsetnr == MAGIC_BINARY_CHARSET_NR);
+ switch ((int)length/[self findCharsetMaxByteLengthPerChar:charsetnr]) {
+ case 255: return isBlob? @"TINYBLOB":@"TINYTEXT";
+ case 65535: return isBlob? @"BLOB":@"TEXT";
+ case 16777215: return isBlob? @"MEDIUMBLOB":@"MEDIUMTEXT";
+ case 4294967295: return isBlob? @"LONGBLOB":@"LONGTEXT";
+ default:
+ switch (length) {
+ case 255: return isBlob? @"TINYBLOB":@"TINYTEXT";
+ case 65535: return isBlob? @"BLOB":@"TEXT";
+ case 16777215: return isBlob? @"MEDIUMBLOB":@"MEDIUMTEXT";
+ case 4294967295: return isBlob? @"LONGBLOB":@"LONGTEXT";
+ default:
+ return @"UNKNOWN";
+ }
+ }
+ }
+ case MYSQL_TYPE_VAR_STRING:
+ if (flags & ENUM_FLAG) {
+ return @"ENUM";
+ }
+ if (flags & SET_FLAG) {
+ return @"SET";
+ }
+ if (charsetnr == MAGIC_BINARY_CHARSET_NR) {
+ return @"VARBINARY";
+ }
+ return @"VARCHAR";
+ case MYSQL_TYPE_STRING:
+ if (flags & ENUM_FLAG) {
+ return @"ENUM";
+ }
+ if (flags & SET_FLAG) {
+ return @"SET";
+ }
+ if ((flags & BINARY_FLAG) && charsetnr == MAGIC_BINARY_CHARSET_NR) {
+ return @"BINARY";
+ }
+ return @"CHAR";
+ case MYSQL_TYPE_ENUM:
+ /* This should never happen */
+ return @"ENUM";
+ case MYSQL_TYPE_YEAR:
+ return @"YEAR";
+ case MYSQL_TYPE_SET:
+ /* This should never happen */
+ return @"SET";
+ case MYSQL_TYPE_GEOMETRY:
+ return @"GEOMETRY";
+ default:
+ return @"UNKNOWN";
+ }
+}
+
+/**
+ * Merge mysql_types into type groups
+ */
+- (NSString *)mysqlTypeToGroupForType:(unsigned int)type withCharsetNr:(unsigned int)charsetnr withFlags:(unsigned int)flags
+{
+ switch(type){
+ case FIELD_TYPE_BIT:
+ return @"bit";
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ return @"integer";
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_DECIMAL:
+ return @"float";
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIMESTAMP:
+ return @"date";
+ case MYSQL_TYPE_VAR_STRING:
+ if (flags & ENUM_FLAG) {
+ return @"enum";
+ }
+ if (flags & SET_FLAG) {
+ return @"enum";
+ }
+ if (charsetnr == MAGIC_BINARY_CHARSET_NR) {
+ return @"binary";
+ }
+ return @"string";
+ case MYSQL_TYPE_STRING:
+ if (flags & ENUM_FLAG) {
+ return @"enum";
+ }
+ if (flags & SET_FLAG) {
+ return @"enum";
+ }
+ if ((flags & BINARY_FLAG) && charsetnr == MAGIC_BINARY_CHARSET_NR) {
+ return @"binary";
+ }
+ return @"string";
+ case MYSQL_TYPE_TINY_BLOB: // should no appear over the wire
+ case MYSQL_TYPE_MEDIUM_BLOB: // should no appear over the wire
+ case MYSQL_TYPE_LONG_BLOB: // should no appear over the wire
+ case MYSQL_TYPE_BLOB:
+ {
+ if (charsetnr == MAGIC_BINARY_CHARSET_NR) {
+ return @"blobdata";
+ } else {
+ return @"textdata";
+ }
+ }
+ case MYSQL_TYPE_GEOMETRY:
+ return @"geometry";
+ default:
+ return @"blobdata";
+
+ }
+}
+
+/**
+ * Convert a mysql_charsetnr into a charset name as string
+ */
+- (NSString *)findCharsetName:(unsigned int)charsetnr
+{
+ const OUR_CHARSET * c = our_charsets60;
+
+ do {
+ if (c->nr == charsetnr)
+ return [self stringWithCString:c->name];
+ ++c;
+ } while (c[0].nr != 0);
+
+ return @"UNKNOWN";
+}
+
+/**
+ * Convert a mysql_charsetnr into a collation name as string
+ */
+- (NSString *)findCharsetCollation:(unsigned int)charsetnr
+{
+ const OUR_CHARSET * c = our_charsets60;
+
+ do {
+ if (c->nr == charsetnr)
+ return [self stringWithCString:c->collation];
+ ++c;
+ } while (c[0].nr != 0);
+
+ return @"UNKNOWN";
+}
+
+/**
+ * Return the max byte length to store a char by using
+ * a specific mysql_charsetnr
+ */
+- (unsigned int)findCharsetMaxByteLengthPerChar:(unsigned int)charsetnr
+{
+ const OUR_CHARSET * c = our_charsets60;
+
+ do {
+ if (c->nr == charsetnr)
+ return c->char_maxlen;
+ ++c;
+ } while (c[0].nr != 0);
+
+ return 1;
+}
+
+#pragma mark -
+
+/**
+ * Do one really needs an explanation for this method? Which by the way you should not use...
+ */
+- (void) dealloc
+{
+ if (mResult) {
+ mysql_free_result(mResult);
+ }
+
+ if (mNames) {
+ [mNames autorelease];
+ }
+
+ if (mMySQLLocales) {
+ [mMySQLLocales autorelease];
+ }
+
+ [super dealloc];
+}
+
+@end