summaryrefslogtreecommitdiff
path: root/psycopg
diff options
context:
space:
mode:
Diffstat (limited to 'psycopg')
-rw-r--r--psycopg/cursor.h1
-rw-r--r--psycopg/cursor_type.c150
-rw-r--r--psycopg/psycopg.h2
3 files changed, 86 insertions, 67 deletions
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