Better separation between interface and state change code

The state change function has a C callable signature.
This commit is contained in:
Daniele Varrazzo 2017-02-04 11:20:54 +00:00
parent ca59fd8b3f
commit 8527144173
3 changed files with 110 additions and 91 deletions

View File

@ -167,8 +167,8 @@ HIDDEN void conn_close_locked(connectionObject *self);
RAISES_NEG HIDDEN int conn_commit(connectionObject *self);
RAISES_NEG HIDDEN int conn_rollback(connectionObject *self);
HIDDEN int conn_set_autocommit(connectionObject *self, int value);
RAISES_NEG HIDDEN int conn_parse_isolevel(connectionObject *self, PyObject *pyval);
RAISES_NEG HIDDEN int conn_parse_onoff(PyObject *pyval);
RAISES_NEG HIDDEN int conn_set_session(connectionObject *self, int autocommit,
int isolevel, int readonly, int deferrable);
RAISES_NEG HIDDEN int conn_switch_isolation_level(connectionObject *self, int level);
RAISES_NEG HIDDEN int conn_set_client_encoding(connectionObject *self, const char *enc);
HIDDEN int conn_poll(connectionObject *self);

View File

@ -1194,9 +1194,11 @@ conn_set_autocommit(connectionObject *self, int value)
return 0;
}
/* Promote an isolation level to one of the levels supported by the server */
static int _adjust_isolevel(connectionObject *self, int level) {
static int
_adjust_isolevel(connectionObject *self, int level) {
if (self->server_version < 80000) {
if (level == ISOLATION_LEVEL_READ_UNCOMMITTED) {
level = ISOLATION_LEVEL_READ_COMMITTED;
@ -1209,93 +1211,21 @@ static int _adjust_isolevel(connectionObject *self, int level) {
}
/* parse a python object into one of the possible isolation level values */
/* Change the state of the session */
RAISES_NEG int
conn_parse_isolevel(connectionObject *self, PyObject *pyval)
conn_set_session(connectionObject *self, int autocommit,
int isolevel, int readonly, int deferrable)
{
int rv = -1;
long level;
isolevel = _adjust_isolevel(self, isolevel);
Py_INCREF(pyval); /* for ensure_bytes */
self->isolevel = isolevel;
self->readonly = readonly;
self->deferrable = deferrable;
self->autocommit = autocommit;
/* parse from one of the level constants */
if (PyInt_Check(pyval)) {
level = PyInt_AsLong(pyval);
if (level == -1 && PyErr_Occurred()) { goto exit; }
if (level < 1 || level > 4) {
PyErr_SetString(PyExc_ValueError,
"isolation_level must be between 1 and 4");
goto exit;
}
rv = level;
}
/* parse from the string -- this includes "default" */
else {
if (!(pyval = psycopg_ensure_bytes(pyval))) {
goto exit;
}
for (level = 1; level <= 4; level++) {
if (0 == strcasecmp(srv_isolevels[level], Bytes_AS_STRING(pyval))) {
rv = level;
break;
}
}
if (rv < 0 && 0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
rv = ISOLATION_LEVEL_DEFAULT;
}
if (rv < 0) {
PyErr_Format(PyExc_ValueError,
"bad value for isolation_level: '%s'", Bytes_AS_STRING(pyval));
goto exit;
}
}
rv = _adjust_isolevel(self, rv);
exit:
Py_XDECREF(pyval);
return rv;
return 0;
}
/* convert False/True/"default" -> 0/1/2 */
RAISES_NEG int
conn_parse_onoff(PyObject *pyval)
{
int rv = -1;
Py_INCREF(pyval); /* for ensure_bytes */
if (PyUnicode_CheckExact(pyval) || Bytes_CheckExact(pyval)) {
if (!(pyval = psycopg_ensure_bytes(pyval))) {
goto exit;
}
if (0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
rv = STATE_DEFAULT;
}
else {
PyErr_Format(PyExc_ValueError,
"the only string accepted is 'default'; got %s",
Bytes_AS_STRING(pyval));
goto exit;
}
}
else {
int istrue;
if (0 > (istrue = PyObject_IsTrue(pyval))) { goto exit; }
rv = istrue ? STATE_ON : STATE_OFF;
}
exit:
Py_XDECREF(pyval);
return rv;
}
/* conn_switch_isolation_level - switch isolation level on the connection */

View File

@ -36,6 +36,9 @@
#include <string.h>
#include <ctype.h>
extern HIDDEN const char *srv_isolevels[];
extern HIDDEN const char *srv_readonly[];
extern HIDDEN const char *srv_deferrable[];
/** DBAPI methods **/
@ -442,6 +445,92 @@ exit:
}
/* parse a python object into one of the possible isolation level values */
RAISES_NEG static int
_psyco_conn_parse_isolevel(PyObject *pyval)
{
int rv = -1;
long level;
Py_INCREF(pyval); /* for ensure_bytes */
/* parse from one of the level constants */
if (PyInt_Check(pyval)) {
level = PyInt_AsLong(pyval);
if (level == -1 && PyErr_Occurred()) { goto exit; }
if (level < 1 || level > 4) {
PyErr_SetString(PyExc_ValueError,
"isolation_level must be between 1 and 4");
goto exit;
}
rv = level;
}
/* parse from the string -- this includes "default" */
else {
if (!(pyval = psycopg_ensure_bytes(pyval))) {
goto exit;
}
for (level = 1; level <= 4; level++) {
if (0 == strcasecmp(srv_isolevels[level], Bytes_AS_STRING(pyval))) {
rv = level;
break;
}
}
if (rv < 0 && 0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
rv = ISOLATION_LEVEL_DEFAULT;
}
if (rv < 0) {
PyErr_Format(PyExc_ValueError,
"bad value for isolation_level: '%s'", Bytes_AS_STRING(pyval));
goto exit;
}
}
exit:
Py_XDECREF(pyval);
return rv;
}
/* convert False/True/"default" -> 0/1/2 */
RAISES_NEG static int
_psyco_conn_parse_onoff(PyObject *pyval)
{
int rv = -1;
Py_INCREF(pyval); /* for ensure_bytes */
if (PyUnicode_CheckExact(pyval) || Bytes_CheckExact(pyval)) {
if (!(pyval = psycopg_ensure_bytes(pyval))) {
goto exit;
}
if (0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
rv = STATE_DEFAULT;
}
else {
PyErr_Format(PyExc_ValueError,
"the only string accepted is 'default'; got %s",
Bytes_AS_STRING(pyval));
goto exit;
}
}
else {
int istrue;
if (0 > (istrue = PyObject_IsTrue(pyval))) { goto exit; }
rv = istrue ? STATE_ON : STATE_OFF;
}
exit:
Py_XDECREF(pyval);
return rv;
}
/* set_session - set default transaction characteristics */
#define psyco_conn_set_session_doc \
@ -474,13 +563,13 @@ psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs)
}
if (Py_None != isolevel) {
if (0 > (c_isolevel = conn_parse_isolevel(self, isolevel))) {
if (0 > (c_isolevel = _psyco_conn_parse_isolevel(isolevel))) {
return NULL;
}
}
if (Py_None != readonly) {
if (0 > (c_readonly = conn_parse_onoff(readonly))) {
if (0 > (c_readonly = _psyco_conn_parse_onoff(readonly))) {
return NULL;
}
}
@ -491,7 +580,7 @@ psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs)
" from PostgreSQL 9.1");
return NULL;
}
if (0 > (c_deferrable = conn_parse_onoff(readonly))) {
if (0 > (c_deferrable = _psyco_conn_parse_onoff(readonly))) {
return NULL;
}
}
@ -500,10 +589,10 @@ psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs)
if (-1 == (c_autocommit = PyObject_IsTrue(autocommit))) { return NULL; }
}
self->isolevel = c_isolevel;
self->readonly = c_readonly;
self->deferrable = c_deferrable;
self->autocommit = c_autocommit;
if (0 > conn_set_session(
self, c_autocommit, c_isolevel, c_readonly, c_deferrable)) {
return NULL;
}
Py_RETURN_NONE;
}