mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-01-31 17:34:08 +03:00
parent
b3b225a9da
commit
f99a8de6d0
|
@ -39,6 +39,10 @@ typedef struct {
|
||||||
PyObject *scale;
|
PyObject *scale;
|
||||||
PyObject *null_ok;
|
PyObject *null_ok;
|
||||||
|
|
||||||
|
/* Extensions to the DBAPI */
|
||||||
|
PyObject *table_oid;
|
||||||
|
PyObject *table_column;
|
||||||
|
|
||||||
} columnObject;
|
} columnObject;
|
||||||
|
|
||||||
#endif /* PSYCOPG_COLUMN_H */
|
#endif /* PSYCOPG_COLUMN_H */
|
||||||
|
|
|
@ -62,7 +62,15 @@ static const char scale_doc[] =
|
||||||
"None for other types.";
|
"None for other types.";
|
||||||
|
|
||||||
static const char null_ok_doc[] =
|
static const char null_ok_doc[] =
|
||||||
"Always none.\n\n";
|
"Always none.";
|
||||||
|
|
||||||
|
static const char table_oid_doc[] =
|
||||||
|
"The OID of the table from which the column was fetched.\n\n"
|
||||||
|
"None if not available";
|
||||||
|
|
||||||
|
static const char table_column_doc[] =
|
||||||
|
"The number (within its table) of the column making up the result\n\n"
|
||||||
|
"None if not available. Note that PostgreSQL column numbers start at 1";
|
||||||
|
|
||||||
|
|
||||||
static PyMemberDef column_members[] = {
|
static PyMemberDef column_members[] = {
|
||||||
|
@ -73,6 +81,8 @@ static PyMemberDef column_members[] = {
|
||||||
{ "precision", T_OBJECT, offsetof(columnObject, precision), READONLY, (char *)precision_doc },
|
{ "precision", T_OBJECT, offsetof(columnObject, precision), READONLY, (char *)precision_doc },
|
||||||
{ "scale", T_OBJECT, offsetof(columnObject, scale), READONLY, (char *)scale_doc },
|
{ "scale", T_OBJECT, offsetof(columnObject, scale), READONLY, (char *)scale_doc },
|
||||||
{ "null_ok", T_OBJECT, offsetof(columnObject, null_ok), READONLY, (char *)null_ok_doc },
|
{ "null_ok", T_OBJECT, offsetof(columnObject, null_ok), READONLY, (char *)null_ok_doc },
|
||||||
|
{ "table_oid", T_OBJECT, offsetof(columnObject, table_oid), READONLY, (char *)table_oid_doc },
|
||||||
|
{ "table_column", T_OBJECT, offsetof(columnObject, table_column), READONLY, (char *)table_column_doc },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,12 +99,12 @@ column_init(columnObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
static char *kwlist[] = {
|
static char *kwlist[] = {
|
||||||
"name", "type_code", "display_size", "internal_size",
|
"name", "type_code", "display_size", "internal_size",
|
||||||
"precision", "scale", "null_ok", NULL};
|
"precision", "scale", "null_ok", "table_oid", "table_column", NULL};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOOOO", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOOOOOO", kwlist,
|
||||||
&self->name, &self->type_code, &self->display_size,
|
&self->name, &self->type_code, &self->display_size,
|
||||||
&self->internal_size, &self->precision, &self->scale,
|
&self->internal_size, &self->precision, &self->scale,
|
||||||
&self->null_ok)) {
|
&self->null_ok, &self->table_oid, &self->table_column)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +122,8 @@ column_dealloc(columnObject *self)
|
||||||
Py_CLEAR(self->precision);
|
Py_CLEAR(self->precision);
|
||||||
Py_CLEAR(self->scale);
|
Py_CLEAR(self->scale);
|
||||||
Py_CLEAR(self->null_ok);
|
Py_CLEAR(self->null_ok);
|
||||||
|
Py_CLEAR(self->table_oid);
|
||||||
|
Py_CLEAR(self->table_column);
|
||||||
|
|
||||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
}
|
}
|
||||||
|
@ -294,6 +306,16 @@ column_setstate(columnObject *self, PyObject *state)
|
||||||
self->null_ok = PyTuple_GET_ITEM(state, 6);
|
self->null_ok = PyTuple_GET_ITEM(state, 6);
|
||||||
Py_INCREF(self->null_ok);
|
Py_INCREF(self->null_ok);
|
||||||
}
|
}
|
||||||
|
if (size > 7) {
|
||||||
|
Py_CLEAR(self->table_oid);
|
||||||
|
self->table_oid = PyTuple_GET_ITEM(state, 7);
|
||||||
|
Py_INCREF(self->table_oid);
|
||||||
|
}
|
||||||
|
if (size > 8) {
|
||||||
|
Py_CLEAR(self->table_column);
|
||||||
|
self->table_column = PyTuple_GET_ITEM(state, 8);
|
||||||
|
Py_INCREF(self->table_column);
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
rv = Py_None;
|
rv = Py_None;
|
||||||
|
|
|
@ -1207,6 +1207,8 @@ _pq_fetch_tuples(cursorObject *curs)
|
||||||
Oid ftype = PQftype(curs->pgres, i);
|
Oid ftype = PQftype(curs->pgres, i);
|
||||||
int fsize = PQfsize(curs->pgres, i);
|
int fsize = PQfsize(curs->pgres, i);
|
||||||
int fmod = PQfmod(curs->pgres, i);
|
int fmod = PQfmod(curs->pgres, i);
|
||||||
|
Oid ftable = PQftable(curs->pgres, i);
|
||||||
|
int ftablecol = PQftablecol(curs->pgres, i);
|
||||||
|
|
||||||
columnObject *column = NULL;
|
columnObject *column = NULL;
|
||||||
PyObject *type = NULL;
|
PyObject *type = NULL;
|
||||||
|
@ -1299,7 +1301,18 @@ _pq_fetch_tuples(cursorObject *curs)
|
||||||
column->scale = tmp;
|
column->scale = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 6/ FIXME: null_ok??? */
|
/* table_oid, table_column */
|
||||||
|
if (ftable != InvalidOid) {
|
||||||
|
PyObject *tmp;
|
||||||
|
if (!(tmp = PyInt_FromLong((long)ftable))) { goto err_for; }
|
||||||
|
column->table_oid = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftablecol > 0) {
|
||||||
|
PyObject *tmp;
|
||||||
|
if (!(tmp = PyInt_FromLong((long)ftablecol))) { goto err_for; }
|
||||||
|
column->table_column = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
PyTuple_SET_ITEM(description, i, (PyObject *)column);
|
PyTuple_SET_ITEM(description, i, (PyObject *)column);
|
||||||
column = NULL;
|
column = NULL;
|
||||||
|
|
|
@ -377,7 +377,7 @@ class CursorTests(ConnectingTestCase):
|
||||||
for i, rec in enumerate(curs):
|
for i, rec in enumerate(curs):
|
||||||
self.assertEqual(i + 1, curs.rownumber)
|
self.assertEqual(i + 1, curs.rownumber)
|
||||||
|
|
||||||
def test_namedtuple_description(self):
|
def test_description_attribs(self):
|
||||||
curs = self.conn.cursor()
|
curs = self.conn.cursor()
|
||||||
curs.execute("""select
|
curs.execute("""select
|
||||||
3.14::decimal(10,2) as pi,
|
3.14::decimal(10,2) as pi,
|
||||||
|
@ -412,6 +412,27 @@ class CursorTests(ConnectingTestCase):
|
||||||
self.assertEqual(c.precision, None)
|
self.assertEqual(c.precision, None)
|
||||||
self.assertEqual(c.scale, None)
|
self.assertEqual(c.scale, None)
|
||||||
|
|
||||||
|
def test_description_extra_attribs(self):
|
||||||
|
curs = self.conn.cursor()
|
||||||
|
curs.execute("""
|
||||||
|
create table testcol (
|
||||||
|
pi decimal(10,2),
|
||||||
|
hi text)
|
||||||
|
""")
|
||||||
|
curs.execute("select oid from pg_class where relname = %s", ('testcol',))
|
||||||
|
oid = curs.fetchone()[0]
|
||||||
|
|
||||||
|
curs.execute("insert into testcol values (3.14, 'hello')")
|
||||||
|
curs.execute("select hi, pi, 42 from testcol")
|
||||||
|
self.assertEqual(curs.description[0].table_oid, oid)
|
||||||
|
self.assertEqual(curs.description[0].table_column, 2)
|
||||||
|
|
||||||
|
self.assertEqual(curs.description[1].table_oid, oid)
|
||||||
|
self.assertEqual(curs.description[1].table_column, 1)
|
||||||
|
|
||||||
|
self.assertEqual(curs.description[2].table_oid, None)
|
||||||
|
self.assertEqual(curs.description[2].table_column, None)
|
||||||
|
|
||||||
def test_pickle_description(self):
|
def test_pickle_description(self):
|
||||||
curs = self.conn.cursor()
|
curs = self.conn.cursor()
|
||||||
curs.execute('SELECT 1 AS foo')
|
curs.execute('SELECT 1 AS foo')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user