2011-11-24 51 views
4

我正在写一个简单的MySQL存储过程:如何防止存储过程的用户传递null?

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 |   | [email protected] | 
+------+--------+-----------+----------+----------+----------------------+ 
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; 
} 

注意到它是如何方便客户忘记来传递参数数组中的参数。然而,这是数据库抽象的低级别部分,我不想在这里设置约束条件来寻找特定的参数。

+1

任何理由,你为什么不会在您的客户端(APP)执行此检查? – Devraj

+0

@Devraj:这里的目标是防止应用程序中的错误。如果MySQL抛出一个错误,它会自动翻译成客户端上的异常或错误代码,而不管客户端是什么。我需要那样做。我会用更多的信息更新这个问题... –

+0

@Devraj:好的,更新。 –

回答

4

的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, 
....