The library can be compiled with Python 3.

Just compiled! No test run yet and many points to review, marked in the
code.

The patch is largely Martin von Löwis work, simplified after refactoring
in the previous commits and adapted to the new code (as the patch was
originally for Psycopg 2.0.9)
This commit is contained in:
Daniele Varrazzo 2010-12-12 21:48:54 +00:00
parent e182201e6e
commit cb6b52945b
21 changed files with 335 additions and 115 deletions

View File

@ -38,7 +38,7 @@ static PyObject *
asis_str(asisObject *self)
{
if (self->wrapped == Py_None) {
return PyString_FromString("NULL");
return Text_FromUTF8("NULL");
}
else {
return PyObject_Str(self->wrapped);

View File

@ -58,7 +58,13 @@ binary_quote(binaryObject *self)
size_t len = 0;
/* if we got a plain string or a buffer we escape it and save the buffer */
if (PyString_Check(self->wrapped) || PyBuffer_Check(self->wrapped)) {
if (Bytes_Check(self->wrapped)
#if PY_MAJOR_VERSION < 3
|| PyBuffer_Check(self->wrapped)
#else
|| PyMemoryView_Check(self->wrapped)
#endif
) {
/* escape and build quoted buffer */
if (PyObject_AsReadBuffer(self->wrapped, (const void **)&buffer,
&buffer_len) < 0)
@ -76,7 +82,7 @@ binary_quote(binaryObject *self)
(self->conn && ((connectionObject*)self->conn)->equote)
? "E'%s'::bytea" : "'%s'::bytea" , to);
else
self->buffer = PyString_FromString("''::bytea");
self->buffer = Text_FromUTF8("''::bytea");
PQfreemem(to);
}

View File

@ -62,26 +62,30 @@ pydatetime_str(pydatetimeObject *self)
if (self->type <= PSYCO_DATETIME_TIMESTAMP) {
PyObject *tz;
/* Select the right PG type to cast into. */
/* Select the right PG type to cast into.
* fmt contains %s in Py2 and %U in Py3,
* So it can be used with the Text_FromFormatS macro */
char *fmt = NULL;
switch (self->type) {
case PSYCO_DATETIME_TIME:
fmt = "'%s'::time";
fmt = "'" Text_S "'::time";
break;
case PSYCO_DATETIME_DATE:
fmt = "'%s'::date";
fmt = "'" Text_S "'::date";
break;
case PSYCO_DATETIME_TIMESTAMP:
tz = PyObject_GetAttrString(self->wrapped, "tzinfo");
if (!tz) { return NULL; }
fmt = (tz == Py_None) ? "'%s'::timestamp" : "'%s'::timestamptz";
fmt = (tz == Py_None)
? "'" Text_S "'::timestamp"
: "'" Text_S "'::timestamptz";
Py_DECREF(tz);
break;
}
iso = PyObject_CallMethod(self->wrapped, "isoformat", NULL);
if (iso) {
res = PyString_FromFormat(fmt, PyString_AsString(iso));
res = Text_FromFormatS(fmt, iso);
Py_DECREF(iso);
}
return res;
@ -89,7 +93,7 @@ pydatetime_str(pydatetimeObject *self)
else {
PyDateTime_Delta *obj = (PyDateTime_Delta*)self->wrapped;
char buffer[8];
char buffer[8];
int i;
int a = obj->microseconds;

View File

@ -45,7 +45,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("'{}'");
if (len == 0) return Text_FromUTF8("'{}'");
tmp = PyTuple_New(len);
@ -53,7 +53,7 @@ list_quote(listObject *self)
PyObject *quoted;
PyObject *wrapped = PyList_GET_ITEM(self->wrapped, i);
if (wrapped == Py_None)
quoted = PyString_FromString("NULL");
quoted = Text_FromUTF8("NULL");
else
quoted = microprotocol_getquoted(wrapped,
(connectionObject*)self->connection);
@ -67,11 +67,15 @@ list_quote(listObject *self)
/* now that we have a tuple of adapted objects we just need to join them
and put "ARRAY[] around the result */
str = PyString_FromString(", ");
str = Text_FromUTF8(", ");
joined = PyObject_CallMethod(str, "join", "(O)", tmp);
if (joined == NULL) goto error;
#if PY_MAJOR_VERSION < 3
res = PyString_FromFormat("ARRAY[%s]", PyString_AsString(joined));
#else
res = PyUnicode_FromFormat("ARRAY[%U]", joined);
#endif
error:
Py_XDECREF(tmp);

View File

@ -39,17 +39,17 @@ pboolean_str(pbooleanObject *self)
{
#ifdef PSYCOPG_NEW_BOOLEAN
if (PyObject_IsTrue(self->wrapped)) {
return PyString_FromString("true");
return Text_FromUTF8("true");
}
else {
return PyString_FromString("false");
return Text_FromUTF8("false");
}
#else
if (PyObject_IsTrue(self->wrapped)) {
return PyString_FromString("'t'");
return Text_FromUTF8("'t'");
}
else {
return PyString_FromString("'f'");
return Text_FromUTF8("'f'");
}
#endif
}

View File

@ -45,7 +45,7 @@ pdecimal_str(pdecimalObject *self)
goto end;
}
else if (check) {
res = PyString_FromString("'NaN'::numeric");
res = Text_FromUTF8("'NaN'::numeric");
goto end;
}
@ -57,7 +57,7 @@ pdecimal_str(pdecimalObject *self)
goto end;
}
if (PyObject_IsTrue(check)) {
res = PyString_FromString("'NaN'::numeric");
res = Text_FromUTF8("'NaN'::numeric");
goto end;
}
@ -66,7 +66,7 @@ pdecimal_str(pdecimalObject *self)
goto end;
}
if (PyObject_IsTrue(check)) {
res = PyString_FromString("'NaN'::numeric");
res = Text_FromUTF8("'NaN'::numeric");
goto end;
}

View File

@ -40,9 +40,9 @@ pfloat_str(pfloatObject *self)
{
double n = PyFloat_AsDouble(self->wrapped);
if (isnan(n))
return PyString_FromString("'NaN'::float");
return Text_FromUTF8("'NaN'::float");
else if (isinf(n))
return PyString_FromString("'Infinity'::float");
return Text_FromUTF8("'Infinity'::float");
else
return PyObject_Repr(self->wrapped);
}

View File

@ -54,6 +54,7 @@ qstring_quote(qstringObject *self)
if (str == NULL) return NULL;
}
#if PY_MAJOR_VERSION < 3
/* if the wrapped object is a simple string, we don't know how to
(re)encode it, so we pass it as-is */
else if (PyString_Check(self->wrapped)) {
@ -61,6 +62,7 @@ qstring_quote(qstringObject *self)
/* INCREF to make it ref-wise identical to unicode one */
Py_INCREF(str);
}
#endif
/* if the wrapped object is not a string, this is an error */
else {
@ -70,7 +72,7 @@ qstring_quote(qstringObject *self)
}
/* encode the string into buffer */
PyString_AsStringAndSize(str, &s, &len);
Bytes_AsStringAndSize(str, &s, &len);
/* Call qstring_escape with the GIL released, then reacquire the GIL
before verifying that the results can fit into a Python string; raise
@ -94,7 +96,8 @@ qstring_quote(qstringObject *self)
return NULL;
}
self->buffer = PyString_FromStringAndSize(buffer, qlen);
/* XXX need to decode in connection's encoding in 3.0 */
self->buffer = Text_FromUTF8AndSize(buffer, qlen);
PyMem_Free(buffer);
Py_DECREF(str);

