mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-12-01 13:13:45 +03:00
COPY FROM works.
This commit is contained in:
parent
3141770f53
commit
e5f558a6be
15
ChangeLog
15
ChangeLog
|
@ -1,5 +1,17 @@
|
||||||
|
2005-03-02 Federico Di Gregorio <fog@debian.org>
|
||||||
|
|
||||||
|
* COPY FROM implemented using both old and new (v3) protocol.
|
||||||
|
|
||||||
|
* psycopg/config.h (Dprintf): declaration for asprintf is gone.
|
||||||
|
|
||||||
|
* psycopg/pqpath.c (_pq_copy_in_v3): implemented.
|
||||||
|
|
||||||
2005-03-01 Federico Di Gregorio <fog@debian.org>
|
2005-03-01 Federico Di Gregorio <fog@debian.org>
|
||||||
|
|
||||||
|
* setup.py: now we generate a slighly more verbose version string
|
||||||
|
that embeds some of the compile options, to facilitate users' bug
|
||||||
|
reports.
|
||||||
|
|
||||||
* psycopg/cursor_type.c (psyco_curs_copy_from): we now use
|
* psycopg/cursor_type.c (psyco_curs_copy_from): we now use
|
||||||
PyOS_snprintf instead of asprintf. On some platforms this can be
|
PyOS_snprintf instead of asprintf. On some platforms this can be
|
||||||
bad (win32).. if that's your case, get a better platform. :/
|
bad (win32).. if that's your case, get a better platform. :/
|
||||||
|
@ -57,7 +69,8 @@
|
||||||
|
|
||||||
2005-01-13 Federico Di Gregorio <fog@debian.org>
|
2005-01-13 Federico Di Gregorio <fog@debian.org>
|
||||||
|
|
||||||
* ZPsycopgDA/db.py (DB.query): ported ZPsycopgDA connection fix
|
* ZPsycopgDA/db.py (DB.query
|
||||||
|
): ported ZPsycopgDA connection fix
|
||||||
from psycopg 1.1.
|
from psycopg 1.1.
|
||||||
|
|
||||||
* lib/*.py: added pydoc-friendly messages.
|
* lib/*.py: added pydoc-friendly messages.
|
||||||
|
|
|
@ -18,7 +18,8 @@ DSN = 'dbname=test'
|
||||||
|
|
||||||
## don't modify anything below tis line (except for experimenting)
|
## don't modify anything below tis line (except for experimenting)
|
||||||
|
|
||||||
import sys, psycopg
|
import sys
|
||||||
|
import psycopg
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
DSN = sys.argv[1]
|
DSN = sys.argv[1]
|
||||||
|
|
178
examples/copy_from.py
Normal file
178
examples/copy_from.py
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
# copy_from.py -- example about copy_from
|
||||||
|
#
|
||||||
|
# Copyright (C) 2002 Tom Jenkins <tjenkins@devis.com>
|
||||||
|
# Copyright (C) 2005 Federico Di Gregorio <fog@initd.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
|
||||||
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
# for more details.
|
||||||
|
#
|
||||||
|
|
||||||
|
## put in DSN your DSN string
|
||||||
|
|
||||||
|
DSN = 'dbname=test'
|
||||||
|
|
||||||
|
## don't modify anything below tis line (except for experimenting)
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import StringIO
|
||||||
|
import psycopg
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
DSN = sys.argv[1]
|
||||||
|
|
||||||
|
print "Opening connection using dns:", DSN
|
||||||
|
conn = psycopg.connect(DSN)
|
||||||
|
print "Encoding for this connection is", conn.encoding
|
||||||
|
|
||||||
|
curs = conn.cursor()
|
||||||
|
try:
|
||||||
|
curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)")
|
||||||
|
except:
|
||||||
|
conn.rollback()
|
||||||
|
curs.execute("DROP TABLE test_copy")
|
||||||
|
curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# copy_from with default arguments, from open file
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'wr')
|
||||||
|
data = ['Tom\tJenkins\t37\n',
|
||||||
|
'Madonna\t\N\t45\n',
|
||||||
|
'Federico\tDi Gregorio\t\N\n']
|
||||||
|
io.writelines(data)
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'r')
|
||||||
|
curs.copy_from(io, 'test_copy')
|
||||||
|
print "1) Copy %d records from file object " % len(data) + \
|
||||||
|
"using defaults (sep: \\t and null = \\N)"
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
curs.execute("SELECT * FROM test_copy")
|
||||||
|
rows = curs.fetchall()
|
||||||
|
print " Select returned %d rows" % len(rows)
|
||||||
|
|
||||||
|
for r in rows:
|
||||||
|
print " %s %s\t%s" % (r[0], r[1], r[2])
|
||||||
|
curs.execute("delete from test_copy")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# copy_from using custom separator, from open file
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'wr')
|
||||||
|
data = ['Tom:Jenkins:37\n',
|
||||||
|
'Madonna:\N:45\n',
|
||||||
|
'Federico:Di Gregorio:\N\n']
|
||||||
|
io.writelines(data)
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'r')
|
||||||
|
curs.copy_from(io, 'test_copy', ':')
|
||||||
|
print "2) Copy %d records from file object using sep = :" % len(data)
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
curs.execute("SELECT * FROM test_copy")
|
||||||
|
rows = curs.fetchall()
|
||||||
|
print " Select returned %d rows" % len(rows)
|
||||||
|
|
||||||
|
for r in rows:
|
||||||
|
print " %s %s\t%s" % (r[0], r[1], r[2])
|
||||||
|
curs.execute("delete from test_copy")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# copy_from using custom null identifier, from open file
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'wr')
|
||||||
|
data = ['Tom\tJenkins\t37\n',
|
||||||
|
'Madonna\tNULL\t45\n',
|
||||||
|
'Federico\tDi Gregorio\tNULL\n']
|
||||||
|
io.writelines(data)
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'r')
|
||||||
|
curs.copy_from(io, 'test_copy', null='NULL')
|
||||||
|
print "3) Copy %d records from file object using null = NULL" % len(data)
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
curs.execute("SELECT * FROM test_copy")
|
||||||
|
rows = curs.fetchall()
|
||||||
|
print " Select using cursor returned %d rows" % len(rows)
|
||||||
|
|
||||||
|
for r in rows:
|
||||||
|
print " %s %s\t%s" % (r[0], r[1], r[2])
|
||||||
|
curs.execute("delete from test_copy")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# copy_from using custom separator and null identifier
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'wr')
|
||||||
|
data = ['Tom:Jenkins:37\n', 'Madonna:NULL:45\n', 'Federico:Di Gregorio:NULL\n']
|
||||||
|
io.writelines(data)
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
io = open('copy_from.txt', 'r')
|
||||||
|
curs.copy_from(io, 'test_copy', ':', 'NULL')
|
||||||
|
print "4) Copy %d records from file object " % len(data) + \
|
||||||
|
"using sep = : and null = NULL"
|
||||||
|
io.close()
|
||||||
|
|
||||||
|
curs.execute("SELECT * FROM test_copy")
|
||||||
|
rows = curs.fetchall()
|
||||||
|
print " Select using cursor returned %d rows" % len(rows)
|
||||||
|
|
||||||
|
for r in rows:
|
||||||
|
print " %s %s\t%s" % (r[0], r[1], r[2])
|
||||||
|
curs.execute("delete from test_copy")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# anything can be used as a file if it has .read() and .readline() methods
|
||||||
|
|
||||||
|
data = StringIO.StringIO()
|
||||||
|
data.write('\n'.join(['Tom\tJenkins\t37',
|
||||||
|
'Madonna\t\N\t45',
|
||||||
|
'Federico\tDi Gregorio\t\N']))
|
||||||
|
data.seek(0)
|
||||||
|
|
||||||
|
curs.copy_from(data, 'test_copy')
|
||||||
|
print "5) Copy 3 records from StringIO object using defaults"
|
||||||
|
|
||||||
|
curs.execute("SELECT * FROM test_copy")
|
||||||
|
rows = curs.fetchall()
|
||||||
|
print " Select using cursor returned %d rows" % len(rows)
|
||||||
|
|
||||||
|
for r in rows:
|
||||||
|
print " %s %s\t%s" % (r[0], r[1], r[2])
|
||||||
|
curs.execute("delete from test_copy")
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# simple error test
|
||||||
|
|
||||||
|
print "6) About to raise an error"
|
||||||
|
data = StringIO.StringIO()
|
||||||
|
data.write('\n'.join(['Tom\tJenkins\t37',
|
||||||
|
'Madonna\t\N\t45',
|
||||||
|
'Federico\tDi Gregorio\taaa']))
|
||||||
|
data.seek(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
curs.copy_from(data, 'test_copy')
|
||||||
|
except StandardError, err:
|
||||||
|
conn.rollback()
|
||||||
|
print " Catched error (as expected):\n", err
|
||||||
|
|
||||||
|
conn.rollback()
|
||||||
|
|
||||||
|
curs.execute("DROP TABLE test_copy")
|
||||||
|
os.unlink('copy_from.txt')
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ class DictCursor(_cursor):
|
||||||
self._build_index()
|
self._build_index()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class DictRow(list):
|
class DictRow(list):
|
||||||
"""A row object that allow by-colun-name access to data."""
|
"""A row object that allow by-colun-name access to data."""
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,6 @@
|
||||||
#ifndef PSYCOPG_CONFIG_H
|
#ifndef PSYCOPG_CONFIG_H
|
||||||
#define PSYCOPG_CONFIG_H 1
|
#define PSYCOPG_CONFIG_H 1
|
||||||
|
|
||||||
/* replacement for asprintf() */
|
|
||||||
#ifndef HAVE_ASPRINTF
|
|
||||||
extern int asprintf(char **buffer, char *fmt, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* debug printf-like function */
|
/* debug printf-like function */
|
||||||
#if defined( __GNUC__) && !defined(__APPLE__)
|
#if defined( __GNUC__) && !defined(__APPLE__)
|
||||||
#ifdef PSYCOPG_DEBUG
|
#ifdef PSYCOPG_DEBUG
|
||||||
|
|
|
@ -134,7 +134,7 @@ psyco_conn_rollback(connectionObject *self, PyObject *args)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PSYCOPG_EXTENSIONS
|
||||||
/* set_isolation_level method - switch connection isolation level */
|
/* set_isolation_level method - switch connection isolation level */
|
||||||
|
|
||||||
#define psyco_conn_set_isolation_level_doc \
|
#define psyco_conn_set_isolation_level_doc \
|
||||||
|
@ -186,7 +186,7 @@ psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/** the connection object **/
|
/** the connection object **/
|
||||||
|
|
|
@ -901,6 +901,7 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -910,7 +911,64 @@ psyco_curs_scroll(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
/* extension: copy_from - implements COPY FROM */
|
/* extension: copy_from - implements COPY FROM */
|
||||||
|
|
||||||
#define psyco_curs_copy_from_doc \
|
#define psyco_curs_copy_from_doc \
|
||||||
"copy_from(file, table, sep='\\t', null='NULL') -> copy file to table."
|
"copy_from(file, table, sep='\\t', null='\\N') -> copy file to table."
|
||||||
|
|
||||||
|
static int
|
||||||
|
_psyco_curs_has_read_check(PyObject* o, void* var)
|
||||||
|
{
|
||||||
|
if (PyObject_HasAttrString(o, "readline")
|
||||||
|
&& PyObject_HasAttrString(o, "read")) {
|
||||||
|
Py_INCREF(o);
|
||||||
|
*((PyObject**)var) = o;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"argument 1 must have both .read() and .readline() methods");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
char query[256];
|
||||||
|
char *table_name;
|
||||||
|
char *sep = "\t", *null = NULL;
|
||||||
|
long int bufsize = DEFAULT_COPYSIZE;
|
||||||
|
PyObject *file, *res = NULL;
|
||||||
|
|
||||||
|
static char *kwlist[] = {"file", "table", "sep", "null", "size", NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ssi", kwlist,
|
||||||
|
_psyco_curs_has_read_check, &file,
|
||||||
|
&table_name, &sep, &null, &bufsize)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXC_IF_CURS_CLOSED(self);
|
||||||
|
|
||||||
|
if (null) {
|
||||||
|
PyOS_snprintf(query, 256, "COPY %s FROM stdin USING DELIMITERS '%s'"
|
||||||
|
" WITH NULL AS '%s'", table_name, sep, null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyOS_snprintf(query, 256, "COPY %s FROM stdin USING DELIMITERS '%s'",
|
||||||
|
table_name, sep);
|
||||||
|
}
|
||||||
|
Dprintf("psyco_curs_copy_from: query = %s", query);
|
||||||
|
|
||||||
|
self->copysize = bufsize;
|
||||||
|
self->copyfile = file;
|
||||||
|
Py_INCREF(file);
|
||||||
|
|
||||||
|
if (pq_execute(self, query, 0) == 1) {
|
||||||
|
res = Py_None;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_psyco_curs_has_write_check(PyObject* o, void* var)
|
_psyco_curs_has_write_check(PyObject* o, void* var)
|
||||||
|
@ -927,41 +985,6 @@ _psyco_curs_has_write_check(PyObject* o, void* var)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
psyco_curs_copy_from(cursorObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
char query[256];
|
|
||||||
char *table_name;
|
|
||||||
char *sep = "\t", *null ="NULL";
|
|
||||||
long int bufsize = DEFAULT_COPYSIZE;
|
|
||||||
PyObject *file, *res = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O&s|ssi",
|
|
||||||
_psyco_curs_has_write_check, &file,
|
|
||||||
&table_name, &sep, &null, &bufsize)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXC_IF_CURS_CLOSED(self);
|
|
||||||
|
|
||||||
PyOS_snprintf(query, 256, "COPY %s FROM stdin USING DELIMITERS '%s'"
|
|
||||||
" WITH NULL AS '%s'", table_name, sep, null);
|
|
||||||
Dprintf("psyco_curs_copy_from: query = %s", query);
|
|
||||||
|
|
||||||
self->copysize = bufsize;
|
|
||||||
self->copyfile = file;
|
|
||||||
Py_INCREF(file);
|
|
||||||
|
|
||||||
if (pq_execute(self, query, 0) == 1) {
|
|
||||||
res = Py_None;
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(query);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* extension: fileno - return the file descripor of the connection */
|
/* extension: fileno - return the file descripor of the connection */
|
||||||
|
|
||||||
#define psyco_curs_fileno_doc \
|
#define psyco_curs_fileno_doc \
|
||||||
|
@ -1084,7 +1107,7 @@ static struct PyMethodDef cursorObject_methods[] = {
|
||||||
{"isready", (PyCFunction)psyco_curs_isready,
|
{"isready", (PyCFunction)psyco_curs_isready,
|
||||||
METH_VARARGS, psyco_curs_isready_doc},
|
METH_VARARGS, psyco_curs_isready_doc},
|
||||||
{"copy_from", (PyCFunction)psyco_curs_copy_from,
|
{"copy_from", (PyCFunction)psyco_curs_copy_from,
|
||||||
METH_VARARGS, psyco_curs_copy_from_doc},
|
METH_VARARGS|METH_KEYWORDS, psyco_curs_copy_from_doc},
|
||||||
#endif
|
#endif
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -73,8 +73,8 @@ pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg)
|
||||||
if (curs && curs->pgres) {
|
if (curs && curs->pgres) {
|
||||||
if (conn->protocol == 3) {
|
if (conn->protocol == 3) {
|
||||||
#ifdef HAVE_PQPROTOCOL3
|
#ifdef HAVE_PQPROTOCOL3
|
||||||
char *pgstate = PQresultErrorField(curs->pgres,
|
char *pgstate =
|
||||||
PG_DIAG_SQLSTATE);
|
PQresultErrorField(curs->pgres, PG_DIAG_SQLSTATE);
|
||||||
if (!strncmp(pgstate, "23", 2))
|
if (!strncmp(pgstate, "23", 2))
|
||||||
exc = IntegrityError;
|
exc = IntegrityError;
|
||||||
else
|
else
|
||||||
|
@ -130,6 +130,8 @@ pq_set_critical(connectionObject *conn, const char *msg)
|
||||||
PyObject *
|
PyObject *
|
||||||
pq_resolve_critical(connectionObject *conn, int close)
|
pq_resolve_critical(connectionObject *conn, int close)
|
||||||
{
|
{
|
||||||
|
Dprintf("pq_resolve_critical: resolving %s", conn->critical);
|
||||||
|
|
||||||
if (conn->critical) {
|
if (conn->critical) {
|
||||||
char *msg = &(conn->critical[6]);
|
char *msg = &(conn->critical[6]);
|
||||||
Dprintf("pq_resolve_critical: error = %s", msg);
|
Dprintf("pq_resolve_critical: error = %s", msg);
|
||||||
|
@ -562,8 +564,51 @@ _pq_copy_in_v3(cursorObject *curs)
|
||||||
/* COPY FROM implementation when protocol 3 is available: this function
|
/* COPY FROM implementation when protocol 3 is available: this function
|
||||||
uses the new PQputCopyData() and can detect errors and set the correct
|
uses the new PQputCopyData() and can detect errors and set the correct
|
||||||
exception */
|
exception */
|
||||||
|
PyObject *o;
|
||||||
|
int length = 0, error = 0;
|
||||||
|
|
||||||
return -1;
|
Dprintf("_pq_copy_in_v3: called with object at %p", curs->copyfile);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
o = PyObject_CallMethod(curs->copyfile, "read", "i", curs->copysize);
|
||||||
|
if (!o || !PyString_Check(o) || (length = PyString_Size(o)) == -1) {
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
if (length == 0 || error == 1) break;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
if (PQputCopyData(curs->conn->pgconn,
|
||||||
|
PyString_AS_STRING(o), length) == -1) {
|
||||||
|
error = 2;
|
||||||
|
}
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (error == 2) break;
|
||||||
|
|
||||||
|
Py_DECREF(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_XDECREF(o);
|
||||||
|
|
||||||
|
Dprintf("_pq_copy_in_v3: error = %d", error);
|
||||||
|
|
||||||
|
if (error == 0 || error == 2)
|
||||||
|
/* 0 means that the copy went well, 2 that there was an error on the
|
||||||
|
backend: in both cases we'll get the error message from the
|
||||||
|
PQresult */
|
||||||
|
PQputCopyEnd(curs->conn->pgconn, NULL);
|
||||||
|
else
|
||||||
|
PQputCopyEnd(curs->conn->pgconn, "error during .read() call");
|
||||||
|
|
||||||
|
/* and finally we grab the operation result from the backend */
|
||||||
|
IFCLEARPGRES(curs->pgres);
|
||||||
|
while ((curs->pgres = PQgetResult(curs->conn->pgconn)) != NULL) {
|
||||||
|
if (PQresultStatus(curs->pgres) == PGRES_FATAL_ERROR)
|
||||||
|
pq_raise(curs->conn, curs, NULL, NULL);
|
||||||
|
IFCLEARPGRES(curs->pgres);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
static int
|
static int
|
||||||
|
@ -587,6 +632,15 @@ _pq_copy_in(cursorObject *curs)
|
||||||
PQputline(curs->conn->pgconn, "\\.\n");
|
PQputline(curs->conn->pgconn, "\\.\n");
|
||||||
PQendcopy(curs->conn->pgconn);
|
PQendcopy(curs->conn->pgconn);
|
||||||
|
|
||||||
|
/* if for some reason we're using a protocol 3 libpq to connect to a
|
||||||
|
protocol 2 backend we still need to cycle on the result set */
|
||||||
|
IFCLEARPGRES(curs->pgres);
|
||||||
|
while ((curs->pgres = PQgetResult(curs->conn->pgconn)) != NULL) {
|
||||||
|
if (PQresultStatus(curs->pgres) == PGRES_FATAL_ERROR)
|
||||||
|
pq_raise(curs->conn, curs, NULL, NULL);
|
||||||
|
IFCLEARPGRES(curs->pgres);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[build_ext]
|
[build_ext]
|
||||||
define=PSYCOPG_DEBUG,PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,HAVE_ASPRINTF,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
|
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
|
||||||
|
# PSYCOPG_DEBUG can be added to enable verbose debug information
|
||||||
# PSYCOPG_OWN_QUOTING can be added above but it is deprecated
|
# PSYCOPG_OWN_QUOTING can be added above but it is deprecated
|
||||||
|
|
||||||
# include_dirs is the preferred method for locating postgresql headers,
|
# include_dirs is the preferred method for locating postgresql headers,
|
||||||
|
|
28
setup.py
28
setup.py
|
@ -48,6 +48,7 @@ from distutils.sysconfig import get_python_inc
|
||||||
import distutils.ccompiler
|
import distutils.ccompiler
|
||||||
|
|
||||||
PSYCOPG_VERSION = '1.99.11/devel'
|
PSYCOPG_VERSION = '1.99.11/devel'
|
||||||
|
version_flags = []
|
||||||
|
|
||||||
have_pydatetime = False
|
have_pydatetime = False
|
||||||
have_mxdatetime = False
|
have_mxdatetime = False
|
||||||
|
@ -80,10 +81,7 @@ if sys.version_info[0] >= 2 and sys.version_info[1] >= 4:
|
||||||
ext = [] ; data_files = []
|
ext = [] ; data_files = []
|
||||||
library_dirs = [] ; libraries = [] ; include_dirs = []
|
library_dirs = [] ; libraries = [] ; include_dirs = []
|
||||||
|
|
||||||
if sys.platform != 'win32':
|
if sys.platform == 'win32':
|
||||||
define_macros.append(('PSYCOPG_VERSION', '"'+PSYCOPG_VERSION+'"'))
|
|
||||||
else:
|
|
||||||
define_macros.append(('PSYCOPG_VERSION', '\\"'+PSYCOPG_VERSION+'\\"'))
|
|
||||||
include_dirs = ['.',
|
include_dirs = ['.',
|
||||||
POSTGRESQLDIR + "\\src\\interfaces\\libpq",
|
POSTGRESQLDIR + "\\src\\interfaces\\libpq",
|
||||||
POSTGRESQLDIR + "\\src\\include" ]
|
POSTGRESQLDIR + "\\src\\include" ]
|
||||||
|
@ -124,12 +122,14 @@ if os.path.exists(mxincludedir):
|
||||||
define_macros.append(('HAVE_MXDATETIME','1'))
|
define_macros.append(('HAVE_MXDATETIME','1'))
|
||||||
sources.append('adapter_mxdatetime.c')
|
sources.append('adapter_mxdatetime.c')
|
||||||
have_mxdatetime = True
|
have_mxdatetime = True
|
||||||
|
version_flags.append('mx')
|
||||||
|
|
||||||
# check for python datetime package
|
# check for python datetime package
|
||||||
if os.path.exists(os.path.join(get_python_inc(plat_specific=1),"datetime.h")):
|
if os.path.exists(os.path.join(get_python_inc(plat_specific=1),"datetime.h")):
|
||||||
define_macros.append(('HAVE_PYDATETIME','1'))
|
define_macros.append(('HAVE_PYDATETIME','1'))
|
||||||
sources.append('adapter_datetime.c')
|
sources.append('adapter_datetime.c')
|
||||||
have_pydatetime = True
|
have_pydatetime = True
|
||||||
|
version_flags.append('dt')
|
||||||
|
|
||||||
# now decide which package will be the default for date/time typecasts
|
# now decide which package will be the default for date/time typecasts
|
||||||
if have_pydatetime and use_pydatetime \
|
if have_pydatetime and use_pydatetime \
|
||||||
|
@ -143,6 +143,26 @@ else:
|
||||||
sys.stderr.write("error: python datetime module not found\n")
|
sys.stderr.write("error: python datetime module not found\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# generate a nice version string to avoid confusion when users report bugs
|
||||||
|
from ConfigParser import ConfigParser
|
||||||
|
parser = ConfigParser()
|
||||||
|
parser.read('setup.cfg')
|
||||||
|
for have in parser.get('build_ext', 'define').split(','):
|
||||||
|
if have == 'PSYCOPG_EXTENSIONS':
|
||||||
|
version_flags.append('ext')
|
||||||
|
elif have == 'HAVE_PQPROTOCOL3':
|
||||||
|
version_flags.append('pq3')
|
||||||
|
if version_flags:
|
||||||
|
PSYCOPG_VERSION_EX = PSYCOPG_VERSION + " (%s)" % ' '.join(version_flags)
|
||||||
|
else:
|
||||||
|
PSYCOPG_VERSION_EX = PSYCOPG_VERSION
|
||||||
|
|
||||||
|
if sys.platform != 'win32':
|
||||||
|
define_macros.append(('PSYCOPG_VERSION', '"'+PSYCOPG_VERSION_EX+'"'))
|
||||||
|
else:
|
||||||
|
define_macros.append(('PSYCOPG_VERSION', '\\"'+PSYCOPG_VERSION_EX+'\\"'))
|
||||||
|
|
||||||
|
|
||||||
# build the extension
|
# build the extension
|
||||||
|
|
||||||
sources = map(lambda x: os.path.join('psycopg', x), sources)
|
sources = map(lambda x: os.path.join('psycopg', x), sources)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user