【问题标题】:Variable binding for Informix returns an errorInformix 的变量绑定返回错误
【发布时间】:2012-05-29 16:55:43
【问题描述】:

当我添加 :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.

【问题讨论】:

    标签: php pdo informix


    【解决方案1】:

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

    $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,这可能会比较棘手 — 但可以做到。

    【讨论】:

    • 我忘了提到我确实尝试过使用 ?而不是 :value:value 是 PHP 处理参数以避免使用位置的另一种方式。我知道一个事实 :value 有效,因为如果我将 SKIP/FIRST 值硬编码并保持其他 :value 参数不变,则查询将按预期工作。我通过使用将 SQL 视为字符串的“脏”方法解决了这个问题,使用 sprintf 之类的东西将参数放入语句中,然后准备结果字符串。
    • 可怕;听起来有点好像解析请求的任何代码都没有意识到 SKIP 和 FIRST 可以后跟占位符,尽管这令人惊讶,因为这样解析会困难得多。话虽如此,:name 表示法令人困惑,因为它与 Informix 原生表示法(例如 dbase:owner.object)相冲突。那是占位符吗?它也与value::int 符号冲突,尽管双冒号可以用来消除歧义。还有DATETIME(2012-05-30 15:30:29) YEAR TO SECOND,至少在:1 可以的变体中。
    • 如果您能找到正确的电子邮件地址(或 URL),请考虑将问题报告给 IBM 的 PDO 团队。 '不是我,仅此而已,但如果他们问,你可以告诉他们我派你来的(jleffler at us dot ibm dot com)。如果我们有确切的发送到服务器的内容(以及您发送到 PDO Informix 的内容)的 SQLIDEBUG/sqliprint 记录,那将是最好的。
    • 我刚刚给负责人发了电子邮件。
    • 您找到解决方案了吗?我遇到了同样的问题——使用 SKIP/FIRST 值作为参数进行查询准备返回“SQL 数据类型超出范围”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 2011-05-17
    相关资源
    最近更新 更多