-2

我有一个用 PL/Python 编写的函数。它是一个在 Python 中运行的数据库函数,这是允许的,因为通过以下方式安装了一种过程语言:

CREATE PROCEDURAL LANGUAGE 'plpythonu' HANDLER plpython_call_handler

(我发现了一个很好的技巧,允许非管理员用户运行,通过使用一个唯一的名称,虽然它与我的问题没有太大关系,我相信你们中的一些人会想知道我是如何做到这一点的,所以下面是答案)

CREATE TRUSTED PROCEDURAL LANGUAGE 'plpythonu2' HANDLER plpython_call_handler
GRANT USAGE ON LANGUAGE plpythonu2 TO admin;

现在到手头的问题,我上面的“hack”对我有用,但是如果我想使用亚马逊的 RDS 服务,我无法安装语言,并且 PL/Python 不可用。然而,SQL 是。

因此,我需要帮助将以下用 Python 编写的函数翻译成纯 SQL。

CREATE OR REPLACE FUNCTION "public"."human_readable_bits" (
  "b" bigint = 0
)
RETURNS varchar AS
$body$
import math
if b:
  exponent = math.floor(math.log(b)/math.log(1024))
  val = b/pow(1024, math.floor(exponent))
  val = round(val*2)/2 -- This rounds to the nearest HALF (X.5) B, Kb, Mb, Gb, etc.
  return "%.2f %s" % (val, ('B','Kb','Mb','Gb','Tb','Pb','Eb','Zb','Yb')[int(exponent)])
else:
  return "0 Gb"
$body$
LANGUAGE 'plpythonu2'
VOLATILE
RETURNS NULL ON NULL INPUT
SECURITY INVOKER
COST 100;

此功能允许我执行以下查询:

 => SELECT human_readable_bits(3285824466906);
 human_readable_bits
---------------------
 3.00 Tb
(1 row)

或者

=> SELECT human_readable_bits(5920466906);
 human_readable_bits
---------------------
 5.50 Gb
(1 row)

另外,作为一个旁注/次要问题,在我创建函数之后,当我查看 DDL 时,其中有一行写着“安全调用者”,有人知道这意味着什么吗?

4

1 回答 1

2

普通 PLPGSQL 函数的转换将是:

CREATE OR REPLACE FUNCTION public.human_readable_bits(b NUMERIC)
  RETURNS VARCHAR AS
$BODY$
declare
   exponent integer;
   val float;
   arr varchar[];
   sz VARCHAR(10);
   result varchar(20);
BEGIN
    if b is null or b = 0 then
       return '0 B';
    end if;

    if b < 1024 then
        return b::varchar || ' Bits';
    end if;

    arr := ARRAY['B','Kb','Mb','Gb','Tb','Pb','Eb','Zb','Yb'];
    exponent := floor( log(b) / log(1024));
    val := b/power(1024,exponent);
    val := round(val*2)/2;

    sz := arr[trunc(floor(log(b) / log(1024)))];

    if strpos(val::varchar,'.') > 0  then
       result := substr(val::varchar, 1, strpos(val::varchar,'.')-1);
       result := result || '.' || rpad( substr(val::varchar, strpos(val::varchar,'.')+1), 2, '0' ) || ' ' || sz;
    else
       result := val::varchar || '.00 ' || sz;
    end if;
    return result;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

作为这个函数的结果:

select human_readable_bits(328582446690656456434534453) hrb0,
       human_readable_bits(3285824466906) hrb1,
       human_readable_bits(5920466906) hrb2,
       human_readable_bits(1024) hrb3,
       human_readable_bits(512) hrb4,
       human_readable_bits(null) hrb5;

会导致:

   hrb0       hrb1        hrb2        hrb3        hrb4        hrb5
  272.00 Zb  3.00 Gb     5.50 Mb     1.00 B     512 Bits       0 B

根据您的附带问题,可以在Create Function Documentation中轻松找到答案

SECURITY INVOKER表示该函数将以调用它的用户的权限执行。这是默认设置。SECURITY DEFINER 指定该函数将以创建它的用户的权限执行。

于 2017-02-05T14:39:37.050 回答