1 /* connection_type.c - python interface to connection objects
2  *
3  * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
4  * Copyright (C) 2020-2021 The Psycopg Team
5  *
6  * This file is part of psycopg.
7  *
8  * psycopg2 is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * In addition, as a special exception, the copyright holders give
14  * permission to link this program with the OpenSSL library (or with
15  * modified versions of OpenSSL that use the same license as OpenSSL),
16  * and distribute linked combinations including the two.
17  *
18  * You must obey the GNU Lesser General Public License in all respects for
19  * all of the code used other than OpenSSL.
20  *
21  * psycopg2 is distributed in the hope that it will be useful, but WITHOUT
22  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24  * License for more details.
25  */
26 
27 #define PSYCOPG_MODULE
28 #include "psycopg/psycopg.h"
29 
30 #include "psycopg/connection.h"
31 #include "psycopg/cursor.h"
32 #include "psycopg/pqpath.h"
33 #include "psycopg/conninfo.h"
34 #include "psycopg/lobject.h"
35 #include "psycopg/green.h"
36 #include "psycopg/xid.h"
37 
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 
42 extern HIDDEN const char *srv_isolevels[];
43 extern HIDDEN const char *srv_readonly[];
44 extern HIDDEN const char *srv_deferrable[];
45 extern HIDDEN const int SRV_STATE_UNCHANGED;
46 
47 /** DBAPI methods **/
48 
49 /* cursor method - allocate a new cursor */
50 
51 #define psyco_conn_cursor_doc \
52 "cursor(name=None, cursor_factory=extensions.cursor, withhold=False) -- new cursor\n\n"     \
53 "Return a new cursor.\n\nThe ``cursor_factory`` argument can be used to\n"  \
54 "create non-standard cursors by passing a class different from the\n"       \
55 "default. Note that the new class *should* be a sub-class of\n"             \
56 "`extensions.cursor`.\n\n"                                                  \
57 ":rtype: `extensions.cursor`"
58 
59 static PyObject *
psyco_conn_cursor(connectionObject * self,PyObject * args,PyObject * kwargs)60 psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs)
61 {
62     PyObject *obj = NULL;
63     PyObject *rv = NULL;
64     PyObject *name = Py_None;
65     PyObject *factory = Py_None;
66     PyObject *withhold = Py_False;
67     PyObject *scrollable = Py_None;
68 
69     static char *kwlist[] = {
70         "name", "cursor_factory", "withhold", "scrollable", NULL};
71 
72     EXC_IF_CONN_CLOSED(self);
73 
74     if (!PyArg_ParseTupleAndKeywords(
75             args, kwargs, "|OOOO", kwlist,
76             &name, &factory, &withhold, &scrollable)) {
77         goto exit;
78     }
79 
80     if (factory == Py_None) {
81         if (self->cursor_factory && self->cursor_factory != Py_None) {
82             factory = self->cursor_factory;
83         }
84         else {
85             factory = (PyObject *)&cursorType;
86         }
87     }
88 
89     if (self->status != CONN_STATUS_READY &&
90         self->status != CONN_STATUS_BEGIN &&
91         self->status != CONN_STATUS_PREPARED) {
92         PyErr_SetString(OperationalError,
93                         "asynchronous connection attempt underway");
94         goto exit;
95     }
96 
97     if (name != Py_None && self->async == 1) {
98         PyErr_SetString(ProgrammingError,
99                         "asynchronous connections "
100                         "cannot produce named cursors");
101         goto exit;
102     }
103 
104     Dprintf("psyco_conn_cursor: new %s cursor for connection at %p",
105         (name == Py_None ? "unnamed" : "named"), self);
106 
107     if (!(obj = PyObject_CallFunctionObjArgs(factory, self, name, NULL))) {
108         goto exit;
109     }
110 
111     if (PyObject_IsInstance(obj, (PyObject *)&cursorType) == 0) {
112         PyErr_SetString(PyExc_TypeError,
113             "cursor factory must be subclass of psycopg2.extensions.cursor");
114         goto exit;
115     }
116 
117     if (0 > curs_withhold_set((cursorObject *)obj, withhold)) {
118         goto exit;
119     }
120     if (0 > curs_scrollable_set((cursorObject *)obj, scrollable)) {
121         goto exit;
122     }
123 
124     Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = "
125         FORMAT_CODE_PY_SSIZE_T,
126         obj, Py_REFCNT(obj)
127     );
128 
129     rv = obj;
130     obj = NULL;
131 
132 exit:
133     Py_XDECREF(obj);
134     return rv;
135 }
136 
137 
138 /* close method - close the connection and all related cursors */
139 
140 #define psyco_conn_close_doc "close() -- Close the connection."
141 
142 static PyObject *
psyco_conn_close(connectionObject * self,PyObject * dummy)143 psyco_conn_close(connectionObject *self, PyObject *dummy)
144 {
145     Dprintf("psyco_conn_close: closing connection at %p", self);
146     conn_close(self);
147     Dprintf("psyco_conn_close: connection at %p closed", self);
148 
149     Py_RETURN_NONE;
150 }
151 
152 
153 /* commit method - commit all changes to the database */
154 
155 #define psyco_conn_commit_doc "commit() -- Commit all changes to database."
156 
157 static PyObject *
psyco_conn_commit(connectionObject * self,PyObject * dummy)158 psyco_conn_commit(connectionObject *self, PyObject *dummy)
159 {
160     EXC_IF_CONN_CLOSED(self);
161     EXC_IF_CONN_ASYNC(self, commit);
162     EXC_IF_TPC_BEGIN(self, commit);
163 
164     if (conn_commit(self) < 0)
165         return NULL;
166 
167     Py_RETURN_NONE;
168 }
169 
170 
171 /* rollback method - roll back all changes done to the database */
172 
173 #define psyco_conn_rollback_doc \
174 "rollback() -- Roll back all changes done to database."
175 
176 static PyObject *
psyco_conn_rollback(connectionObject * self,PyObject * dummy)177 psyco_conn_rollback(connectionObject *self, PyObject *dummy)
178 {
179     EXC_IF_CONN_CLOSED(self);
180     EXC_IF_CONN_ASYNC(self, rollback);
181     EXC_IF_TPC_BEGIN(self, rollback);
182 
183     if (conn_rollback(self) < 0)
184         return NULL;
185 
186     Py_RETURN_NONE;
187 }
188 
189 
190 #define psyco_conn_xid_doc \
191 "xid(format_id, gtrid, bqual) -- create a transaction identifier."
192 
193 static PyObject *
psyco_conn_xid(connectionObject * self,PyObject * args,PyObject * kwargs)194 psyco_conn_xid(connectionObject *self, PyObject *args, PyObject *kwargs)
195 {
196     EXC_IF_CONN_CLOSED(self);
197     EXC_IF_TPC_NOT_SUPPORTED(self);
198 
199     return PyObject_Call((PyObject *)&xidType, args, kwargs);
200 }
201 
202 
203 #define psyco_conn_tpc_begin_doc \
204 "tpc_begin(xid) -- begin a TPC transaction with given transaction ID xid."
205 
206 static PyObject *
psyco_conn_tpc_begin(connectionObject * self,PyObject * args)207 psyco_conn_tpc_begin(connectionObject *self, PyObject *args)
208 {
209     PyObject *rv = NULL;
210     xidObject *xid = NULL;
211     PyObject *oxid;
212 
213     EXC_IF_CONN_CLOSED(self);
214     EXC_IF_CONN_ASYNC(self, tpc_begin);
215     EXC_IF_TPC_NOT_SUPPORTED(self);
216     EXC_IF_IN_TRANSACTION(self, tpc_begin);
217 
218     if (!PyArg_ParseTuple(args, "O", &oxid)) {
219         goto exit;
220     }
221 
222     if (NULL == (xid = xid_ensure(oxid))) {
223         goto exit;
224     }
225 
226     /* two phase commit and autocommit make no point */
227     if (self->autocommit) {
228         PyErr_SetString(ProgrammingError,
229             "tpc_begin can't be called in autocommit mode");
230         goto exit;
231     }
232 
233     if (conn_tpc_begin(self, xid) < 0) {
234         goto exit;
235     }
236 
237     Py_INCREF(Py_None);
238     rv = Py_None;
239 
240 exit:
241     Py_XDECREF(xid);
242     return rv;
243 }
244 
245 
246 #define psyco_conn_tpc_prepare_doc \
247 "tpc_prepare() -- perform the first phase of a two-phase transaction."
248 
249 static PyObject *
psyco_conn_tpc_prepare(connectionObject * self,PyObject * dummy)250 psyco_conn_tpc_prepare(connectionObject *self, PyObject *dummy)
251 {
252     EXC_IF_CONN_CLOSED(self);
253     EXC_IF_CONN_ASYNC(self, tpc_prepare);
254     EXC_IF_TPC_PREPARED(self, tpc_prepare);
255 
256     if (NULL == self->tpc_xid) {
257         PyErr_SetString(ProgrammingError,
258             "prepare must be called inside a two-phase transaction");
259         return NULL;
260     }
261 
262     if (0 > conn_tpc_command(self, "PREPARE TRANSACTION", self->tpc_xid)) {
263         return NULL;
264     }
265 
266     /* transaction prepared: set the state so that no operation
267      * can be performed until commit. */
268     self->status = CONN_STATUS_PREPARED;
269 
270     Py_RETURN_NONE;
271 }
272 
273 
274 /* the type of conn_commit/conn_rollback */
275 typedef int (*_finish_f)(connectionObject *self);
276 
277 /* Implement tpc_commit/tpc_rollback.
278  *
279  * This is a common framework performing the chechs and state manipulation
280  * common to the two functions.
281  *
282  * Parameters are:
283  * - self, args: passed by Python
284  * - opc_f: the function to call in case of one-phase commit/rollback
285  *          one of conn_commit/conn_rollback
286  * - tpc_cmd: the command to execute for a two-phase commit/rollback
287  *
288  * The function can be called in three cases:
289  * - If xid is specified, the status must be "ready";
290  *   issue the commit/rollback prepared.
291  * - if xid is not specified and status is "begin" with a xid,
292  *   issue a normal commit/rollback.
293  * - if xid is not specified and status is "prepared",
294  *   issue the commit/rollback prepared.
295  */
296 static PyObject *
_psyco_conn_tpc_finish(connectionObject * self,PyObject * args,_finish_f opc_f,char * tpc_cmd)297 _psyco_conn_tpc_finish(connectionObject *self, PyObject *args,
298     _finish_f opc_f, char *tpc_cmd)
299 {
300     PyObject *oxid = NULL;
301     xidObject *xid = NULL;
302     PyObject *rv = NULL;
303 
304     if (!PyArg_ParseTuple(args, "|O", &oxid)) { goto exit; }
305 
306     if (oxid) {
307         if (!(xid = xid_ensure(oxid))) { goto exit; }
308     }
309 
310     if (xid) {
311         /* committing/aborting a recovered transaction. */
312         if (self->status != CONN_STATUS_READY) {
313             PyErr_SetString(ProgrammingError,
314                 "tpc_commit/tpc_rollback with a xid "
315                 "must be called outside a transaction");
316             goto exit;
317         }
318         if (0 > conn_tpc_command(self, tpc_cmd, xid)) {
319             goto exit;
320         }
321     } else {
322         /* committing/aborting our own transaction. */
323         if (!self->tpc_xid) {
324             PyErr_SetString(ProgrammingError,
325                 "tpc_commit/tpc_rollback with no parameter "
326                 "must be called in a two-phase transaction");
327             goto exit;
328         }
329 
330         switch (self->status) {
331           case CONN_STATUS_BEGIN:
332             if (0 > opc_f(self)) { goto exit; }
333             break;
334 
335           case CONN_STATUS_PREPARED:
336             if (0 > conn_tpc_command(self, tpc_cmd, self->tpc_xid)) {
337                 goto exit;
338             }
339             break;
340 
341           default:
342             PyErr_SetString(InterfaceError,
343                 "unexpected state in tpc_commit/tpc_rollback");
344             goto exit;
345         }
346 
347         Py_CLEAR(self->tpc_xid);
348 
349         /* connection goes ready */
350         self->status = CONN_STATUS_READY;
351     }
352 
353     Py_INCREF(Py_None);
354     rv = Py_None;
355 
356 exit:
357     Py_XDECREF(xid);
358     return rv;
359 }
360 
361 #define psyco_conn_tpc_commit_doc \
362 "tpc_commit([xid]) -- commit a transaction previously prepared."
363 
364 static PyObject *
psyco_conn_tpc_commit(connectionObject * self,PyObject * args)365 psyco_conn_tpc_commit(connectionObject *self, PyObject *args)
366 {
367     EXC_IF_CONN_CLOSED(self);
368     EXC_IF_CONN_ASYNC(self, tpc_commit);
369     EXC_IF_TPC_NOT_SUPPORTED(self);
370 
371     return _psyco_conn_tpc_finish(self, args,
372                                   conn_commit, "COMMIT PREPARED");
373 }
374 
375 #define psyco_conn_tpc_rollback_doc \
376 "tpc_rollback([xid]) -- abort a transaction previously prepared."
377 
378 static PyObject *
psyco_conn_tpc_rollback(connectionObject * self,PyObject * args)379 psyco_conn_tpc_rollback(connectionObject *self, PyObject *args)
380 {
381     EXC_IF_CONN_CLOSED(self);
382     EXC_IF_CONN_ASYNC(self, tpc_rollback);
383     EXC_IF_TPC_NOT_SUPPORTED(self);
384 
385     return _psyco_conn_tpc_finish(self, args,
386                                   conn_rollback, "ROLLBACK PREPARED");
387 }
388 
389 #define psyco_conn_tpc_recover_doc \
390 "tpc_recover() -- returns a list of pending transaction IDs."
391 
392 static PyObject *
psyco_conn_tpc_recover(connectionObject * self,PyObject * dummy)393 psyco_conn_tpc_recover(connectionObject *self, PyObject *dummy)
394 {
395     EXC_IF_CONN_CLOSED(self);
396     EXC_IF_CONN_ASYNC(self, tpc_recover);
397     EXC_IF_TPC_PREPARED(self, tpc_recover);
398     EXC_IF_TPC_NOT_SUPPORTED(self);
399 
400     return conn_tpc_recover(self);
401 }
402 
403 
404 #define psyco_conn_enter_doc \
405 "__enter__ -> self"
406 
407 static PyObject *
psyco_conn_enter(connectionObject * self,PyObject * dummy)408 psyco_conn_enter(connectionObject *self, PyObject *dummy)
409 {
410     PyObject *rv = NULL;
411 
412     EXC_IF_CONN_CLOSED(self);
413 
414     if (self->entered) {
415         PyErr_SetString(ProgrammingError,
416             "the connection cannot be re-entered recursively");
417         goto exit;
418     }
419 
420     self->entered = 1;
421     Py_INCREF(self);
422     rv = (PyObject *)self;
423 
424 exit:
425     return rv;
426 }
427 
428 
429 #define psyco_conn_exit_doc \
430 "__exit__ -- commit if no exception, else roll back"
431 
432 static PyObject *
psyco_conn_exit(connectionObject * self,PyObject * args)433 psyco_conn_exit(connectionObject *self, PyObject *args)
434 {
435     PyObject *type, *name, *tb;
436     PyObject *tmp = NULL;
437     PyObject *rv = NULL;
438 
439     if (!PyArg_ParseTuple(args, "OOO", &type, &name, &tb)) {
440         goto exit;
441     }
442 
443     /* even if there will be an error, consider ourselves out */
444     self->entered = 0;
445 
446     if (type == Py_None) {
447         if (!(tmp = PyObject_CallMethod((PyObject *)self, "commit", NULL))) {
448             goto exit;
449         }
450     } else {
451         if (!(tmp = PyObject_CallMethod((PyObject *)self, "rollback", NULL))) {
452             goto exit;
453         }
454     }
455 
456     /* success (of the commit or rollback, there may have been an exception in
457      * the block). Return None to avoid swallowing the exception */
458     rv = Py_None;
459     Py_INCREF(rv);
460 
461 exit:
462     Py_XDECREF(tmp);
463     return rv;
464 }
465 
466 
467 /* parse a python object into one of the possible isolation level values */
468 
469 RAISES_NEG static int
_psyco_conn_parse_isolevel(PyObject * pyval)470 _psyco_conn_parse_isolevel(PyObject *pyval)
471 {
472     int rv = -1;
473     long level;
474 
475     Py_INCREF(pyval);   /* for ensure_bytes */
476 
477     /* None is default. This is only used when setting the property, because
478      * set_session() has None used as "don't change" */
479     if (pyval == Py_None) {
480         rv = ISOLATION_LEVEL_DEFAULT;
481     }
482 
483     /* parse from one of the level constants */
484     else if (PyInt_Check(pyval)) {
485         level = PyInt_AsLong(pyval);
486         if (level == -1 && PyErr_Occurred()) { goto exit; }
487         if (level < 1 || level > 4) {
488             PyErr_SetString(PyExc_ValueError,
489                 "isolation_level must be between 1 and 4");
490             goto exit;
491         }
492 
493         rv = level;
494     }
495 
496     /* parse from the string -- this includes "default" */
497     else {
498         if (!(pyval = psyco_ensure_bytes(pyval))) {
499             goto exit;
500         }
501         for (level = 1; level <= 4; level++) {
502             if (0 == strcasecmp(srv_isolevels[level], Bytes_AS_STRING(pyval))) {
503                 rv = level;
504                 break;
505             }
506         }
507         if (rv < 0 && 0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
508             rv = ISOLATION_LEVEL_DEFAULT;
509         }
510         if (rv < 0) {
511             PyErr_Format(PyExc_ValueError,
512                 "bad value for isolation_level: '%s'", Bytes_AS_STRING(pyval));
513             goto exit;
514         }
515     }
516 
517 exit:
518     Py_XDECREF(pyval);
519 
520     return rv;
521 }
522 
523 /* convert False/True/"default" -> 0/1/2 */
524 
525 RAISES_NEG static int
_psyco_conn_parse_onoff(PyObject * pyval)526 _psyco_conn_parse_onoff(PyObject *pyval)
527 {
528     int rv = -1;
529 
530     Py_INCREF(pyval);   /* for ensure_bytes */
531 
532     if (pyval == Py_None) {
533         rv = STATE_DEFAULT;
534     }
535     else if (PyUnicode_CheckExact(pyval) || Bytes_CheckExact(pyval)) {
536         if (!(pyval = psyco_ensure_bytes(pyval))) {
537             goto exit;
538         }
539         if (0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
540             rv = STATE_DEFAULT;
541         }
542         else {
543             PyErr_Format(PyExc_ValueError,
544                 "the only string accepted is 'default'; got %s",
545                 Bytes_AS_STRING(pyval));
546             goto exit;
547         }
548     }
549     else {
550         int istrue;
551         if (0 > (istrue = PyObject_IsTrue(pyval))) { goto exit; }
552         rv = istrue ? STATE_ON : STATE_OFF;
553     }
554 
555 exit:
556     Py_XDECREF(pyval);
557 
558     return rv;
559 }
560 
561 #define _set_session_checks(self,what) \
562 do { \
563     EXC_IF_CONN_CLOSED(self); \
564     EXC_IF_CONN_ASYNC(self, what); \
565     EXC_IF_IN_TRANSACTION(self, what); \
566     EXC_IF_TPC_PREPARED(self, what); \
567 } while(0)
568 
569 /* set_session - set default transaction characteristics */
570 
571 #define psyco_conn_set_session_doc \
572 "set_session(...) -- Set one or more parameters for the next transactions.\n\n" \
573 "Accepted arguments are 'isolation_level', 'readonly', 'deferrable', 'autocommit'."
574 
575 static PyObject *
psyco_conn_set_session(connectionObject * self,PyObject * args,PyObject * kwargs)576 psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs)
577 {
578     PyObject *isolevel = Py_None;
579     PyObject *readonly = Py_None;
580     PyObject *deferrable = Py_None;
581     PyObject *autocommit = Py_None;
582 
583     int c_isolevel = SRV_STATE_UNCHANGED;
584     int c_readonly = SRV_STATE_UNCHANGED;
585     int c_deferrable = SRV_STATE_UNCHANGED;
586     int c_autocommit = SRV_STATE_UNCHANGED;
587 
588     static char *kwlist[] =
589         {"isolation_level", "readonly", "deferrable", "autocommit", NULL};
590 
591     _set_session_checks(self, set_session);
592 
593     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOO", kwlist,
594             &isolevel, &readonly, &deferrable, &autocommit)) {
595         return NULL;
596     }
597 
598     if (Py_None != isolevel) {
599         if (0 > (c_isolevel = _psyco_conn_parse_isolevel(isolevel))) {
600             return NULL;
601         }
602     }
603 
604     if (Py_None != readonly) {
605         if (0 > (c_readonly = _psyco_conn_parse_onoff(readonly))) {
606             return NULL;
607         }
608     }
609     if (Py_None != deferrable) {
610         if (0 > (c_deferrable = _psyco_conn_parse_onoff(deferrable))) {
611             return NULL;
612         }
613     }
614 
615     if (Py_None != autocommit) {
616         if (-1 == (c_autocommit = PyObject_IsTrue(autocommit))) { return NULL; }
617     }
618 
619     if (0 > conn_set_session(
620                 self, c_autocommit, c_isolevel, c_readonly, c_deferrable)) {
621         return NULL;
622     }
623 
624     Py_RETURN_NONE;
625 }
626 
627 
628 /* autocommit - return or set the current autocommit status */
629 
630 #define psyco_conn_autocommit_doc \
631 "Set or return the autocommit status."
632 
633 static PyObject *
psyco_conn_autocommit_get(connectionObject * self)634 psyco_conn_autocommit_get(connectionObject *self)
635 {
636     return PyBool_FromLong(self->autocommit);
637 }
638 
639 BORROWED static PyObject *
_psyco_set_session_check_setter_wrapper(connectionObject * self)640 _psyco_set_session_check_setter_wrapper(connectionObject *self)
641 {
642     /* wrapper to use the EXC_IF macros.
643      * return NULL in case of error, else whatever */
644     _set_session_checks(self, set_session);
645     return Py_None;     /* borrowed */
646 }
647 
648 static int
psyco_conn_autocommit_set(connectionObject * self,PyObject * pyvalue)649 psyco_conn_autocommit_set(connectionObject *self, PyObject *pyvalue)
650 {
651     int value;
652 
653     if (!_psyco_set_session_check_setter_wrapper(self)) { return -1; }
654     if (-1 == (value = PyObject_IsTrue(pyvalue))) { return -1; }
655     if (0 > conn_set_session(self, value,
656                 SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED)) {
657         return -1;
658     }
659 
660     return 0;
661 }
662 
663 
664 /* isolation_level - return or set the current isolation level */
665 
666 #define psyco_conn_isolation_level_doc \
667 "Set or return the connection transaction isolation level."
668 
669 static PyObject *
psyco_conn_isolation_level_get(connectionObject * self)670 psyco_conn_isolation_level_get(connectionObject *self)
671 {
672     if (self->isolevel == ISOLATION_LEVEL_DEFAULT) {
673         Py_RETURN_NONE;
674     } else {
675         return PyInt_FromLong((long)self->isolevel);
676     }
677 }
678 
679 
680 static int
psyco_conn_isolation_level_set(connectionObject * self,PyObject * pyvalue)681 psyco_conn_isolation_level_set(connectionObject *self, PyObject *pyvalue)
682 {
683     int value;
684 
685     if (!_psyco_set_session_check_setter_wrapper(self)) { return -1; }
686     if (0 > (value = _psyco_conn_parse_isolevel(pyvalue))) { return -1; }
687     if (0 > conn_set_session(self, SRV_STATE_UNCHANGED,
688                 value, SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED)) {
689         return -1;
690     }
691 
692     return 0;
693 }
694 
695 
696 /* set_isolation_level method - switch connection isolation level */
697 
698 #define psyco_conn_set_isolation_level_doc \
699 "set_isolation_level(level) -- Switch isolation level to ``level``."
700 
701 static PyObject *
psyco_conn_set_isolation_level(connectionObject * self,PyObject * args)702 psyco_conn_set_isolation_level(connectionObject *self, PyObject *args)
703 {
704     int level = 1;
705     PyObject *pyval = NULL;
706 
707     EXC_IF_CONN_CLOSED(self);
708     EXC_IF_CONN_ASYNC(self, "isolation_level");
709     EXC_IF_TPC_PREPARED(self, "isolation_level");
710 
711     if (!PyArg_ParseTuple(args, "O", &pyval)) return NULL;
712 
713     if (pyval == Py_None) {
714         level = ISOLATION_LEVEL_DEFAULT;
715     }
716 
717     /* parse from one of the level constants */
718     else if (PyInt_Check(pyval)) {
719         level = PyInt_AsLong(pyval);
720 
721         if (level < 0 || level > 4) {
722             PyErr_SetString(PyExc_ValueError,
723                 "isolation level must be between 0 and 4");
724             return NULL;
725         }
726     }
727 
728     if (0 > conn_rollback(self)) {
729         return NULL;
730     }
731 
732     if (level == 0) {
733         if (0 > conn_set_session(self, 1,
734                 SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED)) {
735             return NULL;
736         }
737     }
738     else {
739         if (0 > conn_set_session(self, 0,
740                 level, SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED)) {
741             return NULL;
742         }
743     }
744 
745     Py_RETURN_NONE;
746 }
747 
748 
749 /* readonly - return or set the current read-only status */
750 
751 #define psyco_conn_readonly_doc \
752 "Set or return the connection read-only status."
753 
754 static PyObject *
psyco_conn_readonly_get(connectionObject * self)755 psyco_conn_readonly_get(connectionObject *self)
756 {
757     PyObject *rv = NULL;
758 
759     switch (self->readonly) {
760         case STATE_OFF:
761             rv = Py_False;
762             break;
763         case STATE_ON:
764             rv = Py_True;
765             break;
766         case STATE_DEFAULT:
767             rv = Py_None;
768             break;
769         default:
770             PyErr_Format(InternalError,
771                 "bad internal value for readonly: %d", self->readonly);
772             break;
773     }
774 
775     Py_XINCREF(rv);
776     return rv;
777 }
778 
779 
780 static int
psyco_conn_readonly_set(connectionObject * self,PyObject * pyvalue)781 psyco_conn_readonly_set(connectionObject *self, PyObject *pyvalue)
782 {
783     int value;
784 
785     if (!_psyco_set_session_check_setter_wrapper(self)) { return -1; }
786     if (0 > (value = _psyco_conn_parse_onoff(pyvalue))) { return -1; }
787     if (0 > conn_set_session(self, SRV_STATE_UNCHANGED,
788                 SRV_STATE_UNCHANGED, value, SRV_STATE_UNCHANGED)) {
789         return -1;
790     }
791 
792     return 0;
793 }
794 
795 
796 /* deferrable - return or set the current deferrable status */
797 
798 #define psyco_conn_deferrable_doc \
799 "Set or return the connection deferrable status."
800 
801 static PyObject *
psyco_conn_deferrable_get(connectionObject * self)802 psyco_conn_deferrable_get(connectionObject *self)
803 {
804     PyObject *rv = NULL;
805 
806     switch (self->deferrable) {
807         case STATE_OFF:
808             rv = Py_False;
809             break;
810         case STATE_ON:
811             rv = Py_True;
812             break;
813         case STATE_DEFAULT:
814             rv = Py_None;
815             break;
816         default:
817             PyErr_Format(InternalError,
818                 "bad internal value for deferrable: %d", self->deferrable);
819             break;
820     }
821 
822     Py_XINCREF(rv);
823     return rv;
824 }
825 
826 
827 static int
psyco_conn_deferrable_set(connectionObject * self,PyObject * pyvalue)828 psyco_conn_deferrable_set(connectionObject *self, PyObject *pyvalue)
829 {
830     int value;
831 
832     if (!_psyco_set_session_check_setter_wrapper(self)) { return -1; }
833     if (0 > (value = _psyco_conn_parse_onoff(pyvalue))) { return -1; }
834     if (0 > conn_set_session(self, SRV_STATE_UNCHANGED,
835                 SRV_STATE_UNCHANGED, SRV_STATE_UNCHANGED, value)) {
836         return -1;
837     }
838 
839     return 0;
840 }
841 
842 /* psyco_get_native_connection - expose PGconn* as a Python capsule */
843 
844 #define psyco_get_native_connection_doc \
845 "get_native_connection() -- Return the internal PGconn* as a Python Capsule."
846 
847 static PyObject *
psyco_get_native_connection(connectionObject * self,PyObject * dummy)848 psyco_get_native_connection(connectionObject *self, PyObject *dummy)
849 {
850     EXC_IF_CONN_CLOSED(self);
851 
852     return PyCapsule_New(self->pgconn, "psycopg2.connection.native_connection", NULL);
853 }
854 
855 
856 /* set_client_encoding method - set client encoding */
857 
858 #define psyco_conn_set_client_encoding_doc \
859 "set_client_encoding(encoding) -- Set client encoding to ``encoding``."
860 
861 static PyObject *
psyco_conn_set_client_encoding(connectionObject * self,PyObject * args)862 psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
863 {
864     const char *enc;
865     PyObject *rv = NULL;
866 
867     EXC_IF_CONN_CLOSED(self);
868     EXC_IF_CONN_ASYNC(self, set_client_encoding);
869     EXC_IF_TPC_PREPARED(self, set_client_encoding);
870 
871     if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
872 
873     if (conn_set_client_encoding(self, enc) >= 0) {
874         Py_INCREF(Py_None);
875         rv = Py_None;
876     }
877     return rv;
878 }
879 
880 /* get_transaction_status method - Get backend transaction status */
881 
882 #define psyco_conn_get_transaction_status_doc \
883 "get_transaction_status() -- Get backend transaction status."
884 
885 static PyObject *
psyco_conn_get_transaction_status(connectionObject * self,PyObject * dummy)886 psyco_conn_get_transaction_status(connectionObject *self, PyObject *dummy)
887 {
888     return PyInt_FromLong((long)PQtransactionStatus(self->pgconn));
889 }
890 
891 /* get_parameter_status method - Get server parameter status */
892 
893 #define psyco_conn_get_parameter_status_doc \
894 "get_parameter_status(parameter) -- Get backend parameter status.\n\n" \
895 "Potential values for ``parameter``:\n" \
896 "  server_version, server_encoding, client_encoding, is_superuser,\n" \
897 "  session_authorization, DateStyle, TimeZone, integer_datetimes,\n" \
898 "  and standard_conforming_strings\n" \
899 "If server did not report requested parameter, None is returned.\n\n" \
900 "See libpq docs for PQparameterStatus() for further details."
901 
902 static PyObject *
psyco_conn_get_parameter_status(connectionObject * self,PyObject * args)903 psyco_conn_get_parameter_status(connectionObject *self, PyObject *args)
904 {
905     const char *param = NULL;
906     const char *val = NULL;
907 
908     EXC_IF_CONN_CLOSED(self);
909 
910     if (!PyArg_ParseTuple(args, "s", &param)) return NULL;
911 
912     val = PQparameterStatus(self->pgconn, param);
913     if (!val) {
914         Py_RETURN_NONE;
915     }
916     return conn_text_from_chars(self, val);
917 }
918 
919 /* get_dsn_parameters method - Get connection parameters */
920 
921 #define psyco_conn_get_dsn_parameters_doc \
922 "get_dsn_parameters() -- Get effective connection parameters.\n\n"
923 
924 static PyObject *
psyco_conn_get_dsn_parameters(connectionObject * self,PyObject * dummy)925 psyco_conn_get_dsn_parameters(connectionObject *self, PyObject *dummy)
926 {
927 #if PG_VERSION_NUM >= 90300
928     PyObject *res = NULL;
929     PQconninfoOption *options = NULL;
930 
931     EXC_IF_CONN_CLOSED(self);
932 
933     if (!(options = PQconninfo(self->pgconn))) {
934         PyErr_NoMemory();
935         goto exit;
936     }
937 
938     res = psyco_dict_from_conninfo_options(options, /* include_password = */ 0);
939 
940 exit:
941     PQconninfoFree(options);
942 
943     return res;
944 #else
945     PyErr_SetString(NotSupportedError, "PQconninfo not available in libpq < 9.3");
946     return NULL;
947 #endif
948 }
949 
950 
951 /* lobject method - allocate a new lobject */
952 
953 #define psyco_conn_lobject_doc \
954 "lobject(oid=0, mode=0, new_oid=0, new_file=None,\n"                        \
955 "       lobject_factory=extensions.lobject) -- new lobject\n\n"             \
956 "Return a new lobject.\n\nThe ``lobject_factory`` argument can be used\n"   \
957 "to create non-standard lobjects by passing a class different from the\n"   \
958 "default. Note that the new class *should* be a sub-class of\n"             \
959 "`extensions.lobject`.\n\n"                                                 \
960 ":rtype: `extensions.lobject`"
961 
962 static PyObject *
psyco_conn_lobject(connectionObject * self,PyObject * args,PyObject * keywds)963 psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
964 {
965     Oid oid = InvalidOid, new_oid = InvalidOid;
966     const char *new_file = NULL;
967     const char *smode = "";
968     PyObject *factory = (PyObject *)&lobjectType;
969     PyObject *obj;
970 
971     static char *kwlist[] = {"oid", "mode", "new_oid", "new_file",
972                              "lobject_factory", NULL};
973 
974     if (!PyArg_ParseTupleAndKeywords(args, keywds, "|IzIzO", kwlist,
975                                      &oid, &smode, &new_oid, &new_file,
976                                      &factory)) {
977         return NULL;
978     }
979 
980     EXC_IF_CONN_CLOSED(self);
981     EXC_IF_CONN_ASYNC(self, lobject);
982     EXC_IF_GREEN(lobject);
983     EXC_IF_TPC_PREPARED(self, lobject);
984 
985     Dprintf("psyco_conn_lobject: new lobject for connection at %p", self);
986     Dprintf("psyco_conn_lobject:     parameters: oid = %u, mode = %s",
987             oid, smode);
988     Dprintf("psyco_conn_lobject:     parameters: new_oid = %u, new_file = %s",
989             new_oid, new_file);
990 
991     if (new_file)
992         obj = PyObject_CallFunction(factory, "OIsIs",
993             self, oid, smode, new_oid, new_file);
994     else
995         obj = PyObject_CallFunction(factory, "OIsI",
996             self, oid, smode, new_oid);
997 
998     if (obj == NULL) return NULL;
999     if (PyObject_IsInstance(obj, (PyObject *)&lobjectType) == 0) {
1000         PyErr_SetString(PyExc_TypeError,
1001             "lobject factory must be subclass of psycopg2.extensions.lobject");
1002         Py_DECREF(obj);
1003         return NULL;
1004     }
1005 
1006     Dprintf("psyco_conn_lobject: new lobject at %p: refcnt = "
1007             FORMAT_CODE_PY_SSIZE_T,
1008             obj, Py_REFCNT(obj));
1009     return obj;
1010 }
1011 
1012 /* get the current backend pid */
1013 
1014 #define psyco_conn_get_backend_pid_doc \
1015 "get_backend_pid() -- Get backend process id."
1016 
1017 static PyObject *
psyco_conn_get_backend_pid(connectionObject * self,PyObject * dummy)1018 psyco_conn_get_backend_pid(connectionObject *self, PyObject *dummy)
1019 {
1020     EXC_IF_CONN_CLOSED(self);
1021 
1022     return PyInt_FromLong((long)PQbackendPID(self->pgconn));
1023 }
1024 
1025 
1026 /* get info about the connection */
1027 
1028 #define psyco_conn_info_doc \
1029 "info -- Get connection info."
1030 
1031 static PyObject *
psyco_conn_info_get(connectionObject * self)1032 psyco_conn_info_get(connectionObject *self)
1033 {
1034     return PyObject_CallFunctionObjArgs(
1035         (PyObject *)&connInfoType, (PyObject *)self, NULL);
1036 }
1037 
1038 
1039 /* return the pointer to the PGconn structure */
1040 
1041 #define psyco_conn_pgconn_ptr_doc \
1042 "pgconn_ptr -- Get the PGconn structure pointer."
1043 
1044 static PyObject *
psyco_conn_pgconn_ptr_get(connectionObject * self)1045 psyco_conn_pgconn_ptr_get(connectionObject *self)
1046 {
1047     if (self->pgconn) {
1048         return PyLong_FromVoidPtr((void *)self->pgconn);
1049     }
1050     else {
1051         Py_RETURN_NONE;
1052     }
1053 }
1054 
1055 
1056 /* reset the currect connection */
1057 
1058 #define psyco_conn_reset_doc \
1059 "reset() -- Reset current connection to defaults."
1060 
1061 static PyObject *
psyco_conn_reset(connectionObject * self,PyObject * dummy)1062 psyco_conn_reset(connectionObject *self, PyObject *dummy)
1063 {
1064     int res;
1065 
1066     EXC_IF_CONN_CLOSED(self);
1067     EXC_IF_CONN_ASYNC(self, reset);
1068 
1069     if (pq_reset(self) < 0)
1070         return NULL;
1071 
1072     res = conn_setup(self);
1073     if (res < 0)
1074         return NULL;
1075 
1076     Py_RETURN_NONE;
1077 }
1078 
1079 static PyObject *
psyco_conn_get_exception(PyObject * self,void * closure)1080 psyco_conn_get_exception(PyObject *self, void *closure)
1081 {
1082     PyObject *exception = *(PyObject **)closure;
1083 
1084     Py_INCREF(exception);
1085     return exception;
1086 }
1087 
1088 
1089 #define psyco_conn_poll_doc \
1090 "poll() -> int -- Advance the connection or query process without blocking."
1091 
1092 static PyObject *
psyco_conn_poll(connectionObject * self,PyObject * dummy)1093 psyco_conn_poll(connectionObject *self, PyObject *dummy)
1094 {
1095     int res;
1096 
1097     EXC_IF_CONN_CLOSED(self);
1098 
1099     res = conn_poll(self);
1100     if (res != PSYCO_POLL_ERROR || !PyErr_Occurred()) {
1101         return PyInt_FromLong(res);
1102     } else {
1103         /* There is an error and an exception is already in place */
1104         return NULL;
1105     }
1106 }
1107 
1108 
1109 #define psyco_conn_fileno_doc \
1110 "fileno() -> int -- Return file descriptor associated to database connection."
1111 
1112 static PyObject *
psyco_conn_fileno(connectionObject * self,PyObject * dummy)1113 psyco_conn_fileno(connectionObject *self, PyObject *dummy)
1114 {
1115     long int socket;
1116 
1117     EXC_IF_CONN_CLOSED(self);
1118 
1119     socket = (long int)PQsocket(self->pgconn);
1120 
1121     return PyInt_FromLong(socket);
1122 }
1123 
1124 
1125 #define psyco_conn_isexecuting_doc                           \
1126 "isexecuting() -> bool -- Return True if the connection is " \
1127  "executing an asynchronous operation."
1128 
1129 static PyObject *
psyco_conn_isexecuting(connectionObject * self,PyObject * dummy)1130 psyco_conn_isexecuting(connectionObject *self, PyObject *dummy)
1131 {
1132     /* synchronous connections will always return False */
1133     if (self->async == 0) {
1134         Py_RETURN_FALSE;
1135     }
1136 
1137     /* check if the connection is still being built */
1138     if (self->status != CONN_STATUS_READY) {
1139         Py_RETURN_TRUE;
1140     }
1141 
1142     /* check if there is a query being executed */
1143     if (self->async_cursor != NULL) {
1144         Py_RETURN_TRUE;
1145     }
1146 
1147     /* otherwise it's not executing */
1148     Py_RETURN_FALSE;
1149 }
1150 
1151 
1152 #define psyco_conn_cancel_doc                           \
1153 "cancel() -- cancel the current operation"
1154 
1155 static PyObject *
psyco_conn_cancel(connectionObject * self,PyObject * dummy)1156 psyco_conn_cancel(connectionObject *self, PyObject *dummy)
1157 {
1158     char errbuf[256];
1159 
1160     EXC_IF_CONN_CLOSED(self);
1161     EXC_IF_TPC_PREPARED(self, cancel);
1162 
1163     /* do not allow cancellation while the connection is being built */
1164     Dprintf("psyco_conn_cancel: cancelling with key %p", self->cancel);
1165     if (self->status != CONN_STATUS_READY &&
1166         self->status != CONN_STATUS_BEGIN) {
1167         PyErr_SetString(OperationalError,
1168                         "asynchronous connection attempt underway");
1169         return NULL;
1170     }
1171 
1172     if (PQcancel(self->cancel, errbuf, sizeof(errbuf)) == 0) {
1173         Dprintf("psyco_conn_cancel: cancelling failed: %s", errbuf);
1174         PyErr_SetString(OperationalError, errbuf);
1175         return NULL;
1176     }
1177     Py_RETURN_NONE;
1178 }
1179 
1180 
1181 /** the connection object **/
1182 
1183 
1184 /* object method list */
1185 
1186 static struct PyMethodDef connectionObject_methods[] = {
1187     {"cursor", (PyCFunction)psyco_conn_cursor,
1188      METH_VARARGS|METH_KEYWORDS, psyco_conn_cursor_doc},
1189     {"close", (PyCFunction)psyco_conn_close,
1190      METH_NOARGS, psyco_conn_close_doc},
1191     {"commit", (PyCFunction)psyco_conn_commit,
1192      METH_NOARGS, psyco_conn_commit_doc},
1193     {"rollback", (PyCFunction)psyco_conn_rollback,
1194      METH_NOARGS, psyco_conn_rollback_doc},
1195     {"xid", (PyCFunction)psyco_conn_xid,
1196      METH_VARARGS|METH_KEYWORDS, psyco_conn_xid_doc},
1197     {"tpc_begin", (PyCFunction)psyco_conn_tpc_begin,
1198      METH_VARARGS, psyco_conn_tpc_begin_doc},
1199     {"tpc_prepare", (PyCFunction)psyco_conn_tpc_prepare,
1200      METH_NOARGS, psyco_conn_tpc_prepare_doc},
1201     {"tpc_commit", (PyCFunction)psyco_conn_tpc_commit,
1202      METH_VARARGS, psyco_conn_tpc_commit_doc},
1203     {"tpc_rollback", (PyCFunction)psyco_conn_tpc_rollback,
1204      METH_VARARGS, psyco_conn_tpc_rollback_doc},
1205     {"tpc_recover", (PyCFunction)psyco_conn_tpc_recover,
1206      METH_NOARGS, psyco_conn_tpc_recover_doc},
1207     {"__enter__", (PyCFunction)psyco_conn_enter,
1208      METH_NOARGS, psyco_conn_enter_doc},
1209     {"__exit__", (PyCFunction)psyco_conn_exit,
1210      METH_VARARGS, psyco_conn_exit_doc},
1211     {"set_session", (PyCFunction)psyco_conn_set_session,
1212      METH_VARARGS|METH_KEYWORDS, psyco_conn_set_session_doc},
1213     {"set_isolation_level", (PyCFunction)psyco_conn_set_isolation_level,
1214      METH_VARARGS, psyco_conn_set_isolation_level_doc},
1215     {"set_client_encoding", (PyCFunction)psyco_conn_set_client_encoding,
1216      METH_VARARGS, psyco_conn_set_client_encoding_doc},
1217     {"get_transaction_status", (PyCFunction)psyco_conn_get_transaction_status,
1218      METH_NOARGS, psyco_conn_get_transaction_status_doc},
1219     {"get_parameter_status", (PyCFunction)psyco_conn_get_parameter_status,
1220      METH_VARARGS, psyco_conn_get_parameter_status_doc},
1221     {"get_dsn_parameters", (PyCFunction)psyco_conn_get_dsn_parameters,
1222      METH_NOARGS, psyco_conn_get_dsn_parameters_doc},
1223     {"get_backend_pid", (PyCFunction)psyco_conn_get_backend_pid,
1224      METH_NOARGS, psyco_conn_get_backend_pid_doc},
1225     {"lobject", (PyCFunction)psyco_conn_lobject,
1226      METH_VARARGS|METH_KEYWORDS, psyco_conn_lobject_doc},
1227     {"reset", (PyCFunction)psyco_conn_reset,
1228      METH_NOARGS, psyco_conn_reset_doc},
1229     {"poll", (PyCFunction)psyco_conn_poll,
1230      METH_NOARGS, psyco_conn_poll_doc},
1231     {"fileno", (PyCFunction)psyco_conn_fileno,
1232      METH_NOARGS, psyco_conn_fileno_doc},
1233     {"isexecuting", (PyCFunction)psyco_conn_isexecuting,
1234      METH_NOARGS, psyco_conn_isexecuting_doc},
1235     {"cancel", (PyCFunction)psyco_conn_cancel,
1236      METH_NOARGS, psyco_conn_cancel_doc},
1237     {"get_native_connection", (PyCFunction)psyco_get_native_connection,
1238      METH_NOARGS, psyco_get_native_connection_doc},
1239     {NULL}
1240 };
1241 
1242 /* object member list */
1243 
1244 static struct PyMemberDef connectionObject_members[] = {
1245     {"closed", T_LONG, offsetof(connectionObject, closed), READONLY,
1246         "True if the connection is closed."},
1247     {"encoding", T_STRING, offsetof(connectionObject, encoding), READONLY,
1248         "The current client encoding."},
1249     {"notices", T_OBJECT, offsetof(connectionObject, notice_list), 0},
1250     {"notifies", T_OBJECT, offsetof(connectionObject, notifies), 0},
1251     {"dsn", T_STRING, offsetof(connectionObject, dsn), READONLY,
1252         "The current connection string."},
1253     {"async", T_LONG, offsetof(connectionObject, async), READONLY,
1254         "True if the connection is asynchronous."},
1255     {"async_", T_LONG, offsetof(connectionObject, async), READONLY,
1256         "True if the connection is asynchronous."},
1257     {"status", T_INT,
1258         offsetof(connectionObject, status), READONLY,
1259         "The current transaction status."},
1260     {"cursor_factory", T_OBJECT, offsetof(connectionObject, cursor_factory), 0,
1261         "Default cursor_factory for cursor()."},
1262     {"string_types", T_OBJECT, offsetof(connectionObject, string_types), READONLY,
1263         "A set of typecasters to convert textual values."},
1264     {"binary_types", T_OBJECT, offsetof(connectionObject, binary_types), READONLY,
1265         "A set of typecasters to convert binary values."},
1266     {"protocol_version", T_INT,
1267         offsetof(connectionObject, protocol), READONLY,
1268         "Protocol version used for this connection. Currently always 3."},
1269     {"server_version", T_INT,
1270         offsetof(connectionObject, server_version), READONLY,
1271         "Server version."},
1272     {NULL}
1273 };
1274 
1275 #define EXCEPTION_GETTER(exc) \
1276     { #exc, psyco_conn_get_exception, NULL, exc ## _doc, &exc }
1277 
1278 static struct PyGetSetDef connectionObject_getsets[] = {
1279     EXCEPTION_GETTER(Error),
1280     EXCEPTION_GETTER(Warning),
1281     EXCEPTION_GETTER(InterfaceError),
1282     EXCEPTION_GETTER(DatabaseError),
1283     EXCEPTION_GETTER(InternalError),
1284     EXCEPTION_GETTER(OperationalError),
1285     EXCEPTION_GETTER(ProgrammingError),
1286     EXCEPTION_GETTER(IntegrityError),
1287     EXCEPTION_GETTER(DataError),
1288     EXCEPTION_GETTER(NotSupportedError),
1289     { "autocommit",
1290         (getter)psyco_conn_autocommit_get,
1291         (setter)psyco_conn_autocommit_set,
1292         psyco_conn_autocommit_doc },
1293     { "isolation_level",
1294         (getter)psyco_conn_isolation_level_get,
1295         (setter)psyco_conn_isolation_level_set,
1296         psyco_conn_isolation_level_doc },
1297     { "readonly",
1298         (getter)psyco_conn_readonly_get,
1299         (setter)psyco_conn_readonly_set,
1300         psyco_conn_readonly_doc },
1301     { "deferrable",
1302         (getter)psyco_conn_deferrable_get,
1303         (setter)psyco_conn_deferrable_set,
1304         psyco_conn_deferrable_doc },
1305     { "info",
1306         (getter)psyco_conn_info_get, NULL,
1307         psyco_conn_info_doc },
1308     { "pgconn_ptr",
1309         (getter)psyco_conn_pgconn_ptr_get, NULL,
1310         psyco_conn_pgconn_ptr_doc },
1311     {NULL}
1312 };
1313 #undef EXCEPTION_GETTER
1314 
1315 /* initialization and finalization methods */
1316 
1317 static int
connection_setup(connectionObject * self,const char * dsn,long int async)1318 connection_setup(connectionObject *self, const char *dsn, long int async)
1319 {
1320     int rv = -1;
1321 
1322     Dprintf("connection_setup: init connection object at %p, "
1323 	    "async %ld, refcnt = " FORMAT_CODE_PY_SSIZE_T,
1324             self, async, Py_REFCNT(self)
1325       );
1326 
1327     if (!(self->dsn = conn_obscure_password(dsn))) { goto exit; }
1328     if (!(self->notice_list = PyList_New(0))) { goto exit; }
1329     if (!(self->notifies = PyList_New(0))) { goto exit; }
1330     self->async = async;
1331     self->status = CONN_STATUS_SETUP;
1332     self->async_status = ASYNC_DONE;
1333     if (!(self->string_types = PyDict_New())) { goto exit; }
1334     if (!(self->binary_types = PyDict_New())) { goto exit; }
1335     self->isolevel = ISOLATION_LEVEL_DEFAULT;
1336     self->readonly = STATE_DEFAULT;
1337     self->deferrable = STATE_DEFAULT;
1338 #ifdef CONN_CHECK_PID
1339     self->procpid = getpid();
1340 #endif
1341 
1342     /* other fields have been zeroed by tp_alloc */
1343 
1344     if (0 != pthread_mutex_init(&(self->lock), NULL)) {
1345         PyErr_SetString(InternalError, "lock initialization failed");
1346         goto exit;
1347     }
1348 
1349     if (conn_connect(self, dsn, async) != 0) {
1350         Dprintf("connection_init: FAILED");
1351         goto exit;
1352     }
1353 
1354     rv = 0;
1355 
1356     Dprintf("connection_setup: good connection object at %p, refcnt = "
1357         FORMAT_CODE_PY_SSIZE_T,
1358         self, Py_REFCNT(self));
1359 
1360 exit:
1361     return rv;
1362 }
1363 
1364 
1365 static int
connection_clear(connectionObject * self)1366 connection_clear(connectionObject *self)
1367 {
1368     Py_CLEAR(self->tpc_xid);
1369     Py_CLEAR(self->async_cursor);
1370     Py_CLEAR(self->notice_list);
1371     Py_CLEAR(self->notifies);
1372     Py_CLEAR(self->string_types);
1373     Py_CLEAR(self->binary_types);
1374     Py_CLEAR(self->cursor_factory);
1375     Py_CLEAR(self->pyencoder);
1376     Py_CLEAR(self->pydecoder);
1377     return 0;
1378 }
1379 
1380 static void
connection_dealloc(PyObject * obj)1381 connection_dealloc(PyObject* obj)
1382 {
1383     connectionObject *self = (connectionObject *)obj;
1384 
1385     /* Make sure to untrack the connection before calling conn_close, which may
1386      * allow a different thread to try and dealloc the connection again,
1387      * resulting in a double-free segfault (ticket #166). */
1388     PyObject_GC_UnTrack(self);
1389 
1390     /* close the connection only if this is the same process it was created
1391      * into, otherwise using multiprocessing we may close the connection
1392      * belonging to another process. */
1393 #ifdef CONN_CHECK_PID
1394     if (self->procpid == getpid())
1395 #endif
1396     {
1397         conn_close(self);
1398     }
1399 
1400     if (self->weakreflist) {
1401         PyObject_ClearWeakRefs(obj);
1402     }
1403 
1404     conn_notice_clean(self);
1405 
1406     PyMem_Free(self->dsn);
1407     PyMem_Free(self->encoding);
1408     if (self->error) free(self->error);
1409     if (self->cancel) PQfreeCancel(self->cancel);
1410     PQclear(self->pgres);
1411 
1412     connection_clear(self);
1413 
1414     pthread_mutex_destroy(&(self->lock));
1415 
1416     Dprintf("connection_dealloc: deleted connection object at %p, refcnt = "
1417         FORMAT_CODE_PY_SSIZE_T,
1418         obj, Py_REFCNT(obj)
1419       );
1420 
1421     Py_TYPE(obj)->tp_free(obj);
1422 }
1423 
1424 static int
connection_init(PyObject * obj,PyObject * args,PyObject * kwds)1425 connection_init(PyObject *obj, PyObject *args, PyObject *kwds)
1426 {
1427     const char *dsn;
1428     long int async = 0, async_ = 0;
1429     static char *kwlist[] = {"dsn", "async", "async_", NULL};
1430 
1431     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|ll", kwlist,
1432             &dsn, &async, &async_))
1433         return -1;
1434 
1435     if (async_) { async = async_; }
1436     return connection_setup((connectionObject *)obj, dsn, async);
1437 }
1438 
1439 static PyObject *
connection_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1440 connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1441 {
1442     return type->tp_alloc(type, 0);
1443 }
1444 
1445 static PyObject *
connection_repr(connectionObject * self)1446 connection_repr(connectionObject *self)
1447 {
1448     return PyString_FromFormat(
1449         "<connection object at %p; dsn: '%s', closed: %ld>",
1450         self, (self->dsn ? self->dsn : "<unintialized>"), self->closed);
1451 }
1452 
1453 static int
connection_traverse(connectionObject * self,visitproc visit,void * arg)1454 connection_traverse(connectionObject *self, visitproc visit, void *arg)
1455 {
1456     Py_VISIT((PyObject *)(self->tpc_xid));
1457     Py_VISIT(self->async_cursor);
1458     Py_VISIT(self->notice_list);
1459     Py_VISIT(self->notifies);
1460     Py_VISIT(self->string_types);
1461     Py_VISIT(self->binary_types);
1462     Py_VISIT(self->cursor_factory);
1463     Py_VISIT(self->pyencoder);
1464     Py_VISIT(self->pydecoder);
1465     return 0;
1466 }
1467 
1468 
1469 /* object type */
1470 
1471 #define connectionType_doc \
1472 "connection(dsn, ...) -> new connection object\n\n" \
1473 ":Groups:\n" \
1474 "  * `DBAPI-2.0 errors`: Error, Warning, InterfaceError,\n" \
1475 "    DatabaseError, InternalError, OperationalError,\n" \
1476 "    ProgrammingError, IntegrityError, DataError, NotSupportedError"
1477 
1478 PyTypeObject connectionType = {
1479     PyVarObject_HEAD_INIT(NULL, 0)
1480     "psycopg2.extensions.connection",
1481     sizeof(connectionObject), 0,
1482     connection_dealloc, /*tp_dealloc*/
1483     0,          /*tp_print*/
1484     0,          /*tp_getattr*/
1485     0,          /*tp_setattr*/
1486     0,          /*tp_compare*/
1487     (reprfunc)connection_repr, /*tp_repr*/
1488     0,          /*tp_as_number*/
1489     0,          /*tp_as_sequence*/
1490     0,          /*tp_as_mapping*/
1491     0,          /*tp_hash */
1492     0,          /*tp_call*/
1493     (reprfunc)connection_repr, /*tp_str*/
1494     0,          /*tp_getattro*/
1495     0,          /*tp_setattro*/
1496     0,          /*tp_as_buffer*/
1497     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1498         Py_TPFLAGS_HAVE_WEAKREFS,
1499                 /*tp_flags*/
1500     connectionType_doc, /*tp_doc*/
1501     (traverseproc)connection_traverse, /*tp_traverse*/
1502     (inquiry)connection_clear, /*tp_clear*/
1503     0,          /*tp_richcompare*/
1504     offsetof(connectionObject, weakreflist), /* tp_weaklistoffset */
1505     0,          /*tp_iter*/
1506     0,          /*tp_iternext*/
1507     connectionObject_methods, /*tp_methods*/
1508     connectionObject_members, /*tp_members*/
1509     connectionObject_getsets, /*tp_getset*/
1510     0,          /*tp_base*/
1511     0,          /*tp_dict*/
1512     0,          /*tp_descr_get*/
1513     0,          /*tp_descr_set*/
1514     0,          /*tp_dictoffset*/
1515     connection_init, /*tp_init*/
1516     0,          /*tp_alloc*/
1517     connection_new, /*tp_new*/
1518 };
1519