Initial import.

FossilOrigin-Name: de46b0e10c5d9f516acbbf2ea01d84d0d5ac126412949d459265279262a1b87e
This commit is contained in:
Jonathan Schleifer 2012-10-03 13:20:06 +00:00
commit dbfce3528e
15 changed files with 586 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
build
*.dll
*.dylib
*.so
*~

30
Makefile Normal file
View file

@ -0,0 +1,30 @@
SRCS = PGConnection.m \
PGResult.m \
PGResultRow.m \
exceptions/PGCommandFailedException.m \
exceptions/PGConnectionFailedException.m \
exceptions/PGException.m
all:
@objfw-compile \
--lib 0.0 \
-o objpgsql \
--builddir build \
-Iexceptions \
-I. \
-lpq \
${SRCS}
test:
@objfw-compile \
-o test \
--builddir build \
-Iexceptions \
-I. \
-L. \
-lobjpgsql \
test.m
clean:
rm -f libobjpgsql.* exceptions/*~ *~
rm -fr build

25
PGConnection.h Normal file
View file

@ -0,0 +1,25 @@
#include <libpq-fe.h>
#import <ObjFW/ObjFW.h>
#import "PGResult.h"
@interface PGConnection: OFObject
{
PGconn *conn;
OFDictionary *parameters;
}
#ifdef OF_HAVE_PROPERTIES
@property (copy) OFDictionary *parameters;
#endif
- (void)setParameters: (OFDictionary*)parameters;
- (OFDictionary*)parameters;
- (void)connect;
- (void)reset;
- (PGResult*)executeCommand: (OFString*)command;
- (PGResult*)executeCommand: (OFString*)command
parameters: (OFArray*)parameters;
- (PGconn*)PG_connection;
@end

128
PGConnection.m Normal file
View file

@ -0,0 +1,128 @@
#import "PGConnection.h"
#import "PGConnectionFailedException.h"
#import "PGCommandFailedException.h"
@implementation PGConnection
- (void)dealloc
{
[parameters release];
if (conn != NULL)
PQfinish(conn);
[super dealloc];
}
- (void)setParameters: (OFDictionary*)parameters_
{
OF_SETTER(parameters, parameters_, YES, YES)
}
- (OFDictionary*)parameters
{
OF_GETTER(parameters, YES)
}
- (void)connect
{
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
OFEnumerator *keyEnumerator = [parameters keyEnumerator];
OFEnumerator *objectEnumerator = [parameters objectEnumerator];
OFMutableString *conninfo = nil;
OFString *key, *object;
while ((key = [keyEnumerator nextObject]) != nil &&
(object = [objectEnumerator nextObject]) != nil) {
if (conninfo != nil)
[conninfo appendFormat: @" %@=%@", key, object];
else
conninfo = [OFMutableString stringWithFormat:
@"%@=%@", key, object];
}
if ((conn = PQconnectdb([conninfo UTF8String])) == NULL)
@throw [OFOutOfMemoryException
exceptionWithClass: [self class]];
if (PQstatus(conn) == CONNECTION_BAD)
@throw [PGConnectionFailedException
exceptionWithClass: [self class]
connection: self];
[pool release];
}
- (void)reset
{
PQreset(conn);
}
- (PGResult*)executeCommand: (OFString*)command
{
PGresult *result = PQexec(conn, [command UTF8String]);
if (PQresultStatus(result) == PGRES_FATAL_ERROR) {
PQclear(result);
@throw [PGCommandFailedException
exceptionWithClass: [self class]
connection: self
command: command];
}
if (PQresultStatus(result) == PGRES_TUPLES_OK)
return [PGResult PG_resultWithResult: result];
PQclear(result);
return nil;
}
- (PGResult*)executeCommand: (OFString*)command
parameters: (OFArray*)parameters_
{
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
PGresult *result;
const char **values;
values = [self allocMemoryWithSize: sizeof(*values)
count: [parameters_ count]];
@try {
OFEnumerator *enumerator = [parameters_ objectEnumerator];
size_t i = 0;
id parameter;
while ((parameter = [enumerator nextObject]) != nil) {
if ([parameter isKindOfClass: [OFNull class]])
values[i++] = NULL;
else
values[i++] = [parameter UTF8String];
}
result = PQexecParams(conn, [command UTF8String],
[parameters_ count], NULL, values, NULL, NULL, 0);
} @finally {
[self freeMemory: values];
}
[pool release];
if (PQresultStatus(result) == PGRES_FATAL_ERROR) {
PQclear(result);
@throw [PGCommandFailedException
exceptionWithClass: [self class]
connection: self
command: command];
}
if (PQresultStatus(result) == PGRES_TUPLES_OK)
return [PGResult PG_resultWithResult: result];
PQclear(result);
return nil;
}
- (PGconn*)PG_connection
{
return conn;
}
@end

13
PGResult.h Normal file
View file

@ -0,0 +1,13 @@
#include <libpq-fe.h>
#import <ObjFW/ObjFW.h>
@interface PGResult: OFArray
{
PGresult *result;
}
+ PG_resultWithResult: (PGresult*)result;
- PG_initWithResult: (PGresult*)result;
- (PGresult*)PG_result;
@end

46
PGResult.m Normal file
View file

@ -0,0 +1,46 @@
#import "PGResult.h"
#import "PGResultRow.h"
@implementation PGResult
+ PG_resultWithResult: (PGresult*)result
{
return [[[self alloc] PG_initWithResult: result] autorelease];
}
- PG_initWithResult: (PGresult*)result_
{
self = [super init];
result = result_;
return self;
}
- (void)dealloc
{
if (result != NULL)
PQclear(result);
[super dealloc];
}
- (size_t)count
{
return PQntuples(result);
}
- (id)objectAtIndex: (size_t)index
{
if (index > PQntuples(result))
@throw [OFOutOfRangeException
exceptionWithClass: [self class]];
return [PGResultRow rowWithResult: self
row: index];
}
- (PGresult*)PG_result
{
return result;
}
@end

18
PGResultRow.h Normal file
View file

@ -0,0 +1,18 @@
#include <libpq-fe.h>
#import <ObjFW/ObjFW.h>
#import "PGResult.h"
@interface PGResultRow: OFDictionary
{
PGResult *result;
PGresult *res;
size_t row;
}
+ rowWithResult: (PGResult*)result
row: (size_t)row;
- initWithResult: (PGResult*)result
row: (size_t)row;
@end

117
PGResultRow.m Normal file
View file

@ -0,0 +1,117 @@
#import "PGResultRow.h"
@interface PGResultRowEnumerator: OFEnumerator
{
PGResult *result;
PGresult *res;
size_t row, pos, count;
}
- initWithResult: (PGResult*)result
row: (size_t)row;
@end
@interface PGResultRowKeyEnumerator: PGResultRowEnumerator
@end
@interface PGResultRowObjectEnumerator: PGResultRowEnumerator
@end
@implementation PGResultRow
+ rowWithResult: (PGResult*)result
row: (size_t)row
{
return [[[self alloc] initWithResult: result
row: row] autorelease];
}
- initWithResult: (PGResult*)result_
row: (size_t)row_
{
self = [super init];
result = [result_ retain];
res = [result PG_result];
row = row_;
return self;
}
- (void)dealloc
{
[result release];
[super dealloc];
}
- (size_t)count
{
return PQnfields(res);
}
- (id)objectForKey: (id)key
{
int col;
if ([key isKindOfClass: [OFNumber class]])
col = [key intValue];
else
col = PQfnumber(res, [key UTF8String]);
return [OFString stringWithUTF8String: PQgetvalue(res, row, col)];
}
- (OFEnumerator*)keyEnumerator
{
return [[[PGResultRowKeyEnumerator alloc]
initWithResult: result
row: row] autorelease];
}
- (OFEnumerator*)objectEnumerator
{
return [[[PGResultRowObjectEnumerator alloc]
initWithResult: result
row: row] autorelease];
}
@end
@implementation PGResultRowEnumerator
- initWithResult: (PGResult*)result_
row: (size_t)row_
{
self = [super init];
result = [result_ retain];
res = [result PG_result];
row = row_;
count = PQnfields(res);
return self;
}
- (void)reset
{
pos = 0;
}
@end
@implementation PGResultRowKeyEnumerator
- (id)nextObject
{
if (pos >= count)
return nil;
return [OFString stringWithUTF8String: PQfname(res, pos++)];
}
@end
@implementation PGResultRowObjectEnumerator
- (id)nextObject
{
if (pos >= count)
return nil;
return [OFString stringWithUTF8String: PQgetvalue(res, row, pos++)];
}
@end

View file

@ -0,0 +1,19 @@
#import "PGException.h"
@interface PGCommandFailedException: PGException
{
OFString *command;
}
#ifdef OF_HAVE_PROPERTIES
@property (readonly, copy, nonatomic) OFString *command;
#endif
+ exceptionWithClass: (Class)class_
connection: (PGConnection*)connection
command: (OFString*)command;
- initWithClass: (Class)class_
connection: (PGConnection*)connection
command: (OFString*)command;
- (OFString*)command;
@end

View file

@ -0,0 +1,53 @@
#import "PGCommandFailedException.h"
@implementation PGCommandFailedException
+ exceptionWithClass: (Class)class
connection: (PGConnection*)connection
command: (OFString*)command
{
return [[[self alloc] initWithClass: class
connection: connection
command: command] autorelease];
}
- initWithClass: (Class)class_
connection: (PGConnection*)connection_
command: (OFString*)command_
{
self = [super initWithClass: class_
connection: connection_];
@try {
command = [command_ copy];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
- (void)dealloc
{
[command release];
[super dealloc];
}
- (OFString*)description
{
if (description != nil)
return description;
description = [[OFString alloc] initWithFormat:
@"A PostgreSQL command in class %@ failed: %s\nCommand: %@",
inClass, PQerrorMessage([connection PG_connection]), command];
return description;
}
- (OFString*)command
{
OF_GETTER(command, NO)
}
@end

View file

@ -0,0 +1,4 @@
#import "PGException.h"
@interface PGConnectionFailedException: PGException
@end

View file

@ -0,0 +1,21 @@
#import "PGConnectionFailedException.h"
@implementation PGConnectionFailedException
- (OFString*)description
{
OFAutoreleasePool *pool;
if (description != nil)
return description;
pool = [[OFAutoreleasePool alloc] init];
description = [[OFString alloc] initWithFormat:
@"Establishing a PostgreSQL connection in class %@ failed:\n%s\n"
"Parameters: %@", inClass,
PQerrorMessage([connection PG_connection]),
[connection parameters]];
[pool release];
return description;
}
@end

19
exceptions/PGException.h Normal file
View file

@ -0,0 +1,19 @@
#import <ObjFW/ObjFW.h>
#import "PGConnection.h"
@interface PGException: OFException
{
PGConnection *connection;
}
#ifdef OF_HAVE_PROPERTIES
@property (readonly, retain, nonatomic) PGConnection *connection;
#endif
+ exceptionWithClass: (Class)class_
connection: (PGConnection*)connection;
- initWithClass: (Class)class_
connection: (PGConnection*)connection;
- (PGConnection*)connection;
@end

44
exceptions/PGException.m Normal file
View file

@ -0,0 +1,44 @@
#import "PGException.h"
@implementation PGException
+ exceptionWithClass: (Class)class
connection: (PGConnection*)connection
{
return [[[self alloc] initWithClass: class
connection: connection] autorelease];
}
- initWithClass: (Class)class_
connection: (PGConnection*)connection_
{
self = [super initWithClass: class_];
connection = [connection_ retain];
return self;
}
- (void)dealloc
{
[connection release];
[super dealloc];
}
- (OFString*)description
{
if (description != nil)
return description;
description = [[OFString alloc] initWithFormat:
@"A PostgreSQL operation in class %@ failed: %s", inClass,
PQerrorMessage([connection PG_connection])];
return description;
}
- (PGConnection*)connection
{
OF_GETTER(connection, NO)
}
@end

44
test.m Normal file
View file

@ -0,0 +1,44 @@
#import <ObjFW/ObjFW.h>
#import "PGConnection.h"
#import "PGConnectionFailedException.h"
@interface Test: OFObject
{
PGConnection *connection;
}
@end
OF_APPLICATION_DELEGATE(Test)
@implementation Test
- (void)applicationDidFinishLaunching
{
PGResult *result;
connection = [[PGConnection alloc] init];
[connection setParameters:
[OFDictionary dictionaryWithKeysAndObjects: @"user", @"js",
@"dbname", @"js", nil]];
[connection connect];
[connection executeCommand: @"DROP TABLE IF EXISTS test"];
[connection executeCommand: @"CREATE TABLE test ("
@" id integer,"
@" name varchar(255),"
@" content text"
@")"];
[connection executeCommand: @"INSERT INTO test (id, name, content) "
@"VALUES($1, $2, $3)"
parameters: @[@"1", @"foo", @"Hallo Welt!"]];
[connection executeCommand: @"INSERT INTO test (id, name, content) "
@"VALUES($1, $2, $3)"
parameters: @[@"2", @"bla", @"Blup!!"]];
result = [connection executeCommand: @"SELECT * FROM test"];
of_log(@"%@", result);
of_log(@"JSON: %@", [result JSONRepresentation]);
[OFApplication terminate];
}
@end