diff options
Diffstat (limited to 'src/pl/plpython')
-rw-r--r-- | src/pl/plpython/Makefile | 1 | ||||
-rw-r--r-- | src/pl/plpython/expected/plpython_quote.out | 56 | ||||
-rw-r--r-- | src/pl/plpython/expected/plpython_test.out | 6 | ||||
-rw-r--r-- | src/pl/plpython/plpython.c | 65 | ||||
-rw-r--r-- | src/pl/plpython/sql/plpython_quote.sql | 33 |
5 files changed, 158 insertions, 3 deletions
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile index 3a2411bea18..17fa86880ed 100644 --- a/src/pl/plpython/Makefile +++ b/src/pl/plpython/Makefile @@ -79,6 +79,7 @@ REGRESS = \ plpython_types \ plpython_error \ plpython_unicode \ + plpython_quote \ plpython_drop # where to find psql for running the tests PSQLDIR = $(bindir) diff --git a/src/pl/plpython/expected/plpython_quote.out b/src/pl/plpython/expected/plpython_quote.out new file mode 100644 index 00000000000..eed72923aec --- /dev/null +++ b/src/pl/plpython/expected/plpython_quote.out @@ -0,0 +1,56 @@ +-- test quoting functions +CREATE FUNCTION quote(t text, how text) RETURNS text AS $$ + if how == "literal": + return plpy.quote_literal(t) + elif how == "nullable": + return plpy.quote_nullable(t) + elif how == "ident": + return plpy.quote_ident(t) + else: + raise plpy.Error("unrecognized quote type %s" % how) +$$ LANGUAGE plpythonu; +SELECT quote(t, 'literal') FROM (VALUES + ('abc'), + ('a''bc'), + ('''abc'''), + (''), + (''''), + ('xyzv')) AS v(t); + quote +----------- + 'abc' + 'a''bc' + '''abc''' + '' + '''' + 'xyzv' +(6 rows) + +SELECT quote(t, 'nullable') FROM (VALUES + ('abc'), + ('a''bc'), + ('''abc'''), + (''), + (''''), + (NULL)) AS v(t); + quote +----------- + 'abc' + 'a''bc' + '''abc''' + '' + '''' + NULL +(6 rows) + +SELECT quote(t, 'ident') FROM (VALUES + ('abc'), + ('a b c'), + ('a " ''abc''')) AS v(t); + quote +-------------- + abc + "a b c" + "a "" 'abc'" +(3 rows) + diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out index d92c9876ee7..961f6c0d187 100644 --- a/src/pl/plpython/expected/plpython_test.out +++ b/src/pl/plpython/expected/plpython_test.out @@ -43,9 +43,9 @@ contents.sort() return ", ".join(contents) $$ LANGUAGE plpythonu; select module_contents(); - module_contents -------------------------------------------------------------------------------------------- - Error, Fatal, SPIError, debug, error, execute, fatal, info, log, notice, prepare, warning + module_contents +--------------------------------------------------------------------------------------------------------------------------------------- + Error, Fatal, SPIError, debug, error, execute, fatal, info, log, notice, prepare, quote_ident, quote_literal, quote_nullable, warning (1 row) CREATE FUNCTION elog_test() RETURNS void diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index 4e54d3e8b0e..3013fc8a790 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -2637,6 +2637,10 @@ static PyObject *PLy_spi_execute_query(char *query, long limit); static PyObject *PLy_spi_execute_plan(PyObject *, PyObject *, long); static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *, int, int); +static PyObject *PLy_quote_literal(PyObject *self, PyObject *args); +static PyObject *PLy_quote_nullable(PyObject *self, PyObject *args); +static PyObject *PLy_quote_ident(PyObject *self, PyObject *args); + static PyMethodDef PLy_plan_methods[] = { {"status", PLy_plan_status, METH_VARARGS, NULL}, @@ -2751,6 +2755,13 @@ static PyMethodDef PLy_methods[] = { */ {"execute", PLy_spi_execute, METH_VARARGS, NULL}, + /* + * escaping strings + */ + {"quote_literal", PLy_quote_literal, METH_VARARGS, NULL}, + {"quote_nullable", PLy_quote_nullable, METH_VARARGS, NULL}, + {"quote_ident", PLy_quote_ident, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} }; @@ -3688,6 +3699,60 @@ PLy_output(volatile int level, PyObject *self, PyObject *args) } +static PyObject * +PLy_quote_literal(PyObject *self, PyObject *args) +{ + const char *str; + char *quoted; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "s", &str)) + return NULL; + + quoted = quote_literal_cstr(str); + ret = PyString_FromString(quoted); + pfree(quoted); + + return ret; +} + +static PyObject * +PLy_quote_nullable(PyObject *self, PyObject *args) +{ + const char *str; + char *quoted; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "z", &str)) + return NULL; + + if (str == NULL) + return PyString_FromString("NULL"); + + quoted = quote_literal_cstr(str); + ret = PyString_FromString(quoted); + pfree(quoted); + + return ret; +} + +static PyObject * +PLy_quote_ident(PyObject *self, PyObject *args) +{ + const char *str; + const char *quoted; + PyObject *ret; + + if (!PyArg_ParseTuple(args, "s", &str)) + return NULL; + + quoted = quote_identifier(str); + ret = PyString_FromString(quoted); + + return ret; +} + + /* * Get the name of the last procedure called by the backend (the * innermost, if a plpython procedure call calls the backend and the diff --git a/src/pl/plpython/sql/plpython_quote.sql b/src/pl/plpython/sql/plpython_quote.sql new file mode 100644 index 00000000000..346b5485daf --- /dev/null +++ b/src/pl/plpython/sql/plpython_quote.sql @@ -0,0 +1,33 @@ +-- test quoting functions + +CREATE FUNCTION quote(t text, how text) RETURNS text AS $$ + if how == "literal": + return plpy.quote_literal(t) + elif how == "nullable": + return plpy.quote_nullable(t) + elif how == "ident": + return plpy.quote_ident(t) + else: + raise plpy.Error("unrecognized quote type %s" % how) +$$ LANGUAGE plpythonu; + +SELECT quote(t, 'literal') FROM (VALUES + ('abc'), + ('a''bc'), + ('''abc'''), + (''), + (''''), + ('xyzv')) AS v(t); + +SELECT quote(t, 'nullable') FROM (VALUES + ('abc'), + ('a''bc'), + ('''abc'''), + (''), + (''''), + (NULL)) AS v(t); + +SELECT quote(t, 'ident') FROM (VALUES + ('abc'), + ('a b c'), + ('a " ''abc''')) AS v(t); |