mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-26 10:53:44 +03:00
Merge from 2_0_x branch up to r814.
This commit is contained in:
parent
39249e4741
commit
64933f2004
111
ChangeLog
111
ChangeLog
|
@ -1,5 +1,116 @@
|
|||
2006-09-01 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* Release 2.0.5.
|
||||
|
||||
* Fixed patch from #119, see tracker for details.
|
||||
|
||||
* Preparing release 2.0.5.
|
||||
|
||||
* psycopg/psycopgmodule.c: fixed filling of connection errors
|
||||
to include OperationalError.
|
||||
|
||||
* setup.py: removed pydatetime option from initialize_options
|
||||
to make sure that the value in setup.cfg is used.
|
||||
|
||||
* psycopg/psycopgmodule.c: applied patch from jdahlin (#120)
|
||||
to have .connect() accept either a string or int as the port
|
||||
parameter.
|
||||
|
||||
* psycopg/adapter_binary.c: applied patch from jdahlin (#119)
|
||||
to fix the segfault on empty binary buffers.
|
||||
|
||||
* psycopg/connection_type.c: added .status attribute to expose
|
||||
the internal status.
|
||||
|
||||
* psycopg/pqpath.c: applied patch from intgr (#117) to fix
|
||||
segfault on null queries.
|
||||
|
||||
* psycopg/cursor_type.c: applied patch from intgr (#116) to
|
||||
fix bad keyword naming and segfault in .executemany().
|
||||
|
||||
* ZPsycopgDA/DA.py: applied ImageFile patch from Charlie
|
||||
Clark.
|
||||
|
||||
* lib/pool.py: applied logging patch from Charlie Clark.
|
||||
It will probably get a makeup and be moved to the top-level
|
||||
module later.
|
||||
|
||||
2006-08-02 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* Release 2.0.4.
|
||||
|
||||
* Fixed bug in float conversion (check for NULL string was
|
||||
erroneously removed in 2.0.3!)
|
||||
|
||||
2006-07-31 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* Release 2.0.3.
|
||||
|
||||
* psycopg/cursor_type.c: applied patch from jbellis (#113) to
|
||||
allow column selection in .copy_from().
|
||||
|
||||
* psycopg/psycopgmodule.c: fixed memory leak in custom exceptions
|
||||
(applied patch from #114).
|
||||
|
||||
2006-07-26 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* psycopg/adapter_datetime.c (pydatetime_str): fixed error
|
||||
in conversion of microseconds for intervals and better algo
|
||||
(thanks to Mario Frasca.)
|
||||
|
||||
2006-06-18 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* psycopg/adapter_binary.c: same as below.
|
||||
|
||||
* psycopg/adapter_qstring.c: does not segfault anymore if
|
||||
.getquoted() is called without preparing the qstring with
|
||||
the connection.
|
||||
|
||||
2006-06-15 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* psycopg/typecast_basic.c: fixed problem with bogus
|
||||
conversion when importing gtk (that was crazy, I didn't
|
||||
understand why it happened but the new code just fixes it.)
|
||||
|
||||
* ZPsycopgDA/db.py: better type analisys, using an hash
|
||||
instead of a series of if (variation on patch from Charlie
|
||||
Clark.)
|
||||
|
||||
2006-06-11 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* Release 2.0.2.
|
||||
|
||||
* psycopg/typecast_array.c (typecast_array_cleanup): fixed a
|
||||
problem with typecast_array_cleanup always returning the new
|
||||
string length shorter by 1 (Closes: #93).
|
||||
|
||||
* psycopg/adapter_binary.c: as below.
|
||||
|
||||
* psycopg/adapter_qstring.c: wrapped #warning in #ifdef __GCC__
|
||||
because other compilers don't have it and it will just break
|
||||
compilation (patch from jason, our great win32 builder).
|
||||
|
||||
* psycopg/adapter_list.c: applied patch to adapt an empty list
|
||||
into an empty array and not to NULL (from iGGy, closes: #108).
|
||||
|
||||
* psycopg/cursor_type.c: applied patch from wkv to avoid
|
||||
under-allocating query space when the parameters are not of the
|
||||
right type (Closes: #110).
|
||||
|
||||
* psycopg/connection_int.c: applied patch from wkv to avoid off
|
||||
by one allocation of connection encoding string (Closes: #109).
|
||||
|
||||
2006-06-09 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* Release 2.0.1.
|
||||
|
||||
* Fixed some buglets in ZPsycopgDA (was unable to load due
|
||||
to shorter version number in psycopg module.)
|
||||
|
||||
2006-06-08 Federico Di Gregorio <fog@initd.org>
|
||||
|
||||
* Release 2.0.
|
||||
|
||||
* ZPsycopgDA/DA.py: removed Browse table for 2.0 release; we'll
|
||||
add it back later.
|
||||
|
||||
|
|
26
NEWS
26
NEWS
|
@ -1,3 +1,29 @@
|
|||
What's new in psycopg 2.0.4
|
||||
---------------------------
|
||||
|
||||
* Fixed float conversion bug introduced in 2.0.3.
|
||||
|
||||
What's new in psycopg 2.0.3
|
||||
---------------------------
|
||||
|
||||
* Fixed various buglets and a memory leak (see ChangeLog for details)
|
||||
|
||||
What's new in psycopg 2.0.2
|
||||
---------------------------
|
||||
|
||||
* Fixed a bug in array typecasting that sometimes made psycopg forget about
|
||||
the last element in the array.
|
||||
|
||||
* Fixed some minor buglets in string memory allocations.
|
||||
|
||||
* Builds again with compilers different from gcc (#warning about PostgreSQL
|
||||
version is issued only if __GCC__ is defined.)
|
||||
|
||||
What's new in psycopg 2.0.1
|
||||
---------------------------
|
||||
|
||||
* ZPsycopgDA now actually loads.
|
||||
|
||||
What's new in psycopg 2.0
|
||||
-------------------------
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# See the LICENSE file for details.
|
||||
|
||||
|
||||
ALLOWED_PSYCOPG_VERSIONS = ('2.0',)
|
||||
ALLOWED_PSYCOPG_VERSIONS = ('2.0.1', '2.0.2', '2.0.3', '2.0.4', '2.0.5')
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
@ -30,11 +30,21 @@ import Shared.DC.ZRDB.Connection
|
|||
|
||||
from db import DB
|
||||
from Globals import HTMLFile
|
||||
from ImageFile import ImageFile
|
||||
from ExtensionClass import Base
|
||||
from App.Dialogs import MessageDialog
|
||||
from DateTime import DateTime
|
||||
|
||||
# Build Zope version in a float for later cheks
|
||||
import App
|
||||
zope_version = App.version_txt.getZopeVersion()
|
||||
zope_version = float("%s.%s" %(zope_version[:2]))
|
||||
|
||||
# ImageFile is deprecated in Zope >= 2.9
|
||||
if zope_version < 2.9:
|
||||
from ImageFile import ImageFile
|
||||
else:
|
||||
from App.ImageFile import ImageFile
|
||||
|
||||
# import psycopg and functions/singletons needed for date/time conversions
|
||||
|
||||
import psycopg2
|
||||
|
|
|
@ -26,7 +26,7 @@ import site
|
|||
import pool
|
||||
|
||||
import psycopg2
|
||||
from psycopg2.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN, DATE
|
||||
from psycopg2.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN, DATE, TIME
|
||||
from psycopg2 import NUMBER, STRING, ROWID, DATETIME
|
||||
|
||||
|
||||
|
@ -42,6 +42,7 @@ class DB(TM, dbi_db.DB):
|
|||
self.encoding = enc
|
||||
self.failures = 0
|
||||
self.calls = 0
|
||||
self.make_mappings()
|
||||
|
||||
def getconn(self, create=True):
|
||||
conn = pool.getconn(self.dsn)
|
||||
|
@ -89,32 +90,23 @@ class DB(TM, dbi_db.DB):
|
|||
def sortKey(self):
|
||||
return 1
|
||||
|
||||
def make_mappings(self):
|
||||
"""Generate the mappings used later by self.convert_description()."""
|
||||
self.type_mappings = {}
|
||||
for t, s in [(INTEGER,'i'), (LONGINTEGER, 'i'), (NUMBER, 'n'),
|
||||
(BOOLEAN,'n'), (ROWID, 'i'),
|
||||
(DATETIME, 'd'), (DATE, 'd'), (TIME, 'd')]:
|
||||
for v in t.values:
|
||||
self.type_mappings[v] = (t, s)
|
||||
|
||||
def convert_description(self, desc, use_psycopg_types=False):
|
||||
"""Convert DBAPI-2.0 description field to Zope format."""
|
||||
items = []
|
||||
for name, typ, width, ds, p, scale, null_ok in desc:
|
||||
if typ == NUMBER:
|
||||
if typ == INTEGER or typ == LONGINTEGER:
|
||||
typs = 'i'
|
||||
else:
|
||||
typs = 'n'
|
||||
typp = NUMBER
|
||||
elif typ == BOOLEAN:
|
||||
typs = 'n'
|
||||
typp = BOOLEAN
|
||||
elif typ == ROWID:
|
||||
typs = 'i'
|
||||
typp = ROWID
|
||||
# FIXME: shouldn't DATETIME include other types?
|
||||
elif typ == DATETIME or typ == DATE or typ == TIME:
|
||||
typs = 'd'
|
||||
typp = DATETIME
|
||||
else:
|
||||
typs = 's'
|
||||
typp = STRING
|
||||
m = self.type_mappings.get(typ, (STRING, 's'))
|
||||
items.append({
|
||||
'name': name,
|
||||
'type': use_psycopg_types and typp or typs,
|
||||
'type': use_psycopg_types and m[0] or m[1],
|
||||
'width': width,
|
||||
'precision': p,
|
||||
'scale': scale,
|
||||
|
|
|
@ -51,6 +51,16 @@ ISOLATION_LEVEL_SERIALIZABLE = 2
|
|||
ISOLATION_LEVEL_REPEATABLE_READ = ISOLATION_LEVEL_SERIALIZABLE
|
||||
ISOLATION_LEVEL_READ_UNCOMMITTED = ISOLATION_LEVEL_READ_COMMITTED
|
||||
|
||||
"""Transaction status values."""
|
||||
STATUS_SETUP = 0
|
||||
STATUS_READY = 1
|
||||
STATUS_BEGIN = 2
|
||||
STATUS_SYNC = 3
|
||||
STATUS_ASYNC = 4
|
||||
|
||||
# This is a usefull mnemonic to check if the connection is in a transaction
|
||||
STATUS_IN_TRANSACTION = STATUS_BEGIN
|
||||
|
||||
|
||||
def register_adapter(typ, callable):
|
||||
"""Register 'callable' as an ISQLQuote adapter for type 'typ'."""
|
||||
|
|
16
lib/pool.py
16
lib/pool.py
|
@ -19,11 +19,27 @@ This module implements thread-safe (and not) connection pools.
|
|||
import psycopg2
|
||||
|
||||
try:
|
||||
import logging
|
||||
# do basic initialization if the module is not already initialized
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format='%(asctime)s %(levelname)s %(message)s')
|
||||
# create logger object for psycopg2 module and sub-modules
|
||||
_logger = logging.getLogger("psycopg2")
|
||||
def dbg(*args):
|
||||
_logger.debug("psycopg2", ' '.join([str(x) for x in args]))
|
||||
try:
|
||||
import App # does this make sure that we're running in Zope?
|
||||
_logger.info("installed. Logging using Python logging module")
|
||||
except:
|
||||
_logger.debug("installed. Logging using Python logging module")
|
||||
|
||||
except ImportError:
|
||||
from zLOG import LOG, DEBUG, INFO
|
||||
def dbg(*args):
|
||||
LOG('ZPsycopgDA', DEBUG, "",
|
||||
' '.join([str(x) for x in args])+'\n')
|
||||
LOG('ZPsycopgDA', INFO, "Installed", "Logging using Zope's zLOG\n")
|
||||
|
||||
except:
|
||||
import sys
|
||||
def dbg(*args):
|
||||
|
|
|
@ -44,11 +44,11 @@ binary_escape(unsigned char *from, unsigned int from_length,
|
|||
#if PG_MAJOR_VERSION > 8 || \
|
||||
(PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION > 1) || \
|
||||
(PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION == 1 && PG_PATCH_VERSION >= 4)
|
||||
if (conn)
|
||||
return PQescapeByteaConn(conn, from, from_length, to_length);
|
||||
#else
|
||||
#warning "YOUR POSTGRESQL VERSION IS TOO OLD AND IT CAN BE INSECURE"
|
||||
return PQescapeBytea(from, from_length, to_length);
|
||||
else
|
||||
#endif
|
||||
return PQescapeBytea(from, from_length, to_length);
|
||||
}
|
||||
#else
|
||||
static unsigned char *
|
||||
|
@ -141,14 +141,18 @@ binary_quote(binaryObject *self)
|
|||
if (PyString_Check(self->wrapped) || PyBuffer_Check(self->wrapped)) {
|
||||
/* escape and build quoted buffer */
|
||||
PyObject_AsCharBuffer(self->wrapped, &buffer, &buffer_len);
|
||||
|
||||
to = (char *)binary_escape((unsigned char*)buffer, buffer_len, &len,
|
||||
((connectionObject*)self->conn)->pgconn);
|
||||
self->conn ? ((connectionObject*)self->conn)->pgconn : NULL);
|
||||
if (to == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
self->buffer = PyString_FromFormat("'%s'", to);
|
||||
else
|
||||
self->buffer = PyString_FromString("''");
|
||||
PQfreemem(to);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,15 +64,14 @@ pydatetime_str(pydatetimeObject *self)
|
|||
PyDateTime_Delta *obj = (PyDateTime_Delta*)self->wrapped;
|
||||
|
||||
char buffer[8];
|
||||
int i, j, x;
|
||||
int i;
|
||||
int a = obj->microseconds;
|
||||
|
||||
for (i=1000000, j=0; i > 0 ; i /= 10) {
|
||||
x = a/i;
|
||||
a -= x*i;
|
||||
buffer[j++] = '0'+x;
|
||||
for (i=0; i < 6 ; i++) {
|
||||
buffer[5-i] = '0' + (a % 10);
|
||||
a /= 10;
|
||||
}
|
||||
buffer[j] = '\0';
|
||||
buffer[6] = '\0';
|
||||
|
||||
return PyString_FromFormat("'%d days %d.%s seconds'",
|
||||
obj->days, obj->seconds, buffer);
|
||||
|
|
|
@ -46,7 +46,7 @@ list_quote(listObject *self)
|
|||
|
||||
/* empty arrays are converted to NULLs (still searching for a way to
|
||||
insert an empty array in postgresql */
|
||||
if (len == 0) return PyString_FromString("NULL");
|
||||
if (len == 0) return PyString_FromString("'{}'");
|
||||
|
||||
tmp = PyTuple_New(len);
|
||||
|
||||
|
|
|
@ -45,11 +45,11 @@ qstring_escape(char *to, char *from, size_t len, PGconn *conn)
|
|||
(PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION > 1) || \
|
||||
(PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION == 1 && PG_PATCH_VERSION >= 4)
|
||||
int err;
|
||||
if (conn)
|
||||
return PQescapeStringConn(conn, to, from, len, &err);
|
||||
#else
|
||||
#warning "YOUR POSTGRESQL VERSION IS TOO OLD AND IT CAN BE INSECURE"
|
||||
return PQescapeString(to, from, len);
|
||||
else
|
||||
#endif
|
||||
return PQescapeString(to, from, len);
|
||||
}
|
||||
#else
|
||||
static size_t
|
||||
|
@ -147,7 +147,7 @@ qstring_quote(qstringObject *self)
|
|||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
len = qstring_escape(buffer+1, s, len,
|
||||
((connectionObject*)self->conn)->pgconn);
|
||||
self->conn ? ((connectionObject*)self->conn)->pgconn : NULL);
|
||||
buffer[0] = '\'' ; buffer[len+1] = '\'';
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ conn_connect(connectionObject *self)
|
|||
return -1;
|
||||
}
|
||||
tmp = PQgetvalue(pgres, 0, 0);
|
||||
self->encoding = PyMem_Malloc(strlen(tmp));
|
||||
self->encoding = PyMem_Malloc(strlen(tmp)+1);
|
||||
if (self->encoding == NULL) {
|
||||
/* exception already set by PyMem_Malloc() */
|
||||
PQfinish(pgconn);
|
||||
|
|
|
@ -260,6 +260,9 @@ static struct PyMemberDef connectionObject_members[] = {
|
|||
{"notifies", T_OBJECT, offsetof(connectionObject, notifies), RO},
|
||||
{"dsn", T_STRING, offsetof(connectionObject, dsn), RO,
|
||||
"The current connection string."},
|
||||
{"status", T_LONG,
|
||||
offsetof(connectionObject, status), RO,
|
||||
"The current transaction status."},
|
||||
#endif
|
||||
{NULL}
|
||||
};
|
||||
|
|
|
@ -434,7 +434,7 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
|
|||
}
|
||||
|
||||
#define psyco_curs_executemany_doc \
|
||||
"executemany(query, vars_list=(), async=0) -- Execute many queries with bound vars."
|
||||
"executemany(query, vars_list) -- Execute many queries with bound vars."
|
||||
|
||||
static PyObject *
|
||||
psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||
|
@ -442,9 +442,9 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
|
|||
PyObject *operation = NULL, *vars = NULL;
|
||||
PyObject *v, *iter = NULL;
|
||||
|
||||
static char *kwlist[] = {"query", "vars", NULL};
|
||||
static char *kwlist[] = {"query", "vars_list", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist,
|
||||
&operation, &vars)) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -891,6 +891,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
|
|||
|
||||
if(parameters && parameters != Py_None) {
|
||||
nparameters = PyObject_Length(parameters);
|
||||
if (nparameters < 0) nparameters = 0;
|
||||
}
|
||||
|
||||
/* allocate some memory, build the SQL and create a PyString from it */
|
||||
|
@ -1047,7 +1048,7 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
|
|||
/* extension: copy_from - implements COPY FROM */
|
||||
|
||||
#define psyco_curs_copy_from_doc \
|
||||
"copy_from(file, table, sep='\\t', null='\\N') -- Copy table from file."
|
||||
"copy_from(file, table, sep='\\t', null='\\N', columns=None) -- Copy table from file."
|
||||
|
||||
static int
|
||||
_psyco_curs_has_read_check(PyObject* o, void* var)
|
||||
|
@ -1068,29 +1069,76 @@ _psyco_curs_has_read_check(PyObject* o, void* var)
|
|||
static PyObject *
|
||||
psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
char query[256];
|
||||
char query[1024];
|
||||
char *table_name;
|
||||
char *sep = "\t", *null = NULL;
|
||||
long int bufsize = DEFAULT_COPYSIZE;
|
||||
PyObject *file, *columns, *res = NULL;
|
||||
PyObject *file, *columns = NULL, *res = NULL;
|
||||
char columnlist[1024] = "";
|
||||
|
||||
static char *kwlist[] = {"file", "table", "sep", "null", "size", NULL};
|
||||
static char *kwlist[] = {"file", "table", "sep", "null", "size",
|
||||
"columns", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ssi", kwlist,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ssiO", kwlist,
|
||||
_psyco_curs_has_read_check, &file,
|
||||
&table_name, &sep, &null, &bufsize)) {
|
||||
&table_name, &sep, &null, &bufsize,
|
||||
&columns)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (columns != NULL && columns != Py_None) {
|
||||
PyObject* collistiter = PyObject_GetIter(columns);
|
||||
if (collistiter == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject* col;
|
||||
int collistlen = 2;
|
||||
int colitemlen;
|
||||
char* colname;
|
||||
strcpy(columnlist, " (");
|
||||
while ((col = PyIter_Next(collistiter)) != NULL) {
|
||||
if (!PyString_Check(col)) {
|
||||
Py_DECREF(col);
|
||||
Py_DECREF(collistiter);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Elements in column list must be strings");
|
||||
return NULL;
|
||||
}
|
||||
PyString_AsStringAndSize(col, &colname, &colitemlen);
|
||||
if (collistlen + colitemlen > 1022) {
|
||||
Py_DECREF(col);
|
||||
Py_DECREF(collistiter);
|
||||
PyErr_SetString(PyExc_ValueError, "Column list too long");
|
||||
return NULL;
|
||||
}
|
||||
strncpy(&columnlist[collistlen], colname, colitemlen);
|
||||
collistlen += colitemlen;
|
||||
columnlist[collistlen++] = ',';
|
||||
Py_DECREF(col);
|
||||
}
|
||||
Py_DECREF(collistiter);
|
||||
|
||||
if (collistlen == 2) { /* empty list; we printed no comma */
|
||||
collistlen++;
|
||||
}
|
||||
|
||||
columnlist[collistlen - 1] = ')';
|
||||
columnlist[collistlen] = '\0';
|
||||
}
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXC_IF_CURS_CLOSED(self);
|
||||
|
||||
if (null) {
|
||||
PyOS_snprintf(query, 255, "COPY %s FROM stdin USING DELIMITERS '%s'"
|
||||
" WITH NULL AS '%s'", table_name, sep, null);
|
||||
PyOS_snprintf(query, 1023, "COPY %s%s FROM stdin USING DELIMITERS '%s'"
|
||||
" WITH NULL AS '%s'", table_name, columnlist, sep, null);
|
||||
}
|
||||
else {
|
||||
PyOS_snprintf(query, 255, "COPY %s FROM stdin USING DELIMITERS '%s'",
|
||||
table_name, sep);
|
||||
PyOS_snprintf(query, 1023, "COPY %s%s FROM stdin USING DELIMITERS '%s'",
|
||||
table_name, columnlist, sep);
|
||||
}
|
||||
Dprintf("psyco_curs_copy_from: query = %s", query);
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg)
|
|||
#ifdef HAVE_PQPROTOCOL3
|
||||
char *pgstate =
|
||||
PQresultErrorField(curs->pgres, PG_DIAG_SQLSTATE);
|
||||
if (!strncmp(pgstate, "23", 2))
|
||||
if (pgstate != NULL && !strncmp(pgstate, "23", 2))
|
||||
exc = IntegrityError;
|
||||
else
|
||||
exc = ProgrammingError;
|
||||
|
|
|
@ -118,12 +118,15 @@ _psyco_connect_fill_exc(connectionObject *conn)
|
|||
Py_INCREF(DataError);
|
||||
conn->exc_NotSupportedError = NotSupportedError;
|
||||
Py_INCREF(NotSupportedError);
|
||||
conn->exc_OperationalError = OperationalError;
|
||||
Py_INCREF(OperationalError);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PyObject *conn, *factory = NULL;
|
||||
PyObject *pyport = NULL;
|
||||
|
||||
int idsn=-1, iport=-1;
|
||||
char *dsn=NULL, *database=NULL, *user=NULL, *password=NULL;
|
||||
|
@ -134,12 +137,25 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
|
|||
"user", "password", "sslmode",
|
||||
"connection_factory", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sssisssO", kwlist,
|
||||
&dsn, &database, &host, &iport,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sssOsssO", kwlist,
|
||||
&dsn, &database, &host, &pyport,
|
||||
&user, &password, &sslmode, &factory)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pyport && PyString_Check(pyport)) {
|
||||
PyObject *pyint = PyInt_FromString(PyString_AsString(pyport), NULL, 10);
|
||||
if (!pyint) return NULL;
|
||||
iport = PyInt_AsLong(pyint);
|
||||
}
|
||||
else if (pyport && PyInt_Check(pyport)) {
|
||||
iport = PyInt_AsLong(pyport);
|
||||
}
|
||||
else if (pyport != NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "port must be a string or int");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iport > 0)
|
||||
PyOS_snprintf(port, 16, "%d", iport);
|
||||
|
||||
|
@ -429,6 +445,7 @@ psyco_set_error(PyObject *exc, PyObject *curs, char *msg,
|
|||
PyObject_SetAttrString(err, "cursor", Py_None);
|
||||
|
||||
PyErr_SetObject(exc, err);
|
||||
Py_DECREF(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ typecast_array_cleanup(char **str, int *len)
|
|||
if ((*str)[i] != '=') return -1;
|
||||
|
||||
*str = &((*str)[i+1]);
|
||||
*len = *len - i - 2;
|
||||
*len = *len - i - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -218,6 +218,8 @@ typecast_GENERIC_ARRAY_cast(char *str, int len, PyObject *curs)
|
|||
PyObject *obj = NULL;
|
||||
PyObject *base = ((typecastObject*)((cursorObject*)curs)->caster)->bcast;
|
||||
|
||||
Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s', len = %d", str, len);
|
||||
|
||||
if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||
if (str[0] == '[')
|
||||
typecast_array_cleanup(&str, &len);
|
||||
|
@ -226,7 +228,7 @@ typecast_GENERIC_ARRAY_cast(char *str, int len, PyObject *curs)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
Dprintf("typecast_GENERIC_ARRAY_cast: scanning %s", str);
|
||||
Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s', len = %d", str, len);
|
||||
|
||||
obj = PyList_New(0);
|
||||
|
||||
|
|
|
@ -54,15 +54,14 @@ typecast_LONGINTEGER_cast(char *s, int len, PyObject *curs)
|
|||
static PyObject *
|
||||
typecast_FLOAT_cast(char *s, int len, PyObject *curs)
|
||||
{
|
||||
/* FIXME: is 64 large enough for any float? */
|
||||
char buffer[64];
|
||||
PyObject *str = NULL, *flo = NULL;
|
||||
char *pend;
|
||||
|
||||
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||
if (s[len] != '\0') {
|
||||
strncpy(buffer, s, len); buffer[len] = '\0';
|
||||
s = buffer;
|
||||
}
|
||||
return PyFloat_FromDouble(atof(s));
|
||||
str = PyString_FromStringAndSize(s, len);
|
||||
flo = PyFloat_FromString(str, &pend);
|
||||
Py_DECREF(str);
|
||||
return flo;
|
||||
}
|
||||
|
||||
/** STRING - cast strings of any type to python string **/
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
import psycopg
|
||||
import psycopg2
|
||||
|
||||
conn = psycopg.connect("dbname=test")
|
||||
conn = psycopg2.connect("dbname=test")
|
||||
curs = conn.cursor()
|
||||
|
||||
curs.execute("SELECT ARRAY[1,2,3] AS foo")
|
||||
print curs.fetchone()[0]
|
||||
#curs.execute("SELECT ARRAY[1,2,3] AS foo")
|
||||
#print curs.fetchone()[0]
|
||||
|
||||
curs.execute("SELECT ARRAY['1','2','3'] AS foo")
|
||||
print curs.fetchone()[0]
|
||||
#curs.execute("SELECT ARRAY['1','2','3'] AS foo")
|
||||
#print curs.fetchone()[0]
|
||||
|
||||
curs.execute("""SELECT ARRAY[',','"','\\\\'] AS foo""")
|
||||
d = curs.fetchone()[0]
|
||||
print d, '->', d[0], d[1], d[2]
|
||||
#curs.execute("""SELECT ARRAY[',','"','\\\\'] AS foo""")
|
||||
#d = curs.fetchone()[0]
|
||||
#print d, '->', d[0], d[1], d[2]
|
||||
|
||||
curs.execute("SELECT ARRAY[ARRAY[1,2],ARRAY[3,4]] AS foo")
|
||||
print curs.fetchone()[0]
|
||||
#curs.execute("SELECT ARRAY[ARRAY[1,2],ARRAY[3,4]] AS foo")
|
||||
#print curs.fetchone()[0]
|
||||
|
||||
#curs.execute("SELECT ARRAY[ARRAY[now(), now()], ARRAY[now(), now()]] AS foo")
|
||||
#print curs.description
|
||||
#print curs.fetchone()[0]
|
||||
|
||||
curs.execute("SELECT 1 AS foo, ARRAY[1,2] AS bar")
|
||||
print curs.fetchone()
|
||||
|
||||
curs.execute("SELECT * FROM test()")
|
||||
print curs.fetchone()
|
||||
|
||||
curs.execute("SELECT ARRAY[ARRAY[now(), now()], ARRAY[now(), now()]] AS foo")
|
||||
print curs.description
|
||||
print curs.fetchone()[0]
|
||||
|
|
19
sandbox/gtk.py
Normal file
19
sandbox/gtk.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
import psycopg2
|
||||
|
||||
o = psycopg2.connect("dbname=test")
|
||||
c = o.cursor()
|
||||
|
||||
def sql():
|
||||
c.execute("SELECT 1.23 AS foo")
|
||||
print 1, c.fetchone()
|
||||
#print c.description
|
||||
c.execute("SELECT 1.23::float AS foo")
|
||||
print 2, c.fetchone()
|
||||
#print c.description
|
||||
|
||||
print "BEFORE"
|
||||
sql()
|
||||
import gtk
|
||||
print "AFTER"
|
||||
sql()
|
||||
|
9
sandbox/textfloat.py
Normal file
9
sandbox/textfloat.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
import gtk
|
||||
import psycopg2
|
||||
|
||||
o = psycopg2.connect("dbname=test")
|
||||
c = o.cursor()
|
||||
c.execute("SELECT 1.23::float AS foo")
|
||||
x = c.fetchone()[0]
|
||||
print x, type(x)
|
||||
|
3
setup.py
3
setup.py
|
@ -52,7 +52,7 @@ from distutils.command.build_ext import build_ext
|
|||
from distutils.sysconfig import get_python_inc
|
||||
from distutils.ccompiler import get_default_compiler
|
||||
|
||||
PSYCOPG_VERSION = '2.0'
|
||||
PSYCOPG_VERSION = '2.0.5'
|
||||
version_flags = []
|
||||
|
||||
# to work around older distutil limitations
|
||||
|
@ -95,7 +95,6 @@ class psycopg_build_ext(build_ext):
|
|||
|
||||
def initialize_options(self):
|
||||
build_ext.initialize_options(self)
|
||||
self.use_pydatetime = 1
|
||||
self.use_pg_dll = 1
|
||||
self.pgdir = None
|
||||
self.pg_config = self.DEFAULT_PG_CONFIG
|
||||
|
|
|
@ -62,6 +62,9 @@ class TypesBasicTests(TestCase):
|
|||
b = psycopg2.Binary(s)
|
||||
r = str(self.execute("SELECT %s::bytea AS foo", (b,)))
|
||||
self.failUnless(r == s, "wrong binary quoting")
|
||||
# test to make sure an empty Binary is converted to an empty string
|
||||
b = psycopg2.Binary('')
|
||||
self.assertEqual(str(b), "''")
|
||||
|
||||
def testArray(self):
|
||||
s = self.execute("SELECT %s AS foo", ([[1,2],[3,4]],))
|
||||
|
|
Loading…
Reference in New Issue
Block a user