4

当我添加 :start 作为要跳过的参数时,出现以下错误。我知道如果我对 SKIP/NEXT 值进行硬编码并且 :customerID 保持不变,SQL 查询就可以工作。如果我删除 :start 子句并将其保留为SKIP 1 FIRST 5 ... WHERE t1.customer_num = :customerID ...正常工作。我找不到错误发生的原因。

错误

exception 'PDOException' with message 'SQLSTATE[HY004]: Invalid SQL data type: -11064 [Informix][Informix ODBC Driver]SQL data type out of range

我试过的东西:

  1. 使用 BindParam 而不是 BindValue 通过引用来绑定参数。
  2. 使用 PDO_STR 尝试将 :start 绑定为字符串。没有成功。
  3. SQL 查询本身中 :start 的硬编码值。这行得通。
  4. 使用$sql->bindValue(':start', (int) 1, PDO:PARAM_INT);——不行。
  5. 通过首先分配给 PHP 变量来尝试数字 4,结果相同。

有什么建议么?我正在使用 PHP 5.3。(最近的东西)和 Informix 11 使用 PDO 连接器。同样,它仅适用于 customerID,但不适用于 :start 并返回上述错误。

$sql = null;
$sql= $conn->prepare('SELECT SKIP :start FIRST 5 TRIM(loc_esi_id) FROM customer       t1,customer_ts_data t2 WHERE t1.customer_num = :customerID AND t1.customer_num = t2.customer_num');

//Bind values to parameters(by value)
$sql->bindValue(':start',   $start ,PDO::PARAM_INT);
$sql->bindValue(':customerID', $customerID, PDO::PARAM_INT);

//$sql->bindParam(':count',$count,PDO::PARAM_INT);
$results = null;
try{
$sql->execute();
$results = $sql->fetchAll();
} catch (PDOException $e) {
//Error Handling, etc.
4

1 回答 1

2

通常,:start占位符的表示法既不是标准 SQL 语法也不是(本机)Informix 语法。您需要使用 a?作为占位符,因此:

$sql= $conn->prepare('SELECT SKIP ? FIRST 5 TRIM(loc_esi_id)
                        FROM customer t1
                        JOIN customer_ts_data t2 ON t1.customer_num = t2.customer_num
                       WHERE t1.customer_num = ? AND ');

(如果这一切都需要在 PHP 中写成一行,我很抱歉为了可读性而牺牲了准确性)。

现在,PDO 系统有可能自动将:start符号转换为?,在这种情况下,我们遇到了不同的问题。但是,除非您确定该:name符号有效,否则……不确定的一个原因是bindValue()呼叫似乎需要名称,而不是?可能需要的数字。您的代码错误检查了bindValue()调用吗?

这个 ESQL/C 代码有效,产生了我期望的输出。

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    $ char *dbase = "stores";
    $ int num_skip = 3;
    $ int num_fetch = 5;
    if (argc > 2)
    {
    fprintf(stderr, "Usage: %s [dbase]\n", argv[0]);
    exit(1);
    }
    if (argc == 2)
    dbase = argv[1];

    exec sql whenever error stop;
    exec sql connect to :dbase;

    exec sql prepare p from "select skip ? first ? tabid, tabname from informix.systables";
    exec sql declare c cursor for p;

    exec sql open c using :num_skip, :num_fetch;
    while (sqlca.sqlcode == 0)
    {
    $ int4 tabid;
    $ varchar tabname[129];
    exec sql fetch c into :tabid, :tabname;
    if (sqlca.sqlcode != 0)
        break;
    printf("%d: %s\n", tabid, tabname);
    }
    exec sql close c;

    exec sql free c;
    exec sql free p;
    exec sql disconnect all;
    return 0;
}

输出

4: systabauth
5: syscolauth
6: sysviews
7: sysusers
8: sysdepend

这表明如果正确使用占位符表示法,则可以将参数用于 SKIP 和 FIRST。

如果你找不到一种方法让它与 PDO 一起工作,你可能遇到了一个错误。如果您可以在将环境变量设置为某个类似值的情况下运行您的代码SQLIDEBUG=2:/tmp/your_sub_dir/check,那么您应该在一个名为/tmp/your_sub_dir/check_21484_0_aedc1e0. 数字模式有点变化。然后,您可以sqliprint在文件上运行程序并查看 PDO 发送到服务器的内容。这将是确定 PDO 或 Informix 中是否存在错误的一种非常快速的方法。

例如,我得到的部分输出sqliprint是:

C->S (20)               Time: 2012-05-29 17:55:08.65225
    SQ_CONNECT
         "stores" [6]
         "stores" [6]

C->S (72)               Time: 2012-05-29 17:55:08.65239
    SQ_PREPARE
        # values: 2
        CMD.....: "select skip ? first ? tabid, tabname from informix.systables" [60]
    SQ_NDESCRIBE
    SQ_WANTDONE
    SQ_EOT

可以很清楚的看到发送的 SQL 语句。如果你没有看到?占位符,那么上游就有问题;Informix 的 PDO 驱动程序没有正常工作,或者被滥用。如果你看到?占位符,我们会遇到不同的问题,但如果这是问题,我会感到惊讶。

SQLIDEBUG 机制中唯一需要注意的是,您需要在连接到数据库的任何进程的环境中设置环境变量。对于独立的 ESQL/C 程序,这很简单。如果您正在使用 Web 服务器和 PHP,那可能会比较棘手 — 但可以做到。

于 2012-05-30T01:00:04.723 回答