1

サーバーの詳細:
PHP v5.3.5
MySQLi ライブラリを使用 クライアント API バージョン: mysqlnd 5.0.7-dev - 091210 - $Revision: 304625 $
MySQL サーバー v5.5.9

MySQL に f_get_owner_locations( _in int ) というストアド関数があります。特定の所有者が所有するコンドミニアムの場所を保持するテキスト変数を作成します。私が実行した場合

SELECT f_get_owner_locations( 3 );  

MySQL コマンド ラインから、本来の処理を実行し、1 行を返します。

+----------------------------+
| f_get_owner_locations( 3 ) |
+----------------------------+
| A-01                       |
+----------------------------+

ただし、MySQLi ライブラリを使用して PHP で実行しようとすると、次のようになります。

$sql = "SELECT f_get_owner_locations( 3 )";
$location = $GLOBALS['db']->fetch( $sql );

次のエラーが表示されます。

Fatal error: Call to a member function fetch_field() on a non-object 
in ~/kernel/Database.php on line 328

その行はこれを参照しています:

/**
 * Binds results from a returning SQL statement to an array we can 
 * loop through.
 * 
 * @param   $statement  Statement object we're binding from.
 * @return  Array of values being returned.
 * @since   0.1
 */
private final function _bindResult( $statement )
{
    $results = NULL;
    $bind = array( );

    //Get the result set, so we can loop through the fields.
    $result = $statement->result_metadata( );
    //Loop through the fields and get a reference to each.
    while( $column = $result->fetch_field() ) //<=<=<=LINE 328
        $bind[] = &$results[$column->name];
    //Do the actual binding.
    call_user_func_array( array( $statement, 'bind_result'), $bind );

    //Free the memory since we already have the result.
    $result->free_result();

    return $results;
} //_bindResult

SQL ステートメントに関数呼び出しが含まれていない場合は失敗しないことに注意してください。つまり、これは機能します:

$sql = "SELECT `id` FROM `owners`";
$owners = $GLOBALS['db']->fetch( $sql );

しかし、彼らが所有するコンドミニアムを取得する必要性を追加するとすぐに (このステートメントは MySQL コマンドラインでも機能します):

$sql = "SELECT `id`, f_get_owner_locations(`id`) FROM `owners`";
$owners = $GLOBALS['db']->fetch( $sql );

非オブジェクトでのメンバー関数の呼び出しに関するエラーが発生します。

私は困惑しています。while ループの直前に $result で var_dump を実行すると、_bindResults メソッドで 1 つの適切なダンプが得られ、その後停止し、そのエラーが発生します。

object(mysqli_result)#11 (5) {
  ["current_field"]=>
  int(1)
  ["field_count"]=>
  int(1)
  ["lengths"]=>
  NULL
  ["num_rows"]=>
  int(0)
  ["type"]=>
  int(1)
}

注: f_get_owner_locations への呼び出しは、その選択リストの 2 番目のフィールドであるため、正しい数のフィールドにループする必要があると言っているにもかかわらず、正しいフィールド数を格納していません。

この小さな障害を回避するための提案、またはこれが MySQLi ライブラリ内のバグであるか、バインディング コードの問題であるという確認をいただければ幸いです。

更新: 次のコード:

mysql_connect( ... );
mysql_query( "select f_get_owner_locations(3)" );
die( mysql_error() );

この出力が得られました:

FUNCTION f_get_owner_locations does not exist.

これは私よりも PHP/MySQLi 側の単なる失敗なのだろうか?

更新 2:
要求に応じて、関数の作成に使用されるコード:

drop function if exists f_get_owner_locations;
delimiter |
create function f_get_owner_locations( _in int )
returns text deterministic
begin
    declare _output text default "";
    declare _location varchar(255);
    declare _count int default 0;
    declare _done int default 0;
    declare _cursor cursor for 
        select
            condos.location
        from
            owners left join
            condo_owners on owners.id = condo_owners.owner left join
            condos on condo_owners.condo = condos.id
        where
            owners.id = _in;
    declare continue handler for not found set _done = 1;

    open _cursor;

    repeat
        fetch _cursor into _location;
        set_count = _count + 1;
        set_output = concat( _output, ", ", _location );
    until _done end repeat;

    set _count = _count - 1;

    close _cursor;

    set _output = trim( leading ", " from _output );
    set _output = substring( _output from 1 for (_count * 6) );
    set _output = trim( trailing ", " from _output );
    return _output;
end;|
delimiter ;

少しきれいになるかもしれない少しのリファクタリングで認められましたが、それは私が使用したものです。

4

2 に答える 2

0

したがって、さらにテストを重ねた結果、実際には MySQLi ライブラリやコードのバグではないことがわかりました。

ソリューション?データベース ユーザーに、MySQL のデータベースに対する「実行」権限を付与します。スクリプトが使用していた実際のユーザーではなく、root としてログインしているときに、SQL ステートメントと関数を作成してテストしました。

ああ、IT の喜び。

于 2011-03-15T18:22:06.477 に答える
0

MySQL ストアド プロシージャは、複数の結果セットを返すことができます。最後の結果セットは、関心のある実際のデータです。mysqli が正しく行う数少ないことの 1 つは、複数の結果セットをサポートすることです。

チェックしてみてくださいmysqli::more_resultsmysqli::store_resultまた、 mysqli がデータを持たない可能性のある複数の結果セットをどのように処理するかについては、マニュアル ページの免責事項を確認してください。mysqli_resultの代わりにクラスを使用することになりますmysqli_stmt

于 2011-03-12T21:24:44.420 に答える