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", ¶m)) 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