View File

@ -76,7 +76,8 @@ conn_notice_process(connectionObject *self)
while (notice != NULL) {
PyObject *msg;
msg = PyString_FromString(notice->message);
/* XXX possible other encode I think */
msg = Text_FromUTF8(notice->message);
Dprintf("conn_notice_process: %s", notice->message);
@ -145,8 +146,9 @@ conn_notifies_process(connectionObject *self)
(int) pgn->be_pid, pgn->relname);
if (!(pid = PyInt_FromLong((long)pgn->be_pid))) { goto error; }
if (!(channel = PyString_FromString(pgn->relname))) { goto error; }
if (!(payload = PyString_FromString(pgn->extra))) { goto error; }
/* XXX in the connection encoding? */
if (!(channel = Text_FromUTF8(pgn->relname))) { goto error; }
if (!(payload = Text_FromUTF8(pgn->extra))) { goto error; }
if (!(notify = PyObject_CallFunctionObjArgs((PyObject *)&NotifyType,
pid, channel, payload, NULL))) {
@ -222,15 +224,35 @@ conn_encoding_to_codec(const char *enc)
{
char *tmp;
Py_ssize_t size;
PyObject *pyenc;
PyObject *pyenc = NULL;
PyObject *pybenc = NULL;
char *rv = NULL;
/* Find the Py codec name from the PG encoding */
if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) {
PyErr_Format(OperationalError,
"no Python codec for client encoding '%s'", enc);
goto exit;
}
if (-1 == PyString_AsStringAndSize(pyenc, &tmp, &size)) {
/* Convert the codec in a bytes string to extract the c string.
* At the end of the block we have pybenc with a new ref. */
if (PyUnicode_Check(pyenc)) {
if (!(pybenc = PyUnicode_AsEncodedString(pyenc, "ascii", NULL))) {
goto exit;
}
}
else if (Bytes_Check(pyenc)) {
Py_INCREF(pyenc);
pybenc = pyenc;
}
else {
PyErr_Format(PyExc_TypeError, "bad type for encoding: %s",
Py_TYPE(pyenc)->tp_name);
goto exit;
}
if (-1 == Bytes_AsStringAndSize(pybenc, &tmp, &size)) {
goto exit;
}
@ -239,6 +261,7 @@ conn_encoding_to_codec(const char *enc)
exit:
/* pyenc is borrowed: no decref. */
Py_XDECREF(pybenc);
return rv;
}
@ -1027,7 +1050,7 @@ conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid)
/* convert the xid into PostgreSQL transaction id while keeping the GIL */
if (!(tid = xid_get_tid(xid))) { goto exit; }
if (!(ctid = PyString_AsString(tid))) { goto exit; }
if (!(ctid = Bytes_AsString(tid))) { goto exit; }
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock);

