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

Commita97207b

Browse files
committed
PL/Python: Fix slicing support for result objects for Python 3
The old way of implementing slicing support by implementingPySequenceMethods.sq_slice no longer works in Python 3. You now haveto implement PyMappingMethods.mp_subscript. Do this by simplyproxying the call to the wrapped list of result dictionaries.Consolidate some of the subscripting regression tests.Jan Urbański
1 parent1540d3b commita97207b

File tree

3 files changed

+116
-36
lines changed

3 files changed

+116
-36
lines changed

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

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,3 @@
1-
--
2-
-- result objects
3-
--
4-
CREATE FUNCTION test_resultobject_access() RETURNS void
5-
AS $$
6-
rv = plpy.execute("SELECT fname, lname, username FROM users ORDER BY username")
7-
plpy.info([row for row in rv])
8-
rv[1] = dict([(k, v*2) for (k, v) in rv[1].items()])
9-
plpy.info([row for row in rv])
10-
$$ LANGUAGE plpythonu;
11-
SELECT test_resultobject_access();
12-
INFO: [{'lname': 'doe', 'username': 'j_doe', 'fname': 'jane'}, {'lname': 'doe', 'username': 'johnd', 'fname': 'john'}, {'lname': 'smith', 'username': 'slash', 'fname': 'rick'}, {'lname': 'doe', 'username': 'w_doe', 'fname': 'willem'}]
13-
CONTEXT: PL/Python function "test_resultobject_access"
14-
INFO: [{'lname': 'doe', 'username': 'j_doe', 'fname': 'jane'}, {'lname': 'doedoe', 'username': 'johndjohnd', 'fname': 'johnjohn'}, {'lname': 'smith', 'username': 'slash', 'fname': 'rick'}, {'lname': 'doe', 'username': 'w_doe', 'fname': 'willem'}]
15-
CONTEXT: PL/Python function "test_resultobject_access"
16-
test_resultobject_access
17-
--------------------------
18-
19-
(1 row)
20-
211
--
222
-- nested calls
233
--
@@ -228,6 +208,61 @@ SELECT result_len_test($$UPDATE foo3 SET b= '' WHERE a = 2$$);
228208
0
229209
(1 row)
230210

211+
CREATE FUNCTION result_subscript_test() RETURNS void
212+
AS $$
213+
result = plpy.execute("SELECT 1 AS c UNION SELECT 2 "
214+
"UNION SELECT 3 UNION SELECT 4")
215+
216+
plpy.info(result[1]['c'])
217+
plpy.info(result[-1]['c'])
218+
219+
plpy.info([item['c'] for item in result[1:3]])
220+
plpy.info([item['c'] for item in result[::2]])
221+
222+
result[-1] = {'c': 1000}
223+
result[:2] = [{'c': 10}, {'c': 100}]
224+
plpy.info([item['c'] for item in result[:]])
225+
226+
# raises TypeError, but the message differs on Python 2.6, so silence it
227+
try:
228+
plpy.info(result['foo'])
229+
except TypeError:
230+
pass
231+
else:
232+
assert False, "TypeError not raised"
233+
234+
$$ LANGUAGE plpythonu;
235+
SELECT result_subscript_test();
236+
INFO: 2
237+
CONTEXT: PL/Python function "result_subscript_test"
238+
INFO: 4
239+
CONTEXT: PL/Python function "result_subscript_test"
240+
INFO: [2, 3]
241+
CONTEXT: PL/Python function "result_subscript_test"
242+
INFO: [1, 3]
243+
CONTEXT: PL/Python function "result_subscript_test"
244+
INFO: [10, 100, 3, 1000]
245+
CONTEXT: PL/Python function "result_subscript_test"
246+
result_subscript_test
247+
-----------------------
248+
249+
(1 row)
250+
251+
CREATE FUNCTION result_empty_test() RETURNS void
252+
AS $$
253+
result = plpy.execute("select 1 where false")
254+
255+
plpy.info(result[:])
256+
257+
$$ LANGUAGE plpythonu;
258+
SELECT result_empty_test();
259+
INFO: []
260+
CONTEXT: PL/Python function "result_empty_test"
261+
result_empty_test
262+
-------------------
263+
264+
(1 row)
265+
231266
-- cursor objects
232267
CREATE FUNCTION simple_cursor_test() RETURNS int AS $$
233268
res = plpy.cursor("select fname, lname from users")

