【问题标题】:Fatal Error while calling MySQL stored function from PHP using MySQLi使用 MySQLi 从 PHP 调用 MySQL 存储函数时出现致命错误
【发布时间】:2011-03-12 21:09:47
【问题描述】:

服务器详情:
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 命令行,它会做它应该做的事情并返回一行:

+----------------------------+
| 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 的调用是该选择列表中的第二个字段,因此它没有存储正确的字段计数,尽管它说它需要循环到正确数量的字段。

任何关于绕过这个小障碍的建议或确认这是 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 ;

进行了一些重构,可能会更简洁一些,但这就是我使用的。

【问题讨论】:

    标签: php mysql fatal-error stored-functions


    【解决方案1】:

    MySQL 存储过程可以返回多个结果集,其中最后一个结果集是您感兴趣的实际数据。mysqli 正确执行的少数几件事之一就是支持多个结果集。

    尝试检查mysqli::more_results。还要检查手册页上的免责声明mysqli::store_result,了解 mysqli 如何处理多个结果集,其中一个可能没有数据。您最终将使用 mysqli_result 类而不是 mysqli_stmt

    【讨论】:

    • 嗯。我得调查一下。正如我在对原始问题的编辑中添加的那样,使用常规 MySQL 库而不是 MySQLi 只是为了测试语句本身返回:“FUNCTION f_get_owner_locations 不存在”错误。
    • @Mike S,这很奇怪。当您使用CALL 而不是SELECT 时会发生什么?
    • @Charles,MySQLi 和常规 MySQL 库都给我一个“PROCEDURE f_get_owner_locations 不存在”错误。
    • 能否在您用于创建问题中的存储过程的语句中进行编辑?
    • 谢谢,不幸的是我现在不知所措。我在这里看不到任何应该引起问题的东西。为了娱乐价值,你有没有考虑过尝试PDO,看看它可能会出现什么样的错误?也许它可能包含一个有用的 SQLSTATE 或其他东西。
    【解决方案2】:

    所以,经过更多测试后,我发现这实际上不是 MySQLi 库或我的代码中的错误。

    解决方案?授予数据库用户对 MySQL 中数据库的“执行”权限。当我以 root 身份登录时,我编写并测试了 SQL 语句和函数,而不是脚本使用的实际用户。

    哦,IT 的乐趣。

    【讨论】:

      猜你喜欢
      • 2019-02-16
      • 2011-03-16
      • 1970-01-01
      • 2011-05-02
      • 2018-11-13
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多