terça-feira, 11 de dezembro de 2018

Erro EDBClient: At end of table

Lidando com minhas tarefas normais de programação, tive que dar manutenção em um programa Delphi. O trabalho era meio que uma ajuda a um outro programador, que estava tentando compilar um aplicativo feito em Delphi 7 (antigo, hein!).
Ao tentar compilar o código fonte, tudo funcionava... no entanto, em determinado momento, acessei a parte da aplicação que estava levantando erro.
Ele tinha usado uma estrutura mestre-detalhe bem ao estilo Delphi, com datasets aninhados, até ai, tudo bem. Eu já usei esse recurso com uma estrutura de duas tabelas - uma mestra e outra filha, mas ele no entanto expandiu um pouco o conceito e usava uma estrutura com três tabelas: uma mestra, uma filha e uma neta (filha da filha). O problema era que se levantava erro ao incluir um registro na tabela neta.

Erro EDBClient: At end of table


Caracas, que droga estava acontecendo ai?
Eu sabia sobre erros desse tipo, ocorridos usando cursores em PL/SQL ou T-SQL, agora em Delphi, usando componentes TClientDataSet? Era estranho. Mas foi muito simples, resolver o problema. Aliás, o problema ocorria por algo muito simples, a solução no caso dele é que não foi nada simples pois envolveu uma mudança estrutural do código fonte.
Esse erro acontecia porque havia a inclusão de registro na tabela neta, sem que houvesse um registro mestre na tabela filha. Simples, né?! E de certa forma bem lógico, se você pensar a respeito: como pode haver netos, sem haver pelo menos um filho?

Pela ajuda, ganhei cem contos, e adicionei mais um conhecimento ao meu arsenal...


NICE PROGRAMMING...

sábado, 12 de março de 2016

Fechando recursos automaticamente em Java

Um recurso útil adicionado ao Java a partir do JDK 7 é o recurso try-with-resources, também conhecido como gerenciamento automático de recursos. Antes da adição deste recurso, para se fechar um arquivo ou algum outro tipo de recurso, usava-se o bloco finally com chamadas explícitas ao método close() das classes de fluxo. Abaixo, segue um código que abre um arquivo e fecha-o usando a metodologia "antiga" (não se esqueça de adicionar import java.io.*;):

FileInputStream fs = null;
try
{
  fs = new FileInputStream("C:\Teste.java");
  do
  {
    i = fs.read();
    if (i != -1)
      System.out.print((char) i);
  } while (i != -1);
}
catch (IOException ex) { 
  System.out.println("Erro de I/O: " + ex);
}
// Esta instrução garante que o arquivo será fechado
finally
  try
  {
    if (fs != null) fs.close();
  }
  catch (IOException ex) {
    System.out.println("Erro ao fechar o arquivo."); 
  }
}

Agora vamos usar o recurso try-with-resources para executar automaticamente o fechamento do recurso (não se esqueça de adicionar import java.io.*;):

try (FileInputStream fs = new FileInputStream("C:\Teste.java"))
{
  do  {
    i = fs.read();
    if (i != -1)
      System.out.print((char) i);
  } while (i != -1);
}
catch (IOException ex) {
  System.out.println("Erro de I/O: " + ex);
}


A diferença entre o tamanho dos códigos é clara. A forma geral de try-with-resources é:
try (especificação do recurso)
{
  // usa o recurso
}

Agora, as regras para se usar try-with-resources:

  • Só pode ser usado com recursos que implementam a interface AutoCloseable (definida em java.lang);
  • O recurso declarado na instrução try é implicitamente final, isto é, ele não pode ser redefinido depois de criado;
  • Instruções catch e finally podem ser usadas em conjunto com try-with-resources;
  • A variável de recurso é local ao bloco try;
  • Mais de um recurso pode ser inicializado na instrução try, bastando-se separá-las por ";" - ponto e vírgula.

Todas as classes de fluxo em Java, implementam as duas interfaces: AutoCloseable e Closeable (definida em java.io), logo, fornecem o método close().
Outra coisa importante a ser mencionada: exceções não são perdidas com try-with-resources. As exceções são suprimidas e podem ser obtidas utilizando-se o método getSupressed() de Throwable.

Se você estiver trabalhando com o JDK 7 ou superior, vai querer utilizar este novo recurso da linguagem!

segunda-feira, 17 de fevereiro de 2014

Criando um controle data-aware

Depois de algum tempo, longe do blog, eu volto. Mas agora resolvi abordar um assunto que poucos programadores Delphi conhecem: a classe TDataLink. Vou explicar rapidamente o que esta classe faz.
A conexão entre um datasource e um controle data-aware (consciente de dados) é feita através de um data link, um descendente da classe TDataLink. O controle data-aware deve criar e gerenciar o data link. Logo, para criar um controle que tem consciência de dados, você deve adicionar um data link ao seu componente e manipular algumas propriedades deste data link interno.
O dataset utiliza o data link para notificar o controle data-aware de qual algo aconteceu, como por exemplo, a conexão ficou ativa, os dados mudaram, etc. O controle data-aware utiliza o data link para exigir dados do dataset ou para mudá-los e notificar o dataset que tal mudança ocorreu.
Falando assim até parece fácil, né? Mas na vida real as coisas são um pouco mais complicadas porque você só pode ter um data link por controle data-aware, no entanto você pode ligar vários datasources à um dataset e você geralmente liga vários controles data-aware à um datasource, ....
A classe TDataLink é declarada na unit DB (Delphi 7), Data.DB no XE em diante. Esta classe tem alguns métodos que atuam quase como eventos e são tipo "canivete suíço" e que podem ser redefinidos em classes descendentes para interceptar operações do usuário ou então eventos do datasource. Como de praxe, vamos dar uma olhada na definição da classe:

TDataLink = class(TPersistent)

protected

    procedure ActiveChanged; virtual;

    procedure CheckBrowseMode; virtual;

    procedure DataEvent(Event: TDataEvent; Info: NativeInt); virtual;

    procedure DataSetChanged; virtual;

    procedure DataSetScrolled(Distance: Integer); virtual;

    procedure EditingChanged; virtual;

    procedure FocusControl(Field: TFieldRef); virtual;

    function GetActiveRecord: Integer; virtual;

    function GetBOF: Boolean; virtual;

    function GetBufferCount: Integer; virtual;

    function GetEOF: Boolean; virtual;

    function GetRecordCount: Integer; virtual;

    procedure LayoutChanged; virtual;

    function MoveBy(Distance: Integer): Integer; virtual;

    procedure RecordChanged(Field: TField); virtual;

    procedure SetActiveRecord(Value: Integer); virtual;

    procedure SetBufferCount(Value: Integer); virtual;

    procedure UpdateData; virtual;

    property VisualControl: Boolean read FVisualControl write FVisualControl;

Agora vejamos a enumeração TDataEvent:

TDataEvent = (deFieldChange, deRecordChange, deDataSetChange,
    deDataSetScroll, deLayoutChange, deUpdateRecord, deUpdateState,
    deCheckBrowseMode, dePropertyChange, deFieldListChange,
    deFocusControl, deParentScroll, deConnectChange, deReconcileError,
    deDisabledStateChange);

Esta enumeração na verdade lista todos os eventos que são manipulados pelo método DataEvent da classe TDataLink. Este método (privado no Delphi 7 e protegido no XE), funciona como um procedimento de janela para o DataSource. O datasource chama seu método NotifyDataLinks para transferir o evento para cada data link associado à ele, só então ele dispara seus método OnDataChange e OnUpdateData. Interessante, não?
Isto é importante: RARAMENTE você vai usar a classe TDataLink diretamente. Sempre que precisar, é melhor derivar uma nova classe e é o que é feito com os controles data-aware do Delphi (menos o DBGrid). Controles tais como DBEdit, DBCombo, etc... eles usam uma classe derivada de TDataLink: TFieldDataLink. Esta classe é muito útil para controles que necessitem trabalhar com um registro por vez (daí o motivo de DBGrid não utilizá-la).

sexta-feira, 30 de agosto de 2013

Caracteres de Controle

Rápido estudo sobre caracteres de controle


Quantas vezes você viu o símbolo ^ em Delphi e não soube do que se tratava?
Mas o que este símbolo representado pelo caractere 033 em C/C++ significa?

Seguindo a abordagem de estudo rápido e direto, explicarei o que são Caracteres de Controle.

O padrão atualmente utilizado é o ANSI X3.64.
Lembre-se bem: ANSI X3.64

O padrão ANSI X3.64 é baseado no terminal VT-102
O VT-102 era um terminal com um teclado de 102 teclas, algo
soa familiar? (teclados ABNT-2 padrão 102 teclas)

Qualquer caractere de controle é precedido pela tecla ESC,
daí o motivo de serem também chamados de caracteres de ESCape.

O caractere de escape é representado por um circunflexo ^ em
Delphi, ou o caractere 033 (octal) em C/C++, 27 em decimal (#27).

A notação para mostrar um caractere de escape é ESC[

Não se esqueça a notação para mostrar um caractere de escape é: ESC[

A tecla de escape subtrai 64 unidades do código de caractere enviado ao PC.
Assim ^G = 7.
Lembre-se: a letra G é o código 71 na tabela ASCII, logo:
^71 => 71 - 64 = 7.

Em unicode o código de controle deve ser precedido de \u.

Principais códigos de controle encontrados em programação:

^J = (Line feed)
^L = (Form feed)
^M = (ENTER/RETURN)
^G = (BELL)

Perguntas:

Qual o padrão de codificação de caracteres atualmente utilizado?
R. ANSI X3.64

Este padrão foi baseado em que outro antigo padrão?
R. Foi baseado no VT-102Todo caractere de controle é precedido por qual caractere?
R. É precedido pelo caractere de Escape

Qual a notação utilizada para indicar um caractere de controle?
R. A notação utilizada é ESC[ + código desejado

A representação do caractere de escape em programação é feita de que forma?
R. Em Delphi por meio do circunflexo ^ em C/C++ por meio do caractere octal 033

Quantas unidades o ESCape subtrai do código de caractere enviado ao SO?
R. O escape subtrai 64 unidades do código enviado.

Espero ter ajudado e boa programação!