การเชื่อมโยงตัวแปรสำหรับ Informix ส่งกลับข้อผิดพลาด

ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อฉันเพิ่ม :start เป็นพารามิเตอร์ที่จะข้าม ฉันรู้ว่าแบบสอบถาม SQL ใช้งานได้หากฉันฮาร์ดโค้ดค่า SKIP/NEXT และ :customerID ถูกทิ้งไว้ตามลำพัง ถ้าฉันลบส่วนคำสั่ง :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. ค่าฮาร์ดโค้ดสำหรับ :start ในแบบสอบถาม SQL เอง มันได้ผล
  4. ใช้ $sql->bindValue(':start', (int) 1, PDO:PARAM_INT); ไม่ต้องไป
  5. ลองหมายเลข 4 โดยกำหนดให้กับตัวแปร PHP ก่อน ผลลัพธ์เดียวกัน

ข้อเสนอแนะใด ๆ? ฉันใช้ 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.

person Howard Grimberg    schedule 29.05.2012    source แหล่งที่มา


คำตอบ (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 ที่ส่งมาได้ชัดเจนมาก หากคุณไม่เห็นตัวยึดตำแหน่ง ? แสดงว่ามีปัญหาที่ต้นทาง ไดรเวอร์ PDO สำหรับ Informix ทำงานไม่ถูกต้องหรือมีการใช้งานในทางที่ผิด หากคุณเห็นตัวยึดตำแหน่ง ? เราคงประสบปัญหาอื่น แต่ฉันคงจะแปลกใจถ้านั่นคือปัญหา

ข้อแม้เดียวในกลไก SQLIDEBUG คือคุณต้องได้รับการตั้งค่าตัวแปรสภาพแวดล้อมในสภาพแวดล้อมของกระบวนการใดก็ตามที่เชื่อมต่อกับฐานข้อมูล สำหรับโปรแกรม ESQL/C แบบสแตนด์อโลนนั่นเป็นเรื่องเล็กน้อย หากคุณกำลังใช้งานผ่านเว็บเซิร์ฟเวอร์และ PHP นั่นอาจจะยุ่งยากกว่าแต่ก็สามารถทำได้

person Jonathan Leffler    schedule 30.05.2012
comment
ฉันลืมบอกไปว่าฉันได้ลองใช้ตัวแปรตำแหน่งโดยใช้ ? แทนที่จะเป็น :value :value เป็นอีกทางเลือกหนึ่งที่ PHP จัดการพารามิเตอร์เพื่อหลีกเลี่ยงการใช้ตำแหน่ง ฉันรู้ว่า :value ใช้งานได้จริงเพราะหากฉันฮาร์ดโค้ดค่า SKIP/FIRST และปล่อยให้พารามิเตอร์ :value อื่นๆ ยังคงอยู่ แบบสอบถามจะทำงานตามที่คาดไว้ ฉันแก้ไขปัญหานี้ได้โดยใช้วิธีสกปรกในการจัดการกับ SQL เหมือนเป็นสตริง โดยใช้สิ่งต่าง ๆ เช่น sprintf ฯลฯ เพื่อนำพารามิเตอร์เข้าสู่คำสั่ง จากนั้นเตรียมสตริงผลลัพธ์ - person Howard Grimberg; 31.05.2012
comment
น่าสยดสยอง; ฟังดูราวกับว่าโค้ดใดก็ตามที่กำลังแยกวิเคราะห์คำขอไม่ทราบว่าสามารถตามด้วยตัวยึดตำแหน่ง SKIP และ FIRST ได้ แม้ว่าจะเป็นเรื่องที่น่าแปลกใจเนื่องจากการแยกวิเคราะห์ด้วยวิธีนั้นจะยากกว่ามาก ต้องบอกว่า :name สัญกรณ์เป็นสิ่งที่น่ารำคาญเนื่องจากขัดแย้งกับสัญกรณ์ดั้งเดิมของ Informix เช่น dbase:owner.object นั่นเป็นตัวยึดตำแหน่งหรือไม่? นอกจากนี้ยังขัดแย้งกับสัญกรณ์ value::int แม้ว่าจะสามารถใช้เครื่องหมายทวิภาคคู่เพื่อแยกความกำกวมได้ก็ตาม และยังมี DATETIME(2012-05-30 15:30:29) YEAR TO SECOND อย่างน้อยก็ในรูปแบบที่ :1 ใช้ได้ - person Jonathan Leffler; 31.05.2012
comment
ลองรายงานปัญหาไปยังทีม PDO ที่ IBM หากคุณสามารถค้นหาที่อยู่อีเมล (หรือ URL ที่ถูกต้อง) ได้ 'ไม่ใช่ฉัน แค่นั้นแหละ แต่คุณสามารถบอกพวกเขาว่าฉันส่งให้คุณหากพวกเขาถาม (jleffler ที่ us dot ibm dot com) คงจะดีที่สุดถ้าเรามีบันทึก SQLIDEBUG/sqliprint ของสิ่งที่ถูกส่งไปยังเซิร์ฟเวอร์อย่างแน่นอน (รวมถึงสิ่งที่คุณส่งไปยัง PDO Informix) - person Jonathan Leffler; 31.05.2012
comment
ฉันเพิ่งส่งอีเมลถึงคนที่รับผิดชอบ - person Howard Grimberg; 31.05.2012
comment
คุณเคยพบวิธีแก้ไขปัญหานี้หรือไม่? ฉันมีปัญหาเดียวกัน - เตรียมการสืบค้นด้วยค่า SKIP/FIRST เนื่องจากพารามิเตอร์ส่งคืนชนิดข้อมูล SQL อยู่นอกช่วง - person fukawi2; 12.09.2017
comment
ใช่. นี่เป็นจุดบกพร่องในไดรเวอร์ PDO สำหรับ Informix ฉันสิ้นสุดการแก้ไขโดยใช้การประมวลผลสตริงเพื่อสร้างสตริง SQL แบบดิบและส่งสิ่งนั้นเป็นพารามิเตอร์ ข้อเสียคือการสูญเสียการหลบหนีสตริง, การกำหนดพารามิเตอร์ ใช้ด้วยความระมัดระวัง - person Howard Grimberg; 12.09.2017