Pengikatan variabel untuk Informix mengembalikan kesalahan

Saya mendapatkan kesalahan berikut ketika saya menambahkan :start sebagai parameter untuk dilewati. Saya tahu kueri SQL berfungsi jika saya mengkodekan nilai SKIP/NEXT dengan keras dan :ID Pelanggan dibiarkan begitu saja. Jika saya menghapus klausa :start dan membiarkannya sebagai SKIP 1 FIRST 5 ... WHERE t1.customer_num = :customerID ... itu berfungsi dengan baik. Saya tidak dapat menemukan mengapa kesalahan ini terjadi.

Kesalahan

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

Hal yang saya coba:

  1. Menggunakan BindParam alih-alih BindValue untuk mengikat parameter dengan referensi.
  2. Menggunakan PDO_STR untuk mencoba mengikat :start sebagai string. Tidak berhasil.
  3. Nilai pengkodean keras untuk :start dalam kueri SQL itu sendiri. Ini bekerja.
  4. Menggunakan $sql->bindValue(':start', (int) 1, PDO:PARAM_INT); jangan pergi.
  5. Mencoba nomor 4 dengan menugaskan variabel PHP terlebih dahulu, hasilnya sama.

Ada Saran? Saya menggunakan PHP 5.3.(sesuatu yang terbaru) dengan Informix 11 menggunakan konektor PDO. Sekali lagi, ini berfungsi hanya dengan ID pelanggan tetapi tidak dengan :start dan mengembalikan kesalahan di atas.

$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 sumber


Jawaban (1)


Secara umum, notasi :start untuk placeholder bukanlah sintaks SQL standar atau sintaks Informix (asli). Anda perlu menggunakan ? untuk placeholder, jadi:

$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 ');

(dan jika semuanya harus dalam satu baris di PHP, saya minta maaf karena telah mengorbankan akurasi demi keterbacaan).

Sekarang, ada kemungkinan sistem PDO mengubah notasi :start menjadi ? secara otomatis, dalam hal ini kita menghadapi masalah yang berbeda. Namun kecuali Anda yakin bahwa notasi :name berfungsi, ... Salah satu alasan untuk tidak yakin adalah bahwa panggilan bindValue() sepertinya memerlukan nama, bukan nomor yang mungkin diperlukan oleh ?. Apakah kesalahan kode Anda memeriksa panggilan bindValue()?

Kode ESQL/C ini berfungsi, menghasilkan output yang saya harapkan.

#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;
}

Keluaran

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

Hal ini menunjukkan bahwa jika notasi placeholder digunakan dengan benar, maka Anda dapat menggunakan parameter untuk SKIP dan FIRST.

Jika Anda tidak dapat menemukan cara agar ini berfungsi dengan PDO, Anda mungkin mendapatkan bug. Jika Anda dapat menjalankan kode Anda dengan variabel lingkungan SQLIDEBUG=2:/tmp/your_sub_dir/check yang disetel ke nilai serupa, maka Anda akan menemukan catatan tentang apa yang dikirim ke server (selain pengaturan koneksi) dalam file dengan nama seperti /tmp/your_sub_dir/check_21484_0_aedc1e0. Pola angkanya sedikit bervariasi. Anda kemudian dapat menjalankan program sqliprint pada file tersebut dan melihat apa yang dikirim PDO ke server. Ini akan menjadi cara yang sangat cepat untuk menentukan apakah PDO atau Informix mempunyai bug di dalamnya.

Misalnya, bagian dari keluaran yang saya dapatkan dari sqliprint adalah:

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

Anda dapat melihat pernyataan SQL yang dikirim dengan sangat jelas. Jika Anda tidak melihat ? placeholder, berarti ada masalah di bagian hulu; baik driver PDO untuk Informix tidak berfungsi dengan benar, atau sedang disalahgunakan. Jika Anda melihat placeholder ?, kita akan menghadapi masalah yang berbeda, tapi saya akan terkejut jika itu masalahnya.

Satu-satunya peringatan dalam mekanisme SQLIDEBUG adalah Anda perlu mengatur variabel lingkungan di lingkungan proses mana pun yang terhubung ke database. Untuk program ESQL/C mandiri, itu sepele. Jika Anda menggunakan server web dan PHP, itu mungkin lebih rumit tetapi bisa dilakukan.

person Jonathan Leffler    schedule 30.05.2012
comment
Saya lupa menyebutkan bahwa saya mencoba varian posisi menggunakan ? bukannya :nilai. :value adalah cara alternatif PHP menangani parameter untuk menghindari penggunaan posisi. Saya tahu pasti :value berfungsi karena jika saya melakukan hardcode pada nilai SKIP/FIRST dan membiarkan parameter :value lainnya tetap utuh, kueri berfungsi seperti yang diharapkan. Saya mengatasi masalah ini dengan menggunakan metode kotor dalam memperlakukan SQL seperti string, menggunakan hal-hal seperti sprintf, dll untuk memasukkan parameter ke dalam pernyataan dan kemudian menyiapkan string yang dihasilkan. - person Howard Grimberg; 31.05.2012
comment
Mengerikan; sepertinya kode apa pun yang menguraikan permintaan tidak menyadari bahwa SKIP dan FIRST dapat diikuti oleh placeholder, meskipun hal ini mengejutkan karena akan jauh lebih sulit untuk menguraikannya dengan cara itu. Meskipun demikian, notasi :name merupakan gangguan yang membingungkan karena bertabrakan dengan notasi asli Informix seperti dbase:owner.object. Apakah itu pengganti atau bukan? Ini juga bertabrakan dengan notasi value::int, meskipun titik dua dapat digunakan untuk memperjelasnya. Dan juga dengan DATETIME(2012-05-30 15:30:29) YEAR TO SECOND, setidaknya pada varian dimana :1 OK. - person Jonathan Leffler; 31.05.2012
comment
Pertimbangkan untuk melaporkan masalah ini ke tim PDO di IBM, jika Anda dapat menemukan alamat email (atau URL) yang benar. 'Bukan saya, itu saja, tapi Anda bisa memberi tahu mereka bahwa saya mengirim Anda jika mereka bertanya (jleffler di kami dot ibm dot com). Akan lebih baik jika kita memiliki catatan SQLIDEBUG/sqliprint tentang apa yang dikirim ke server (serta apa yang Anda kirim ke PDO Informix). - person Jonathan Leffler; 31.05.2012
comment
Saya baru saja mengirim email kepada orang-orang yang bertanggung jawab. - person Howard Grimberg; 31.05.2012
comment
Apakah Anda pernah menemukan solusi untuk ini? Saya mengalami masalah yang sama -- menyiapkan pertanyaan dengan nilai SKIP/FIRST sebagai parameter mengembalikan tipe data SQL di luar jangkauan - person fukawi2; 12.09.2017
comment
Ya. Ini adalah bug pada driver PDO untuk Informix. Saya akhirnya mengatasinya dengan menggunakan pemrosesan string untuk membuat string SQL mentah dan mengirimkannya sebagai parameter. Sisi negatifnya adalah hilangnya pelolosan string, parameterisasi. Gunakan dengan hati-hati. - person Howard Grimberg; 12.09.2017