gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 07:58:52 25 4
gpt4 key购买 nike

我正在尝试编写一个 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 中执行该语句 block 。

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 注入(inject),如果您随后将该参数值连接到过程中的另一个字符串并执行动态 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 存储过程准备语句(动态 SQL)参数化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23545525/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com