]> err.no Git - sope/blob - sope-gdl1/PostgreSQL/PGConnection.m
added an ivar to WOComponent, minor cleanups
[sope] / sope-gdl1 / PostgreSQL / PGConnection.m
1 /* 
2    PGConnection.m
3
4    Copyright (C) 2004 SKYRIX Software AG and Helge Hess
5
6    Author: Helge Hess (helge.hess@opengroupware.org)
7    
8    This file is part of the PostgreSQL72 Adaptor Library
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Library General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Library General Public License for more details.
19
20    You should have received a copy of the GNU Library General Public
21    License along with this library; see the file COPYING.LIB.
22    If not, write to the Free Software Foundation,
23    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25 // $Id: PGConnection.m 1 2004-08-20 10:38:46Z znek $
26
27 #include "PGConnection.h"
28 #include "common.h"
29 #include <libpq-fe.h>
30
31 #if PG_MAJOR_VERSION >= 6 && PG_MINOR_VERSION > 3
32 #  define NG_HAS_NOTICE_PROCESSOR 1
33 #  define NG_HAS_BINARY_TUPLES    1
34 #  define NG_HAS_FMOD             1
35 #endif
36
37 #if PG_MAJOR_VERSION >= 7 && PG_MINOR_VERSION > 3
38 #  define NG_SET_CLIENT_ENCODING 1
39 #endif
40
41 @implementation PGConnection
42
43 static BOOL debugOn = NO;
44
45 - (id)initWithHostName:(NSString *)_host port:(NSString *)_port
46   options:(NSString *)_options tty:(NSString *)_tty 
47   database:(NSString *)_dbname 
48   login:(NSString *)_login password:(NSString *)_pwd
49 {
50   if ((self = [self init])) {
51     NSException *error;
52     
53     error = [self connectWithHostName:_host port:_port options:_options 
54                   tty:_tty database:_dbname login:_login password:_pwd];
55     if (error != nil) {
56       if (debugOn) 
57         NSLog(@"%s: could not connect: %@", __PRETTY_FUNCTION__, error);
58       [self release];
59       return nil;
60     }
61   }
62   return self;
63 }
64
65 - (void)dealloc {
66   [self finish];
67   [super dealloc];
68 }
69
70 /* support */
71
72 - (const char *)_cstrFromString:(NSString *)_s {
73   // TODO: fix API, check what the API string encoding is
74   return [_s cString];
75 }
76 - (NSString *)_stringFromCString:(const char *)_cstr {
77   return [NSString stringWithCString:_cstr];
78 }
79
80 /* accessors */
81
82 - (BOOL)isValid {
83   return self->_connection != NULL ? YES : NO;
84 }
85
86 /* errors */
87
88 - (NSException *)_makeConnectException:(const char *)_func {
89   return [NSException exceptionWithName:@"PGConnectFailed"
90                       reason:[NSString stringWithCString:_func]
91                       userInfo:nil];
92 }
93
94 /* connect operations */
95
96 - (void)_disconnect {
97   if (self->_connection != NULL)
98     [self finish];
99 }
100
101 - (NSException *)startConnectWithInfo:(NSString *)_conninfo {
102   [self _disconnect];
103   
104   self->_connection = PQconnectStart([self _cstrFromString:_conninfo]);
105   if (self->_connection == NULL)
106     return [self _makeConnectException:__PRETTY_FUNCTION__];
107   return nil;
108 }
109 // TODO: add method for polling connect status
110
111 - (NSException *)connectWithInfo:(NSString *)_conninfo {
112   [self _disconnect];
113   
114   self->_connection = PQconnectdb([self _cstrFromString:_conninfo]);
115   if (self->_connection == NULL)
116     return [self _makeConnectException:__PRETTY_FUNCTION__];
117   return nil;
118 }
119
120 - (NSException *)connectWithHostName:(NSString *)_host port:(NSString *)_port
121   options:(NSString *)_options tty:(NSString *)_tty 
122   database:(NSString *)_dbname 
123   login:(NSString *)_login password:(NSString *)_pwd
124 {
125   [self _disconnect];
126
127   self->_connection = PQsetdbLogin([self _cstrFromString:_host],
128                                    [self _cstrFromString:_port],
129                                    [self _cstrFromString:_options],
130                                    [self _cstrFromString:_tty],
131                                    [self _cstrFromString:_dbname],
132                                    [self _cstrFromString:_login],
133                                    [self _cstrFromString:_pwd]);
134   if (self->_connection == NULL)
135     return [self _makeConnectException:__PRETTY_FUNCTION__];
136   return nil;
137 }
138
139 - (void)finish {
140   if (self->_connection != NULL) {
141     PQfinish(self->_connection);
142     self->_connection = NULL;
143   }
144 }
145
146 - (BOOL)isConnectionOK {
147   if (![self isValid]) 
148     return NO;
149   return PQstatus(self->_connection) == CONNECTION_OK ? YES : NO;
150 }
151
152 /* message callbacks */
153
154 - (BOOL)setNoticeProcessor:(void *)_callback context:(void *)_ctx {
155 #if NG_HAS_NOTICE_PROCESSOR
156   PQsetNoticeProcessor(self->_connection, _callback, _ctx);
157   return YES; // TODO: improve error handling
158 #else
159   return NO;
160 #endif
161 }
162
163 /* settings */
164
165 - (BOOL)setClientEncoding:(NSString *)_encoding {
166   return PQsetClientEncoding(self->_connection, 
167                              [self _cstrFromString:_encoding]) == 0 ? YES : NO;
168 }
169
170 /* errors */
171
172 - (NSString *)errorMessage {
173   if (![self isValid])
174     return nil;
175   
176   return [self _stringFromCString:PQerrorMessage(self->_connection)];
177 }
178
179 /* queries */
180
181 - (void *)rawExecute:(NSString *)_sql {
182   return PQexec(self->_connection, [self _cstrFromString:_sql]);
183 }
184 - (void)clearRawResults:(void *)_ptr {
185   if (_ptr == NULL) return;
186   PQclear(_ptr);
187 }
188
189 - (PGResultSet *)execute:(NSString *)_sql {
190   void *handle;
191   
192   if ((handle = [self rawExecute:_sql]) == NULL)
193     return nil;
194
195   return [[[PGResultSet alloc] initWithConnection:self handle:handle]
196                         autorelease];
197 }
198
199 /* debugging */
200
201 - (BOOL)isDebuggingEnabled {
202   return debugOn;
203 }
204
205 /* description */
206
207 - (NSString *)description {
208   NSMutableString *ms;
209
210   ms = [NSMutableString stringWithCapacity:128];
211   [ms appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])];
212   if ([self isValid])
213     [ms appendFormat:@" connection=0x%08X", self->_connection];
214   else
215     [ms appendString:@" not-connected"];
216   [ms appendString:@">"];
217   return ms;
218 }
219
220 @end /* PGConnection */
221
222 @implementation PGResultSet
223
224 /* wraps PGresult */
225
226 - (id)initWithConnection:(PGConnection *)_con handle:(void *)_handle {
227   if (_handle == NULL) {
228     [self release];
229     return nil;
230   }
231   if ((self = [super init])) {
232     self->connection = [_con retain];
233     self->results    = _handle;
234   }
235   return self;
236 }
237
238 - (void)dealloc {
239   [self clear];
240   [self->connection release];
241   [super dealloc];
242 }
243
244 /* accessors */
245
246 - (BOOL)isValid {
247   return self->results != NULL ? YES : NO;
248 }
249
250 - (BOOL)containsBinaryTuples {
251 #if NG_HAS_BINARY_TUPLES
252   if (self->results == NULL) return NO;
253   return PQbinaryTuples(self->results) ? YES : NO;
254 #else
255   return NO;
256 #endif
257 }
258
259 - (NSString *)commandStatus {
260   char *cstr;
261   
262   if (self->results == NULL)
263     return nil;
264   if ((cstr = PQcmdStatus(self->results)) == NULL)
265     return nil;
266   return [NSString stringWithCString:cstr];
267 }
268
269 - (NSString *)commandTuples {
270   char *cstr;
271   
272   if (self->results == NULL)
273     return nil;
274   if ((cstr = PQcmdTuples(self->results)) == NULL)
275     return nil;
276   return [NSString stringWithCString:cstr];
277 }
278
279 /* fields */
280
281 - (unsigned)fieldCount {
282   return self->results != NULL ? PQnfields(self->results) : 0;
283 }
284
285 - (NSString *)fieldNameAtIndex:(unsigned int)_idx {
286   // TODO: charset
287   if (self->results == NULL) return nil;
288   return [NSString stringWithCString:PQfname(self->results, _idx)];
289 }
290
291 - (int)indexOfFieldNamed:(NSString *)_name {
292   return PQfnumber(self->results, [_name cString]);
293 }
294
295 - (int)fieldSizeAtIndex:(unsigned int)_idx {
296   if (self->results == NULL) return 0;
297   return PQfsize(self->results, _idx);
298 }
299
300 - (int)modifierAtIndex:(unsigned int)_idx {
301   if (self->results == NULL) return 0;
302 #if NG_HAS_FMOD
303   return PQfmod(self->results, _idx);
304 #else
305   return 0;
306 #endif
307 }
308
309 /* tuples */
310
311 - (unsigned int)tupleCount {
312   if (self->results == NULL) return 0;
313   return PQntuples(self->results);
314 }
315
316 - (BOOL)isNullTuple:(int)_tuple atIndex:(unsigned int)_idx {
317   if (self->results == NULL) return NO;
318   return PQgetisnull(self->results, _tuple, _idx) ? YES : NO;
319 }
320
321 - (void *)rawValueOfTuple:(int)_tuple atIndex:(unsigned int)_idx {
322   if (self->results == NULL) return NULL;
323   return PQgetvalue(self->results, _tuple, _idx);
324 }
325
326 - (int)lengthOfTuple:(int)_tuple atIndex:(unsigned int)_idx {
327   if (self->results == NULL) return 0;
328   return PQgetlength(self->results, _tuple, _idx);
329 }
330
331 /* operations */
332
333 - (void)clear {
334   if (self->results == NULL) return;
335   PQclear(self->results);
336   self->results = NULL;
337 }
338
339 @end /* PGResultSet */