【问题标题】:Use stored procedure to add users to database使用存储过程将用户添加到数据库
【发布时间】:2019-07-02 00:29:56
【问题描述】:

我正在尝试创建一个可以授予用户访问数据库的存储过程。这个想法是该过程将接受一个参数(给定的用户名),然后让用户访问数据库。因此,执行此操作的正常 Mariadb 查询是:

GRANT ALL ON databaseNameHere.* TO 'userNameHere'@'%';

问题是,'userNameHere' 需要用引号括起来才能执行此查询,因此我需要将引号连接到给定的用户名参数。 我想用 DECLARE 来做到这一点:

DELIMITER $$
CREATE PROCEDURE GrantUserAccess(IN as_username CHAR(25)) 
BEGIN
  SET @sql = CONCAT("GRANT ALL ON archimodels.* TO '" as_username "'@'%'")
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END$$

DELIMITER ;

我一直遇到错误声明:

您的 SQL 语法有错误;检查手册 对应于您的 MariaDB 服务器版本,以便使用正确的语法 在'"'@'%'") 附近准备 stmt FROM @sql;执行语句;解除分配 准备 stmt; EN' 在第 3 行

这是我想要做的一个例子,唯一的问题是我需要将引号连接到用户名 https://www.oreilly.com/library/view/mysql-stored-procedure/0596100892/re39.html

【问题讨论】:

  • 为什么存储过程在这里有帮助?
  • 我得到了脚本部分,但不清楚为什么存储过程会有所帮助。只需在您的脚本系统中执行此操作,无论是什么,而不是在 MySQL 存储过程中。
  • @spencer7593 这些不是特定于 Windows 的,它们是一种称为“智能引号”的功能,存在于许多文字处理类型编辑器中。代码编辑器没有该功能,因为它对于引号很重要的代码来说是一种麻烦。
  • @spencer7593 除非您受到某种专横的官僚企业约束,否则只需将其作为 SQL 代码而不是存储过程来执行。这些存储过程包装器通常会掩盖重要的错误并限制对GRANT 命令中重要配置指令的访问。
  • @tadman:DBA 可以授予这些权限。该过程可以在获得国会法案批准后启动,并附有陆军工程兵团的环境影响研究。

标签: mysql stored-procedures mariadb


【解决方案1】:

有几处有问题。

1) “智能引号”用大引号和双引号字符代替 ASCII 引号和双引号字符

2) 要在 SQL 语句的文本中包含过程参数或变量的内容,我们需要使用动态 SQL PREPARE/EXECUTE/DEALLOCATE

我们还需要保证传入的参数是有效的;如果用户不存在,GRANT 语句将创建没有密码的用户。如果参数碰巧包含一个单引号字符,如果我们不对其进行转义,就会破坏我们的 SQL。我们还可以考虑使用 TRIM() 函数从参数中删除任何前导或尾随空格。

类似这样的:

DELIMITER $$

CREATE PROCEDURE GrantUserAccess(IN as_username CHAR(25)) 
BEGIN
  SET @sql = CONCAT('GRANT ALL ON databaseNameHere.* TO '''
               ,REPLACE(as_username,'''','''''')
               ,'''@''%''' );
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
  SET @sql = '';
END$$

DELIMITER ;

【讨论】:

  • 非常感谢您的回答。我有几个问题,因为它仍然出错:为什么我需要使用“智能引号”将单引号放在双引号内有什么问题?你能解释一下 1.) 为什么你在CONCAT 中使用REPLACE 和这么多额外的引号? 2.) 你能否解释一下为什么在DELIMITER 的最后一行有SET @sql = ''; 我在这里找到了一个很好的例子:oreilly.com/library/view/mysql-stored-procedure/0596100892/… 我会在上面更新我的帖子。
  • 问题中的代码包含怪异的大引号。不要使用那些。使用旧的 ascii 单引号和双引号字符,如上面的答案。在 MySQL 中,我们将字符串文字括在单引号中。如果我们想在文字中包含一个单引号字符,我们在它前面加上一个额外的单引号。如果我们想从中产生值“it's”,那么文字将是“'it''s'”。
  • 不保证传入的参数不包含单引号字符,例如“CALL GrantUserAccess('it''s') ;”。当我们将该值合并到包含单引号的字符串中时,该单引号会弄乱 SQL 语法,这将引发语法错误... TO 'it's'.'%' 我们通过正确转义潜在的单引号来避免该语法错误,以便 SQL生成的将是 ... TO 'it''s'.'%' 我们需要转义单引号以缓解 SQL 注入漏洞。
  • 是的,缺少 CONCAT 的右括号。已编辑答案以包含它。
  • 在默认设置sql_mode 的情况下,ANSI SQL 规范的 MySQL 扩展允许使用双引号将字符串文字括起来。但是,如果将sql_mode 更改为包含ANSI_QUOTES,则双引号包含标识符 而不是字符串文字(ala Oracle)。在字符串文字周围使用双引号时,将 sql_mode 更改为包含 ANSI_QUOTES 将导致 SQL 中断。我的偏好是避免这个问题,并编写独立于 sql_mode 设置工作的 SQL。我只是按照 ANSI SQL 标准使用单引号,就像在 Oracle、SQL Server、Teradata 中一样
猜你喜欢
  • 2014-09-02
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2018-09-30
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 2016-02-12
相关资源
最近更新 更多