public
Description: A simple Nu/Objective-C interface to PostgreSQL databases.
Homepage: http://programming.nu
Clone URL: git://github.com/timburks/nupostgresql.git
Added parameterized queries using PostgreSQL prepared statements.
timburks (author)
Thu Jul 31 15:50:48 -0700 2008
commit  fcba024e040bd1d69700c5216dd49a8329e38348
tree    0d49b4ddc63eedf8566de6e8012a3366f0c201f8
parent  035955fe1c6ad5e812dfe03da68ea4cb866a7a08
...
18
19
20
 
 
 
 
 
 
 
21
22
23
...
31
32
33
34
 
35
36
37
...
44
45
46
47
 
48
49
50
...
57
58
59
60
 
61
62
63
...
18
19
20
21
22
23
24
25
26
27
28
29
30
...
38
39
40
 
41
42
43
44
...
51
52
53
 
54
55
56
57
...
64
65
66
 
67
68
69
70
0
@@ -18,6 +18,13 @@
0
 (class PGFieldType (ivar-accessors))
0
 
0
 (class PGResult (ivar-accessors)
0
+ (- (id) array is
0
+ (set a (array))
0
+ ((self tupleCount) times:
0
+ (do (i)
0
+ (a addObject: (self dictionaryForTuple:i))))
0
+ a)
0
+
0
      (- (id) dictionaryForTuple:(int)i is
0
         (set d (dict))
0
         ((self fieldTypes) eachWithIndex:
0
@@ -31,7 +38,7 @@
0
      ;; Perform a query and return the result as an array of dictionaries.
0
      ;; Each row of a query result is returned as a dictionary.
0
      (- (id) queryAsArray:(id) query is
0
- (set result (self exec:query))
0
+ (set result (self query:query))
0
         (if result
0
             (then (set a (array))
0
                   ((result tupleCount) times:
0
@@ -44,7 +51,7 @@
0
      ;; with the top-level dictionary keyed by the specified key.
0
      ;; Each row of a query result is returned as a dictionary.
0
      (- (id) queryAsDictionary:(id) query withKey:(id) key is
0
- (set result (self exec:query))
0
+ (set result (self query:query))
0
         (if result
0
             (then (set d (dict))
0
                   ((result tupleCount) times:
0
@@ -57,7 +64,7 @@
0
      ;; Perform a query and return a single result as a dictionary.
0
      ;; Returns nil if multiple matches exist.
0
      (- (id) queryAsValue:(id) query is
0
- (set result (self exec:query))
0
+ (set result (self query:query))
0
         (if (eq (result tupleCount) 1)
0
             (then (result dictionaryForTuple:0))
0
             (else nil))))
...
1
2
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
5
6
...
155
156
157
158
159
160
161
...
210
211
212
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
215
216
...
220
221
222
 
 
 
 
 
 
223
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
194
195
196
 
197
198
199
...
248
249
250
 
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
...
286
287
288
289
290
291
292
293
294
295
0
@@ -1,6 +1,45 @@
0
 #import <Foundation/Foundation.h>
0
 #import <Nu/Nu.h>
0
 #include "libpq-fe.h"
0
+#include "ecpgtype.h"
0
+
0
+const char *nameOfType(enum ECPGttype code)
0
+{
0
+ switch (code) {
0
+ case ECPGt_char: return "char";
0
+ case ECPGt_unsigned_char: return "unsigned char";
0
+ case ECPGt_short: return "short";
0
+ case ECPGt_unsigned_short: return "unsigned short";
0
+ case ECPGt_int: return "int";
0
+ case ECPGt_unsigned_int: return "unsigned int";
0
+ case ECPGt_long: return "long";
0
+ case ECPGt_unsigned_long: return "unsigned long";
0
+ case ECPGt_long_long: return "long long";
0
+ case ECPGt_unsigned_long_long: return "unsigned long long";
0
+ case ECPGt_bool: return "bool";
0
+ case ECPGt_float: return "float";
0
+ case ECPGt_double: return "double";
0
+ case ECPGt_varchar: return "varchar";
0
+ case ECPGt_varchar2: return "varchar2";
0
+ case ECPGt_numeric: return "numeric"; /* this is a decimal that stores its digits in a malloced array */
0
+ case ECPGt_decimal: return "decimal"; /* this is a decimal that stores its digits in a fixed array */
0
+ case ECPGt_date: return "date";
0
+ case ECPGt_timestamp: return "timestamp";
0
+ case ECPGt_interval: return "interval";
0
+ case ECPGt_array: return "array";
0
+ case ECPGt_struct: return "struct";
0
+ case ECPGt_union: return "union";
0
+ /* sql descriptor: return ""; no C variable */
0
+ case ECPGt_descriptor: return "descriptor";
0
+ case ECPGt_char_variable: return "char variable";
0
+ case ECPGt_const: return "const"; /* a constant is needed sometimes */
0
+ case ECPGt_EOIT: return "EOIT"; /* End of insert types. */
0
+ case ECPGt_EORT: return "EORT"; /* End of result types. */
0
+ /* no indicator */
0
+ case ECPGt_NO_INDICATOR: return "no indicator";
0
+ };
0
+ return "";
0
+}
0
 
0
 @interface PGFieldType : NSObject
0
 {
0
@@ -155,7 +194,6 @@ void notice_processor(void *arg, const char *message)
0
     }
0
 }
0
 
0
-
0
 - (id) init
0
 {
0
     [super init];
0
@@ -210,7 +248,35 @@ void notice_processor(void *arg, const char *message)
0
     PQfinish(connection);
0
 }
0
 
0
-- (PGResult *) exec:(NSString *)command
0
+- (PGResult *) query:(id)query withArguments:(id) arguments
0
+{
0
+ if (connection == nil) {
0
+ NSLog(@"There is no connection to a database.");
0
+ return nil;
0
+ }
0
+ PGresult *preparationResult = PQprepare(connection, "", [query cStringUsingEncoding:NSUTF8StringEncoding], 0, 0);
0
+ PGresult *descriptionResult = PQdescribePrepared(connection, "");
0
+ /*
0
+ NSLog(@"prepared query expects %d arguments", PQnparams(descriptionResult));
0
+ for (int i = 0; i < PQnparams(descriptionResult); i++) {
0
+ NSLog(@"param %d type %s", i, nameOfType(PQparamtype(descriptionResult, i)));
0
+ }
0
+ */
0
+ int paramCount = [arguments count];
0
+ char **paramValues = (char **) malloc (paramCount * sizeof(char *));
0
+ for (int i = 0; i < paramCount; i++) {
0
+ NSString *stringValue = [[arguments objectAtIndex:i] stringValue];
0
+ paramValues[i] = strdup([stringValue cStringUsingEncoding:NSUTF8StringEncoding]);
0
+ }
0
+ PGresult *result = PQexecPrepared(connection, "", paramCount, (const char **) paramValues, 0, 0, 0);
0
+ for (int i = 0; i < paramCount; i++) {
0
+ free(paramValues[i]);
0
+ }
0
+ free(paramValues);
0
+ return [[[PGResult alloc] initWithResult:result] autorelease];
0
+}
0
+
0
+- (PGResult *) query:(NSString *)command
0
 {
0
     if (connection == nil) {
0
         NSLog(@"There is no connection to a database.");
0
@@ -220,4 +286,10 @@ void notice_processor(void *arg, const char *message)
0
     return [[[PGResult alloc] initWithResult:result] autorelease];
0
 }
0
 
0
+- (PGResult *) exec:(NSString *)command
0
+{
0
+ NSLog(@"exec: is deprecated, please use query: instead.");
0
+ return [self query:command];
0
+}
0
+
0
 @end
...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
50
51
52
53
54
55
 
 
56
 
57
58
59
60
61
 
62
63
64
...
74
75
76
77
 
78
79
80
...
86
87
88
89
90
91
92
93
 
 
 
 
94
95
96
...
111
112
113
114
115
116
 
 
 
117
118
119
120
121
122
 
 
123
124
125
126
127
128
129
130
131
132
 
 
 
 
 
 
 
 
 
133
134
135
136
137
 
138
139
140
141
142
143
 
 
144
145
146
147
148
149
 
150
151
152
...
154
155
156
157
 
158
159
 
 
160
161
162
163
 
 
164
165
166
...
7
8
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
11
12
13
14
 
 
15
16
17
18
19
20
21
22
 
23
24
25
26
...
36
37
38
 
39
40
41
42
...
48
49
50
 
 
 
 
 
51
52
53
54
55
56
57
...
72
73
74
 
 
 
75
76
77
78
79
80
81
 
 
82
83
84
85
86
87
88
 
 
 
 
 
89
90
91
92
93
94
95
96
97
98
99
100
101
 
102
103
104
105
106
 
 
107
108
109
110
111
112
113
 
114
115
116
117
...
119
120
121
 
122
123
 
124
125
126
127
128
 
129
130
131
132
133
0
@@ -7,58 +7,20 @@
0
 
0
 (class TestPostgreSQL is NuTestCase
0
      
0
- (- (id) testFamily is
0
- (set c ((PGConnection alloc) init))
0
- (c setConnectionInfo:(dict user:"postgres" dbname:"test"))
0
- (set result (c connect))
0
- (assert_equal 1 result)
0
- (set result (c exec:"drop table if exists triples"))
0
- (set result (c exec:<<-END
0
-create table triples (
0
- subject text,
0
- object text,
0
- relation text)
0
-END))
0
- (set result (c exec:<<-END
0
-insert into triples ( subject, object, relation )
0
-values
0
-('homer', 'marge', 'wife'),
0
-('homer', 'bart', 'son'),
0
-('homer', 'lisa', 'daughter'),
0
-('marge', 'homer', 'husband'),
0
-('marge', 'lisa', 'daughter'),
0
-('marge', 'bart', 'son'),
0
-('bart', 'homer', 'father'),
0
-('bart', 'marge', 'mother'),
0
-('bart', 'lisa', 'sister'),
0
-('lisa', 'homer', 'father'),
0
-('lisa', 'marge', 'mother'),
0
-('lisa', 'bart', 'brother')
0
-END))
0
- (set result (c exec:"select * from triples"))
0
- (assert_equal 12 (result tupleCount))
0
- (set result (c exec:"select * from triples where subject = 'homer'"))
0
- (assert_equal 3 (result tupleCount))
0
- (set result (c exec:"select object from triples where subject = 'homer' and relation = 'son'"))
0
- (assert_equal 1 (result tupleCount))
0
- (assert_equal "bart" (result valueOfTuple:0 field:0))
0
- (set result (c exec:"drop table triples")))
0
-
0
-
0
-
0
- (- testFamily2 is
0
+ (- testFamily is
0
         (set m ((PGConnection alloc) init))
0
         (m setConnectionInfo:(dict user:"postgres" dbname:"test"))
0
         (set result (m connect))
0
         (assert_equal 1 result)
0
- (set result (m exec:"drop table if exists triples"))
0
- (set result (m exec:<<-END
0
+ (set result (m query:"drop table if exists triples"))
0
+ (set result (m query:<<-END
0
         create table triples (
0
+ id serial primary key,
0
           subject text,
0
           object text,
0
           relation text)          
0
         END))
0
- (set result (m exec:<<-END
0
+ (set result (m query:<<-END
0
         insert into triples ( subject, object, relation )
0
         values
0
         ('homer', 'marge', 'wife'),
0
@@ -74,7 +36,7 @@ END))
0
         ('lisa', 'marge', 'mother'),
0
         ('lisa', 'bart', 'brother')
0
         END))
0
- (set result (m exec:"select * from triples"))
0
+ (set result (m query:"select * from triples"))
0
         (assert_equal 12 (result tupleCount))
0
         (set resultArray (m queryAsArray:"select * from triples where subject = 'homer'"))
0
         (assert_equal 3 (resultArray count))
0
@@ -86,11 +48,10 @@ END))
0
                        ("marge" (assert_equal "wife" (d valueForKey:"relation")))
0
                        (else nil))))
0
         
0
- (if NO
0
- (set result (m exec:"select object from triples where subject = 'homer' and relation = 'son'"))
0
- (assert_equal 1 (result tupleCount))
0
- (set row (result nextRowAsArray))
0
- (assert_equal "bart" (row objectAtIndex:0)))
0
+ (set result (m queryAsArray:"select object from triples where subject = 'homer' and relation = 'son'"))
0
+ (assert_equal 1 (result count))
0
+ (set row (result 0))
0
+ (assert_equal "bart" (row "object"))
0
         
0
         (set result (m queryAsValue:"select * from triples where subject = 'homer' and relation = 'wife'"))
0
         (assert_equal "marge" (result "object"))
0
@@ -111,42 +72,46 @@ END))
0
         
0
         (set result (m queryAsArray:"select * from triples where subject = 'homer' and relation = 'husband'"))
0
         (assert_equal 0 (result count))
0
- (set result (m exec:"drop table triples")))
0
-
0
- (- _testInsert is
0
+ (set result (m query:"drop table triples")))
0
+
0
+ (- testInsert is
0
         (set m ((PGConnection alloc) init))
0
         (m setConnectionInfo:(dict user:"postgres" dbname:"test"))
0
         (set result (m connect))
0
         (assert_equal 1 result)
0
- (set result (m exec:"drop table if exists cities"))
0
- (set result (m exec:<<-END
0
+ (set result (m query:"drop table if exists cities"))
0
+ (set result (m query:<<-END
0
         create table cities (
0
           id SERIAL PRIMARY KEY,
0
           city text,
0
           nation text)          
0
         END))
0
- (set result (m insertRowInTable:"cities" withDictionary:(dict city:"San Francisco" nation:"United States")))
0
- (set result (m insertRowInTable:"cities" withDictionary:(dict city:"Tokyo" nation:"Japan")))
0
- (set result (m insertRowInTable:"cities" withDictionary:(dict city:"Bangalore" nation:"India")))
0
- (set result (m insertRowInTable:"cities" withDictionary:(dict city:"Copenhagen" nation:"Denmark")))
0
- (set result (m exec:"select * from cities"))
0
+ (set result (m query:"insert into cities (city, nation) values ($1, $2)" withArguments:(array "San Francisco" "United States")))
0
+ (set result (m query:"insert into cities (city, nation) values ($1, $2)" withArguments:(array "Tokyo" "Japan")))
0
+ (set result (m query:"insert into cities (city, nation) values ($1, $2)" withArguments:(array "Bangalore" "India")))
0
+ (set result (m query:"insert into cities (city, nation) values ($1, $2)" withArguments:(array "Copenhagen" "Denmark")))
0
+ ; (set result (m insertRowInTable:"cities" withDictionary:(dict city:"San Francisco" nation:"United States")))
0
+ ; (set result (m insertRowInTable:"cities" withDictionary:(dict city:"Tokyo" nation:"Japan")))
0
+ ; (set result (m insertRowInTable:"cities" withDictionary:(dict city:"Bangalore" nation:"India")))
0
+ ; (set result (m insertRowInTable:"cities" withDictionary:(dict city:"Copenhagen" nation:"Denmark")))
0
+ (set result (m query:"select * from cities"))
0
         (assert_equal 4 (result tupleCount))
0
         (set result ((m queryAsDictionary:"select * from cities" withKey:"nation")))
0
         (assert_equal "Tokyo" ((result "Japan") "city")))
0
      
0
- (- _testUpdate is
0
+ (- testUpdate is
0
         (set m ((PGConnection alloc) init))
0
         (m setConnectionInfo:(dict user:"postgres" dbname:"test"))
0
         (set result (m connect))
0
         (assert_equal 1 result)
0
- (set result (m exec:"drop table if exists cities"))
0
- (set result (m exec:<<-END
0
+ (set result (m query:"drop table if exists cities"))
0
+ (set result (m query:<<-END
0
           create table cities (
0
             id integer,
0
             city text,
0
             nation text)          
0
           END))
0
- (set result (m exec:<<-END
0
+ (set result (m query:<<-END
0
           insert into cities ( id, city, nation )
0
           values
0
           (1, 'San Francisco', 'United States'),
0
@@ -154,13 +119,15 @@ END))
0
           (3, 'Bangalore', 'India'),
0
           (4, 'Copenhagen', 'Denmark')
0
           END))
0
- (set result (m exec:"select * from cities"))
0
+ (set result (m query:"select * from cities"))
0
         (assert_equal 4 (result tupleCount))
0
- (set result (m updateTable:"cities" withDictionary:(dict city:"Yokohama") forId:2))
0
+ (set result (m query:"update cities set city = $1 where id = $2" withArguments:(array "Yokohama" 2)))
0
+ ;; (set result (m updateTable:"cities" withDictionary:(dict city:"Yokohama") forId:2))
0
         (set result (m queryAsValue:"select * from cities where id = 2"))
0
         (assert_equal "Yokohama" (result "city"))
0
         (assert_equal "Japan" (result "nation"))
0
- (set result (m updateTable:"cities" withDictionary:(dict city:"London" nation:"England") forId:4))
0
+ (set result (m query:"update cities set city = $1, nation = $2 where id = $3" withArguments:(array "London" "England" 4)))
0
+ ;; (set result (m updateTable:"cities" withDictionary:(dict city:"London" nation:"England") forId:4))
0
         (set result (m queryAsValue:"select * from cities where id = 4"))
0
         (assert_equal "London" (result "city"))
0
         (assert_equal "England" (result "nation"))))

Comments

    No one has commented yet.