View File

@ -498,7 +498,7 @@ psyco_conn_get_parameter_status(connectionObject *self, PyObject *args)
Py_INCREF(Py_None);
return Py_None;
}
return PyString_FromString(val);
return Text_FromUTF8(val);
}

View File

@ -87,7 +87,7 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
just before returning. we also init *new to NULL to exit with an error
if we can't complete the mogrification */
n = *new = NULL;
c = PyString_AsString(fmt);
c = Bytes_AsString(fmt);
while(*c) {
/* handle plain percent symbol in format string */
@ -116,7 +116,7 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
for (d = c + 2; *d && *d != ')'; d++);
if (*d == ')') {
key = PyString_FromStringAndSize(c+2, (Py_ssize_t) (d-c-2));
key = Bytes_FromStringAndSize(c+2, (Py_ssize_t) (d-c-2));
value = PyObject_GetItem(var, key);
/* key has refcnt 1, value the original value + 1 */
@ -144,7 +144,7 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
optimization over the adapting code and can go away in
the future if somebody finds a None adapter usefull. */
if (value == Py_None) {
t = PyString_FromString("NULL");
t = Text_FromUTF8("NULL");
PyDict_SetItem(n, key, t);
/* t is a new object, refcnt = 1, key is at 2 */
@ -220,7 +220,7 @@ _mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new)
d = c+1;
if (value == Py_None) {
PyTuple_SET_ITEM(n, index, PyString_FromString("NULL"));
PyTuple_SET_ITEM(n, index, Text_FromUTF8("NULL"));
while (*d && !isalpha(*d)) d++;
if (*d) *d = 's';
Py_DECREF(value);
@ -267,7 +267,7 @@ static PyObject *_psyco_curs_validate_sql_basic(
goto fail;
}
if (PyString_Check(sql)) {
if (Bytes_Check(sql)) {
/* Necessary for ref-count symmetry with the unicode case: */
Py_INCREF(sql);
}
@ -314,7 +314,7 @@ _psyco_curs_merge_query_args(cursorObject *self,
the curren exception (we will later restore it if the type or the
strings do not match.) */
if (!(fquery = PyString_Format(query, args))) {
if (!(fquery = Text_Format(query, args))) {
PyObject *err, *arg, *trace;
int pe = 0;
@ -327,7 +327,7 @@ _psyco_curs_merge_query_args(cursorObject *self,
if (PyObject_HasAttrString(arg, "args")) {
PyObject *args = PyObject_GetAttrString(arg, "args");
PyObject *str = PySequence_GetItem(args, 0);
const char *s = PyString_AS_STRING(str);
const char *s = Bytes_AS_STRING(str);
Dprintf("psyco_curs_execute: -> %s", s);
@ -397,9 +397,15 @@ _psyco_curs_execute(cursorObject *self,
}
if (self->name != NULL) {
#if PY_MAJOR_VERSION < 3
self->query = PyString_FromFormat(
"DECLARE %s CURSOR WITHOUT HOLD FOR %s",
self->name, PyString_AS_STRING(fquery));
#else
self->query = PyUnicode_FromFormat(
"DECLARE %s CURSOR WITHOUT HOLD FOR %U",
self->name, fquery);
#endif
Py_DECREF(fquery);
}
else {
@ -408,9 +414,15 @@ _psyco_curs_execute(cursorObject *self,
}
else {
if (self->name != NULL) {
#if PY_MAJOR_VERSION < 3
self->query = PyString_FromFormat(
"DECLARE %s CURSOR WITHOUT HOLD FOR %s",
self->name, PyString_AS_STRING(operation));
#else
self->query = PyUnicode_FromFormat(
"DECLARE %s CURSOR WITHOUT HOLD FOR %U",
self->name, operation);
#endif
}
else {
/* Transfer reference ownership of the str in operation to
@ -423,7 +435,7 @@ _psyco_curs_execute(cursorObject *self,
/* At this point, the SQL statement must be str, not unicode */
res = pq_execute(self, PyString_AS_STRING(self->query), async);
res = pq_execute(self, Bytes_AS_STRING(self->query), async);
Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres);
if (res == -1) { goto fail; }
@ -950,7 +962,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
sql[sl-2] = ')';
sql[sl-1] = '\0';
operation = PyString_FromString(sql);
operation = Text_FromUTF8(sql);
PyMem_Free((void*)sql);
if (_psyco_curs_execute(self, operation, parameters, self->conn->async)) {
@ -1105,14 +1117,14 @@ static int _psyco_curs_copy_columns(PyObject *columns, char *columnlist)
columnlist[0] = '(';
while ((col = PyIter_Next(coliter)) != NULL) {
if (!PyString_Check(col)) {
if (!Bytes_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);
Bytes_AsStringAndSize(col, &colname, &collen);
if (offset + collen > DEFAULT_COPYBUFF - 2) {
Py_DECREF(col);
Py_DECREF(coliter);
@ -1417,7 +1429,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs)
self->copyfile = file;
/* At this point, the SQL statement must be str, not unicode */
if (pq_execute(self, PyString_AS_STRING(sql), 0) != 1) { goto fail; }
if (pq_execute(self, Bytes_AS_STRING(sql), 0) != 1) { goto fail; }
res = Py_None;
Py_INCREF(res);

View File

@ -119,7 +119,7 @@ psyco_lobj_read(lobjectObject *self, PyObject *args)
return NULL;
}
res = PyString_FromStringAndSize(buffer, size);
res = Bytes_FromStringAndSize(buffer, size);
PyMem_Free(buffer);
return res;

View File

@ -83,7 +83,11 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto)
Py_ssize_t i, ii;
type = Py_TYPE(obj);
if (!((Py_TPFLAGS_HAVE_CLASS & type->tp_flags) && type->tp_mro)) {
if (!(
#if PY_MAJOR_VERSION < 3
(Py_TPFLAGS_HAVE_CLASS & type->tp_flags) &&
#endif
type->tp_mro)) {
/* has no mro */
return NULL;
}
@ -134,7 +138,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
/* None is always adapted to NULL */
if (obj == Py_None)
return PyString_FromString("NULL");
return Text_FromUTF8("NULL");
Dprintf("microprotocols_adapt: trying to adapt %s",
Py_TYPE(obj)->tp_name);

View File

@ -78,7 +78,8 @@ notify_init(NotifyObject *self, PyObject *args, PyObject *kwargs)
}
if (!payload) {
payload = PyString_FromStringAndSize("", 0);
/* XXX review encoding */
payload = Text_FromUTF8AndSize("", 0);
}
Py_CLEAR(self->pid);
@ -213,7 +214,7 @@ notify_repr(NotifyObject *self)
PyObject *format = NULL;
PyObject *args = NULL;
if (!(format = PyString_FromString("Notify(%r, %r, %r)"))) {
if (!(format = Text_FromUTF8("Notify(%r, %r, %r)"))) {
goto exit;
}
@ -225,7 +226,7 @@ notify_repr(NotifyObject *self)
Py_INCREF(self->payload);
PyTuple_SET_ITEM(args, 2, self->payload);
rv = PyString_Format(format, args);
rv = Text_Format(format, args);
exit:
Py_XDECREF(args);

View File

@ -980,14 +980,15 @@ _pq_fetch_tuples(cursorObject *curs)
}
Dprintf("_pq_fetch_tuples: using cast at %p (%s) for type %d",
cast, PyString_AS_STRING(((typecastObject*)cast)->name),
cast, Bytes_AS_STRING(((typecastObject*)cast)->name),
PQftype(curs->pgres,i));
Py_INCREF(cast);
PyTuple_SET_ITEM(curs->casts, i, cast);
/* 1/ fill the other fields */
PyTuple_SET_ITEM(dtitem, 0,
PyString_FromString(PQfname(curs->pgres, i)));
/* XXX guaranteed to be ASCII/UTF8? */
Text_FromUTF8(PQfname(curs->pgres, i)));
PyTuple_SET_ITEM(dtitem, 1, type);
/* 2/ display size is the maximum size of this field result tuples. */
@ -1066,13 +1067,13 @@ _pq_copy_in_v3(cursorObject *curs)
while (1) {
o = PyObject_CallFunctionObjArgs(func, size, NULL);
if (!(o && PyString_Check(o) && (length = PyString_GET_SIZE(o)) != -1)) {
if (!(o && Bytes_Check(o) && (length = Bytes_GET_SIZE(o)) != -1)) {
error = 1;
}
if (length == 0 || length > INT_MAX || error == 1) break;
Py_BEGIN_ALLOW_THREADS;
res = PQputCopyData(curs->conn->pgconn, PyString_AS_STRING(o),
res = PQputCopyData(curs->conn->pgconn, Bytes_AS_STRING(o),
/* Py_ssize_t->int cast was validated above */
(int) length);
Dprintf("_pq_copy_in_v3: sent %d bytes of data; res = %d",
@ -1219,7 +1220,7 @@ pq_fetch(cursorObject *curs)
/* backend status message */
Py_XDECREF(curs->pgstatus);
curs->pgstatus = PyString_FromString(PQcmdStatus(curs->pgres));
curs->pgstatus = Text_FromUTF8(PQcmdStatus(curs->pgres));
switch(pgstatus) {

View File

@ -126,17 +126,38 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
return NULL;
}
#if PY_MAJOR_VERSION < 3
if (pyport && PyString_Check(pyport)) {
PyObject *pyint = PyInt_FromString(PyString_AsString(pyport), NULL, 10);
if (!pyint) goto fail;
/* Must use PyInt_AsLong rather than PyInt_AS_LONG, because
* PyInt_FromString can return a PyLongObject: */
iport = PyInt_AsLong(pyint);
Py_DECREF(pyint);
PyObject *pyint = PyInt_FromString(PyString_AsString(pyport), NULL, 10);
if (!pyint) goto fail;
/* Must use PyInt_AsLong rather than PyInt_AS_LONG, because
* PyInt_FromString can return a PyLongObject: */
iport = PyInt_AsLong(pyint);
Py_DECREF(pyint);
if (iport == -1 && PyErr_Occurred())
goto fail;
}
else if (pyport && PyInt_Check(pyport)) {
iport = PyInt_AsLong(pyport);
iport = PyInt_AsLong(pyport);
if (iport == -1 && PyErr_Occurred())
goto fail;
}
#else
if (pyport && PyUnicode_Check(pyport)) {
PyObject *pyint = PyObject_CallFunction((PyObject*)&PyLong_Type,
"Oi", pyport, 10);
if (!pyint) goto fail;
iport = PyLong_AsLong(pyint);
Py_DECREF(pyint);
if (iport == -1 && PyErr_Occurred())
goto fail;
}
else if (pyport && PyLong_Check(pyport)) {
iport = PyLong_AsLong(pyport);
if (iport == -1 && PyErr_Occurred())
goto fail;
}
#endif
else if (pyport != NULL) {
PyErr_SetString(PyExc_TypeError, "port must be a string or int");
goto fail;
@ -288,13 +309,23 @@ psyco_adapters_init(PyObject *mod)
PyTypeObject *type;
microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&pfloatType);
#if PY_MAJOR_VERSION < 3
microprotocols_add(&PyInt_Type, NULL, (PyObject*)&asisType);
#endif
microprotocols_add(&PyLong_Type, NULL, (PyObject*)&asisType);
microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType);
#if PY_MAJOR_VERSION < 3
microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType);
#endif
microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType);
#if PY_MAJOR_VERSION < 3
microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType);
#else
microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType);
microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType);
microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType);
#endif
microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType);
if ((type = (PyTypeObject*)psyco_GetDecimalType()) != NULL)
@ -407,7 +438,7 @@ static void psyco_encodings_fill(PyObject *dict)
encodingPair *enc;
for (enc = encodings; enc->pgenc != NULL; enc++) {
PyObject *value = PyString_FromString(enc->pyenc);
PyObject *value = Text_FromUTF8(enc->pyenc);
PyDict_SetItemString(dict, enc->pgenc, value);
Py_DECREF(value);
}
@ -472,12 +503,18 @@ psyco_errors_init(void)
dict = PyDict_New();
if (exctable[i].docstr) {
str = PyString_FromString(exctable[i].docstr);
str = Text_FromUTF8(exctable[i].docstr);
PyDict_SetItemString(dict, "__doc__", str);
}
if (exctable[i].base == 0)
if (exctable[i].base == 0) {
#if PY_MAJOR_VERSION < 3
base = PyExc_StandardError;
#else
/* StandardError is gone in 3.0 */
base = NULL;
#endif
}
else
base = *exctable[i].base;
@ -546,13 +583,16 @@ psyco_set_error(PyObject *exc, PyObject *curs, const char *msg,
if (err) {
if (pgerror) {
t = PyString_FromString(pgerror);
/* XXX is this always ASCII? If not, it needs
to be decoded properly for Python 3. */
t = Text_FromUTF8(pgerror);
PyObject_SetAttrString(err, "pgerror", t);
Py_DECREF(t);
}
if (pgcode) {
t = PyString_FromString(pgcode);
/* XXX likewise */
t = Text_FromUTF8(pgcode);
PyObject_SetAttrString(err, "pgcode", t);
Py_DECREF(t);
}
@ -703,12 +743,26 @@ static PyMethodDef psycopgMethods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */
};
#if PY_MAJOR_VERSION > 2
static struct PyModuleDef psycopgmodule = {
PyModuleDef_HEAD_INIT,
"_psycopg",
NULL,
-1,
psycopgMethods,
NULL,
NULL,
NULL,
NULL
};
#endif
PyMODINIT_FUNC
init_psycopg(void)
INIT_MODULE(_psycopg)(void)
{
static void *PSYCOPG_API[PSYCOPG_API_pointers];
PyObject *module, *dict;
PyObject *module = NULL, *dict;
PyObject *c_api_object;
#ifdef PSYCOPG_DEBUG
@ -734,36 +788,36 @@ init_psycopg(void)
Py_TYPE(&NotifyType) = &PyType_Type;
Py_TYPE(&XidType) = &PyType_Type;
if (PyType_Ready(&connectionType) == -1) return;
if (PyType_Ready(&cursorType) == -1) return;
if (PyType_Ready(&typecastType) == -1) return;
if (PyType_Ready(&qstringType) == -1) return;
if (PyType_Ready(&binaryType) == -1) return;
if (PyType_Ready(&isqlquoteType) == -1) return;
if (PyType_Ready(&pbooleanType) == -1) return;
if (PyType_Ready(&pfloatType) == -1) return;
if (PyType_Ready(&pdecimalType) == -1) return;
if (PyType_Ready(&asisType) == -1) return;
if (PyType_Ready(&listType) == -1) return;
if (PyType_Ready(&chunkType) == -1) return;
if (PyType_Ready(&NotifyType) == -1) return;
if (PyType_Ready(&XidType) == -1) return;
if (PyType_Ready(&connectionType) == -1) goto exit;
if (PyType_Ready(&cursorType) == -1) goto exit;
if (PyType_Ready(&typecastType) == -1) goto exit;
if (PyType_Ready(&qstringType) == -1) goto exit;
if (PyType_Ready(&binaryType) == -1) goto exit;
if (PyType_Ready(&isqlquoteType) == -1) goto exit;
if (PyType_Ready(&pbooleanType) == -1) goto exit;
if (PyType_Ready(&pfloatType) == -1) goto exit;
if (PyType_Ready(&pdecimalType) == -1) goto exit;
if (PyType_Ready(&asisType) == -1) goto exit;
if (PyType_Ready(&listType) == -1) goto exit;
if (PyType_Ready(&chunkType) == -1) goto exit;
if (PyType_Ready(&NotifyType) == -1) goto exit;
if (PyType_Ready(&XidType) == -1) goto exit;
#ifdef PSYCOPG_EXTENSIONS
Py_TYPE(&lobjectType) = &PyType_Type;
if (PyType_Ready(&lobjectType) == -1) return;
if (PyType_Ready(&lobjectType) == -1) goto exit;
#endif
/* import mx.DateTime module, if necessary */
#ifdef HAVE_MXDATETIME
Py_TYPE(&mxdatetimeType) = &PyType_Type;
if (PyType_Ready(&mxdatetimeType) == -1) return;
if (PyType_Ready(&mxdatetimeType) == -1) goto exit;
if (mxDateTime_ImportModuleAndAPI() != 0) {
Dprintf("initpsycopg: why marc hide mx.DateTime again?!");
PyErr_SetString(PyExc_ImportError, "can't import mx.DateTime module");
return;
goto exit;
}
if (psyco_adapter_mxdatetime_init()) { return; }
if (psyco_adapter_mxdatetime_init()) { goto exit; }
#endif
/* import python builtin datetime module, if available */
@ -771,22 +825,22 @@ init_psycopg(void)
if (pyDateTimeModuleP == NULL) {
Dprintf("initpsycopg: can't import datetime module");
PyErr_SetString(PyExc_ImportError, "can't import datetime module");
return;
goto exit;
}
/* Initialize the PyDateTimeAPI everywhere is used */
PyDateTime_IMPORT;
if (psyco_adapter_datetime_init()) { return; }
if (psyco_adapter_datetime_init()) { goto exit; }
Py_TYPE(&pydatetimeType) = &PyType_Type;
if (PyType_Ready(&pydatetimeType) == -1) return;
if (PyType_Ready(&pydatetimeType) == -1) goto exit;
/* import psycopg2.tz anyway (TODO: replace with C-level module?) */
pyPsycopgTzModule = PyImport_ImportModule("psycopg2.tz");
if (pyPsycopgTzModule == NULL) {
Dprintf("initpsycopg: can't import psycopg2.tz module");
PyErr_SetString(PyExc_ImportError, "can't import psycopg2.tz module");
return;
goto exit;
}
pyPsycopgTzLOCAL =
PyObject_GetAttrString(pyPsycopgTzModule, "LOCAL");
@ -794,7 +848,13 @@ init_psycopg(void)
PyObject_GetAttrString(pyPsycopgTzModule, "FixedOffsetTimezone");
/* initialize the module and grab module's dictionary */
#if PY_MAJOR_VERSION < 3
module = Py_InitModule("_psycopg", psycopgMethods);
#else
module = PyModule_Create(&psycopgmodule);
#endif
if (!module) { goto exit; }
dict = PyModule_GetDict(module);
/* initialize all the module's exported functions */
@ -812,9 +872,9 @@ init_psycopg(void)
/* set some module's parameters */
PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION);
PyModule_AddStringConstant(module, "__doc__", "psycopg PostgreSQL driver");
PyModule_AddObject(module, "apilevel", PyString_FromString(APILEVEL));
PyModule_AddObject(module, "apilevel", Text_FromUTF8(APILEVEL));
PyModule_AddObject(module, "threadsafety", PyInt_FromLong(THREADSAFETY));
PyModule_AddObject(module, "paramstyle", PyString_FromString(PARAMSTYLE));
PyModule_AddObject(module, "paramstyle", Text_FromUTF8(PARAMSTYLE));
/* put new types in module dictionary */
PyModule_AddObject(module, "connection", (PyObject*)&connectionType);
@ -866,4 +926,11 @@ init_psycopg(void)
#endif
Dprintf("initpsycopg: module initialization complete");
exit:
#if PY_MAJOR_VERSION > 2
return module;
#else
return;
#endif
}

View File

@ -74,4 +74,66 @@
#define FORMAT_CODE_SIZE_T "%zu"
#endif
/* Abstract from text type. Only supported for ASCII and UTF-8 */
#if PY_MAJOR_VERSION < 3
#define Text_Type PyString_Type
#define Text_Check(s) PyString_Check(s)
#define Text_Format(f,a) PyString_Format(f,a)
#define Text_FromUTF8(s) PyString_FromString(s)
#define Text_FromUTF8AndSize(s,n) PyString_FromStringAndSize(s,n)
/* f must contain exactly a %s placeholder */
#define Text_FromFormatS(f,s) PyString_FromFormat(f, PyString_AsString(s))
#define Text_S "%s"
#else
#define Text_Type PyUnicode_Type
#define Text_Check(s) PyUnicode_Check(s)
#define Text_Format(f,a) PyUnicode_Format(f,a)
#define Text_FromUTF8(s) PyUnicode_FromString(s)
#define Text_FromUTF8AndSize(s,n) PyUnicode_FromStringAndSize(s,n)
/* f must contain exactly a %U placeholder */
#define Text_FromFormatS(f,s) PyUnicode_FromFormat(f, s)
#define Text_S "%U"
#endif
#if PY_MAJOR_VERSION > 2
#define PyInt_Type PyLong_Type
#define PyInt_AsLong PyLong_AsLong
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromSsize_t PyLong_FromSsize_t
#define PyString_FromFormat PyUnicode_FromFormat
#define Py_TPFLAGS_HAVE_ITER 0L
#define Py_TPFLAGS_HAVE_RICHCOMPARE 0L
#ifndef PyNumber_Int
#define PyNumber_Int PyNumber_Long
#endif
#endif /* PY_MAJOR_VERSION > 2 */
#if PY_MAJOR_VERSION < 3
/* XXX BytesType -> Bytes_Type */
#define BytesType PyString_Type
#define Bytes_Check PyString_Check
#define Bytes_AS_STRING PyString_AS_STRING
#define Bytes_GET_SIZE PyString_GET_SIZE
#define Bytes_Size PyString_Size
#define Bytes_AsString PyString_AsString
#define Bytes_AsStringAndSize PyString_AsStringAndSize
#define Bytes_FromStringAndSize PyString_FromStringAndSize
#else
#define BytesType PyBytes_Type
#define Bytes_Check PyBytes_Check
#define Bytes_AS_STRING PyBytes_AS_STRING
#define Bytes_GET_SIZE PyBytes_GET_SIZE
#define Bytes_Size PyBytes_Size
#define Bytes_AsString PyBytes_AsString
#define Bytes_AsStringAndSize PyBytes_AsStringAndSize
#define Bytes_FromStringAndSize PyBytes_FromStringAndSize
#endif
/* Mangle the module name into the name of the module init function */
#if PY_MAJOR_VERSION > 2
#define INIT_MODULE(m) PyInit_ ## m
#else
#define INIT_MODULE(m) init ## m
#endif
#endif /* !defined(PSYCOPG_PYTHON_H) */

View File

@ -429,24 +429,22 @@ typecast_del(void *self)
static PyObject *
typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
{
PyObject *string, *cursor;
char *string;
Py_ssize_t length;
PyObject *cursor;
if (!PyArg_ParseTuple(args, "OO", &string, &cursor)) {
if (!PyArg_ParseTuple(args, "z#O", &string, &length, &cursor)) {
return NULL;
}
// If the string is not a string but a None value we're being called
// from a Python-defined caster. There is no need to convert, just
// return it.
if (string == Py_None) {
Py_INCREF(string);
return string;
// from a Python-defined caster.
if (!string) {
Py_INCREF(Py_None);
return Py_None;
}
return typecast_cast(obj,
PyString_AsString(string), PyString_Size(string),
cursor);
return typecast_cast(obj, string, length, cursor);
}
PyTypeObject typecastType = {
@ -560,7 +558,7 @@ typecast_from_python(PyObject *self, PyObject *args, PyObject *keywds)
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!OO", kwlist,
&PyTuple_Type, &v,
&PyString_Type, &name,
&Text_Type, &name,
&cast, &base)) {
return NULL;
}
@ -585,7 +583,7 @@ typecast_from_c(typecastObject_initlist *type, PyObject *dict)
}
}
name = PyString_FromString(type->name);
name = Text_FromUTF8(type->name);
if (!name) goto end;
while (type->values[len] != 0) len++;

View File

@ -25,6 +25,7 @@
/** INTEGER - cast normal integers (4 bytes) to python int **/
#if PY_MAJOR_VERSION < 3
static PyObject *
typecast_INTEGER_cast(const char *s, Py_ssize_t len, PyObject *curs)
{
@ -37,6 +38,9 @@ typecast_INTEGER_cast(const char *s, Py_ssize_t len, PyObject *curs)
}
return PyInt_FromString((char *)s, NULL, 0);
}
#else
#define typecast_INTEGER_cast typecast_LONGINTEGER_cast
#endif
/** LONGINTEGER - cast long integers (8 bytes) to python long **/
@ -59,23 +63,30 @@ static PyObject *
typecast_FLOAT_cast(const char *s, Py_ssize_t len, PyObject *curs)
{
PyObject *str = NULL, *flo = NULL;
char *pend;
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
str = PyString_FromStringAndSize(s, len);
flo = PyFloat_FromString(str, &pend);
str = Text_FromUTF8AndSize(s, len);
#if PY_MAJOR_VERSION < 3
flo = PyFloat_FromString(str, NULL);
#else
flo = PyFloat_FromString(str);
#endif
Py_DECREF(str);
return flo;
}
/** STRING - cast strings of any type to python string **/
#if PY_MAJOR_VERSION < 3
static PyObject *
typecast_STRING_cast(const char *s, Py_ssize_t len, PyObject *curs)
{
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
return PyString_FromStringAndSize(s, len);
}
#else
#define typecast_STRING_cast typecast_UNICODE_cast
#endif
/** UNICODE - cast strings of any type to a python unicode object **/

View File

@ -53,6 +53,9 @@ chunk_repr(chunkObject *self)
);
}
#if PY_MAJOR_VERSION < 3
/* XXX support 3.0 buffer protocol */
static Py_ssize_t
chunk_getreadbuffer(chunkObject *self, Py_ssize_t segment, void **ptr)
{
@ -82,6 +85,22 @@ static PyBufferProcs chunk_as_buffer =
(charbufferproc) NULL
};
#else
/* 3.0 buffer interface */
int chunk_getbuffer(PyObject *_self, Py_buffer *view, int flags)
{
chunkObject *self = (chunkObject*)_self;
return PyBuffer_FillInfo(view, _self, self->base, self->len, 1, flags);
}
static PyBufferProcs chunk_as_buffer =
{
chunk_getbuffer,
NULL,
};
#endif
#define chunk_doc "memory chunk"
PyTypeObject chunkType = {
@ -156,8 +175,13 @@ typecast_BINARY_cast(const char *s, Py_ssize_t l, PyObject *curs)
/* size_t->Py_ssize_t cast was validated above: */
chunk->len = (Py_ssize_t) len;
#if PY_MAJOR_VERSION < 3
if ((res = PyBuffer_FromObject((PyObject *)chunk, 0, chunk->len)) == NULL)
goto fail;
#else
if ((res = PyMemoryView_FromObject((PyObject*)chunk)) == NULL)
goto fail;
#endif
/* PyBuffer_FromObject() created a new reference. We'll release our
* reference held in 'chunk' in the 'cleanup' clause. */

View File

@ -150,11 +150,11 @@ xid_init(XidObject *self, PyObject *args, PyObject *kwargs)
Py_XDECREF(tmp);
tmp = self->gtrid;
self->gtrid = PyString_FromString(gtrid);
self->gtrid = Text_FromUTF8(gtrid);
Py_XDECREF(tmp);
tmp = self->bqual;
self->bqual = PyString_FromString(bqual);
self->bqual = Text_FromUTF8(bqual);
Py_XDECREF(tmp);
return 0;
@ -233,7 +233,7 @@ xid_repr(XidObject *self)
PyObject *args = NULL;
if (Py_None == self->format_id) {
if (!(format = PyString_FromString("<Xid: %r (unparsed)>"))) {
if (!(format = Text_FromUTF8("<Xid: %r (unparsed)>"))) {
goto exit;
}
if (!(args = PyTuple_New(1))) { goto exit; }
@ -241,7 +241,7 @@ xid_repr(XidObject *self)
PyTuple_SET_ITEM(args, 0, self->gtrid);
}
else {
if (!(format = PyString_FromString("<Xid: (%r, %r, %r)>"))) {
if (!(format = Text_FromUTF8("<Xid: (%r, %r, %r)>"))) {
goto exit;
}
if (!(args = PyTuple_New(3))) { goto exit; }
@ -253,7 +253,7 @@ xid_repr(XidObject *self)
PyTuple_SET_ITEM(args, 2, self->bqual);
}
rv = PyString_Format(format, args);
rv = Text_Format(format, args);
exit:
Py_XDECREF(args);
@ -457,7 +457,7 @@ xid_get_tid(XidObject *self)
if (!(ebqual = _xid_encode64(self->bqual))) { goto exit; }
/* rv = "%d_%s_%s" % (format_id, egtrid, ebqual) */
if (!(format = PyString_FromString("%d_%s_%s"))) { goto exit; }
if (!(format = Text_FromUTF8("%d_%s_%s"))) { goto exit; }
if (!(args = PyTuple_New(3))) { goto exit; }
Py_INCREF(self->format_id);
@ -465,7 +465,7 @@ xid_get_tid(XidObject *self)
PyTuple_SET_ITEM(args, 1, egtrid); egtrid = NULL;
PyTuple_SET_ITEM(args, 2, ebqual); ebqual = NULL;
if (!(rv = PyString_Format(format, args))) { goto exit; }
if (!(rv = Text_Format(format, args))) { goto exit; }
}
exit:
@ -621,7 +621,7 @@ XidObject *
xid_from_string(PyObject *str) {
XidObject *rv;
if (!(PyString_Check(str) || PyUnicode_Check(str))) {
if (!(Bytes_Check(str) || PyUnicode_Check(str))) {
PyErr_SetString(PyExc_TypeError, "not a valid transaction id");
return NULL;
}