PostgreSQL C函数获取值

PostgreSQL C function to get values

我正在尝试用 C 编写 PostgreSQL 函数。

我的目标是找到列表的最小值。所以,我的函数将像这样执行:

SELECT min_to_max(val) FROM (VALUES(1),(2),(3)) x(val);
SELECT min_to_max(val) FROM my_table;

这是我的 C 代码,我在这里丢失了。例如,有一个名为“PG_GETARG_INT32”的函数可以获取整数值,但我不知道如何从 table 中获取值以便进行处理。有什么想法吗?

#include "postgres.h"
#include "fmgr.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(get_sum);

Datum
get_sum(PG_FUNCTION_ARGS)
{   
    ArrayType  *v1,
    bool isnull;

    isnull = PG_ARGISNULL(0);
    if (isnull)
      ereport( ERROR,
               ( errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
               errmsg("The input cannot be empty")));
    
    List a = PG_GETARR_SOMEFUNCTION_2_GET_LIST(0);

    # for loop iteration to find min_val

    # return min_val
}

已编辑(2022.05.13 - 以下为编辑部分):

感谢@Laurenz Albe。我取得了一些进步。

然而,现在我想走得更远(不需要使用 C 语言。正如 Laurenz Albe 所说,我只是迈出了一小步)。

我的函数和聚合如下所示,用于查找最小值和最大值:

CREATE or replace FUNCTION find_min_func(
    state integer,
    next  integer
) RETURNS integer
LANGUAGE plpgsql
STRICT
AS $$
declare
min_val integer;                      
begin                                 
if  <=  then min_val := ;       
elsif  < then min_val := ;      
end if;                               
return min_val;                       
END;
$$;

CREATE or replace AGGREGATE find_min(integer)
(
    SFUNC    = find_min_func,
    STYPE    = integer
);

CREATE or replace FUNCTION find_max_func(
    state integer,
    next  integer
) RETURNS integer
LANGUAGE plpgsql
STRICT
AS $$
declare
max_val integer;                      
begin                                 
if  >=  then max_val := ;       
elsif  >  then max_val := ;      
end if;                               
return max_val;                       
END;
$$;

CREATE or replace AGGREGATE find_max(integer)
(
    SFUNC    = find_max_func, -- State function
    STYPE    = integer       -- State type
);

他们工作得很好,但现在我想做一些类似

的事情

SELECT min_to_max(val) 来自 (VALUES(1),(2),(3)) x(val);

预期输出: 1 -> 3

所以,我只是写了一个状态函数和聚合对,如下所示(我知道这是错误的):

CREATE or replace FUNCTION find_min_and_max_func(
    state integer,
    next  integer
) RETURNS varchar
LANGUAGE plpgsql
STRICT
AS $$
declare
min_val integer;  
max_val integer;   
output varchar;                   
begin    
if  <=  then min_val := ;   max_val := ;      
elsif  < then min_val := ;   max_val := ;
end if;
output = cast(min_val as varchar) || '->' ||     cast(max_val as varchar)       ;             
return output;                       
END;
$$;

CREATE or replace AGGREGATE find_min_and_max(integer)
(
    SFUNC    = find_min_and_max_func, -- State function
    STYPE    = varchar       -- State type
);

这是错误的,因为状态函数将参数作为整数但 returns(?) varchar,所以它会变化。

如何在这里安排我的状态函数?

谢谢!

要创建聚合函数,您必须使用 CREATE AGGREGATE。您在 SQL 中创建它。您可能需要在 C 中实现的是 状态转换函数 (SFUNC),也许还有其他函数,具体取决于您要创建的聚合类型。

聚合函数不必从table中读取; PostgreSQL 执行器将向它提供所需的数据。

如果您开始编写 C 函数,您或许应该从比聚合函数更简单的东西开始。

在@Laurenz Albe(再次感谢他)的帮助下,我找到了解决方案。另外,我查看了:

  1. https://hoverbear.org/blog/postgresql-aggregates-with-rust/
  2. https://hashrocket.com/blog/posts/custom-aggregates-in-postgresql

这是我的解决方案:

CREATE or replace FUNCTION find_min_and_max_func(
    state point,
    next  integer
) RETURNS point
LANGUAGE plpgsql
STRICT
AS $$
declare
min_val integer;  
max_val integer;                   
begin    
if state[0] <= next then min_val := state[0];  
elsif next < state[0] then min_val := next;  
end if;
if state[1] >= next then max_val := state[1];  
elsif next > state[1] then max_val := next;  
end if;               
return point(min_val, max_val) ;                     
END;
$$;

CREATE or replace FUNCTION find_min_and_max_final_func(
    state point
) RETURNS varchar
LANGUAGE plpgsql
STRICT
AS $$                 
begin              
return cast(state[0] as varchar) || '->' || cast(state[1] as varchar) ;                     
END;
$$;


CREATE or replace AGGREGATE find_min_and_max(integer)
(
    SFUNC    = find_min_and_max_func, -- State function
    STYPE    = point,       -- State type
    FINALFUNC = find_min_and_max_final_func,
    initcond = '(1231231232131,0)'
);

SELECT find_min_and_max(value) FROM UNNEST(ARRAY [1, 2, 3]) as value;

 find_min_and_max
------------------
 1->6
(1 row)

谢谢!