Author: cito
Date: Thu Nov 26 15:32:19 2015
New Revision: 639
Log:
Backport of recently added features to 4.x
Ported the support for bool objects and the additional getter
functions back from the trunk to 4.x. The bool object support
is disabled by support, so we stay fully backward compatible.
The docs for these features have already been taken over.
Modified:
branches/4.x/module/TEST_PyGreSQL_classic_connection.py
branches/4.x/module/TEST_PyGreSQL_dbapi20.py
branches/4.x/module/pgmodule.c
Modified: branches/4.x/module/TEST_PyGreSQL_classic_connection.py
==============================================================================
--- branches/4.x/module/TEST_PyGreSQL_classic_connection.py Thu Nov 26
15:03:45 2015 (r638)
+++ branches/4.x/module/TEST_PyGreSQL_classic_connection.py Thu Nov 26
15:32:19 2015 (r639)
@@ -519,26 +519,34 @@
self.assertEqual(self.c.query("select $1::text", [None]
).getresult(), [(None,)])
- def testQueryWithBoolParams(self):
+ def testQueryWithBoolParams(self, use_bool=None):
query = self.c.query
- self.assertEqual(query("select false").getresult(), [('f',)])
- self.assertEqual(query("select true").getresult(), [('t',)])
- self.assertEqual(query("select $1::bool", (None,)).getresult(),
- [(None,)])
- self.assertEqual(query("select $1::bool", ('f',)).getresult(),
[('f',)])
- self.assertEqual(query("select $1::bool", ('t',)).getresult(),
[('t',)])
- self.assertEqual(query("select $1::bool", ('false',)).getresult(),
- [('f',)])
- self.assertEqual(query("select $1::bool", ('true',)).getresult(),
- [('t',)])
- self.assertEqual(query("select $1::bool", ('n',)).getresult(),
[('f',)])
- self.assertEqual(query("select $1::bool", ('y',)).getresult(),
[('t',)])
- self.assertEqual(query("select $1::bool", (0,)).getresult(), [('f',)])
- self.assertEqual(query("select $1::bool", (1,)).getresult(), [('t',)])
- self.assertEqual(query("select $1::bool", (False,)).getresult(),
- [('f',)])
- self.assertEqual(query("select $1::bool", (True,)).getresult(),
- [('t',)])
+ if use_bool is not None:
+ use_bool_default = pg.get_bool()
+ pg.set_bool(use_bool)
+ try:
+ v_false, v_true = (False, True) if use_bool else 'ft'
+ r_false, r_true = [(v_false,)], [(v_true,)]
+ self.assertEqual(query("select false").getresult(), r_false)
+ self.assertEqual(query("select true").getresult(), r_true)
+ q = "select $1::bool"
+ self.assertEqual(query(q, (None,)).getresult(), [(None,)])
+ self.assertEqual(query(q, ('f',)).getresult(), r_false)
+ self.assertEqual(query(q, ('t',)).getresult(), r_true)
+ self.assertEqual(query(q, ('false',)).getresult(), r_false)
+ self.assertEqual(query(q, ('true',)).getresult(), r_true)
+ self.assertEqual(query(q, ('n',)).getresult(), r_false)
+ self.assertEqual(query(q, ('y',)).getresult(), r_true)
+ self.assertEqual(query(q, (0,)).getresult(), r_false)
+ self.assertEqual(query(q, (1,)).getresult(), r_true)
+ self.assertEqual(query(q, (False,)).getresult(), r_false)
+ self.assertEqual(query(q, (True,)).getresult(), r_true)
+ finally:
+ if use_bool is not None:
+ pg.set_bool(use_bool_default)
+
+ def testQueryWithBoolParamsAndUseBool(self):
+ self.testQueryWithBoolParams(use_bool=True)
def testQueryWithIntParams(self):
query = self.c.query
Modified: branches/4.x/module/TEST_PyGreSQL_dbapi20.py
==============================================================================
--- branches/4.x/module/TEST_PyGreSQL_dbapi20.py Thu Nov 26 15:03:45
2015 (r638)
+++ branches/4.x/module/TEST_PyGreSQL_dbapi20.py Thu Nov 26 15:32:19
2015 (r639)
@@ -156,6 +156,25 @@
else:
self.assertEqual(inval, outval)
+ def test_bool(self):
+ values = [False, True, None, 't', 'f', 'true', 'false']
+ table = self.table_prefix + 'booze'
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ cur.execute(
+ "create table %s (n smallint, booltest bool)" % table)
+ params = enumerate(values)
+ cur.executemany("insert into %s values (%%s,%%s)" % table, params)
+ cur.execute("select * from %s order by 1" % table)
+ rows = cur.fetchall()
+ finally:
+ con.close()
+ rows = [row[1] for row in rows]
+ values[3] = values[5] = True
+ values[4] = values[6] = False
+ self.assertEqual(rows, values)
+
def test_set_decimal_type(self):
decimal_type = pgdb.decimal_type()
self.assert_(decimal_type is not None and callable(decimal_type))
Modified: branches/4.x/module/pgmodule.c
==============================================================================
--- branches/4.x/module/pgmodule.c Thu Nov 26 15:03:45 2015 (r638)
+++ branches/4.x/module/pgmodule.c Thu Nov 26 15:32:19 2015 (r639)
@@ -120,7 +120,7 @@
static PyObject *decimal = NULL, /* decimal type */
*namedresult = NULL; /* function for getting
named results */
static char decimal_point = '.'; /* decimal point used in money values */
-
+static int use_bool = 0; /* whether or not bool objects shall be returned */
/* --------------------------------------------------------------------- */
/* OBJECTS DECLARATION */
@@ -337,6 +337,16 @@
return 1;
}
+/* define internal types */
+
+#define PYGRES_INT 1
+#define PYGRES_LONG 2
+#define PYGRES_FLOAT 3
+#define PYGRES_DECIMAL 4
+#define PYGRES_MONEY 5
+#define PYGRES_BOOL 6
+#define PYGRES_DEFAULT 7
+
/* shared functions for converting PG types to Python types */
int *
get_type_array(PGresult *result, int nfields)
@@ -357,28 +367,32 @@
case INT2OID:
case INT4OID:
case OIDOID:
- typ[j] = 1;
+ typ[j] = PYGRES_INT;
break;
case INT8OID:
- typ[j] = 2;
+ typ[j] = PYGRES_LONG;
break;
case FLOAT4OID:
case FLOAT8OID:
- typ[j] = 3;
+ typ[j] = PYGRES_FLOAT;
break;
case NUMERICOID:
- typ[j] = 4;
+ typ[j] = PYGRES_DECIMAL;
break;
case CASHOID:
- typ[j] = 5;
+ typ[j] = PYGRES_MONEY;
+ break;
+
+ case BOOLOID:
+ typ[j] = PYGRES_BOOL;
break;
default:
- typ[j] = 6;
+ typ[j] = PYGRES_DEFAULT;
break;
}
}
@@ -2155,21 +2169,21 @@
else
switch (typ[j])
{
- case 1: /* int2/4 */
+ case PYGRES_INT:
val = PyInt_FromString(s, NULL,
10);
break;
- case 2: /* int8 */
+ case PYGRES_LONG:
val = PyLong_FromString(s,
NULL, 10);
break;
- case 3: /* float/double */
+ case PYGRES_FLOAT:
tmp_obj =
PyString_FromString(s);
val =
PyFloat_FromString(tmp_obj, NULL);
Py_DECREF(tmp_obj);
break;
- case 5: /* money */
+ case PYGRES_MONEY:
/* convert to decimal only if
decimal point is set */
if (!decimal_point) goto
default_case;
for (k = 0;
@@ -2185,9 +2199,9 @@
}
cashbuf[k] = 0;
s = cashbuf;
+ /* FALLTHROUGH */ /* no break */
- /* FALLTHROUGH */ /* no break */
- case 4: /* numeric */
+ case PYGRES_DECIMAL:
if (decimal)
{
tmp_obj =
Py_BuildValue("(s)", s);
@@ -2201,6 +2215,16 @@
Py_DECREF(tmp_obj);
break;
+ case PYGRES_BOOL:
+ /* convert to bool only if
bool_type is set */
+ if (use_bool)
+ {
+ val = *s == 't' ?
Py_True : Py_False;
+ Py_INCREF(val);
+ break;
+ }
+ /* FALLTHROUGH */ /* no break */
+
default:
default_case:
val = PyString_FromString(s);
@@ -2285,21 +2309,21 @@
else
switch (typ[j])
{
- case 1: /* int2/4 */
+ case PYGRES_INT:
val = PyInt_FromString(s, NULL,
10);
break;
- case 2: /* int8 */
+ case PYGRES_LONG:
val = PyLong_FromString(s,
NULL, 10);
break;
- case 3: /* float/double */
+ case PYGRES_FLOAT:
tmp_obj =
PyString_FromString(s);
val =
PyFloat_FromString(tmp_obj, NULL);
Py_DECREF(tmp_obj);
break;
- case 5: /* money */
+ case PYGRES_MONEY:
/* convert to decimal only if
decimal point is set */
if (!decimal_point) goto
default_case;
@@ -2316,9 +2340,9 @@
}
cashbuf[k] = 0;
s = cashbuf;
+ /* FALLTHROUGH */ /* no break */
- /* FALLTHROUGH */ /* no break */
- case 4: /* numeric */
+ case PYGRES_DECIMAL:
if (decimal)
{
tmp_obj =
Py_BuildValue("(s)", s);
@@ -2332,6 +2356,16 @@
Py_DECREF(tmp_obj);
break;
+ case PYGRES_BOOL:
+ /* convert to bool only if
bool_type is set */
+ if (use_bool)
+ {
+ val = *s == 't' ?
Py_True : Py_False;
+ Py_INCREF(val);
+ break;
+ }
+ /* FALLTHROUGH */ /* no break */
+
default:
default_case:
val = PyString_FromString(s);
@@ -3700,9 +3734,38 @@
return ret;
}
+/* get decimal point */
+static char get_decimal_point__doc__[] =
+"get_decimal_point() -- get decimal point to be used for money values.";
+
+static PyObject *
+get_decimal_point(PyObject *self, PyObject * args)
+{
+ PyObject *ret = NULL;
+ char s[2];
+
+ if (PyArg_ParseTuple(args, ""))
+ {
+ if (decimal_point)
+ {
+ s[0] = decimal_point; s[1] = '\0';
+ ret = PyString_FromString(s);
+ } else {
+ Py_INCREF(Py_None); ret = Py_None;
+ }
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "get_decimal_point() takes no parameter");
+ }
+
+ return ret;
+}
+
/* set decimal point */
static char set_decimal_point__doc__[] =
-"set_decimal_point() -- set decimal point to be used for money values.";
+"set_decimal_point(char) -- set decimal point to be used for money values.";
static PyObject *
set_decimal_point(PyObject *self, PyObject * args)
@@ -3729,35 +3792,25 @@
return ret;
}
-/* get decimal point */
-static char get_decimal_point__doc__[] =
-"get_decimal_point() -- get decimal point to be used for money values.";
+/* get decimal type */
+static char get_decimal__doc__[] =
+"get_decimal() -- set a decimal type to be used for numeric values.";
static PyObject *
-get_decimal_point(PyObject *self, PyObject * args)
+get_decimal(PyObject *self, PyObject *args)
{
PyObject *ret = NULL;
- char s[2];
if (PyArg_ParseTuple(args, ""))
{
- if (decimal_point) {
- s[0] = decimal_point; s[1] = '\0';
- ret = PyString_FromString(s);
- } else {
- Py_INCREF(Py_None); ret = Py_None;
- }
- }
- else
- {
- PyErr_SetString(PyExc_TypeError,
- "get_decimal_point() takes no parameter");
+ ret = decimal ? decimal : Py_None;
+ Py_INCREF(ret);
}
return ret;
}
-/* set decimal */
+/* set decimal type */
static char set_decimal__doc__[] =
"set_decimal(cls) -- set a decimal type to be used for numeric values.";
@@ -3780,12 +3833,70 @@
Py_INCREF(Py_None); ret = Py_None;
}
else
- PyErr_SetString(PyExc_TypeError, "decimal type must be
None or callable");
+ PyErr_SetString(PyExc_TypeError,
+ "decimal type must be None or callable");
+ }
+
+ return ret;
+}
+
+/* get usage of bool values */
+static char get_bool__doc__[] =
+"get_bool() -- check whether boolean values are converted to bool.";
+
+static PyObject *
+get_bool(PyObject *self, PyObject * args)
+{
+ PyObject *ret = NULL;
+
+ if (PyArg_ParseTuple(args, ""))
+ {
+ ret = use_bool ? Py_True : Py_False;
+ Py_INCREF(ret);
+ }
+
+ return ret;
+}
+
+/* set usage of bool values */
+static char set_bool__doc__[] =
+"set_bool(bool) -- set whether boolean values should be converted to bool.";
+
+static PyObject *
+set_bool(PyObject *self, PyObject * args)
+{
+ PyObject *ret = NULL;
+ int i;
+
+ /* gets arguments */
+ if (PyArg_ParseTuple(args, "i", &i))
+ {
+ use_bool = i ? 1 : 0;
+ Py_INCREF(Py_None); ret = Py_None;
+ }
+
+ return ret;
+}
+
+/* get named result factory */
+static char get_namedresult__doc__[] =
+"get_namedresult(cls) -- get the function used for getting named results.";
+
+static PyObject *
+get_namedresult(PyObject *self, PyObject *args)
+{
+ PyObject *ret = NULL;
+
+ if (PyArg_ParseTuple(args, ""))
+ {
+ ret = namedresult ? namedresult : Py_None;
+ Py_INCREF(ret);
}
+
return ret;
}
-/* set named result */
+/* set named result factory */
static char set_namedresult__doc__[] =
"set_namedresult(cls) -- set a function to be used for getting named results.";
@@ -3805,6 +3916,7 @@
else
PyErr_SetString(PyExc_TypeError, "parameter must be
callable");
}
+
return ret;
}
@@ -4159,12 +4271,18 @@
escape_bytea__doc__},
{"unescape_bytea", (PyCFunction) unescape_bytea, METH_VARARGS,
unescape_bytea__doc__},
- {"set_decimal_point", (PyCFunction) set_decimal_point, METH_VARARGS,
- set_decimal_point__doc__},
{"get_decimal_point", (PyCFunction) get_decimal_point, METH_VARARGS,
get_decimal_point__doc__},
+ {"set_decimal_point", (PyCFunction) set_decimal_point, METH_VARARGS,
+ set_decimal_point__doc__},
+ {"get_decimal", (PyCFunction) get_decimal, METH_VARARGS,
+ get_decimal__doc__},
{"set_decimal", (PyCFunction) set_decimal, METH_VARARGS,
set_decimal__doc__},
+ {"get_bool", (PyCFunction) get_bool, METH_VARARGS, get_bool__doc__},
+ {"set_bool", (PyCFunction) set_bool, METH_VARARGS, set_bool__doc__},
+ {"get_namedresult", (PyCFunction) get_namedresult, METH_VARARGS,
+ get_namedresult__doc__},
{"set_namedresult", (PyCFunction) set_namedresult, METH_VARARGS,
set_namedresult__doc__},
_______________________________________________
PyGreSQL mailing list
[email protected]
https://mail.vex.net/mailman/listinfo.cgi/pygresql