如何将参数化 ORDER BY 与 pg_prepare() pg_execute() 一起使用


How to use parametric ORDER BY with pg_prepare() pg_execute()?

我想按用户决定的东西对这个查询进行排序,所以我把它参数化了。我真的不明白为什么第二个参数被忽略了!(它不对结果进行排序)

function getY($id, $order){
    ....
    ....
    $db = connection_pgsql() or die ('connection failed');
    $sql = "SELECT id, y FROM test WHERE id = $1 ORDER BY $2";
    $resource = pg_prepare($db, "get_y", $sql);
    $value = array($id, $order);
    $resource = pg_execute($db, "get_y", $value);
    ....
    ....
}

如果我像这样传递它:

$sql = "SELECT id, y FROM test WHERE id = $1 ORDER BY {$order}";

有效,但我认为它不安全(不是吗?

我只发现了PDO::execute的pgsql 42601错误,这实际上并不能解决我的问题。

ORDER BY $2 正在对固定值进行排序,如下所示:

SELECT * FROM t1 ORDER BY 'some string';

由于所有记录都将按同一字符串排序,因此没有排序。

ORDER BY 也是无法准备的东西,因为在准备期间您没有告诉数据库要用于排序的列。这就像计划一次公路旅行,但不知道去哪里。

要解决此问题,您需要动态SQL和其他一些安全措施:

function getY($id, $order){
    ....
    ....
    $db = connection_pgsql() or die ('connection failed');
    $sql = "SELECT quote_ident($1);"; // give me a secure object name
    $resource = pg_query_params($db, $sql, array($order)); // error handling is missing
    $order = pg_fetch_result($resource, 0, 0);
    $sql = "SELECT id, y FROM test WHERE id = $1 
        ORDER BY ".$order.";"; // <===== it's now safe to use
    $resource = pg_prepare($db, "get_y", $sql); // error handling is missing
    $value = array($id);
    $resource = pg_execute($db, "get_y", $value); // error handling is missing
    ....
    ....
}

现在,您创建了一个完整的 SQL 字符串,该字符串可以准备并因 quote_ident() 而保存。无论$order中有什么内容,它都将被视为PostgreSQL中的标识符。在这种情况下就像一列。如果缺少该列,准备将失败。这就是为什么您需要正确的错误处理,您知道有一天此查询会因为输入错误而失败。

如果只使用此语句一次,也可以使用 pg_query_params() 代替 pg_prepare() + pg_execute()。