Неустранимая ошибка при вызове хранимой функции MySQL из PHP с использованием MySQLi - PullRequest
1 голос
/ 13 марта 2011

Сведения о сервере:
PHP v5.3.5
Использование клиентской версии API библиотеки MySQLi: mysqlnd 5.0.7-dev - 091210 - $ Редакция: 304625 $
MySQL Server v5.5.9

У меня есть сохраненная функция в MySQL, которая называется f_get_owner_locations (_in int).Он создает текстовую переменную, в которой хранятся данные о том, какие квартиры принадлежат конкретному владельцу.Если я запускаю

SELECT f_get_owner_locations( 3 );  

из командной строки MySQL, он делает то, что должен, и возвращает одну строку:

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

Однако всякий раз, когда я пытаюсь запустить его через PHPиспользуя библиотеку MySQLi следующим образом:

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

Это дает мне ошибку при вызове функции-члена для необъекта.

Я в тупике.Выполнение var_dump для $ result прямо перед циклом while, в моем методе _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 ;

Допускается небольшой рефакторинг, который может быть немного чище, но это то, что я использовал.

Ответы [ 2 ]

0 голосов
/ 15 марта 2011

Итак, после дополнительного тестирования, а что нет, я обнаружил, что на самом деле это не ошибка в библиотеках MySQLi или в моем коде.

Решение?Дайте пользователю базы данных разрешение «Выполнить» для базы данных в MySQL.Я написал и протестировал операторы и функции SQL, когда я вошел в систему как пользователь root, а не фактический пользователь, который использовал скрипт.

О, радости ИТ.

0 голосов
/ 13 марта 2011

Хранимые процедуры MySQL могут возвращать несколько наборов результатов , где последний набор результатов - это фактические данные, которые вас интересуют. Одна из немногих вещей, которые mysqli делает правильно, - это поддержка нескольких наборов результатов.

Попробуйте проверить mysqli::more_results.Также проверьте отказ от ответственности на странице руководства для mysqli::store_result о том, как mysqli обрабатывает несколько наборов результатов, в которых один может не иметь данных.В итоге вы будете работать с классом mysqli_result вместо mysqli_stmt.

...