summaryrefslogtreecommitdiff
path: root/psycopg/column_type.c
diff options
context:
space:
mode:
Diffstat (limited to 'psycopg/column_type.c')
-rw-r--r--psycopg/column_type.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/psycopg/column_type.c b/psycopg/column_type.c
new file mode 100644
index 0000000..8ee7d4c
--- /dev/null
+++ b/psycopg/column_type.c
@@ -0,0 +1,375 @@
+/* column_type.c - python interface to cursor.description objects
+ *
+ * Copyright (C) 2018 Daniele Varrazzo <daniele.varrazzo@gmail.com>
+ *
+ * This file is part of psycopg.
+ *
+ * psycopg2 is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link this program with the OpenSSL library (or with
+ * modified versions of OpenSSL that use the same license as OpenSSL),
+ * and distribute linked combinations including the two.
+ *
+ * You must obey the GNU Lesser General Public License in all respects for
+ * all of the code used other than OpenSSL.
+ *
+ * psycopg2 is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ */
+
+#define PSYCOPG_MODULE
+#include "psycopg/psycopg.h"
+
+#include "psycopg/column.h"
+
+
+static const char column_doc[] =
+ "Description of a column returned by a query.\n\n"
+ "The DBAPI demands this object to be a 7-items sequence. This object\n"
+ "respects this interface, but adds names for the exposed attributes\n"
+ "and adds attribute not requested by the DBAPI.";
+
+static const char name_doc[] =
+ "The name of the column returned.";
+
+static const char type_code_doc[] =
+ "The PostgreSQL OID of the column.\n\n"
+ "You can use the pg_type system table to get more informations about the\n"
+ "type. This is the value used by Psycopg to decide what Python type use\n"
+ "to represent the value";
+
+static const char display_size_doc[] =
+ "The actual length of the column in bytes.\n\n"
+ "Obtaining this value is computationally intensive, so it is always None\n"
+ "unless the PSYCOPG_DISPLAY_SIZE parameter is set at compile time.";
+
+static const char internal_size_doc[] =
+ "The size in bytes of the column associated to this column on the server.\n\n"
+ "Set to a negative value for variable-size types.";
+
+static const char precision_doc[] =
+ "Total number of significant digits in columns of type NUMERIC.\n\n"
+ "None for other types.";
+
+static const char scale_doc[] =
+ "Count of decimal digits in the fractional part in columns of type NUMERIC.\n\n"
+ "None for other types.";
+
+static const char null_ok_doc[] =
+ "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[] = {
+ { "name", T_OBJECT, offsetof(columnObject, name), READONLY, (char *)name_doc },
+ { "type_code", T_OBJECT, offsetof(columnObject, type_code), READONLY, (char *)type_code_doc },
+ { "display_size", T_OBJECT, offsetof(columnObject, display_size), READONLY, (char *)display_size_doc },
+ { "internal_size", T_OBJECT, offsetof(columnObject, internal_size), READONLY, (char *)internal_size_doc },
+ { "precision", T_OBJECT, offsetof(columnObject, precision), READONLY, (char *)precision_doc },
+ { "scale", T_OBJECT, offsetof(columnObject, scale), READONLY, (char *)scale_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 }
+};
+
+
+static PyObject *
+column_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ return type->tp_alloc(type, 0);
+}
+
+
+static int
+column_init(columnObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {
+ "name", "type_code", "display_size", "internal_size",
+ "precision", "scale", "null_ok", "table_oid", "table_column", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOOOOOO", kwlist,
+ &self->name, &self->type_code, &self->display_size,
+ &self->internal_size, &self->precision, &self->scale,
+ &self->null_ok, &self->table_oid, &self->table_column)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void
+column_dealloc(columnObject *self)
+{
+ Py_CLEAR(self->name);
+ Py_CLEAR(self->type_code);
+ Py_CLEAR(self->display_size);
+ Py_CLEAR(self->internal_size);
+ Py_CLEAR(self->precision);
+ Py_CLEAR(self->scale);
+ Py_CLEAR(self->null_ok);
+ Py_CLEAR(self->table_oid);
+ Py_CLEAR(self->table_column);
+
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+
+static PyObject*
+column_repr(columnObject *self)
+{
+ PyObject *rv = NULL;
+ PyObject *format = NULL;
+ PyObject *args = NULL;
+ PyObject *tmp;
+
+ if (!(format = Text_FromUTF8("Column(name=%r, type_code=%r)"))) {
+ goto exit;
+ }
+
+ if (!(args = PyTuple_New(2))) { goto exit; }
+
+ tmp = self->name ? self->name : Py_None;
+ Py_INCREF(tmp);
+ PyTuple_SET_ITEM(args, 0, tmp);
+
+ tmp = self->type_code ? self->type_code : Py_None;
+ Py_INCREF(tmp);
+ PyTuple_SET_ITEM(args, 1, tmp);
+
+ rv = Text_Format(format, args);
+
+exit:
+ Py_XDECREF(args);
+ Py_XDECREF(format);
+
+ return rv;
+}
+
+
+static PyObject *
+column_richcompare(columnObject *self, PyObject *other, int op)
+{
+ PyObject *rv = NULL;
+ PyObject *tself = NULL;
+
+ if (!(tself = PyObject_CallFunctionObjArgs(
+ (PyObject *)&PyTuple_Type, (PyObject *)self, NULL))) {
+ goto exit;
+ }
+
+ rv = PyObject_RichCompare(tself, other, op);
+
+exit:
+ Py_XDECREF(tself);
+ return rv;
+}
+
+
+/* column description can be accessed as a 7 items tuple for DBAPI compatibility */
+
+static Py_ssize_t
+column_len(columnObject *self)
+{
+ return 7;
+}
+
+
+static PyObject *
+column_getitem(columnObject *self, Py_ssize_t item)
+{
+ PyObject *rv = NULL;
+
+ if (item < 0)
+ item += 7;
+
+ switch (item) {
+ case 0:
+ rv = self->name;
+ break;
+ case 1:
+ rv = self->type_code;
+ break;
+ case 2:
+ rv = self->display_size;
+ break;
+ case 3:
+ rv = self->internal_size;
+ break;
+ case 4:
+ rv = self->precision;
+ break;
+ case 5:
+ rv = self->scale;
+ break;
+ case 6:
+ rv = self->null_ok;
+ break;
+ default:
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+
+ if (!rv) {
+ rv = Py_None;
+ }
+
+ Py_INCREF(rv);
+ return rv;
+}
+
+
+static PySequenceMethods column_sequence = {
+ (lenfunc)column_len, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc)column_getitem, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ 0, /* sq_contains */
+ 0, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
+};
+
+
+static PyObject *
+column_getstate(columnObject *self)
+{
+ return PyObject_CallFunctionObjArgs(
+ (PyObject *)&PyTuple_Type, (PyObject *)self, NULL);
+}
+
+
+PyObject *
+column_setstate(columnObject *self, PyObject *state)
+{
+ Py_ssize_t size;
+ PyObject *rv = NULL;
+
+ if (state == Py_None) {
+ goto exit;
+ }
+ if (!PyTuple_Check(state)) {
+ PyErr_SetString(PyExc_TypeError, "state is not a tuple");
+ goto error;
+ }
+
+ size = PyTuple_GET_SIZE(state);
+
+ if (size > 0) {
+ Py_CLEAR(self->name);
+ self->name = PyTuple_GET_ITEM(state, 0);
+ Py_INCREF(self->name);
+ }
+ if (size > 1) {
+ Py_CLEAR(self->type_code);
+ self->type_code = PyTuple_GET_ITEM(state, 1);
+ Py_INCREF(self->type_code);
+ }
+ if (size > 2) {
+ Py_CLEAR(self->display_size);
+ self->display_size = PyTuple_GET_ITEM(state, 2);
+ Py_INCREF(self->display_size);
+ }
+ if (size > 3) {
+ Py_CLEAR(self->internal_size);
+ self->internal_size = PyTuple_GET_ITEM(state, 3);
+ Py_INCREF(self->internal_size);
+ }
+ if (size > 4) {
+ Py_CLEAR(self->precision);
+ self->precision = PyTuple_GET_ITEM(state, 4);
+ Py_INCREF(self->precision);
+ }
+ if (size > 5) {
+ Py_CLEAR(self->scale);
+ self->scale = PyTuple_GET_ITEM(state, 5);
+ Py_INCREF(self->scale);
+ }
+ if (size > 6) {
+ Py_CLEAR(self->null_ok);
+ self->null_ok = PyTuple_GET_ITEM(state, 6);
+ 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:
+ rv = Py_None;
+ Py_INCREF(rv);
+
+error:
+ return rv;
+}
+
+
+static PyMethodDef column_methods[] = {
+ /* Make Column picklable. */
+ {"__getstate__", (PyCFunction)column_getstate, METH_NOARGS },
+ {"__setstate__", (PyCFunction)column_setstate, METH_O },
+ {NULL}
+};
+
+
+PyTypeObject columnType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "psycopg2.extensions.Column",
+ sizeof(columnObject), 0,
+ (destructor)column_dealloc, /* tp_dealloc */
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)column_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ &column_sequence, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ column_doc, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ (richcmpfunc)column_richcompare, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ column_methods, /*tp_methods*/
+ column_members, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ (initproc)column_init, /*tp_init*/
+ 0, /*tp_alloc*/
+ column_new, /*tp_new*/
+};