...
[plcapi.git] / psycopg2 / psycopg / connection_type.c
1 /* connection_type.c - python interface to connection objects
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 <structmember.h>
24 #include <stringobject.h>
25
26 #include <string.h>
27
28 #define PSYCOPG_MODULE
29 #include "psycopg/config.h"
30 #include "psycopg/python.h"
31 #include "psycopg/psycopg.h"
32 #include "psycopg/connection.h"
33 #include "psycopg/cursor.h"
34
35 /** DBAPI methods **/
36
37 /* cursor method - allocate a new cursor */
38
39 #define psyco_conn_cursor_doc \
40 "cursor(cursor_factory=extensions.cursor) -- new cursor\n\n"                \
41 "Return a new cursor.\n\nThe ``cursor_factory`` argument can be used to\n"  \
42 "create non-standard cursors by passing a class different from the\n"       \
43 "default. Note that the new class *should* be a sub-class of\n"             \
44 "`extensions.cursor`.\n\n"                                                  \
45 ":rtype: `extensions.cursor`"
46
47 static PyObject *
48 psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
49 {
50     char *name = NULL;
51     PyObject *obj, *factory = NULL;
52
53     static char *kwlist[] = {"name", "cursor_factory", NULL};
54     
55     if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sO", kwlist,
56                                      &name, &factory)) {
57         return NULL;
58     }
59
60     EXC_IF_CONN_CLOSED(self);
61
62     Dprintf("psyco_conn_cursor: new cursor for connection at %p", self);
63     Dprintf("psyco_conn_cursor:     parameters: name = %s", name);
64     
65     if (factory == NULL) factory = (PyObject *)&cursorType;
66     if (name)
67         obj = PyObject_CallFunction(factory, "Os", self, name);    
68     else
69         obj = PyObject_CallFunction(factory, "O", self);
70
71     if (obj == NULL) return NULL;
72     if (PyObject_IsInstance(obj, (PyObject *)&cursorType) == 0) {
73         PyErr_SetString(PyExc_TypeError,
74             "cursor factory must be subclass of psycopg2._psycopg.cursor");
75         Py_DECREF(obj);
76         return NULL;
77     }
78     
79     Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = %d",
80             obj, obj->ob_refcnt);
81     return obj;
82 }
83
84
85 /* close method - close the connection and all related cursors */
86
87 #define psyco_conn_close_doc "close() -- Close the connection."
88
89 static PyObject *
90 psyco_conn_close(connectionObject *self, PyObject *args)
91 {
92     EXC_IF_CONN_CLOSED(self);
93
94     if (!PyArg_ParseTuple(args, "")) return NULL;
95                                      
96     Dprintf("psyco_conn_close: closing connection at %p", self);
97     conn_close(self);
98     Dprintf("psyco_conn_close: connection at %p closed", self);
99
100     Py_INCREF(Py_None);
101     return Py_None;
102 }
103
104
105 /* commit method - commit all changes to the database */
106
107 #define psyco_conn_commit_doc "commit() -- Commit all changes to database."
108
109 static PyObject *
110 psyco_conn_commit(connectionObject *self, PyObject *args)
111 {
112     EXC_IF_CONN_CLOSED(self);
113
114     if (!PyArg_ParseTuple(args, "")) return NULL;
115
116     /* FIXME: check return status? */
117     conn_commit(self);
118
119     Py_INCREF(Py_None);
120     return Py_None;
121 }
122
123
124 /* rollback method - roll back all changes done to the database */
125
126 #define psyco_conn_rollback_doc \
127 "rollback() -- Roll back all changes done to database."
128
129 static PyObject *
130 psyco_conn_rollback(connectionObject *self, PyObject *args)
131 {
132     EXC_IF_CONN_CLOSED(self);
133
134     if (!PyArg_ParseTuple(args, "")) return NULL;
135
136     /* FIXME: check return status? */
137     conn_rollback(self);
138
139     Py_INCREF(Py_None);
140     return Py_None;
141 }
142
143
144 #ifdef PSYCOPG_EXTENSIONS
145 /* set_isolation_level method - switch connection isolation level */
146
147 #define psyco_conn_set_isolation_level_doc \
148 "set_isolation_level(level) -- Switch isolation level to ``level``."
149
150 static PyObject *
151 psyco_conn_set_isolation_level(connectionObject *self, PyObject *args)
152 {
153     int level = 1;
154     
155     EXC_IF_CONN_CLOSED(self);
156
157     if (!PyArg_ParseTuple(args, "i", &level)) return NULL;
158
159     if (level < 0 || level > 2) {
160         PyErr_SetString(PyExc_ValueError,
161                         "isolation level out of bounds (0,3)");
162         return NULL;
163     }
164     
165     /* FIXME: check return status? */
166     conn_switch_isolation_level(self, level);
167
168     Py_INCREF(Py_None);
169     return Py_None;
170 }
171
172 \f
173
174 /* set_isolation_level method - switch connection isolation level */
175
176 #define psyco_conn_set_client_encoding_doc \
177 "set_client_encoding(encoding) -- Set client encoding to ``encoding``."
178
179 static PyObject *
180 psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
181 {
182     char *enc = NULL;
183     
184     EXC_IF_CONN_CLOSED(self);
185
186     if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
187     
188     if (conn_set_client_encoding(self, enc) == 0) {
189         Py_INCREF(Py_None);
190         return Py_None;
191     }
192     else {
193         return NULL;
194     }
195 }
196 #endif
197
198
199 /** the connection object **/
200
201
202 /* object method list */
203
204 static struct PyMethodDef connectionObject_methods[] = {
205     {"cursor", (PyCFunction)psyco_conn_cursor,
206      METH_VARARGS|METH_KEYWORDS, psyco_conn_cursor_doc},
207     {"close", (PyCFunction)psyco_conn_close,
208      METH_VARARGS, psyco_conn_close_doc},
209     {"commit", (PyCFunction)psyco_conn_commit,
210      METH_VARARGS, psyco_conn_commit_doc},
211     {"rollback", (PyCFunction)psyco_conn_rollback,
212      METH_VARARGS, psyco_conn_rollback_doc},
213 #ifdef PSYCOPG_EXTENSIONS
214     {"set_isolation_level", (PyCFunction)psyco_conn_set_isolation_level,
215      METH_VARARGS, psyco_conn_set_isolation_level_doc},
216     {"set_client_encoding", (PyCFunction)psyco_conn_set_client_encoding,
217      METH_VARARGS, psyco_conn_set_client_encoding_doc},    
218 #endif    
219     {NULL}
220 };
221
222 /* object member list */
223
224 static struct PyMemberDef connectionObject_members[] = {
225     /* DBAPI-2.0 extensions (exception objects) */
226     {"Error", T_OBJECT, 
227         offsetof(connectionObject, exc_Error), RO, Error_doc},
228     {"Warning", 
229         T_OBJECT, offsetof(connectionObject, exc_Warning), RO, Warning_doc},
230     {"InterfaceError", T_OBJECT,
231         offsetof(connectionObject, exc_InterfaceError), RO,
232         InterfaceError_doc},
233     {"DatabaseError", T_OBJECT,
234         offsetof(connectionObject, exc_DatabaseError), RO, DatabaseError_doc},
235     {"InternalError", T_OBJECT,
236         offsetof(connectionObject, exc_InternalError), RO, InternalError_doc},
237     {"OperationalError", T_OBJECT,
238         offsetof(connectionObject, exc_OperationalError), RO,
239         OperationalError_doc},
240     {"ProgrammingError", T_OBJECT,
241         offsetof(connectionObject, exc_ProgrammingError), RO,
242         ProgrammingError_doc},
243     {"IntegrityError", T_OBJECT,
244         offsetof(connectionObject, exc_IntegrityError), RO,
245         IntegrityError_doc},
246     {"DataError", T_OBJECT,
247         offsetof(connectionObject, exc_DataError), RO, DataError_doc},
248     {"NotSupportedError", T_OBJECT,
249         offsetof(connectionObject, exc_NotSupportedError), RO,
250         NotSupportedError_doc},
251 #ifdef PSYCOPG_EXTENSIONS    
252     {"closed", T_LONG, offsetof(connectionObject, closed), RO,
253         "True if the connection is closed."},
254     {"isolation_level", T_LONG,
255         offsetof(connectionObject, isolation_level), RO,
256         "The current isolation level."},
257     {"encoding", T_STRING, offsetof(connectionObject, encoding), RO,
258         "The current client encoding."},
259     {"notices", T_OBJECT, offsetof(connectionObject, notice_list), RO},
260     {"notifies", T_OBJECT, offsetof(connectionObject, notifies), RO},
261     {"dsn", T_STRING, offsetof(connectionObject, dsn), RO,
262         "The current connection string."},
263     {"status", T_LONG,
264         offsetof(connectionObject, status), RO,
265         "The current transaction status."},
266 #endif    
267     {NULL}
268 };
269
270 /* initialization and finalization methods */
271
272 static int
273 connection_setup(connectionObject *self, char *dsn)
274 {
275     Dprintf("connection_setup: init connection object at %p, refcnt = %d",
276             self, ((PyObject *)self)->ob_refcnt);
277     
278     self->dsn = strdup(dsn);
279     self->notice_list = PyList_New(0);
280     self->notifies = PyList_New(0);
281     self->closed = 0;
282     self->status = CONN_STATUS_READY;
283     self->critical = NULL;
284     self->async_cursor = NULL;
285     self->pgconn = NULL;
286     self->mark = 0;
287     
288     pthread_mutex_init(&(self->lock), NULL);
289  
290     if (conn_connect(self) != 0) {
291         pthread_mutex_destroy(&(self->lock));
292         Dprintf("connection_init: FAILED");
293         return -1;
294     }
295  
296     Dprintf("connection_setup: good connection object at %p, refcnt = %d",
297             self, ((PyObject *)self)->ob_refcnt);
298     return 0;
299 }
300
301 static void
302 connection_dealloc(PyObject* obj)
303 {
304     connectionObject *self = (connectionObject *)obj;
305
306     if (self->closed == 0) conn_close(self);
307     
308     if (self->dsn) free(self->dsn);
309     if (self->encoding) PyMem_Free(self->encoding);
310     if (self->critical) free(self->critical);
311     
312     Py_XDECREF(self->notice_list);
313     Py_XDECREF(self->notifies);
314     Py_XDECREF(self->async_cursor);
315     
316     pthread_mutex_destroy(&(self->lock));
317
318     Dprintf("connection_dealloc: deleted connection object at %p, refcnt = %d",
319             obj, obj->ob_refcnt);
320
321     obj->ob_type->tp_free(obj);
322 }
323
324 static int
325 connection_init(PyObject *obj, PyObject *args, PyObject *kwds)
326 {
327     char *dsn;
328
329     if (!PyArg_ParseTuple(args, "s", &dsn))
330         return -1;
331
332     return connection_setup((connectionObject *)obj, dsn);
333 }
334
335 static PyObject *
336 connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
337 {
338     return type->tp_alloc(type, 0);
339 }
340
341 static void
342 connection_del(PyObject* self)
343 {
344     PyObject_Del(self);
345 }
346
347 static PyObject *
348 connection_repr(connectionObject *self)
349 {
350     return PyString_FromFormat(
351         "<connection object at %p; dsn: '%s', closed: %ld>",
352         self, self->dsn, self->closed);
353 }
354
355
356 /* object type */
357
358 #define connectionType_doc \
359 "connection(dsn, ...) -> new connection object\n\n" \
360 ":Groups:\n" \
361 "  * `DBAPI-2.0 errors`: Error, Warning, InterfaceError,\n" \
362 "    DatabaseError, InternalError, OperationalError,\n" \
363 "    ProgrammingError, IntegrityError, DataError, NotSupportedError"
364
365 PyTypeObject connectionType = {
366     PyObject_HEAD_INIT(NULL)
367     0,
368     "psycopg2._psycopg.connection",
369     sizeof(connectionObject),
370     0,
371     connection_dealloc, /*tp_dealloc*/
372     0,          /*tp_print*/ 
373     0,          /*tp_getattr*/
374     0,          /*tp_setattr*/
375     0,          /*tp_compare*/
376     (reprfunc)connection_repr, /*tp_repr*/
377     0,          /*tp_as_number*/
378     0,          /*tp_as_sequence*/
379     0,          /*tp_as_mapping*/
380     0,          /*tp_hash */
381
382     0,          /*tp_call*/
383     (reprfunc)connection_repr, /*tp_str*/
384     0,          /*tp_getattro*/
385     0,          /*tp_setattro*/
386     0,          /*tp_as_buffer*/
387
388     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
389     connectionType_doc, /*tp_doc*/
390     
391     0,          /*tp_traverse*/
392     0,          /*tp_clear*/
393
394     0,          /*tp_richcompare*/
395     0,          /*tp_weaklistoffset*/
396
397     0,          /*tp_iter*/
398     0,          /*tp_iternext*/
399
400     /* Attribute descriptor and subclassing stuff */
401
402     connectionObject_methods, /*tp_methods*/
403     connectionObject_members, /*tp_members*/
404     0,          /*tp_getset*/
405     0,          /*tp_base*/
406     0,          /*tp_dict*/
407     
408     0,          /*tp_descr_get*/
409     0,          /*tp_descr_set*/
410     0,          /*tp_dictoffset*/
411     
412     connection_init, /*tp_init*/
413     0, /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
414     connection_new, /*tp_new*/
415     (freefunc)connection_del, /*tp_free  Low-level free-memory routine */
416     0,          /*tp_is_gc For PyObject_IS_GC */
417     0,          /*tp_bases*/
418     0,          /*tp_mro method resolution order */
419     0,          /*tp_cache*/
420     0,          /*tp_subclasses*/
421     0           /*tp_weaklist*/
422 };