使用STORED PROCEDURES:mysqli->查询中的不同结果(" CALL select_procedure")VS mysqli->查询(" SELECT ...")

时间:2016-07-10 17:49:45

标签: php mysql stored-procedures mysqli

我正在将所有mysqli查询迁移到STORED PROCEDURE。 它应该像更改mysqli调用中的一行一样简单,但是,以下两个代码会给出不同的结果:

常规查询,它可以正常工作:

$query = $this->mysqli->query("SELECT DISTINCT ID FROM user
                                   WHERE 
                                   MATCH (name) AGAINST ('* *$sanitized* *') ");

if ($query) {   
  $nrows = $query -> num_rows;
  if ($nrows > 0) {
      $searchResult = 'We found '. $nrows .' results';
  }
}

调用PROCEDURE,在布尔值"上返回" fetch_array()错误:

$query = $this->mysqli->query("CALL myfunction('.$sanitized.')");

程序定义为:

DELIMITER $$
CREATE PROCEDURE myfunction (sanitized VARCHAR(124))
BEGIN
    SELECT DISTINCT ID FROM user
                                   WHERE 
                                   MATCH (name) AGAINST ('* *sanitized* *');
END 
$$
DELIMITER ;

我无法找到解决方案,似乎没有人在此论坛中遇到类似的问题。

1 个答案:

答案 0 :(得分:0)

考虑与Prepared Statements一起使用concat(),因为它们经常出现。

DROP PROCEDURE if exists myStoredProc101;
DELIMITER $$
CREATE PROCEDURE myStoredProc101
(   pSanitized VARCHAR(124)
)
BEGIN
    set @mySql:=concat("SELECT DISTINCT ID FROM user where match(name) against ('* *",pSanitized,"* *')");
    PREPARE stmt1 FROM @mySql;
    EXECUTE stmt1;
    DEALLOCATE PREPARE stmt1;
END 
$$
DELIMITER ;

你的存储过程没有机会工作,因为它甚至没有使用你的参数。你所做的是把一些东西埋在一个字符串文字中。另外,varchar(124)有点奇怪:p

关于人们对预备语句的唯一成功是使用用户变量(使用@)与使用本地变量(来自DECLARE)失败的尝试。所以,这可能会为你节省几个小时的头部撞击。

从PHP手册页Stored Procedures

  

处理结果集

     

存储过程可以返回结果集。从a返回的结果集   使用mysqli_query无法正确获取存储过程。该   mysqli_query函数结合了语句执行和获取   第一个结果集设置为缓冲结果集(如果有)。但是,那里   是对用户隐藏的附加存储过程结果集   导致mysqli_query无法返回用户预期的结果集。

     

使用提取从存储过程返回的结果集   mysqli_real_query或mysqli_multi_query。这两个功能都允许抓取   语句返回的任意数量的结果集,例如CALL。   无法获取存储过程返回的所有结果集会导致   错误。

至于从mysqli调用存储过程,请查看来自Pablo Tobar的Answer。对于许多变量来说,它看起来并不特别令人愉快,但这似乎就是它所处的位置。 Spoiler Alert:使用mysql变量,而不是PHP变量。

当然,Pablo没有返回结果集,而是写入存储过程中的OUT var。也许你需要做他为IN参数做的事情,然后调用multi_query(),然后调用store_result(),然后调用fetch_all()(简而言之,PHP引用页面向上) )。

或者,可以通过Palladium here进行电话会议。

在任何一种情况下,都必须采取措施避免将 SQL注入传递给存储过程例程的已知漏洞。