Initial import.
FossilOrigin-Name: de46b0e10c5d9f516acbbf2ea01d84d0d5ac126412949d459265279262a1b87e
This commit is contained in:
commit
dbfce3528e
15 changed files with 586 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
build
|
||||
*.dll
|
||||
*.dylib
|
||||
*.so
|
||||
*~
|
30
Makefile
Normal file
30
Makefile
Normal 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
25
PGConnection.h
Normal 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
128
PGConnection.m
Normal 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
13
PGResult.h
Normal 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
46
PGResult.m
Normal 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
18
PGResultRow.h
Normal 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
117
PGResultRow.m
Normal 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
|
19
exceptions/PGCommandFailedException.h
Normal file
19
exceptions/PGCommandFailedException.h
Normal 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
|
53
exceptions/PGCommandFailedException.m
Normal file
53
exceptions/PGCommandFailedException.m
Normal 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
|
4
exceptions/PGConnectionFailedException.h
Normal file
4
exceptions/PGConnectionFailedException.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#import "PGException.h"
|
||||
|
||||
@interface PGConnectionFailedException: PGException
|
||||
@end
|
21
exceptions/PGConnectionFailedException.m
Normal file
21
exceptions/PGConnectionFailedException.m
Normal 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
19
exceptions/PGException.h
Normal 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
44
exceptions/PGException.m
Normal 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
44
test.m
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue