0% acharam este documento útil (0 voto)
49 visualizações15 páginas

Tema PL SQL 2022 Pag01 A 15

1) PL/SQL é a extensão procedural da linguagem SQL da Oracle que permite a programação estruturada em blocos com declarações, comandos e tratamento de exceções. 2) Um bloco PL/SQL contém uma parte declarativa, uma parte executável e uma parte de tratamento de exceções. Variáveis e constantes devem ser declaradas antes de serem usadas. 3) Cursores permitem manipular resultados de consultas que retornam múltiplas linhas, permitindo acessar cada linha individualmente.

Enviado por

kamil
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
49 visualizações15 páginas

Tema PL SQL 2022 Pag01 A 15

1) PL/SQL é a extensão procedural da linguagem SQL da Oracle que permite a programação estruturada em blocos com declarações, comandos e tratamento de exceções. 2) Um bloco PL/SQL contém uma parte declarativa, uma parte executável e uma parte de tratamento de exceções. Variáveis e constantes devem ser declaradas antes de serem usadas. 3) Cursores permitem manipular resultados de consultas que retornam múltiplas linhas, permitindo acessar cada linha individualmente.

Enviado por

kamil
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 15

MANUAL DE PL/SQL

PL/SQL (Procedural Language/SQL)


PL/SQL (Linguagem Procedural/SQL) é a extensão procedural da Oracle para SQL. Existem duas
versões de PL/SQL: uma é parte do servidor Oracle e a outra é um mecanismo separado incorporado em
várias ferramentas Oracle. Eles são muito semelhantes entre si e possuem os mesmos mecanismos de
construção, sintaxe e lógica de programação, embora as ferramentas PL/SQL para Oracle tenham algumas
extensões para atender aos requisitos da ferramenta específica.
A PL/SQL possui conceitos semelhantes às linguagens de programação modernas, como declarações
de variáveis e constantes, estruturas de controle, manipulação de excepções e modularização. A PL/SQL é
uma linguagem estruturada em blocos: os blocos podem ser totalmente separados ou aninhados uns dentro
dos outros. As unidades básicas que constituem um programa PL/SQL são procedimentos, funções e blocos
anónimos (sem nome).
Um bloco PL/SQL tem três partes:
• uma parte de declaração opcional, na qual variáveis, constantes, cursores e excepções são
definidas e possivelmente inicializadas;
• uma parte executável obrigatória, na qual as variáveis são manipuladas, começa por BEGIN e
termina por END;
• uma parte de excepção opcional, para lidar com quaisquer excepções levantadas durante a execução.

• Declarações
Variáveis e constantes devem ser declaradas antes que possam ser referenciadas em outras instruções,
incluindo outras declarações declarativas. Exemplos de declarações:
vStaffNo VARCHAR2(5);
vRent NUMBER (6, 2) NOT NULL := 600;
MAX_PROPERTIES CONSTANT NUMBER := 100;
Também é possível declarar uma variável para ser do mesmo tipo que uma coluna numa tabela
especificada ou outra variável usando o atributo%TYPE:
vStaffNo Staff.staffNo%TYPE;

Da mesma forma, podemos declarar que uma variável é do mesmo tipo que uma linha inteira de uma

Elaborado por Dra. Otília Fernandes da Graça 1


MANUAL DE PL/SQL

tabela ou vista, usando o atributo%ROWTYPE. Nesse caso, os campos no registo obtêm seus nomes e tipos
de dados das colunas na tabela ou vista:
vStaffRec Staff%ROWTYPE;
%TYPE e %ROWTYPE não são SQL standard.

• Atribuições
Na parte executável de um bloco PL/SQL, as variáveis podem ser atribuídas de duas maneiras: usando
a instrução de atribuição normal (:=) ou como o resultado de uma instrução SQL, SELECT ou FETCH.
Exemplos:
vStaffNo := ‘SG14’;
vRent := 500;
SELECT COUNT (*) INTO x FROM PropertyForRent WHERE staffNo = vStaffNo;
No terceiro caso, a variável x é definida como o resultado da instrução SELECT (nesse caso, igual ao
número de propriedades geridas pelo membro do staff SG14).
Observe que, no SQL standard, uma atribuição usa a palavra-chave SET no início da linha com o
símbolo “=”, em vez do “: =”. Por exemplo:
SET vStaffNo = ‘SG14’
• Instruções de CONTROL
O PL/SQL suporta os mecanismos habituais de fluxo de controle condicional, iterativo e sequencial:
• Instrução condicional IF
• Instrução condicional CASE
• Instrução iteração (LOOP)
• Instrução iteração (WHILE e REPEAT)
• Instrução iteração (FOR)

• Excepções em PL/SQL
Uma excepção é um identificador em PL/SQL criado durante a execução de um bloco que finaliza
seu corpo principal de acções. Um bloco sempre termina quando uma excepção é gerada, embora o
manipulador de excepções possa executar algumas acções finais. Uma excepção pode ser levantada
automaticamente pelo Oracle - por exemplo, a excepção NO_DATA_FOUND é levantada sempre que
nenhuma linha é recuperada da base de dados numa instrução SELECT. Também é possível que uma
excepção seja levantada explicitamente usando a instrução RAISE. Para lidar com excepções levantadas,
são especificadas rotinas separadas denominadas manipuladores de excepção (handlers).
Uma excepção definida pelo utilizador é definida na parte declarativa de um bloco PL/SQL. Na parte
executável, uma verificação é feita para a condição de excepção e, se encontrada, a excepção é gerada. O
manipulador de excepções propriamente dito é definido no final do bloco PL/SQL.

Elaborado por Dra. Otília Fernandes da Graça 2


MANUAL DE PL/SQL

Sintaxe:
DECLARE
past_due EXCEPTION;
BEGIN
... ...
IF ... THEN
RAISE past_due; - esse não é tratado
END IF;
...
EXCEPTION
WHEN past_due THEN - não suporta excepções
HANDLE
...
WHEN OTHERS THEN
...
END;

• Ao tratar excepções tornamos as unidades de programa mais amigáveis e a execução não é


interrompida.
3 Tipos de excepções:
– Predefinidas
– Não predefinidas
– Definidas pelo utilizador

• Excepções Predefinidas
– DUP_VAL_ON_INDEX – valor de índice duplicado
– LOGIN_DENIED – ocorre na tentativa de conexão com o BD com um utilizador/senha
inválido
– INVALID_NUMBER – ocorre na tentativa de converter uma string para um número, quando
a string não representa um número válido
– NO_DATA_FOUND – comando SELECT/INTO não retornou linha alguma
– TOO_MANY_ROWS – comando SELECT/INTO retornou mais de uma linha
– TIMEOUT_ON_RESOURCE – ocorre quando acontecer um timeout enquanto aguarda-se
um recurso
– NO_LOGGED_ON – ocorre na tentativa de acessar a base de dados sem que se esteja
conectado a ele
– OTHERS “Espera uma mensagem de erro” – trata outros erros, usando as funções
SQL_CODE (número do erro) e
SQLERRM (texto do erro)

Elaborado por Dra. Otília Fernandes da Graça 3


MANUAL DE PL/SQL

• Excepções Não Predefinidas (sem nome)


Nem todos os erros têm exception. Para se fazer o tratamento destes erros, é preciso criar a
exception na secção de declaração e vincular o número do erro com a exception criada.
– excepção OTHERS
– PRAGMA EXCEPTION_INIT
PRAGMA – renomeia um erro Oracle identificado por seu número
– permite que a excepção seja referenciada pelo novo nome

• Excepções Definidas pelo Utilizador


– Precisam de ser declaradas na secção de declaração – nome_da_excepção EXCEPTION e
– Chamadas explicitamente na secção de comandos - RAISE nome_da_excepção

Exemplo:

DECLARE
nome_nulo EXCEPTION; *criação da exception*
PRAGMA EXCEPTION_INIT (nome_nulo, -1400); *relaciona o número do erro com a exception*
BEGIN

RAISE_APPLICATION_ERROR (-1400,’Nome nulo’); *provoca o erro, mostrando a
mensagem e o erro*

EXCEPTION
when nome_nulo then
…; *tratamento do erro*
when others then
…;
END;

