Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1c51c7d

Browse files
committed
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 argumentof quote_literal_cstr() const char *. This also makes it moreconsistent with quote_identifier().Jan Urbański, reviewed by Hitoshi Harada, some refinements by PeterEisentraut
1 parent3e6b305 commit1c51c7d

File tree

8 files changed

+179
-7
lines changed

8 files changed

+179
-7
lines changed

‎doc/src/sgml/plpython.sgml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,23 @@ $$ LANGUAGE plpythonu;
997997
<xref linkend="guc-client-min-messages"> configuration
998998
variables. See <xref linkend="runtime-config"> for more information.
999999
</para>
1000+
1001+
<para>
1002+
Another set of utility functions are
1003+
<literal>plpy.quote_literal(<replaceable>string</>)</literal>,
1004+
<literal>plpy.quote_nullable(<replaceable>string</>)</literal>, and
1005+
<literal>plpy.quote_ident(<replaceable>string</>)</literal>. They
1006+
are equivalent to the built-in quoting functions described in <xref
1007+
linkend="functions-string">. They are useful when constructing
1008+
ad-hoc queries. A PL/Python equivalent of dynamic SQL from <xref
1009+
linkend="plpgsql-quote-literal-example"> would be:
1010+
<programlisting>
1011+
plpy.execute("UPDATE tbl SET %s = %s where key = %s" % (
1012+
plpy.quote_ident(colname),
1013+
plpy.quote_nullable(newvalue),
1014+
plpy.quote_literal(keyvalue)))
1015+
</programlisting>
1016+
</para>
10001017
</sect1>
10011018

10021019
<sect1 id="plpython-envar">

‎src/backend/utils/adt/quote.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ quote_ident(PG_FUNCTION_ARGS)
4343
* uses this for before thinking you know better.
4444
*/
4545
staticsize_t
46-
quote_literal_internal(char*dst,char*src,size_tlen)
46+
quote_literal_internal(char*dst,constchar*src,size_tlen)
4747
{
48-
char*s;
48+
constchar*s;
4949
char*savedst=dst;
5050

5151
for (s=src;s<src+len;s++)
@@ -99,7 +99,7 @@ quote_literal(PG_FUNCTION_ARGS)
9999
* returns a properly quoted literal
100100
*/
101101
char*
102-
quote_literal_cstr(char*rawstr)
102+
quote_literal_cstr(constchar*rawstr)
103103
{
104104
char*result;
105105
intlen;

‎src/include/utils/builtins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ extern int32 type_maximum_size(Oid type_oid, int32 typemod);
988988
/* quote.c */
989989
externDatumquote_ident(PG_FUNCTION_ARGS);
990990
externDatumquote_literal(PG_FUNCTION_ARGS);
991-
externchar*quote_literal_cstr(char*rawstr);
991+
externchar*quote_literal_cstr(constchar*rawstr);
992992
externDatumquote_nullable(PG_FUNCTION_ARGS);
993993

994994
/* guc.c */

‎src/pl/plpython/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ REGRESS = \
7979
plpython_types\
8080
plpython_error\
8181
plpython_unicode\
82+
plpython_quote\
8283
plpython_drop
8384
# where to find psql for running the tests
8485
PSQLDIR =$(bindir)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
-- test quoting functions
2+
CREATE FUNCTION quote(t text, how text) RETURNS text AS $$
3+
if how == "literal":
4+
return plpy.quote_literal(t)
5+
elif how == "nullable":
6+
return plpy.quote_nullable(t)
7+
elif how == "ident":
8+
return plpy.quote_ident(t)
9+
else:
10+
raise plpy.Error("unrecognized quote type %s" % how)
11+
$$ LANGUAGE plpythonu;
12+
SELECT quote(t, 'literal') FROM (VALUES
13+
('abc'),
14+
('a''bc'),
15+
('''abc'''),
16+
(''),
17+
(''''),
18+
('xyzv')) AS v(t);
19+
quote
20+
-----------
21+
'abc'
22+
'a''bc'
23+
'''abc'''
24+
''
25+
''''
26+
'xyzv'
27+
(6 rows)
28+
29+
SELECT quote(t, 'nullable') FROM (VALUES
30+
('abc'),
31+
('a''bc'),
32+
('''abc'''),
33+
(''),
34+
(''''),
35+
(NULL)) AS v(t);
36+
quote
37+
-----------
38+
'abc'
39+
'a''bc'
40+
'''abc'''
41+
''
42+
''''
43+
NULL
44+
(6 rows)
45+
46+
SELECT quote(t, 'ident') FROM (VALUES
47+
('abc'),
48+
('a b c'),
49+
('a " ''abc''')) AS v(t);
50+
quote
51+
--------------
52+
abc
53+
"a b c"
54+
"a "" 'abc'"
55+
(3 rows)
56+

‎src/pl/plpython/expected/plpython_test.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ contents.sort()
4343
return ", ".join(contents)
4444
$$ LANGUAGE plpythonu;
4545
select module_contents();
46-
module_contents
47-
-------------------------------------------------------------------------------------------
48-
Error, Fatal, SPIError, debug, error, execute, fatal, info, log, notice, prepare, warning
46+
module_contents
47+
---------------------------------------------------------------------------------------------------------------------------------------
48+
Error, Fatal, SPIError, debug, error, execute, fatal, info, log, notice, prepare,quote_ident, quote_literal, quote_nullable,warning
4949
(1 row)
5050

5151
CREATE FUNCTION elog_test() RETURNS void

‎src/pl/plpython/plpython.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,6 +2637,10 @@ static PyObject *PLy_spi_execute_query(char *query, long limit);
26372637
staticPyObject*PLy_spi_execute_plan(PyObject*,PyObject*,long);
26382638
staticPyObject*PLy_spi_execute_fetch_result(SPITupleTable*,int,int);
26392639

2640+
staticPyObject*PLy_quote_literal(PyObject*self,PyObject*args);
2641+
staticPyObject*PLy_quote_nullable(PyObject*self,PyObject*args);
2642+
staticPyObject*PLy_quote_ident(PyObject*self,PyObject*args);
2643+
26402644

26412645
staticPyMethodDefPLy_plan_methods[]= {
26422646
{"status",PLy_plan_status,METH_VARARGS,NULL},
@@ -2751,6 +2755,13 @@ static PyMethodDef PLy_methods[] = {
27512755
*/
27522756
{"execute",PLy_spi_execute,METH_VARARGS,NULL},
27532757

2758+
/*
2759+
* escaping strings
2760+
*/
2761+
{"quote_literal",PLy_quote_literal,METH_VARARGS,NULL},
2762+
{"quote_nullable",PLy_quote_nullable,METH_VARARGS,NULL},
2763+
{"quote_ident",PLy_quote_ident,METH_VARARGS,NULL},
2764+
27542765
{NULL,NULL,0,NULL}
27552766
};
27562767

@@ -3688,6 +3699,60 @@ PLy_output(volatile int level, PyObject *self, PyObject *args)
36883699
}
36893700

36903701

3702+
staticPyObject*
3703+
PLy_quote_literal(PyObject*self,PyObject*args)
3704+
{
3705+
constchar*str;
3706+
char*quoted;
3707+
PyObject*ret;
3708+
3709+
if (!PyArg_ParseTuple(args,"s",&str))
3710+
returnNULL;
3711+
3712+
quoted=quote_literal_cstr(str);
3713+
ret=PyString_FromString(quoted);
3714+
pfree(quoted);
3715+
3716+
returnret;
3717+
}
3718+
3719+
staticPyObject*
3720+
PLy_quote_nullable(PyObject*self,PyObject*args)
3721+
{
3722+
constchar*str;
3723+
char*quoted;
3724+
PyObject*ret;
3725+
3726+
if (!PyArg_ParseTuple(args,"z",&str))
3727+
returnNULL;
3728+
3729+
if (str==NULL)
3730+
returnPyString_FromString("NULL");
3731+
3732+
quoted=quote_literal_cstr(str);
3733+
ret=PyString_FromString(quoted);
3734+
pfree(quoted);
3735+
3736+
returnret;
3737+
}
3738+
3739+
staticPyObject*
3740+
PLy_quote_ident(PyObject*self,PyObject*args)
3741+
{
3742+
constchar*str;
3743+
constchar*quoted;
3744+
PyObject*ret;
3745+
3746+
if (!PyArg_ParseTuple(args,"s",&str))
3747+
returnNULL;
3748+
3749+
quoted=quote_identifier(str);
3750+
ret=PyString_FromString(quoted);
3751+
3752+
returnret;
3753+
}
3754+
3755+
36913756
/*
36923757
* Get the name of the last procedure called by the backend (the
36933758
* innermost, if a plpython procedure call calls the backend and the
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-- test quoting functions
2+
3+
CREATEFUNCTIONquote(ttext, howtext) RETURNStextAS $$
4+
if how=="literal":
5+
returnplpy.quote_literal(t)
6+
elif how=="nullable":
7+
returnplpy.quote_nullable(t)
8+
elif how=="ident":
9+
returnplpy.quote_ident(t)
10+
else:
11+
raiseplpy.Error("unrecognized quote type %s" % how)
12+
$$ LANGUAGE plpythonu;
13+
14+
SELECT quote(t,'literal')FROM (VALUES
15+
('abc'),
16+
('a''bc'),
17+
('''abc'''),
18+
(''),
19+
(''''),
20+
('xyzv'))AS v(t);
21+
22+
SELECT quote(t,'nullable')FROM (VALUES
23+
('abc'),
24+
('a''bc'),
25+
('''abc'''),
26+
(''),
27+
(''''),
28+
(NULL))AS v(t);
29+
30+
SELECT quote(t,'ident')FROM (VALUES
31+
('abc'),
32+
('a b c'),
33+
('a "''abc'''))AS v(t);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp