Procedimentos Armazenados
O banco de dados MySQL suporta procedimentos armazenados. Um procedimento armazenado é uma
sub-rotina armazenada no catálogo do banco de dados. Aplicações podem chamar e
executar o procedimento. A declaração CALL
da linguagem SQL é usada para executar um procedimento armazenado.
Parâmetro
Procedimentos armazenados podem ter parâmetros IN
,
INOUT
e OUT
,
dependendo da versão do MySQL. A interface mysqli não tem nenhuma ciência
especial dos diferentes tipos de parâmetros.
Parâmetro IN
Parâmetros de entrada são providos pela declaração CALL
.
Certifique-se que os valores são corretamente escapados.
Exemplo #1 Chamando um procedimento armazenado
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query("CREATE PROCEDURE p(IN id_val INT) BEGIN INSERT INTO test(id) VALUES(id_val); END;");
$mysqli->query("CALL p(1)");
$result = $mysqli->query("SELECT id FROM test");
var_dump($result->fetch_assoc());
O exemplo acima produzirá:
array(1) {
["id"]=>
string(1) "1"
}
Parâmetros INOUT/OUT
Os valores dos parâmetros INOUT
/OUT
são acessados com o uso de variáveis de sessão.
Exemplo #2 Uso de variáveis de sessão
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p(OUT msg VARCHAR(50)) BEGIN SELECT "Hi!" INTO msg; END;');
$mysqli->query("SET @msg = ''");
$mysqli->query("CALL p(@msg)");
$result = $mysqli->query("SELECT @msg as _p_out");
$row = $result->fetch_assoc();
echo $row['_p_out'];
O exemplo acima produzirá:
Desenvolvedores de aplicações e de frameworks podem ser capazes de fornecer uma API mais
conveniente que use uma mistura de variáveis de sessão e inspeção de catálogos de banco de dados.
Entretanto, deve ser observado o possível impacto em desempenho de uma solução
customizada baseada em inspeção de catálogo.
Lidando com conjuntos de resultados
Procedimentos armazenados podem retornar conjuntos de resultados. Resultados retornados de um
procedimento armazenado não podem ser recebidos corretamente usando mysqli::query().
A função mysqli::query() combina execução de instrução
e recebimento do primeiro conjunto de dados em um conjunto de resultados com buffer, se houver.
Porém, haverá conjuntos adicionais de resultados que estarão ocultos
para o usuário, o que fará com que mysqli::query() falhe
no retorno dos dados esperados.
Conjuntos de resultados retornados de um procedimento armazenado são recebidos usando-se
mysqli::real_query() ou mysqli::multi_query().
Ambas as funções permitem receber qualquer número de conjuntos retornados pela
instrução, como CALL
. Falha no recebimento de todos
os conjuntos retornados pelo procedimento armazenado causa um erro.
Exemplo #3 Recebendo resultados de procedimentos armazenados
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");
$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;');
$mysqli->multi_query("CALL p()");
do {
if ($result = $mysqli->store_result()) {
printf("---\n");
var_dump($result->fetch_all());
$result->free();
}
} while ($mysqli->next_result());
O exemplo acima produzirá:
---
array(3) {
[0]=>
array(1) {
[0]=>
string(1) "1"
}
[1]=>
array(1) {
[0]=>
string(1) "2"
}
[2]=>
array(1) {
[0]=>
string(1) "3"
}
}
---
array(3) {
[0]=>
array(1) {
[0]=>
string(1) "2"
}
[1]=>
array(1) {
[0]=>
string(1) "3"
}
[2]=>
array(1) {
[0]=>
string(1) "4"
}
}
Uso de procedimentos armazenados
Nenhuma manipulação especial é necessária ao usar a interface de procedimentos
armazenados para receber resultados do mesmo procedimento como no exemplo acima.
As interfaces para procedimentos armazenados e não armazenados são similares.
Deve ser observado que pode haver versões do servidor MYSQL que não suportem
preparação da instrução CALL
da linguagem SQL.
Exemplo #4 Procedimentos Armazenados e Instruções Preparadas
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");
$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;');
$stmt = $mysqli->prepare("CALL p()");
$stmt->execute();
do {
if ($result = $stmt->get_result()) {
printf("---\n");
var_dump($result->fetch_all());
$result->free();
}
} while ($stmt->next_result());
O exemplo acima produzirá:
---
array(3) {
[0]=>
array(1) {
[0]=>
int(1)
}
[1]=>
array(1) {
[0]=>
int(2)
}
[2]=>
array(1) {
[0]=>
int(3)
}
}
---
array(3) {
[0]=>
array(1) {
[0]=>
int(2)
}
[1]=>
array(1) {
[0]=>
int(3)
}
[2]=>
array(1) {
[0]=>
int(4)
}
}
Obviamente, o uso da API 'bind' para recebimento de dados também é suportado.
Exemplo #5 Procedimentos Armazenados e Instruções Preparadas usando a API bind
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)");
$mysqli->query("DROP PROCEDURE IF EXISTS p");
$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;');
$stmt = $mysqli->prepare("CALL p()");
$stmt->execute();
do {
if ($stmt->store_result()) {
$stmt->bind_result($id_out);
while ($stmt->fetch()) {
echo "id = $id_out\n";
}
}
} while ($stmt->next_result());
O exemplo acima produzirá:
id = 1
id = 2
id = 3
id = 2
id = 3
id = 4
Veja também