因此,我一直在尝试使用 COPY (SELECT...) TO STDOUT WITH (FORMAT CSV, HEADER),但是
- PDO::query() 使用 prepare,而 COPY 不支持
- PDO::exec() 不返回结果
- PDO::pgsqlCopyToFile() 不支持其他参数,仅支持分隔符和空值(以及列)
但是您知道它支持什么吗?SQL 注入!
https://github.com/php/php-src/blob/7dfbf4d1b74b5e629f2331261944fa072a92e1cb/ext/pdo_pgsql/pgsql_driver.c#L870
spprintf(&query, 0, "COPY %s TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", ...
没有任何转义,因此您可以像这样调用此方法
<?php
$db->pgsqlCopyToFile("(select * from t1 cross join t2 using (whatever))", '/tmp/test.csv', ',', '\' header--');
?>
这实际上会产生
COPY (select...) TO STDIN WITH DELIMITER E',' NULL AS E'' header--
它仍然使用本地文件系统,我可以接受,但至少我不必绕过 CSV 标头。
如果有人知道在不将(在我的情况下是巨大的)结果集复制到数组和 fputcsv() 的情况下执行此操作的更好方法,我洗耳恭听。我尝试了 pg_query 和 pg_copy_to 的所有组合,但都无济于事。