This commit was manufactured by cvs2svn to create branch
[plcapi.git] / psycopg2 / psycopg / connection_int.c
1 /* connection_int.c - code used by the connection object
2  *
3  * Copyright (C) 2003 Federico Di Gregorio <fog@debian.org>
4  *
5  * This file is part of psycopg.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2,
10  * or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #include <Python.h>
23 #include <string.h>
24
25 #define PSYCOPG_MODULE
26 #include "psycopg/config.h"
27 #include "psycopg/psycopg.h"
28 #include "psycopg/connection.h"
29 #include "psycopg/cursor.h"
30 #include "psycopg/pqpath.h"
31
32 /* conn_notice_callback - process notices */
33
34 void
35 conn_notice_callback(void *args, const char *message)
36 {
37     connectionObject *self = (connectionObject *)args;
38
39     Dprintf("conn_notice_callback: %s", message);
40
41     /* unfortunately the old protocl return COPY FROM errors only as notices,
42        so we need to filter them looking for such errors */
43     if (strncmp(message, "ERROR", 5) == 0)
44         pq_set_critical(self, message);
45     else
46         PyList_Append(self->notice_list, PyString_FromString(message));
47 }
48
49 /* conn_connect - execute a connection to the dataabase */
50
51 int
52 conn_connect(connectionObject *self)
53 {
54     PGconn *pgconn;
55     PGresult *pgres;
56     char *data, *tmp;
57     int i;
58     
59     /* we need the initial date style to be ISO, for typecasters; if the user
60        later change it, she must know what she's doing... */
61     const char *datestyle = "SET DATESTYLE TO 'ISO'";
62     const char *encoding  = "SHOW client_encoding";
63     const char *isolevel  = "SHOW default_transaction_isolation";
64     
65     const char *lvl1a = "read uncommitted";
66     const char *lvl1b = "read committed";
67     const char *lvl2a = "repeatable read";
68     const char *lvl2b = "serializable";
69     
70     Py_BEGIN_ALLOW_THREADS;
71     pgconn = PQconnectdb(self->dsn);
72     Py_END_ALLOW_THREADS;
73     
74     Dprintf("conn_connect: new postgresql connection at %p", pgconn);
75
76     if (pgconn == NULL)
77     {
78         Dprintf("conn_connect: PQconnectdb(%s) FAILED", self->dsn);
79         PyErr_SetString(OperationalError, "PQconnectdb() failed");
80         return -1;
81     }
82     else if (PQstatus(pgconn) == CONNECTION_BAD)
83     {
84         Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn);
85         PyErr_SetString(OperationalError, PQerrorMessage(pgconn));
86         PQfinish(pgconn);
87         return -1;
88     }
89
90     PQsetNoticeProcessor(pgconn, conn_notice_callback, (void*)self);
91
92     Py_BEGIN_ALLOW_THREADS;
93     pgres = PQexec(pgconn, datestyle);
94     Py_END_ALLOW_THREADS;
95
96     if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
97         PyErr_SetString(OperationalError, "can't set datestyle to ISO");
98         PQfinish(pgconn);
99         IFCLEARPGRES(pgres);
100         return -1;
101     }
102     CLEARPGRES(pgres);
103
104     Py_BEGIN_ALLOW_THREADS;
105     pgres = PQexec(pgconn, encoding);
106     Py_END_ALLOW_THREADS;
107
108     if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
109         PyErr_SetString(OperationalError, "can't fetch client_encoding");
110         PQfinish(pgconn);
111         IFCLEARPGRES(pgres);
112         return -1;
113     }
114     tmp = PQgetvalue(pgres, 0, 0);
115     self->encoding = PyMem_Malloc(strlen(tmp)+1);
116     if (self->encoding == NULL) {
117         /* exception already set by PyMem_Malloc() */
118         PQfinish(pgconn);
119         IFCLEARPGRES(pgres);
120         return -1;
121     }  
122     for (i=0 ; i < strlen(tmp) ; i++)
123         self->encoding[i] = toupper(tmp[i]);
124     self->encoding[i] = '\0';
125     CLEARPGRES(pgres);
126     
127     Py_BEGIN_ALLOW_THREADS;
128     pgres = PQexec(pgconn, isolevel);
129     Py_END_ALLOW_THREADS;
130
131     if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) {
132         PyErr_SetString(OperationalError,
133                          "can't fetch default_isolation_level");
134         PQfinish(pgconn);
135         IFCLEARPGRES(pgres);
136         return -1;
137     }
138     data = PQgetvalue(pgres, 0, 0);
139     if ((strncmp(lvl1a, data, strlen(lvl1a)) == 0)
140         || (strncmp(lvl1b, data, strlen(lvl1b)) == 0))
141         self->isolation_level = 1;
142     else if ((strncmp(lvl2a, data, strlen(lvl2a)) == 0)
143         || (strncmp(lvl2b, data, strlen(lvl2b)) == 0))
144         self->isolation_level = 2;
145     else
146         self->isolation_level = 2;
147     CLEARPGRES(pgres);
148
149     if (PQsetnonblocking(pgconn, 1) != 0) {
150         Dprintf("conn_connect: PQsetnonblocking() FAILED");
151         PyErr_SetString(OperationalError, "PQsetnonblocking() failed");
152         PQfinish(pgconn);
153         return -1;
154     }
155
156 #ifdef HAVE_PQPROTOCOL3
157     self->protocol = PQprotocolVersion(pgconn);
158 #else
159     self->protocol = 2;
160 #endif
161     Dprintf("conn_connect: using protocol %d", self->protocol);
162     
163     self->pgconn = pgconn;
164     return 0;
165 }
166
167 /* conn_close - do anything needed to shut down the connection */
168
169 void
170 conn_close(connectionObject *self)
171 {
172     /* sets this connection as closed even for other threads; also note that
173        we need to check the value of pgconn, because we get called even when
174        the connection fails! */
175     Py_BEGIN_ALLOW_THREADS;
176     pthread_mutex_lock(&self->lock);
177
178     self->closed = 1;
179
180     /* execute a forced rollback on the connection (but don't check the
181        result, we're going to close the pq connection anyway */    
182     if (self->pgconn) {
183         pq_abort(self);
184         PQfinish(self->pgconn);
185         Dprintf("conn_close: PQfinish called");
186         self->pgconn = NULL;
187     }
188
189     pthread_mutex_unlock(&self->lock);
190     Py_END_ALLOW_THREADS;
191
192 }
193
194 /* conn_commit - commit on a connection */
195
196 int
197 conn_commit(connectionObject *self)
198 {
199     int res;
200
201     Py_BEGIN_ALLOW_THREADS;
202     pthread_mutex_lock(&self->lock);
203
204     res = pq_commit(self);
205     self->mark++;
206     
207     pthread_mutex_unlock(&self->lock);
208     Py_END_ALLOW_THREADS;
209
210     return res;
211 }
212
213 /* conn_rollback - rollback a connection */
214
215 int
216 conn_rollback(connectionObject *self)
217 {
218     int res;
219
220     Py_BEGIN_ALLOW_THREADS;
221     pthread_mutex_lock(&self->lock);
222
223     res = pq_abort(self);
224     self->mark++;
225     
226     pthread_mutex_unlock(&self->lock);
227     Py_END_ALLOW_THREADS;
228
229     return res;
230 }
231
232 /* conn_switch_isolation_level - switch isolation level on the connection */
233
234 int
235 conn_switch_isolation_level(connectionObject *self, int level)
236 {
237     int res = 0;
238
239     Py_BEGIN_ALLOW_THREADS;
240     pthread_mutex_lock(&self->lock);
241     
242     /* if the current isolation level is > 0 we need to abort the current
243        transaction before changing; that all folks! */
244     if (self->isolation_level != level && self->isolation_level > 0) {
245         res = pq_abort(self);
246     }
247     self->isolation_level = level;
248     self->mark++;
249     
250     Dprintf("conn_switch_isolation_level: switched to level %d", level);
251     
252     pthread_mutex_unlock(&self->lock);
253     Py_END_ALLOW_THREADS;
254
255     return res;   
256 }
257
258 /* conn_set_client_encoding - switch client encoding on connection */
259
260 int
261 conn_set_client_encoding(connectionObject *self, char *enc)
262 {
263     PGresult *pgres;
264     char query[48];
265     int res = 0;
266     
267     /* TODO: check for async query here and raise error if necessary */
268     
269     Py_BEGIN_ALLOW_THREADS;
270     pthread_mutex_lock(&self->lock);
271     
272     /* set encoding, no encoding string is longer than 24 bytes */
273     PyOS_snprintf(query, 47, "SET client_encoding = '%s'", enc);
274
275     /* abort the current transaction, to set the encoding ouside of
276        transactions */
277     res = pq_abort(self);
278
279     if (res == 0) {
280         pgres = PQexec(self->pgconn, query);
281
282         if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
283             res = -1;
284         }
285         else {
286             /* no error, we can proceeed and store the new encoding */
287             if (self->encoding) free(self->encoding);
288             self->encoding = strdup(enc);
289         }
290
291         IFCLEARPGRES(pgres);
292     }
293     
294     Dprintf("conn_set_client_encoding: set encoding to %s", self->encoding);
295     
296     pthread_mutex_unlock(&self->lock);
297     Py_END_ALLOW_THREADS;
298
299     if (res == -1)
300         PyErr_Format(OperationalError, "can't set encoding to %s", enc);
301         
302     return res;   
303 }