summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--NEWS19
-rw-r--r--ZPsycopgDA/DA.py2
-rw-r--r--examples/copy_from.py4
-rw-r--r--psycopg/cursor.h1
-rw-r--r--psycopg/cursor_type.c150
-rw-r--r--psycopg/psycopg.h2
-rw-r--r--setup.cfg2
-rw-r--r--setup.py2
9 files changed, 110 insertions, 82 deletions
diff --git a/ChangeLog b/ChangeLog
index 0f847ef..75011f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/NEWS b/NEWS
index 2ae7315..80caa2d 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/ZPsycopgDA/DA.py b/ZPsycopgDA/DA.py
index 48ac612..81cd264 100644
--- a/ZPsycopgDA/DA.py
+++ b/ZPsycopgDA/DA.py
@@ -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
diff --git a/examples/copy_from.py b/examples/copy_from.py
index edd3294..dfeff5c 100644
--- a/examples/copy_from.py
+++ b/examples/copy_from.py
@@ -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()
diff --git a/psycopg/cursor.h b/psycopg/cursor.h
index 8fb0489..d8af1e8 100644
--- a/psycopg/cursor.h
+++ b/psycopg/cursor.h
@@ -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 */
diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c
index 6dbe846..e4b0319 100644
--- a/psycopg/cursor_type.c
+++ b/psycopg/cursor_type.c
@@ -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;
diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h
index 15ce8bb..aeb174c 100644
--- a/psycopg/psycopg.h
+++ b/psycopg/psycopg.h
@@ -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
diff --git a/setup.cfg b/setup.cfg
index b4ea08b..3d75373 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -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
diff --git a/setup.py b/setup.py
index c11c25f..9dfc79b 100644
--- a/setup.py
+++ b/setup.py
@@ -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')