• Cursores em PL/SQL
Uma instrução SELECT pode ser usada se a consulta retornar uma e apenas uma linha. Para manipular
uma consulta que possa retornar um número arbitrário de linhas (ou seja, zero, uma ou mais linhas), o
PL/SQL usa cursores para permitir que as linhas de um resultado da consulta sejam acessadas uma de cada
vez. Com efeito, o cursor actua como um ponteiro para uma linha específica da consulta resultado. O cursor
pode ser avançado por 1 para acessar a próxima linha. Um cursor deve ser declarado e aberto antes de poder
ser usado, e deve ser fechado para desativá-lo depois que ele não for mais necessário. Depois que o cursor
for aberto, as linhas da consulta resultado podem ser recuperadas uma de cada vez, usando uma instrução
FETCH, ao contrário de uma instrução SELECT.
O SQL também pode ser incorporado em linguagens de programação de alto nível e os cursores
também são usados para tratar consultas que podem retornar um número arbitrário de linhas.

Elaborado por Dra. Otília Fernandes da Graça 4


MANUAL DE PL/SQL

Sintaxe:
CURSOR cursor_name [(parameter[, parameter]...)] IS select_statement;

• Existem 2 tipos de cursores:


– Implícito que dispensa qualquer tipo de tratamento
– Explícito gerado apenas pelo SELECT, que deve ser declarado e manipulado via comandos
próprios.
Criando um cursor explícito podemos carregar o conteúdo de uma tabela em memória sem precisar de
emitir tantos SELECT/INTO quantos os registos da tabela.
• 4 atributos podem ser usados por cursores:
– sql%rowcount – informa quantas linhas foram afectadas pelo comando que gerou o cursor
– sql%found – será true caso alguma linha tenha sido afectada
– sql%notfound – será false caso alguma linha tenha sido afectada
– sql%isopen – será true caso o cursor esteja aberto
No caso de cursores explícitos, o prefixo sql será substituído pelo nome da variável que representa o
cursor

Exemplo I
DECLARE
my_sal emp.sal%TYPE;
factor INTEGER :=2;
CURSOR c1(p_Job varchar2) IS
SELECT factor*sal
FROM emp
WHERE job=p_Job;
BEGIN
...
OPEN c1(‘ANALISTA’);
LOOP
FETCH c1 INTO my_sal;
EXIT WHEN c1%NOT FOUND;
...
END LOOP;
CLOSE c1;
END;

Elaborado por Dra. Otília Fernandes da Graça 5


MANUAL DE PL/SQL

Exemplo II
DECLARE
Cursor c_cliente IS
Select * from Clientes order by Nome_Cli;

Cursor c_Fatura(p_cli number) IS


Select * from Fatura where cod_cli = p_cli;
R_Cliente c_cliente%rowtype;
R_Fatura c_fatura%rowtype;
BEGIN
OPEN c_cliente;
LOOP
FETCH c_cliente INTO R_cliente;
EXIT When c_cliente%NOT FOUND;
OPEN c_fatura (R_cliente.cod_cli);
DBMS_OUTPUT.PUT_LINE (R_cliente.Nome);
LOOP
FETCH c_fatura INTO R_fatura;
EXIT When c_Fatura%NOT FOUND;
DBMS_OUTPUT.PUT_LINE (R_Fatura.Data);
END LOOP;
CLOSE c_Fatura;
END LOOP;
CLOSE c_Cliente;
END;
/
NOTAS:
– Para os dados serem mostrados no SQL*Plus, a propriedade SERVEROUTPUT deve ser
configurada para ON.
Exemplo: SET ServerOutPut ON
– O uso do pacote fornecido pela Oracle DBMS_OUTPUT permite a saída de blocos e
subprogramas PL/SQL.
– Passando parâmetros para cursores: O PL/SQL permite que os cursores sejam
parametrizados, de modo que a mesma definição do cursor possa ser reutilizada com diferentes
critérios.

Elaborado por Dra. Otília Fernandes da Graça 6


MANUAL DE PL/SQL

Subprogramas: Procedures e Functions


