Index: ObjPgSQL.xcodeproj/project.pbxproj ================================================================== --- ObjPgSQL.xcodeproj/project.pbxproj +++ ObjPgSQL.xcodeproj/project.pbxproj @@ -19,11 +19,11 @@ 4BCC7454161F82820074ED30 /* PGCommandFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BCC744E161F82820074ED30 /* PGCommandFailedException.m */; }; 4BCC7455161F82820074ED30 /* PGConnectionFailedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCC744F161F82820074ED30 /* PGConnectionFailedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BCC7456161F82820074ED30 /* PGConnectionFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BCC7450161F82820074ED30 /* PGConnectionFailedException.m */; }; 4BCC7457161F82820074ED30 /* PGException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BCC7451161F82820074ED30 /* PGException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BCC7458161F82820074ED30 /* PGException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BCC7452161F82820074ED30 /* PGException.m */; }; - 4BCC7460161F842F0074ED30 /* libpq.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BCC745F161F842F0074ED30 /* libpq.dylib */; }; + 4BCC74B0162036A70074ED30 /* libpq.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BCC74AF162036A70074ED30 /* libpq.dylib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 4BCC7424161F81760074ED30 /* ObjPgSQL.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjPgSQL.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4BCC743C161F82000074ED30 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = /Library/Frameworks/ObjFW.framework; sourceTree = ""; }; @@ -38,21 +38,21 @@ 4BCC744E161F82820074ED30 /* PGCommandFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGCommandFailedException.m; path = exceptions/PGCommandFailedException.m; sourceTree = SOURCE_ROOT; }; 4BCC744F161F82820074ED30 /* PGConnectionFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGConnectionFailedException.h; path = exceptions/PGConnectionFailedException.h; sourceTree = SOURCE_ROOT; }; 4BCC7450161F82820074ED30 /* PGConnectionFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGConnectionFailedException.m; path = exceptions/PGConnectionFailedException.m; sourceTree = SOURCE_ROOT; }; 4BCC7451161F82820074ED30 /* PGException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGException.h; path = exceptions/PGException.h; sourceTree = SOURCE_ROOT; }; 4BCC7452161F82820074ED30 /* PGException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGException.m; path = exceptions/PGException.m; sourceTree = SOURCE_ROOT; }; - 4BCC745F161F842F0074ED30 /* libpq.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpq.dylib; path = usr/lib/libpq.dylib; sourceTree = SDKROOT; }; 4BCC7464161F85DF0074ED30 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; + 4BCC74AF162036A70074ED30 /* libpq.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpq.dylib; path = /usr/local/lib/libpq.dylib; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 4BCC7420161F81760074ED30 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4BCC74B0162036A70074ED30 /* libpq.dylib in Frameworks */, 4BCC743D161F82000074ED30 /* ObjFW.framework in Frameworks */, - 4BCC7460161F842F0074ED30 /* libpq.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ @@ -113,11 +113,11 @@ sourceTree = ""; }; 4BCC7461161F843F0074ED30 /* Libraries */ = { isa = PBXGroup; children = ( - 4BCC745F161F842F0074ED30 /* libpq.dylib */, + 4BCC74AF162036A70074ED30 /* libpq.dylib */, ); name = Libraries; sourceTree = ""; }; /* End PBXGroup section */ @@ -279,10 +279,14 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = NO; INFOPLIST_FILE = Info.plist; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + /usr/local/lib, + ); PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = framework; }; name = Debug; }; @@ -293,10 +297,14 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; FRAMEWORK_VERSION = A; GCC_PRECOMPILE_PREFIX_HEADER = NO; INFOPLIST_FILE = Info.plist; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + /usr/local/lib, + ); PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = framework; }; name = Release; }; Index: PGConnection.h ================================================================== --- PGConnection.h +++ PGConnection.h @@ -20,6 +20,10 @@ - (void)reset; - (PGResult*)executeCommand: (OFString*)command; - (PGResult*)executeCommand: (OFString*)command parameters: (id)firstParameter, ...; - (PGconn*)PG_connection; +- (void)insertRow: (OFDictionary*)row + intoTable: (OFString*)table; +- (void)insertRows: (OFArray*)rows + intoTable: (OFString*)table; @end Index: PGConnection.m ================================================================== --- PGConnection.m +++ PGConnection.m @@ -123,11 +123,90 @@ return [PGResult PG_resultWithResult: result]; PQclear(result); return nil; } + +- (void)insertRow: (OFDictionary*)row + intoTable: (OFString*)table +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFMutableString *command; + OFEnumerator *enumerator; + const char **values; + PGresult *result; + OFString *key, *value; + size_t i, count; + + command = [OFMutableString stringWithString: @"INSERT INTO "]; + [command appendString: table]; + [command appendString: @" ("]; + + count = [row count]; + + i = 0; + enumerator = [row keyEnumerator]; + while ((key = [enumerator nextObject]) != nil) { + if (i > 0) + [command appendString: @", "]; + + [command appendString: key]; + + i++; + } + + [command appendString: @") VALUES ("]; + + values = [self allocMemoryWithSize: sizeof(*values) + count: count]; + @try { + i = 0; + enumerator = [row objectEnumerator]; + while ((value = [enumerator nextObject]) != nil) { + if (i > 0) + [command appendString: @", "]; + + values[i] = [value UTF8String]; + + [command appendFormat: @"$%zd", ++i]; + } + + [command appendString: @")"]; + + result = PQexecParams(conn, [command UTF8String], (int)count, + NULL, values, NULL, NULL, 0); + } @finally { + [self freeMemory: values]; + } + + [pool release]; + + if (PQresultStatus(result) != PGRES_COMMAND_OK) { + PQclear(result); + @throw [PGCommandFailedException + exceptionWithClass: [self class] + connection: self + command: command]; + } + + PQclear(result); +} + +- (void)insertRows: (OFArray*)rows + intoTable: (OFString*)table +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFEnumerator *enumerator = [rows objectEnumerator]; + OFDictionary *row; + + while ((row = [enumerator nextObject]) != nil) + [self insertRow: row + intoTable: table]; + + [pool release]; +} - (PGconn*)PG_connection { return conn; } @end Index: test.m ================================================================== --- test.m +++ test.m @@ -32,10 +32,12 @@ @"VALUES($1, $2, $3)" parameters: @"1", @"foo", @"Hallo Welt!", nil]; [connection executeCommand: @"INSERT INTO test (id, content) " @"VALUES($1, $2)" parameters: @"2", @"Blup!!", nil]; + [connection insertRow: @{ @"content": @"Hallo!", @"name": @"foo" } + intoTable: @"test"]; result = [connection executeCommand: @"SELECT * FROM test"]; of_log(@"%@", result); of_log(@"JSON: %@", [result JSONRepresentation]);