ObjPgSQL  Check-in [de46b0e10c]

Overview
Comment:Initial import.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | descendants | trunk
Files: files | file ages | folders
SHA3-256: de46b0e10c5d9f516acbbf2ea01d84d0d5ac126412949d459265279262a1b87e
User & Date: js 2012-10-03 13:20:06
Context
2012-10-03
16:04
Add "make install". check-in: 58715a7dc6 user: js tags: trunk
13:20
Initial import. check-in: de46b0e10c user: js tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace

Added .gitignore.











>
>
>
>
>
1
2
3
4
5
build
*.dll
*.dylib
*.so
*~

Added Makefile.





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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

Added PGConnection.h.



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

Added PGConnection.m.

































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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

Added PGResult.h.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
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

Added PGResult.m.





























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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

Added PGResultRow.h.





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

Added PGResultRow.m.











































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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

Added exceptions/PGCommandFailedException.h.







































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

Added exceptions/PGCommandFailedException.m.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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

Added exceptions/PGConnectionFailedException.h.









>
>
>
>
1
2
3
4
#import "PGException.h"

@interface PGConnectionFailedException: PGException
@end

Added exceptions/PGConnectionFailedException.m.











































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

Added exceptions/PGException.h.







































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

Added exceptions/PGException.m.

























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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

Added test.m.

























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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