mirror of
https://github.com/gnustep/libs-sqlclient.git
synced 2025-02-15 08:01:33 +00:00
Close to basic functionality in jdbc
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@23325 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
563e93f83e
commit
37111f260d
1 changed files with 349 additions and 461 deletions
810
JDBC.m
810
JDBC.m
|
@ -566,21 +566,29 @@ static void JException (JNIEnv *env)
|
|||
@interface SQLClientJDBC : SQLClient
|
||||
@end
|
||||
|
||||
@interface SQLClientJDBC(Embedded)
|
||||
- (NSData*) dataFromBLOB: (const char *)blob;
|
||||
- (NSDate*) dbToDateFromBuffer: (char*)b length: (int)l;
|
||||
@end
|
||||
|
||||
static NSDate *future = nil;
|
||||
static NSNull *null = nil;
|
||||
|
||||
|
||||
@implementation SQLClientJDBC
|
||||
|
||||
static int JDBCDATE = 0;
|
||||
static int JDBCTIME = 0;
|
||||
static int JDBCTIMESTAMP = 0;
|
||||
static int JDBCBOOLEAN = 0;
|
||||
static int JDBCBLOB = 0;
|
||||
static int JDBCBINARY = 0;
|
||||
static int JDBCVARBINARY = 0;
|
||||
static int JDBCLONGVARBINARY = 0;
|
||||
static int JDBCVARCHAR = 0;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (future == nil)
|
||||
{
|
||||
JNIEnv *env;
|
||||
jclass jc;
|
||||
jfieldID jf;
|
||||
|
||||
future = [NSCalendarDate dateWithString: @"9999-01-01 00:00:00 +0000"
|
||||
calendarFormat: @"%Y-%m-%d %H:%M:%S %z"
|
||||
locale: nil];
|
||||
|
@ -589,6 +597,55 @@ static NSNull *null = nil;
|
|||
RETAIN(null);
|
||||
|
||||
[SQLClientJVM startVirtualMachineWithClassPath: nil libraryPath: nil];
|
||||
env = SQLClientJNIEnv();
|
||||
jc = (*env)->FindClass(env, "java/sql/Types");
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "DATE", "I");
|
||||
JException (env);
|
||||
JDBCDATE = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "TIME", "I");
|
||||
JException (env);
|
||||
JDBCTIME = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "TIMESTAMP", "I");
|
||||
JException (env);
|
||||
JDBCTIMESTAMP = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "BOOLEAN", "I");
|
||||
JException (env);
|
||||
JDBCBOOLEAN = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "BLOB", "I");
|
||||
JException (env);
|
||||
JDBCBLOB = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "BINARY", "I");
|
||||
JException (env);
|
||||
JDBCBINARY = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "VARBINARY", "I");
|
||||
JException (env);
|
||||
JDBCVARBINARY = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "LONGVARBINARY", "I");
|
||||
JException (env);
|
||||
JDBCLONGVARBINARY = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
jf = (*env)->GetStaticFieldID(env, jc, "VARCHAR", "I");
|
||||
JException (env);
|
||||
JDBCVARCHAR = (*env)->GetStaticIntField(env, jc, jf);
|
||||
JException (env);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -662,31 +719,6 @@ static NSNull *null = nil;
|
|||
return NO;
|
||||
}
|
||||
|
||||
#if 0
|
||||
jc = (*env)->FindClass(env, "java/lang/ClassLoader");
|
||||
JException (env);
|
||||
jm = (*env)->GetStaticMethodID(env, jc,
|
||||
"getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
JException (env);
|
||||
jo = (*env)->CallStaticObjectMethod(env, jc, jm);
|
||||
JException (env);
|
||||
jm = (*env)->GetMethodID(env, jc,
|
||||
"findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||
JException (env);
|
||||
jc = (*env)->CallObjectMethod (env, jo, jm,
|
||||
JStringFromNSString(env, cname));
|
||||
JExceptionClear (env);
|
||||
if (jc == 0)
|
||||
{
|
||||
jc = (*env)->CallObjectMethod (env, jo, jm,
|
||||
JStringFromNSString(env, cname));
|
||||
JException (env);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
/* Ensure the driver for the database is loaded.
|
||||
*/
|
||||
cname = [cname stringByReplacingString: @"." withString: @"/"];
|
||||
|
@ -707,7 +739,6 @@ static NSNull *null = nil;
|
|||
return NO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get the driver manager class.
|
||||
*/
|
||||
|
@ -907,6 +938,7 @@ static NSNull *null = nil;
|
|||
[self name], stmt];
|
||||
}
|
||||
|
||||
NSLog(@"UPDATE (%@)", stmt);
|
||||
if ([info count] > 1)
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -944,7 +976,7 @@ static NSNull *null = nil;
|
|||
{
|
||||
// Not in a transaction ... commit at once.
|
||||
(*env)->CallVoidMethod (env, ji->connection, ji->commit);
|
||||
JExceptionClear (env);
|
||||
JException (env);
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
|
@ -969,36 +1001,12 @@ static NSNull *null = nil;
|
|||
DESTROY(arp);
|
||||
}
|
||||
|
||||
static unsigned int trim(char *str)
|
||||
{
|
||||
char *start = str;
|
||||
|
||||
while (isspace(*str))
|
||||
{
|
||||
str++;
|
||||
}
|
||||
if (str != start)
|
||||
{
|
||||
strcpy(start, str);
|
||||
}
|
||||
str = start;
|
||||
while (*str != '\0')
|
||||
{
|
||||
str++;
|
||||
}
|
||||
while (str > start && isspace(str[-1]))
|
||||
{
|
||||
*--str = '\0';
|
||||
}
|
||||
return (str - start);
|
||||
}
|
||||
|
||||
- (NSMutableArray*) backendQuery: (NSString*)stmt
|
||||
{
|
||||
NSMutableArray *records = nil;
|
||||
#if 0
|
||||
CREATE_AUTORELEASE_POOL(arp);
|
||||
PGresult *result = 0;
|
||||
JNIEnv *env = SQLClientJNIEnv();
|
||||
JInfo *ji = (JInfo*)extra;
|
||||
|
||||
if ([stmt length] == 0)
|
||||
{
|
||||
|
@ -1009,7 +1017,12 @@ static unsigned int trim(char *str)
|
|||
|
||||
NS_DURING
|
||||
{
|
||||
char *statement;
|
||||
int fieldCount;
|
||||
jclass resultClass;
|
||||
jobject result;
|
||||
jclass metaDataClass;
|
||||
jobject metaData;
|
||||
jmethodID jm;
|
||||
|
||||
/*
|
||||
* Ensure we have a working connection.
|
||||
|
@ -1021,45 +1034,114 @@ static unsigned int trim(char *str)
|
|||
[self name], stmt];
|
||||
}
|
||||
|
||||
statement = (char*)[stmt UTF8String];
|
||||
result = PQexec(extra, statement);
|
||||
if (result == 0 || PQresultStatus(result) == PGRES_FATAL_ERROR)
|
||||
{
|
||||
NSString *str;
|
||||
const char *cstr;
|
||||
result = (*env)->CallObjectMethod (env, ji->statement, ji->executeQuery,
|
||||
JStringFromNSString(env, stmt));
|
||||
JException (env);
|
||||
resultClass = (*env)->GetObjectClass(env, result);
|
||||
JException (env);
|
||||
jm = (*env)->GetMethodID (env, resultClass,
|
||||
"getMetaData", "()Ljava/sql/ResultSetMetaData;");
|
||||
JException (env);
|
||||
metaData = (*env)->CallObjectMethod (env, result, jm);
|
||||
JException (env);
|
||||
metaDataClass = (*env)->GetObjectClass(env, metaData);
|
||||
JException (env);
|
||||
jm = (*env)->GetMethodID (env, metaDataClass,
|
||||
"getColumnCount", "()I");
|
||||
JException (env);
|
||||
fieldCount = (*env)->CallIntMethod (env, metaData, jm);
|
||||
JException (env);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
cstr = PQerrorMessage(extra);
|
||||
}
|
||||
else
|
||||
{
|
||||
cstr = PQresultErrorMessage(result);
|
||||
}
|
||||
str = [NSString stringWithUTF8String: cstr];
|
||||
[self backendDisconnect];
|
||||
[NSException raise: SQLException format: @"%@", str];
|
||||
}
|
||||
if (PQresultStatus(result) == PGRES_TUPLES_OK)
|
||||
if (fieldCount > 0)
|
||||
{
|
||||
int recordCount = PQntuples(result);
|
||||
int fieldCount = PQnfields(result);
|
||||
NSString *keys[fieldCount];
|
||||
int types[fieldCount];
|
||||
int modifiers[fieldCount];
|
||||
int formats[fieldCount];
|
||||
int i;
|
||||
unsigned i;
|
||||
jmethodID next;
|
||||
jmethodID wasNull;
|
||||
jmethodID getBinaryStream;
|
||||
jmethodID getBoolean;
|
||||
jmethodID getBytes;
|
||||
jmethodID getString;
|
||||
jmethodID getTimestamp;
|
||||
|
||||
/* Get the names of each field
|
||||
*/
|
||||
jm = (*env)->GetMethodID (env, metaDataClass,
|
||||
"getColumnName", "(I)Ljava/lang/String;");
|
||||
JException (env);
|
||||
for (i = 0; i < fieldCount; i++)
|
||||
{
|
||||
keys[i] = [NSString stringWithUTF8String: PQfname(result, i)];
|
||||
types[i] = PQftype(result, i);
|
||||
modifiers[i] = PQfmod(result, i);
|
||||
formats[i] = PQfformat(result, i);
|
||||
jstring js = (*env)->CallObjectMethod (env, metaData, jm, i+1);
|
||||
|
||||
JException (env);
|
||||
keys[i] = NSStringFromJString (env, js);
|
||||
}
|
||||
|
||||
records = [[NSMutableArray alloc] initWithCapacity: recordCount];
|
||||
for (i = 0; i < recordCount; i++)
|
||||
/* Get the types of each field.
|
||||
* We treat most as strings.
|
||||
*/
|
||||
jm = (*env)->GetMethodID (env, metaDataClass,
|
||||
"getColumnType", "(I)I");
|
||||
JException (env);
|
||||
for (i = 0; i < fieldCount; i++)
|
||||
{
|
||||
int v = (*env)->CallIntMethod (env, metaData, jm, i+1);
|
||||
|
||||
NSLog(@"Field %d (%@) type %d", i, keys[i], v);
|
||||
if (v == JDBCDATE)
|
||||
{
|
||||
types[i] = JDBCDATE;
|
||||
}
|
||||
else if (v == JDBCTIME)
|
||||
{
|
||||
types[i] = JDBCTIME;
|
||||
}
|
||||
else if (v == JDBCTIMESTAMP)
|
||||
{
|
||||
types[i] = JDBCTIMESTAMP;
|
||||
}
|
||||
else if (v == JDBCBOOLEAN)
|
||||
{
|
||||
types[i] = JDBCBOOLEAN;
|
||||
}
|
||||
else if (v == JDBCBLOB || v == JDBCBINARY || v == JDBCVARBINARY
|
||||
|| v == JDBCLONGVARBINARY)
|
||||
{
|
||||
types[i] = JDBCBLOB;
|
||||
}
|
||||
else
|
||||
{
|
||||
types[i] = JDBCVARCHAR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate through the result set
|
||||
*/
|
||||
wasNull = (*env)->GetMethodID (env, resultClass,
|
||||
"wasNull", "()Z");
|
||||
JException (env);
|
||||
getBinaryStream = (*env)->GetMethodID (env, resultClass,
|
||||
"getBinaryStream", "(I)Ljava/io/InputStream;");
|
||||
JException (env);
|
||||
getBoolean = (*env)->GetMethodID (env, resultClass,
|
||||
"getBoolean", "(I)Z");
|
||||
JException (env);
|
||||
getBytes = (*env)->GetMethodID (env, resultClass,
|
||||
"getBytes", "(I)[B");
|
||||
JException (env);
|
||||
getTimestamp = (*env)->GetMethodID (env, resultClass,
|
||||
"getTimestamp", "(I)Ljava/sql/Timestamp;");
|
||||
JException (env);
|
||||
getString = (*env)->GetMethodID (env, resultClass,
|
||||
"getString", "(I)Ljava/lang/String;");
|
||||
JException (env);
|
||||
|
||||
next = (*env)->GetMethodID (env, resultClass,
|
||||
"next", "()Z");
|
||||
JException (env);
|
||||
records = [[NSMutableArray alloc] initWithCapacity: 100];
|
||||
while ((*env)->CallBooleanMethod (env, result, next) == JNI_TRUE)
|
||||
{
|
||||
SQLRecord *record;
|
||||
id values[fieldCount];
|
||||
|
@ -1067,57 +1149,108 @@ static unsigned int trim(char *str)
|
|||
|
||||
for (j = 0; j < fieldCount; j++)
|
||||
{
|
||||
id v = null;
|
||||
id v = null;
|
||||
|
||||
if (PQgetisnull(result, i, j) == 0)
|
||||
if (types[j] == JDBCBOOLEAN)
|
||||
{
|
||||
char *p = PQgetvalue(result, i, j);
|
||||
int size = PQgetlength(result, i, j);
|
||||
BOOL b = NO;
|
||||
|
||||
if ([self debugging] > 1)
|
||||
{
|
||||
[self debug: @"%@ type:%d mod:%d size: %d\n",
|
||||
keys[j], types[j], modifiers[j], size];
|
||||
}
|
||||
if (formats[j] == 0) // Text
|
||||
if ((*env)->CallBooleanMethod (env, result,
|
||||
getBoolean, j+1) == JNI_TRUE)
|
||||
{
|
||||
switch (types[j])
|
||||
b = YES;
|
||||
}
|
||||
JException (env);
|
||||
if ((*env)->CallBooleanMethod (env, result,
|
||||
wasNull) == JNI_FALSE)
|
||||
{
|
||||
if (b == YES)
|
||||
{
|
||||
case 1082: // Date
|
||||
case 1083: // Time
|
||||
case 1114: // Timestamp without time zone.
|
||||
case 1184: // Timestamp with time zone.
|
||||
v = [self dbToDateFromBuffer: p
|
||||
length: trim(p)];
|
||||
break;
|
||||
|
||||
case 16: // BOOL
|
||||
if (*p == 't')
|
||||
{
|
||||
v = @"YES";
|
||||
}
|
||||
else
|
||||
{
|
||||
v = @"NO";
|
||||
}
|
||||
break;
|
||||
|
||||
case 17: // BYTEA
|
||||
v = [self dataFromBLOB: p];
|
||||
break;
|
||||
|
||||
default:
|
||||
trim(p);
|
||||
v = [NSString stringWithUTF8String: p];
|
||||
break;
|
||||
v = @"Y";
|
||||
}
|
||||
else
|
||||
{
|
||||
v = @"N";
|
||||
}
|
||||
}
|
||||
else // Binary
|
||||
JException (env);
|
||||
}
|
||||
else if (types[j] == JDBCTIMESTAMP
|
||||
|| types[j] == JDBCTIME
|
||||
|| types[j] == JDBCDATE)
|
||||
{
|
||||
jclass jc;
|
||||
jobject jo;
|
||||
|
||||
jo = (*env)->CallObjectMethod (env, result,
|
||||
getTimestamp, j+1);
|
||||
JException (env);
|
||||
if ((*env)->CallBooleanMethod (env, result,
|
||||
wasNull) == JNI_FALSE)
|
||||
{
|
||||
NSLog(@"Binary data treated as NSNull "
|
||||
@"in %@ type:%d mod:%d size:%d\n",
|
||||
keys[j], types[j], modifiers[j], size);
|
||||
long milli;
|
||||
NSString *format;
|
||||
|
||||
JException (env);
|
||||
jc = (*env)->GetObjectClass(env, jo);
|
||||
JException (env);
|
||||
jm = (*env)->GetMethodID (env, jc, "getTime", "()J");
|
||||
JException (env);
|
||||
milli = (*env)->CallLongMethod (env, jo, jm);
|
||||
JException (env);
|
||||
v = [NSCalendarDate
|
||||
dateWithTimeIntervalSince1970: milli];
|
||||
if (types[j] == JDBCTIMESTAMP)
|
||||
{
|
||||
if (milli % 1000 == 0)
|
||||
{
|
||||
format = @"%Y-%m-%d %H:%M:%S %z";
|
||||
}
|
||||
else
|
||||
{
|
||||
format = @"%Y-%m-%d %H:%M:%S.%F %z";
|
||||
}
|
||||
}
|
||||
else if (types[j] == JDBCTIME)
|
||||
{
|
||||
format = @"%H:%M:%S.%F";
|
||||
}
|
||||
else
|
||||
{
|
||||
format = @"%Y-%m-%d";
|
||||
}
|
||||
[v setCalendarFormat: format];
|
||||
}
|
||||
NSLog(@"DATE: %@", v);
|
||||
JException (env);
|
||||
}
|
||||
else if (types[j] == JDBCBLOB)
|
||||
{
|
||||
jbyteArray jo;
|
||||
|
||||
jo = (*env)->CallObjectMethod (env, result,
|
||||
getBytes, j+1);
|
||||
JException (env);
|
||||
if ((*env)->CallBooleanMethod (env, result,
|
||||
wasNull) == JNI_FALSE)
|
||||
{
|
||||
v = NSDataFromByteArray(env, jo);
|
||||
}
|
||||
JException (env);
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject jo;
|
||||
|
||||
jo = (*env)->CallObjectMethod (env, result,
|
||||
getString, j+1);
|
||||
JException (env);
|
||||
if ((*env)->CallBooleanMethod (env, result,
|
||||
wasNull) == JNI_FALSE)
|
||||
{
|
||||
v = NSStringFromJString(env, jo);
|
||||
}
|
||||
JException (env);
|
||||
}
|
||||
values[j] = v;
|
||||
}
|
||||
|
@ -1130,8 +1263,7 @@ static unsigned int trim(char *str)
|
|||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: SQLException format: @"%s",
|
||||
PQresultErrorMessage(result)];
|
||||
records = [NSMutableArray array];
|
||||
}
|
||||
}
|
||||
NS_HANDLER
|
||||
|
@ -1147,10 +1279,6 @@ static unsigned int trim(char *str)
|
|||
[self debug: @"Error executing statement:\n%@\n%@",
|
||||
stmt, localException];
|
||||
}
|
||||
if (result != 0)
|
||||
{
|
||||
PQclear(result);
|
||||
}
|
||||
DESTROY(records);
|
||||
RETAIN (localException);
|
||||
RELEASE (arp);
|
||||
|
@ -1159,14 +1287,25 @@ static unsigned int trim(char *str)
|
|||
}
|
||||
NS_ENDHANDLER
|
||||
DESTROY(arp);
|
||||
if (result != 0)
|
||||
{
|
||||
PQclear(result);
|
||||
}
|
||||
#endif
|
||||
return AUTORELEASE(records);
|
||||
}
|
||||
|
||||
- (void) begin
|
||||
{
|
||||
[lock lock];
|
||||
if (_inTransaction == NO)
|
||||
{
|
||||
_inTransaction = YES;
|
||||
// Leave us locked so the transaction can't be interfered with
|
||||
}
|
||||
else
|
||||
{
|
||||
[lock unlock];
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"begin used inside transaction"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) commit
|
||||
{
|
||||
[lock lock];
|
||||
|
@ -1197,6 +1336,73 @@ static unsigned int trim(char *str)
|
|||
NS_ENDHANDLER
|
||||
}
|
||||
|
||||
- (NSString*) quoteString: (NSString *)s
|
||||
{
|
||||
static NSCharacterSet *special = nil;
|
||||
NSMutableString *m;
|
||||
NSRange r;
|
||||
unsigned l;
|
||||
|
||||
if (special == nil)
|
||||
{
|
||||
NSString *stemp;
|
||||
|
||||
/*
|
||||
* NB. length of C string is 3, so we include a nul character as a
|
||||
* special.
|
||||
*/
|
||||
stemp = [[NSString alloc] initWithBytes: "'\\"
|
||||
length: 3
|
||||
encoding: NSASCIIStringEncoding];
|
||||
special = [NSCharacterSet characterSetWithCharactersInString: stemp];
|
||||
RELEASE(stemp);
|
||||
RETAIN(special);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step through string removing nul characters
|
||||
* and escaping quote characters as required.
|
||||
*/
|
||||
m = AUTORELEASE([s mutableCopy]);
|
||||
l = [m length];
|
||||
r = NSMakeRange(0, l);
|
||||
r = [m rangeOfCharacterFromSet: special options: NSLiteralSearch range: r];
|
||||
while (r.length > 0)
|
||||
{
|
||||
unichar c = [m characterAtIndex: r.location];
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
r.length = 1;
|
||||
[m replaceCharactersInRange: r withString: @""];
|
||||
l--;
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
r.length = 0;
|
||||
[m replaceCharactersInRange: r withString: @"\\"];
|
||||
l++;
|
||||
r.location += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.length = 0;
|
||||
[m replaceCharactersInRange: r withString: @"'"];
|
||||
l++;
|
||||
r.location += 2;
|
||||
}
|
||||
r = NSMakeRange(r.location, l - r.location);
|
||||
r = [m rangeOfCharacterFromSet: special
|
||||
options: NSLiteralSearch
|
||||
range: r];
|
||||
}
|
||||
|
||||
/* Add quoting around it. */
|
||||
[m replaceCharactersInRange: NSMakeRange(0, 0) withString: @"'"];
|
||||
[m appendString: @"'"];
|
||||
return m;
|
||||
}
|
||||
|
||||
- (void) rollback
|
||||
{
|
||||
[lock lock];
|
||||
|
@ -1223,329 +1429,11 @@ static unsigned int trim(char *str)
|
|||
}
|
||||
}
|
||||
|
||||
- (unsigned) copyEscapedBLOB: (NSData*)blob into: (void*)buf
|
||||
{
|
||||
unsigned length = 0;
|
||||
#if 0
|
||||
const unsigned char *src = [blob bytes];
|
||||
unsigned sLen = [blob length];
|
||||
unsigned char *ptr = (unsigned char*)buf;
|
||||
unsigned i;
|
||||
|
||||
ptr[length++] = '\'';
|
||||
for (i = 0; i < sLen; i++)
|
||||
{
|
||||
unsigned char c = src[i];
|
||||
|
||||
if (c < 32 || c > 126)
|
||||
{
|
||||
ptr[length] = '\\';
|
||||
ptr[length+1] = '\\';
|
||||
ptr[length + 4] = (c & 7) + '0';
|
||||
c >>= 3;
|
||||
ptr[length + 3] = (c & 7) + '0';
|
||||
c >>= 3;
|
||||
ptr[length + 2] = (c & 7) + '0';
|
||||
length += 5;
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
if (standardEscaping == NO)
|
||||
{
|
||||
ptr[length++] = '\\';
|
||||
ptr[length++] = '\\';
|
||||
}
|
||||
ptr[length++] = '\\';
|
||||
ptr[length++] = '\\';
|
||||
}
|
||||
else if (c == '\'')
|
||||
{
|
||||
ptr[length++] = '\'';
|
||||
ptr[length++] = '\'';
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr[length++] = c;
|
||||
}
|
||||
}
|
||||
ptr[length++] = '\'';
|
||||
#endif
|
||||
return length;
|
||||
}
|
||||
|
||||
- (unsigned) lengthOfEscapedBLOB: (NSData*)blob
|
||||
{
|
||||
unsigned int sLen = [blob length];
|
||||
unsigned int length = sLen + 2;
|
||||
#if 0
|
||||
unsigned char *src = (unsigned char*)[blob bytes];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sLen; i++)
|
||||
{
|
||||
unsigned char c = src[i];
|
||||
|
||||
if (c < 32 || c > 126)
|
||||
{
|
||||
length += 4;
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
if (standardEscaping == NO)
|
||||
{
|
||||
length += 2;
|
||||
}
|
||||
length += 1;
|
||||
}
|
||||
else if (c == '\'')
|
||||
{
|
||||
length += 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return length;
|
||||
}
|
||||
|
||||
- (NSData *) dataFromBLOB: (const char *)blob
|
||||
{
|
||||
NSMutableData *md = nil;
|
||||
#if 0
|
||||
unsigned sLen = strlen(blob == 0 ? "" : blob);
|
||||
unsigned dLen = 0;
|
||||
unsigned char *dst;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sLen; i++)
|
||||
{
|
||||
unsigned c = blob[i];
|
||||
|
||||
dLen++;
|
||||
if (c == '\\')
|
||||
{
|
||||
c = blob[++i];
|
||||
if (c != '\\')
|
||||
{
|
||||
i += 2; // Skip 2 digits octal
|
||||
}
|
||||
}
|
||||
}
|
||||
md = [NSMutableData dataWithLength: dLen];
|
||||
dst = (unsigned char*)[md mutableBytes];
|
||||
|
||||
dLen = 0;
|
||||
for (i = 0; i < sLen; i++)
|
||||
{
|
||||
unsigned c = blob[i];
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
c = blob[++i];
|
||||
if (c != '\\')
|
||||
{
|
||||
c = c - '0';
|
||||
c <<= 3;
|
||||
c += blob[++i] - '0';
|
||||
c <<= 3;
|
||||
c += blob[++i] - '0';
|
||||
}
|
||||
}
|
||||
dst[dLen++] = c;
|
||||
}
|
||||
#endif
|
||||
return md;
|
||||
}
|
||||
|
||||
- (NSDate*) dbToDateFromBuffer: (char*)b length: (int)l
|
||||
{
|
||||
NSDate *d = nil;
|
||||
#if 0
|
||||
char buf[l+32]; /* Allow space to expand buffer. */
|
||||
BOOL milliseconds = NO;
|
||||
NSString *s;
|
||||
int i;
|
||||
|
||||
memcpy(buf, b, l);
|
||||
b = buf;
|
||||
/*
|
||||
* Find end of string.
|
||||
*/
|
||||
for (i = 0; i < l; i++)
|
||||
{
|
||||
if (b[i] == '\0')
|
||||
{
|
||||
l = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (l > 0 && isspace(b[l-1]))
|
||||
{
|
||||
l--;
|
||||
}
|
||||
b[l] = '\0';
|
||||
|
||||
if (l == 10)
|
||||
{
|
||||
s = [NSString stringWithUTF8String: b];
|
||||
d = [NSCalendarDate dateWithString: s
|
||||
calendarFormat: @"%Y-%m-%d"
|
||||
locale: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
int e;
|
||||
|
||||
/* If it's a simple date (YYYY-MM-DD) append time for start of day. */
|
||||
if (l == 10)
|
||||
{
|
||||
strcat(b, " 00:00:00 +0000");
|
||||
l += 15;
|
||||
}
|
||||
|
||||
i = l;
|
||||
while (i-- > 0)
|
||||
{
|
||||
if (b[i] == '+' || b[i] == '-')
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (b[i] == ':' || b[i] == ' ')
|
||||
{
|
||||
i = 0;
|
||||
break; /* No time zone found */
|
||||
}
|
||||
}
|
||||
if (i == 0)
|
||||
{
|
||||
/* A date and time without a timezone ... assume gmt */
|
||||
strcpy(b + l, " +0000");
|
||||
i = l + 1;
|
||||
l += 6;
|
||||
}
|
||||
|
||||
e = i;
|
||||
if (isdigit(b[i-1]))
|
||||
{
|
||||
/*
|
||||
* Make space between seconds and timezone.
|
||||
*/
|
||||
memmove(&b[i+1], &b[i], l - i);
|
||||
b[i++] = ' ';
|
||||
b[++l] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we have a four digit timezone value.
|
||||
*/
|
||||
if (isdigit(b[i+1]) && isdigit(b[i+2]))
|
||||
{
|
||||
if (b[i+3] == '\0')
|
||||
{
|
||||
// Two digit time zone ... append zero minutes
|
||||
b[l++] = '0';
|
||||
b[l++] = '0';
|
||||
b[l] = '\0';
|
||||
}
|
||||
else if (b[i+3] == ':')
|
||||
{
|
||||
// Zone with colon before minutes ... remove it
|
||||
b[i+3] = b[i+4];
|
||||
b[i+4] = b[i+5];
|
||||
b[--l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME ... horrible kludge for postgres returning timestamps with
|
||||
fractional second information. Force it to 3 digit millisecond */
|
||||
while (i-- > 0)
|
||||
{
|
||||
if (b[i] == '.')
|
||||
{
|
||||
milliseconds = YES;
|
||||
i++;
|
||||
if (!isdigit(b[i]))
|
||||
{
|
||||
memmove(&b[i+3], &b[i], e-i);
|
||||
l += 3;
|
||||
memcpy(&b[i], "000", 3);
|
||||
}
|
||||
i++;
|
||||
if (!isdigit(b[i]))
|
||||
{
|
||||
memmove(&b[i+2], &b[i], e-i);
|
||||
l += 2;
|
||||
memcpy(&b[i], "00", 2);
|
||||
}
|
||||
i++;
|
||||
if (!isdigit(b[i]))
|
||||
{
|
||||
memmove(&b[i+1], &b[i], e-i);
|
||||
l += 1;
|
||||
memcpy(&b[i], "0", 1);
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i > 0 && i < e)
|
||||
{
|
||||
memmove(&b[i], &b[e], l - e);
|
||||
l -= (e - i);
|
||||
}
|
||||
b[l] = '\0';
|
||||
if (l == 0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
s = [NSString stringWithUTF8String: b];
|
||||
if (milliseconds == YES)
|
||||
{
|
||||
d = [NSCalendarDate dateWithString: s
|
||||
calendarFormat: @"%Y-%m-%d %H:%M:%S.%F %z"
|
||||
locale: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
d = [NSCalendarDate dateWithString: s
|
||||
calendarFormat: @"%Y-%m-%d %H:%M:%S %z"
|
||||
locale: nil];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self backendDisconnect];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString*) quoteString: (NSString *)s
|
||||
{
|
||||
#if 0
|
||||
NSData *d = [s dataUsingEncoding: NSUTF8StringEncoding];
|
||||
unsigned l = [d length];
|
||||
unsigned char *to = NSZoneMalloc(NSDefaultMallocZone(), (l * 2) + 3);
|
||||
|
||||
#ifdef HAVE_PQESCAPESTRINGCONN
|
||||
int err;
|
||||
|
||||
[self backendConnect];
|
||||
l = PQescapeStringConn(extra, (char*)(to + 1), [d bytes], l, &err);
|
||||
#else
|
||||
l = PQescapeString(to + 1, [d bytes], l);
|
||||
#endif
|
||||
to[0] = '\'';
|
||||
to[l + 1] = '\'';
|
||||
s = [[NSString alloc] initWithBytesNoCopy: to
|
||||
length: l + 2
|
||||
encoding: NSUTF8StringEncoding
|
||||
freeWhenDone: YES];
|
||||
s = AUTORELEASE(s);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
Loading…
Reference in a new issue