【问题标题】:How does one prevent a user of a stored procedure from passing null?如何防止存储过程的用户传递 null?
【发布时间】:2011-11-24 04:15:58
【问题描述】:

我正在写一个简单的 MySQL 存储过程:

DELIMITER $
DROP PROCEDURE IF EXISTS GetUserByCaseId $
CREATE DEFINER = 'DEV_Organization'@'localhost' 
PROCEDURE GetUserByCaseId (IN searchedForId VARCHAR(8)) 
  LANGUAGE SQL NOT DETERMINISTIC READS SQL DATA SQL SECURITY DEFINER
BEGIN
  SELECT 
    CaseIdAuthenticator.sid AS sid, 
    CaseIdAuthenticator.caseId AS caseId, 
    User.firstName AS firstName, 
    User.lastName AS lastName, 
    User.position AS position, 
    User.email AS email 
  FROM CaseIdAuthenticator
  INNER JOIN User ON User.sid = CaseIdAuthenticator.sid
  WHERE CaseIdAuthenticator.caseId = searchedForId
  LIMIT 1;
END
$

这行得通:

mysql> CALL DEV_Organization.GetUserByCaseId("bro4");
+------+--------+-----------+----------+----------+----------------------+
| sid  | caseId | firstName | lastName | position | email                |
+------+--------+-----------+----------+----------+----------------------+
| 3773 | bro4   | Billy     | O'Neal   |          | billy.oneal@case.edu |
+------+--------+-----------+----------+----------+----------------------+
1 row in set (0.00 sec)

但不幸的是允许客户端通过传递 NULL 侥幸逃脱:

mysql> CALL DEV_Organization.GetUserByCaseId(NULL);
Empty set (0.00 sec)

我宁愿让它抛出一个错误。我怎样才能做到这一点? (只需设置一个VARCHAR(8) NOT NULL的类型就会导致MySQL在创建过程时抛出错误...)

编辑:评论者询问了我的理由。我正在使用 PHP 领域的数据库 API,如下所示:

/**
 * Inside function which is used to implement other procedure functions.
 *
 * @param string $suffix The database schema suffix.
 * @param string $procedure The name of the procedure that should be executed.
 * @param array $arguments A set of arguments which should be passed to the stored procedure.
 * @return PDOStatement The PDOStatement generated by sending the query to the MySQL Server.
 */
private function ProcedureInner($suffix, $procedure, $arguments = array())
{
  $suffix = (string)$suffix;
  $procedure = (string)$procedure;
  $questionMarks = '';
  $args = count($arguments);
  if ($args > 0)
  {
    $questionMarks = '?';
    for ($idx = 1; $idx < $args; ++$idx)
    {
      $questionMarks .= ', ?';
    }
  }
  $stmt = $this->pdo->prepare("CALL `{$this->mode}_{$suffix}`.`{$procedure}` ({$questionMarks})");
  $stmt->execute($arguments);
  return $stmt;
}

/**
 * Executes a stored procedure which returns a single value in a single row.
 *
 * @param string $schema The suffix of the schema where the procedure is located.
 * @param string $procedure The name of the procedure to call.
 * @param array $arguments Arguments to supply to the procedure, if any.
 * @return mixed The content of the value.
 */
public function ProcedureScalar($schema, $procedure, $arguments = array())
{
  $result = $this->ProcedureInner($schema, $procedure, $arguments);
  $answer = $result->fetchColumn(0);
  $result->closeCursor();
  return $answer;
}

注意客户端很容易忘记在参数数组中传递参数。但是,这是数据库抽象的低级部分,我不想在此处放置寻找特定参数的约束。

【问题讨论】:

  • 您有什么理由不在您的客户端(应用程序)中执行此检查?
  • @Devraj:这里的目标是防止应用程序中的错误。如果 MySQL 抛出错误,它会在客户端上自动转换为异常或错误代码,无论该客户端碰巧是什么。我需要这样。我会用更多信息更新问题...

标签: mysql sql stored-procedures


【解决方案1】:

MySQL 5.5 及更高版本为此提供了SIGNAL(在用户例程中引发任意异常):

....
BEGIN
  IF searchedForId IS NULL THEN
    SIGNAL SQLSTATE '45000' -- unhandled user-defined exception
      SET MESSAGE_TEXT = 'Parameter may not be NULL';
  END IF;
  SELECT 
    CaseIdAuthenticator.sid AS sid, 
....

【讨论】:

    猜你喜欢
    • 2014-08-29
    • 2011-02-13
    • 1970-01-01
    • 2012-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多