Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

...

O programa deve ter variáveis para todas as colunas que desejar fazer entrada de dados na tela. Neste caso podemos declarar facilmente um RECORD que contenha todas as colunas da tabela LIVROS.

 

DATABASE livros 

   DEFINE mr_livros LIKE livros.*
MAIN
    CALL menu()
END MAIN 

FUNCTION menu()
   OPEN WINDOW w_livros AT 2,2 WITH FORM "livros"
END FUNCTION 

...

A função consultar, recebe o número do livro que se pretende procurar, procura-o no banco de dados, e mostra na entrada de dados todos os dados correspondentes. Note que o número do livro é introduzido na form.

 

FUNCTION consultar()
  CLEAR FORM 

  INPUT BY NAME mr_livros.numero 

  SELECT *
    INTO mr_livros.*
    FROM livros
    WHERE numero = mr_livros.numero 

IF status != 0 THEN
     ERROR "Livro não cadastrado"
  ELSE
     DISPLAY BY NAME mr_livros.*
  END IF
END FUNCTION 

Função que procura um livro com determinado número

A instrução CLEAR FORM serve para limpar todos os campos existentes na form corrente. No exemplo acima, se a busca for bem sucedida é feito um display de todas as colunas da tabela.

...

Esta função aceita os valores sem inicializar variáveis e sem limpar os campos da form, validando a existência de um livro válido.

 

 

 FUNCTION

FUNCTION modificar()
  IF mr_livros.numero IS NULL THEN
     ERROR "Nao ha nenhum livro para mudar"
  ELSE
     INPUT BY NAME mr_livros.* WITHOUT DEFAULTS

 


     WHENEVER ERROR CONTINUE
     UPDATE livros
        SET livros.* = mr_livros.*
      WHERE livros.numero = mr_livros.numero
     WHENEVER ERROR STOP
     IF sqlca.sqlcode <> 0 THEN
        ERROR “Erro na modificação – “,sqlca.sqlcode
     ELSE
        ERROR “Livro modificado.”
     END IF
  END IF

 END

END FUNCTION

 

Modificação de um livro

É feito um teste da variável mr_livros.numero para garantir que está preenchida com um número de livro existente.

...

Esta função exclui do banco de dados o livro correspondente aos dados presentes na entrada de dados.

 

 

 

 FUNCTION

FUNCTION excluir()
  IF mr_livros.numero IS NULL THEN
     ERROR "Não há nenhum livro para excluir"
  ELSE
     WHENEVER ERROR CONTINUE
     DELETE FROM livros
      WHERE numero = mr_livros.numero
     WHENEVER ERROR

STOP 

STOP 

     IF sqlca.sqlcode <> 0 THEN
        ERROR "Erro na exclusão - ",sqlca.sqlcode
     ELSE
        INITIALIZE mr_livros.* TO NULL
        CLEAR FORM
        ERROR "Livro excluído"
     END IF
  END IF

 END

END FUNCTION

 

Exclusão de um livro

O teste da existência de livro corrente é feito da mesma forma que na função modificar.

As instruções INITIALIZE e CLEAR FORM aparecem para garantir a não existência do livro corrente após a sua exclusão quando bem sucedida.

 

10    Gestão de janelas – parte 2

...

A tecla de atalho para confirmação de uma instrução de entrada de dados (INPUT, DISPLAY ARRAY, INPUT ARRAY, PROMPT) antes que esta seja concluída normalmente, ou seja, podendo ser pressionada a qualquer momento, é a tecla ESC. A tecla ENTER é assumida como padrão para navegação entre campos e no caso do cursor estar posicionado no último campo pertencente a entrada de dados atual e o usuário pressionar ENTER, automaticamente a entrada de dados terá seus dados confirmados. Neste caso a variável INT_FLAG terá seu valor inalterado. 

10.3   Exercício – novo campo e tratamento de tecla de interrupção

...

A form tem que possuir um novo campo onde será visualizado o nome da editora na seção SCREEN, assim:

 

 

 

 EditoraEditora: [f009 ] [f9d                        ] 

 Novo campo para visualização do nome de editora

