mysql sql语句 参数化_MySQL存储过程准备语句(动态SQL)参数化

我正在尝试编写一个MySQL搜索函数来构建动态sql值并通过预准备语句执行它.显然我想通过参数传递用户输入(搜索词)以确保安全性,但我无法弄清楚如何将一个参数匹配到多个?查询中的标记.可能最能表明我的意思:

CREATE DEFINER=`admin`@`localhost` PROCEDURE `WEBSITE_mainSearch`(

IN searchWordIn VARCHAR(128)

)

BEGIN

DECLARE articlesModule BIT;

SET @query = '';

SET @searchWordIn = searchWordIn;

SELECT articlesModuleEnabled INTO articlesModule FROM sys_options WHERE ID = 1;

SET @query = CONCAT(@query, 'SELECT blockName AS itemName, blockPath AS seoName, blockID AS itemID, MATCH(blockName, blockBody) AGAINST (?) AS relevance, \'block\' AS itemType FROM content_blocks WHERE MATCH(blockName, blockBody) AGAINST (?)') ;

IF articlesModule = 1 THEN

SET @query = CONCAT(@query, 'UNION SELECT articleName AS itemName, seoName, articleID AS itemID, MATCH(articleName, articleBody) AGAINST (?) AS relevance, \'article\' AS itemType FROM news_articles WHERE MATCH(articleName, articleBody) AGAINST (?)') ;

END IF;

PREPARE stmt FROM @query;

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;

DEALLOCATE PREPARE stmt;

END

由于将根据启用的模块动态确定?s的数量,如何知道在此语句中将searchWordIn作为参数发送多少时间EXECUTE stmt USING searchWordIn;?

谢谢 !

解决方法:

必须为EXECUTE语句提供一个固定的参数列表,因此您必须在IF / THEN / ELSE块中准备并执行该语句.

IF articlesModule = 1 THEN

SET @query = ... UNION ...

PREPARE stmt FROM @query;

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;

ELSE

SET @query = ...; /* no UNION */

PREPARE stmt FROM @query;

EXECUTE stmt USING @searchWordIn, @searchWordIn;

END IF;

我不知道在MySQL存储过程语言的有限范围内解决这个问题的方法.对我而言,这是在存储过程中不使用动态SQL的另一个好理由.

你的意见:

I can’t do the suggestion above – the system I am using has about 7 modules.

我看到……你可以使用CASE statement而不是IF / THEN / ELSE,但实际上你有27 = 128个不同的查询字符串案例,因为我认为这7个模块中的任何一个都可以被搜索到.

允许您使用查询参数的替代方法是忘记使用UNION,而是以最多运行7个单独的SELECT查询并将所有这些查询作为多个结果集返回的方式编写过程.这就是存储过程的目的.但是您必须在PHP层中编写代码以依次获取每个结果集.也就是说,循环遍历结果集,并在该循环内循环遍历当前结果集的行.参见PDO::nextRowset()或mysqli::next_result()的示例.

I supposed I’m safe simply CONCATenating the search word in to the dynamic SQL

不,如果你这样做,你就不安全了!使用PHP中的查询参数将字符串传递给CALL WEBSITE_mainSearch(?)对于防止SQL注入是没有用的,如果然后将该参数值连接到过程内的另一个字符串并执行动态SQL解析和执行.使用查询参数不会使参数值“安全”,它们只是将这些值与SQL分析阶段分开.

如果在连接字符串时使用MySQL的内置函数QUOTE(),则会更安全. QUOTE()会转义特殊字符,就像mysql_real_escape_string()一样.除了它略有不同,因为它还产生分隔字符串的单引号,就像PDO::quote()那样.

SET @query = CONCAT(@query, 'SELECT blockName AS itemName, blockPath AS seoName,

blockID AS itemID, MATCH(blockName, blockBody) AGAINST (',

QUOTE(searchWordIn), ') AS relevance, \'block\' AS itemType

FROM content_blocks WHERE MATCH(blockName, blockBody) AGAINST (',

QUOTE(searchWordIn),')') ;

更新:还有一个选择:使用UNION添加更多子查询,并保留模块的计数.然后使用CASE根据累计计数使用不同数量的参数执行准备好的查询.

SET @n = 0;

IF articlesModule = 1 THEN

SET @query = ... UNION ...

SET @n = @n+1;

END IF;

IF newsModule = 1 THEN

SET @query = ... UNION ...

SET @n = @n+1;

END IF;

... and similar for the other 5 modules ...

PREPARE stmt FROM @query;

CASE @n

WHEN 1:

EXECUTE stmt USING @searchWordIn, @searchWordIn;

WHEN 2:

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;

WHEN 3:

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn;

WHEN 4:

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;

WHEN 5:

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn;

WHEN 6:

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn;

WHEN 7:

EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn,

@searchWordIn, @searchWordIn;

END;

标签:mysql,prepared-statement,stored-procedures

来源: https://codeday.me/bug/20190830/1770919.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值