I’m writing a simple MySQL stored procedure:
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
$
This works:
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)
but unfortunately allows the client to get away with passing NULL:
mysql> CALL DEV_Organization.GetUserByCaseId(NULL);
Empty set (0.00 sec)
I would rather have this throw an error instead. How can I do this? (Simply setting a type of VARCHAR(8) NOT NULL causes MySQL to throw an error when creating the procedure…)
EDIT: Commenters have asked for my rationale. I’m working with a database API back in PHP land that looks like this:
/**
* 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;
}
note how it’s easy for the client to forget to pass an argument in the arguments array. However, this being a low level part of the database abstraction I don’t want to put constraints looking for particular arguments in here.
MySQL 5.5 and later offers SIGNAL for just this purpose (to raise arbitrary exceptions in user routines):