Как можно предотвратить передачу пользователем null хранимой процедуры? - PullRequest
4 голосов
/ 24 ноября 2011

Я пишу простую хранимую процедуру 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 выдавать ошибку при создании процедуры ...)

РЕДАКТИРОВАТЬ: Комментаторы запросили мое обоснование.Я работаю с API базы данных в PHP-земле, которая выглядит следующим образом:

/**
 * 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;
}

обратите внимание, как легко клиенту забыть передать аргумент в массиве arguments.Однако, поскольку это низкоуровневая часть абстракции базы данных, я не хочу помещать здесь ограничения для поиска конкретных аргументов.

1 Ответ

4 голосов
/ 24 ноября 2011

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, 
....
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...