Os subprogramas são denominados blocos PL/SQL que podem receber parâmetros e serem
chamados. A PL/SQL possui dois tipos de subprograma chamados procedimentos e funções (armazenados).
Procedimentos e funções podem levar um conjunto de parâmetros dados a eles pelo programa de chamada
e executar um conjunto de acções. Ambos podem modificar e retornar dados passados para eles como um
parâmetro. A diferença entre um procedimento e uma função é que uma função sempre retornará um único
valor para o chamador, enquanto um procedimento não. Geralmente, os procedimentos são usados, a menos
que apenas um valor de retorno seja necessário.
Os procedimentos e funções são muito semelhantes aos encontrados na maioria das linguagens de
programação de alto nível, e têm as mesmas vantagens: fornecem modularidade e extensibilidade,
promovem a capacidade de reutilização e manutenção e ajudam na abstracção. Um parâmetro tem um nome
e um tipo de dados especificados, mas também pode ser designado como:
• IN - o parâmetro é usado apenas como um valor de entrada.
• OUT - o parâmetro é usado apenas como um valor de saída.
• IN OUT - o parâmetro é usado como valor de entrada e saída.

PROCEDURE

Sintaxe para criar uma procedure:


CREATE OR REPLACE nome_procedure (lista de parâmetros opcional) IS
declarações locais
BEGIN
comandos
END;
Ou
CREATE OR REPLACE nome_procedure [(argumento1 [IN | OUT | IN OUT]
datatype, [argumento2 [IN | OUT | IN OUT] datatype] …)]
{IS | AS} <secção declarativa>
BEGIN
Comandos <secção de execução>
[EXCEPTION
<tratamento_de_excepções>]
END [nome_procedure];

REPLACE - indica que caso a procedure exista ela será eliminada e substituída pela nova versão criada
pelo comando;
nome_procedure indica o nome da procedure
argumento, parâmetro da procedure

Elaborado por Dra. Otília Fernandes da Graça 7


MANUAL DE PL/SQL

IN, indica que deve especificar o valor deste parâmetro na chamada da procedure
OUT, indica que a procedure irá retornar um valor para este parâmetro
IN OUT, através deste parâmetro deve-se especificar um valor para a procedure e este voltará
modificado
Datatype, tipo de dado do parâmetro
IS | AS, é onde se faz a declaração das variáveis ou constantes locais
BEGIN comandos END é o bloco PL/SQL, indica as acções que serão executadas por aquela procedure.

Exemplo:
CREATE OR REPLACE PROCEDURE AlimentaHistorico (ultima_turma IN NUMBER, ultimo_aluno
IN NUMBER)
IS
BEGIN
DELETE historico; /*comentario: elimina registos actuais*/
FOR i IN 1.. ultima_turma LOOP
FOR j IN 1 .. ultimo_aluno LOOP
INSERT INTO historico (cod_turma, matricula) VALUES (i, j);
END LOOP;
END LOOP;
COMMIT;
END;
/
A rotina tem 2 parâmetros de entrada.

– Para verificar a existência de uma procedure consultamos a tabela user_objects:

SELECT object_name
FROM user_objects
WHERE object_type = ‘PROCEDURE’;
– Para verificar o estado da procedure através de uma simples consulta:

SELECT object_name, status


FROM user_objects
WHERE object_name LIKE “AlimentaHistorico”;

– Para executar a procedure


EXEC alimentahistorico (10, 10);

Elaborado por Dra. Otília Fernandes da Graça 8


MANUAL DE PL/SQL

- Para verificar o funcionamento da procedure


SELECT *
FROM historico;

Durante a criação da procedure pode ocorrer algum erro. Nesse caso será mostrada uma mensagem
semelhante a esta:
Aviso: Procedimento criado com erros de compilação
Ou
MGR-00072: Warning: Procedure alimentahistorico created with compilation errors
Nesse caso o erro pode ser verificado através do SHOW ERROR que lista a linha/coluna onde o erro
ocorreu.
O comando SHOW ERROR sem parâmetros adicionais mostra os erros da última compilação.
Por exemplo:
SHOW ERROR alimentahistorico
Ou
SHOW ERROR PROCEDURE alimentahistorico
Ou
SHOW ERROR

– Para remover uma procedure


DROP PROCEDURE nome_procedure

FUNCTIONS
Para criar uma function no SQL*Plus:

CREATE OR REPLACE nome_function (lista de parâmetros de entrada opcional)


