summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Di Gregorio <fog@initd.org>2005-10-22 06:59:31 +0000
committerFederico Di Gregorio <fog@initd.org>2005-10-22 06:59:31 +0000
commitef3430d24f3a1580a994e6dec8b5926a752efaed (patch)
treebaa59cd9e3208147bc476eddf743088860287227
parentf687f2853ed619e4ee1b53f350cc31158e81e9cf (diff)
downloadpsycopg2-ef3430d24f3a1580a994e6dec8b5926a752efaed.tar.gz
Implemented named cursors.
-rw-r--r--ChangeLog24
-rw-r--r--NEWS6
-rw-r--r--examples/fetch.py33
-rw-r--r--psycopg/connection.h1
-rw-r--r--psycopg/connection_int.c11
-rw-r--r--psycopg/connection_type.c16
-rw-r--r--psycopg/cursor.h13
-rw-r--r--psycopg/cursor_type.c221
-rw-r--r--psycopg/psycopgmodule.c29
9 files changed, 259 insertions, 95 deletions
diff --git a/ChangeLog b/ChangeLog
index 070daa2..7f516e9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2005-10-22 Federico Di Gregorio <fog@initd.org>
+
+ * psycopg/cursor_type.c: added support for named cursors:
+ - .fetchXXX() methods now execute a FETCH if the cursor is named
+ - .execute() executes a DECLARE if the cursor is named
+ - .execute() fails if a named cursor is used in autocommit
+ - .executemany() can't be called on named cursors
+ - .scroll() executes a MOVE if the cursor is named
+ - .close() executes a CLOSE if the cursor is named
+ Also, a "transaction mark" was added to both the connection and the
+ cursor and an exception is raised when using a named cursor unless the
+ two marks correspond.
+
+ * psycopg/connection_int.c: snprintf->PyOS_snprintf.
+
+ * psycopg/psycopgmodule.c: snprintf->PyOS_snprintf.
+
+ * psycopg/cursor_type.c: changed self->query type from C string to
+ PyObject* to better manage queries in named cursors.
+
+ * psycopg/psycopgmodule.c: cleaned up exception names (now the errors
+ is printed as psycopg2.Error and not as the confusing
+ psycopg2._psycopg.Error.)
+
2005-10-20 Federico Di Gregorio <fog@initd.org>
* lib/pool.py: renamed ThreadedConnectionPool to PersistentConnectionPool
diff --git a/NEWS b/NEWS
index 21cd8e8..6979ba0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,9 @@
+What's new in psycopg 2.0 beta 6
+--------------------------------
+
+* Support for named cursors (see examples/fetch.py).
+
+
What's new in psycopg 2.0 beta 5
--------------------------------
diff --git a/examples/fetch.py b/examples/fetch.py
index e80859b..67818d2 100644
--- a/examples/fetch.py
+++ b/examples/fetch.py
@@ -52,19 +52,28 @@ conn.commit()
# does some nice tricks with the transaction and postgres cursors
# (remember to always commit or rollback before a DECLARE)
-
-curs.execute("DECLARE crs CURSOR FOR SELECT * FROM test_fetch")
-curs.execute("FETCH 10 FROM crs")
-print "First 10 rows:", flatten(curs.fetchall())
-curs.execute("MOVE -5 FROM crs")
+#
+# we don't need to DECLARE ourselves, psycopg now support named
+# cursor (but we leave the code here, comments, as an example of
+# what psycopg is doing under the hood)
+#curs.execute("DECLARE crs CURSOR FOR SELECT * FROM test_fetch")
+#curs.execute("FETCH 10 FROM crs")
+#print "First 10 rows:", flatten(curs.fetchall())
+#curs.execute("MOVE -5 FROM crs")
+#print "Moved back cursor by 5 rows (to row 5.)"
+#curs.execute("FETCH 10 FROM crs")
+#print "Another 10 rows:", flatten(curs.fetchall())
+#curs.execute("FETCH 10 FROM crs")
+#print "The remaining rows:", flatten(curs.fetchall())
+
+ncurs = conn.cursor("crs")
+ncurs.execute("SELECT * FROM test_fetch")
+print "First 10 rows:", flatten(ncurs.fetchmany(10))
+ncurs.scroll(-5)
print "Moved back cursor by 5 rows (to row 5.)"
-curs.execute("FETCH 10 FROM crs")
-print "Another 10 rows:", flatten(curs.fetchall())
-curs.execute("FETCH 10 FROM crs")
-print "The remaining rows:", flatten(curs.fetchall())
-
-# rollback to close the transaction
-
+print "Another 10 rows:", flatten(ncurs.fetchmany(10))
+print "Another one:", list(ncurs.fetchone())
+print "The remaining rows:", flatten(ncurs.fetchall())
conn.rollback()
curs.execute("DROP TABLE test_fetch")
diff --git a/psycopg/connection.h b/psycopg/connection.h
index c973b92..7010120 100644
--- a/psycopg/connection.h
+++ b/psycopg/connection.h
@@ -48,6 +48,7 @@ typedef struct {
long int closed; /* 2 means connection has been closed */
long int isolation_level; /* isolation level for this connection */
+ long int mark; /* number of commits/rollbacks done so far */
int status; /* status of the connection */
int protocol; /* protocol version */
diff --git a/psycopg/connection_int.c b/psycopg/connection_int.c
index ea1e9aa..9795e0e 100644
--- a/psycopg/connection_int.c
+++ b/psycopg/connection_int.c
@@ -191,7 +191,8 @@ conn_commit(connectionObject *self)
pthread_mutex_lock(&self->lock);
res = pq_commit(self);
-
+ self->mark++;
+
pthread_mutex_unlock(&self->lock);
Py_END_ALLOW_THREADS;
@@ -209,7 +210,8 @@ conn_rollback(connectionObject *self)
pthread_mutex_lock(&self->lock);
res = pq_abort(self);
-
+ self->mark++;
+
pthread_mutex_unlock(&self->lock);
Py_END_ALLOW_THREADS;
@@ -232,7 +234,8 @@ conn_switch_isolation_level(connectionObject *self, int level)
res = pq_abort(self);
}
self->isolation_level = level;
-
+ self->mark++;
+
Dprintf("conn_switch_isolation_level: switched to level %d", level);
pthread_mutex_unlock(&self->lock);
@@ -256,7 +259,7 @@ conn_set_client_encoding(connectionObject *self, char *enc)
pthread_mutex_lock(&self->lock);
/* set encoding, no encoding string is longer than 24 bytes */
- snprintf(query, 47, "SET client_encoding = '%s'", enc);
+ PyOS_snprintf(query, 47, "SET client_encoding = '%s'", enc);
/* abort the current transaction, to set the encoding ouside of
transactions */
diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c
index 4a018b0..0af2d33 100644
--- a/psycopg/connection_type.c
+++ b/psycopg/connection_type.c
@@ -62,9 +62,18 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds)
Dprintf("psyco_conn_cursor: parameters: name = %s", name);
if (factory == NULL) factory = (PyObject *)&cursorType;
- obj = PyObject_CallFunction(factory, "O", self);
-
- /* TODO: added error checking on obj (cursor) here */
+ if (name)
+ obj = PyObject_CallFunction(factory, "Os", self, name);
+ else
+ obj = PyObject_CallFunction(factory, "O", self);
+
+ if (obj == NULL) return NULL;
+ if (PyObject_IsInstance(obj, (PyObject *)&cursorType) == 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "cursor factory must be subclass of psycopg2._psycopg.cursor");
+ Py_DECREF(obj);
+ return NULL;
+ }
Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = %d",
obj, obj->ob_refcnt);
@@ -259,6 +268,7 @@ connection_setup(connectionObject *self, char *dsn)
self->critical = NULL;
self->async_cursor = NULL;
self->pgconn = NULL;
+ self->mark = 0;
pthread_mutex_init(&(self->lock), NULL);
diff --git a/psycopg/cursor.h b/psycopg/cursor.h
index 96ab6dd..5aab172 100644
--- a/psycopg/cursor.h
+++ b/psycopg/cursor.h
@@ -46,6 +46,7 @@ typedef struct {
long int columns; /* number of columns fetched from the db */
long int arraysize; /* how many rows should fetchmany() return */
long int row; /* the row counter for fetch*() operations */
+ long int mark; /* transaction marker, copied from conn */
PyObject *description; /* read-only attribute: sequence of 7-item
sequences.*/
@@ -65,9 +66,11 @@ typedef struct {
PyObject *tuple_factory; /* factory for result tuples */
PyObject *tzinfo_factory; /* factory for tzinfo objects */
+ PyObject *query; /* last query executed */
+
char *qattr; /* quoting attr, used when quoting strings */
char *notice; /* a notice from the backend */
- char *query; /* last query executed */
+ char *name; /* this cursor name */
PyObject *string_types; /* a set of typecasters for string types */
PyObject *binary_types; /* a set of typecasters for binary types */
@@ -83,10 +86,16 @@ if ((self)->closed || ((self)->conn && (self)->conn->closed)) { \
PyErr_SetString(InterfaceError, "cursor already closed"); \
return NULL; }
-#define EXC_IF_NO_TUPLES(self) if ((self)->notuples) { \
+#define EXC_IF_NO_TUPLES(self) \
+if ((self)->notuples && (self)->name == NULL) { \
PyErr_SetString(ProgrammingError, "no results to fetch"); \
return NULL; }
+#define EXC_IF_NO_MARK(self) \
+if ((self)->mark != (self)->conn->mark) { \
+ PyErr_SetString(ProgrammingError, "named cursor isn't valid anymore"); \
+ return NULL; }
+
#ifdef __cplusplus
}
#endif
diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c
index f1eda83..b446513 100644
--- a/psycopg/cursor_type.c
+++ b/psycopg/cursor_type.c
@@ -14,7 +14,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU General Public Likcense
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
@@ -51,6 +51,14 @@ psyco_curs_close(cursorObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "")) return NULL;
EXC_IF_CURS_CLOSED(self);
+
+ if (self->name != NULL) {
+ char buffer[128];
+
+ EXC_IF_NO_MARK(self);
+ PyOS_snprintf(buffer, 127, "CLOSE %s", self->name);
+ if (pq_execute(self, buffer, 0) == -1) return NULL;
+ }
self->closed = 1;
Dprintf("psyco_curs_close: cursor at %p closed", self);
@@ -276,7 +284,7 @@ _psyco_curs_execute(cursorObject *self,
IFCLEARPGRES(self->pgres);
if (self->query) {
- free(self->query);
+ Py_DECREF(self->query);
self->query = NULL;
}
@@ -284,25 +292,7 @@ _psyco_curs_execute(cursorObject *self,
/* here we are, and we have a sequence or a dictionary filled with
objects to be substituted (bound variables). we try to be smart and do
- the right thing (i.e., what the user expects), so:
-
- 1. if the bound variable is None the format string is changed into a %s
- (just like now) and the variable substituted with the "NULL" string;
-
- 2. if a bound variable has the .sqlquote method, we suppose it is able
- to do the required quoting by itself: we call the method and
- substitute the result in the sequence/dictionary. if the result of
- calling .sqlquote is not a string object or the format string is not
- %s we raise an error;
-
- 3. if a bound variable does not have the .sqlquote method AND the
- format string is %s str() is called on the variable and the result
- wrapped in a psycopg.QuotedString object;
-
- 4. if the format string is not %s we suppose the object is capable to
- format itself accordingly, so we don't touch it.
-
- let's go... */
+ the right thing (i.e., what the user expects) */
if (vars && vars != Py_None)
{
@@ -363,18 +353,33 @@ _psyco_curs_execute(cursorObject *self,
Py_XDECREF(uoperation);
return 0;
}
- self->query = strdup(PyString_AS_STRING(fquery));
-
- Dprintf("psyco_curs_execute: cvt->refcnt = %d, fquery->refcnt = %d",
- cvt->ob_refcnt, fquery->ob_refcnt);
- Py_DECREF(fquery);
+
+ if (self->name != NULL) {
+ self->query = PyString_FromFormat(
+ "DECLARE %s CURSOR WITHOUT HOLD FOR %s",
+ self->name, PyString_AS_STRING(fquery));
+ Py_DECREF(fquery);
+ }
+ else {
+ self->query = fquery;
+ }
+
+ Dprintf("psyco_curs_execute: cvt->refcnt = %d", cvt->ob_refcnt);
Py_DECREF(cvt);
}
else {
- self->query = strdup(PyString_AS_STRING(operation));
+ if (self->name != NULL) {
+ self->query = PyString_FromFormat(
+ "DECLARE %s CURSOR WITHOUT HOLD FOR %s",
+ self->name, PyString_AS_STRING(operation));
+ }
+ else {
+ Py_INCREF(operation);
+ self->query = operation;
+ }
}
-
- res = pq_execute(self, self->query, async);
+
+ res = pq_execute(self, PyString_AS_STRING(self->query), async);
Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres);
@@ -396,6 +401,24 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
return NULL;
}
+ if (self->name != NULL) {
+ if (self->query != Py_None) {
+ PyErr_SetString(ProgrammingError,
+ "can't call .execute() on named cursors more than once");
+ return NULL;
+ }
+ if (self->conn->isolation_level == 0) {
+ PyErr_SetString(ProgrammingError,
+ "can't use a named cursor outside of transactions");
+ return NULL;
+ }
+ if (self->conn->mark != self->mark) {
+ PyErr_SetString(ProgrammingError,
+ "named cursor isn't valid anymore");
+ return NULL;
+ }
+ }
+
EXC_IF_CURS_CLOSED(self);
if (_psyco_curs_execute(self, operation, vars, async)) {
@@ -424,6 +447,12 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
}
EXC_IF_CURS_CLOSED(self);
+
+ if (self->name != NULL) {
+ PyErr_SetString(ProgrammingError,
+ "can't call .executemany() on named cursors");
+ return NULL;
+ }
if (!PyIter_Check(vars)) {
vars = iter = PyObject_GetIter(vars);
@@ -643,7 +672,6 @@ _psyco_curs_buildrow_with_factory(cursorObject *self, int row)
return _psyco_curs_buildrow_fill(self, res, row, n, 0);
}
-
PyObject *
psyco_curs_fetchone(cursorObject *self, PyObject *args)
{
@@ -655,6 +683,15 @@ psyco_curs_fetchone(cursorObject *self, PyObject *args)
if (_psyco_curs_prefetch(self) < 0) return NULL;
EXC_IF_NO_TUPLES(self);
+ if (self->name != NULL) {
+ char buffer[128];
+
+ EXC_IF_NO_MARK(self);
+ PyOS_snprintf(buffer, 127, "FETCH FORWARD 1 FROM %s", self->name);
+ if (pq_execute(self, buffer, 0) == -1) return NULL;
+ if (_psyco_curs_prefetch(self) < 0) return NULL;
+ }
+
Dprintf("psyco_curs_fetchone: fetching row %ld", self->row);
Dprintf("psyco_curs_fetchone: rowcount = %ld", self->rowcount);
@@ -706,6 +743,16 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
if (_psyco_curs_prefetch(self) < 0) return NULL;
EXC_IF_NO_TUPLES(self);
+ if (self->name != NULL) {
+ char buffer[128];
+
+ EXC_IF_NO_MARK(self);
+ PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM %s",
+ (int)size, self->name);
+ if (pq_execute(self, buffer, 0) == -1) return NULL;
+ if (_psyco_curs_prefetch(self) < 0) return NULL;
+ }
+
/* make sure size is not > than the available number of rows */
if (size > self->rowcount - self->row || size < 0) {
size = self->rowcount - self->row;
@@ -767,6 +814,15 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args)
EXC_IF_CURS_CLOSED(self);
if (_psyco_curs_prefetch(self) < 0) return NULL;
EXC_IF_NO_TUPLES(self);
+
+ if (self->name != NULL) {
+ char buffer[128];
+
+ EXC_IF_NO_MARK(self);
+ PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM %s", self->name);
+ if (pq_execute(self, buffer, 0) == -1) return NULL;
+ if (_psyco_curs_prefetch(self) < 0) return NULL;
+ }
size = self->rowcount - self->row;
@@ -823,6 +879,12 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
EXC_IF_CURS_CLOSED(self);
+ if (self->name != NULL) {
+ PyErr_SetString(ProgrammingError,
+ "can't call .executemany() on named cursors");
+ return NULL;
+ }
+
if(parameters && parameters != Py_None) {
nparameters = PyObject_Length(parameters);
}
@@ -932,27 +994,47 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
EXC_IF_CURS_CLOSED(self);
- if (strcmp(mode, "relative") == 0) {
- newpos = self->row + value;
- } else if ( strcmp( mode, "absolute") == 0) {
- newpos = value;
- } else {
- PyErr_SetString(ProgrammingError,
- "scroll mode must be 'relative' or 'absolute'");
- return NULL;
- }
-
- if (newpos < 0 || newpos >= self->rowcount ) {
- PyErr_SetString(PyExc_IndexError,
- "scroll destination out of bounds");
- return NULL;
+ /* if the cursor is not named we have the full result set and we can do
+ our own calculations to scroll; else we just delegate the scrolling
+ to the MOVE SQL statement */
+ if (self->name == NULL) {
+ if (strcmp(mode, "relative") == 0) {
+ newpos = self->row + value;
+ } else if (strcmp( mode, "absolute") == 0) {
+ newpos = value;
+ } else {
+ PyErr_SetString(ProgrammingError,
+ "scroll mode must be 'relative' or 'absolute'");
+ return NULL;
+ }
+
+ if (newpos < 0 || newpos >= self->rowcount ) {
+ PyErr_SetString(PyExc_IndexError,
+ "scroll destination out of bounds");
+ return NULL;
+ }
+
+ self->row = newpos;
}
- self->row = newpos;
+ else {
+ char buffer[128];
+
+ EXC_IF_NO_MARK(self);
+
+ if (strcmp(mode, "absolute") == 0) {
+ PyOS_snprintf(buffer, 127, "MOVE ABSOLUTE %d FROM %s",
+ value, self->name);
+ }
+ else {
+ PyOS_snprintf(buffer, 127, "MOVE %d FROM %s", value, self->name);
+ }
+ if (pq_execute(self, buffer, 0) == -1) return NULL;
+ if (_psyco_curs_prefetch(self) < 0) return NULL;
+ }
Py_INCREF(Py_None);
return Py_None;
-
}
@@ -1221,14 +1303,15 @@ static struct PyMemberDef cursorObject_members[] = {
/* DBAPI-2.0 extensions */
{"rownumber", T_LONG, OFFSETOF(row), RO},
{"connection", T_OBJECT, OFFSETOF(conn), RO},
-#ifdef PSYCOPG_EXTENSIONS
+#ifdef PSYCOPG_EXTENSIONS
+ {"name", T_STRING, OFFSETOF(name), RO},
{"statusmessage", T_OBJECT, OFFSETOF(pgstatus), RO},
- {"query", T_STRING, OFFSETOF(query), RO},
+ {"query", T_OBJECT, OFFSETOF(query), RO},
{"row_factory", T_OBJECT, OFFSETOF(tuple_factory), 0},
{"tzinfo_factory", T_OBJECT, OFFSETOF(tzinfo_factory), 0},
{"typecaster", T_OBJECT, OFFSETOF(caster), RO},
{"string_types", T_OBJECT, OFFSETOF(string_types), 0},
- {"binary_types", T_OBJECT, OFFSETOF(binary_types), 0},
+ {"binary_types", T_OBJECT, OFFSETOF(binary_types), 0},
#endif
{NULL}
};
@@ -1236,16 +1319,29 @@ static struct PyMemberDef cursorObject_members[] = {
/* initialization and finalization methods */
static int
-cursor_setup(cursorObject *self, connectionObject *conn)
+cursor_setup(cursorObject *self, connectionObject *conn, char *name)
{
- Dprintf("cursor_setup: init cursor object at %p, refcnt = %d",
- self, ((PyObject *)self)->ob_refcnt);
+ Dprintf("cursor_setup: init cursor object at %p", self);
+ Dprintf("cursor_setup: parameters: name = %s, conn = %p", name, conn);
+ if (name) {
+ self->name = PyMem_Malloc(strlen(name)+1);
+ if (self->name == NULL) return 1;
+ strncpy(self->name, name, strlen(name)+1);
+ }
+
+ /* FIXME: why does this raise an excpetion on the _next_ line of code?
+ if (PyObject_IsInstance((PyObject*)conn,
+ (PyObject *)&connectionType) == 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument 1 must be subclass of psycopg2._psycopg.connection");
+ return 1;
+ } */
self->conn = conn;
Py_INCREF((PyObject*)self->conn);
self->closed = 0;
-
+ self->mark = conn->mark;
self->pgres = NULL;
self->notuples = 1;
self->arraysize = 1;
@@ -1254,7 +1350,6 @@ cursor_setup(cursorObject *self, connectionObject *conn)
self->casts = NULL;
self->notice = NULL;
- self->query = NULL;
self->string_types = NULL;
self->binary_types = NULL;
@@ -1265,6 +1360,8 @@ cursor_setup(cursorObject *self, connectionObject *conn)
Py_INCREF(Py_None);
self->tuple_factory = Py_None;
Py_INCREF(Py_None);
+ self->query = Py_None;
+ Py_INCREF(Py_None);
/* default tzinfo factory */
self->tzinfo_factory = pyPsycopgTzFixedOffsetTimezone;
@@ -1280,15 +1377,15 @@ cursor_dealloc(PyObject* obj)
{
cursorObject *self = (cursorObject *)obj;
-
- if (self->query) free(self->query);
-
- Py_DECREF((PyObject*)self->conn);
+ if (self->name) PyMem_Free(self->name);
+
+ Py_XDECREF((PyObject*)self->conn);
Py_XDECREF(self->casts);
Py_XDECREF(self->description);
Py_XDECREF(self->pgstatus);
Py_XDECREF(self->tuple_factory);
Py_XDECREF(self->tzinfo_factory);
+ Py_XDECREF(self->query);
IFCLEARPGRES(self->pgres);
@@ -1301,16 +1398,18 @@ cursor_dealloc(PyObject* obj)
static int
cursor_init(PyObject *obj, PyObject *args, PyObject *kwds)
{
+ char *name = NULL;
PyObject *conn;
- if (!PyArg_ParseTuple(args, "O", &conn))
+
+ if (!PyArg_ParseTuple(args, "O|s", &conn, &name))
return -1;
- return cursor_setup((cursorObject *)obj, (connectionObject *)conn);
+ return cursor_setup((cursorObject *)obj, (connectionObject *)conn, name);
}
static PyObject *
cursor_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
+{
return type->tp_alloc(type, 0);
}
diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c
index 0876565..92b7a9d 100644
--- a/psycopg/psycopgmodule.c
+++ b/psycopg/psycopgmodule.c
@@ -139,7 +139,7 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
}
if (iport > 0)
- snprintf(port, 16, "%d", iport);
+ PyOS_snprintf(port, 16, "%d", iport);
if (dsn == NULL) {
int l = 36; /* len("dbname= user= password= host= port=\0") */
@@ -295,26 +295,29 @@ PyObject *Error, *Warning, *InterfaceError, *DatabaseError,
static void
psyco_errors_init(void)
{
- Error = PyErr_NewException("psycopg2._psycopg.Error",
- PyExc_StandardError, NULL);
- Warning = PyErr_NewException("psycopg2._psycopg.Warning",
+ /* the names of the exceptions here reflect the oranization of the
+ psycopg2 module and not the fact the the original error objects
+ live in _psycopg */
+
+ Error = PyErr_NewException("psycopg2.Error", PyExc_StandardError, NULL);
+
+ Warning = PyErr_NewException("psycopg2.Warning",
PyExc_StandardError,NULL);
- InterfaceError = PyErr_NewException("psycopg2._psycopg.InterfaceError",
+ InterfaceError = PyErr_NewException("psycopg2.InterfaceError",
Error, NULL);
- DatabaseError = PyErr_NewException("psycopg2._psycopg.DatabaseError",
+ DatabaseError = PyErr_NewException("psycopg2.DatabaseError",
Error, NULL);
- InternalError = PyErr_NewException("psycopg2._psycopg.InternalError",
+ InternalError = PyErr_NewException("psycopg2.InternalError",
DatabaseError, NULL);
- OperationalError = PyErr_NewException("psycopg2._psycopg.OperationalError",
+ OperationalError = PyErr_NewException("psycopg2.OperationalError",
DatabaseError, NULL);
- ProgrammingError = PyErr_NewException("psycopg2._psycopg.ProgrammingError",
+ ProgrammingError = PyErr_NewException("psycopg2.ProgrammingError",
DatabaseError, NULL);
- IntegrityError = PyErr_NewException("psycopg2._psycopg.IntegrityError",
+ IntegrityError = PyErr_NewException("psycopg2.IntegrityError",
DatabaseError,NULL);
- DataError = PyErr_NewException("psycopg2._psycopg.DataError",
+ DataError = PyErr_NewException("psycopg2.DataError",
DatabaseError, NULL);
- NotSupportedError =
- PyErr_NewException("psycopg2._psycopg.NotSupportedError",
+ NotSupportedError = PyErr_NewException("psycopg2.NotSupportedError",
DatabaseError, NULL);
}