summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Eisentraut2011-02-22 21:33:44 +0000
committerPeter Eisentraut2011-02-22 21:41:23 +0000
commit1c51c7d5ffd407426f314b2cd317ef77f14efb1f (patch)
tree86ff75cfeb5801164eb4b3d4f5ce5dba20d8acad /src
parent3e6b305d9e2a4616bf69e31b0b21ebbb844ba50e (diff)
Add PL/Python functions for quoting strings
Add functions plpy.quote_ident, plpy.quote_literal, plpy.quote_nullable, which wrap the equivalent SQL functions. To be able to propagate char * constness properly, make the argument of quote_literal_cstr() const char *. This also makes it more consistent with quote_identifier(). Jan UrbaƄski, reviewed by Hitoshi Harada, some refinements by Peter Eisentraut
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/quote.c6
-rw-r--r--src/include/utils/builtins.h2
-rw-r--r--src/pl/plpython/Makefile1
-rw-r--r--src/pl/plpython/expected/plpython_quote.out56
-rw-r--r--src/pl/plpython/expected/plpython_test.out6
-rw-r--r--src/pl/plpython/plpython.c65
-rw-r--r--src/pl/plpython/sql/plpython_quote.sql33
7 files changed, 162 insertions, 7 deletions
diff --git a/src/backend/utils/adt/quote.c b/src/backend/utils/adt/quote.c
index 055d0a7ab8d..2a6edeaafc9 100644
--- a/src/backend/utils/adt/quote.c
+++ b/src/backend/utils/adt/quote.c
@@ -43,9 +43,9 @@ quote_ident(PG_FUNCTION_ARGS)
* uses this for before thinking you know better.
*/
static size_t
-quote_literal_internal(char *dst, char *src, size_t len)
+quote_literal_internal(char *dst, const char *src, size_t len)
{
- char *s;
+ const char *s;
char *savedst = dst;
for (s = src; s < src + len; s++)
@@ -99,7 +99,7 @@ quote_literal(PG_FUNCTION_ARGS)
* returns a properly quoted literal
*/
char *
-quote_literal_cstr(char *rawstr)
+quote_literal_cstr(const char *rawstr)
{
char *result;
int len;
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 8652ba03a05..72b0cdea7f7 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -988,7 +988,7 @@ extern int32 type_maximum_size(Oid type_oid, int32 typemod);
/* quote.c */
extern Datum quote_ident(PG_FUNCTION_ARGS);
extern Datum quote_literal(PG_FUNCTION_ARGS);
-extern char *quote_literal_cstr(char *rawstr);
+extern char *quote_literal_cstr(const char *rawstr);
extern Datum quote_nullable(PG_FUNCTION_ARGS);
/* guc.c */
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);