Precisa também introduzir os atributos para este campo na seção ATTRIBUTES:

 

 

 

 f9d f9d = FORMONLY.nome_editora TYPE LIKE editoras.nome, NOENTRY; 

  Atributos do novo campo

O atributo FORMONLY identifica um campo com um nome permitindo dizer qual o tipo para esse campo. Neste caso definimos o tipo com LIKE , no entanto é possível definir o tipo através dos tipos elementares.

 

 

 

 campo campo = FORMONLY.nome_do_campo [TYPE [tipo_de_dados | LIKE tabela.coluna]]
                                [NOT NULL][,lista_de_atributos] 

 Definição genérica do atributo FORMONLY

Utilizou-se também o atributo NOENTRY para forçar a instrução INPUT a não editar este campo, ou seja, para o comando INPUT este campo será somente para visualização.

O programa 4GL ainda não sabe como fazer a validação do código de editor. Para conseguir realizar esta função, utiliza-se a cláusula AFTER FIELD, faz-se uma consulta na tabela de editores e apresenta-se o nome do editor encontrado na tela.

 

 

 

 DEFINE DEFINE l_nome_editora LIKE editoras.nome; 
 INPUT BY NAME mr_livros.* 

 AFTER FIELD editora
    INITIALIZE l_nome_editora TO NULL
    WHENEVER ERROR CONTINUE
    SELECT nome
      INTO l_nome_editora
      FROM editoras
     WHERE codigo = mr_livros.editora
    WHENEVER ERROR STOP
    IF sqlca.sqlcode = NOTFOUND THEN
       ERROR "Editora não cadastrada."
       NEXT FIELD edicaoedição
    ELSE
       DISPLAY l_nome_editora TO nome _ editora
    END IF

 END INPUT

 

 

END INPUT 

Alteração das instruções INPUT para efetuar as validações

Quando a variável SQLCA.SQLCODE indica a constante NOTFOUND, quer dizer que não foi encontrada a editora cujo código foi informado pelo usuário, sendo que neste caso é apresentada uma mensagem de erro e o cursor é retornado novamente para informar o mesmo campo até que o usuário informe um código de editora válido.

Para tratamento das teclas de interrupção ou confirmação, usando a variável INT_FLAG, de forma que a inclusão, modificação, consulta ou exclusão somente sejam efetivadas caso esta variável esteja com seu valor igual a 0 (FALSE), ou seja, se o usuário não pressionar a tecla de interrupção, deve-se implementar da seguinte forma:

 

 

 

 DEFINE DEFINE l_nome_editora LIKE editora.nome; 

 LET int_flag = 0
   INPUT BY NAME mr_livros.*

 

 AFTER AFTER FIELD edicaoedição
    INITIALIZE l_nome_editora TO NULL
    WHENEVER ERROR CONTINUE
    SELECT nome
      INTO l_nome_editora
      FROM editoras
     WHERE codigo = mr_livros.editora
    WHENEVER ERROR STOP
    IF sqlca.sqlcode = NOTFOUND THEN
       ERROR "Editora não cadastrada."
       NEXT FIELD editora
    ELSE
       DISPLAY l_nome_editora TO nome _ editora
    END IFIF 

 

 AFTER AFTER INPUT
    IF int_flag = 0 THEN
       #Consistências da entrada de dados
    END IF

 END INPUT

 

END INPUT 

IF  IF int_flag <> 0 THEN
 
    ERROR “Inclusão cancelada.”
 ELSEELSE
    #Realizar a inclusão do livro(INSERT)

 END IF

 

 

END IF 

Alteração das instruções INPUT para efetuar as validações

 

11    Interação do 4GL com o banco de dados

...

Uma instrução SELECT pode dar origem a mais de uma linha da dados (depende da cláusula WHERE).

 

 

 

  errselecterrselect.4gl
 DATABASE
DATABASE livros

 

MAIN MAIN
   DEFINE l_numero LIKE livros.numero,
          l_nome LIKE livros.nome,
          l          l_edicao LIKE livros.edicao edicao 

   SELECT numero, nome, edicaoedição
     INTO l_numero, l_nome, l_edicao
     FROM livros

 END MAIN

 

END MAIN 

$  $ fglpc errselect.4gl
 $ $ fglgo errselect.4go
 Program Program stopped at "errselect.4gl" line number 9.
 SQL SQL statement error number -284.
 A A subquery has returned not exactly one row. 

 Leitura com instrução SELECT que dá origem a mais do que uma linha.

Se consultar o manual de 4GL verificará que o erro aconteceu porque uma busca não devolveu exatamente uma linha.

...

Esta ação é realizada com o auxilio da instrução DECLARE associada a  uma instrução SELECT.

...

 

 DECLARE cq_livros CURSOR FOR
  SELECT numero, nome, edicaoedição
    FROM livros
       WHERE numero < 5

 

 

...

  

Abrir o cursor

Esta ação é realizada com a instrução OPEN, que provoca a execução da instrução SELECT associada ao cursor e a busca correspondente na base de dados é realizada nessa altura. A partir desta instrução até o cursor ser fechado fica associado um conjunto de linhas (conjunto ativo) que corresponde ao resultado da instrução SELECT. O cursor fica posicionado imediatamente antes da primeira linha.

 

...

 

 OPEN cq_livroslivros 

 

   

 

Acessar uma ou mais vezes ao cursor

Os acessos são feitos com o auxilio da instrução FETCH que avança a linha corrente para a linha seguinte e armazena os dados retornados desta linha nas variáveis definidas na cláusula INTO. Se o cursor estiver posicionado na ultima linha, a variável sqlca.sqlcode será atualizada com o valor NOTFOUND (ou código 100).

 

 

 

 WHILE WHILE 1
    FETCH cq_livros INTO numero, nome, edicao;
    IF sqlca.sqlcode != 0 THEN
       EXIT WHILE
    END IF
    DISPLAY numero, nome, editora
 END WHILE

 

 

WHILE 

 

Fechar o cursor

Ação realizada pela instrução CLOSE que faz a colocação do cursor em estado fechado.

Não é possível invocar uma outra instrução sobre o cursor que não esteja aberto. O cursor por estar fechado não deixa de ter uma instrução SELECT associada, que ao ser invocado pela instrução OPEN é executada novamente a instrução SELECT associado ao cursor.

 

...

 

 CLOSE cq_livros livros 

 

Um cursor pode também ser fechado automaticamente através de uma instrução de fim de transação (COMMIT WORK ou ROLLBACK WORK), já que uma das ações destas instruções é fechar todos os cursores que se encontrarem abertos no momento. Mas isto somente ocorre se na instrução de definição do cursor (DECLARE) tiver sido omitido o atributo WITH HOLD.

Apresenta-se um exemplo de acesso a uma tabela do banco de dados por intermédio de um cursor. 

 

 

  cursor1.4gl

 DATABASE DATABASE livros

 

MAIN MAIN
   DEFINE numero LIKE livros.numero,
          nome   LIKE livros.nome,
          aux    SMALLINT SMALLINT 

   DECLARE cq_livros CURSOR WITH HOLD FOR
          SELECT numero, @nome
      FROM livros
     WHERE numero < 5

 

   LET aux = 1 

   OPEN cq_livros

 

   WHILE aux = 1
      FETCH cq_livros INTO numero, nome
      IF sqlca.sqlcode != 0 THEN
         EXIT WHILE
      END IF

 

      DISPLAY numero, nome
   END WHILEWHILE 

 

   CLOSE cq_livros
 END END MAIN

 

 $ fglpc cursor1.4gl
 $ fglgo cursor1.4go
 1Artificial 1Artificial Inteligence Using C
 2C 2C Power User's Guide
 3Microprocessors3Microprocessors
 4The 4The Complete ReferenceReference 

 

 

Leitura dos livros com número < 5 usando um cursor

Quando se declara um cursor, pode-se definir a intenção de alterar os valores de algumas coluna das linhas lidas. Essa intenção define-se através da declaração "FOR UPDATE" após a instrução SELECT do cursor, como na figura a seguir.

 

...

 

 DECLARE nome_cursor CURSOR FOR
  SELECT ...
 FOR UPDATE 

 

Definição genérica da declaração de um cursor FOR UPDATE

A alteração faz-se da seguinte forma: 

  1. Declarar um cursor "FOR UPDATE" 

 

 

 DECLARE cq_livros CURSOR FOR
  SELECT   SELECT numero, nome, edicaoedição
    FROM livros
   WHERE numero < 5
 FOR UPDATE

 

 

 

  1. Abrir o cursor da forma descrita anteriormente.

 

...

 

 OPEN cq_livros livros 

 

 

  1. Posicionar o cursor na linha que se quer alterar:

 

 

 

 FETCH cq_livros INTO ... 

   

 

Invocar a instrução UPDATE para alteração das colunas definidas na cláusula SET do registro corrente do cursor utilizando a cláusula CURRENT OF para indicar a atualização do registro correspondente a linha corrente do cursor. 

 

UPDATE 

 UPDATE

    SET <colunas a modificar>
    WHERE CURRENT OF cq_livroslivros 

 

   

 

Depois da instrução UPDATE o cursor continua posicionado na linha corrente.

 

...

 

  cursupd.4gl

 DATABASE DATABASE livros 
 MAIN
   DEFINE numero LIKE livros.numero,
         nome   LIKE livros.nome,
         edicao LIKE livros.edicao,
         ans    CHAR(1),
         aux    SMALLINT SMALLINT 

   DECLARE cq_livros CURSOR FOR
    SELECT numero, nome, edicaoedição
      FROM livros
     WHERE numero < 5
   FOR UPDATE OF edicaoedicao 

 

   OPEN cq_livros

 

   WHILE aux = 1
      FETCH cq_livros INTO numero, nome, edicaoedição

 

      IF edicao IS NULL THEN
         PROMPT nome CLIPPED,"-Qual a editora para este livro: "
            FOR edicaoedição

 

         UPDATE livros
            SET edicao = edicaoedição
          WHERE CURRENT OF cq_livros livros 

         PROMPT "Quer alterar mais livros (s/n):"
                               FOR CHAR ans
         IF ans != "s" THEN
            EXIT WHILE
         END IF
      END IF IF 

      IF sqlca.sqlcode != 0 THEN
         EXIT WHILE
      END IF

   END WHILE

 END MAIN 

 $ fglpc cursupd.4gl
 $ fglgo cursupd.4go

 Artificial Artificial Inteligence using C

 -Qual a editora para este livro: BERTR
 Quer Quer alterar mais livros (s/n): n
 $ 

 

Cursor para alteração ( FOR UPDATE )

11.1.1    Cursores com atributo SCROLL

...

Para evitar estes problemas usa-se os cursores com SCROLL (ou SCROLL cursor). O seu funcionamento é idêntico a um cursor normal sendo declarado, aberto, lido e fechado (DECLARE, OPEN, FETCH e CLOSE). A principal diferença entre os dois tipos de cursores está no fato dos cursores com SCROLL não poderem ser utilizados com a cláusula FOR UPDATE e na instrução FETCH o SCROLL cursor permite utilizar algumas palavras chaves que definem a forma de acesso desejada aos registros ativos num cursor aberto.

As formas de acesso são: 

 

FETCH CURRENT

Registro corrente

FETCH PREVIOUS

Registro anterior

FETCH NEXT

Registro seguinte

FETCH FIRST

Primeiro registro

FETCH LAST

Último registro

FETCH RELATIVE

Registro N a partir do registro corrente, respeitando o conjunto ativo do cursor. Quando N for positivo, indica N registros após o registro corrente e quando N for negativo, indica N registros antes do registro corrente

FETCH ABSOLUTE

Elemento N do conjunto de registros ativo do cursor

 

...

  1. Declarar um cursor associando-o a uma instrução INSERT.

 

 

 

 DECLARE DECLARE cq_livros CURSOR FOR
  INSERT INTO livros
         (numero, nome, edicao)
  VALUES (l_numero, l_nome, l_edicao) 

 

...

  

  1. Abrir o cursor. Identico a um cursor normal.

 

 

 

 OPEN OPEN cq_livros

 

 

