问题描述
我正在运行 Postgresql 9.4,我对它如何处理 plpython 导入感到困惑,特别是关于 Decimal。
第一个例子:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
def myfoo():
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
SELECT devel.foo();
结果:
有点令人惊讶,因为 Postgresql 9.4 中的一个变化是它应该隐式地使用十进制而不是在 plpython 中使用浮点数。但是好的,让我们添加导入:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
from decimal import Decimal
def myfoo():
eval("Decimal('40.0')");
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
select devel.foo()
再次:
现在让我们尝试将导入放在函数中:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
def myfoo():
from decimal import Decimal
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
select devel.foo();
结果:devel.foo()
现在可以正常执行,打印“完成”。另一个奇怪的事情:以下也有效:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
from decimal import Decimal
def myfoo():
var = Decimal('40.0')
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
问题:为什么在 myfoo()
中看不到顶级导入?为什么我在函数中使用 Decimal 会突然生效?
解决方法
这是记录在案的 Python 行为 here。 plpythonu 执行环境不是全局的。
注意,eval() 无权访问嵌套的作用域(非本地) 封闭环境。
在 python 中试试这个代码(在 PostgreSQL 之外):
def bar():
from decimal import Decimal
def foo():
return eval("Decimal('40.0')")
return foo()
print(bar())
它以 NameError: name 'Decimal' is not defined
失败。
使用 Decimal
将 global
放入您的全局变量中:
def bar():
from decimal import Decimal
global Decimal
def foo():
return eval("Decimal('40.0')")
return foo()
print(bar())