Various fixes, now all examples work.

This commit is contained in:
Federico Di Gregorio 2007-04-13 14:07:11 +00:00
parent 8274a032b1
commit d6e232e2b9
9 changed files with 110 additions and 82 deletions

View File

@ -1,5 +1,15 @@
2007-04-14 Federico Di Gregorio <fog@initd.org>
* psycopg/psycopg.h: fixed probable typo in definition of
CONV_CODE_PY_SSIZE_T: d -> i for Python < 2.5.
* Fixed some of the examples.
2007-04-13 Federico Di Gregorio <fog@initd.org>
* Applied slighly modified patch from daniel (#176). Made
buffer size a compile-time parameter.
* Applied patch from David Rushby: typecast_binary.c cleanup.
* Applied patch from David Rushby for int->size_t transition.

19
NEWS
View File

@ -1,22 +1,21 @@
What's new in psycopg 2.0.6
---------------------------
* Full support for PostgreSQL 8.2, including NULLs in arrays.
* Full support for Python 2.5 and 64 bit architectures.
* Support for almost all PostgreSQL encodings.
* Better management of times and dates both from Python and in Zope.
* Better support for PostgreSQL, Python and win32:
- full support for PostgreSQL 8.2, including NULLs in arrays
- support for almost all existing PostgreSQL encodings
- full list of PostgreSQL error codes available by importing the
psycopg2.errorcodes module
- full support for Python 2.5 and 64 bit architectures
- better build support on win32 platform
* Support for per-connection type-casters (used by ZPsycopgDA too, this
fixes a long standing bug that made different connections use a random
set of date/time type-casters instead of the configured one.)
* We now have a full list of PostgreSQL error codes available by
importing the psycopg2.errorcodes module.
* Better management of times and dates both from Python and in Zope.
* Better build support on win32 platform.
* copy_to and copy_from now take an extra "columns" parameter.
* Fixed some small buglets and build glitches:
- removed double mutex destroy

View File

@ -18,7 +18,7 @@
# See the LICENSE file for details.
ALLOWED_PSYCOPG_VERSIONS = ('2.0.5', '2.0.6b2', '2.0.6')
ALLOWED_PSYCOPG_VERSIONS = ('2.0.6',)
import sys
import time

View File

@ -45,8 +45,8 @@ conn.commit()
io = open('copy_from.txt', 'wr')
data = ['Tom\tJenkins\t37\n',
'Madonna\t\N\t45\n',
'Federico\tDi Gregorio\t\N\n']
'Madonna\t\\N\t45\n',
'Federico\tDi Gregorio\t\\N\n']
io.writelines(data)
io.close()

View File

@ -63,6 +63,7 @@ typedef struct {
PyObject *copyfile; /* file-like used during COPY TO/FROM ops */
Py_ssize_t copysize; /* size of the copy buffer during COPY TO/FROM ops */
#define DEFAULT_COPYSIZE 16384
#define DEFAULT_COPYBUFF 1024
PyObject *tuple_factory; /* factory for result tuples */
PyObject *tzinfo_factory; /* factory for tzinfo objects */

View File

@ -88,15 +88,6 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
c = PyString_AsString(fmt);
while(*c) {
/* check if some crazy guy mixed formats */
if (kind == 2) {
Py_XDECREF(n);
psyco_set_error(ProgrammingError, (PyObject*)conn,
"argument formats can't be mixed", NULL, NULL);
return -1;
}
kind = 1;
/* handle plain percent symbol in format string */
if (c[0] == '%' && c[1] == '%') {
c+=2; force = 1;
@ -109,6 +100,15 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
4/ ...and add it to the new dictionary to be used as argument
*/
else if (c[0] == '%' && c[1] == '(') {
/* check if some crazy guy mixed formats */
if (kind == 2) {
Py_XDECREF(n);
psyco_set_error(ProgrammingError, (PyObject*)conn,
"argument formats can't be mixed", NULL, NULL);
return -1;
}
kind = 1;
/* let's have d point the end of the argument */
for (d = c + 2; *d && *d != ')'; d++);
@ -1076,6 +1076,55 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
#ifdef PSYCOPG_EXTENSIONS
#define COPY_BUFFER_SIZE 1024
static int _psyco_curs_copy_columns(PyObject *columns, char *columnlist)
{
PyObject *col, *coliter;
Py_ssize_t collen;
char* colname;
int offset = 1;
columnlist[0] = '\0';
if (columns == NULL || columns == Py_None) return 0;
coliter = PyObject_GetIter(columns);
if (coliter == NULL) return 0;
columnlist[0] = '(';
while ((col = PyIter_Next(coliter)) != NULL) {
if (!PyString_Check(col)) {
Py_DECREF(col);
Py_DECREF(coliter);
PyErr_SetString(PyExc_ValueError,
"elements in column list must be strings");
return -1;
}
PyString_AsStringAndSize(col, &colname, &collen);
if (offset + collen > DEFAULT_COPYBUFF - 2) {
Py_DECREF(col);
Py_DECREF(coliter);
PyErr_SetString(PyExc_ValueError, "column list too long");
return -1;
}
strncpy(&columnlist[offset], colname, collen);
offset += collen;
columnlist[offset++] = ',';
Py_DECREF(col);
}
Py_DECREF(coliter);
if (offset == 2) {
return 0;
}
else {
columnlist[offset - 1] = ')';
columnlist[offset] = '\0';
return 1;
}
}
/* extension: copy_from - implements COPY FROM */
#define psyco_curs_copy_from_doc \
@ -1100,12 +1149,12 @@ _psyco_curs_has_read_check(PyObject* o, void* var)
static PyObject *
psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
{
char query[1024];
char query[DEFAULT_COPYBUFF];
char *table_name;
char *sep = "\t", *null = NULL;
Py_ssize_t bufsize = DEFAULT_COPYSIZE;
Py_ssize_t bufsize = DEFAULT_COPYBUFF;
PyObject *file, *columns = NULL, *res = NULL;
char columnlist[1024] = "";
char columnlist[DEFAULT_COPYBUFF];
static char *kwlist[] = {"file", "table", "sep", "null", "size",
"columns", NULL};
@ -1119,58 +1168,19 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
return NULL;
}
if (columns != NULL && columns != Py_None) {
PyObject* collistiter = PyObject_GetIter(columns);
PyObject* col;
Py_ssize_t collistlen = 2;
Py_ssize_t colitemlen;
char* colname;
if (collistiter == NULL) {
return NULL;
}
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()) {
if (_psyco_curs_copy_columns(columns, columnlist) == -1)
return NULL;
}
EXC_IF_CURS_CLOSED(self);
if (null) {
PyOS_snprintf(query, 1023, "COPY %s%s FROM stdin USING DELIMITERS '%s'"
PyOS_snprintf(query, DEFAULT_COPYBUFF-1,
"COPY %s%s FROM stdin USING DELIMITERS '%s'"
" WITH NULL AS '%s'", table_name, columnlist, sep, null);
}
else {
PyOS_snprintf(query, 1023, "COPY %s%s FROM stdin USING DELIMITERS '%s'",
PyOS_snprintf(query, DEFAULT_COPYBUFF-1,
"COPY %s%s FROM stdin USING DELIMITERS '%s'",
table_name, columnlist, sep);
}
Dprintf("psyco_curs_copy_from: query = %s", query);
@ -1188,8 +1198,10 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
return res;
}
/* extension: copy_to - implements COPY TO */
#define psyco_curs_copy_to_doc \
"copy_to(file, table, sep='\\t', null='\\N') -- Copy table to file."
"copy_to(file, table, sep='\\t', null='\\N', columns=None) -- Copy table to file."
static int
_psyco_curs_has_write_check(PyObject* o, void* var)
@ -1209,28 +1221,34 @@ _psyco_curs_has_write_check(PyObject* o, void* var)
static PyObject *
psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
{
char query[256];
char query[DEFAULT_COPYBUFF];
char columnlist[DEFAULT_COPYBUFF];
char *table_name;
char *sep = "\t", *null = NULL;
PyObject *file, *res = NULL;
PyObject *file, *columns = NULL, *res = NULL;
static char *kwlist[] = {"file", "table", "sep", "null", NULL};
static char *kwlist[] = {"file", "table", "sep", "null", "columns", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ss", kwlist,
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ssO", kwlist,
_psyco_curs_has_write_check, &file,
&table_name, &sep, &null)) {
&table_name, &sep, &null, &columns)) {
return NULL;
}
if (_psyco_curs_copy_columns(columns, columnlist) == -1)
return NULL;
EXC_IF_CURS_CLOSED(self);
if (null) {
PyOS_snprintf(query, 255, "COPY %s TO stdout USING DELIMITERS '%s'"
" WITH NULL AS '%s'", table_name, sep, null);
PyOS_snprintf(query, DEFAULT_COPYBUFF-1,
"COPY %s%s TO stdout USING DELIMITERS '%s'"
" WITH NULL AS '%s'", table_name, columnlist, sep, null);
}
else {
PyOS_snprintf(query, 255, "COPY %s TO stdout USING DELIMITERS '%s'",
table_name, sep);
PyOS_snprintf(query, DEFAULT_COPYBUFF-1,
"COPY %s%s TO stdout USING DELIMITERS '%s'",
table_name, columnlist, sep);
}
self->copysize = 0;

View File

@ -48,7 +48,7 @@ extern "C" {
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 5
#define CONV_CODE_PY_SSIZE_T "n"
#else
#define CONV_CODE_PY_SSIZE_T "d"
#define CONV_CODE_PY_SSIZE_T "i"
typedef int Py_ssize_t;
#define PY_SSIZE_T_MIN INT_MIN

View File

@ -1,5 +1,5 @@
[build_ext]
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3,PSYCOPG_DEBUG
# PSYCOPG_EXTENSIONS enables extensions to PEP-249 (you really want this)
# PSYCOPG_DISPLAY_SIZE enable display size calculation (a little slower)
# HAVE_PQFREEMEM should be defined on PostgreSQL >= 7.4

View File

@ -54,7 +54,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.6b2'
PSYCOPG_VERSION = '2.0.6'
version_flags = []
PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win')