Resumão de PL/SQL, parte 3: fundamentos da linguagem

1) O bloco PL/SQL

A menor estrutura de código PL/SQL é o bloco, que pode ser anônimo ou nomeado. O bloco é dividido em 4 partes, das quais somente 1 é obrigatória:

  1. Cabeçalho: opcional, usada apenas nos blocos nomeados, e determina a maneira pela qual o programa deve ser invocado;
  2. Declaração: opcional, serve para declararmos variáveis, cursores, etc.;
  3. Execução: obrigatória, é o programa propriamente dito;
  4. Exceções: opcional, serve para definirmos o que fazer em caso de erros no programa especificado na parte de execução.

Esquematicamente:

Header Section
IS
   Declaration Section
BEGIN
   Execution Section
EXCEPTION
   Exception Section
END;

1.1) Bloco anônimo

Um bloco PL/SQL anônimo não tem nome e, por isso mesmo, não pode ser chamado por outros blocos. Ele serve como um contêiner que executa código PL/SQL, podendo chamar blocos nomeados (como funções ou procedures).

Esquematicamente o bloco anônimo tem a seguinte estrutura (seções entre colchetes são opcionais, palavras-chave estão em negrito):

[ DECLARE
   ... declarações de variáveis, etc. ... ]

BEGIN
   ... código PL/SQL ...

[ EXCEPTION
   ... código para manipulação de erros ... ]

END;

1.2) Blocos nomeados

São blocos que têm nome, são armazenados no banco de dados, e podem ser chamados de outros blocos (nomeados ou anônimos). À diferença dos blocos anônimos, os blocos nomeados tem um cabeçalho que define o nome e o objetivo do bloco (por exemplo: é uma procedure, uma função, um trigger, etc.).

1.3) Blocos aninhados e escopo

Os blocos podem ser aninhados e isso define o escopo das variáveis existentes em cada bloco. As variáveis definidas nos blocos mais externos podem ser utilizadas nos blocos mais internos (o inverso não é verdadeiro).

Blocos aninhados podem ter um label através do uso de << e >>, por exemplo: <<bloco_local>>. Note bem: label não é nome, mas pode ser útil para qualificar as referências às variáveis e colunas.

1.4) Qualifique as referências às variáveis e colunas

Devemos qualificar o escopo das variáveis e colunas em nosso código SQL e PL/SQL para aumentar a legibilidade do código, garantir que o compilador sempre interpretará as variáveis e colunas da maneira como queremos, e evitar bugs à medida que o código aumenta e que alterações à estrutura das tabelas do banco de dados ocorrem (por exemplo: você pode ter uma variável v_total hoje mas, amanhã, alguém acrescentou uma coluna à uma tabela exatamente com o mesmo nome; pronto, seu código PL/SQL não funciona mais pois o compilador não sabe se o código se refere à variável v_total ou à coluna v_total da tabela).

Para saber se a qualificação é obrigatória ou opcional, temos que verificar a visibilidade da variável.

Um identificador visível pode ser referenciado apenas pelo seu nome, sem qualificação, e incluem:

  • Identificadores declarados no próprio bloco ou no bloco pai;
  • Objetos de banco de dados ou objetos PL/SQL que são possuídos pelo seu schema;
  • Um objeto que você não possui, mas que tem privilégios de acesso e que tenham um sinônimo que você pode ver

Um identificador invisível deve ser qualificado com um prefixo adequado para que o compilador PL/SQL saiba do que estamos tratando, por exemplo:

<schema>.<objeto>.<objeto>

Lembre-se que a ordem de resolução de identificadores é primeiro buscar um nome de coluna de banco de dados igual ao nome do identificador e, depois, buscar um nome declarado no código PL/SQL.

1.5) Programas aninhados

É um procedimento ou função que aparece totalmente dentro da seção de declaração de um bloco. Útil quando você terá uma parte de código que será reutilizado várias vezes dentro do bloco: você inclui a procedure ou função na seção de declaração do bloco, e pode reutilizá-la dentro do bloco, em vários locais, chamando seu nome.

2) Os caracteres aceitos em PL/SQL

PL/SQL é case-insentive (o compilador enxerga tudo como uppercase) e aceita os caracteres: A-Z, a-z, 0-9, whitespace (tab, espaço, newline, carriage return) e símbolos (~ ! @ # $ % * () _ – + = | : ; ” ‘ < > , . ? / ^). Alguns desses símbolos têm significado especial em SQL e em PL/SQL:

  • ; = termina os statements e declarações
  • % = indicador de atributo
  • @ = indicador de localização
  • << e >> = delimitadores de labels
  • := é indicador de atribuição de valor à variáveis, etc.
  • => é operador de associação para notação posicional
  • . . (dois pontos) é operador de range

Esses caracteres e símbolos se combinam para formar as unidades léxicas da linguagem, ou seja, os menores componentes individuais, que são os identificadores, os literais, os delimitadores e os comentários.

2.1) Identificadores

Um identificador é simplesmente um nome para um objeto PL/SQL, ou uma palavra reservada. As regras para os identificadores são as seguintes:

  • Máximo de 30 caracteres
  • Devem começar com uma letra
  • Podem incluir $, _ e #
  • Não podem conter whitespace

