mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-11-04 01:37:31 +03:00 
			
		
		
		
	Merge branch 'diagnostics' into devel
This commit is contained in:
		
						commit
						73949cd1b8
					
				| 
						 | 
					@ -165,9 +165,9 @@ functionalities defined by the |DBAPI|_.
 | 
				
			||||||
        table_name
 | 
					        table_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        A string with the error field if available; `!None` if not available.
 | 
					        A string with the error field if available; `!None` if not available.
 | 
				
			||||||
        The attribute value is available only if the error sent by the server
 | 
					        The attribute value is available only if the error sent by the server:
 | 
				
			||||||
        includes the specified field and should remain available until the
 | 
					        not all the fields are available for all the errors and for all the
 | 
				
			||||||
        cursor that generated the exception executes another query.
 | 
					        server versions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. autofunction:: set_wait_callback(f)
 | 
					.. autofunction:: set_wait_callback(f)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,7 +118,7 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
 | 
				
			||||||
            if (kind == 2) {
 | 
					            if (kind == 2) {
 | 
				
			||||||
                Py_XDECREF(n);
 | 
					                Py_XDECREF(n);
 | 
				
			||||||
                psyco_set_error(ProgrammingError, curs,
 | 
					                psyco_set_error(ProgrammingError, curs,
 | 
				
			||||||
                   "argument formats can't be mixed", NULL, NULL);
 | 
					                   "argument formats can't be mixed");
 | 
				
			||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            kind = 1;
 | 
					            kind = 1;
 | 
				
			||||||
| 
						 | 
					@ -190,7 +190,7 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
 | 
				
			||||||
                /* we found %( but not a ) */
 | 
					                /* we found %( but not a ) */
 | 
				
			||||||
                Py_XDECREF(n);
 | 
					                Py_XDECREF(n);
 | 
				
			||||||
                psyco_set_error(ProgrammingError, curs,
 | 
					                psyco_set_error(ProgrammingError, curs,
 | 
				
			||||||
                   "incomplete placeholder: '%(' without ')'", NULL, NULL);
 | 
					                   "incomplete placeholder: '%(' without ')'");
 | 
				
			||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            c = d + 1;  /* after the ) */
 | 
					            c = d + 1;  /* after the ) */
 | 
				
			||||||
| 
						 | 
					@ -205,7 +205,7 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
 | 
				
			||||||
            if (kind == 1) {
 | 
					            if (kind == 1) {
 | 
				
			||||||
                Py_XDECREF(n);
 | 
					                Py_XDECREF(n);
 | 
				
			||||||
                psyco_set_error(ProgrammingError, curs,
 | 
					                psyco_set_error(ProgrammingError, curs,
 | 
				
			||||||
                  "argument formats can't be mixed", NULL, NULL);
 | 
					                  "argument formats can't be mixed");
 | 
				
			||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            kind = 2;
 | 
					            kind = 2;
 | 
				
			||||||
| 
						 | 
					@ -267,7 +267,7 @@ static PyObject *_psyco_curs_validate_sql_basic(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!sql || !PyObject_IsTrue(sql)) {
 | 
					    if (!sql || !PyObject_IsTrue(sql)) {
 | 
				
			||||||
        psyco_set_error(ProgrammingError, self,
 | 
					        psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                         "can't execute an empty query", NULL, NULL);
 | 
					                         "can't execute an empty query");
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -338,8 +338,7 @@ _psyco_curs_merge_query_args(cursorObject *self,
 | 
				
			||||||
                if (!strcmp(s, "not enough arguments for format string")
 | 
					                if (!strcmp(s, "not enough arguments for format string")
 | 
				
			||||||
                  || !strcmp(s, "not all arguments converted")) {
 | 
					                  || !strcmp(s, "not all arguments converted")) {
 | 
				
			||||||
                    Dprintf("psyco_curs_execute:     -> got a match");
 | 
					                    Dprintf("psyco_curs_execute:     -> got a match");
 | 
				
			||||||
                    psyco_set_error(ProgrammingError, self,
 | 
					                    psyco_set_error(ProgrammingError, self, s);
 | 
				
			||||||
                                     s, NULL, NULL);
 | 
					 | 
				
			||||||
                    pe = 1;
 | 
					                    pe = 1;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -482,13 +481,12 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
 | 
				
			||||||
    if (self->name != NULL) {
 | 
					    if (self->name != NULL) {
 | 
				
			||||||
        if (self->query != Py_None) {
 | 
					        if (self->query != Py_None) {
 | 
				
			||||||
            psyco_set_error(ProgrammingError, self,
 | 
					            psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                "can't call .execute() on named cursors more than once",
 | 
					                "can't call .execute() on named cursors more than once");
 | 
				
			||||||
                NULL, NULL);
 | 
					 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (self->conn->autocommit) {
 | 
					        if (self->conn->autocommit) {
 | 
				
			||||||
            psyco_set_error(ProgrammingError, self,
 | 
					            psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                "can't use a named cursor outside of transactions", NULL, NULL);
 | 
					                "can't use a named cursor outside of transactions");
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        EXC_IF_NO_MARK(self);
 | 
					        EXC_IF_NO_MARK(self);
 | 
				
			||||||
| 
						 | 
					@ -533,7 +531,7 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->name != NULL) {
 | 
					    if (self->name != NULL) {
 | 
				
			||||||
        psyco_set_error(ProgrammingError, self,
 | 
					        psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                "can't call .executemany() on named cursors", NULL, NULL);
 | 
					                "can't call .executemany() on named cursors");
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1038,7 +1036,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (self->name != NULL) {
 | 
					    if (self->name != NULL) {
 | 
				
			||||||
        psyco_set_error(ProgrammingError, self,
 | 
					        psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                         "can't call .callproc() on named cursors", NULL, NULL);
 | 
					                         "can't call .callproc() on named cursors");
 | 
				
			||||||
        goto exit;
 | 
					        goto exit;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1165,13 +1163,13 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
 | 
				
			||||||
            newpos = value;
 | 
					            newpos = value;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            psyco_set_error(ProgrammingError, self,
 | 
					            psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                "scroll mode must be 'relative' or 'absolute'", NULL, NULL);
 | 
					                "scroll mode must be 'relative' or 'absolute'");
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (newpos < 0 || newpos >= self->rowcount ) {
 | 
					        if (newpos < 0 || newpos >= self->rowcount ) {
 | 
				
			||||||
            psyco_set_error(ProgrammingError, self,
 | 
					            psyco_set_error(ProgrammingError, self,
 | 
				
			||||||
                             "scroll destination out of bounds", NULL, NULL);
 | 
					                             "scroll destination out of bounds");
 | 
				
			||||||
            return NULL;
 | 
					            return NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,12 +26,14 @@
 | 
				
			||||||
#ifndef PSYCOPG_DIAGNOSTICS_H
 | 
					#ifndef PSYCOPG_DIAGNOSTICS_H
 | 
				
			||||||
#define PSYCOPG_DIAGNOSTICS_H 1
 | 
					#define PSYCOPG_DIAGNOSTICS_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "psycopg/error.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern HIDDEN PyTypeObject diagnosticsType;
 | 
					extern HIDDEN PyTypeObject diagnosticsType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    PyObject_HEAD
 | 
					    PyObject_HEAD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PyObject *err;           /* exception to retrieve the diagnostics from */
 | 
					    errorObject *err;  /* exception to retrieve the diagnostics from */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} diagnosticsObject;
 | 
					} diagnosticsObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@
 | 
				
			||||||
#include "psycopg/psycopg.h"
 | 
					#include "psycopg/psycopg.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "psycopg/diagnostics.h"
 | 
					#include "psycopg/diagnostics.h"
 | 
				
			||||||
#include "psycopg/cursor.h"
 | 
					#include "psycopg/error.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* These are new in PostgreSQL 9.3. Defining them here so that psycopg2 can
 | 
					/* These are new in PostgreSQL 9.3. Defining them here so that psycopg2 can
 | 
				
			||||||
 * use them with a 9.3+ server even if compiled against pre-9.3 headers. */
 | 
					 * use them with a 9.3+ server even if compiled against pre-9.3 headers. */
 | 
				
			||||||
| 
						 | 
					@ -55,27 +55,15 @@
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
psyco_diagnostics_get_field(diagnosticsObject *self, void *closure)
 | 
					psyco_diagnostics_get_field(diagnosticsObject *self, void *closure)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // closure contains the field code.
 | 
					    const char *errortext;
 | 
				
			||||||
    PyObject *rv = NULL;
 | 
					
 | 
				
			||||||
    PyObject *curs = NULL;
 | 
					    if (!self->err->pgres) {
 | 
				
			||||||
    const char* errortext;
 | 
					        Py_INCREF(Py_None);
 | 
				
			||||||
    if (!(curs = PyObject_GetAttrString(self->err, "cursor")) ||
 | 
					        return Py_None;
 | 
				
			||||||
        !PyObject_TypeCheck(curs, &cursorType) ||
 | 
					 | 
				
			||||||
        ((cursorObject *)curs)->pgres == NULL) {
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    errortext = PQresultErrorField(
 | 
					
 | 
				
			||||||
        ((cursorObject *)curs)->pgres, (Py_intptr_t) closure);
 | 
					    errortext = PQresultErrorField(self->err->pgres, (Py_intptr_t) closure);
 | 
				
			||||||
    if (errortext) {
 | 
					    return error_text_from_chars(self->err, errortext);
 | 
				
			||||||
        rv = conn_text_from_chars(((cursorObject *)curs)->conn, errortext);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
exit:
 | 
					 | 
				
			||||||
    if (!rv) {
 | 
					 | 
				
			||||||
        rv = Py_None;
 | 
					 | 
				
			||||||
        Py_INCREF(rv);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    Py_XDECREF(curs);
 | 
					 | 
				
			||||||
    return rv;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,8 +122,14 @@ diagnostics_init(diagnosticsObject *self, PyObject *args, PyObject *kwds)
 | 
				
			||||||
    if (!PyArg_ParseTuple(args, "O", &err))
 | 
					    if (!PyArg_ParseTuple(args, "O", &err))
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyObject_TypeCheck(err, &errorType)) {
 | 
				
			||||||
 | 
					        PyErr_SetString(PyExc_TypeError,
 | 
				
			||||||
 | 
					            "The argument must be a psycopg2.Error");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Py_INCREF(err);
 | 
					    Py_INCREF(err);
 | 
				
			||||||
    self->err = err;
 | 
					    self->err = (errorObject *)err;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										43
									
								
								psycopg/error.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								psycopg/error.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					/* error.h - definition for the psycopg base Error type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2013  Daniele Varrazzo <daniele.varrazzo@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file is part of psycopg.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * psycopg2 is free software: you can redistribute it and/or modify it
 | 
				
			||||||
 | 
					 * under the terms of the GNU Lesser General Public License as published
 | 
				
			||||||
 | 
					 * by the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In addition, as a special exception, the copyright holders give
 | 
				
			||||||
 | 
					 * permission to link this program with the OpenSSL library (or with
 | 
				
			||||||
 | 
					 * modified versions of OpenSSL that use the same license as OpenSSL),
 | 
				
			||||||
 | 
					 * and distribute linked combinations including the two.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You must obey the GNU Lesser General Public License in all respects for
 | 
				
			||||||
 | 
					 * all of the code used other than OpenSSL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * psycopg2 is distributed in the hope that it will be useful, but WITHOUT
 | 
				
			||||||
 | 
					 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef PSYCOPG_ERROR_H
 | 
				
			||||||
 | 
					#define PSYCOPG_ERROR_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern HIDDEN PyTypeObject errorType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    PyBaseExceptionObject exc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PyObject *pgerror;
 | 
				
			||||||
 | 
					    PyObject *pgcode;
 | 
				
			||||||
 | 
					    cursorObject *cursor;
 | 
				
			||||||
 | 
					    char *codec;
 | 
				
			||||||
 | 
					    PGresult *pgres;
 | 
				
			||||||
 | 
					} errorObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HIDDEN PyObject *error_text_from_chars(errorObject *self, const char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* PSYCOPG_ERROR_H */
 | 
				
			||||||
							
								
								
									
										291
									
								
								psycopg/error_type.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								psycopg/error_type.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,291 @@
 | 
				
			||||||
 | 
					/* error_type.c - python interface to the Error objects
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2013  Daniele Varrazzo <daniele.varrazzo@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file is part of psycopg.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * psycopg2 is free software: you can redistribute it and/or modify it
 | 
				
			||||||
 | 
					 * under the terms of the GNU Lesser General Public License as published
 | 
				
			||||||
 | 
					 * by the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In addition, as a special exception, the copyright holders give
 | 
				
			||||||
 | 
					 * permission to link this program with the OpenSSL library (or with
 | 
				
			||||||
 | 
					 * modified versions of OpenSSL that use the same license as OpenSSL),
 | 
				
			||||||
 | 
					 * and distribute linked combinations including the two.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You must obey the GNU Lesser General Public License in all respects for
 | 
				
			||||||
 | 
					 * all of the code used other than OpenSSL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * psycopg2 is distributed in the hope that it will be useful, but WITHOUT
 | 
				
			||||||
 | 
					 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 | 
				
			||||||
 | 
					 * License for more details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PSYCOPG_MODULE
 | 
				
			||||||
 | 
					#include "psycopg/psycopg.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "psycopg/error.h"
 | 
				
			||||||
 | 
					#include "psycopg/diagnostics.h"
 | 
				
			||||||
 | 
					#include "psycopg/pqpath.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PyObject *
 | 
				
			||||||
 | 
					error_text_from_chars(errorObject *self, const char *str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (str == NULL) {
 | 
				
			||||||
 | 
					        Py_INCREF(Py_None);
 | 
				
			||||||
 | 
					        return (Py_None);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if PY_MAJOR_VERSION < 3
 | 
				
			||||||
 | 
					        return PyString_FromString(str);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        return PyUnicode_Decode(str, strlen(str),
 | 
				
			||||||
 | 
					            self->codec ? self->codec : "ascii", "replace");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char pgerror_doc[] =
 | 
				
			||||||
 | 
					    "The error message returned by the backend, if available, else None";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char pgcode_doc[] =
 | 
				
			||||||
 | 
					    "The error code returned by the backend, if available, else None";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char cursor_doc[] =
 | 
				
			||||||
 | 
					    "The cursor that raised the exception, if available, else None";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char diag_doc[] =
 | 
				
			||||||
 | 
					    "A Diagnostics object to get further information about the error";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyMemberDef error_members[] = {
 | 
				
			||||||
 | 
					    { "pgerror", T_OBJECT, offsetof(errorObject, pgerror),
 | 
				
			||||||
 | 
					        READONLY, (char *)pgerror_doc },
 | 
				
			||||||
 | 
					    { "pgcode", T_OBJECT, offsetof(errorObject, pgcode),
 | 
				
			||||||
 | 
					        READONLY, (char *)pgcode_doc },
 | 
				
			||||||
 | 
					    { "cursor", T_OBJECT, offsetof(errorObject, cursor),
 | 
				
			||||||
 | 
					        READONLY, (char *)cursor_doc },
 | 
				
			||||||
 | 
					    { NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					error_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return ((PyTypeObject *)PyExc_StandardError)->tp_new(
 | 
				
			||||||
 | 
					            type, args, kwargs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					error_init(errorObject *self, PyObject *args, PyObject *kwargs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (((PyTypeObject *)PyExc_StandardError)->tp_init(
 | 
				
			||||||
 | 
					            (PyObject *)self, args, kwargs) < 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					error_traverse(errorObject *self, visitproc visit, void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Py_VISIT(self->cursor);
 | 
				
			||||||
 | 
					    return ((PyTypeObject *)PyExc_StandardError)->tp_traverse(
 | 
				
			||||||
 | 
					        (PyObject *)self, visit, arg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					error_clear(errorObject *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Py_CLEAR(self->pgerror);
 | 
				
			||||||
 | 
					    Py_CLEAR(self->pgcode);
 | 
				
			||||||
 | 
					    Py_CLEAR(self->cursor);
 | 
				
			||||||
 | 
					    PyMem_Free(self->codec);
 | 
				
			||||||
 | 
					    IFCLEARPGRES(self->pgres);
 | 
				
			||||||
 | 
					    return ((PyTypeObject *)PyExc_StandardError)->tp_clear((PyObject *)self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					error_dealloc(errorObject *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    error_clear(self);
 | 
				
			||||||
 | 
					    return Py_TYPE(self)->tp_free((PyObject *)self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					error_get_diag(errorObject *self, void *closure)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return PyObject_CallFunctionObjArgs(
 | 
				
			||||||
 | 
					        (PyObject *)&diagnosticsType, (PyObject *)self, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct PyGetSetDef error_getsets[] = {
 | 
				
			||||||
 | 
					    { "diag", (getter)error_get_diag, NULL, (char *)diag_doc },
 | 
				
			||||||
 | 
					    { NULL }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if PY_VERSION_HEX >= 0x02050000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Error.__reduce__
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The method is required to make exceptions picklable: set the cursor
 | 
				
			||||||
 | 
					 * attribute to None. Only working from Py 2.5: previous versions
 | 
				
			||||||
 | 
					 * would require implementing __getstate__, and as of 2012 it's a little
 | 
				
			||||||
 | 
					 * bit too late to care. */
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					psyco_error_reduce(errorObject *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PyObject *meth = NULL;
 | 
				
			||||||
 | 
					    PyObject *tuple = NULL;
 | 
				
			||||||
 | 
					    PyObject *dict = NULL;
 | 
				
			||||||
 | 
					    PyObject *rv = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(meth = PyObject_GetAttrString(PyExc_StandardError, "__reduce__"))) {
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!(tuple = PyObject_CallFunctionObjArgs(meth, self, NULL))) {
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* tuple is (type, args): convert it to (type, args, dict)
 | 
				
			||||||
 | 
					     * with our extra items in the dict.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * If these checks fail, we can still return a valid object. Pickle
 | 
				
			||||||
 | 
					     * will likely fail downstream, but there's nothing else we can do here */
 | 
				
			||||||
 | 
					    if (!PyTuple_Check(tuple)) { goto exit; }
 | 
				
			||||||
 | 
					    if (2 != PyTuple_GET_SIZE(tuple)) { goto exit; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(dict = PyDict_New())) { goto error; }
 | 
				
			||||||
 | 
					    if (0 != PyDict_SetItemString(dict, "pgerror", self->pgerror)) { goto error; }
 | 
				
			||||||
 | 
					    if (0 != PyDict_SetItemString(dict, "pgcode", self->pgcode)) { goto error; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        PyObject *newtuple;
 | 
				
			||||||
 | 
					        if (!(newtuple = PyTuple_Pack(3,
 | 
				
			||||||
 | 
					                PyTuple_GET_ITEM(tuple, 0),
 | 
				
			||||||
 | 
					                PyTuple_GET_ITEM(tuple, 1),
 | 
				
			||||||
 | 
					                dict))) {
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Py_DECREF(tuple);
 | 
				
			||||||
 | 
					        tuple = newtuple;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
					    rv = tuple;
 | 
				
			||||||
 | 
					    tuple = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
					    Py_XDECREF(dict);
 | 
				
			||||||
 | 
					    Py_XDECREF(tuple);
 | 
				
			||||||
 | 
					    Py_XDECREF(meth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PyObject *
 | 
				
			||||||
 | 
					psyco_error_setstate(errorObject *self, PyObject *state)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PyObject *rv = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* we don't call the StandartError's setstate as it would try to load the
 | 
				
			||||||
 | 
					     * dict content as attributes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state == Py_None) {
 | 
				
			||||||
 | 
					        goto exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!PyDict_Check(state)) {
 | 
				
			||||||
 | 
					        PyErr_SetString(PyExc_TypeError, "state is not a dictionary");
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* load the dict content in the structure */
 | 
				
			||||||
 | 
					    Py_CLEAR(self->pgerror);
 | 
				
			||||||
 | 
					    self->pgerror = PyDict_GetItemString(state, "pgerror");
 | 
				
			||||||
 | 
					    Py_XINCREF(self->pgerror);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_CLEAR(self->pgcode);
 | 
				
			||||||
 | 
					    self->pgcode = PyDict_GetItemString(state, "pgcode");
 | 
				
			||||||
 | 
					    Py_XINCREF(self->pgcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_CLEAR(self->cursor);
 | 
				
			||||||
 | 
					    /* We never expect a cursor in the state as it's not picklable.
 | 
				
			||||||
 | 
					     * at most there could be a None here, coming from Psycopg < 2.5 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit:
 | 
				
			||||||
 | 
					    rv = Py_None;
 | 
				
			||||||
 | 
					    Py_INCREF(rv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
					    return rv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* PY_VERSION_HEX >= 0x02050000 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyMethodDef error_methods[] = {
 | 
				
			||||||
 | 
					#if PY_VERSION_HEX >= 0x02050000
 | 
				
			||||||
 | 
					    /* Make Error and all its subclasses picklable.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * TODO: this comment applied to the __reduce_ex__ implementation: now
 | 
				
			||||||
 | 
					     * pickling may work on Py 2.4 too... but it's 2013 now.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Don't do it it on Py 2.4: [__reduce_ex__] it is not used by the pickle
 | 
				
			||||||
 | 
					     * protocol, and if called manually fails in an unsettling way,
 | 
				
			||||||
 | 
					     * probably because the exceptions were old-style classes. */
 | 
				
			||||||
 | 
					    {"__reduce__", (PyCFunction)psyco_error_reduce, METH_NOARGS },
 | 
				
			||||||
 | 
					    {"__setstate__", (PyCFunction)psyco_error_setstate, METH_O },
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    {NULL}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PyTypeObject errorType = {
 | 
				
			||||||
 | 
					    PyVarObject_HEAD_INIT(NULL, 0)
 | 
				
			||||||
 | 
					    "psycopg2.Error",
 | 
				
			||||||
 | 
					    sizeof(errorObject),
 | 
				
			||||||
 | 
					    0,
 | 
				
			||||||
 | 
					    (destructor)error_dealloc, /* tp_dealloc */
 | 
				
			||||||
 | 
					    0,          /*tp_print*/
 | 
				
			||||||
 | 
					    0,          /*tp_getattr*/
 | 
				
			||||||
 | 
					    0,          /*tp_setattr*/
 | 
				
			||||||
 | 
					    0,          /*tp_compare*/
 | 
				
			||||||
 | 
					    0,          /*tp_repr*/
 | 
				
			||||||
 | 
					    0,          /*tp_as_number*/
 | 
				
			||||||
 | 
					    0,          /*tp_as_sequence*/
 | 
				
			||||||
 | 
					    0,          /*tp_as_mapping*/
 | 
				
			||||||
 | 
					    0,          /*tp_hash */
 | 
				
			||||||
 | 
					    0,          /*tp_call*/
 | 
				
			||||||
 | 
					    0,          /*tp_str*/
 | 
				
			||||||
 | 
					    0,          /*tp_getattro*/
 | 
				
			||||||
 | 
					    0,          /*tp_setattro*/
 | 
				
			||||||
 | 
					    0,          /*tp_as_buffer*/
 | 
				
			||||||
 | 
					    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
 | 
				
			||||||
 | 
					    Error_doc, /*tp_doc*/
 | 
				
			||||||
 | 
					    (traverseproc)error_traverse, /*tp_traverse*/
 | 
				
			||||||
 | 
					    (inquiry)error_clear, /*tp_clear*/
 | 
				
			||||||
 | 
					    0,          /*tp_richcompare*/
 | 
				
			||||||
 | 
					    0,          /*tp_weaklistoffset*/
 | 
				
			||||||
 | 
					    0,          /*tp_iter*/
 | 
				
			||||||
 | 
					    0,          /*tp_iternext*/
 | 
				
			||||||
 | 
					    error_methods, /*tp_methods*/
 | 
				
			||||||
 | 
					    error_members, /*tp_members*/
 | 
				
			||||||
 | 
					    error_getsets, /*tp_getset*/
 | 
				
			||||||
 | 
					    0,          /*tp_base Will be set to StandardError in module init */
 | 
				
			||||||
 | 
					    0,          /*tp_dict*/
 | 
				
			||||||
 | 
					    0,          /*tp_descr_get*/
 | 
				
			||||||
 | 
					    0,          /*tp_descr_set*/
 | 
				
			||||||
 | 
					    0,          /*tp_dictoffset*/
 | 
				
			||||||
 | 
					    (initproc)error_init, /*tp_init*/
 | 
				
			||||||
 | 
					    0, /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
 | 
				
			||||||
 | 
					    error_new, /*tp_new*/
 | 
				
			||||||
 | 
					    0,          /*tp_free  Low-level free-memory routine */
 | 
				
			||||||
 | 
					    0,          /*tp_is_gc For PyObject_IS_GC */
 | 
				
			||||||
 | 
					    0,          /*tp_bases*/
 | 
				
			||||||
 | 
					    0,          /*tp_mro method resolution order */
 | 
				
			||||||
 | 
					    0,          /*tp_cache*/
 | 
				
			||||||
 | 
					    0,          /*tp_subclasses*/
 | 
				
			||||||
 | 
					    0           /*tp_weaklist*/
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -78,13 +78,13 @@ RAISES_NEG HIDDEN int lobject_close(lobjectObject *self);
 | 
				
			||||||
#define EXC_IF_LOBJ_LEVEL0(self) \
 | 
					#define EXC_IF_LOBJ_LEVEL0(self) \
 | 
				
			||||||
if (self->conn->autocommit) {                                       \
 | 
					if (self->conn->autocommit) {                                       \
 | 
				
			||||||
    psyco_set_error(ProgrammingError, NULL,                         \
 | 
					    psyco_set_error(ProgrammingError, NULL,                         \
 | 
				
			||||||
        "can't use a lobject outside of transactions", NULL, NULL); \
 | 
					        "can't use a lobject outside of transactions");             \
 | 
				
			||||||
    return NULL;                                                    \
 | 
					    return NULL;                                                    \
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#define EXC_IF_LOBJ_UNMARKED(self) \
 | 
					#define EXC_IF_LOBJ_UNMARKED(self) \
 | 
				
			||||||
if (self->conn->mark != self->mark) {                  \
 | 
					if (self->conn->mark != self->mark) {                  \
 | 
				
			||||||
    psyco_set_error(ProgrammingError, NULL,            \
 | 
					    psyco_set_error(ProgrammingError, NULL,            \
 | 
				
			||||||
        "lobject isn't valid anymore", NULL, NULL);    \
 | 
					        "lobject isn't valid anymore");                \
 | 
				
			||||||
    return NULL;                                       \
 | 
					    return NULL;                                       \
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -333,7 +333,7 @@ lobject_setup(lobjectObject *self, connectionObject *conn,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (conn->autocommit) {
 | 
					    if (conn->autocommit) {
 | 
				
			||||||
        psyco_set_error(ProgrammingError, NULL,
 | 
					        psyco_set_error(ProgrammingError, NULL,
 | 
				
			||||||
            "can't use a lobject outside of transactions", NULL, NULL);
 | 
					            "can't use a lobject outside of transactions");
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,7 +203,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
 | 
				
			||||||
    /* else set the right exception and return NULL */
 | 
					    /* else set the right exception and return NULL */
 | 
				
			||||||
    PyOS_snprintf(buffer, 255, "can't adapt type '%s'",
 | 
					    PyOS_snprintf(buffer, 255, "can't adapt type '%s'",
 | 
				
			||||||
        Py_TYPE(obj)->tp_name);
 | 
					        Py_TYPE(obj)->tp_name);
 | 
				
			||||||
    psyco_set_error(ProgrammingError, NULL, buffer, NULL, NULL);
 | 
					    psyco_set_error(ProgrammingError, NULL, buffer);
 | 
				
			||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,7 @@
 | 
				
			||||||
#include "psycopg/green.h"
 | 
					#include "psycopg/green.h"
 | 
				
			||||||
#include "psycopg/typecast.h"
 | 
					#include "psycopg/typecast.h"
 | 
				
			||||||
#include "psycopg/pgtypes.h"
 | 
					#include "psycopg/pgtypes.h"
 | 
				
			||||||
 | 
					#include "psycopg/error.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,15 +150,20 @@ exception_from_sqlstate(const char *sqlstate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* pq_raise - raise a python exception of the right kind
 | 
					/* pq_raise - raise a python exception of the right kind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   This function should be called while holding the GIL. */
 | 
					   This function should be called while holding the GIL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The function passes the ownership of the pgres to the returned exception,
 | 
				
			||||||
 | 
					   wherer the pgres was the explicit argument or taken from the cursor.
 | 
				
			||||||
 | 
					   So, after calling it curs->pgres will be set to null */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RAISES static void
 | 
					RAISES static void
 | 
				
			||||||
pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
 | 
					pq_raise(connectionObject *conn, cursorObject *curs, PGresult **pgres)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PyObject *exc = NULL;
 | 
					    PyObject *exc = NULL;
 | 
				
			||||||
    const char *err = NULL;
 | 
					    const char *err = NULL;
 | 
				
			||||||
    const char *err2 = NULL;
 | 
					    const char *err2 = NULL;
 | 
				
			||||||
    const char *code = NULL;
 | 
					    const char *code = NULL;
 | 
				
			||||||
 | 
					    PyObject *pyerr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (conn == NULL) {
 | 
					    if (conn == NULL) {
 | 
				
			||||||
        PyErr_SetString(DatabaseError,
 | 
					        PyErr_SetString(DatabaseError,
 | 
				
			||||||
| 
						 | 
					@ -171,13 +177,13 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
 | 
				
			||||||
        conn->closed = 2;
 | 
					        conn->closed = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pgres == NULL && curs != NULL)
 | 
					    if (pgres == NULL && curs != NULL)
 | 
				
			||||||
        pgres = curs->pgres;
 | 
					        pgres = &curs->pgres;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pgres) {
 | 
					    if (pgres && *pgres) {
 | 
				
			||||||
        err = PQresultErrorMessage(pgres);
 | 
					        err = PQresultErrorMessage(*pgres);
 | 
				
			||||||
        if (err != NULL) {
 | 
					        if (err != NULL) {
 | 
				
			||||||
            Dprintf("pq_raise: PQresultErrorMessage: err=%s", err);
 | 
					            Dprintf("pq_raise: PQresultErrorMessage: err=%s", err);
 | 
				
			||||||
            code = PQresultErrorField(pgres, PG_DIAG_SQLSTATE);
 | 
					            code = PQresultErrorField(*pgres, PG_DIAG_SQLSTATE);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (err == NULL) {
 | 
					    if (err == NULL) {
 | 
				
			||||||
| 
						 | 
					@ -210,7 +216,26 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
 | 
				
			||||||
    err2 = strip_severity(err);
 | 
					    err2 = strip_severity(err);
 | 
				
			||||||
    Dprintf("pq_raise: err2=%s", err2);
 | 
					    Dprintf("pq_raise: err2=%s", err2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    psyco_set_error(exc, curs, err2, err, code);
 | 
					    pyerr = psyco_set_error(exc, curs, err2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pyerr && PyObject_TypeCheck(pyerr, &errorType)) {
 | 
				
			||||||
 | 
					        errorObject *perr = (errorObject *)pyerr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PyMem_Free(perr->codec);
 | 
				
			||||||
 | 
					        psycopg_strdup(&perr->codec, conn->codec, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Py_CLEAR(perr->pgerror);
 | 
				
			||||||
 | 
					        perr->pgerror = error_text_from_chars(perr, err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Py_CLEAR(perr->pgcode);
 | 
				
			||||||
 | 
					        perr->pgcode = error_text_from_chars(perr, code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IFCLEARPGRES(perr->pgres);
 | 
				
			||||||
 | 
					        if (pgres && *pgres) {
 | 
				
			||||||
 | 
					            perr->pgres = *pgres;
 | 
				
			||||||
 | 
					            *pgres = NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* pq_set_critical, pq_resolve_critical - manage critical errors
 | 
					/* pq_set_critical, pq_resolve_critical - manage critical errors
 | 
				
			||||||
| 
						 | 
					@ -388,14 +413,16 @@ pq_complete_error(connectionObject *conn, PGresult **pgres, char **error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s",
 | 
					    Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s",
 | 
				
			||||||
            conn->pgconn, *pgres, *error ? *error : "(null)");
 | 
					            conn->pgconn, *pgres, *error ? *error : "(null)");
 | 
				
			||||||
    if (*pgres != NULL)
 | 
					    if (*pgres != NULL) {
 | 
				
			||||||
        pq_raise(conn, NULL, *pgres);
 | 
					        pq_raise(conn, NULL, pgres);
 | 
				
			||||||
 | 
					        /* now *pgres is null */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    else if (*error != NULL) {
 | 
					    else if (*error != NULL) {
 | 
				
			||||||
        PyErr_SetString(OperationalError, *error);
 | 
					        PyErr_SetString(OperationalError, *error);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        PyErr_SetString(OperationalError, "unknown error");
 | 
					        PyErr_SetString(OperationalError, "unknown error");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    IFCLEARPGRES(*pgres);
 | 
					
 | 
				
			||||||
    if (*error) {
 | 
					    if (*error) {
 | 
				
			||||||
        free(*error);
 | 
					        free(*error);
 | 
				
			||||||
        *error = NULL;
 | 
					        *error = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1509,8 +1536,6 @@ pq_fetch(cursorObject *curs, int no_result)
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        Dprintf("pq_fetch: uh-oh, something FAILED: pgconn = %p", curs->conn);
 | 
					        Dprintf("pq_fetch: uh-oh, something FAILED: pgconn = %p", curs->conn);
 | 
				
			||||||
        pq_raise(curs->conn, curs, NULL);
 | 
					        pq_raise(curs->conn, curs, NULL);
 | 
				
			||||||
        /* don't clear curs->pgres, because it contains detailed error
 | 
					 | 
				
			||||||
           information */
 | 
					 | 
				
			||||||
        ex = -1;
 | 
					        ex = -1;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,8 +120,7 @@ HIDDEN PyObject *psyco_GetDecimalType(void);
 | 
				
			||||||
typedef struct cursorObject cursorObject;
 | 
					typedef struct cursorObject cursorObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* some utility functions */
 | 
					/* some utility functions */
 | 
				
			||||||
RAISES HIDDEN void psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
 | 
					RAISES HIDDEN PyObject *psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg);
 | 
				
			||||||
                            const char *pgerror, const char *pgcode);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
HIDDEN char *psycopg_escape_string(PyObject *conn,
 | 
					HIDDEN char *psycopg_escape_string(PyObject *conn,
 | 
				
			||||||
              const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen);
 | 
					              const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,7 @@
 | 
				
			||||||
#include "psycopg/typecast.h"
 | 
					#include "psycopg/typecast.h"
 | 
				
			||||||
#include "psycopg/microprotocols.h"
 | 
					#include "psycopg/microprotocols.h"
 | 
				
			||||||
#include "psycopg/microprotocols_proto.h"
 | 
					#include "psycopg/microprotocols_proto.h"
 | 
				
			||||||
 | 
					#include "psycopg/error.h"
 | 
				
			||||||
#include "psycopg/diagnostics.h"
 | 
					#include "psycopg/diagnostics.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "psycopg/adapter_qstring.h"
 | 
					#include "psycopg/adapter_qstring.h"
 | 
				
			||||||
| 
						 | 
					@ -409,8 +410,8 @@ static struct {
 | 
				
			||||||
    PyObject **base;
 | 
					    PyObject **base;
 | 
				
			||||||
    const char *docstr;
 | 
					    const char *docstr;
 | 
				
			||||||
} exctable[] = {
 | 
					} exctable[] = {
 | 
				
			||||||
    { "psycopg2.Error", &Error, 0, Error_doc },
 | 
					    { "psycopg2.Error", &Error, &PyExc_StandardError, Error_doc },
 | 
				
			||||||
    { "psycopg2.Warning", &Warning, 0, Warning_doc },
 | 
					    { "psycopg2.Warning", &Warning, &PyExc_StandardError, Warning_doc },
 | 
				
			||||||
    { "psycopg2.InterfaceError", &InterfaceError, &Error, InterfaceError_doc },
 | 
					    { "psycopg2.InterfaceError", &InterfaceError, &Error, InterfaceError_doc },
 | 
				
			||||||
    { "psycopg2.DatabaseError", &DatabaseError, &Error, DatabaseError_doc },
 | 
					    { "psycopg2.DatabaseError", &DatabaseError, &Error, DatabaseError_doc },
 | 
				
			||||||
    { "psycopg2.InternalError", &InternalError, &DatabaseError, InternalError_doc },
 | 
					    { "psycopg2.InternalError", &InternalError, &DatabaseError, InternalError_doc },
 | 
				
			||||||
| 
						 | 
					@ -434,61 +435,6 @@ static struct {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if PY_VERSION_HEX >= 0x02050000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Error.__reduce_ex__
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The method is required to make exceptions picklable: set the cursor
 | 
					 | 
				
			||||||
 * attribute to None. Only working from Py 2.5: previous versions
 | 
					 | 
				
			||||||
 * would require implementing __getstate__, and as of 2012 it's a little
 | 
					 | 
				
			||||||
 * bit too late to care. */
 | 
					 | 
				
			||||||
static PyObject *
 | 
					 | 
				
			||||||
psyco_error_reduce_ex(PyObject *self, PyObject *args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PyObject *proto = NULL;
 | 
					 | 
				
			||||||
    PyObject *super = NULL;
 | 
					 | 
				
			||||||
    PyObject *tuple = NULL;
 | 
					 | 
				
			||||||
    PyObject *dict = NULL;
 | 
					 | 
				
			||||||
    PyObject *rv = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* tuple = Exception.__reduce_ex__(self, proto) */
 | 
					 | 
				
			||||||
    if (!PyArg_ParseTuple(args, "O", &proto)) {
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!(super = PyObject_GetAttrString(PyExc_Exception, "__reduce_ex__"))) {
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!(tuple = PyObject_CallFunctionObjArgs(super, self, proto, NULL))) {
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* tuple[2]['cursor'] = None
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * If these checks fail, we can still return a valid object. Pickle
 | 
					 | 
				
			||||||
     * will likely fail downstream, but there's nothing else we can do here */
 | 
					 | 
				
			||||||
    if (!PyTuple_Check(tuple)) { goto exit; }
 | 
					 | 
				
			||||||
    if (3 > PyTuple_GET_SIZE(tuple)) { goto exit; }
 | 
					 | 
				
			||||||
    dict = PyTuple_GET_ITEM(tuple, 2);      /* borrowed */
 | 
					 | 
				
			||||||
    if (!PyDict_Check(dict)) { goto exit; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Modify the tuple inplace and return it */
 | 
					 | 
				
			||||||
    if (0 != PyDict_SetItemString(dict, "cursor", Py_None)) {
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
exit:
 | 
					 | 
				
			||||||
    rv = tuple;
 | 
					 | 
				
			||||||
    tuple = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
    Py_XDECREF(tuple);
 | 
					 | 
				
			||||||
    Py_XDECREF(super);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return rv;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  /* PY_VERSION_HEX >= 0x02050000 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
psyco_errors_init(void)
 | 
					psyco_errors_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -498,18 +444,13 @@ psyco_errors_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    PyObject *dict = NULL;
 | 
					    PyObject *dict = NULL;
 | 
				
			||||||
    PyObject *base;
 | 
					 | 
				
			||||||
    PyObject *str = NULL;
 | 
					    PyObject *str = NULL;
 | 
				
			||||||
    PyObject *descr = NULL;
 | 
					 | 
				
			||||||
    PyObject *diag_property = NULL;
 | 
					 | 
				
			||||||
    int rv = -1;
 | 
					    int rv = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if PY_VERSION_HEX >= 0x02050000
 | 
					    /* 'Error' has been defined elsewhere: only init the other classes */
 | 
				
			||||||
    static PyMethodDef psyco_error_reduce_ex_def =
 | 
					    Error = (PyObject *)&errorType;
 | 
				
			||||||
        {"__reduce_ex__", psyco_error_reduce_ex, METH_VARARGS, "pickle helper"};
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i=0; exctable[i].name; i++) {
 | 
					    for (i = 1; exctable[i].name; i++) {
 | 
				
			||||||
        if (!(dict = PyDict_New())) { goto exit; }
 | 
					        if (!(dict = PyDict_New())) { goto exit; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (exctable[i].docstr) {
 | 
					        if (exctable[i].docstr) {
 | 
				
			||||||
| 
						 | 
					@ -518,58 +459,16 @@ psyco_errors_init(void)
 | 
				
			||||||
            Py_CLEAR(str);
 | 
					            Py_CLEAR(str);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (exctable[i].base == 0) {
 | 
					 | 
				
			||||||
            #if PY_MAJOR_VERSION < 3
 | 
					 | 
				
			||||||
            base = PyExc_StandardError;
 | 
					 | 
				
			||||||
            #else
 | 
					 | 
				
			||||||
            /* StandardError is gone in 3.0 */
 | 
					 | 
				
			||||||
            base = NULL;
 | 
					 | 
				
			||||||
            #endif
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            base = *exctable[i].base;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!(*exctable[i].exc = PyErr_NewException(
 | 
					        if (!(*exctable[i].exc = PyErr_NewException(
 | 
				
			||||||
                exctable[i].name, base, dict))) {
 | 
					                exctable[i].name, *exctable[i].base, dict))) {
 | 
				
			||||||
            goto exit;
 | 
					            goto exit;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Py_CLEAR(dict);
 | 
					        Py_CLEAR(dict);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Make pgerror, pgcode and cursor default to None on psycopg
 | 
					 | 
				
			||||||
       error objects.  This simplifies error handling code that checks
 | 
					 | 
				
			||||||
       these attributes. */
 | 
					 | 
				
			||||||
    PyObject_SetAttrString(Error, "pgerror", Py_None);
 | 
					 | 
				
			||||||
    PyObject_SetAttrString(Error, "pgcode", Py_None);
 | 
					 | 
				
			||||||
    PyObject_SetAttrString(Error, "cursor", Py_None);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!(diag_property = PyObject_CallFunctionObjArgs(
 | 
					 | 
				
			||||||
            (PyObject *) &PyProperty_Type, &diagnosticsType, NULL))) {
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    PyObject_SetAttrString(Error, "diag", diag_property);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* install __reduce_ex__ on Error to make all the subclasses picklable.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * Don't install it on Py 2.4: it is not used by the pickle
 | 
					 | 
				
			||||||
     * protocol, and if called manually fails in an unsettling way,
 | 
					 | 
				
			||||||
     * probably because the exceptions were old-style classes. */
 | 
					 | 
				
			||||||
#if PY_VERSION_HEX >= 0x02050000
 | 
					 | 
				
			||||||
    if (!(descr = PyDescr_NewMethod((PyTypeObject *)Error,
 | 
					 | 
				
			||||||
            &psyco_error_reduce_ex_def))) {
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (0 != PyObject_SetAttrString(Error,
 | 
					 | 
				
			||||||
            psyco_error_reduce_ex_def.ml_name, descr)) {
 | 
					 | 
				
			||||||
        goto exit;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rv = 0;
 | 
					    rv = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
    Py_XDECREF(diag_property);
 | 
					 | 
				
			||||||
    Py_XDECREF(descr);
 | 
					 | 
				
			||||||
    Py_XDECREF(str);
 | 
					    Py_XDECREF(str);
 | 
				
			||||||
    Py_XDECREF(dict);
 | 
					    Py_XDECREF(dict);
 | 
				
			||||||
    return rv;
 | 
					    return rv;
 | 
				
			||||||
| 
						 | 
					@ -613,11 +512,10 @@ psyco_errors_set(PyObject *type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Create a new error of the given type with extra attributes. */
 | 
					   Create a new error of the given type with extra attributes. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RAISES void
 | 
					/* TODO: may have been changed to BORROWED */
 | 
				
			||||||
psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
 | 
					RAISES PyObject *
 | 
				
			||||||
                const char *pgerror, const char *pgcode)
 | 
					psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PyObject *t;
 | 
					 | 
				
			||||||
    PyObject *pymsg;
 | 
					    PyObject *pymsg;
 | 
				
			||||||
    PyObject *err = NULL;
 | 
					    PyObject *err = NULL;
 | 
				
			||||||
    connectionObject *conn = NULL;
 | 
					    connectionObject *conn = NULL;
 | 
				
			||||||
| 
						 | 
					@ -633,31 +531,24 @@ psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        /* what's better than an error in an error handler in the morning?
 | 
					        /* what's better than an error in an error handler in the morning?
 | 
				
			||||||
         * Anyway, some error was set, refcount is ok... get outta here. */
 | 
					         * Anyway, some error was set, refcount is ok... get outta here. */
 | 
				
			||||||
        return;
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err && PyObject_TypeCheck(err, &errorType)) {
 | 
				
			||||||
 | 
					        errorObject *perr = (errorObject *)err;
 | 
				
			||||||
 | 
					        if (curs) {
 | 
				
			||||||
 | 
					            Py_CLEAR(perr->cursor);
 | 
				
			||||||
 | 
					            Py_INCREF(curs);
 | 
				
			||||||
 | 
					            perr->cursor = curs;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (err) {
 | 
					    if (err) {
 | 
				
			||||||
        if (curs) {
 | 
					 | 
				
			||||||
            PyObject_SetAttrString(err, "cursor", (PyObject *)curs);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (pgerror) {
 | 
					 | 
				
			||||||
            if ((t = conn_text_from_chars(conn, pgerror))) {
 | 
					 | 
				
			||||||
                PyObject_SetAttrString(err, "pgerror", t);
 | 
					 | 
				
			||||||
                Py_DECREF(t);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (pgcode) {
 | 
					 | 
				
			||||||
            if ((t = conn_text_from_chars(conn, pgcode))) {
 | 
					 | 
				
			||||||
                PyObject_SetAttrString(err, "pgcode", t);
 | 
					 | 
				
			||||||
                Py_DECREF(t);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PyErr_SetObject(exc, err);
 | 
					        PyErr_SetObject(exc, err);
 | 
				
			||||||
        Py_DECREF(err);
 | 
					        Py_DECREF(err);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -891,6 +782,7 @@ INIT_MODULE(_psycopg)(void)
 | 
				
			||||||
    Py_TYPE(&chunkType)      = &PyType_Type;
 | 
					    Py_TYPE(&chunkType)      = &PyType_Type;
 | 
				
			||||||
    Py_TYPE(&NotifyType)     = &PyType_Type;
 | 
					    Py_TYPE(&NotifyType)     = &PyType_Type;
 | 
				
			||||||
    Py_TYPE(&XidType)        = &PyType_Type;
 | 
					    Py_TYPE(&XidType)        = &PyType_Type;
 | 
				
			||||||
 | 
					    Py_TYPE(&errorType)      = &PyType_Type;
 | 
				
			||||||
    Py_TYPE(&diagnosticsType) = &PyType_Type;
 | 
					    Py_TYPE(&diagnosticsType) = &PyType_Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (PyType_Ready(&connectionType) == -1) goto exit;
 | 
					    if (PyType_Ready(&connectionType) == -1) goto exit;
 | 
				
			||||||
| 
						 | 
					@ -908,6 +800,8 @@ INIT_MODULE(_psycopg)(void)
 | 
				
			||||||
    if (PyType_Ready(&chunkType) == -1) goto exit;
 | 
					    if (PyType_Ready(&chunkType) == -1) goto exit;
 | 
				
			||||||
    if (PyType_Ready(&NotifyType) == -1) goto exit;
 | 
					    if (PyType_Ready(&NotifyType) == -1) goto exit;
 | 
				
			||||||
    if (PyType_Ready(&XidType) == -1) goto exit;
 | 
					    if (PyType_Ready(&XidType) == -1) goto exit;
 | 
				
			||||||
 | 
					    errorType.tp_base = (PyTypeObject *)PyExc_StandardError;
 | 
				
			||||||
 | 
					    if (PyType_Ready(&errorType) == -1) goto exit;
 | 
				
			||||||
    if (PyType_Ready(&diagnosticsType) == -1) goto exit;
 | 
					    if (PyType_Ready(&diagnosticsType) == -1) goto exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef PSYCOPG_EXTENSIONS
 | 
					#ifdef PSYCOPG_EXTENSIONS
 | 
				
			||||||
| 
						 | 
					@ -1043,6 +937,7 @@ INIT_MODULE(_psycopg)(void)
 | 
				
			||||||
    pydatetimeType.tp_alloc = PyType_GenericAlloc;
 | 
					    pydatetimeType.tp_alloc = PyType_GenericAlloc;
 | 
				
			||||||
    NotifyType.tp_alloc = PyType_GenericAlloc;
 | 
					    NotifyType.tp_alloc = PyType_GenericAlloc;
 | 
				
			||||||
    XidType.tp_alloc = PyType_GenericAlloc;
 | 
					    XidType.tp_alloc = PyType_GenericAlloc;
 | 
				
			||||||
 | 
					    errorType.tp_alloc = PyType_GenericAlloc;
 | 
				
			||||||
    diagnosticsType.tp_alloc = PyType_GenericAlloc;
 | 
					    diagnosticsType.tp_alloc = PyType_GenericAlloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef PSYCOPG_EXTENSIONS
 | 
					#ifdef PSYCOPG_EXTENSIONS
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -114,6 +114,7 @@ typedef unsigned long Py_uhash_t;
 | 
				
			||||||
#define PyInt_AsLong           PyLong_AsLong
 | 
					#define PyInt_AsLong           PyLong_AsLong
 | 
				
			||||||
#define PyInt_FromLong         PyLong_FromLong
 | 
					#define PyInt_FromLong         PyLong_FromLong
 | 
				
			||||||
#define PyInt_FromSsize_t      PyLong_FromSsize_t
 | 
					#define PyInt_FromSsize_t      PyLong_FromSsize_t
 | 
				
			||||||
 | 
					#define PyExc_StandardError    PyExc_Exception
 | 
				
			||||||
#define PyString_FromFormat    PyUnicode_FromFormat
 | 
					#define PyString_FromFormat    PyUnicode_FromFormat
 | 
				
			||||||
#define Py_TPFLAGS_HAVE_ITER   0L
 | 
					#define Py_TPFLAGS_HAVE_ITER   0L
 | 
				
			||||||
#define Py_TPFLAGS_HAVE_RICHCOMPARE 0L
 | 
					#define Py_TPFLAGS_HAVE_RICHCOMPARE 0L
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,10 +115,16 @@ psycopg_escape_identifier_easy(const char *from, Py_ssize_t len)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Store the return in 'to' and return 0 in case of success, else return -1
 | 
					 * Store the return in 'to' and return 0 in case of success, else return -1
 | 
				
			||||||
 * and raise an exception.
 | 
					 * and raise an exception.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If from is null, store null into to.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
RAISES_NEG int
 | 
					RAISES_NEG int
 | 
				
			||||||
psycopg_strdup(char **to, const char *from, Py_ssize_t len)
 | 
					psycopg_strdup(char **to, const char *from, Py_ssize_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    if (!from) {
 | 
				
			||||||
 | 
					        *to = NULL;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (!len) { len = strlen(from); }
 | 
					    if (!len) { len = strlen(from); }
 | 
				
			||||||
    if (!(*to = PyMem_Malloc(len + 1))) {
 | 
					    if (!(*to = PyMem_Malloc(len + 1))) {
 | 
				
			||||||
        PyErr_NoMemory();
 | 
					        PyErr_NoMemory();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								setup.py
									
									
									
									
									
								
							| 
						 | 
					@ -428,7 +428,7 @@ sources = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'connection_int.c', 'connection_type.c',
 | 
					    'connection_int.c', 'connection_type.c',
 | 
				
			||||||
    'cursor_int.c', 'cursor_type.c',
 | 
					    'cursor_int.c', 'cursor_type.c',
 | 
				
			||||||
    'diagnostics_type.c',
 | 
					    'diagnostics_type.c', 'error_type.c',
 | 
				
			||||||
    'lobject_int.c', 'lobject_type.c',
 | 
					    'lobject_int.c', 'lobject_type.c',
 | 
				
			||||||
    'notify_type.c', 'xid_type.c',
 | 
					    'notify_type.c', 'xid_type.c',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -441,8 +441,8 @@ sources = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
depends = [
 | 
					depends = [
 | 
				
			||||||
    # headers
 | 
					    # headers
 | 
				
			||||||
    'config.h', 'pgtypes.h', 'psycopg.h', 'python.h',
 | 
					    'config.h', 'pgtypes.h', 'psycopg.h', 'python.h', 'connection.h',
 | 
				
			||||||
    'connection.h', 'cursor.h', 'diagnostics.h', 'green.h', 'lobject.h',
 | 
					    'cursor.h', 'diagnostics.h', 'error.h', 'green.h', 'lobject.h',
 | 
				
			||||||
    'notify.h', 'pqpath.h', 'xid.h',
 | 
					    'notify.h', 'pqpath.h', 'xid.h',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    'adapter_asis.h', 'adapter_binary.h', 'adapter_datetime.h',
 | 
					    'adapter_asis.h', 'adapter_binary.h', 'adapter_datetime.h',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -222,6 +222,38 @@ class ExceptionsTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(diag.sqlstate, '42P01')
 | 
					        self.assertEqual(diag.sqlstate, '42P01')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_diagnostics_independent(self):
 | 
				
			||||||
 | 
					        cur = self.conn.cursor()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            cur.execute("l'acqua e' poca e 'a papera nun galleggia")
 | 
				
			||||||
 | 
					        except Exception, exc:
 | 
				
			||||||
 | 
					            diag1 = exc.diag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.conn.rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            cur.execute("select level from water where ducks > 1")
 | 
				
			||||||
 | 
					        except psycopg2.Error, exc:
 | 
				
			||||||
 | 
					            diag2 = exc.diag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(diag1.sqlstate, '42601')
 | 
				
			||||||
 | 
					        self.assertEqual(diag2.sqlstate, '42P01')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_diagnostics_from_commit(self):
 | 
				
			||||||
 | 
					        cur = self.conn.cursor()
 | 
				
			||||||
 | 
					        cur.execute("""
 | 
				
			||||||
 | 
					            create temp table test_deferred (
 | 
				
			||||||
 | 
					               data int primary key,
 | 
				
			||||||
 | 
					               ref int references test_deferred (data)
 | 
				
			||||||
 | 
					                   deferrable initially deferred)
 | 
				
			||||||
 | 
					        """)
 | 
				
			||||||
 | 
					        cur.execute("insert into test_deferred values (1,2)")
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.conn.commit()
 | 
				
			||||||
 | 
					        except psycopg2.Error, exc:
 | 
				
			||||||
 | 
					            e = exc
 | 
				
			||||||
 | 
					        self.assertEqual(e.diag.sqlstate, '23503')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @skip_before_postgres(9, 3)
 | 
					    @skip_before_postgres(9, 3)
 | 
				
			||||||
    def test_9_3_diagnostics(self):
 | 
					    def test_9_3_diagnostics(self):
 | 
				
			||||||
        cur = self.conn.cursor()
 | 
					        cur = self.conn.cursor()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user