2

2日間格闘した後、ここで助けを求めてみます。CentOS 5.4 サーバーで DB2 (iSeries) および PHP (5.3) を操作するために unixODBC (2.2.11) を使用しています。PHP を 5.1 から 5.3 にアップグレードしてからだと思いますが、特定のクエリで PHP が segfault するようになりました。いくつかの調査の後、次のテーブルなど、長い文字フィールドを持つ一部のクエリで問題が発生することを発見しました。

TABLE (
    CONTRACTID  NUMERIC,
    SOMETEXT    CHAR(583)
)

この単純なコードは、segfault を引き起こします。

try {
    $conn = new PDO("odbc:".$dsn, $username, $password, array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
    );
}
catch (Exception $e) {
    echo $e->getMessage();
}

$sql = 'SELECT * FROM LIB.TABLE ';
$stmt = $conn->prepare($sql);
$vals = $stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

unixODBC および/または PHP >= 5.1 の列の長さの制限またはバグはありますか? このWebアプリケーションは非常にうまく機能しましたが、この問題に遭遇しました..

ところで、unixODBC 2.2.14 と PHP 5.3 を搭載した最新の 64 ビット CentOS 6.2 マシンでテストしましたが、問題は同じです。

どんな助けでも大歓迎です、

ありがとう

ファビアン

更新: PHP odbc 関数を使用すると、動作します:

$conn = odbc_connect($dsn, $username, $password);
$res = odbc_exec($conn, $sql);
$rows = odbc_fetch_array($res);

したがって、問題は PDO に関連しています。何か考えはありますか?

4

3 に答える 3

9

ここで同じ問題に遭遇しました。64 ビットの php-odbc モジュールが、NULL 値を持つフィールドを返すときにセグ フォールトを引き起こしていることがわかりました。回避策は、NULL 値が存在する可能性のある各フィールドを結合することです。それは良い解決策ではありません。php-odbc.c コードを見ていますが、修正を保証することはできません。

回避策: SELECT COALESCE(CHAR(フィールド名),'') FROM ...

このサーバーを 32 ビット版に置き換えようと思います。私はうまく機能する他の人を持っています。

于 2012-11-30T13:48:49.467 に答える
6

Centos 6.3 と Vertica 6 および Centos に付属の UnixODBC で同様の問題が発生しました。PHP は単に segfault になります。だから私は走っstrace php mytest.phpて、それが見つけて開こうとしているのを見つけました/usr/lib64/libodbccr.so.1

ただし、Centos 6.3 のみlibodbccr.so.2

したがって、迅速で汚い修正は、次の手順を実行することです。/usr/lib64

ln -s libodbccr.so.2 libodbccr.so.1

自己責任!

于 2013-01-09T21:14:47.477 に答える
5

pdo (いずれにしても使用していません)、unixODBC、または DB2 ドライバーの問題を知っているとは言えません。最初のプラットフォームが 64 ビット ビルドを使用しているのか 32 ビット ビルドを使用しているのか、あなたのメールからはわかりませんが、Microsoft が 64 ビット サポートを追加したときに ODBC が変更されました ( SQLLEN/SQLULEN および 32/64 ビット プラットフォーム64 ビット ODBCを参照)。)。基本的に、一部の ODBC API の型は SQLINTEGER から SQLLEN に変更されており、SQLLEN は 64 ビット ビルドでは 64 ビット、32 ビット ビルドでは 32 ビットです。ただし、Microsoft がこれを行うことを誰も知らなかったので、これらの引数の一部は実際には仕様で 32 ビット量として記述されていたため、一部の ODBC ドライバー作成者はこれらの引数に 32 ビット量を使用して 64 ビット プラットフォーム用の ODBC ドライバーを既に構築していました。明らかに、ある方法で構築されたアプリケーションまたはドライバー マネージャーと、別の方法で構築されたドライバーを混在させると、すべてが壊れて失われ、segfault が発生する可能性が非常に高くなります。そのため、まず、64 ビット バイナリを使用している場合は、ODBC ドライバーが正しくビルドされているかどうかを確認する必要があります。IBM にお問い合わせください。

unixODBC 2.2.11 はかなり古く、問題が修正されたことはわかっていますが、まだ広く使用しており、カーソル ライブラリに小さな問題が 1 つだけあります。とにかく、2.2.14 を試してみましたが、問題は同じでした。それが unixODBC の問題であるとは思えませんが、それは私の豊富な経験に基づくものであり、事実を知っているからではありません。

さて、上で概説した状況に陥らないと仮定すると、多くのことを行うことができます。unixODBC でログを有効にしてみてください。そうすれば、どの ODBC 呼び出しが行われているか、どれが失敗したかを確認できます。また、何が起こっているのかについて、渡された引数から手がかりを得るかもしれません。odbcinst.ini ファイルに以下を追加して、ロギングを有効にします。

[ODBC]
Trace=yes
TraceFile=/tmp/unixodbc.log

問題の列に対する SQLBindCol または SQLGetData の呼び出しを探します。これでうまくいかない場合は、最後をここに貼り付けてみてください。確認します。

コマンド ラインから PHP プログラムを実行できる場合、gdb をインストールすると、gdb の下で実行でき、問題が発生した場所のスタック ダンプが表示されます。gdb /path/to/php を実行してから r myscript.php と入力し、Enter を押して実行します。セグメンテーション違反が発生した場合は、bt (バックトレース) コマンドを使用してスタックを表示できます。それは、どのコードがセグメンテーション違反を引き起こしているかを特定する必要がありますが、必ずしもそのコードが障害であるとは限りません (たとえば、php が 10 バイトのバッファーへのポインターを渡したが嘘をつき、それが 100 バイトであると言った場合、末尾を書き出すコードはそうではありません故障して)。

于 2012-06-07T12:19:15.570 に答える