‎src/pl/plpython/plpy_resultobject.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ static PyObject *PLy_result_item(PyObject *arg, Py_ssize_t idx);
2323
staticPyObject*PLy_result_slice(PyObject*arg,Py_ssize_tlidx,Py_ssize_thidx);
2424
staticintPLy_result_ass_item(PyObject*arg,Py_ssize_tidx,PyObject*item);
2525
staticintPLy_result_ass_slice(PyObject*rg,Py_ssize_tlidx,Py_ssize_thidx,PyObject*slice);
26+
staticPyObject*PLy_result_subscript(PyObject*arg,PyObject*item);
27+
staticintPLy_result_ass_subscript(PyObject*self,PyObject*item,PyObject*value);
2628

2729
staticcharPLy_result_doc[]= {
2830
"Results of a PostgreSQL query"
@@ -38,6 +40,12 @@ static PySequenceMethods PLy_result_as_sequence = {
3840
PLy_result_ass_slice,/* sq_ass_slice */
3941
};
4042

43+
staticPyMappingMethodsPLy_result_as_mapping= {
44+
PLy_result_length,/* mp_length */
45+
PLy_result_subscript,/* mp_subscript */
46+
PLy_result_ass_subscript,/* mp_ass_subscript */
47+
};
48+
4149
staticPyMethodDefPLy_result_methods[]= {
4250
{"colnames",PLy_result_colnames,METH_NOARGS,NULL},
4351
{"coltypes",PLy_result_coltypes,METH_NOARGS,NULL},
@@ -64,7 +72,7 @@ static PyTypeObject PLy_ResultType = {
6472
0,/* tp_repr */
6573
0,/* tp_as_number */
6674
&PLy_result_as_sequence,/* tp_as_sequence */
67-
0,/* tp_as_mapping */
75+
&PLy_result_as_mapping,/* tp_as_mapping */
6876
0,/* tp_hash */
6977
0,/* tp_call */
7078
0,/* tp_str */
@@ -251,3 +259,19 @@ PLy_result_ass_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx, PyObject *
251259
rv=PyList_SetSlice(ob->rows,lidx,hidx,slice);
252260
returnrv;
253261
}
262+
263+
staticPyObject*
264+
PLy_result_subscript(PyObject*arg,PyObject*item)
265+
{
266+
PLyResultObject*ob= (PLyResultObject*)arg;
267+
268+
returnPyObject_GetItem(ob->rows,item);
269+
}
270+
271+
staticint
272+
PLy_result_ass_subscript(PyObject*arg,PyObject*item,PyObject*value)
273+
{
274+
PLyResultObject*ob= (PLyResultObject*)arg;
275+
276+
returnPyObject_SetItem(ob->rows,item,value);
277+
}

‎src/pl/plpython/sql/plpython_spi.sql

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
1-
--
2-
-- result objects
3-
--
4-
5-
CREATEFUNCTIONtest_resultobject_access() RETURNS void
6-
AS $$
7-
rv=plpy.execute("SELECT fname, lname, username FROM users ORDER BY username")
8-
plpy.info([row for rowin rv])
9-
rv[1]= dict([(k, v*2) for (k, v)in rv[1].items()])
10-
plpy.info([row for rowin rv])
11-
$$ LANGUAGE plpythonu;
12-
13-
SELECT test_resultobject_access();
14-
15-
161
--
172
-- nested calls
183
--
@@ -147,6 +132,42 @@ SELECT result_len_test($$CREATE TEMPORARY TABLE foo3 (a int, b text)$$);
147132
SELECT result_len_test($$INSERT INTO foo3VALUES (1,'one'), (2,'two')$$);
148133
SELECT result_len_test($$UPDATE foo3SET b=''WHERE a=2$$);
149134

135+
CREATEFUNCTIONresult_subscript_test() RETURNS void
136+
AS $$
137+
result=plpy.execute("SELECT 1 AS c UNION SELECT 2"
138+
"UNION SELECT 3 UNION SELECT 4")
139+
140+
plpy.info(result[1]['c'])
141+
plpy.info(result[-1]['c'])
142+
143+
plpy.info([item['c'] for itemin result[1:3]])
144+
plpy.info([item['c'] for itemin result[::2]])
145+
146+
result[-1]= {'c':1000}
147+
result[:2]= [{'c':10}, {'c':100}]
148+
plpy.info([item['c'] for itemin result[:]])
149+
150+
# raises TypeError, but the message differs on Python 2.6, so silence it
151+
try:
152+
plpy.info(result['foo'])
153+
except TypeError:
154+
pass
155+
else:
156+
assert False,"TypeError not raised"
157+
158+
$$ LANGUAGE plpythonu;
159+
160+
SELECT result_subscript_test();
161+
162+
CREATEFUNCTIONresult_empty_test() RETURNS void
163+
AS $$
164+
result=plpy.execute("select 1 where false")
165+
166+
plpy.info(result[:])
167+
168+
$$ LANGUAGE plpythonu;
169+
170+
SELECT result_empty_test();
150171

151172
-- cursor objects
152173

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp