UNIVERSIDADE REGIONAL DE BLUMENAU CENTRO DE CIÊNCIAS EXATAS E NATURAIS CURSO DE CIÊNCIAS DA COMPUTAÇÃO (Bacharelado) SOFTWARE PARA REPLICAÇÃO DE OBJETOS ENTRE DUAS INSTÂNCIAS DE UM SGBD ORACLE TRABALHO DE CONCLUSÃO DE CURSO SUBMETIDO À UNIVERSIDADE REGIONAL DE BLUMENAU PARA A OBTENÇÃO DOS CRÉDITOS NA DISCIPLINA COM NOME EQUIVALENTE NO CURSO DE CIÊNCIAS DA COMPUTAÇÃO — BACHARELADO ANDRINO CARLOS DE SOUZA JUNIOR BLUMENAU, MARCO/2003 2003/03-22 SOFTWARE PARA REPLICAÇÃO DE OBJETOS ENTRE DUAS INSTÂNCIAS DE UM SGBD ORACLE ANDRINO CARLOS DE SOUZA JUNIOR ESTE TRABALHO DE CONCLUSÃO DE CURSO, FOI JULGADO ADEQUADO PARA OBTENÇÃO DOS CRÉDITOS NA DISCIPLINA DE TRABALHO DE CONCLUSÃO DE CURSO OBRIGATÓRIA PARA OBTENÇÃO DO TÍTULO DE: BACHAREL EM CIÊNCIAS DA COMPUTAÇÃO Prof. Alexander Roberto Valdameri — Orientador na FURB Prof. José Roque Voltolini da Silva — Coordenador do TCC BANCA EXAMINADORA Prof. Alexander Roberto Valdameri Prof. Maurício Capobianco Lopes Prof. Wilson Pedro Carli ii DEDICATÓRIA Este trabalho de conclusão de curso é dedicado à Andrino Carlos e Maria de Lourdes, pelo amor, carinho e força recebida ao longo destes anos de graduação. iii AGRADECIMENTOS Aos meus pais, Andrino Carlos e Maria de Lourdes, que me deram força e energia necessária para a realização desta graduação. A empresa Bunge Alimentos, que forneceu-me equipamentos e ajuda nas dificuldades encontradas por esta monografia. Ao meu orientador, prof. Alexander Roberto Valdameri, pela confiança e perseverança na conclusão deste trabalho, que sempre com idéias oportunas, auxiliou-me nos problemas técnicos. A minha querida amiga Joice, onde sua ajuda e companheirismo sempre estavam presentes nos momentos difíceis. A todos aqueles que, direta ou indiretamente, contribuíram para a realização deste trabalho. iv SUMÁRIO LISTA DE ABREVIATURAS...............................................................................................vii RESUMO................................................................................................................................viii ABSTRACT .............................................................................................................................ix LISTA DE FIGURAS............................................................................................................... x LISTA DE QUADROS............................................................................................................xi 1 INTRODUÇÃO ..................................................................................................................... 1 1.1 OBJETIVOS DO TRABALHO.................................................................................. 2 1.2 ORGANIZAÇÃO....................................................................................................... 2 2 AMBIENTE DESENVOLVIMENTO X PRODUÇÃO..................................................... 4 3 ORACLE ................................................................................................................................ 6 3.1 INSTÂNCIAS E OBJETOS DE UMA INSTÂNCIA................................................. 6 3.1.1 Tabelas ................................................................................................................... 6 3.1.2 Visões...................................................................................................................... 7 3.1.3 Unidades De Programação .................................................................................... 7 3.1.4 Sinônimos ............................................................................................................... 8 3.1.5 Índices..................................................................................................................... 8 3.1.6 Clusters................................................................................................................... 8 3.2 LINGUAGEM DE CONSULTA SQL ....................................................................... 9 3.2.1 Literais.................................................................................................................... 9 3.2.2 Comentários ......................................................................................................... 10 3.2.3 Tipos De Dados .................................................................................................... 10 3.2.4 Expressões ............................................................................................................ 12 3.2.5 Condições ............................................................................................................. 13 v 3.3 CURSORES ............................................................................................................. 13 3.3.1 Laços For Em Cursores........................................................................................ 15 3.3.2 Cursores Dinâmicos ............................................................................................. 16 3.3.3 Manipulação De Cursores Dinâmicos ................................................................. 17 4 DESENVOLVIMENTO DO SOFTWARE....................................................................... 19 4.1 REQUISITOS PRINCIPAIS DO PROBLEMA ....................................................... 19 4.2 ESPECIFICAÇÃO ................................................................................................... 19 4.2.1 Diagrama De Contexto......................................................................................... 20 4.2.2 Diagrama De Fluxo De Dados (Dfd)................................................................... 20 4.2.3 Diagrama De Entidade/Relacionamento ............................................................. 21 4.3 IMPLEMENTAÇÃO ............................................................................................... 23 4.3.1 Técnicas E Ferramentas Utilizadas ..................................................................... 23 4.3.2 Apresentação Da Implementação......................................................................... 27 5 CONSIDERAÇÕES FINAIS.............................................................................................. 35 5.1 CONCLUSÃO.......................................................................................................... 35 5.2 LIMITAÇÕES .......................................................................................................... 35 5.3 EXTENSÕES ........................................................................................................... 36 6 ANEXO 1 – CÓDIGO FONTE DA ROTINA .................................................................. 37 REFERÊNCIAS BIBLIOGRÁFICAS ................................................................................. 42 vi LISTA DE ABREVIATURAS AD Administrador de Dados ANSI American National Standards Institute DBA Data Base Administrator DER Diagrama Entidade e Relacionamento DFD Diagrama de Fluxo de Dados PL/SQL Program Language / Structured Query Language SGBD Sistema Gerenciador de Banco de Dados SGBDR Sistema Gerenciador de Banco de Dados Relacional SQL Structured Query Language vii RESUMO Este trabalho consiste no desenvolvimento de uma ferramenta que executa cópia de dados entre tabelas de diferentes instâncias (ambiente produção x ambiente desenvolvimento) juntamente com suas respectivas restrições de parentesco. O protótipo especificado e desenvolvido neste trabalho efetua documentação das cópias realizadas, além de garantir que as restrições de parentescos entre as tabelas também estejam existentes na instância de destino, como por exemplo a nota fiscal e seus respectivos itens. viii ABSTRACT This study consists in a development tool that analyzes and restructures PL/SQL source codes, using legibility patterns, obtained in library research. The prototype specified and developed in this work performs documentation of the programs and subroutines, shows warnings about some programming constructions and format the attributes of the source code like indentation, keywords, table columns and internal variables. ix LISTA DE FIGURAS FIGURA 1 : DIAGRAMA DE CONTEXTO ........................................................................... 20 FIGURA 2 : DIAGRAMA DE FLUXO DE DADOS............................................................... 21 FIGURA 3 : TELA DE PARAMETRIZAÇÃO........................................................................ 28 FIGURA 4 : LISTA DE INSTÂNCIAS.................................................................................... 28 FIGURA 5 : TELA PRINCIPAL DO SOFTWARE ................................................................. 29 FIGURA 6 : ERRO DE INSTÂNCIA INCORRETA ............................................................... 29 FIGURA 7 : INSTÂNCIAS DISPONÍVEIS............................................................................. 30 FIGURA 8 : TABELA INEXISTENTE NO DESTINO ........................................................... 30 FIGURA 9 : ERRO CÓPIA VIA SQL PLUS ........................................................................... 31 FIGURA 10 : CÓPIA VIA SOFTWARE.................................................................................. 32 FIGURA 11 : RESULTADO CÓPIA VIA SOFTWARE......................................................... 33 FIGURA 12 : CONSULTA LOGS DE CÓPIAS ...................................................................... 34 FIGURA 13 : CAMPO COMANDO INSERT ......................................................................... 34 x LISTA DE QUADROS QUADRO 1 – COMENTÁRIO DE LINHA ÚNICA ............................................................... 10 QUADRO 2 – COMENTÁRIO DE MÚLTIPLAS LINHAS ................................................... 10 QUADRO 3 – TIPOS DE DADOS INTERNOS ...................................................................... 11 QUADRO 4 – EXEMPLO DE DECLARAÇÃO DE CURSOR............................................... 14 QUADRO 5 – CURSOR COM PARÂMETROS ..................................................................... 15 QUADRO 6 – EXEMPLO DE INICIALIZAÇÃO DE UM CURSOR..................................... 15 QUADRO 7 – REFERÊNCIA INDIVIDUAL DE CAMPOS DO CURSOR........................... 16 QUADRO 8 – VARIÁVEL DO TIPO CURSOR ..................................................................... 18 QUADRO 9 – COMANDOS FETCH E CLOSE...................................................................... 18 QUADRO 10 – CABEÇALHO DA SUBROTINA .................................................................. 23 QUADRO 11 – PROCEDIMENTO ORGANIZA_WHERE ................................................... 24 QUADRO 12 – PROCEDIMENTO RECRIA_WHERE.......................................................... 25 QUADRO 13 – PROCEDIMENTO GRAVA_LOG ................................................................ 27 xi 1 1 INTRODUÇÃO No processo de testes de software, umas das maiores dificuldades encontradas atualmente pelos desenvolvedores é a igualdade de ambientes entre desenvolvimento e produção. O desenvolvedor, com o intuito de executar todas as tarefas possíveis em um ambiente semelhante ao de um usuário, muitas vezes acaba executando um simples overview das funcionalidades do sistema devido aos poucos dados existentes, acarretando assim, em possíveis falhas no projeto final, dificultando sua manutenção. Segundo Lowell (1985), a manutenção consome recursos vitais para o desenvolvimento de novos projetos. Sendo assim, o ideal é que este processo de manutenção seja o mais rápido e eficiente possível. Para a averiguação das alterações efetuadas pelos desenvolvedores, o correto seria possuir um ambiente de testes o mais próximo possível do original, algo que raramente consegue-se obter. Em tratando-se de sistemas baseados em estruturas de armazenamento em bancos de dados, faz-se necessário a replicação dos objetos que constituem o modelo físico do sistema em ambos os ambientes citados, para que se possa avaliar efetivamente as rotinas e seu funcionamento. Atualmente no mercado existem diversos Sistemas Gerenciadores de Banco de Dados – SGBD, como exemplo pode-se citar o MySQL, que oferecem um mecanismo de replicação de objetos entre duas instâncias. Porém, outros como o SGBD Oracle, objeto de estudo deste trabalho, não oferece tal recurso, o que dificulta a consolidação do projeto através dos testes e da validação. Segundo Ramalho (1999), o Oracle é um sistema de gerenciamento de banco de dados relacional que, além do banco de dados, possui uma instância de servidor Oracle. O Oracle possui duas estruturas, a física e a lógica. Elas são separadas, podendo-se gerenciar o armazenamento físico sem afetar o acesso lógico de armazenamento. Assim, esta proposta tem por finalidade solucionar uma grande deficiência existente em diversas empresas no que tange à criação, manutenção, integridade e confiabilidade de 2 uma base de dados adequada a ser utilizada em uma das principais etapas do desenvolvimento do sistema, no caso, a fase de testes. Esta fase, conforme Hetzel (1987), deve ser considerada uma atividade necessária na coleta de informações, de modo a permitir que se possa avaliar o trabalho com eficiência. Sendo assim, será desenvolvido um software para replicação de objetos entre duas instâncias de um SGBD Oracle, uma vez que o mesmo auxiliará os desenvolvedores oferecendo um ambiente mais propício para testes e validações dos sistemas desenvolvidos. A tecnologia utilizada para desenvolvimento da ferramenta foi o Form Builder 6.0i, que faz parte do pacote de desenvolvimento chamado Developer/2000, existente no Oracle. 1.1 OBJETIVOS DO TRABALHO Este trabalho tem como objetivo principal o desenvolvimento de um software para realizar cópias entre duas instâncias de um SGBD Oracle 8i com o intuito de auxiliar o desenvolvedor na automatização do controle das restrições existentes por falta de relacionamentos existentes entre objetos. Os objetivos específicos do trabalho são: a) executar a cópia de dados de tabelas entre duas instâncias previamente informadas; b) armazenar históricos das cópias efetuadas para possíveis auditorias; c) gerenciamento de chaves duplicadas e foreing keys / tabelas inexistentes; d) gerenciamento de permissões de objetos para usuários. 1.2 ORGANIZAÇÃO O trabalho é composto por quatro capítulos. Neste primeiro capítulo foram apresentados a origem do trabalho, objetivo e organização. No segundo capítulo são apresentadas as principais características do ambiente de testes x ambiente de desenvolvimento a nível de banco de dados. No terceiro capítulo são apresentados conceitos e características do banco de dados Oracle, além de informações sobre a linguagem de programação PL/SQL. 3 No quarto capítulo é descrita a especificação do protótipo, assim como detalhes sobre sua implementação. No quinto capítulo são apresentadas as conclusões e sugestões a respeito do trabalho desenvolvido. 4 2 AMBIENTE DESENVOLVIMENTO X PRODUÇÃO Segundo Pressman (1995), a atividade de teste de software é um elemento crítico da garantia de qualidade de software e representa a última revisão de especificação, projeto e codificação. Se a atividade de teste for conduzida com sucesso ela descobrirá erros no software. Como um benefício secundário, a atividade de teste demonstra que as funções de software aparentemente estão trabalhando de acordo com as especificações e que os requisitos de desempenho foram aparentemente cumpridos. Para se obter confiança nos testes e facilidade no andamento desta fase, é de grande importância possuir um ambiente propício para o desenvolvedor executar seus testes. O ideal seria possuir o mesmo ambiente que o usuário final, mas como isto não é possível devido a várias limitações, procura-se aproximar-se ao máximo deste. Conforme Herbert (1997), as atividades de execução e de seleção de dados de entrada são as mais importantes na fase de testes: a arte de testar um programa inicia quando a pessoa que conduz o teste seleciona os valores de entrada. Em se tratando de SGBD, o maior problema refere-se ao grande volume de dados que o ambiente de produção possui. Quando o desenvolvedor procura igualar as bases, ocorre diversas vezes estouro de área. Mesmo quando tenta-se buscar apenas dados referente ao seu teste, acaba sofrendo problemas devido às restrições de parentesco nas tabelas. Tem-se por exemplo uma nota fiscal, que quando copiada a nota, é necessário copiar também os itens da nota, os produtos, os vencimentos, o cliente e assim por diante. Caso algum destes dados não existir no ambiente de desenvolvimento, ocorre erro de integridade. O SGBD Oracle não possui nenhuma ferramenta que permita ao desenvolvedor dizer somente que deseja copiar a nota fiscal e que faça implicitamente a cópia das demais tabelas relacionadas automaticamente. Esta é uma grande desvantagem, pois o desenvolvedor perde uma grande parte do tempo destinado ao teste em apenas montar a base de dados. Outro fator importante que praticamente é inexistente no ambiente de desenvolvimento é a falta de concorrência. Muitos testes podem ser executados com sucesso no ambiente de desenvolvimento, mas no momento da execução se tornam verdadeiros fracassos, onde o 5 sistema passa a maior parte de tempo “preso” por algum outro usuário, sem a necessidade do travamento do registro. Temos ainda como possíveis pontos de falhas no teste os vícios do desenvolvedor em testar somente o que foi alterado, pois se for testar todo o componente, a base disponível é muito restrita e com tão poucos dados, talvez seja gasto mais tempo testando do que alterando o sistema. Por último, temos ainda o ambiente cliente servidor, onde o cliente encontra-se em locais distantes do SGBD, o que faz o sistema possuir um pequeno delay no processamento da informação, algo que no ambiente de testes passa despercebido, tendo em vista que os testes normalmente são feitos em ambientes locais. Este trabalho tem como objetivo solucionar a parte de cópia de tabelas com registros dependentes, ou seja, criar uma melhoria no SGBD Oracle para facilitar a montagem do banco de desenvolvimento. 6 3 ORACLE Segundo Ault (1995), o Oracle é um sistema de gerenciamento de banco de dados relacional (SGBDR). Um SGBDR armazena dados em tabelas chamadas de relações, as quais representações bidimensionais de dados, onde as linhas – chamadas de tuplas no jargão relacional – representam registros, e as colunas – chamadas de atributos – são as partes de informação contidas no registro. Os três principais aspectos do modelo relacional, no qual o Oracle se baseia, são as estruturas, as operações e as regras de integridade, conforme Morais (1995). As estruturas são os objetos que guardam os dados de um banco de dados. As estruturas e os dados podem ser manipulados através de operações. As operações são as ações que permitem aos usuários manipularem os dados e as estruturas de um banco de dados. Essas operações devem aderir a um conjunto de regras de integridade predefinidas. As regras de integridade são leis que governam quais operações são permitidas nos dados e nas estruturas de um banco de dados, com o propósito de protegê-los de operações indevidas. 3.1 INSTÂNCIAS E OBJETOS DE UMA INSTÂNCIA Uma instância é uma coleção de objetos ligados à identificação única de um usuário em um banco de dados, conforme Morais (1995). Segundo Oracle (1992) objetos de uma instância são as estruturas lógicas que se referem diretamente aos dados de uma base de dados. Objetos de um esquema incluem estruturas como tabelas, visões, seqüências, store procedures, sinônimos, índices, clusters e links entre banco de dados. 3.1.1 TABELAS Uma tabela é a unidade básica usada para guardar os dados de um banco de dados Oracle, isto é, ela contém todos os dados acessíveis pelos usuários. Uma tabela é composta por linhas e colunas e possui um único nome que a identifica. Cada uma das colunas das tabelas também possui apenas um único nome identificador, um 7 tipo de dado associado, um tamanho e uma escala ou precisão (usadas somente para os tipos de dados numéricos). Uma linha é uma coleção de colunas com informações correspondente a um único registro, segundo Morais (1995). 3.1.2 VISÕES Segundo Oracle (1992), uma visão é uma representação customizada dos dados de uma ou mais tabelas (ou outras visões). Conforme Morais (1995) uma visão é representada e armazenada no dicionário de dados como um simples texto. Quando uma visão é referenciada em um comando SQL, o Oracle combina o comando que referencia a visão com o comando que a define no dicionário de dados, analisa o comando composto, armazena-o na área de memória com os comandos SQL compartilháveis entre os usuários e, finalmente, o executa. Um comando que referencia uma visão, somente é analisado novamente (para obter um plano de execução do comando), quando não existe nenhum comando idêntico definido na área de memória compartilhada que armazena os comandos SQL. Sempre que possível, o Oracle combina a consulta que referencia uma visão com a consulta que a define. Isso é feito para que o comando final não referencie mais um objeto, no caso a visão. 3.1.3 UNIDADES DE PROGRAMAÇÃO O termo “unidades de programação” refere-se a stored procedures, functions e packages, conforme Morais (1995) . As procedures ou functions são um grupo de instruções SQL e PL/SQL agrupados e que formam uma unidade para executar uma tarefa específica. As functions e procedures permitem a combinação da flexibilidade e facilidade da linguagem SQL com a funcionalidade procedural da liguagem PL/SQL. As packages permitem um meio bastante eficaz de encapsular as procedures e functions relacionadas em unidades lógicas dentro de um banco de dados e oferecem benefícios no armazenamento e manutenção destas procedures e functions. Elas oferecem 8 também nova funcionalidade a essas estruturas, assim como uma maior funcionalidade e melhor performance para o banco de dados. 3.1.4 SINÔNIMOS Um sinônimo é um alias (apelido) para uma tabela, visão, seqüência ou unidades de programação. Um sinônimo não é um tipo de objeto por si mesmo, mas referencia diretamente um objeto, segundo Oracle (1992). Um sinônimo pode ser público ou privado. Um sinônimo público é pertencente a um grupo especial de usuários chamado PUBLIC e é acessível a todos os usuários do banco de dados. Um sinônimo privado está contido na instância de um usuário específico e disponível somente para este e aos outros usuários a que este concedeu permissões. 3.1.5 ÍNDICES Os índices são estruturas opcionais associadas com tabelas, que podem ser criadas para aumentarem a performance da recuperação de dados, conforme Oracle (1992). 3.1.6 CLUSTERS Clusters são um método opcional de armazenamento de tabelas de dados, segundo Oracle (1992). Segundo Morais (1995), clusters agrupam duas ou mais tabelas, fisicamente guardadas juntas nos mesmos blocos de dados, pelo fato de elas compartilharem informações entre si. Um cluster também pode ser usado para conter somente uma tabela. Como as linhas das tabela agrupadas em um cluster estão fisicamente juntas, o seu uso pode melhorar o acesso aos dados em algumas ocasiões. 9 3.2 LINGUAGEM DE CONSULTA SQL O termo “SQL” é originado do acrônimo de “Structured Query Language”- Linguagem de Consulta Estruturada. Segundo Date (1989), a linguagem SQL é composta por um grupo de facilidades para definição, manipulação e controle de dados de um banco de dados relacional. A partir da publicação do trabalho de E.F. Codd, “A Relational Model of Data for Large Shared Data Banks” – um modelo relacional de dados para grandes bancos de dados compartilhados, em 1970, várias empresas, incentivadas por este trabalho, desenvolveram produtos para suportar a gerência de um banco de dados. Em 1974, nos laboratórios da IBM, definida por D. D. Chamberlin e outros, surgiu a linguagem Structured Query Language (SEQUEL). No ano seguinte, foi implementado um protótipo da mesma, chamado SEQUEL-SRM. No final dos anos 70, e início dos anos 80, a linguagem SQL foi implementada em alguns produtos da própria IBM, e também de outros fabricantes, que também passaram a suportar a linguagem. O interesse pela padronização da linguagem iniciou-se em 1982, por intermédio do órgão de padronização American National Standards Institute (ANSI). O processo de padronização foi baseado na linguagem SQL definida pela IBM. Posteriormente, os padrões foram reconhecidos também pela International Standards Organization (ISO), sob forma da norma ISO 9075 Date (1989). A seguir são apresentados os principais elementos da linguagem SQL. 3.2.1 LITERAIS Os termos “literal” e “valor constante” são sinônimos, e referem-se a valores de dados fixos. Como exemplo, pode-se citar ‘BCC’ e ‘101’, que são literais caractere e inclusos entre aspas simples e 500, que é um literal numérico, conforme Oracle (1997). 10 Muitas expressões e funções do SQL necessitam de valores literais caractere e numéricos. Literais também podem ser expressões como parte de expressões e condições. 3.2.2 COMENTÁRIOS Comentários não afetam a execução de procedimentos SQL, mas aumentam a legibilidade das aplicações, portanto, devem ser usados sempre que possível. Comentários podem ser expressos de duas formas: linha única e linhas múltiplas. Comentário de linha única é representado pelo delimitador “--“, conforme o quadro 1: Quadro 1 – Comentário de linha única SELECT cd_empregado, nome FROM empresa WHERE cd_empresa = 65; -- AND cd_filial = 134; Esta linha não será considerada Fonte: Adaptado de Oracle (1997). O comentário de múltiplas linhas é representado pelos delimitadores “/*” para iniciar um comentário, e “*/” para encerrar um comentário, confome o quadro 2: Quadro 2 – Comentário de múltiplas linhas /* A rotina abaixo bloqueia todos os clientes devedores Implementado em 26/10/2002 */ UPDATE cliente SET id_bloqueado = ‘SIM’ WHERE dt_liquidacao >= TRUNC(SYSDATE); Fonte: Adaptado de Oracle (1997). 3.2.3 TIPOS DE DADOS Todo literal ou coluna manipulada pelo Sistema Gerenciador de Banco de Dados (SGBD) Oracle tem um tipo de dado, sendo que o tipo de dado do valor associa um conjunto 11 de propriedades, que servem para que o banco de dados faça o tratamento correto para cada valor. No processo de criação de tabelas, clusters e stored procedures no banco, são utilizados tipos de dados internos. Estes tipos de dados definem o domínio de valores que cada coluna ou argumento pode possuir, conforme o quadro 3. Quadro 3 – Tipos de Dados Internos Tipo de Dado Descrição String de tamanho variável em bytes com máximo de 4000 e mínimo de VARCHAR2(tam) 1. Deve ser especificado um tamanho para VARCHAR2. String de tamanho variável em bytes com máximo de 4000 e mínimo de NVARCHAR2(tam) 1, de acordo com o conjunto de caracteres nacional escolhido. Deve ser especificado um tamanho para NVARCHAR2. NUMBER(p,s) LONG Numérico com precisão p e escala s. A precisão pode variar de 1 a 38 e a escala de –84 até 127. Dados em formato caracterer de tamanho 2 gigabytes, ou 231 -1 bytes. Período de data válida de 1º de janeiro de 4712 AC até 31º Dezembro de DATE 4712 DC. Dados binários em formato Raw com tamanho em bytes. O tamanho deve RAW(tam) ser especificado e é no máximo 2000. LONG RAW Dados binários de tamanho variável até 2 gigabytes. String hexadecimal que representa o endereço único de uma linha em uma ROWID tabela. CHAR(tam) Caracter de tamanho fixo, com tamanho em bytes. Possui tamanho mínimo e padrão de 1 byte e máximo de 2000 bytes. Caracter de tamanho fixo, com tamanho em bytes. Possui tamanho NCHAR(tam) mínimo e padrão de 1 byte e máximo de 2000 bytes, de acordo com o conjunto de caracteres nacional escolhido. MLSLABEL Formato binário de um label de sistema operacional. Usado para manter 12 compatibilidade com versões antigas. Objeto caracter grande contendo caracteres de byte simples. Tamanho CLOB variável de conjunto de caracteres não é permitido. Tamanho máximo de 4 gigabytes. Objeto caracter grande contendo caracteres de múltiplos bytes. Tamanho NCLOB máximo de 4 gigabytes. Usado para armazenar dados de conjuntos de caracteres nacionais. BLOB Objeto binário grande. Tamanho máximo é de 4 gigabytes. Contém o localizador para um arquivo binário de grande armazenado fora BFILE da base de dados. Tamanho máximo de 4 gigabytes. Fonte: Traduzido de Oracle (1997). 3.2.4 EXPRESSÕES A expressão é a combinação de um ou mais valores, operadores e funções do SQL que resultam em um valor. Uma expressão geralmente assume o tipo de dado dos seus componentes. Abaixo, um exemplo de uma expressão, que utiliza funções e operadores; esta expressão adiciona sete dias para a data atual, remove a quantidade de horas adjacentes e converte o resultado para o tipo de dado CHAR (Oracle, 1997): TO_CHAR(TRUNC(SYSDATE+7)) As expressões podem ser utilizadas em: a) a lista de seleção do comando SELECT; b) como condição das cláusulas WHERE e HAVING; c) as cláusulas CONNECT BY, START WITH, e ORDER BY; d) a cláusula VALUES do comando INSERT; e) a cláusula SET do comando UPDATE. 13 3.2.5 CONDIÇÕES Um condição especifica uma combinação de uma ou mais expressões e operadores lógicos que resultam em VERDADEIRO, FALSO ou desconhecido, segundo Oracle (1997). A condição pode ser usada na cláusula WHERE destes comandos: a) DELETE; b) SELECT; c) UPDATE. No comando SELECT, podem ser usadas condições nas seguintes cláusulas: a) WHERE; b) START WITH; c) CONNECT BY; d) HAVING. Pode-se dizer que a condição seria um tipo de dado “lógico”, mas a linguagem não suporta formalmente este tipo. Operadores lógicos podem combinar múltiplas condições em uma única condição, conforme o exemplo abaixo, que utiliza o operador AND para combinar duas condições: (1 = 1) AND (5 < 7) 3.3 CURSORES Oracle utiliza áreas de trabalho para executar comandos SQL e armazenar a informação processada. Um cursor permite percorrer esta área de trabalho para ler as informações armazenadas. Há dois tipos de cursores: implícitos e explícitos. Cursores implícitos são criados pelo Oracle a cada execução de um comando SQL, mas não podem ser utilizados em um programa em PL/SQL. Cursores explícitos podem ser manipulados em um programa PL/SQL. A declaração de um cursor segue a sintaxe DECLARE CURSOR nome_cursor IS comando_select; Por exemplo, 14 Quadro 4 – Exemplo de Declaração de Cursor DECLARE CURSOR c1 IS SELECT empno, ename, job FROM emp WHERE deptno = 20; A declaração do cursor associa um comando SQL a ele. Um curso permitirá ler, linha a linha, o resultado de um consulta. Da mesma maneira que um arquivo, o cursor deve ser aberto, percorrer uma a uma cada linha, até o final do conjunto de dados. O comando OPEN executa a consulta associada ao cursor, obtém um conjunto de linhas como resposta a consulta e posiciona o cursor na primeira linha. O comando FETCH retorna os valores da linha corrente e avança uma posição na lista. O comando CLOSE desabilita o cursor, liberando o espaço de memória ocupado pelo conjunto resposta. A sintaxe do comando OPEN é: OPEN nome_cursor; A sintaxe do comando CLOSE é: CLOSE nome_cursor; E do comando FETCH é FETCH nome_curso INTO [lista_variáveis]. A lista de variáveis pode conter uma ou mais variáveis. Há duas alternativas: utilizar variáveis individuais, de tipos correspondentes ao retorno do SELECT; ou utilizar uma variável de um tipo registro adequado ao SELECT. Para o cursor declarado acima, é possível: FETCH c1 INTO my_empno, my_ename, my_deptno; ou FETCH c1 INTO my_record; Todos cursores possuem quatro propriedades que podem ser úteis em um programa: %FOUND: indica se a última operação FETCH encontrou uma linha. Seu valor é verdadeiro até a última linha. %NOTFOUND: indica se a última operação FETCH não encontrou uma linha. Seu valor é falso até a última linha. %ISOPEN: indica se o cursor está aberto ou não. 15 %ROWCOUNT: retorna o número de linhas do cursor. Para testar se o cursor retornou algum valor válido ou já atingiu o final do conjunto, pode-se testar a propriedade FOUND do cursor. Por exemplo, FETCH C1 INTO .... WHILE C1%FOUND LOOP Um cursor pode, ainda, ter parâmetros. Deste modo, a definição do cursor fica alterada: Quadro 5 – Cursor com Parâmetros DECLARE CURSOR emp_cursor(dnum NUMBER) IS SELECT sal, comm FROM emp WHERE deptno = dnum; A inicialização do cursor, que pode ser por um comando OPEN ou FOR-LOOP é feita passando o valor do parâmetro. Por exemplo: Quadro 6 – Exemplo de Inicialização de um Cursor FOR emp_record IN emp_cursor(20) LOOP END LOOP; 3.3.1 LAÇOS FOR EM CURSORES Em muitas situações, percorrer todas as linhas resultantes de uma tabela pode ser realizado com o comando FOR, e não com OPEN-FETCH-CLOSE. Um laço FOR em cursores exige uma variável, que é declarada implicitamente dentro do comando. No exemplo abaixo, a variável emp_rec é do tipo registro. Para referir campos individuais da variável, é utilizada a notação ponto (.). 16 Quadro 7 – Referência Individual de Campos do Cursor DECLARE CURSOR c1 IS SELECT ename, sal, hiredate, deptno FROM emp; ... BEGIN FOR emp_rec IN c1 LOOP ... salary_total := salary_total + emp_rec.sal; END LOOP; 3.3.2 CURSORES DINÂMICOS Embora a maioria dos programas em PL/SQL execute comandos previsíveis, que permitem uma declaração estática de um cursor, em algumas situações é necessário alterar dinamicamente, em tempo de execução, o comando SELECT que define o cursor. As seguintes situações são típicas: a) É necessário utilizar um comando de definição de dados (DDL), como o CREATE, um comando de atribuição ou revogação de direitos (GRANT e REVOKE) ou um comando de controle de sessão (ALTER SESSION). Em PL/SQL, estes comandos são necessariamente dinâmicos. b) É necessário compor a clausula WHERE de acordo com condições que o usuário escolhe ou não na interface. O comando adequado é o EXECUTE IMMEDIATE, cuja sintaxe é: EXECUTE IMMEDIATE comando_sql [INTO {variável1, variável2, . ]... | variável_registro}] [USING parâmetro1, parâmetro2, ...}; O comando SQL é especificado na primeira. Na clausula INTO, indica-se as variáveis que receberão o retorno do comando, ou apenas uma variável do tipo registro. Na clausula USING indica-se os parâmetros do comando. Abaixo há um conjunto de exemplos: 17 a) EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE'; executa o comando ALTER SESSION. b) EXECUTE IMMEDIATE 'CREATE TABLE bonus (id NUMBER, amt NUMBER)'; - executa o comando de criação de uma tabela. c) sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)'; d) EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location; executa o comando INSERT, colocando os valores passados por parâmetro na clausula USING. e) sql_stmt := 'SELECT * FROM emp WHERE empno = :1'; f) EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id; - executa o commando SELECT, atribuindoa resposta à variável emp_rec. A identificação do empregado é passada por parâmetro. g) EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num' h) USING dept_id; - retira uma tupla da tabela dept. 3.3.3 MANIPULAÇÃO DE CURSORES DINÂMICOS No caso de comandos SELECT que retornem mais de uma linha no conjunto resposta, é necessário utilizar os comandos OPEN-FETCH-CLOSE para percorrer, linha a linha, o conjunto resposta. Para o comando OPEN utiliza-se a seguinte variação sintática: OPEN {variável_cursor } FOR string_sql [USING argumento1[, argumento2]...]; Uma variável do tipo cursor deve ser declarada, a priori. O comando SQL é montado em uma variável do tipo string, conforme a necessidade do programa, e colocado na clausula 18 FOR. Se houverem parâmetros no comando SQL, os argumentos são passados na clausula USING. O exemplo abaixo ilustra este caso. Veja que a variável emp_cv é declarada como sendo do tipo cursor e no comando SELECT há um parâmetro, cujo valor é atribuído na clausula USING. Quadro 8 – Variável do Tipo Cursor DECLARE TYPE EmpCurTyp IS REF CURSOR; -- define como tipo REF CURSOR emp_cv EmpCurTyp; -- declara a variável cursor my_ename VARCHAR2(15); my_sal NUMBER := 1000; BEGIN OPEN emp_cv FOR – abre a variável cursor 'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal; ... END; Os comandos FETCH e CLOSE permanecem semelhantes, como mostra o trecho de código a seguir: Quadro 9 – Comandos Fetch e Close FETCH emp_cv INTO my_ename, my_sal; END LOOP; CLOSE emp_cv; -- fecha a variável cursor 19 4 DESENVOLVIMENTO DO SOFTWARE Neste tópico será abordado a especificação, recursos e restrições do software. Apresentar-se-á também um caso de uso, comum para desenvolvedores. 4.1 REQUISITOS PRINCIPAIS DO PROBLEMA O software irá realizar cópia de tabelas entre duas instâncias inclusive as restrições caso não existam na instância de destino. Todas as tabelas que foram copiadas e a quantidade de linhas serão armazenadas para possíveis auditorias. As consistências que o software irá fazer para executar a cópia são: a) verificação da existência da tabela na instância de origem; b) verificação da exatidão da cláusula de cópia; c) verificação da estrutura das tabelas entre as duas instâncias. Alguns avisos serão gerados a respeito de problemas contornáveis pelo software. São eles: a) verificação da existência da tabela de destino, sendo que, caso não exista, será criada; b) verificação da falta de registros pai/filho, sendo que neste caso, o sistema será responsável por realizar a cópia. O protótipo gera também um resumo após toda a cópia estar realizada. 4.2 ESPECIFICAÇÃO A especificação é apresentada através do diagrama de contexto, diagrama de fluxo de dados, modelo entidade-relacionamento e o dicionário de dados. Através da engenharia reversa do dicionário de dados do SGBD Oracle, extraiu-se o modelo entidade-relacionamento e o dicionário de dados. Isto faz-se necessário para identificar os locais onde os dados relativos aos objetos encontram-se armazenados. Para as especificações utilizou-se a ferramenta Case Power Designer. 20 4.2.1 DIAGRAMA DE CONTEXTO Este diagrama de contexto representa o fluxo de dados, que representa as tarefas que podem ser executadas na ferramenta. A Figura 1 mostra o diagrama de contexto. Figura 1 : Diagrama de contexto 1 Parâmetro DBA Cópia Desenvolvedor IADG2000 Estatística Log da Cópia 4.2.2 DIAGRAMA DE FLUXO DE DADOS (DFD) O DFD é utilizado para particionar o sistema, mostrando os processos de cada entrada e saída da ferramenta, apresentado na Figura 2. 21 Figura 2 : Diagrama de fluxo de dados 1 DBA Parâmetro Manter Parâmetro Parâmetro_Ok PRM_COPA_TABELA 2 Estatística DBA Extrair Estatística Estatística LOG_COPIA_TABELA 3 Cópia Desenvolvedor Executar Cópia Copia_Ok TABELA_INFORMADA 4 Desenvolvedor Log_Copia Log_Copia_Ok Extrair Log LOG_COPIA_TABELA_ 4.2.3 DIAGRAMA DE ENTIDADE/RELACIONAMENTO O Modelo Entidade/Relacionamento é utilizado para exemplificar quais as tabelas internas do SGBD foram utilizadas e quais tabelas são próprias do sistema. As tabelas do Metadados do Oracle não possui relacionamento, tendo em vista que a presença de chaves primárias é inexistente. 22 Figura 3 : Diagrama entidade/relacionamento ALL_CONSTRAINTS OWNER CONSTRAINT_NAME CONSTRAINT_TYPE TABLE_NAME SEARCH_CONDITION R_OWNER R_CONSTRAINT_NAME DELETE_RULE STATUS DEFERRABLE DEFERRED VALIDATED GENERATED BAD RELY LAST_CHANGE VARCHAR2(30) VARCHAR2(30) VARCHAR2(1) VARCHAR2(30) LONG VARCHAR2(30) VARCHAR2(30) VARCHAR2(9) VARCHAR2(8) VARCHAR2(14) VARCHAR2(9) VARCHAR2(13) VARCHAR2(14) VARCHAR2(3) VARCHAR2(4) DATE ALL_CONS_COLUMNS OWNER CONSTRAINT_NAME TABLE_NAME COLUMN_NAME POSITION VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) VARCHAR2(4000) NUMBER ALL_TAB_COLUMNS OWNER TABLE_NAME COLUMN_NAME DATA_TYPE DATA_TYPE_MOD DATA_TYPE_OWNER DATA_LENGTH DATA_PRECISION DATA_SCALE NULLABLE COLUMN_ID DEFAULT_LENGTH DATA_DEFAULT NUM_DISTINCT LOW_VALUE HIGH_VALUE DENSITY NUM_NULLS NUM_BUCKETS LAST_ANALYZED SAMPLE_SIZE CHARACTER_SET_NAME CHAR_COL_DECL_LENGTH GLOBAL_STATS USER_STATS AVG_COL_LEN VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) VARCHAR2(106) VARCHAR2(3) VARCHAR2(30) NUMBER NUMBER NUMBER VARCHAR2(1) NUMBER NUMBER LONG NUMBER RAW(32) RAW(32) NUMBER NUMBER NUMBER DATE NUMBER VARCHAR2(44) NUMBER VARCHAR2(3) VARCHAR2(3) NUMBER ALL_TABLES OWNER TABLE_NAME TABLESPACE_NAME CLUSTER_NAME IOT_NAME PCT_FREE PCT_USED INI_TRANS MAX_TRANS INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS PCT_INCREASE FREELISTS FREELIST_GROUPS LOGGING BACKED_UP NUM_ROWS BLOCKS EMPTY_BLOCKS AVG_SPACE CHAIN_CNT AVG_ROW_LEN AVG_SPACE_FREELIST_BLOCKS NUM_FREELIST_BLOCKS DEGREE INSTANCES CACHE TABLE_LOCK SAMPLE_SIZE LAST_ANALYZED PARTITIONED IOT_TYPE TEMPORARY SECONDARY NESTED BUFFER_POOL ROW_MOVEMENT GLOBAL_STATS USER_STATS DURATION SKIP_CORRUPT MONITORING CLUSTER_OWNER VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) VARCHAR2(30) NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER VARCHAR2(3) VARCHAR2(1) NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER VARCHAR2(10) VARCHAR2(10) VARCHAR2(5) VARCHAR2(8) NUMBER DATE VARCHAR2(3) VARCHAR2(12) VARCHAR2(1) VARCHAR2(1) VARCHAR2(3) VARCHAR2(7) VARCHAR2(8) VARCHAR2(3) VARCHAR2(3) VARCHAR2(15) VARCHAR2(8) VARCHAR2(3) VARCHAR2(30) ALL_DB_LINKS OWNER DB_LINK USERNAME HOST CREATED VARCHAR2(30) VARCHAR2(128) VARCHAR2(30) VARCHAR2(2000) DATE log_copia_tabela prm_copia_tabela cd_instance_origem cd_instance_destino nm_owner_origem nm_owner_destino varchar(10) varchar(10) varchar2(30) varchar2(30) cd_tabela_oracle cd_usuario dt_copia_tabela ds_clausula_where cd_instance_origem cd_instance_destino nm_owner_origem nm_owner_destino qt_registros_copiados varchar2(30) varchar2(12) date varchar2(2000) varchar(50) varchar(50) varchar2(30) varchar2(30) number(09) 23 As tabelas constantes no diagrama entidade/relacionamento são: a) All_Tables Dados das tabelas do SGBD Oracle. b) All_Constraints Restrições das tabelas. c) All_Cons_Colums Restrições das linhas das tabelas. d) All_Db_Links Instâncias pertencentes ao SGBD. e) Prm_Copia_Tabela Parâmetro utilizado para executar a cópia. f) Log_Copia_Tabela Resultado após a execução da cópia. 4.3 IMPLEMENTAÇÃO 4.3.1 TÉCNICAS E FERRAMENTAS UTILIZADAS Inicialmente seria utilizada a ferramenta Oracle Designer versão 6.0, mas tendo em vista que a mesma não possuía suporte a todos os diagramas desejados (diagrama de fluxo de dados), optou-se pela utilização da ferramenta Power Designer. Para realizar a implementação do protótipo, a partir da especificação realizada, foi utilizada a ferramenta Forms Developer 6i. Esta ferramenta foi escolhida por sua natividade ao SGBD Oracle, além de ser o padrão da Bunge Alimentos, empresa onde o software irá ser utilizado. Esta ferramenta não suporta comandos dinâmicos, portanto, foi desenvolvido uma subrotina que será chamada pelo programa para realizar todo o processo da cópia. O quadro 4 mostra o cabeçalho desta subrotina. Quadro 10 – Cabeçalho da Subrotina CREATE OR REPLACE PACKAGE IADG2001 IS PROCEDURE CONTROLE(P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG P_NM_OWNER_DST P_CD_TABELA_ORACLE_ORG P_CD_TABELA_ORACLE_DST P_DS_CLAUSULA VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2); PROCEDURE ORGANIZA_WHERE(P_NM_OWNER IN VARCHAR2, P_CD_TABELA_ORACLE IN VARCHAR2, P_DS_CLAUSULA IN OUT VARCHAR2 ); PROCEDURE RECRIA_WHERE(P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG VARCHAR2, VARCHAR2, VARCHAR2, 24 P_NM_OWNER_DST P_CD_TABELA_ORACLE_ORG P_NM_CONSTRAINT P_DS_CLAUSULA PROCEDURE GRAVA_LOG(P_DS_INSERT P_CD_TABELA_ORACLE P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG P_NM_OWNER_DST P_QT_GRAVADOS VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2); VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, NUMBER); END IADG2001; O bloco principal que é chamado pelo Forms é a procedure Controle. É recebido como parâmetro as instâncias de origem e destino, os owners de origem e de destino, a tabela de origem (de onde será retirado os dados) e a de destino (para onde os dados serão gravados) e a cláusula de cópia. Na primeira chamada da subrotina, as tabelas de origem e destino serão iguais, mas quando é utilizada a recursividade interna no programa, as mesmas se tornam diferentes. O primeiro passo feito pelo bloco controle é colocar os apelidos nos campos da cláusula de cópia. Para tanto, a rotina Organiza_Where se encarrega de tal tarefa, conforme quadro 5. Todos os campos da tabela são pesquisados dentro da tabela interna do Oracle chamada ALL_TAB_COLUMNS. Quadro 11 – Procedimento Organiza_Where PROCEDURE ORGANIZA_WHERE(P_NM_OWNER IN VARCHAR2, P_CD_TABELA_ORACLE IN VARCHAR2, P_DS_CLAUSULA IN OUT VARCHAR2) IS CURSOR C1 IS SELECT * FROM ALL_TAB_COLUMNS WHERE OWNER = P_NM_OWNER AND TABLE_NAME = P_CD_TABELA_ORACLE; R1 C1%ROWTYPE; NR_POS NUMBER(05); BEGIN OPEN C1; LOOP FETCH C1 INTO R1; EXIT WHEN C1%NOTFOUND; NR_POS := INSTR(P_DS_CLAUSULA,R1.COLUMN_NAME); IF NR_POS <> 0 THEN IF SUBSTR(P_DS_CLAUSULA,NR_POS+LENGTH(R1.COLUMN_NAME),1) IN (' ','.',')','*','+','-','/',',') THEN -- Verifica se o campo tem complemento IF NR_POS <> 1 THEN IF SUBSTR(P_DS_CLAUSULA,NR_POS-1,1) <> '.' THEN P_DS_CLAUSULA := SUBSTR(P_DS_CLAUSULA,1,NR_POS-1)|| P_CD_TABELA_ORACLE ||'.'|| SUBSTR(P_DS_CLAUSULA,NR_POS,LENGTH(P_DS_CLAUSULA)-NR_POS+1); END IF; ELSE P_DS_CLAUSULA := P_CD_TABELA_ORACLE ||'.'|| P_DS_CLAUSULA; END IF; 25 END IF; END IF; END LOOP; CLOSE C1; END; Em seguida, é voltado para a rotina principal, que tem por objetivo neste momento de fazer a junção da sintaxe do comando insert com a tabela mais a cláusula de cópia. Após feito isto, é executado o insert dinamicamente através do comando Execute Immediate. Caso ocorrer erro de restrição na cópia, é identificado qual o nome da constraint em que o erro ocorreu, e é passado para a rotina Recria_Where. A rotina Recria_Where executa o ligamento entre as tabelas e inclui mais sua própria restrição para copiar somente o que não possui na instância de origem e também somente o que for necessário para a cópia anterior se realizar com sucesso, conforme quadro 6. Para a criação do cursor dinâmico foi utilizado o comando Ref Cursor, que neste exemplo está sendo utilizado para a busca de todas as colunas da restrição na instância de destino. Quadro 12 – Procedimento Recria_Where PROCEDURE RECRIA_WHERE(P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG P_NM_OWNER_DST P_CD_TABELA_ORACLE_ORG P_NM_CONSTRAINT P_DS_CLAUSULA VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2) IS TYPE CUR_COLUNA IS REF CURSOR; C1 CUR_COLUNA; COMANDO_SQL COMANDO_SQL_2 VARCHAR2(1000); VARCHAR2(1000); NM_TABELA_ORACLE_FK NM_CAMPO_FK DS_CLAUSULA_TMP DS_CLAUSULA_EXISTS VARCHAR2(30); VARCHAR2(40); VARCHAR2(200); VARCHAR2(200); NM_TABELA_ORACLE DS_CLAUSULA NM_CAMPO DS_ERRO DS_ULTIMO_INSERT VARCHAR2(500); VARCHAR2(4000); VARCHAR2(50); VARCHAR2(500); VARCHAR2(1000); W_TABLE_NAME W_COLUMN_NAME W_POSITION BEGIN VARCHAR2(30); VARCHAR2(50); NUMBER(05); DS_CLAUSULA := P_DS_CLAUSULA; NM_TABELA_ORACLE := P_CD_TABELA_ORACLE_ORG; COMANDO_SQL := 'SELECT ' ' ' FROM ' WHERE ' AND TABLE_NAME, ' || COLUMN_NAME, ' || POSITION ' || ALL_CONS_COLUMNS@'||P_CD_INSTANCE_DST|| OWNER = :1 ' || CONSTRAINT_NAME = :2'; 26 OPEN C1 FOR COMANDO_SQL USING P_NM_OWNER_DST, P_NM_CONSTRAINT; LOOP FETCH C1 INTO W_TABLE_NAME, W_COLUMN_NAME, W_POSITION; EXIT WHEN C1%NOTFOUND; BEGIN COMANDO_SQL_2 := 'SELECT B.COLUMN_NAME , ' || ' B.TABLE_NAME ' || ' FROM ALL_CONS_COLUMNS@'||P_CD_INSTANCE_DST||' B, '|| ' ALL_CONSTRAINTS@' ||P_CD_INSTANCE_DST||' A '|| ' WHERE A.OWNER = :1 '|| ' AND A.CONSTRAINT_NAME = :2 ' || ' AND B.OWNER = A.OWNER ' || ' AND B.CONSTRAINT_NAME = A.R_CONSTRAINT_NAME '|| ' AND B.POSITION = :3'; EXECUTE IMMEDIATE COMANDO_SQL_2 INTO NM_CAMPO_FK, NM_TABELA_ORACLE_FK USING P_NM_OWNER_DST, P_NM_CONSTRAINT, W_POSITION; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE_APPLICATION_ERROR(-20200,'Erro na busca de campos da constraint '|| P_NM_CONSTRAINT||': '||SQLERRM); END; DS_CLAUSULA_TMP := W_TABLE_NAME || '.' || W_COLUMN_NAME || ' = ' || NM_TABELA_ORACLE_FK || '.' || NM_CAMPO_FK; IF DS_CLAUSULA IS NOT NULL THEN DS_CLAUSULA := DS_CLAUSULA_TMP || ' AND ' || DS_CLAUSULA; ELSE DS_CLAUSULA := DS_CLAUSULA_TMP; END IF; -- Verificação do Not Exists IF DS_CLAUSULA_EXISTS IS NOT NULL THEN DS_CLAUSULA_EXISTS := DS_CLAUSULA_EXISTS || ' AND '; END IF; DS_CLAUSULA_EXISTS := DS_CLAUSULA_EXISTS || NM_TABELA_ORACLE_FK||'.'||NM_CAMPO_FK||' = A.'|| NM_CAMPO_FK; -END LOOP; CLOSE C1; NM_TABELA_ORACLE := NM_TABELA_ORACLE_FK || ', '|| NM_TABELA_ORACLE; DS_CLAUSULA_EXISTS := ' AND NOT EXISTS (SELECT * FROM '|| NM_TABELA_ORACLE_FK||'@'||P_CD_INSTANCE_DST|| ' A WHERE '||DS_CLAUSULA_EXISTS||')'; DS_CLAUSULA := DS_CLAUSULA || DS_CLAUSULA_EXISTS; IADG2001.CONTROLE(P_CD_INSTANCE_ORG, P_CD_INSTANCE_DST, P_NM_OWNER_ORG, P_NM_OWNER_DST, NM_TABELA_ORACLE, NM_TABELA_ORACLE_FK, DS_CLAUSULA); END; Por fim, esta subrotina chama dinamicamente a própria rotina principal do programa, sendo que a tabela de origem será a tabela anterior mais a tabela que ocorreu o erro de restrição, e a tabela de destino será somente a tabela em que ocorreu o erro de restrição. Por fim, após as cópias serem realizadas com sucesso, é gerado o log informando a quantidade de linhas copiadas e o comando executado. A rotina encarregada desta função é a 27 Grava_Log. O funcionamento do procedimento é simples: são recebidos todos os parâmetros necessários e é feito um simples insert na tabela LOG_COPIA_TABELA. O quadro 7 mostra o funcionamento deste procedimento. Quadro 13 – Procedimento Grava_Log PROCEDURE GRAVA_LOG(P_DS_INSERT VARCHAR2, P_CD_TABELA_ORACLE VARCHAR2, P_CD_INSTANCE_ORG VARCHAR2, P_CD_INSTANCE_DST VARCHAR2, P_NM_OWNER_ORG VARCHAR2, P_NM_OWNER_DST VARCHAR2, P_QT_GRAVADOS NUMBER) is BEGIN insert into log_copia_tabela (CD_TABELA_ORACLE ,CD_USUARIO ,DT_COPIA_TABELA ,DS_CLAUSULA_WHERE ,CD_INSTANCE_ORIGEM ,CD_INSTANCE_DESTINO ,NM_OWNER_ORIGEM ,NM_OWNER_DESTINO ,QT_REGISTROS_COPIADOS) values (P_CD_TABELA_ORACLE ,USER ,SYSDATE ,P_DS_INSERT ,P_CD_INSTANCE_ORG ,P_CD_INSTANCE_DST ,P_NM_OWNER_ORG ,P_NM_OWNER_DST ,P_QT_GRAVADOS); EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20300,'Erro ao inserir LOG: '||sqlerrm); END; A rotina completa se encontra no anexo deste trabalho. 4.3.2 APRESENTAÇÃO DA IMPLEMENTAÇÃO Para demonstrar a operacionalidade da implementação foi realizado um estudo de caso, com uma execução passo-a-passo do processo de cópia, utilizando o software construído. O primeiro passo é feito pelo DBA, que tem como objetivo parametrizar o sistema, informando qual será a instância de produção (origem) e a instância de desenvolvimento (destino). É também de sua responsabilidade informar qual o usuário (owner) das duas instâncias. Ao executar o aplicativo, a tela inicial é apresentada, conforme a figura 3. 28 Figura 3 : Tela de parametrização Nesta tela o DBA pode solicitar uma lista de valores com as instâncias disponíveis, conforme figura 4. Figura 4 : Lista de instâncias Após parametrizado o sistema, o processo passa a ser de responsabilidade do desenvolvedor, que agora possui permissão de executar a cópia. A figura 5 mostra a interface do desenvoldedor. 29 Figura 5 : Tela principal do software Os usuários de origem/destino e as instâncias de origem/destino são buscadas automaticamente pelos parâmetros definidos pelo DBA. O software consiste para que a instância em que está sendo executado o programa é a mesma que a instância de origem. Isto se faz necessário para a performance não ficar prejudicada. Caso isto não ocorra, é exibido uma mensagem conforme a figura 6, que impedirá o usuário de continuar, informando qual a instância que o software deve executar. Figura 6 : Erro de instância incorreta Caso o desenvolvedor não souber o nome completo da tabela, é disponibilizado uma lista com todas as tabelas pertencentes à instância, conforme figura 7. 30 Figura 7 : Instâncias disponíveis Caso a tabela escolhida não existir na instância de destino, será aberto uma janela perguntando se deve-se criar tal tabela, conforme figura 8. Figura 8 : Tabela inexistente no destino 31 Na figura 9, é mostrado o problema que ocorre quando tenta-se copiar uma tabela de produção para o ambiente de desenvolvimento, onde a mesma possui integridades faltantes no destino. Pode-se observar que a constraint T0011_SERIE não está completa, sendo necessário consultar qual tabela a mesma referencia e quais os atributos referenciados, para então fazer a carga, correndo o risco desta nova tabela também ocorrer erro na integridade. Figura 9 : Erro cópia via SQL Plus Com a utilização do software, basta apenas informar a tabela e a cláusula where, que o sistema se responsabilizará de buscar os dados, conforme figura 10. 32 Figura 10 : Cópia via software Após pressionar o botão de executar a cópia, o sistema executará a package IADG2001, que conterá toda a lógica para a cópia, sendo a mesma implementada através de cursores dinâmicos e recursividade (ver capítulo 4.3.1). A figura 11 mostra o resultado da cópia, onde foram copiadas as tabelas SERIE_CNH_FILIAL_CGC_TESTE, que possuia integridade de dados com 9 (nove) registros da tabela FILIAL_TESTE, que esta por sua vez possuia integridade de dados com 1 (um) registro da tabela empresa. O comando insert é informado a título de curiosidade para o desenvolvedor. 33 Figura 11 : Resultado cópia via software Para acompanhamento por parte do DBA, todos os dados copiados são gravados na tabela LOG_COPIA_TABELA, onde o mesmo pode fazer a consulta através da tela demonstrada na figura 12. 34 Figura 12 : Consulta logs de cópias As estatítica da quantidade de registros copiados se encontram no campo registros copiados. Como o comando insert é normalmente muito maior que o campo disponibilizado, basta o DBA dar um clique duplo no campo para abrir uma janela maior, conforme figura 13. Figura 13 : Campo comando insert 35 5 CONSIDERAÇÕES FINAIS 5.1 CONCLUSÃO A carência de bibliografias relatando o processo de migração de estruturas no ambiente produção para o ambiente de desenvolvimento dificultou a contextualização e o enriquecimento literário deste trabalho, haja vista que tais mecanismos não são explorados e documentados pelas empresas de informática. O trabalho procurou apresentar os aspectos relevantes no processo de replicação de objetos entre dois servidores, em questão, banco de dados Oracle. Procurou-se estabelecer critérios para gerar documentação das cópias, com criação de históricos, para preservar a segurança dos dados da empresa. Durante a implementação, encontrou-se grande dificuldade no gerenciamento de cursores dinâmicos, tendo em vista que não foi possível fazer a criação de variáveis em tempo de execução pelo PL/SQL (linguagem procedural imbutida - extensão da SQL). A literatura nesta área foi restrita devido a este gerenciamento ser presente apenas na última versão da ferramenta. A ferramenta foi colocada em testes na empresa Bunge Alimentos SA, sendo que a meta esperada foi atingida. Atualmente, cerca de 25% dos analistas estão utilizando esta ferramenta para executar suas cópias. A consulta dos logs das cópias foram disponibilizadas para todos os analistas e não somente para o DBA. Acredita-se que este trabalho possa servir de alicerce para novas aplicações e sobretudo para a geração de documentos que relatam as dificuldades encontradas pelos analistas de sistemas e programadores na compatibilização de ambientes de desenvolvimento e produção. 5.2 LIMITAÇÕES O software possui como limitação a regravação de dados que já existem na instância de destino. Optou-se em não se fazer esta regravação pois poderia estar excluindo dados que foram modificados propositadamente pelo desenvolvedor. 36 Outra limitação existente refere-se à cópia de views, pois este tipo de estrutura pode agregar vária tabelas conjuntas, onde sua implementação ficaria complexa demais e sujeita a gerar problemas. 5.3 EXTENSÕES Como sugestão para futuros trabalhos, a inclusão de parametrização deste protótipos, tais como gerenciamento de chaves duplicadas, cópias de restrições e cópias de view seriam de grande valia para futuros projetos. Outro projeto que seria de muita importância seria a geração de concorrência para tabelas informadas, facilitando assim, uma outra parte de testes de software. 37 6 ANEXO 1 – CÓDIGO FONTE DA ROTINA -- ======================================================================= -- PROGRAMA IADG2001 -- FUNCAO EXECUTAR COPIA ENTRE TABELA -- ANALISTA ANDRINO CARLOS DE SOUZA JUNIOR -- PROGRAMADOR ANDRINO CARLOS DE SOUZA JUNIOR -- CODIFICACAO /NOV/02 -- ======================================================================= CREATE OR REPLACE PACKAGE IADG2001 IS PROCEDURE CONTROLE(P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG P_NM_OWNER_DST P_CD_TABELA_ORACLE_ORG P_CD_TABELA_ORACLE_DST P_DS_CLAUSULA VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2); PROCEDURE ORGANIZA_WHERE(P_NM_OWNER IN VARCHAR2, P_CD_TABELA_ORACLE IN VARCHAR2, P_DS_CLAUSULA IN OUT VARCHAR2 ); PROCEDURE RECRIA_WHERE(P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG P_NM_OWNER_DST P_CD_TABELA_ORACLE_ORG P_NM_CONSTRAINT P_DS_CLAUSULA PROCEDURE GRAVA_LOG(P_DS_INSERT P_CD_TABELA_ORACLE P_CD_INSTANCE_ORG P_CD_INSTANCE_DST P_NM_OWNER_ORG P_NM_OWNER_DST P_QT_GRAVADOS VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2); VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, VARCHAR2, NUMBER); END IADG2001; / CREATE OR REPLACE PACKAGE BODY IADG2001 IS PROCEDURE VALORES CONTROLE(P_CD_INSTANCE_ORG P_CD_INSTANCE_DST VARCHAR2, VARCHAR2, --> INSTANCIA QUE SERA BUSCADO OS --> INSTANCIA QUE SERA GRAVADO OS VALORES P_NM_OWNER_ORG P_NM_OWNER_DST P_CD_TABELA_ORACLE_ORG VALORES A SEREM GRAVADOS P_CD_TABELA_ORACLE_DST P_DS_CLAUSULA DE GRAVACAO IS DS_SELECT DS_INSERT VARCHAR2(4000); VARCHAR2(4000); CD_INSTANCE_ORG CD_INSTANCE_DST NM_OWNER_ORG NM_OWNER_DST CD_TABELA_ORACLE_ORG CD_TABELA_ORACLE_DST DS_CLAUSULA VARCHAR2(050); VARCHAR2(050); VARCHAR2(050); VARCHAR2(050); VARCHAR2(500); VARCHAR2(050); VARCHAR2(4000); NR_POS_INICIO NUMBER(05); VARCHAR2, --> OWNER ORIGEM VARCHAR2, --> OWNER DESTINO VARCHAR2, --> TABELA(S) DE ONDE SERA BUSCADO OS VARCHAR2, --> TABELA ONDE SERA GRAVADO OS VALORES VARCHAR2) --> CLAUSULA WHERE UTILIZADA NO SELECT 38 NR_POS_FIM NUMBER(05); NM_CONSTRAINT VARCHAR2(100); W_INDEX EXCEPTION; PRAGMA EXCEPTION_INIT(W_INDEX,-2291); BEGIN DBMS_APPLICATION_INFO.SET_MODULE('',''); DBMS_APPLICATION_INFO.SET_MODULE(MODULE_NAME => ''||'IADG2001'||'', ACTION_NAME => ' '); CD_INSTANCE_ORG CD_INSTANCE_DST NM_OWNER_ORG NM_OWNER_DST CD_TABELA_ORACLE_ORG CD_TABELA_ORACLE_DST DS_CLAUSULA := := := := := := := P_CD_INSTANCE_ORG; P_CD_INSTANCE_DST; P_NM_OWNER_ORG; P_NM_OWNER_DST; P_CD_TABELA_ORACLE_ORG; P_CD_TABELA_ORACLE_DST; P_DS_CLAUSULA; DS_SELECT := 'SELECT DISTINCT '||P_CD_TABELA_ORACLE_DST||'.* FROM ' || CD_TABELA_ORACLE_ORG; ORGANIZA_WHERE(NM_OWNER_ORG, CD_TABELA_ORACLE_DST, DS_CLAUSULA); IF DS_CLAUSULA IS NOT NULL THEN DS_SELECT := DS_SELECT || ' WHERE ' || DS_CLAUSULA; END IF; LOOP BEGIN DS_INSERT := 'INSERT INTO ' || CD_TABELA_ORACLE_DST|| '@'||CD_INSTANCE_DST|| ' ('||DS_SELECT||')'; EXECUTE IMMEDIATE DS_INSERT; GRAVA_LOG(DS_INSERT, CD_TABELA_ORACLE_DST, P_CD_INSTANCE_ORG ,P_CD_INSTANCE_DST ,P_NM_OWNER_ORG ,P_NM_OWNER_DST ,SQL%ROWCOUNT); EXIT; EXCEPTION WHEN W_INDEX THEN NR_POS_INICIO := INSTR(SQLERRM,'CONSTRAINT')+12; NR_POS_FIM := INSTR(SUBSTR(SQLERRM,NR_POS_INICIO,100),'.')-1; -- ACHAR NOME DA CONSTRAINT NR_POS_INICIO := NR_POS_FIM + 1 + NR_POS_INICIO; NR_POS_FIM := INSTR(SUBSTR(SQLERRM,NR_POS_INICIO,100),')')-1; NM_CONSTRAINT := SUBSTR(SQLERRM,NR_POS_INICIO,NR_POS_FIM); RECRIA_WHERE(CD_INSTANCE_ORG, CD_INSTANCE_DST, NM_OWNER_ORG, NM_OWNER_DST, CD_TABELA_ORACLE_ORG, NM_CONSTRAINT, DS_CLAUSULA); WHEN OTHERS THEN ROLLBACK; GRAVA_LOG(DS_INSERT, CD_TABELA_ORACLE_DST, P_CD_INSTANCE_ORG ,P_CD_INSTANCE_DST ,P_NM_OWNER_ORG ,P_NM_OWNER_DST 39 ,0); COMMIT; RAISE_APPLICATION_ERROR(-20100,'ERRO AO INSERIR '|| CD_TABELA_ORACLE_DST || ': '||SQLERRM); END; END LOOP; COMMIT; END; --------------------------------------------------------------- PROCEDURE PARA COLOCAR O ALIAS NA FRENTE DO CAMPO DA TABELA PROCEDURE ORGANIZA_WHERE(P_NM_OWNER IN VARCHAR2, P_CD_TABELA_ORACLE IN VARCHAR2, P_DS_CLAUSULA IN OUT VARCHAR2) IS CURSOR C1 IS SELECT * FROM ALL_TAB_COLUMNS WHERE OWNER = P_NM_OWNER AND TABLE_NAME = P_CD_TABELA_ORACLE; R1 C1%ROWTYPE; NR_POS NUMBER(05); BEGIN OPEN C1; LOOP FETCH C1 INTO R1; EXIT WHEN C1%NOTFOUND; NR_POS := INSTR(UPPER(P_DS_CLAUSULA),R1.COLUMN_NAME); IF NR_POS <> 0 THEN IF SUBSTR(P_DS_CLAUSULA,NR_POS+LENGTH(R1.COLUMN_NAME),1) IN (' ','.',')','*','+','-','/',',') THEN -- VERIFICA SE O CAMPO TEM COMPLEMENTO IF NR_POS <> 1 THEN IF SUBSTR(P_DS_CLAUSULA,NR_POS-1,1) <> '.' THEN P_DS_CLAUSULA := SUBSTR(P_DS_CLAUSULA,1,NR_POS-1)|| P_CD_TABELA_ORACLE ||'.'|| SUBSTR(P_DS_CLAUSULA,NR_POS,LENGTH(P_DS_CLAUSULA)-NR_POS+1); END IF; ELSE P_DS_CLAUSULA := P_CD_TABELA_ORACLE ||'.'|| P_DS_CLAUSULA; END IF; END IF; END IF; END LOOP; CLOSE C1; COMMIT; END; --------------------------------------------------------------- RECRIAR CLAUSULA WHERE E CHAMAR PROGRAMA IADG2001 NOVAMENTE PROCEDURE RECRIA_WHERE(P_CD_INSTANCE_ORG VARCHAR2, P_CD_INSTANCE_DST VARCHAR2, P_NM_OWNER_ORG VARCHAR2, P_NM_OWNER_DST VARCHAR2, P_CD_TABELA_ORACLE_ORG VARCHAR2, P_NM_CONSTRAINT VARCHAR2, P_DS_CLAUSULA VARCHAR2) IS TYPE CUR_COLUNA IS REF CURSOR; C1 CUR_COLUNA; COMANDO_SQL COMANDO_SQL_2 VARCHAR2(1000); VARCHAR2(1000); NM_TABELA_ORACLE_FK NM_CAMPO_FK DS_CLAUSULA_TMP DS_CLAUSULA_EXISTS VARCHAR2(30); VARCHAR2(40); VARCHAR2(200); VARCHAR2(200); NM_TABELA_ORACLE DS_CLAUSULA VARCHAR2(500); VARCHAR2(4000); 40 NM_CAMPO DS_ERRO DS_ULTIMO_INSERT W_TABLE_NAME W_COLUMN_NAME W_POSITION BEGIN VARCHAR2(50); VARCHAR2(500); VARCHAR2(1000); VARCHAR2(30); VARCHAR2(50); NUMBER(05); DS_CLAUSULA := P_DS_CLAUSULA; NM_TABELA_ORACLE := P_CD_TABELA_ORACLE_ORG; COMANDO_SQL := 'SELECT ' ' ' FROM ' WHERE ' AND TABLE_NAME, ' || COLUMN_NAME, ' || POSITION ' || ALL_CONS_COLUMNS@'||P_CD_INSTANCE_DST|| OWNER = :1 ' || CONSTRAINT_NAME = :2'; OPEN C1 FOR COMANDO_SQL USING P_NM_OWNER_DST, P_NM_CONSTRAINT; LOOP FETCH C1 INTO W_TABLE_NAME, W_COLUMN_NAME, W_POSITION; EXIT WHEN C1%NOTFOUND; BEGIN COMANDO_SQL_2 := 'SELECT B.COLUMN_NAME , ' || ' B.TABLE_NAME ' || ' FROM ALL_CONS_COLUMNS@'||P_CD_INSTANCE_DST||' B, '|| ' ALL_CONSTRAINTS@' ||P_CD_INSTANCE_DST||' A '|| ' WHERE A.OWNER = :1 '|| ' AND A.CONSTRAINT_NAME = :2 ' || ' AND B.OWNER = A.OWNER ' || ' AND B.CONSTRAINT_NAME = A.R_CONSTRAINT_NAME '|| ' AND B.POSITION = :3'; EXECUTE IMMEDIATE COMANDO_SQL_2 INTO NM_CAMPO_FK, NM_TABELA_ORACLE_FK USING P_NM_OWNER_DST, P_NM_CONSTRAINT, W_POSITION; EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE_APPLICATION_ERROR(-20200,'ERRO NA BUSCA DE CAMPOS DA CONSTRAINT '|| P_NM_CONSTRAINT||': '||SQLERRM); END; DS_CLAUSULA_TMP := W_TABLE_NAME || '.' || W_COLUMN_NAME || ' = ' || NM_TABELA_ORACLE_FK || '.' || NM_CAMPO_FK; IF DS_CLAUSULA IS NOT NULL THEN DS_CLAUSULA := DS_CLAUSULA_TMP || ' AND ' || DS_CLAUSULA; ELSE DS_CLAUSULA := DS_CLAUSULA_TMP; END IF; -- VERIFICAÇÃO DO NOT EXISTS IF DS_CLAUSULA_EXISTS IS NOT NULL THEN DS_CLAUSULA_EXISTS := DS_CLAUSULA_EXISTS || ' AND '; END IF; DS_CLAUSULA_EXISTS := DS_CLAUSULA_EXISTS || NM_TABELA_ORACLE_FK||'.'||NM_CAMPO_FK||' = A.'|| NM_CAMPO_FK; -END LOOP; CLOSE C1; NM_TABELA_ORACLE := NM_TABELA_ORACLE_FK || ', '|| NM_TABELA_ORACLE; DS_CLAUSULA_EXISTS := ' AND NOT EXISTS (SELECT * FROM '|| NM_TABELA_ORACLE_FK||'@'||P_CD_INSTANCE_DST|| ' A WHERE '||DS_CLAUSULA_EXISTS||')'; DS_CLAUSULA := DS_CLAUSULA || DS_CLAUSULA_EXISTS; IADG2001.CONTROLE(P_CD_INSTANCE_ORG, P_CD_INSTANCE_DST, P_NM_OWNER_ORG, P_NM_OWNER_DST, NM_TABELA_ORACLE, 41 NM_TABELA_ORACLE_FK, DS_CLAUSULA); END; PROCEDURE GRAVA_LOG(P_DS_INSERT VARCHAR2, P_CD_TABELA_ORACLE VARCHAR2, P_CD_INSTANCE_ORG VARCHAR2, P_CD_INSTANCE_DST VARCHAR2, P_NM_OWNER_ORG VARCHAR2, P_NM_OWNER_DST VARCHAR2, P_QT_GRAVADOS NUMBER) IS BEGIN INSERT INTO LOG_COPIA_TABELA (CD_TABELA_ORACLE ,CD_USUARIO ,DT_COPIA_TABELA ,DS_CLAUSULA_WHERE ,CD_INSTANCE_ORIGEM ,CD_INSTANCE_DESTINO ,NM_OWNER_ORIGEM ,NM_OWNER_DESTINO ,QT_REGISTROS_COPIADOS) VALUES (P_CD_TABELA_ORACLE ,USER ,SYSDATE ,P_DS_INSERT ,P_CD_INSTANCE_ORG ,P_CD_INSTANCE_DST ,P_NM_OWNER_ORG ,P_NM_OWNER_DST ,P_QT_GRAVADOS); EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20300,'ERRO AO INSERIR LOG: '||SQLERRM); END; END IADG2001; 42 REFERÊNCIAS BIBLIOGRÁFICAS AULT, Michael R. Oracle 7 - Adminitração & Gerenciamento. Rio de Janeiro: Infobook, 1995. DATE, C. J. Guia para o padrão SQL. Rio de Janeiro: Campus, 1989. HERBERT, Juliana Silva e PRICE, Ana Maria de Alencar. Estratégia de geração de dados de teste baseada na análise simbólica e dinâmica do programa. Fortaleza : XI SBES – Simpósio Brasileiro de Engenharia de Software. Universidade Federal do Ceara, 1997. HETZEL, William. Guia Completo ao Teste de Software. Rio de Janeiro: Campus, 1987. LOWELL, Jay Arthur. Produtividade do programador – um guia para gerentes, analistas e programadores. Rio de Janeiro: Campus, 1985. MORAIS, Rinaldo de Oliveira. Oracle 7 Server – Conceitos Básicos. São Paulo: Érica, 1995. ORACLE CORPORATION. Oracle 7 – Concepts Manual. Estados Unidos da América, 1992. ORACLE CORPORATION. ch1.htm. Oracle8 SQL reference - release 8.0. 1997. Arquivo.(15,9 kbytes). CD-Rom. Quadralay WebWorks Publisher 3.5.0. PRESSMAN, Roger S. Engenharia de software. São Paulo: Makron Books, 1995. RAMALHO, José Antônio. Oracle 8i. São Paulo: Berkeley Brasil, 1999.