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

Commit4ab6ebf

Browse files
committed
Add Unicode support in PL/Python
PL/Python now accepts Unicode objects where it previously only accepted stringobjects (for example, as return value). Unicode objects are converted to thePostgreSQL server encoding as necessary.This change is also necessary for future Python 3 support, which treats allstrings as Unicode objects.Since this removes the error conditions that the plpython_unicode test filetested for, the alternative result files are no longer necessary.
1 parent9bb3428 commit4ab6ebf

File tree

8 files changed

+175
-143
lines changed

8 files changed

+175
-143
lines changed

‎src/pl/plpython/expected/README

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,3 @@ Guide to alternative expected files:
22

33
plpython_error_2.outPython 2.2, 2.3, 2.4
44
plpython_error.outPython 2.5, 2.6
5-
6-
plpython_unicode_2.outPython 2.2
7-
plpython_unicode_3.outPython 2.3, 2.4
8-
plpython_unicode.outPython 2.5, 2.6

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,19 @@ ERROR: unexpected return value from trigger procedure
342342
DETAIL: Expected None, "OK", "SKIP", or "MODIFY".
343343
CONTEXT: PL/Python function "stupid3"
344344
DROP TRIGGER stupid_trigger3 ON trigger_test;
345+
-- Unicode variant
346+
CREATE FUNCTION stupid3u() RETURNS trigger
347+
AS $$
348+
return u"foo"
349+
$$ LANGUAGE plpythonu;
350+
CREATE TRIGGER stupid_trigger3
351+
BEFORE UPDATE ON trigger_test
352+
FOR EACH ROW EXECUTE PROCEDURE stupid3u();
353+
UPDATE trigger_test SET v = 'null' WHERE i = 0;
354+
ERROR: unexpected return value from trigger procedure
355+
DETAIL: Expected None, "OK", "SKIP", or "MODIFY".
356+
CONTEXT: PL/Python function "stupid3u"
357+
DROP TRIGGER stupid_trigger3 ON trigger_test;
345358
-- deleting the TD dictionary
346359
CREATE FUNCTION stupid4() RETURNS trigger
347360
AS $$
@@ -398,6 +411,20 @@ ERROR: key "a" found in TD["new"] does not exist as a column in the triggering
398411
CONTEXT: while modifying trigger row
399412
PL/Python function "stupid7"
400413
DROP TRIGGER stupid_trigger7 ON trigger_test;
414+
-- Unicode variant
415+
CREATE FUNCTION stupid7u() RETURNS trigger
416+
AS $$
417+
TD["new"] = {u'a': 'foo', u'b': 'bar'}
418+
return "MODIFY"
419+
$$ LANGUAGE plpythonu;
420+
CREATE TRIGGER stupid_trigger7
421+
BEFORE UPDATE ON trigger_test
422+
FOR EACH ROW EXECUTE PROCEDURE stupid7u();
423+
UPDATE trigger_test SET v = 'null' WHERE i = 0;
424+
ERROR: key "a" found in TD["new"] does not exist as a column in the triggering row
425+
CONTEXT: while modifying trigger row
426+
PL/Python function "stupid7u"
427+
DROP TRIGGER stupid_trigger7 ON trigger_test;
401428
-- calling a trigger function directly
402429
SELECT stupid7();
403430
ERROR: trigger functions can only be called as triggers

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

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,47 @@
44
CREATE TABLE unicode_test (
55
testvalue text NOT NULL
66
);
7-
CREATE FUNCTIONunicode_return_error() RETURNS text AS E'
7+
CREATE FUNCTIONunicode_return() RETURNS text AS E'
88
return u"\\x80"
99
' LANGUAGE plpythonu;
10-
CREATE FUNCTIONunicode_trigger_error() RETURNS trigger AS E'
10+
CREATE FUNCTIONunicode_trigger() RETURNS trigger AS E'
1111
TD["new"]["testvalue"] = u"\\x80"
1212
return "MODIFY"
1313
' LANGUAGE plpythonu;
1414
CREATE TRIGGER unicode_test_bi BEFORE INSERT ON unicode_test
15-
FOR EACH ROW EXECUTE PROCEDUREunicode_trigger_error();
16-
CREATE FUNCTIONunicode_plan_error1() RETURNS text AS E'
15+
FOR EACH ROW EXECUTE PROCEDUREunicode_trigger();
16+
CREATE FUNCTIONunicode_plan1() RETURNS text AS E'
1717
plan = plpy.prepare("SELECT $1 AS testvalue", ["text"])
1818
rv = plpy.execute(plan, [u"\\x80"], 1)
1919
return rv[0]["testvalue"]
2020
' LANGUAGE plpythonu;
21-
CREATE FUNCTIONunicode_plan_error2() RETURNS text AS E'
22-
plan = plpy.prepare("SELECT $1AS testvalue1,$2 AStestvalue2", ["text", "text"])
23-
rv = plpy.execute(plan,u"\\x80", 1)
24-
return rv[0]["testvalue1"]
21+
CREATE FUNCTIONunicode_plan2() RETURNS text AS E'
22+
plan = plpy.prepare("SELECT $1||$2 AStestvalue", ["text",u"text"])
23+
rv = plpy.execute(plan,["foo", "bar"], 1)
24+
return rv[0]["testvalue"]
2525
' LANGUAGE plpythonu;
26-
SELECT unicode_return_error();
27-
ERROR: PL/Python: could not create string representation of Python object
28-
DETAIL: <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
29-
CONTEXT: while creating return value
30-
PL/Python function "unicode_return_error"
26+
SELECT unicode_return();
27+
unicode_return
28+
----------------
29+
\u0080
30+
(1 row)
31+
3132
INSERT INTO unicode_test (testvalue) VALUES ('test');
32-
ERROR: PL/Python: could not create string representation of Python object
33-
DETAIL: <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
34-
CONTEXT: while modifying trigger row
35-
PL/Python function "unicode_trigger_error"
36-
SELECT unicode_plan_error1();
37-
WARNING: PL/Python: <class 'plpy.Error'>: unrecognized error in PLy_spi_execute_plan
38-
CONTEXT: PL/Python function "unicode_plan_error1"
39-
ERROR: PL/Python: could not execute plan
40-
DETAIL: <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
41-
CONTEXT: PL/Python function "unicode_plan_error1"
42-
SELECT unicode_plan_error2();
43-
ERROR: PL/Python: could not execute plan
44-
DETAIL: <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\x80' in position 0: ordinal not in range(128)
45-
CONTEXT: PL/Python function "unicode_plan_error2"
33+
SELECT * FROM unicode_test;
34+
testvalue
35+
-----------
36+
\u0080
37+
(1 row)
38+
39+
SELECT unicode_plan1();
40+
unicode_plan1
41+
---------------
42+
\u0080
43+
(1 row)
44+
45+
SELECT unicode_plan2();
46+
unicode_plan2
47+
---------------
48+
foobar
49+
(1 row)
50+

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

Lines changed: 0 additions & 45 deletions
This file was deleted.

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

Lines changed: 0 additions & 45 deletions
This file was deleted.

‎src/pl/plpython/plpython.c

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**********************************************************************
22
* plpython.c - python as a procedural language for PostgreSQL
33
*
4-
*$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.128 2009/09/09 19:00:09 petere Exp $
4+
*$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.129 2009/09/12 22:13:12 petere Exp $
55
*
66
*********************************************************************
77
*/
@@ -54,6 +54,7 @@ typedef int Py_ssize_t;
5454
#include"executor/spi.h"
5555
#include"funcapi.h"
5656
#include"fmgr.h"
57+
#include"mb/pg_wchar.h"
5758
#include"miscadmin.h"
5859
#include"nodes/makefuncs.h"
5960
#include"parser/parse_type.h"
@@ -238,6 +239,9 @@ static void *PLy_malloc0(size_t);
238239
staticchar*PLy_strdup(constchar*);
239240
staticvoidPLy_free(void*);
240241

242+
staticPyObject*PLyUnicode_Str(PyObject*unicode);
243+
staticchar*PLyUnicode_AsString(PyObject*unicode);
244+
241245
/* sub handlers for functions and triggers */
242246
staticDatumPLy_function_handler(FunctionCallInfofcinfo,PLyProcedure*);
243247
staticHeapTuplePLy_trigger_handler(FunctionCallInfofcinfo,PLyProcedure*);
@@ -474,13 +478,19 @@ PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
474478
{
475479
char*srv;
476480

477-
if (!PyString_Check(plrv))
481+
if (PyString_Check(plrv))
482+
srv=PyString_AsString(plrv);
483+
elseif (PyUnicode_Check(plrv))
484+
srv=PLyUnicode_AsString(plrv);
485+
else
486+
{
478487
ereport(ERROR,
479488
(errcode(ERRCODE_DATA_EXCEPTION),
480489
errmsg("unexpected return value from trigger procedure"),
481490
errdetail("Expected None or a string.")));
491+
srv=NULL;/* keep compiler quiet */
492+
}
482493

483-
srv=PyString_AsString(plrv);
484494
if (pg_strcasecmp(srv,"SKIP")==0)
485495
rv=NULL;
486496
elseif (pg_strcasecmp(srv,"MODIFY")==0)
@@ -572,15 +582,24 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
572582

573583
for (i=0;i<natts;i++)
574584
{
585+
char*plattstr;
586+
575587
platt=PyList_GetItem(plkeys,i);
576-
if (!PyString_Check(platt))
588+
if (PyString_Check(platt))
589+
plattstr=PyString_AsString(platt);
590+
elseif (PyUnicode_Check(platt))
591+
plattstr=PLyUnicode_AsString(platt);
592+
else
593+
{
577594
ereport(ERROR,
578595
(errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string",i)));
579-
attn=SPI_fnumber(tupdesc,PyString_AsString(platt));
596+
plattstr=NULL;/* keep compiler quiet */
597+
}
598+
attn=SPI_fnumber(tupdesc,plattstr);
580599
if (attn==SPI_ERROR_NOATTRIBUTE)
581600
ereport(ERROR,
582601
(errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
583-
PyString_AsString(platt))));
602+
plattstr)));
584603
atti=attn-1;
585604

586605
plval=PyDict_GetItem(plntup,platt);
@@ -1942,7 +1961,10 @@ PLyObject_ToDatum(PLyTypeInfo *info,
19421961

19431962
Assert(plrv!=Py_None);
19441963

1945-
plrv_so=PyObject_Str(plrv);
1964+
if (PyUnicode_Check(plrv))
1965+
plrv_so=PLyUnicode_Str(plrv);
1966+
else
1967+
plrv_so=PyObject_Str(plrv);
19461968
if (!plrv_so)
19471969
PLy_elog(ERROR,"could not create string representation of Python object");
19481970

@@ -2562,10 +2584,16 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
25622584
Form_pg_typetypeStruct;
25632585

25642586
optr=PySequence_GetItem(list,i);
2565-
if (!PyString_Check(optr))
2587+
if (PyString_Check(optr))
2588+
sptr=PyString_AsString(optr);
2589+
elseif (PyUnicode_Check(optr))
2590+
sptr=PLyUnicode_AsString(optr);
2591+
else
2592+
{
25662593
ereport(ERROR,
25672594
(errmsg("plpy.prepare: type name at ordinal position %d is not a string",i)));
2568-
sptr=PyString_AsString(optr);
2595+
sptr=NULL;/* keep compiler quiet */
2596+
}
25692597

25702598
/********************************************************
25712599
* Resolve argument type names and then look them up by
@@ -2670,7 +2698,7 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
26702698

26712699
if (list!=NULL)
26722700
{
2673-
if (!PySequence_Check(list)||PyString_Check(list))
2701+
if (!PySequence_Check(list)||PyString_Check(list)||PyUnicode_Check(list))
26742702
{
26752703
PLy_exception_set(PLy_exc_spi_error,"plpy.execute takes a sequence as its second argument");
26762704
returnNULL;
@@ -2714,7 +2742,10 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
27142742
elem=PySequence_GetItem(list,j);
27152743
if (elem!=Py_None)
27162744
{
2717-
so=PyObject_Str(elem);
2745+
if (PyUnicode_Check(elem))
2746+
so=PLyUnicode_Str(elem);
2747+
else
2748+
so=PyObject_Str(elem);
27182749
if (!so)
27192750
PLy_elog(ERROR,"could not execute plan");
27202751
Py_DECREF(elem);
@@ -3303,3 +3334,32 @@ PLy_free(void *ptr)
33033334
{
33043335
free(ptr);
33053336
}
3337+
3338+
/*
3339+
* Convert a Python unicode object to a Python string object in
3340+
* PostgreSQL server encoding. Reference ownership is passed to the
3341+
* caller.
3342+
*/
3343+
staticPyObject*
3344+
PLyUnicode_Str(PyObject*unicode)
3345+
{
3346+
/*
3347+
* This assumes that the PostgreSQL encoding names are acceptable
3348+
* to Python, but that appears to be the case.
3349+
*/
3350+
returnPyUnicode_AsEncodedString(unicode,GetDatabaseEncodingName(),"strict");
3351+
}
3352+
3353+
/*
3354+
* Convert a Python unicode object to a C string in PostgreSQL server
3355+
* encoding. No Python object reference is passed out of this
3356+
* function.
3357+
*/
3358+
staticchar*
3359+
PLyUnicode_AsString(PyObject*unicode)
3360+
{
3361+
PyObject*o=PLyUnicode_Str(unicode);
3362+
char*rv=PyString_AsString(o);
3363+
Py_XDECREF(o);
3364+
returnrv;
3365+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp