aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2017-02-25 08:42:25 -0500
committerPeter Eisentraut <peter_e@gmx.net>2017-03-27 11:37:22 -0400
commit70ec3f1f8f0b753c38a1a582280a02930d7cac5f (patch)
tree71ea0b916782cb47290374095145ca4eabb90bd7 /src
parent090010f2ec9b1f9ac1124dc628b89586f911b641 (diff)
downloadpostgresql-70ec3f1f8f0b753c38a1a582280a02930d7cac5f.tar.gz
postgresql-70ec3f1f8f0b753c38a1a582280a02930d7cac5f.zip
PL/Python: Add cursor and execute methods to plan object
Instead of plan = plpy.prepare(...) res = plpy.execute(plan, ...) you can now write plan = plpy.prepare(...) res = plan.execute(...) or even res = plpy.prepare(...).execute(...) and similarly for the cursor() method. This is more in object oriented style, and makes the hybrid nature of the existing execute() function less confusing. Reviewed-by: Andrew Dunstan <andrew.dunstan@2ndquadrant.com>
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpython/expected/plpython_spi.out19
-rw-r--r--src/pl/plpython/plpy_cursorobject.c3
-rw-r--r--src/pl/plpython/plpy_cursorobject.h1
-rw-r--r--src/pl/plpython/plpy_planobject.c31
-rw-r--r--src/pl/plpython/plpy_spi.c3
-rw-r--r--src/pl/plpython/plpy_spi.h1
-rw-r--r--src/pl/plpython/sql/plpython_spi.sql18
7 files changed, 67 insertions, 9 deletions
diff --git a/src/pl/plpython/expected/plpython_spi.out b/src/pl/plpython/expected/plpython_spi.out
index 0d78ca1de48..e54dca9e2ef 100644
--- a/src/pl/plpython/expected/plpython_spi.out
+++ b/src/pl/plpython/expected/plpython_spi.out
@@ -31,6 +31,19 @@ except Exception, ex:
return None
'
LANGUAGE plpythonu;
+CREATE FUNCTION spi_prepared_plan_test_two(a text) RETURNS text
+ AS
+'if "myplan" not in SD:
+ q = "SELECT count(*) FROM users WHERE lname = $1"
+ SD["myplan"] = plpy.prepare(q, [ "text" ])
+try:
+ rv = SD["myplan"].execute([a])
+ return "there are " + str(rv[0]["count"]) + " " + str(a) + "s"
+except Exception, ex:
+ plpy.error(str(ex))
+return None
+'
+ LANGUAGE plpythonu;
CREATE FUNCTION spi_prepared_plan_test_nested(a text) RETURNS text
AS
'if "myplan" not in SD:
@@ -80,8 +93,8 @@ select spi_prepared_plan_test_one('doe');
there are 3 does
(1 row)
-select spi_prepared_plan_test_one('smith');
- spi_prepared_plan_test_one
+select spi_prepared_plan_test_two('smith');
+ spi_prepared_plan_test_two
----------------------------
there are 1 smiths
(1 row)
@@ -372,7 +385,7 @@ plan = plpy.prepare(
["text"])
for row in plpy.cursor(plan, ["w"]):
yield row['fname']
-for row in plpy.cursor(plan, ["j"]):
+for row in plan.cursor(["j"]):
yield row['fname']
$$ LANGUAGE plpythonu;
CREATE FUNCTION cursor_plan_wrong_args() RETURNS SETOF text AS $$
diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c
index 7bb89921484..18e689f1415 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -25,7 +25,6 @@
static PyObject *PLy_cursor_query(const char *query);
-static PyObject *PLy_cursor_plan(PyObject *ob, PyObject *args);
static void PLy_cursor_dealloc(PyObject *arg);
static PyObject *PLy_cursor_iternext(PyObject *self);
static PyObject *PLy_cursor_fetch(PyObject *self, PyObject *args);
@@ -160,7 +159,7 @@ PLy_cursor_query(const char *query)
return (PyObject *) cursor;
}
-static PyObject *
+PyObject *
PLy_cursor_plan(PyObject *ob, PyObject *args)
{
PLyCursorObject *cursor;
diff --git a/src/pl/plpython/plpy_cursorobject.h b/src/pl/plpython/plpy_cursorobject.h
index c73033c486b..ef23865dd2c 100644
--- a/src/pl/plpython/plpy_cursorobject.h
+++ b/src/pl/plpython/plpy_cursorobject.h
@@ -19,5 +19,6 @@ typedef struct PLyCursorObject
extern void PLy_cursor_init_type(void);
extern PyObject *PLy_cursor(PyObject *self, PyObject *args);
+extern PyObject *PLy_cursor_plan(PyObject *ob, PyObject *args);
#endif /* PLPY_CURSOROBJECT_H */
diff --git a/src/pl/plpython/plpy_planobject.c b/src/pl/plpython/plpy_planobject.c
index 16c39a05ddf..390b4e90d45 100644
--- a/src/pl/plpython/plpy_planobject.c
+++ b/src/pl/plpython/plpy_planobject.c
@@ -10,11 +10,15 @@
#include "plpy_planobject.h"
+#include "plpy_cursorobject.h"
#include "plpy_elog.h"
+#include "plpy_spi.h"
#include "utils/memutils.h"
static void PLy_plan_dealloc(PyObject *arg);
+static PyObject *PLy_plan_cursor(PyObject *self, PyObject *args);
+static PyObject *PLy_plan_execute(PyObject *self, PyObject *args);
static PyObject *PLy_plan_status(PyObject *self, PyObject *args);
static char PLy_plan_doc[] = {
@@ -22,6 +26,8 @@ static char PLy_plan_doc[] = {
};
static PyMethodDef PLy_plan_methods[] = {
+ {"cursor", PLy_plan_cursor, METH_VARARGS, NULL},
+ {"execute", PLy_plan_execute, METH_VARARGS, NULL},
{"status", PLy_plan_status, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
@@ -112,6 +118,31 @@ PLy_plan_dealloc(PyObject *arg)
static PyObject *
+PLy_plan_cursor(PyObject *self, PyObject *args)
+{
+ PyObject *planargs = NULL;
+
+ if (!PyArg_ParseTuple(args, "|O", &planargs))
+ return NULL;
+
+ return PLy_cursor_plan(self, planargs);
+}
+
+
+static PyObject *
+PLy_plan_execute(PyObject *self, PyObject *args)
+{
+ PyObject *list = NULL;
+ long limit = 0;
+
+ if (!PyArg_ParseTuple(args, "|Ol", &list, &limit))
+ return NULL;
+
+ return PLy_spi_execute_plan(self, list, limit);
+}
+
+
+static PyObject *
PLy_plan_status(PyObject *self, PyObject *args)
{
if (PyArg_ParseTuple(args, ":status"))
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 07ab6a087e5..c6856ccbacc 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -30,7 +30,6 @@
static PyObject *PLy_spi_execute_query(char *query, long limit);
-static PyObject *PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit);
static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *tuptable,
uint64 rows, int status);
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata);
@@ -193,7 +192,7 @@ PLy_spi_execute(PyObject *self, PyObject *args)
return NULL;
}
-static PyObject *
+PyObject *
PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
{
volatile int nargs;
diff --git a/src/pl/plpython/plpy_spi.h b/src/pl/plpython/plpy_spi.h
index b0427947ef4..817a7584e79 100644
--- a/src/pl/plpython/plpy_spi.h
+++ b/src/pl/plpython/plpy_spi.h
@@ -10,6 +10,7 @@
extern PyObject *PLy_spi_prepare(PyObject *self, PyObject *args);
extern PyObject *PLy_spi_execute(PyObject *self, PyObject *args);
+extern PyObject *PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit);
typedef struct PLyExceptionEntry
{
diff --git a/src/pl/plpython/sql/plpython_spi.sql b/src/pl/plpython/sql/plpython_spi.sql
index 7427de824b3..fcf049cb66d 100644
--- a/src/pl/plpython/sql/plpython_spi.sql
+++ b/src/pl/plpython/sql/plpython_spi.sql
@@ -37,6 +37,20 @@ return None
'
LANGUAGE plpythonu;
+CREATE FUNCTION spi_prepared_plan_test_two(a text) RETURNS text
+ AS
+'if "myplan" not in SD:
+ q = "SELECT count(*) FROM users WHERE lname = $1"
+ SD["myplan"] = plpy.prepare(q, [ "text" ])
+try:
+ rv = SD["myplan"].execute([a])
+ return "there are " + str(rv[0]["count"]) + " " + str(a) + "s"
+except Exception, ex:
+ plpy.error(str(ex))
+return None
+'
+ LANGUAGE plpythonu;
+
CREATE FUNCTION spi_prepared_plan_test_nested(a text) RETURNS text
AS
'if "myplan" not in SD:
@@ -79,7 +93,7 @@ return a + r
--
select nested_call_one('pass this along');
select spi_prepared_plan_test_one('doe');
-select spi_prepared_plan_test_one('smith');
+select spi_prepared_plan_test_two('smith');
select spi_prepared_plan_test_nested('smith');
SELECT join_sequences(sequences) FROM sequences;
@@ -275,7 +289,7 @@ plan = plpy.prepare(
["text"])
for row in plpy.cursor(plan, ["w"]):
yield row['fname']
-for row in plpy.cursor(plan, ["j"]):
+for row in plan.cursor(["j"]):
yield row['fname']
$$ LANGUAGE plpythonu;