如何将php数组传递给postgres函数

Rya*_*sch 5 php postgresql postgresql-9.1

我正在努力将PHP数组传递给以下函数.

$recipients = array();
$recipients['6c2f7451-bac8-4cdd-87ce-45d55d152078'] = 5.00;
$recipients['8c2f3421-bac8-4cdd-87ce-45d55d152074'] = 10.00;

$originator = '5630cc6d-f994-43ff-abec-1ebb74d39a3f';
$params = array($originator, $recipients);

pg_query_params(_conn, 'SELECT widgetallocationrequest($1, $2)', $params);

$results = pg_fetch_all(pg_query_params);
...
Run Code Online (Sandbox Code Playgroud)

该函数接受自定义类型的数组:

CREATE TYPE widgetallocationrequest AS (id uuid, amount numeric(13,4));
Run Code Online (Sandbox Code Playgroud)

并枚举每个项目并执行一项操作:

CREATE FUNCTION distributeWidgets(pid uuid, precipients widgetallocationrequest[])
 RETURNS BOOLEAN AS
 $BODY$
{
FOREACH v_recipient IN ARRAY precipients
LOOP
    ...do something
END LOOP;
}
  RETURN TRUE;
END;
$BODY$
LANGUAGE plpgsql VOLATILE STRICT
COST 100;

***(if the specific code sample contains errors it's only pseudocode, i'm really just looking for the best way to pass a php array to a postgres custom type array as a parameter so it can be enumerated in the postgres function)***
Run Code Online (Sandbox Code Playgroud)

更新:我能够通过以下方式直接从postgres(而不是从PHP)成功调用该函数:

SELECT distributeWidgets('5630cc6d-f994-43ff-abec-1ebb74d39a3f',
ARRAY[('ac747f0e-93d4-43a9-bc5b-09df06593239', '5.00'), ('8c2f3421-bac8-4cdd-87ce-45d55d152074', '10.00')]::widgetallocationrequest[]);
Run Code Online (Sandbox Code Playgroud)

但仍然不确定如何从这个postgres示例转换回PHP

我已尝试过以下建议,引用函数的输出会产生以下错误:

在此输入图像描述

函数的字符串如下:

'SELECT account.hldtoexpalloc('0d6311cc-0d74-4a32-8cf9-87835651e1ee', '0124a045-b2e8-4a9f-b8c4-43b1e4cf638d', '{{\"6c2f7451-bac8-4cdd-87ce-45d55d152078\",5.00},{\"8c2f3421-bac8-4cdd-87ce-45d55d152074\",10.00}}')'
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 4

更新:我刚刚注意到您不仅需要数组,还需要使用复合类型的数组。恶心。我从来不需要和他们一起工作,所以我必须做一些检查。

数组的正确 PostgreSQL 语法似乎是widgetallocationrequest

'{"(8c2f3421-bac8-4cdd-87ce-45d55d152074,10.0000)","(6c2f7451-bac8-4cdd-87ce-45d55d152078,5.0000)"}'::widgetallocationrequest[]
Run Code Online (Sandbox Code Playgroud)

看看每个复合类型行是如何包含在"(col1,col2)"数组{a,b,c}容器中的?

以下是我如何创建该值的 PostgreSQL SQL 示例:

-- Create the array of composites from a VALUES() statement
--
SELECT array_agg(x::widgetallocationrequest) 
FROM (VALUES 
    ('8c2f3421-bac8-4cdd-87ce-45d55d152074',10.00),
    ('6c2f7451-bac8-4cdd-87ce-45d55d152078',5.00)
) x;
Run Code Online (Sandbox Code Playgroud)

...以及我如何验证它的有效性:

-- Unpack it back into a row-set of columns
SELECT * FROM unnest('{"(8c2f3421-bac8-4cdd-87ce-45d55d152074,10.0000)","(6c2f7451-bac8-4cdd-87ce-45d55d152078,5.0000)"}'::widgetallocationrequest[]);
Run Code Online (Sandbox Code Playgroud)

现在,PHP 的 Pg 驱动程序甚至不支持数组,更不用说复合类型的数组了,因此您必须找到其他人编写您想要的内容或自己编写。编写一个可靠的解析器会很“有趣”,但不会有效地利用时间。

让我们采取另一种方法:生成一个查询,让您通过转换到widgetallocationrequest[]内部 PostgreSQL 来正常调用该函数。

这是一个虚拟函数,其参数与真实函数相同,我们将用作调用目标:

CREATE OR REPLACE FUNCTION distributeWidgets(pid uuid, precipients widgetallocationrequest[]) RETURNS boolean AS $$
SELECT 't'::boolean;
$$ LANGUAGE 'sql';
Run Code Online (Sandbox Code Playgroud)

您可以看到它可以使用复合数组语法来调用,这给您带来了很多麻烦:

SELECT distributewidgets(null, '{"(8c2f3421-bac8-4cdd-87ce-45d55d152074,10.0000)","(6c2f7451-bac8-4cdd-87ce-45d55d152078,5.0000)"}');
Run Code Online (Sandbox Code Playgroud)

...但理想情况下,您希望避免从 PHP 中生成任何可怕的内容,并且驱动程序缺少重要功能,因此它无法为您做到这一点。

相反,您可以使用TEMPORARY表来生成参数,INSERT将每个参数行放入具有常规参数化的表中INSERT,然后执行查询来执行该函数。

BEGIN;

CREATE TEMPORARY TABLE dw_args ( id uuid, amount numeric(13,4) );

-- Use proper parameterized INSERTs from PHP, this is just an example
INSERT INTO dw_args(id,amount) VALUES ('8c2f3421-bac8-4cdd-87ce-45d55d152074',10.00);
INSERT INTO dw_args(id,amount) VALUES ('6c2f7451-bac8-4cdd-87ce-45d55d152078',5.00);

SELECT distributewidgets(null, array_agg(ROW(x.*)::widgetallocationrequest)) 
FROM dw_args x;

DROP TABLE dw_args;

COMMIT;
Run Code Online (Sandbox Code Playgroud)

警告:如果处理不当,以下内容很容易受到SQL 注入攻击。如果可能的话,使用上述临时表方法。不要成为鲍比的下一个受害者;阅读有关 SQL 注入的 PHP 文档

如果由于某种原因绝对有必要在一个语句中运行所有这些内容,您可以使用VALUESPHP 中的一组查询生成一个查询,并将其转换为widgetallocationrequest[]使用 PostgreSQL 查询。我在上面演示了它,但以下是如何将其与调用结合起来 distributeWidgets(...)

SELECT distributewidgets(null, array_agg(x::widgetallocationrequest)) 
FROM (VALUES 
        ('8c2f3421-bac8-4cdd-87ce-45d55d152074',10.00),
        ('6c2f7451-bac8-4cdd-87ce-45d55d152078',5.00)
) x;
Run Code Online (Sandbox Code Playgroud)

只要您非常小心SQL 注入,您就可以使用字符串操作在 PHP 中轻松构建这种东西。

如果可能的话,请使用临时表方法。

另请参见PHP 数组到 postgres 数组

  • 我敢打赌,这是因为任何关心语言正常工作的人都已经放弃了 PHP。前进一步,后退两步。特别是在涉及面向对象支持的情况下。 (3认同)