Adote convenções de nomes para seus identificadores, por exemplo prefixar parâmetros com p_, funções com fn_, triggers com trg_, packages com pkg_, variáveis com v_, etc.

Palavras reservadas são identificadores que têm um significado especial para a SQL e a PL/SQL (por exemplo: END, BEGIN, SELECT, etc.) ou identificadores definidos nas bult-in package STANDARD e DBMS_STANDARD.

As palavras reservadas especiais da SQL e da PL/SQL não podem ser utilizadas de jeito nenhum, o compilador dá erro. Já os identificadores das packages STANDARD e DBMS_STANDARD não são reservados, ou seja, você pode utilizá-los, embora isso não seja recomendado.

Para conhecer a lista de palavras reservadas, pesquisa a view V$RESERVED_WORDS e evite utilizar alguma coisa listada ali (no Oracle 12.1.0.1.0 existem 2089 identificadores, sendo 100 palavras reservadas e o restante identificadores das packages STANDARD e DBMS_STANDARD).

2.2) Literais

Literais são valores que não são representados por um identificador, ou seja, são apenas simples valores. Os literais podem ser:

  • Números
  • Strings
  • Time interval
  • Boolean
  • Null

2.2.1) Literais string

Literais de string devem ser delimitados por aspas simples e são case-sensitive.

Na PL/SQL e na SQL, null é usualmente a mesma coisa que um string sem nenhum caracter, ”, mas o comportamente é diferente se a variável em questão é varchar2 ou char: se for varchar2, PL/SQL realmente deixa null, mas se for char a PL/SQL preenche com espaços, tornando-a not null. Cuidado com isso se for usar variáveis e colunas char.

Um efeito colateral do uso obrigatório das aspas simples ao redor dos literais de string é que quando você precisa usar um string que contém uma aspas simples em seu interior, por exemplo Mc’Donalds, você tem que prefixar a aspas simples com outra aspas simples, por exemplo Mc”Donalds, ou usar delimitadores q” customizados, por exemplo q'{Mc’Donolds}’. Verifique os exemplos:

SELECT ''''''          FROM DUAL;
SELECT ''' '''         FROM DUAL;
SELECT ' '' '' '       FROM DUAL;
SELECT 'Mc''Donalds'   FROM DUAL;
SELECT q'{Mc'Donalds}' FROM DUAL;
SELECT q'xMc'Donaldsx' FROM DUAL;
SELECT q'!Mc'Donalds!' FROM DUAL;

2.2.2) Literais numéricos

Literais numéricos podem ser números inteiros ou números reais (quando têm parte fracionária, mesmo que a parte fracionária seja 0).

Também podemos usar notação científica (ex.: 3.05E8) e, a partir do Oracle 10g, um número real pode ser do datatype NUMBER, da própria Oracle, ou do datatype BINARY (32 bits, com sufixo f) ou BINARY DOUBLE (64 bits, com sufixo d), do padrão IEEE754.

Em geral eu não uso os datatypes da IEEE754 por causa do problema de cálculo com esses números de pontos flutuantes pois dão erro em algumas situações. Verifique as queries abaixo: a primeira o datatype é NUMBER, da Oracle, e as outras o datatype BINARY e com o BYNARY DOUBLE; veja qual dá o resultado correto:

SELECT 1 * (0.5 -0.4 -0.1) FROM dual;
SELECT 1f * (0.5f -0.4f -0.1f) FROM dual;
SELECT 1d * (0.5d -0.4d -0.1d) FROM dual;

2.2.3) Literais booleanos

São a representação do verdadeiro e falso, TRUE e FALSE, e não devem ter aspas simples ou duplas. Note que uma variável booleana também pode ser null.

Ao usuar variáveis booleanas em uma expressão, a variável pode falar por si mesma. As duas formas abaixo são iguais:

IF v_booleana = TRUE THEN ... ELSE ... END IF;
IF v_booleana THEN ... ELSE ... END IF;

2.3) Delimitadores

Os statements e declarations da PL/SQL são delimitados por um ;

2.4) Comentários

Podem ser em uma únia linha, iniciando com 2 hífens (–), ou de múltiplas linhas, entre /* e */.

3) A keyword PRAGMA

O pragma é uma maneira de passar opções ao compilador PL/SQL que podem resultar em comportamentos diferentes do programa durante o runtime. Ela pode ser usada na seção de declaração de um bloco PL/SQL, com a seguinte sintaxe:

PRAGMA <instrução ao compilador>;

Algumas das instruções ao compilador que podem ser utilizadas são:

  • AUTONOMOUS_TRANSACTION: faz com que o programa execute um commit ou rollback dentro do bloco corrente sem afetar a transação principal;
  • EXCEPTION_INIT: associa um número de erro particular com um identificador que você declarou como uma exception;
  • RESTRICT_REFERENCES: informa o purity level de um programa ao compilador;
  • SERIALLY_REUSABLE: informa que dados ao nível da package não devem persistir entre referências a esses dados.

4) Labels

O label serve para dar um apelido a uma parte particular de seu programa, geralmente um bloco aninhado (mas você pode dar um label para um bloco anônimo também), podendo .

Um label também serve basicamente como:

  • Qualificador para as referências às variáveis, colunas e outros elementos;
  • Alvo para uma instrução GOTO;
  • Alvo de uma instrução EXIT de um loop aninhado sem executar o loop exterior.

Leave a Reply