aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks/PostgresKit/Source
diff options
context:
space:
mode:
authorstuconnolly <stuart02@gmail.com>2012-09-03 10:22:17 +0000
committerstuconnolly <stuart02@gmail.com>2012-09-03 10:22:17 +0000
commite124a1d0fb576c311a6ac601b1c08e6ce51bcd30 (patch)
tree5a3350fc75bcad1f5c8d07f8a66ea53b0a07805f /Frameworks/PostgresKit/Source
parentd4e8474b3437771fd6891def8324981d82186a88 (diff)
downloadsequelpro-e124a1d0fb576c311a6ac601b1c08e6ce51bcd30.tar.gz
sequelpro-e124a1d0fb576c311a6ac601b1c08e6ce51bcd30.tar.bz2
sequelpro-e124a1d0fb576c311a6ac601b1c08e6ce51bcd30.zip
Initial commit of PostgresKit, our new Postgres framework as a start towards adding PostgreSQL support to Sequel Pro.
Note, that the framerwork is by no means feature complete and in it's current state has quite a few limitations: - No support for Postgres' asynchronous query API - Only supports the very basic data types (char/text and numerics) - No support (outide of libpq) for re-establishing dropped connections Current feature support includes: - Basic connection handling - Query execution - Prepared statement execution - Encoding support similar to SPMySQL's
Diffstat (limited to 'Frameworks/PostgresKit/Source')
-rw-r--r--Frameworks/PostgresKit/Source/FLXConstants.h41
-rw-r--r--Frameworks/PostgresKit/Source/FLXConstants.m31
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnection.h97
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnection.m460
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionDelegate.h58
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.h39
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.m197
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.h56
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.m220
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.h38
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.m29
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.h38
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.m322
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.h32
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.m131
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h33
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.m105
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.h33
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.m133
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresError.h74
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresError.m136
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresException.h28
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresException.m64
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresResult.h71
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresResult.m264
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresStatement.h44
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresStatement.m81
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h35
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m86
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.h38
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.m46
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h84
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h28
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m325
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.h28
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m77
-rw-r--r--Frameworks/PostgresKit/Source/FLXPostgresTypes.h80
-rw-r--r--Frameworks/PostgresKit/Source/PostgresKit-Prefix.pch31
-rw-r--r--Frameworks/PostgresKit/Source/PostgresKit.h27
39 files changed, 3740 insertions, 0 deletions
diff --git a/Frameworks/PostgresKit/Source/FLXConstants.h b/Frameworks/PostgresKit/Source/FLXConstants.h
new file mode 100644
index 00000000..95ab17f6
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXConstants.h
@@ -0,0 +1,41 @@
+//
+// $Id$
+//
+// FLXConstants.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Result set row types
+typedef enum
+{
+ FLXPostgresResultRowAsArray = 1,
+ FLXPostgresResultRowAsDictionary = 2
+}
+FLXPostgresResultRowType;
+
+// Defaults
+extern NSString *FLXPostgresConnectionDefaultEncoding;
+extern NSString *FLXPostgresConnectionErrorDomain;
+extern NSStringEncoding FLXPostgresConnectionDefaultStringEncoding;
+
+// Server parameters
+extern NSString *FLXPostgresParameterServerEncoding;
+extern NSString *FLXPostgresParameterClientEncoding;
+extern NSString *FLXPostgresParameterSuperUser;
+extern NSString *FLXPostgresParameterTimeZone;
+extern NSString *FLXPostgresParameterIntegerDateTimes;
diff --git a/Frameworks/PostgresKit/Source/FLXConstants.m b/Frameworks/PostgresKit/Source/FLXConstants.m
new file mode 100644
index 00000000..3dc68ff9
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXConstants.m
@@ -0,0 +1,31 @@
+//
+// $Id$
+//
+// FLXConstants.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+NSString *FLXPostgresConnectionDefaultEncoding = @"UNICODE";
+NSString *FLXPostgresConnectionErrorDomain = @"FLXPostgresConnectionError";
+NSStringEncoding FLXPostgresConnectionDefaultStringEncoding = NSUTF8StringEncoding;
+
+NSString *FLXPostgresParameterServerEncoding = @"server_encoding";
+NSString *FLXPostgresParameterClientEncoding = @"client_encoding";
+NSString *FLXPostgresParameterSuperUser = @"is_superuser";
+NSString *FLXPostgresParameterTimeZone = @"TimeZone";
+NSString *FLXPostgresParameterIntegerDateTimes = @"integer_datetimes";
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnection.h b/Frameworks/PostgresKit/Source/FLXPostgresConnection.h
new file mode 100644
index 00000000..20260818
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnection.h
@@ -0,0 +1,97 @@
+//
+// $Id$
+//
+// FLXPostgresConnection.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeHandlerProtocol.h"
+#import "FLXPostgresConnectionDelegate.h"
+
+@class FLXPostgresResult;
+@class FLXPostgresStatement;
+@class FLXPostgresConnectionParameters;
+
+@interface FLXPostgresConnection : NSObject
+{
+ PGconn *_connection;
+
+ NSString *_host;
+ NSString *_user;
+ NSString *_database;
+ NSString *_password;
+ NSString *_socketPath;
+ NSString *_lastErrorMessage;
+ NSString *_encoding;
+
+ const char **_connectionParamNames;
+ const char **_connectionParamValues;
+
+ NSStringEncoding _stringEncoding;
+
+ NSUInteger _port;
+ NSUInteger _timeout;
+ NSUInteger _keepAliveInterval;
+
+ BOOL _useSocket;
+ BOOL _useKeepAlive;
+ BOOL _lastQueryWasCancelled;
+ BOOL _delegateSupportsWillExecute;
+
+ NSMutableDictionary *_typeMap;
+
+ FLXPostgresConnectionParameters *_parameters;
+
+ NSObject <FLXPostgresConnectionDelegate> *_delegate;
+}
+
+@property (readwrite, assign) NSObject <FLXPostgresConnectionDelegate> *delegate;
+
+@property (readwrite, retain) NSString *host;
+@property (readwrite, retain) NSString *user;
+@property (readwrite, retain) NSString *database;
+@property (readwrite, retain) NSString *password;
+@property (readwrite, retain) NSString *socketPath;
+
+@property (readonly) NSString *encoding;
+@property (readonly) NSString *lastErrorMessage;
+@property (readonly) NSStringEncoding stringEncoding;
+@property (readonly) FLXPostgresConnectionParameters *parameters;
+
+@property (readwrite, assign) BOOL useSocket;
+@property (readwrite, assign) BOOL useKeepAlive;
+@property (readwrite, assign) BOOL lastQueryWasCancelled;
+
+@property (readwrite, assign) NSUInteger timeout;
+@property (readwrite, assign) NSUInteger port;
+@property (readwrite, assign) NSUInteger keepAliveInterval;
+
+- (id)initWithDelegate:(NSObject <FLXPostgresConnectionDelegate> *)delegate;
+
+- (BOOL)connect;
+- (void)disconnect;
+- (BOOL)isConnected;
+- (BOOL)reset;
+
+- (NSUInteger)clientVersion;
+- (NSUInteger)serverVersion;
+- (NSUInteger)serverProcessId;
+
+- (BOOL)cancelCurrentQuery:(NSError **)error;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnection.m b/Frameworks/PostgresKit/Source/FLXPostgresConnection.m
new file mode 100644
index 00000000..3bd24bb2
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnection.m
@@ -0,0 +1,460 @@
+//
+// $Id$
+//
+// FLXPostgresConnection.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnection.h"
+#import "FLXPostgresConnectionParameters.h"
+#import "FLXPostgresConnectionTypeHandling.h"
+#import "FLXPostgresConnectionPrivateAPI.h"
+#import "FLXPostgresTypeNumberHandler.h"
+#import "FLXPostgresTypeStringHandler.h"
+#import "FLXPostgresException.h"
+#import "FLXPostgresStatement.h"
+#import "FLXPostgresResult.h"
+
+#import "pthread.h"
+
+// Connection default constants
+static NSUInteger FLXPostgresConnectionDefaultTimeout = 30;
+static NSUInteger FLXPostgresConnectionDefaultServerPort = 5432;
+static NSUInteger FLXPostgresConnectionDefaultKeepAlive = 60;
+
+// libpq connection parameters
+static const char *FLXPostgresApplicationName = "PostgresKit";
+static const char *FLXPostgresApplicationParam = "application_name";
+static const char *FLXPostgresUserParam = "user";
+static const char *FLXPostgresHostParam = "host";
+static const char *FLXPostgresPasswordParam = "password";
+static const char *FLXPostgresPortParam = "port";
+static const char *FLXPostgresDatabaseParam = "dbname";
+static const char *FLXPostgresConnectionTimeoutParam = "conect_timeout";
+static const char *FLXPostgresClientEncodingParam = "client_encoding";
+static const char *FLXPostgresKeepAliveParam = "keepalives";
+static const char *FLXPostgresKeepAliveIntervalParam = "keepalives_interval";
+
+@interface FLXPostgresConnection ()
+
+- (void)_pollConnection;
+- (void)_loadDatabaseParameters;
+- (void)_createConnectionParameters;
+
+// libpq callback
+static void _FLXPostgresConnectionNoticeProcessor(void *arg, const char *message);
+
+@end
+
+@implementation FLXPostgresConnection
+
+@synthesize port = _port;
+@synthesize host = _host;
+@synthesize user = _user;
+@synthesize database = _database;
+@synthesize password = _password;
+@synthesize useSocket = _useSocket;
+@synthesize socketPath = _socketPath;
+@synthesize delegate = _delegate;
+@synthesize timeout = _timeout;
+@synthesize useKeepAlive = _useKeepAlive;
+@synthesize keepAliveInterval = _keepAliveInterval;
+@synthesize lastQueryWasCancelled = _lastQueryWasCancelled;
+@synthesize lastErrorMessage = _lastErrorMessage;
+@synthesize encoding = _encoding;
+@synthesize stringEncoding = _stringEncoding;
+@synthesize parameters = _parameters;
+
+#pragma mark -
+#pragma mark Initialisation
+
+- (id)init
+{
+ return [self initWithDelegate:nil];
+}
+
+/**
+ * Initialise a new connection with the supplied delegate.
+ *
+ * @param delegate The delegate this connection should use.
+ *
+ * @return The new connection instance.
+ */
+- (id)initWithDelegate:(NSObject <FLXPostgresConnectionDelegate> *)delegate
+{
+ if ((self = [super init])) {
+
+ _delegate = delegate;
+
+ _port = FLXPostgresConnectionDefaultServerPort;
+ _timeout = FLXPostgresConnectionDefaultTimeout;
+
+ _useKeepAlive = YES;
+ _keepAliveInterval = FLXPostgresConnectionDefaultKeepAlive;
+
+ _connection = nil;
+ _lastErrorMessage = nil;
+ _lastQueryWasCancelled = NO;
+
+ _stringEncoding = FLXPostgresConnectionDefaultStringEncoding;
+ _encoding = [NSString stringWithString:FLXPostgresConnectionDefaultEncoding];
+
+ _delegateSupportsWillExecute = [_delegate respondsToSelector:@selector(connection:willExecute:values:)];
+
+ _typeMap = [[NSMutableDictionary alloc] init];
+
+ [self registerTypeHandlers];
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Accessors
+
+- (PGconn *)postgresConnection
+{
+ return _connection;
+}
+
+#pragma mark -
+#pragma mark Connection Handling
+
+/**
+ * Does this connection have an underlying connection established with the server.
+ *
+ * @return A BOOL indicating the result of the query.
+ */
+- (BOOL)isConnected
+{
+ if (!_connection) return NO;
+
+ return PQstatus(_connection) == CONNECTION_OK;
+}
+
+/**
+ * Attempts to disconnect the underlying connection with the server.
+ */
+- (void)disconnect
+{
+ if (!_connection) return;
+
+ [self cancelCurrentQuery:nil];
+
+ PQfinish(_connection);
+
+ _connection = nil;
+
+ if (_delegate && [_delegate respondsToSelector:@selector(connectionDisconnected:)]) {
+ [_delegate connectionDisconnected:self];
+ }
+}
+
+/**
+ * Initiates the underlying connection to the server asynchronously.
+ *
+ * Note, that if no user, host or database is set when connect is called, then libpq's defaults are used.
+ * For no host, this means a socket connection to /tmp is attempted.
+ *
+ * @return A BOOL indicating the success of requesting the connection. Note, that this does not indicate
+ * that a successful connection has been made, only that it has successfullly been requested.
+ */
+- (BOOL)connect
+{
+ if ([self isConnected]) {
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain reason:@"Attempt to initiate a connection that is already active"];
+
+ return NO;
+ }
+
+ [self _createConnectionParameters];
+
+ // Perform the connection
+ _connection = PQconnectStartParams(_connectionParamNames, _connectionParamValues, 0);
+
+ if (!_connection || PQstatus(_connection) == CONNECTION_BAD) {
+
+ // TODO: implement reconnection attempt
+ return NO;
+ }
+
+ [self performSelectorInBackground:@selector(_pollConnection) withObject:nil];
+
+ return YES;
+}
+
+/**
+ * Attempts the reset the underlying connection.
+ *
+ * @note A return value of NO means that the connection is not currently
+ * connected to be reset and YES means the reset request was successful,
+ * not that the connection re-establishment has succeeded. Use -isConnected
+ * to check this.
+ *
+ * @return A BOOL indicating the success of the call.
+ */
+- (BOOL)reset
+{
+ if (![self isConnected]) return NO;
+
+ PQreset(_connection);
+
+ return YES;
+}
+
+/**
+ * Returns the PostgreSQL client library (libpq) version being used.
+ *
+ * @return The library version (e.g. version 9.1 is 90100).
+ */
+- (NSUInteger)clientVersion
+{
+ return PQlibVersion();
+}
+
+/**
+ * Returns the version of the server we're connected to.
+ *
+ * @return The server version (e.g. version 9.1 is 90100). Zero is returned if there's no connection.
+ */
+- (NSUInteger)serverVersion
+{
+ if (![self isConnected]) return 0;
+
+ return PQserverVersion(_connection);
+}
+
+/**
+ * Returns the ID of the process handling this connection on the remote host.
+ *
+ * @return The process ID or -1 if no connection is available.
+ */
+- (NSUInteger)serverProcessId
+{
+ if (![self isConnected]) return -1;
+
+ return PQbackendPID(_connection);
+}
+
+/**
+ * Attempts to cancel the query currently executing on this connection.
+ *
+ * @param error Populated if query was unabled to be cancelled.
+ *
+ * @return A BOOL indicating the success of the request
+ */
+- (BOOL)cancelCurrentQuery:(NSError **)error
+{
+ if (![self isConnected]) return NO;
+
+ PGcancel *cancel = PQgetCancel(_connection);
+
+ if (!cancel) return NO;
+
+ char errorBuf[256];
+
+ int result = PQcancel(cancel, errorBuf, 256);
+
+ PQfreeCancel(cancel);
+
+ if (!result) {
+ if (error != NULL) {
+ *error = [NSError errorWithDomain:FLXPostgresConnectionErrorDomain
+ code:0
+ userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithUTF8String:errorBuf] forKey:NSLocalizedDescriptionKey]];
+ }
+
+ return NO;
+ }
+
+ _lastQueryWasCancelled = YES;
+
+ return YES;
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Polls the connection that was previously requested via -connect and waits for meaninful status.
+ *
+ * @note This method should be called on a background thread as it will block waiting for the connection.
+ */
+- (void)_pollConnection
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ BOOL failed = NO;
+ BOOL connected = NO;
+
+ while (!connected && !failed)
+ {
+ switch (PQconnectPoll(_connection))
+ {
+ case PGRES_POLLING_READING:
+ case PGRES_POLLING_WRITING:
+ case PGRES_POLLING_ACTIVE: // Obsolete so we don't really care about it
+ break;
+ case PGRES_POLLING_OK:
+ connected = YES;
+ break;
+ case PGRES_POLLING_FAILED:
+ failed = YES;
+ break;
+ }
+ }
+
+ if (connected) {
+ PQsetNoticeProcessor(_connection, _FLXPostgresConnectionNoticeProcessor, self);
+
+ [self _loadDatabaseParameters];
+
+ if (_delegate && [_delegate respondsToSelector:@selector(connectionEstablished:)]) {
+ [_delegate performSelectorOnMainThread:@selector(connectionEstablished:) withObject:self waitUntilDone:NO];
+ }
+ }
+
+ [pool release];
+}
+
+/**
+ * Loads the database parameters.
+ */
+- (void)_loadDatabaseParameters
+{
+ if (_parameters) [_parameters release];
+
+ _parameters = [[FLXPostgresConnectionParameters alloc] initWithConnection:self];
+
+ BOOL success = [_parameters loadParameters];
+
+ if (!success) {
+ NSLog(@"PostgresKit: Warning: Failed to load database parameters.");
+ }
+}
+
+/**
+ * libpq notice processor function. Simply passes the message onto the connection delegate.
+ *
+ * @param arg The calling connection.
+ * @param message The message that was sent.
+ */
+static void _FLXPostgresConnectionNoticeProcessor(void *arg, const char *message)
+{
+ FLXPostgresConnection *connection = (FLXPostgresConnection *)arg;
+
+ if ([connection isKindOfClass:[FLXPostgresConnection class]]) {
+
+ if ([connection delegate] && [[connection delegate] respondsToSelector:@selector(connection:notice:)]) {
+ [[connection delegate] connection:connection notice:[NSString stringWithUTF8String:message]];
+ }
+ }
+}
+
+/**
+ * Creates the parameter arrays required to establish a connection.
+ */
+- (void)_createConnectionParameters
+{
+ BOOL hasUser = NO;
+ BOOL hasHost = NO;
+ BOOL hasPassword = NO;
+ BOOL hasDatabase = NO;
+
+ if (_connectionParamNames) free(_connectionParamNames);
+ if (_connectionParamValues) free(_connectionParamValues);
+
+ int paramCount = 6;
+
+ if (_user && [_user length]) paramCount++, hasUser = YES;
+ if (_host && [_host length]) paramCount++, hasHost = YES;
+ if (_password && [_password length]) paramCount++, hasPassword = YES;
+ if (_database && [_database length]) paramCount++, hasDatabase = YES;
+
+ _connectionParamNames = malloc(paramCount * sizeof(*_connectionParamNames));
+ _connectionParamValues = malloc(paramCount * sizeof(*_connectionParamValues));
+
+ _connectionParamNames[0] = FLXPostgresApplicationParam;
+ _connectionParamValues[0] = FLXPostgresApplicationName;
+
+ _connectionParamNames[1] = FLXPostgresPortParam;
+ _connectionParamValues[1] = [[[NSNumber numberWithUnsignedInteger:_port] stringValue] UTF8String];
+
+ _connectionParamNames[2] = FLXPostgresConnectionTimeoutParam;
+ _connectionParamValues[2] = [[[NSNumber numberWithUnsignedInteger:_timeout] stringValue] UTF8String];
+
+ _connectionParamNames[3] = FLXPostgresClientEncodingParam;
+ _connectionParamValues[3] = [_encoding UTF8String];
+
+ _connectionParamNames[4] = FLXPostgresKeepAliveParam;
+ _connectionParamValues[4] = _useKeepAlive ? "1" : "0";
+
+ _connectionParamNames[5] = FLXPostgresKeepAliveIntervalParam;
+ _connectionParamValues[5] = [[[NSNumber numberWithUnsignedInteger:_keepAliveInterval] stringValue] UTF8String];
+
+ NSUInteger i = 6;
+
+ if (hasUser) {
+ _connectionParamNames[i] = FLXPostgresUserParam;
+ _connectionParamValues[i] = [_user UTF8String];
+
+ i++;
+ }
+
+ if (hasHost) {
+ _connectionParamNames[i] = FLXPostgresHostParam;
+ _connectionParamValues[i] = [_host UTF8String];
+
+ i++;
+ }
+
+ if (hasPassword) {
+ _connectionParamNames[i] = FLXPostgresPasswordParam;
+ _connectionParamValues[i] = [_password UTF8String];
+
+ i++;
+ }
+
+ if (hasDatabase) {
+ _connectionParamNames[i] = FLXPostgresDatabaseParam;
+ _connectionParamValues[i] = [_database UTF8String];
+ }
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ [_typeMap release];
+
+ [self disconnect];
+
+ [self setHost:nil];
+ [self setUser:nil];
+ [self setDatabase:nil];
+
+ if (_connectionParamNames) free(_connectionParamNames);
+ if (_connectionParamValues) free(_connectionParamValues);
+
+ if (_parameters) [_parameters release], _parameters = nil;
+ if (_lastErrorMessage) [_lastErrorMessage release], _lastErrorMessage = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionDelegate.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionDelegate.h
new file mode 100644
index 00000000..9626d8e1
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionDelegate.h
@@ -0,0 +1,58 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionDelegate.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+@class FLXPostgresConnection;
+
+@protocol FLXPostgresConnectionDelegate <NSObject>
+
+/**
+ * Called whenever a connection is successfully established.
+ *
+ * @param connection The connection instance.
+ */
+- (void)connectionEstablished:(FLXPostgresConnection *)connection;
+
+/**
+ * Called whenever a connection is disconnected.
+ *
+ * @param connection The connection instance.
+ */
+- (void)connectionDisconnected:(FLXPostgresConnection *)connection;
+
+/**
+ * Called whenever a message is received from the PostgreSQL server.
+ *
+ * @param connection The connection instance.
+ * @param notice The notice message received.
+ */
+- (void)connection:(FLXPostgresConnection *)connection notice:(NSString *)notice;
+
+/**
+ * Called just before a query is about to be executed.
+ *
+ * @param connection The connection executing the query.
+ * @param query The query about the be executed.
+ * @param values The values of the query.
+ */
+- (void)connection:(FLXPostgresConnection *)connection willExecute:(NSObject *)query values:(NSArray *)values;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.h
new file mode 100644
index 00000000..c6686465
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.h
@@ -0,0 +1,39 @@
+// $Id$
+//
+// FLXPostgresConnectionEncoding.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 4, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnection (FLXPostgresConnectionEncoding)
+
+- (BOOL)setEncoding:(NSString *)encoding;
+
++ (NSStringEncoding)stringEncodingForPostgreSQLCharset:(const char *)charset;
++ (NSString *)postgreSQLCharsetForStringEncoding:(NSStringEncoding)stringEncoding;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.m
new file mode 100644
index 00000000..ddecee64
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionEncoding.m
@@ -0,0 +1,197 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionEncoding.m
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 4, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import "FLXPostgresConnectionEncoding.h"
+#import "FLXPostgresConnectionPrivateAPI.h"
+
+@implementation FLXPostgresConnection (FLXPostgresConnectionEncoding)
+
+/**
+ * Set the current connection's encoding.
+ *
+ * @param encoding The name of the encoding to use.
+ *
+ * @return A BOOL indicating the success of the operation. NO means there was either no connection or the
+ * encoding name wasn't recognised by the server.
+ */
+- (BOOL)setEncoding:(NSString *)encoding
+{
+ if (![self isConnected]) return NO;
+
+ if ([_encoding isEqualToString:encoding]) return YES;
+
+ if (PQsetClientEncoding(_connection, [encoding UTF8String]) != 0) return NO;
+
+ [_encoding release], _encoding = [[NSString alloc] initWithString:encoding];
+
+ _stringEncoding = [FLXPostgresConnection stringEncodingForPostgreSQLCharset:[encoding UTF8String]];
+
+ return YES;
+}
+
+/**
+ * Translates the supplied encoding name to it's corresponding string encoding identifier.
+ *
+ * @param charset The character set as a char array.
+ *
+ * @return The string encoding identifier.
+ */
++ (NSStringEncoding)stringEncodingForPostgreSQLCharset:(const char *)charset
+{
+ if (!strcmp(charset, "UNICODE") || !strcmp(charset, "MULE_INTERNAL")) {
+ return NSUTF8StringEncoding;
+ }
+ else if (!strcmp(charset, "LATIN1")) {
+ return NSISOLatin1StringEncoding;
+ }
+ else if (!strcmp(charset, "LATIN2")) {
+ return NSISOLatin2StringEncoding;
+ }
+ else if (!strcmp(charset, "LATIN3")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin3);
+ }
+ else if (!strcmp(charset, "LATIN4")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin4);
+ }
+ else if (!strcmp(charset, "LATIN5")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin5);
+ }
+ else if (!strcmp(charset, "LATIN6")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin6);
+ }
+ else if (!strcmp(charset, "LATIN7")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin7);
+ }
+ else if (!strcmp(charset, "LATIN8")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin8);
+ }
+ else if (!strcmp(charset, "LATIN9")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin9);
+ }
+ else if (!strcmp(charset, "LATIN10")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatin10);
+ }
+ else if (!strcmp(charset, "SQL_ASCII")) {
+ return NSASCIIStringEncoding;
+ }
+ else if (!strcmp(charset, "EUC_JP")) {
+ return NSJapaneseEUCStringEncoding;
+ }
+ else if (!strcmp(charset, "EUC_CN")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingEUC_CN);
+ }
+ else if (!strcmp(charset, "EUC_KR")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingEUC_KR);
+ }
+ else if (!strcmp(charset, "JOHAB")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingWindowsKoreanJohab);
+ }
+ else if (!strcmp(charset, "EUC_TW")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingEUC_TW);
+ }
+ else if (!strcmp(charset, "ISO_8859_5")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatinCyrillic);
+ }
+ else if (!strcmp(charset, "ISO_8859_6")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatinArabic);
+ }
+ else if (!strcmp(charset, "ISO_8859_7")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatinGreek);
+ }
+ else if (!strcmp(charset, "ISO_8859_8")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISOLatinHebrew);
+ }
+ else if (!strcmp(charset, "KOI8")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingKOI8_R);
+ }
+ else if (!strcmp(charset, "ALT")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingDOSRussian);
+ }
+ else if (!strcmp(charset, "WIN")) {
+ return NSWindowsCP1251StringEncoding;
+ }
+ else if (!strcmp(charset, "WIN1256")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingWindowsArabic);
+ }
+ else if (!strcmp(charset, "TCVN")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingWindowsVietnamese);
+ }
+ else if (!strcmp(charset, "WIN874")) {
+ return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingDOSThai);
+ }
+
+ NSLog(@"PostgresKit: Warning: Unable to process unknown PostgreSQL encoding '%s'; falling back to UTF8.", charset);
+
+ return FLXPostgresConnectionDefaultStringEncoding;
+}
+
+/**
+ * Translates the supplied encoding identifier to it's corresponding encoding name.
+ *
+ * @param stringEncoding The string encoding to translate
+ *
+ * @return The encoding name as a string or nil if there's no mapping.
+ */
++ (NSString *)postgreSQLCharsetForStringEncoding:(NSStringEncoding)stringEncoding
+{
+ switch (stringEncoding)
+ {
+ case NSASCIIStringEncoding:
+ return @"SQL_ASCII";
+
+ case NSJapaneseEUCStringEncoding:
+ return @"EUC_JP";
+
+ case NSUTF8StringEncoding:
+ case NSNonLossyASCIIStringEncoding:
+ return @"UNICODE";
+
+ case NSISOLatin1StringEncoding:
+ case NSWindowsCP1252StringEncoding:
+ return @"LATIN1";
+
+ case NSISOLatin2StringEncoding:
+ case NSWindowsCP1250StringEncoding:
+ return @"LATIN2";
+
+ case NSWindowsCP1251StringEncoding:
+ return @"WIN";
+
+ case NSWindowsCP1253StringEncoding:
+ return @"ISO_8859_7";
+
+ case NSWindowsCP1254StringEncoding:
+ return @"LATIN5";
+ }
+
+ return nil;
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.h
new file mode 100644
index 00000000..84864a1a
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.h
@@ -0,0 +1,56 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionParameters.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 29, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import <pthread.h>
+
+@class FLXPostgresConnection;
+
+@interface FLXPostgresConnectionParameters : NSObject
+{
+ FLXPostgresConnection *_connection;
+
+ NSMutableArray *_parameterNames;
+ NSMutableDictionary *_parameters;
+
+ pthread_mutex_t _readLock;
+}
+
+/**
+ * @property connection The database connection to use.
+ */
+@property (readwrite, assign) FLXPostgresConnection *connection;
+
+- (id)initWithConnection:(FLXPostgresConnection *)connection;
+
+- (BOOL)loadParameters;
+
+- (id)valueForParameter:(NSString *)parameter;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.m
new file mode 100644
index 00000000..f1161f89
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionParameters.m
@@ -0,0 +1,220 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionParameters.m
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on August 29, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import "FLXPostgresConnectionParameters.h"
+#import "FLXPostgresConnectionPrivateAPI.h"
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnectionParameters ()
+
+- (void)_loadParameters:(id)object;
+- (BOOL)_isBooleanParameterValue:(NSString *)value;
+- (BOOL)_booleanForParameterValue:(NSString *)value;
+
+@end
+
+@implementation FLXPostgresConnectionParameters
+
+@synthesize connection = _connection;
+
+#pragma mark -
+
+- (id)init
+{
+ return [self initWithConnection:nil];
+}
+
+/**
+ * Initialise a parameters instance with the supplied connection.
+ *
+ * @param connection The connection to use.
+ *
+ * @return The initialised instance.
+ */
+- (id)initWithConnection:(FLXPostgresConnection *)connection
+{
+ if ((self = [super init])) {
+ _connection = connection;
+
+ pthread_mutex_init(&_readLock, NULL);
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Public API
+
+/**
+ * Loads the database parameters.
+ *
+ * @return A BOOL indicating the success of the load.
+ */
+- (BOOL)loadParameters
+{
+ pthread_mutex_lock(&_readLock);
+
+ if (!_connection || ![_connection isConnected]) {
+ pthread_mutex_unlock(&_readLock);
+
+ return NO;
+ }
+
+ if (!_parameterNames) {
+ _parameterNames = [[NSMutableArray alloc] init];
+
+ [_parameterNames addObject:FLXPostgresParameterServerEncoding];
+ [_parameterNames addObject:FLXPostgresParameterClientEncoding];
+ [_parameterNames addObject:FLXPostgresParameterSuperUser];
+ [_parameterNames addObject:FLXPostgresParameterTimeZone];
+ [_parameterNames addObject:FLXPostgresParameterIntegerDateTimes];
+ }
+
+ pthread_mutex_unlock(&_readLock);
+
+ [self performSelectorInBackground:@selector(_loadParameters:) withObject:_parameterNames];
+
+ return YES;
+}
+
+/**
+ * Gets the object for the supplied parameter.
+ *
+ * @param parameter The name of the parameter to lookup.
+ *
+ * @return The parameter value or nil if parameters haven't been loaded or it can't be found.
+ */
+- (id)valueForParameter:(NSString *)parameter
+{
+ pthread_mutex_lock(&_readLock);
+
+ if (!_parameters || ![_parameters count]) {
+ pthread_mutex_unlock(&_readLock);
+
+ return nil;
+ }
+
+ id value = [_parameters objectForKey:parameter];
+
+ pthread_mutex_unlock(&_readLock);
+
+ return value;
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Loads the values of the supplied array of parameters by query the current connection.
+ *
+ * @param object The parameters to load.
+ */
+- (void)_loadParameters:(id)object
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ pthread_mutex_lock(&_readLock);
+
+ NSArray *parameters = (NSArray *)object;
+
+ if (!_parameters) {
+ _parameters = [[NSMutableDictionary alloc] initWithCapacity:[parameters count]];
+ }
+
+ for (NSString *parameter in parameters)
+ {
+ const char *value = PQparameterStatus([_connection postgresConnection], [parameter UTF8String]);
+
+ if (!value) continue;
+
+ NSString *stringValue = [NSString stringWithUTF8String:value];
+
+ id paramObject = [self _isBooleanParameterValue:stringValue] ? [NSNumber numberWithBool:[self _booleanForParameterValue:stringValue]] : stringValue;
+
+ [_parameters setObject:paramObject forKey:parameter];
+ }
+
+ pthread_mutex_unlock(&_readLock);
+
+ [pool release];
+}
+
+/**
+ * Determines whether or not the supplied value is a boolean value.
+ *
+ * @param value The value to look at.
+ *
+ * @return A BOOL indicating if the value is a boolean type.
+ */
+- (BOOL)_isBooleanParameterValue:(NSString *)value
+{
+ value = [value uppercaseString];
+
+ return
+ [value isEqualToString:@"ON"] ||
+ [value isEqualToString:@"YES"] ||
+ [value isEqualToString:@"TRUE"] ||
+ [value isEqualToString:@"OFF"] ||
+ [value isEqualToString:@"NO"] ||
+ [value isEqualToString:@"FALSE"];
+}
+
+/**
+ * Determines the boolean value for the supplied boolean string representation.
+ *
+ * @param value The value to look at.
+ *
+ * @return A BOOL indicating the value of the string representation.
+ */
+- (BOOL)_booleanForParameterValue:(NSString *)value
+{
+ value = [value uppercaseString];
+
+ return
+ [value isEqualToString:@"ON"] ||
+ [value isEqualToString:@"YES"] ||
+ [value isEqualToString:@"TRUE"];
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ _connection = nil;
+
+ pthread_mutex_destroy(&_readLock);
+
+ if (_parameters) [_parameters release], _parameters = nil;
+ if (_parameterNames) [_parameterNames release], _parameterNames = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.h
new file mode 100644
index 00000000..53bcf4ee
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.h
@@ -0,0 +1,38 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionPrivateAPI.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnection (FLXPostgresConnectionPrivateAPI)
+
+- (PGconn *)postgresConnection;
+- (void)_createConnectionParameters;
+
+@end
+
+@interface FLXPostgresConnection (FLXPostgresConnectionQueryPreparationPrivateAPI)
+
+- (BOOL)_prepare:(FLXPostgresStatement *)statement num:(int)paramNum types:(FLXPostgresOid *)paramTypes;
+
+@end
+
+
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.m
new file mode 100644
index 00000000..52610305
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionPrivateAPI.m
@@ -0,0 +1,29 @@
+//
+// FLXPostgresConnectionPrivateAPI.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnectionPrivateAPI.h"
+#import "FLXPostgresConnectionDelegateProtocol.h"
+#import "FLXPostgresResult.h"
+
+@implementation FLXPostgresConnection (FLXPostgresConnectionPrivateAPI)
+
+
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.h
new file mode 100644
index 00000000..b1c8aed0
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.h
@@ -0,0 +1,38 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionQueryExecution.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnection (FLXPostgresConnectionQueryExecution)
+
+// Synchronous interface
+- (FLXPostgresResult *)execute:(NSString *)query;
+- (FLXPostgresResult *)executeWithFormat:(NSString *)query, ...;
+- (FLXPostgresResult *)executePrepared:(FLXPostgresStatement *)statement;
+- (FLXPostgresResult *)execute:(NSString *)query values:(NSArray *)values;
+- (FLXPostgresResult *)execute:(NSString *)query value:(NSObject *)value;
+- (FLXPostgresResult *)executePrepared:(FLXPostgresStatement *)statement values:(NSArray *)values;
+- (FLXPostgresResult *)executePrepared:(FLXPostgresStatement *)statement value:(NSObject *)value;
+
+// Asynchronous interface
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.m
new file mode 100644
index 00000000..894338a7
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryExecution.m
@@ -0,0 +1,322 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionQueryExecution.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnectionQueryExecution.h"
+#import "FLXPostgresConnectionPrivateAPI.h"
+#import "FLXPostgresConnectionTypeHandling.h"
+#import "FLXPostgresConnectionDelegate.h"
+#import "FLXPostgresConnection.h"
+#import "FLXPostgresException.h"
+#import "FLXPostgresResult.h"
+#import "FLXPostgresTypeHandlerProtocol.h"
+#import "FLXPostgresStatement.h"
+
+// Constants
+static int FLXPostgresResultsAsBinary = 1;
+
+// Internal query structure
+typedef struct
+{
+ int paramNum;
+ const void **paramValues;
+ FLXPostgresOid* paramTypes;
+ int *paramLengths;
+ int *paramFormats;
+}
+FLXQueryParamData;
+
+@interface FLXPostgresConnection ()
+
+- (FLXPostgresResult *)_execute:(NSObject *)query values:(NSArray *)values;
+- (BOOL)_queryDidError:(PGresult *)result;
+- (FLXQueryParamData *)_createParameterDataStructureWithCount:(int)paramNum;
+- (void)_destroyParamDataStructure:(FLXQueryParamData *)paramData;
+
+@end
+
+@implementation FLXPostgresConnection (FLXPostgresConnectionQueryExecution)
+
+#pragma mark -
+#pragma mark Synchronous Interface
+
+- (FLXPostgresResult *)execute:(NSString *)query
+{
+ return [self _execute:query values:nil];
+}
+
+- (FLXPostgresResult *)execute:(NSString *)query value:(NSObject *)value
+{
+ return [self _execute:query values:[NSArray arrayWithObject:value]];
+}
+
+- (FLXPostgresResult *)executePrepared:(FLXPostgresStatement *)statement value:(NSObject *)value
+{
+ return [self _execute:statement values:[NSArray arrayWithObject:value]];
+}
+
+- (FLXPostgresResult *)executePrepared:(FLXPostgresStatement *)statement
+{
+ return [self _execute:statement values:nil];
+}
+
+- (FLXPostgresResult *)executePrepared:(FLXPostgresStatement *)statement values:(NSArray *)values
+{
+ return [self _execute:statement values:values];
+}
+
+- (FLXPostgresResult *)execute:(NSString *)query values:(NSArray *)values
+{
+ return [self _execute:query values:values];
+}
+
+- (FLXPostgresResult *)executeWithFormat:(NSString *)query, ...
+{
+ va_list argumentList;
+ va_start(argumentList, query);
+
+ NSMutableString *string = [[NSMutableString alloc] init];
+
+ CFStringAppendFormatAndArguments((CFMutableStringRef)string, (CFDictionaryRef)nil, (CFStringRef)query, argumentList);
+
+ va_end(argumentList);
+
+ FLXPostgresResult *result = [self _execute:string values:nil];
+
+ [string release];
+
+ return result;
+}
+
+#pragma mark -
+#pragma mark Asynchronous Interface
+
+#pragma mark -
+#pragma mark Private API
+
+- (FLXPostgresResult *)_execute:(NSObject *)query values:(NSArray *)values
+{
+ _lastQueryWasCancelled = NO;
+
+ if (![self isConnected] || !query || ![query isKindOfClass:[NSString class]] || [query isKindOfClass:[FLXPostgresStatement class]]) return nil;
+
+ // Notify the delegate
+ if (_delegate && _delegateSupportsWillExecute) {
+ [_delegate connection:self willExecute:query values:values];
+ }
+
+ FLXQueryParamData *paramData = [self _createParameterDataStructureWithCount:values ? (int)[values count] : 0];
+
+ if (!paramData) return nil;
+
+ // Fill the data structures
+ for (int i = 0; i < paramData->paramNum; i++)
+ {
+ id nativeObject = [values objectAtIndex:i];
+
+ NSParameterAssert(nativeObject);
+
+ // Deterime if bound value is an NSNull
+ if ([nativeObject isKindOfClass:[NSNull class]]) {
+ paramData->paramValues[i] = NULL;
+ paramData->paramTypes[i] = 0;
+ paramData->paramLengths[i] = 0;
+ paramData->paramFormats[i] = 0;
+
+ continue;
+ }
+
+ // Obtain correct handler for this class
+ id <FLXPostgresTypeHandlerProtocol> typeHandler = [self typeHandlerForClass:[nativeObject class]];
+
+ if (!typeHandler) {
+ [self _destroyParamDataStructure:paramData];
+
+ // TODO: get rid of exceptions
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain reason:[NSString stringWithFormat:@"Parameter $%u unsupported class %@", (i + 1), NSStringFromClass([nativeObject class])]];
+ return nil;
+ }
+
+ FLXPostgresOid type = 0;
+ NSData *data = [typeHandler remoteDataFromObject:nativeObject type:&type];
+
+ if (!data) {
+ [self _destroyParamDataStructure:paramData];
+
+ // TODO: get rid of exceptions
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain reason:[NSString stringWithFormat:@"Parameter $%u cannot be converted into a bound value", (i + 1)]];
+ return nil;
+ }
+
+ // Check length of data
+ if ([data length] > INT_MAX) {
+ [self _destroyParamDataStructure:paramData];
+
+ // TODO: get rid of exceptions
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain reason:[NSString stringWithFormat:@"Bound value $%u exceeds maximum size", (i + 1)]];
+ return nil;
+ }
+
+ // Assign data
+ paramData->paramTypes[i] = type;
+
+ // NOTE: if data length is zero, we encode as text instead, as NSData returns 0 for
+ // empty data, and it gets encoded as a NULL.
+ if ([data length] == 0) {
+ paramData->paramValues[i] = "";
+ paramData->paramFormats[i] = 0;
+ paramData->paramLengths[i] = 0;
+ }
+ else {
+ // Send as binary data
+ paramData->paramValues[i] = [data bytes];
+ paramData->paramLengths[i] = (int)[data length];
+ paramData->paramFormats[i] = 1;
+ }
+ }
+
+ // Execute the command - return data in binary
+ PGresult *result = nil;
+
+ if ([query isKindOfClass:[NSString class]]) {
+
+ result = PQexecParams(_connection,
+ [(NSString *)query UTF8String],
+ paramData->paramNum,
+ paramData->paramTypes,
+ (const char **)paramData->paramValues,
+ (const int *)paramData->paramLengths,
+ (const int *)paramData->paramFormats,
+ FLXPostgresResultsAsBinary);
+ }
+ else if ([query isKindOfClass:[FLXPostgresStatement class]]) {
+ FLXPostgresStatement *statement = (FLXPostgresStatement *)query;
+
+ // Statement has not been prepared yet, so prepare it with the given parameter types
+ if (![statement name]) {
+ BOOL prepareResult = [self _prepare:statement num:paramData->paramNum types:paramData->paramTypes];
+
+ if (!prepareResult || ![statement name]) return nil;
+ }
+
+ result = PQexecPrepared(_connection,
+ [statement UTF8Name],
+ paramData->paramNum,
+ (const char **)paramData->paramValues,
+ (const int *)paramData->paramLengths,
+ (const int *)paramData->paramFormats,
+ FLXPostgresResultsAsBinary);
+ }
+ else {
+ // TODO: get rid of exceptions
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain reason:[NSString stringWithFormat:@"Trying to execute a query that is not of type NSString or FLXPostgresStatement"]];
+ return nil;
+ }
+
+ [self _destroyParamDataStructure:paramData];
+
+ if (!result || [self _queryDidError:result]) return nil;
+
+ return [[[FLXPostgresResult alloc] initWithResult:result connection:self] autorelease];
+}
+
+/**
+ * Determines whether or not the supplied result indicates an error occurred.
+ *
+ * @param result The result to examine.
+ *
+ * @return A BOOL indicating if an error occurred.
+ */
+- (BOOL)_queryDidError:(PGresult *)result
+{
+ ExecStatusType status = PQresultStatus(result);
+
+ if (status == PGRES_BAD_RESPONSE || status == PGRES_FATAL_ERROR) {
+ NSString *error = [NSString stringWithUTF8String:PQresultErrorMessage(result)];
+
+ if (_lastErrorMessage) [_lastErrorMessage release], _lastErrorMessage = nil;
+
+ _lastErrorMessage = [[NSString alloc] initWithString:error];
+
+ PQclear(result);
+
+ return YES;
+ }
+
+ return NO;
+}
+
+/**
+ * Creates the internal query parameter data structure.
+ *
+ * @note This method will throw an exception if it can't allocated the required memory.
+ *
+ * @param paramNum The number of parameters the structure should accommodate.
+ *
+ * @return The data structure or nil if an exception occurred.
+ */
+- (FLXQueryParamData *)_createParameterDataStructureWithCount:(int)paramNum
+{
+ FLXQueryParamData *paramData = malloc(sizeof(FLXQueryParamData));
+
+ paramData->paramNum = paramNum;
+ paramData->paramValues = NULL;
+ paramData->paramTypes = NULL;
+ paramData->paramLengths = NULL;
+ paramData->paramFormats = NULL;
+
+ if (paramData->paramNum) {
+ paramData->paramValues = malloc(sizeof(void *) * paramData->paramNum);
+ paramData->paramTypes = malloc(sizeof(FLXPostgresOid) * paramData->paramNum);
+ paramData->paramLengths = malloc(sizeof(int) * paramData->paramNum);
+ paramData->paramFormats = malloc(sizeof(int) * paramData->paramNum);
+
+ if (!paramData->paramValues || !paramData->paramLengths || !paramData->paramFormats) {
+ [self _destroyParamDataStructure:paramData];
+
+ // Probably justifies throwing an exception if we can't allocate any memory!
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain reason:@"Memory allocation error"];
+
+ return nil;
+ }
+ }
+
+ return paramData;
+}
+
+/**
+ * Frees the memory associated with the supplied parameter data structure.
+ *
+ * @param paramData The parameter data to destroy.
+ */
+- (void)_destroyParamDataStructure:(FLXQueryParamData *)paramData
+{
+ if (!paramData) return;
+
+ if (paramData->paramValues) free(paramData->paramValues);
+ if (paramData->paramTypes) free(paramData->paramTypes);
+ if (paramData->paramLengths) free(paramData->paramLengths);
+ if (paramData->paramFormats) free(paramData->paramFormats);
+
+ free(paramData);
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.h
new file mode 100644
index 00000000..1d769b51
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.h
@@ -0,0 +1,32 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionQueryPreparation.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnection (FLXPostgresConnectionQueryPreparation)
+
+- (NSString *)quote:(NSObject *)object;
+
+- (FLXPostgresStatement *)prepare:(NSString *)query;
+- (FLXPostgresStatement *)prepareWithFormat:(NSString *)query, ...;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.m
new file mode 100644
index 00000000..d8bf59b7
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionQueryPreparation.m
@@ -0,0 +1,131 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionQueryPreparation.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnectionQueryPreparation.h"
+#import "FLXPostgresConnectionTypeHandling.h"
+#import "FLXPostgresConnectionPrivateAPI.h"
+#import "FLXPostgresStatement.h"
+#import "FLXPostgresException.h"
+
+@implementation FLXPostgresConnection (FLXPostgresConnectionQueryPreparation)
+
+/**
+ * Quotes the supplied object in accordance with it's data type.
+ *
+ * @param object The object to quote.
+ *
+ * @return A string representation of the quoted object.
+ */
+- (NSString *)quote:(NSObject *)object
+{
+ if (!object || [object isKindOfClass:[NSNull class]]) return @"NULL";
+
+ id <FLXPostgresTypeHandlerProtocol> handler = [self typeHandlerForClass:[object class]];
+
+ if (!handler) {
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain
+ reason:[NSString stringWithFormat:@"Unsupported class '%@'", NSStringFromClass([object class])]];
+
+ return nil;
+ }
+
+ return [handler quotedStringFromObject:object];
+}
+
+/**
+ * Creates a prepared statment from the supplied query.
+ *
+ * @param query The query to create the statement from.
+ *
+ * @return The prepared statement instance.
+ */
+- (FLXPostgresStatement *)prepare:(NSString *)query
+{
+ if (!query || ![query length]) return nil;
+
+ return [[[FLXPostgresStatement alloc] initWithStatement:query] autorelease];
+}
+
+/**
+ * Creates a prepared statment from the supplied query format and values.
+ *
+ * @param query The query to create the statement from.
+ * @param ... Any values to insert into the query (optional).
+ *
+ * @return The prepared statement instance.
+ */
+- (FLXPostgresStatement *)prepareWithFormat:(NSString *)query, ...
+{
+ if (!query || ![query length]) return nil;
+
+ va_list args;
+ va_start(args, query);
+
+ NSMutableString *string = [[NSMutableString alloc] initWithFormat:query arguments:args];
+
+ va_end(args);
+
+ FLXPostgresStatement *statement = [self prepare:string];
+
+ [string release];
+
+ return statement;
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Actually prepares the supplied statement against the database.
+ *
+ * @param statement The statement to prepare.
+ * @param paranNum The number of parameters the statement contains.
+ * @param paramTypes Any of Postgres parameter types.
+ *
+ * @return A BOOL indicating succes. Returns NO if there's no statement, statement name or current connection.
+ */
+- (BOOL)_prepare:(FLXPostgresStatement *)statement num:(int)paramNum types:(FLXPostgresOid *)paramTypes
+{
+ if (!statement || ![statement name] || ![self isConnected]) return NO;
+
+ NSString *name = [[NSProcessInfo processInfo] globallyUniqueString];
+
+ PGresult *result = PQprepare(_connection, [name UTF8String], [statement UTF8Statement], paramNum, paramTypes);
+
+ if (!result) return NO;
+
+ ExecStatusType resultStatus = PQresultStatus(result);
+
+ if (resultStatus == PGRES_BAD_RESPONSE || resultStatus == PGRES_FATAL_ERROR) {
+ PQclear(result);
+
+ return NO;
+ }
+
+ PQclear(result);
+
+ [statement setName:name];
+
+ return YES;
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h
new file mode 100644
index 00000000..351b1d24
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.h
@@ -0,0 +1,33 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionTypeHandling.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on July 29, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnection (FLXPostgresConnectionTypeHandling)
+
+- (void)registerTypeHandlers;
+
+- (id <FLXPostgresTypeHandlerProtocol>)typeHandlerForClass:(Class)class;
+- (id <FLXPostgresTypeHandlerProtocol>)typeHandlerForRemoteType:(FLXPostgresOid)type;
+
+- (void)registerTypeHandler:(Class)handlerClass;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.m
new file mode 100644
index 00000000..bd46e788
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionTypeHandling.m
@@ -0,0 +1,105 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionTypeHandling.m
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on July 29, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnectionTypeHandling.h"
+#import "FLXPostgresTypeStringHandler.h"
+#import "FLXPostgresTypeNumberHandler.h"
+#import "FLXPostgresException.h"
+
+@implementation FLXPostgresConnection (FLXPostgresConnectionTypeHandling)
+
+/**
+ * Register all of our data type handlers for this connection.
+ */
+- (void)registerTypeHandlers
+{
+ if (_typeMap) {
+ [_typeMap release];
+
+ _typeMap = [[NSMutableDictionary alloc] init];
+ }
+
+ [self registerTypeHandler:[FLXPostgresTypeStringHandler class]];
+ [self registerTypeHandler:[FLXPostgresTypeNumberHandler class]];
+}
+
+/**
+ * Get the data type handler for the supplied class.
+ *
+ * @param class The class to get the handler for.
+ *
+ * @return The handler or nil if there's none associated with the class.
+ */
+- (id <FLXPostgresTypeHandlerProtocol>)typeHandlerForClass:(Class)class
+{
+ return [_typeMap objectForKey:NSStringFromClass(class)];
+}
+
+/**
+ * Get the data type handler for the supplied PostgreSQL type.
+ *
+ * @param type The PostgreSQL type to get the handler for.
+ *
+ * @return The handler or nil if there's none associated with the type.
+ */
+- (id <FLXPostgresTypeHandlerProtocol>)typeHandlerForRemoteType:(FLXPostgresOid)type
+{
+ return [_typeMap objectForKey:[NSNumber numberWithUnsignedInteger:type]];
+}
+
+/**
+ * Register the supplied type handler class.
+ *
+ * @param handlerClass The handler class to register.
+ */
+- (void)registerTypeHandler:(Class)handlerClass
+{
+ if (![handlerClass conformsToProtocol:@protocol(FLXPostgresTypeHandlerProtocol)]) {
+ [FLXPostgresException raise:FLXPostgresConnectionErrorDomain
+ reason:@"Class '%@' does not conform to protocol '%@'", NSStringFromClass(handlerClass), NSStringFromProtocol(@protocol(FLXPostgresTypeHandlerProtocol))];
+ }
+
+ // Create an instance of this class
+ id <FLXPostgresTypeHandlerProtocol> handler = [[[handlerClass alloc] initWithConnection:self] autorelease];
+
+ // Add to the type map - for native class
+ [_typeMap setObject:handler forKey:NSStringFromClass([handler nativeClass])];
+
+ NSArray *aliases = [handler classAliases];
+
+ if (aliases) {
+ for (NSString *alias in aliases)
+ {
+ [_typeMap setObject:handler forKey:alias];
+ }
+ }
+
+ FLXPostgresOid *remoteTypes = [handler remoteTypes];
+
+ for (NSUInteger i = 0; remoteTypes[i]; i++)
+ {
+ NSNumber *key = [NSNumber numberWithUnsignedInteger:remoteTypes[i]];
+
+ [_typeMap setObject:handler forKey:key];
+ }
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.h b/Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.h
new file mode 100644
index 00000000..60eacfea
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.h
@@ -0,0 +1,33 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionUtils.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnection.h"
+
+@interface FLXPostgresConnection (FLXPostgresConnectionUtils)
+
+- (NSArray *)schemas;
+- (NSArray *)databases;
+- (NSArray *)tablesInSchema:(NSString *)schema;
+- (NSArray *)columnNamesForTable:(NSString *)table inSchema:(NSString *)schema;
+- (NSString *)primaryKeyForTable:(NSString *)table inSchema:(NSString *)schema;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.m b/Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.m
new file mode 100644
index 00000000..e988c7f2
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresConnectionUtils.m
@@ -0,0 +1,133 @@
+//
+// $Id$
+//
+// FLXPostgresConnectionUtils.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresConnectionQueryPreparation.h"
+#import "FLXPostgresConnectionQueryExecution.h"
+#import "FLXPostgresResult.h"
+
+@interface FLXPostgresConnection ()
+
+- (NSArray *)_executeAndReturnResult:(NSString *)query;
+
+@end
+
+@implementation FLXPostgresConnection (FLXPostgresConnectionUtils)
+
+/**
+ * Returns an array of all databases.
+ *
+ * @return An array of strings or nil if no connection is present.
+ */
+- (NSArray *)databases
+{
+ return [self isConnected] ? [self _executeAndReturnResult:@"SELECT DISTINCT \"catalog_name\" FROM \"information_schema\".\"schemata\""] : nil;
+}
+
+/**
+ * Returns an array of all schemas.
+ *
+ * @return An array of strings or nil if no connection is present.
+ */
+- (NSArray *)schemas
+{
+ return [self isConnected] ? [self _executeAndReturnResult:[NSString stringWithFormat:@"SELECT \"schema_name\" FROM \"information_schema\".\"schemata\" WHERE \"catalog_name\" = %@", [self quote:[self database]]]] : nil;
+}
+
+/**
+ * Returns an array of tables in the supplied schema.
+ *
+ * @param schem The schema to get tables for.
+ *
+ * @return An array of strings or nil if not connected or parameters are not valid.
+ */
+- (NSArray * )tablesInSchema:(NSString *)schema
+{
+ if (![self isConnected] || !schema || ![schema length]) return nil;
+
+ return [self _executeAndReturnResult:[NSString stringWithFormat:@"SELECT \"table_name\" FROM \"information_schema\".\"tables\" WHERE \"table_catalog\" = %@ AND \"table_schema\" = %@ AND \"table_type\" = 'BASE TABLE'", [self quote:[self database]], [self quote:schema]]];
+}
+
+/**
+ * Get the primary key column name on the supplied table in the supplied schema.
+ *
+ * @param table The table to get the primary key for.
+ * @param schema The schem the table belongs to.
+ *
+ * @return The column name as a string or nil not connected or parameters are not valid.
+ */
+- (NSString *)primaryKeyForTable:(NSString *)table inSchema:(NSString *)schema
+{
+ if (![self isConnected] || !table || ![table length] || !schema || ![schema length]) return nil;
+
+ NSString *join = @"\"information_schema\".\"table_constraints\" t INNER JOIN \"information_schema\".\"key_column_usage\" k ON t.\"constraint_name\" = k.\"constraint_name\"";
+ NSString *where = [NSString stringWithFormat:@"t.\"constraint_type\" = 'PRIMARY KEY' AND t.\"table_catalog\" = %@ AND t.\"table_schema\" = %@ AND t.\"table_name\" = %@", [self quote:[self database]], [self quote:schema], [self quote:table]];
+
+ FLXPostgresResult *result = [self executeWithFormat:@"SELECT k.\"column_name\" FROM %@ WHERE %@", join, where];
+
+ return [result numberOfRows] == 0 ? nil : [[result rowAsArray] objectAtIndex:0];
+}
+
+/**
+ * Returns an array of column names for the supplied table and schema.
+ *
+ * @param table The table to get column names from.
+ * @param schema The schem the table belongs to.
+ *
+ * @return An array of strings or nil if not connected or parameters are not valid.
+ */
+- (NSArray *)columnNamesForTable:(NSString *)table inSchema:(NSString *)schema
+{
+ if (![self isConnected] || !table || ![table length] || !schema || ![schema length]) return nil;
+
+ return [self _executeAndReturnResult:[NSString stringWithFormat:@"SELECT \"column_name\" FROM \"information_schema\".\"columns\" WHERE \"table_catalog\" = %@ AND \"table_schema\" = %@ AND \"table_name\" = %@", [self quote:[self database]], [self quote:schema], [self quote:table]]];
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Executes the supplied query and returns the result.
+ *
+ * @param query The query to execute.
+ *
+ * @return The result as an array.
+ */
+- (NSArray *)_executeAndReturnResult:(NSString *)query
+{
+ FLXPostgresResult *result = [self execute:query];
+
+ if (!result || ![result numberOfRows]) return nil;
+
+ NSArray *row = nil;
+ NSMutableArray *data = [NSMutableArray arrayWithCapacity:(NSUInteger)[result numberOfRows]];
+
+ while ((row = [result rowAsArray]))
+ {
+ if (![row count]) continue;
+
+ [data addObject:[row objectAtIndex:0]];
+ }
+
+ return data;
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresError.h b/Frameworks/PostgresKit/Source/FLXPostgresError.h
new file mode 100644
index 00000000..e9009ecb
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresError.h
@@ -0,0 +1,74 @@
+//
+// $Id$
+//
+// FLXPostgresError.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 3, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+@interface FLXPostgresError : NSObject
+{
+ NSString *_errorSeverity;
+ NSString *_errorStateCode;
+ NSString *_errorPrimaryMessage;
+ NSString *_errorDetailMessage;
+ NSString *_errorMessageHint;
+
+ NSUInteger _errorStatementPosition;
+}
+
+/**
+ * @property errorSeverity
+ */
+@property (readonly) NSString *errorSeverity;
+
+/**
+ * @property errorStateCode
+ */
+@property (readonly) NSString *errorStateCode;
+
+/**
+ * @property errorPrimaryMessage
+ */
+@property (readonly) NSString *errorPrimaryMessage;
+
+/**
+ * @property errorDetailMessage
+ */
+@property (readonly) NSString *errorDetailMessage;
+
+/**
+ * @property errorMessageHint
+ */
+@property (readonly) NSString *errorMessageHint;
+
+/**
+ * @property errorStatementPosition
+ */
+@property (readonly) NSUInteger errorStatementPosition;
+
+- (id)initWithResult:(PGresult *)result;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresError.m b/Frameworks/PostgresKit/Source/FLXPostgresError.m
new file mode 100644
index 00000000..6a0a6210
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresError.m
@@ -0,0 +1,136 @@
+//
+// $Id$
+//
+// FLXPostgresError.m
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 3, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import "FLXPostgresError.h"
+#import "FLXPostgresException.h"
+
+@interface FLXPostgresError ()
+
+- (void)_extractErrorDetailsFromResult:(PGresult *)result;
+- (NSString *)_extractErrorField:(int)field fromResult:(PGresult *)result;
+
+@end
+
+@implementation FLXPostgresError
+
+@synthesize errorSeverity = _errorSeverity;
+@synthesize errorStateCode = _errorStateCode;
+@synthesize errorPrimaryMessage = _errorPrimaryMessage;
+@synthesize errorDetailMessage = _errorDetailMessage;
+@synthesize errorMessageHint = _errorMessageHint;
+@synthesize errorStatementPosition = _errorStatementPosition;
+
+#pragma mark -
+
+- (id)init
+{
+ [FLXPostgresException raise:NSInternalInconsistencyException
+ reason:@"%@ shouldn't be init'd directly; use initWithResult: instead.", [self className]];
+
+ return nil;
+}
+
+- (id)initWithResult:(PGresult *)result
+{
+ if ((self = [super init])) {
+
+ _errorSeverity = nil;
+ _errorStateCode = nil;
+ _errorPrimaryMessage = nil;
+ _errorDetailMessage = nil;
+ _errorMessageHint = nil;
+ _errorStatementPosition = -1;
+
+ if (result) [self _extractErrorDetailsFromResult:result];
+ }
+
+ return self;
+}
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"<%@: Sev %@ (%@): %@>", [self className], _errorSeverity, _errorStateCode, _errorPrimaryMessage];
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Extracts all the error information from the supplied result.
+ *
+ * @param result The Postgres result to extract the information from.
+ */
+- (void)_extractErrorDetailsFromResult:(PGresult *)result
+{
+ // Note that we don't expose all the fields that are available.
+ // The ones we don't mostly include information internal to Postgres
+ // that generally isn't useful to end users.
+ _errorSeverity = [self _extractErrorField:PG_DIAG_SEVERITY fromResult:result];
+ _errorStateCode = [self _extractErrorField:PG_DIAG_SQLSTATE fromResult:result];
+ _errorPrimaryMessage = [self _extractErrorField:PG_DIAG_MESSAGE_PRIMARY fromResult:result];
+ _errorDetailMessage = [self _extractErrorField:PG_DIAG_MESSAGE_DETAIL fromResult:result];
+ _errorMessageHint = [self _extractErrorField:PG_DIAG_MESSAGE_HINT fromResult:result];
+
+ NSString *statementPosition = [self _extractErrorField:PG_DIAG_STATEMENT_POSITION fromResult:result];
+
+ _errorStatementPosition = [statementPosition integerValue];
+
+ [statementPosition release];
+}
+
+/**
+ * Extracts the supplied error field from the supplied Postgres result.
+ *
+ * @param field The error field to extract.
+ * @param result The Postgres result to extract the field from.
+ *
+ * @return A string representing the error value. The caller is responsible for freeing the associated memory.
+ */
+- (NSString *)_extractErrorField:(int)field fromResult:(PGresult *)result
+{
+ const char *errorData = PQresultErrorField(result, field);
+
+ return [[NSString alloc] initWithBytes:errorData length:strlen(errorData) encoding:NSUTF8StringEncoding];
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ if (_errorSeverity) [_errorSeverity release], _errorSeverity = nil;
+ if (_errorStateCode) [_errorStateCode release], _errorStateCode = nil;
+ if (_errorPrimaryMessage) [_errorPrimaryMessage release], _errorPrimaryMessage = nil;
+ if (_errorDetailMessage) [_errorDetailMessage release], _errorDetailMessage = nil;
+ if (_errorMessageHint) [_errorMessageHint release], _errorMessageHint = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresException.h b/Frameworks/PostgresKit/Source/FLXPostgresException.h
new file mode 100644
index 00000000..54b781c4
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresException.h
@@ -0,0 +1,28 @@
+//
+// $Id$
+//
+// FLXPostgresException.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+@interface FLXPostgresException : NSException
+
++ (void)raise:(NSString *)name connection:(void *)connection;
++ (void)raise:(NSString *)name reason:(NSString *)reason, ...;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresException.m b/Frameworks/PostgresKit/Source/FLXPostgresException.m
new file mode 100644
index 00000000..266ac1a7
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresException.m
@@ -0,0 +1,64 @@
+//
+// $Id$
+//
+// FLXPostgresException.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresException.h"
+
+@implementation FLXPostgresException
+
+/**
+ * Raise a new exception with the supplied details.
+ *
+ * @param name The name of the exception to raise.
+ * @param connection The connection associated with the exception being raised.
+ */
++ (void)raise:(NSString *)name connection:(void *)connection
+{
+ const char *errorMessage = "Unknown error";
+
+ if (connection) errorMessage = PQerrorMessage(connection);
+
+ errorMessage = strlen(errorMessage) ? errorMessage : "Unknown error";
+
+ [[[[FLXPostgresException alloc] initWithName:name reason:[NSString stringWithUTF8String:errorMessage] userInfo:nil] autorelease] raise];
+}
+
+/**
+ * Raise a new exception with the supplied details.
+ *
+ * @param name The name of the exception to raise.
+ * @param reason The reason for the exception being raised.
+ */
++ (void)raise:(NSString *)name reason:(NSString *)reason, ...
+{
+ va_list args;
+ va_start(args, reason);
+
+ NSString *reasonMessage = [[NSString alloc] initWithFormat:reason arguments:args];
+
+ va_end(args);
+
+ [[[[FLXPostgresException alloc] initWithName:name reason:reasonMessage userInfo:nil] autorelease] raise];
+
+ [reasonMessage release];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresResult.h b/Frameworks/PostgresKit/Source/FLXPostgresResult.h
new file mode 100644
index 00000000..e198cee5
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresResult.h
@@ -0,0 +1,71 @@
+//
+// $Id$
+//
+// FLXPostgresResult.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "libpq-fe.h"
+#import "FLXConstants.h"
+
+@class FLXPostgresConnection;
+
+@interface FLXPostgresResult : NSObject
+{
+ void *_result;
+ void **_typeHandlers;
+
+ unsigned long long _row;
+ unsigned int _numberOfFields;
+ unsigned long long _numberOfRows;
+
+ NSString **_fields;
+
+ NSStringEncoding _stringEncoding;
+
+ FLXPostgresConnection *_connection;
+}
+
+/**
+ * @property numberOfFields The number of fields this result has.
+ */
+@property (readonly) unsigned int numberOfFields;
+
+/**
+ * @property numberOfRows The number or rows this result has.
+ */
+@property (readonly) unsigned long long numberOfRows;
+
+/**
+ * @property stringEncoding The ecoding that was in use when this result was created.
+ */
+@property (readonly) NSStringEncoding stringEncoding;
+
+- (id)initWithResult:(PGresult *)result connection:(FLXPostgresConnection *)connection;
+
+- (unsigned int)numberOfFields;
+
+- (void)seekToRow:(unsigned long long)row;
+
+- (NSArray *)fields;
+
+- (NSArray *)rowAsArray;
+- (NSDictionary *)rowAsDictionary;
+- (id)rowAsType:(FLXPostgresResultRowType)type;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresResult.m b/Frameworks/PostgresKit/Source/FLXPostgresResult.m
new file mode 100644
index 00000000..62e0d222
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresResult.m
@@ -0,0 +1,264 @@
+//
+// $Id$
+//
+// FLXPostgresResult.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresResult.h"
+#import "FLXPostgresException.h"
+#import "FLXPostgresConnection.h"
+#import "FLXPostgresConnectionTypeHandling.h"
+
+static NSString *FLXPostgresResultError = @"FLXPostgresResultError";
+
+@interface FLXPostgresResult ()
+
+- (void)_populateFields;
+- (id)_objectForRow:(unsigned int)row column:(unsigned int)column;
+- (id <FLXPostgresTypeHandlerProtocol>)_typeHandlerForColumn:(unsigned int)column;
+
+@end
+
+@implementation FLXPostgresResult
+
+@synthesize numberOfRows = _numberOfRows;
+@synthesize numberOfFields = _numberOfFields;
+@synthesize stringEncoding = _stringEncoding;
+
+#pragma mark -
+#pragma mark Initialisation
+
+/**
+ * Prevent normal initialisation.
+ *
+ * @return nil
+ */
+- (id)init
+{
+ [FLXPostgresException raise:NSInternalInconsistencyException reason:@"%@ shouldn't be init'd directly; use initWithResult:connection: instead.", [self className]];
+
+ return nil;
+}
+
+/**
+ * Initialises a result with the supplied details.
+ *
+ * @param result The underlying PostgreSQL result this wrapper represents.
+ * @param connection The connection the result came from.
+ *
+ * @return The result wrapper.
+ */
+- (id)initWithResult:(PGresult *)result connection:(FLXPostgresConnection *)connection
+{
+ NSParameterAssert(result);
+
+ if ((self = [super init])) {
+
+ _row = 0;
+ _result = result;
+ _numberOfRows = PQntuples(_result);
+ _numberOfFields = PQnfields(_result);
+ _connection = [connection retain];
+
+ _stringEncoding = [_connection stringEncoding];
+
+ _typeHandlers = (void **)calloc(sizeof(void *), _numberOfFields);
+
+ unsigned long long affectedRows = (unsigned long long)[[NSString stringWithUTF8String:PQcmdTuples(_result)] longLongValue];
+
+ _numberOfRows = PQresultStatus(_result) == PGRES_TUPLES_OK ? _numberOfRows : affectedRows;
+
+ [self _populateFields];
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Public API
+
+/**
+ * This result's fields as an array.
+ *
+ * @return The array of fields.
+ */
+- (NSArray *)fields
+{
+ return [NSArray arrayWithObjects:_fields count:_numberOfFields];
+}
+
+/**
+ * Sets the current row marker to the supplied row.
+ *
+ * @param row The row to seek to.
+ */
+- (void)seekToRow:(unsigned long long)row
+{
+ if (row >= _numberOfRows) row = _numberOfRows - 1;
+
+ _row = row;
+}
+
+#pragma mark -
+#pragma mark Data Retrieval
+
+/**
+ * Return the current row as an array.
+ *
+ * @return The array of data.
+ */
+- (NSArray *)rowAsArray
+{
+ return [self rowAsType:FLXPostgresResultRowAsArray];
+}
+
+/**
+ * Return the current row as dictionary with keys as field names and values as the data.
+ *
+ * @return The row as a dictionary.
+ */
+- (NSDictionary *)rowAsDictionary
+{
+ return [self rowAsType:FLXPostgresResultRowAsDictionary];
+}
+
+/**
+ * Return the current row in the format specified by the supplied type.
+ *
+ * @return The data row as either an array or dictionary.
+ */
+- (id)rowAsType:(FLXPostgresResultRowType)type
+{
+ if (_row >= _numberOfRows) return nil;
+
+ id data;
+
+ data = (type == FLXPostgresResultRowAsArray) ? [NSMutableArray arrayWithCapacity:_numberOfFields] : [NSMutableDictionary dictionaryWithCapacity:_numberOfFields];
+
+ for (unsigned int i = 0; i < _numberOfFields; i++)
+ {
+ id object = [self _objectForRow:(int)_row column:i];
+
+ if (type == FLXPostgresResultRowAsArray) {
+ [(NSMutableArray *)data addObject:object];
+ }
+ else {
+ [(NSMutableDictionary *)data setObject:object forKey:_fields[i]];
+ }
+ }
+
+ _row++;
+
+ return data;
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Populates the internal field names array.
+ */
+- (void)_populateFields
+{
+ _fields = malloc(sizeof(NSString *) * _numberOfFields);
+
+ for (unsigned int i = 0; i < _numberOfFields; i++)
+ {
+ const char *bytes = PQfname(_result, i);
+
+ if (!bytes) continue;
+
+ _fields[i] = [[NSString alloc] initWithBytes:bytes length:strlen(bytes) encoding:_stringEncoding];
+ }
+}
+
+/**
+ * Get the native object at the supplied row and column.
+ *
+ * @param row The row index to get the data from.
+ * @param column The column index to get the data from.
+ *
+ * @return The native object or nil if out of this result's range.
+ */
+- (id)_objectForRow:(unsigned int)row column:(unsigned int)column
+{
+ if (row >= _numberOfRows || column >= _numberOfFields) return nil;
+
+ // Check for null
+ if (PQgetisnull(_result, row, column)) return [NSNull null];
+
+ // Get bytes and length
+ const void *bytes = PQgetvalue(_result, row, column);
+
+ NSUInteger length = PQgetlength(_result, row, column);
+ FLXPostgresOid type = PQftype(_result, column);
+
+ // Get handler for this type
+ id <FLXPostgresTypeHandlerProtocol> handler = [self _typeHandlerForColumn:column];
+
+ if (!handler) {
+ NSLog(@"PostgresKit: Warning: No type handler found for type %d, return NSData.", type);
+
+ return [NSData dataWithBytes:bytes length:length];
+ }
+
+ return [handler objectFromRemoteData:bytes length:length type:type];
+}
+
+/**
+ * Get the data type handler for the supplied column index.
+ *
+ * @param column The column index to get the handler for.
+ *
+ * @return The type handler or nil if out of this result's range.
+ */
+- (id <FLXPostgresTypeHandlerProtocol>)_typeHandlerForColumn:(unsigned int)column
+{
+ if (column >= _numberOfFields) return nil;
+
+ id handler = _typeHandlers[column];
+
+ if (!handler) {
+ FLXPostgresOid type = PQftype(_result, column);
+
+ _typeHandlers[column] = [_connection typeHandlerForRemoteType:type];
+
+ handler = _typeHandlers[column];
+ }
+
+ return handler;
+}
+
+#pragma mark -
+
+-(void)dealloc
+{
+ PQclear(_result);
+
+ for (unsigned int i = 0; i < _numberOfFields; i++) [_fields[i] release];
+
+ free(_fields);
+ free(_typeHandlers);
+
+ if (_connection) [_connection release], _connection = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresStatement.h b/Frameworks/PostgresKit/Source/FLXPostgresStatement.h
new file mode 100644
index 00000000..fafbb8dc
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresStatement.h
@@ -0,0 +1,44 @@
+//
+// $Id$
+//
+// FLXPostgresStatement.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+@interface FLXPostgresStatement : NSObject
+{
+ NSString *_statement;
+ NSString *_name;
+}
+
+/**
+ * @property statement The query statement.
+ */
+@property (readwrite, retain) NSString *statement;
+
+/**
+ * @property name The name of this statement.
+ */
+@property (readwrite, retain) NSString *name;
+
+- (id)initWithStatement:(NSString *)queryStatement;
+
+- (const char *)UTF8Name;
+- (const char *)UTF8Statement;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresStatement.m b/Frameworks/PostgresKit/Source/FLXPostgresStatement.m
new file mode 100644
index 00000000..a1505ccd
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresStatement.m
@@ -0,0 +1,81 @@
+//
+// $Id$
+//
+// FLXPostgresStatement.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresStatement.h"
+
+@implementation FLXPostgresStatement
+
+@synthesize name = _name;
+@synthesize statement = _statement;
+
+#pragma mark -
+#pragma mark Initialisation
+
+- (id)initWithStatement:(NSString *)queryStatement
+{
+ if ((self = [super init])) {
+ [self setStatement:queryStatement];
+ [self setName:nil];
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Public API
+
+/**
+ * Returns a null terminated C string of the statement's name.
+ *
+ * @return The statement name.
+ */
+- (const char *)UTF8Name
+{
+ return [[self name] UTF8String];
+}
+
+/**
+ * Returns a null terminated C string of the statement.
+ *
+ * @return The prepared statement.
+ */
+- (const char *)UTF8Statement
+{
+ return [[self statement] UTF8String];
+}
+
+- (NSString *)description
+{
+ return [self name] ? [NSString stringWithFormat:@"<%@ %@>", [self className], [self name]] : [NSString stringWithFormat:@"<%@>", [self className]];
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ if (_name) [_name release], _name = nil;
+ if (_statement) [_statement release], _statement = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h
new file mode 100644
index 00000000..154d364f
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.h
@@ -0,0 +1,35 @@
+//
+// $Id$
+//
+// FLXPostgresTypeDateTimeHandler.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 1, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import "FLXPostgresTypeHandler.h"
+
+@interface FLXPostgresTypeDateTimeHandler : FLXPostgresTypeHandler <FLXPostgresTypeHandlerProtocol>
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m
new file mode 100644
index 00000000..761e9e17
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeDateTimeHandler.m
@@ -0,0 +1,86 @@
+//
+// $Id$
+//
+// FLXPostgresTypeDateTimeHandler.m
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 1, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#import "FLXPostgresTypeDateTimeHandler.h"
+#import "FLXPostgresConnection.h"
+
+static FLXPostgresOid FLXPostgresTypeDateTimeTypes[] =
+{
+ FLXPostgresOidAbsTime,
+ FLXPostgresOidDate,
+ FLXPostgresOidTime,
+ FLXPostgresOidTimeTZ,
+ 0
+};
+
+@implementation FLXPostgresTypeDateTimeHandler
+
+#pragma mark -
+#pragma mark Protocol Implementation
+
+- (FLXPostgresOid *)remoteTypes
+{
+ return FLXPostgresTypeDateTimeTypes;
+}
+
+- (Class)nativeClass
+{
+ return [NSDate class];
+}
+
+- (NSArray *)classAliases
+{
+ return nil;
+}
+
+- (NSData *)remoteDataFromObject:(id)object type:(FLXPostgresOid *)type
+{
+ if (!object || !type || ![object isKindOfClass:[NSDate class]]) return nil;
+
+ return nil;
+}
+
+- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type
+{
+ if (!bytes || !type) return nil;
+
+ // TODO: Imeplement me!
+ return nil;
+}
+
+- (NSString *)quotedStringFromObject:(id)object
+{
+ if (!object || ![object isKindOfClass:[NSString class]]) return nil;
+
+ // TODO: Imeplement me!
+ return nil;
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.h
new file mode 100644
index 00000000..f2808d52
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.h
@@ -0,0 +1,38 @@
+//
+// $Id$
+//
+// FLXPostgresTypeHandler.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on July 27, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeHandlerProtocol.h"
+
+@class FLXPostgresConnection;
+
+@interface FLXPostgresTypeHandler : NSObject
+{
+ FLXPostgresConnection *_connection;
+}
+
+/**
+ * @property connection The connection this type handler is associated with.
+ */
+@property (readonly) FLXPostgresConnection *connection;
+
+- (id)initWithConnection:(FLXPostgresConnection *)connection;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.m
new file mode 100644
index 00000000..a1b5fac6
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandler.m
@@ -0,0 +1,46 @@
+//
+// $Id$
+//
+// FLXPostgresTypeHandler.h
+// PostgresKit
+//
+// Created by Stuart Connolly (stuconnolly.com) on July 27, 2012.
+// Copyright (c) 2012 Stuart Connolly. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeHandler.h"
+
+@implementation FLXPostgresTypeHandler
+
+@synthesize connection = _connection;
+
+- (id)initWithConnection:(FLXPostgresConnection *)connection
+{
+ if ((self = [super init])) {
+ _connection = [connection retain];
+ }
+
+ return self;
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ if (_connection) [_connection release], _connection = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h
new file mode 100644
index 00000000..49261e60
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeHandlerProtocol.h
@@ -0,0 +1,84 @@
+//
+// $Id$
+//
+// FLXPostgresTypeHandlerProtocol.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypes.h"
+
+@class FLXPostgresConnection;
+
+/**
+ * @protocol FLXPostgresTypeHandlerProtocol
+ */
+@protocol FLXPostgresTypeHandlerProtocol
+
+/**
+ * The remote type values handled by this class (terminated by 0).
+ *
+ * @return The remote types as an array of FLXPostgresOid's.
+ */
+- (FLXPostgresOid *)remoteTypes;
+
+/**
+ * What is the native class this class handles.
+ *
+ * @return The native class.
+ */
+- (Class)nativeClass;
+
+/**
+ * Any aliases that the native class is known by.
+ *
+ * @return An of aliases as strings or nil if none.
+ */
+- (NSArray *)classAliases;
+
+/**
+ * Return a transmittable data representation from the supplied object,
+ * and set the remote type for the data.
+ *
+ * @param object The object to produce the data for.
+ * @param type The type of object we're supplying.
+ *
+ * @return The data represenation as an NSData instance.
+ */
+- (NSData *)remoteDataFromObject:(id)object type:(FLXPostgresOid *)type;
+
+/**
+ * Convert the supplied remote data into an object.
+ *
+ * @param bytes The remote data to convert.
+ * @param length The length of the data.
+ * @param type The type of data.
+ *
+ * @return An object represenation of the data.
+ */
+- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type;
+
+/**
+ * Return a quoted string from an object.
+ *
+ * @param object The object to quote.
+ *
+ * @return A string represenation of the object quoted.
+ */
+- (NSString *)quotedStringFromObject:(id)object;
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h
new file mode 100644
index 00000000..a3305e19
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.h
@@ -0,0 +1,28 @@
+//
+// $Id$
+//
+// FLXPostgresTypeNumberHandler.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeHandler.h"
+
+@interface FLXPostgresTypeNumberHandler : FLXPostgresTypeHandler <FLXPostgresTypeHandlerProtocol>
+
+@end
+
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m
new file mode 100644
index 00000000..0c75e282
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeNumberHandler.m
@@ -0,0 +1,325 @@
+//
+// $Id$
+//
+// FLXPostgresTypeNumberHandler.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeNumberHandler.h"
+#import "FLXPostgresTypes.h"
+
+static FLXPostgresOid FLXPostgresTypeNumberTypes[] =
+{
+ FLXPostgresOidInt8,
+ FLXPostgresOidInt2,
+ FLXPostgresOidInt4,
+ FLXPostgresOidFloat4,
+ FLXPostgresOidFloat8,
+ FLXPostgresOidBool,
+ 0
+};
+
+@implementation FLXPostgresTypeNumberHandler
+
+#pragma mark -
+#pragma mark Integer & Unsigned Integer
+
+- (SInt16)int16FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ return EndianS16_BtoN(*((SInt16 *)bytes));
+}
+
+- (SInt32)int32FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ return EndianS32_BtoN(*((SInt32 *)bytes));
+}
+
+- (SInt64)int64FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ return EndianS64_BtoN(*((SInt64 *)bytes));
+}
+
+- (UInt16)unsignedInt16FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ return EndianU16_BtoN(*((UInt16 *)bytes));
+}
+
+- (UInt32)unsignedInt32FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ return EndianU32_BtoN(*((UInt32 *)bytes));
+}
+
+- (UInt64)unsignedInt64FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ return EndianU64_BtoN(*((UInt64 *)bytes));
+}
+
+- (NSNumber *)integerObjectFromBytes:(const void *)bytes length:(NSUInteger)length
+{
+ if (!bytes) return nil;
+
+ switch (length)
+ {
+ case 2:
+ return [NSNumber numberWithShort:[self int16FromBytes:bytes]];
+ case 4:
+ return [NSNumber numberWithInteger:[self int32FromBytes:bytes]];
+ case 8:
+ return [NSNumber numberWithLongLong:[self int64FromBytes:bytes]];
+ }
+
+ return nil;
+}
+
+- (NSNumber *)unsignedIntegerObjectFromBytes:(const void *)bytes length:(NSUInteger)length
+{
+ if (!bytes) return nil;
+
+ switch (length)
+ {
+ case 2:
+ return [NSNumber numberWithUnsignedShort:[self unsignedInt16FromBytes:bytes]];
+ case 4:
+ return [NSNumber numberWithUnsignedInteger:[self unsignedInt32FromBytes:bytes]];
+ case 8:
+ return [NSNumber numberWithUnsignedLongLong:[self unsignedInt64FromBytes:bytes]];
+ }
+
+ return nil;
+}
+
+- (NSData *)remoteDataFromInt64:(SInt64)value
+{
+ if (sizeof(SInt64) != 8) return nil;
+
+ value = EndianS64_NtoB(value);
+
+ return [NSData dataWithBytes:&value length:sizeof(value)];
+}
+
+- (NSData *)remoteDataFromInt32:(SInt32)value
+{
+ if (sizeof(SInt32) != 4) return nil;
+
+ value = EndianS32_NtoB(value);
+
+ return [NSData dataWithBytes:&value length:sizeof(value)];
+}
+
+- (NSData *)remoteDataFromInt16:(SInt16)value
+{
+ if (sizeof(SInt16) != 2) return nil;
+
+ value = EndianS16_NtoB(value);
+
+ return [NSData dataWithBytes:&value length:sizeof(value)];
+}
+
+#pragma mark -
+#pragma mark Floating Point
+
+- (Float32)float32FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ union { Float32 r; UInt32 i; } u32;
+
+ u32.r = *((Float32 *)bytes);
+ u32.i = CFSwapInt32HostToBig(u32.i);
+
+ return u32.r;
+}
+
+- (Float64)float64FromBytes:(const void *)bytes
+{
+ if (!bytes) return 0;
+
+ union { Float64 r; UInt64 i; } u64;
+
+ u64.r = *((Float64 *)bytes);
+ u64.i = CFSwapInt64HostToBig(u64.i);
+
+ return u64.r;
+}
+
+- (NSNumber *)realObjectFromBytes:(const void *)bytes length:(NSUInteger)length
+{
+ switch (length)
+ {
+ case 4:
+ return [NSNumber numberWithFloat:[self float32FromBytes:bytes]];
+ case 8:
+ return [NSNumber numberWithDouble:[self float64FromBytes:bytes]];
+ }
+
+ return nil;
+}
+
+
+- (NSData *)remoteDataFromFloat32:(Float32)value
+{
+ if (sizeof(Float32) != 4) return nil;
+
+ union { Float32 r; UInt32 i; } u32;
+
+ u32.r = value;
+ u32.i = CFSwapInt32HostToBig(u32.i);
+
+ return [NSData dataWithBytes:&u32 length:sizeof(u32)];
+}
+
+- (NSData *)remoteDataFromFloat64:(Float64)value
+{
+ if (sizeof(Float64) != 8) return nil;
+
+ union { Float64 r; UInt64 i; } u64;
+
+ u64.r = value;
+ u64.i = CFSwapInt64HostToBig(u64.i);
+
+ return [NSData dataWithBytes:&u64 length:sizeof(u64)];
+}
+
+#pragma mark -
+#pragma mark Boolean
+
+- (BOOL)booleanFromBytes:(const void *)bytes
+{
+ if (!bytes) return NO;
+
+ return (*((const int8_t *)bytes) ? YES : NO);
+}
+
+- (NSNumber *)booleanObjectFromBytes:(const void *)bytes length:(NSUInteger)length
+{
+ if (!bytes || length != 1) return nil;
+
+ return [NSNumber numberWithBool:[self booleanFromBytes:bytes]];
+}
+
+
+- (NSData *)remoteDataFromBoolean:(BOOL)value
+{
+ return [NSData dataWithBytes:&value length:1];
+}
+
+#pragma mark -
+#pragma mark Protocol Implementation
+
+- (FLXPostgresOid *)remoteTypes
+{
+ return FLXPostgresTypeNumberTypes;
+}
+
+- (Class)nativeClass
+{
+ return [NSNumber class];
+}
+
+- (NSArray *)classAliases
+{
+ return nil;
+}
+
+- (NSData *)remoteDataFromObject:(id)object type:(FLXPostgresOid *)type
+{
+ if (!object || !type || ![object isKindOfClass:[NSNumber class]]) return nil;
+
+ NSNumber *number = (NSNumber *)object;
+
+ const char *objectType = [number objCType];
+
+ switch (objectType[0])
+ {
+ case 'c':
+ case 'C':
+ case 'B': // Boolean
+ (*type) = FLXPostgresOidBool;
+ return [self remoteDataFromBoolean:[(NSNumber *)object boolValue]];
+ case 'i': // Integer
+ case 'l': // Long
+ case 'S': // Unsigned short
+ (*type) = FLXPostgresOidInt4;
+ return [self remoteDataFromInt32:[(NSNumber *)object shortValue]];
+ case 's':
+ (*type) = FLXPostgresOidInt2;
+ return [self remoteDataFromInt16:[(NSNumber *)object shortValue]];
+ case 'q': // Long long
+ case 'Q': // Unsigned long long
+ case 'I': // Unsigned integer
+ case 'L': // Unsigned long
+ (*type) = FLXPostgresOidInt8;
+ return [self remoteDataFromInt64:[(NSNumber *)object longLongValue]];
+ case 'f': // Float
+ (*type) = FLXPostgresOidFloat4;
+ return [self remoteDataFromFloat32:[(NSNumber *)object floatValue]];
+ case 'd': // Double
+ (*type) = FLXPostgresOidFloat8;
+ return [self remoteDataFromFloat64:[(NSNumber *)object doubleValue]];
+ }
+
+ return nil;
+}
+
+- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type
+{
+ if (!bytes || !length || !type) return nil;
+
+ switch (type)
+ {
+ case FLXPostgresOidInt8:
+ case FLXPostgresOidInt2:
+ case FLXPostgresOidInt4:
+ return [self integerObjectFromBytes:bytes length:length];
+ case FLXPostgresOidFloat4:
+ case FLXPostgresOidFloat8:
+ return [self realObjectFromBytes:bytes length:length];
+ case FLXPostgresOidBool:
+ return [self booleanObjectFromBytes:bytes length:length];
+ default:
+ return nil;
+ }
+}
+
+- (NSString *)quotedStringFromObject:(id)object
+{
+ if (!object || ![object isKindOfClass:[NSNumber class]]) return nil;
+
+ const char *type = [object objCType];
+
+ if (type[0] == 'c' || type[0] == 'C' || type[0] == 'B') {
+ return ([(NSNumber *)object boolValue] ? @"true" : @"false");
+ }
+ else {
+ return [(NSNumber *)object stringValue];
+ }
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.h b/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.h
new file mode 100644
index 00000000..43a70cfe
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.h
@@ -0,0 +1,28 @@
+//
+// $Id$
+//
+// FLXPostgresTypeStringHandler.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeHandler.h"
+
+@interface FLXPostgresTypeStringHandler : FLXPostgresTypeHandler <FLXPostgresTypeHandlerProtocol>
+
+@end
+
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m b/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m
new file mode 100644
index 00000000..de1d064d
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypeStringHandler.m
@@ -0,0 +1,77 @@
+//
+// $Id$
+//
+// FLXPostgresTypeStringHandler.m
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresTypeStringHandler.h"
+#import "FLXPostgresConnection.h"
+#import "FLXPostgresTypes.h"
+
+static FLXPostgresOid FLXPostgresTypeStringTypes[] =
+{
+ FLXPostgresOidText,
+ FLXPostgresOidChar,
+ FLXPostgresOidVarchar,
+ FLXPostgresOidUnknown,
+ 0
+};
+
+@implementation FLXPostgresTypeStringHandler
+
+#pragma mark -
+#pragma mark Protocol Implementation
+
+- (FLXPostgresOid *)remoteTypes
+{
+ return FLXPostgresTypeStringTypes;
+}
+
+- (Class)nativeClass
+{
+ return [NSString class];
+}
+
+- (NSArray *)classAliases
+{
+ return [NSArray arrayWithObject:@"NSCFString"];
+}
+
+- (NSData *)remoteDataFromObject:(id)object type:(FLXPostgresOid *)type
+{
+ if (!object || !type || ![object isKindOfClass:[NSString class]]) return nil;
+
+ return [(NSString *)object dataUsingEncoding:[_connection stringEncoding]];
+}
+
+- (id)objectFromRemoteData:(const void *)bytes length:(NSUInteger)length type:(FLXPostgresOid)type
+{
+ if (!bytes || !type) return nil;
+
+ return [[[NSString alloc] initWithBytes:bytes length:length encoding:[_connection stringEncoding]] autorelease];
+}
+
+- (NSString *)quotedStringFromObject:(id)object
+{
+ if (!object || ![object isKindOfClass:[NSString class]]) return nil;
+
+ return [NSString stringWithFormat:@"'%@'", [[object description] stringByReplacingOccurrencesOfString:@"'" withString:@"''"]];
+}
+
+@end
diff --git a/Frameworks/PostgresKit/Source/FLXPostgresTypes.h b/Frameworks/PostgresKit/Source/FLXPostgresTypes.h
new file mode 100644
index 00000000..7c146e41
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/FLXPostgresTypes.h
@@ -0,0 +1,80 @@
+//
+// $Id$
+//
+// FLXPostgresTypes.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "postgres_ext.h"
+
+// Generic PostgreSQL object ID
+typedef Oid FLXPostgresOid;
+
+// See PostgreSQL source: include/catalog/pg_type.h
+
+enum
+{
+ FLXPostgresOidBool = 16,
+ FLXPostgresOidData = 17,
+ FLXPostgresOidName = 19,
+ FLXPostgresOidInt8 = 20,
+ FLXPostgresOidInt2 = 21,
+ FLXPostgresOidInt4 = 23,
+ FLXPostgresOidText = 25,
+ FLXPostgresOidOid = 26,
+ FLXPostgresOidXML = 142,
+ FLXPostgresOidPoint = 600,
+ FLXPostgresOidLSeg = 601,
+ FLXPostgresOidPath = 602,
+ FLXPostgresOidBox = 603,
+ FLXPostgresOidPolygon = 604,
+ FLXPostgresOidFloat4 = 700,
+ FLXPostgresOidFloat8 = 701,
+ FLXPostgresOidAbsTime = 702,
+ FLXPostgresOidUnknown = 705,
+ FLXPostgresOidCircle = 718,
+ FLXPostgresOidMoney = 790,
+ FLXPostgresOidMacAddr = 829,
+ FLXPostgresOidIPAddr = 869,
+ FLXPostgresOidNetAddr = 869,
+ FLXPostgresOidArrayBool = 1000,
+ FLXPostgresOidArrayData = 1001,
+ FLXPostgresOidArrayChar = 1002,
+ FLXPostgresOidArrayName = 1003,
+ FLXPostgresOidArrayInt2 = 1005,
+ FLXPostgresOidArrayInt4 = 1007,
+ FLXPostgresOidArrayText = 1009,
+ FLXPostgresOidArrayVarchar = 1015,
+ FLXPostgresOidArrayInt8 = 1016,
+ FLXPostgresOidArrayFloat4 = 1021,
+ FLXPostgresOidArrayFloat8 = 1022,
+ FLXPostgresOidArrayMacAddr = 1040,
+ FLXPostgresOidArrayIPAddr = 1041,
+ FLXPostgresOidChar = 1042,
+ FLXPostgresOidVarchar = 1043,
+ FLXPostgresOidDate = 1082,
+ FLXPostgresOidTime = 1083,
+ FLXPostgresOidTimestamp = 1114,
+ FLXPostgresOidTimestampTZ = 1184,
+ FLXPostgresOidInterval = 1186,
+ FLXPostgresOidTimeTZ = 1266,
+ FLXPostgresOidBit = 1560,
+ FLXPostgresOidVarbit = 1562,
+ FLXPostgresOidNumeric = 1700,
+ FLXPostgresOidMax = 1700
+};
diff --git a/Frameworks/PostgresKit/Source/PostgresKit-Prefix.pch b/Frameworks/PostgresKit/Source/PostgresKit-Prefix.pch
new file mode 100644
index 00000000..822e702a
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/PostgresKit-Prefix.pch
@@ -0,0 +1,31 @@
+//
+// $Id$
+//
+// PostgresKit-Prefix.pch
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifdef __OBJC__
+ #import <Foundation/Foundation.h>
+
+ // PostgreSQL interface
+ #import "libpq-fe.h"
+
+ // Framework constants
+ #import "FLXConstants.h"
+#endif
diff --git a/Frameworks/PostgresKit/Source/PostgresKit.h b/Frameworks/PostgresKit/Source/PostgresKit.h
new file mode 100644
index 00000000..cc9c7f13
--- /dev/null
+++ b/Frameworks/PostgresKit/Source/PostgresKit.h
@@ -0,0 +1,27 @@
+//
+// PostgresKit.h
+// PostgresKit
+//
+// Copyright (c) 2008-2009 David Thorpe, djt@mutablelogic.com
+//
+// Forked by the Sequel Pro Team on July 22, 2012.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#import "FLXPostgresResult.h"
+#import "FLXPostgresStatement.h"
+#import "FLXPostgresException.h"
+#import "FLXPostgresConnection.h"
+#import "FLXPostgresConnectionUtils.h"
+#import "FLXPostgresConnectionQueryExecution.h"
+#import "FLXPostgresConnectionQueryPreparation.h"