...

livros 

  

  1. Ler os dados para dentro de determinada variáveis (INPUT, LET).

...

  1. Escrever as variáveis no buffer com o auxilio da instrução PUT.

 

 

 

 

 PUT PUT cq_livros livros 

 

  1. Fechar o cursor. 

 

 

 CLOSE CLOSE cq_livros livros 

 

 

 

O 4GL força a escrita do buffer no banco de dados sempre que o limite do buffer seja atingido ou o cursor seja fechado.

...

  1. Colocação de uma string com as instruções SQL desejadas dentro de uma variável tipo CHAR.

 

 

 

 LET LET l_sql_delete = “DELETE FROM livros WHERE numero = 10”10” 

 

 

Instrução PREPARE

  1. Definição de um identificador de instrução a partir da string que contém a instrução. Esta tarefa e executada pela instrução PREPARE. Há validação da sintaxe da instrução contido na string.

 

 

 

 PREPARE PREPARE var_delete FROM l_sql_delete delete 

 

Instrução PREPARE

  1. Execução da instrução através da instrução EXECUTE.

 

 

 

 EXECUTE EXECUTE var_deletedelete 

 

 

Instrução EXECUTE

As instruções SQL enviadas ao PREPARE em tempo de execução não podem fazer referência a variáveis do 4GL, visto que nesta fase o programa já foi compilado.

...

  1. Preparar a instrução com PREPARE.

 

...

 

 PREPARE id_expressão FROM expressão_charchar  

  

 

 

  1. Declarar o cursor para essa instrução.

 

 

 

 DECLARE DECLARE nome_cursor CURSOR FOR id_expressãoexpressão 

 

   

 

  1. Usar o cursor da mesma forma que se usa com instruções definidas antes da compilação. Se for usado o caracter '?' para substituir variáveis, é necessário usar a cláusula USING na abertura do cursor. 

 

 

 OPEN OPEN nome_cursor USING var1 var2 ... varn

 

 

 

varn 

11.3   Exercício – Otimização da função de consulta

A função de consulta foi inicialmente implementada de forma que utilizasse o comando INPUT seguido de um comando SELECT para pesquisa do registro no banco de dados.

...

A instrução CONSTRUCT edita a form corrente, e a partir dos dados que o usuário informa nas diversas colunas, constrói uma parte de uma instrução SELECT numa variável tipo CHAR que posteriormente pode ser preparada e executada. A variável CHAR preparada pela instrução CONSTRUCT pode ser utilizada como a cláusula WHERE de um SELECT, sem conter a palavra  chave WHERE.

 

...

 

 CONSTRUCT {BY NAME variavel_char ON lista_de_colunas
           |variavel_char ON lista_de_colunas
      FROM {lista_de_campos|record_tela[[n]].*}{[,...]} 

[{BEFORE CONSTRUCT
 |AFTER CONSTRUCT
 |BEFORE FIELD sublista_de_campos
 |AFTER {FIELD sublista_de_campos|INPUT}
 |ON KEY(lista_de_teclas)}
    instrução
    ...
    [NEXT FIELD nome_do_campo]
    ...
    [EXIT CONSTRUCT]
    ...
    ...
 END CONSTRUCT 

 

Definição genérica da instrução CONSTRUCT

Esta instrução em relação à cláusula BY NAME, funciona da mesma forma como na instrução INPUT, ou seja, se for utilizada não é necessário indicar o nome das variáveis internas relacionadas às forms a que se pretendem editar.

...

Para tratar este tipo de tela o 4GL possui as instruções DISPLAY ARRAY e INPUT ARRAY, associadas a novas definições nas forms.

 

 

 

 DISPLAY ARRAY array_de_records TO array_da_tela.*
         [ATTRIBUTE(lista_de atributos)]
 {ON KEY (lista_de_teclas)
     instrução
     ...
     [EXIT DISPLAY]
 ...
 END DISPLAY

 

 

Definição genérica da instrução DISPLAY ARRAY

A instrução DISPLAY ARRAY envia um array de records do programa para a tela, por intermédio de um array de linhas na tela.

...