RETURN tipo de retorno
IS
declarações locais
BEGIN
comandos
END;

Ou

CREATE [OR REPLACE] FUNCTION <nome_da_funcao>


([<argumento1> <IN |OUT | IN OUT> < datatype> [{:= |DEFAULT} valor],
<argumento2> < IN |OUT | IN OUT > < datatype> [{: = |DEFAULT} valor],
...]) RETURN < datatype>
IS | AS
<seccao_declarativa>
Elaborado por Dra. Otília Fernandes da Graça 9
MANUAL DE PL/SQL

BEGIN
<seccao_de_execucao>
[EXCEPTION
<tratamento_de_excepcoes>]
END [<nome_da_funcao>];

• Exemplo:
CREATE OR REPLACE FUNCTION ValorEmDolar (meticais IN NUMBER, cotacao IN
NUMBER)
RETURN NUMBER
IS
BEGIN
RETURN meticais/cotacao;
END;

• A execução da função pode ser:


– Sql> column nome_curso format a40
– Sql> SELECT nome_curso, preco “Em MT”, ValorEmDolar (preco, 1.87) “Em UD$”
FROM cursos;

• Para verificar a existência de uma function:


– Sql> SELECT object_name
FROM user_objects
WHERE object_type = ‘FUNCTION’;

• Uma função pode ser activada a partir de um comando SQL do tipo DML nas cláusulas WHERE,
HAVING, ORDER BY, GROUP BY em SELECT; VALUES em INSERT; SET em UPDATE e
WHERE em DELETE. Nestes casos a função não pode ter comandos SQL.
• Apagar uma função
DROP FUNCTION nome_funçao;

Elaborado por Dra. Otília Fernandes da Graça 10


MANUAL DE PL/SQL

Uso de Procedures e Functions


• Criar uma procedure que classifique os cursos de acordo com o preço: menor que 300 é
barato, menor que 600 é médio, noutros casos é caro.
CREATE OR REPLACE PROCEDURE Classifica_Cursos
IS
v_qtos_cursos NUMBER (3) := 0;
v_curso_corrente NUMBER (3) := 1;
v_nome_curso cursos.nome_curso%TYPE;
v_preco cursos.preco%TYPE;
v_classifica VARCHAR2(10);
BEGIN
SELECT COUNT (*)
INTO v_qtos_cursos
FROM cursos;
FOR i IN 1..v_qtos_cursos LOOP
SELECT nome_curso, preco
INTO v_nome_curso, v_preco
FROM cursos
WHERE cod_curso = i;
IF v_preco < 300 THEN
v_classifica := 'Barato';
ELSIF v_preco < 600 THEN
v_classifica := 'Médio';
ELSE
v_classifica := 'Caro';
END IF;
DBMS_OUTPUT.PUT_LINE ('Curso: '|| v_nome_curso || ' é ' ||
v_classifica);
END LOOP;
END;
/
Execute a procedure.
Análise do resultado:
- Assume que os códigos de cursos começam por 1 e são sequenciais
- SELECT / INTO somente funciona se houver um e apenas um dado para retornar.
- Se houver, por exemplo, 20 cursos, existirão 20 acessos ao servidor via comando SELECT/INTO

Como resolver? Com uso de cursores

Elaborado por Dra. Otília Fernandes da Graça 11


MANUAL DE PL/SQL

CREATE OR REPLACE PROCEDURE Classifica_Cursos_Cur_Exp


IS
CURSOR ccursos IS
SELECT nome_curso, preco FROM cursos;
v_nome_curso cursos.nome_curso%TYPE;
v_preco cursos.preco%TYPE;
v_classifica VARCHAR2(10);
BEGIN
OPEN ccursos;
FETCH ccursos INTO v_nome_curso, v_preço;
WHILE ccursos%FOUND LOOP
IF v_preco < 300 THEN
v_classifica := 'Barato';
ELSIF v_preco < 600 THEN
v_classifica := 'Médio';
ELSE
v_classifica := 'Caro';
END IF;
DBMS_OUTPUT.PUT_LINE ('Curso: '|| v_nome_curso || ' é ' || v_classifica);
FETCH ccursos INTO v_nome_curso, v_preco;
END LOOP;
CLOSE cursos;
END;
/

Exercício: Faça a procedure Classifica_Cursos_Cur_Exp usando FOR.

• Filtrar os cursos que não atingem um determinado preço.


CREATE OR REPLACE PROCEDURE Class_Cursos_Cur_Exp_Param
(v_valor_minimo number)
IS
CURSOR ccursos (v_valor_minimo IN NUMBER) IS
SELECT nome_curso, preco FROM cursos
WHERE preco > v_valor_minimo;

BEGIN
OPEN ccursos (v_valor_minimo);
FETCH ccursos INTO v_nome_curso, v_preco;

Complete e execute a procedure. Observe o resultado.

Elaborado por Dra. Otília Fernandes da Graça 12


MANUAL DE PL/SQL

• Seleccionar dados usando uma variação do comando SELECT.


Seleccionar informação de um curso:
CREATE OR REPLACE PROCEDURE Retorna_Info_Curso
(v_ch IN cursos.carga_horaria%TYPE)
IS
v_nome cursos.nome_curso%TYPE;
v_preco cursos.preco%TYPE;
BEGIN
SELECT nome_curso, preco
INTO v_nome, v_preco
FROM cursos
WHERE carga_horaria = v_ch;
DBMS_OUTPUT.PUT_LINE ('Curso: '|| v_nome);
DBMS_OUTPUT.PUT_LINE ('Preço: '|| to_char(v_preco));
END;
/

Para executar:
– Exec Retorna_Info_Curso (40)
– Exec Retorna_Info_Curso (32)
– Exec Retorna_Info_Curso (99)
Analise os resultados

• Crie uma função para calcular o total arrecadado num curso.


CREATE OR REPLACE FUNCTION Calcula_Total_Arrecadado
RETURN number
IS
v_soma number;
BEGIN
select sum(preco)
into v_soma
from cursos c, turmas t, historico h
where c.cod_curso = t.cod_curso
and t.cod_turma = h.cod_turma;
return v_soma;
END;
/
Execute e analise o resultado.

Elaborado por Dra. Otília Fernandes da Graça 13


MANUAL DE PL/SQL

• Crie uma procedure para inserir um instrutor. Use sequência para gerar o código
do instrutor.
DROP SEQUENCE Gera_Cod_instrutor;
CREATE SEQUENCE Gera_Cod_instrutor start with 50;

CREATE OR REPLACE PROCEDURE Insere_Instrutor


(v_nome in instrutores.nome_instrutor%type,
v_tel in instrutores.tel_instrutor%type,
v_adm in instrutores.admissao%type)
IS
BEGIN
insert into instrutores
values (Gera_Cod_instrutor.Nextval, v_nome, v_tel,v_adm);
commit; -- Sem este comando, a gravação efectiva não ocorre
END;
/

Execute e verifique o resultado na tabela instrutores.

• Criar uma procedure que actualize o telefone de um instrutor (a rotina deve


receber os dados necessários por parâmetros).
• Crie uma procedure que elimine instrutores sem turmas.
• Execute e verifique na tabela.

• Criar uma função que retorne informação de um curso. Use exception para
controlar os erros.

create or replace function Retorna_Info_Curso_Tratada


(v_ch in cursos.carga_horaria%type)
return varchar2
Is
v_nome cursos.nome_curso%type;
v_preco cursos.preco%type;
msg varchar2(60);
begin
select nome_curso, preco
into v_nome, v_preco
from cursos
where carga_horaria = v_ch;
return ('curso: '|| v_nome || chr(10) || 'preço: '|| to_char(v_preco));

Elaborado por Dra. Otília Fernandes da Graça 14


MANUAL DE PL/SQL

exception
when no_data_found then
return ('Nenhum curso possui carga horária especificada');
when too_many_rows then
return ('Muitos cursos possuem carga horária especificada');
when others then
msg := 'Erro desconhecido: ' || to_char(sqlcode);
return (msg);
end;

- Active a função e mostre a saída.

• Criar uma função para inserir instrutor. Controle os erros.


• Criar uma função que insere aluno na turma caso não esteja cheia.

Elaborado por Dra. Otília Fernandes da Graça 15

Você também pode gostar

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy