As funções básicas de acesso a dados do AdvPL (Acesso a Banco de Dados - Funções genéricas) encapsulam as tabelas de dados das RRDs (Drivers e RDDs) permitindo dois modos de acesso ( exclusivo / compartilhado ), e um mecanismo de bloqueio total e parcial para atualização de registros em tabelas abertas em modo compartilhado por mais de um processo. Uma tabela de dados deve ser aberta pela aplicação para ser possível ler, incluir e alterar dados. A abertura de qualquer tabela deve especificar um ALIAS – ou "apelido" : Trata-se de uma string que identifica a tabela aberta dentro do processo atual. Através do ALIAS da tabela, podemos endereçar as colunas da tabela de modo direto ( ALIAS->CAMPO ) para leitura e atribuição de valores, e/ou chamar funcões que devem atuar neste ALIAS, usando a sintaxe ALIAS->(FUNCAO()). Uma função chamada sem informar o ALIAS atua sobre a área de trabalho atual – que corresponde ao último ALIAS aberto, ou ao último ALIAS selecionado através da função DBSelectArea. Como podemos manter no mesmo processo múltiplas tabelas abertas em múltiplos drivers ou RDDs, cada abertura de tabela exige o nome de um ALIAS para esta tabela, para ser possível referenciá-la. A criação, abertura e fechamento de uma tabela são feitas através das funções abaixo:

As tabelas são abertas em um modo de navegação ISAM, onde o alias aberto está sempre posicionado em um determinado registro da tabela ( chamado de registro corrente ), ou em EOF() – final de arquivo , registro em branco – e é permitido criar e abrir um ou mais índices, e é possível posicionar em qualquer registro da tabela usando as funções de navegação de dados do ISAM: 

Existem funções auxiliares para determinar o estado ou registro atual da tabela e o estado da última operação executada, a seguir:

Para realizar operações de inclusão, atualização e eliminação de registros, utilizamos as funções a seguir:

A navegação nos dados de uma tabela ISAM estã sujeita a aplicação de filtros de visibilidade lógica. Isto singifica que, após definido um filtro de visualização de dados, a proxima operação de navegação nos dados posicionará no próximo registro da ordem em uso atual que atenda a condição de filtro. Um filtro pode ser qualquer expressão AdvPL que referencie os campos da tabela e retorne .T. (veradeiro) caso o registro deva ser logicamente visivel pela aplicação. As funções e comandos abaixo lidam com filtros:

Exstem ainda funções genéricas que atuam sobre todos os ALIAS abertos no processo atual da aplicação, como por exemplo:

Estrutura da tabela e tipos de campos

O conceito de RDDs parte da premissa que as tabelas de dados devem armazenar valores compativeis com os tipos de variáveis AdvPL. Por isso, ao criarmos uma tabela através da função DBCreate, informamos um array com o nome, tipo , tamanho e numero de casas decimais dos campos que devem compor a estrutura da tabela. Os tipos podem ser "C" caractere, "N" numérico , "D" Data AdvPL, "L" lógico ou booleano, e "M" Memo – tamanho variável. A quantidade e tamanho máximo de campos e índices que podem ser usadas em uma tabela dependem do Driver e/ou RDD utilizados. Alguns drives inclusive exigem que, quando usado campo(s) do tipo "M" memo, estes sejam os últimos campos da estrutura – como é o caso das RDDs CTREE.

Modo de Abertura de tabelas 

A função DbUseArea permite duas configurações de acesso a uma tabela : Modo de compartilhamento e modo de edição. Os modos de compartilhamento podem ser SHARED (compartilhado) ou EXCLUSIVE (excclusivo). Uma tabela aberta no modo compartilhado pode ser aberta em modo compartilhado por outros processos, enquanto uma tabela aberta em modo exclusivo nao pode ser aberta por nenhum outro processo, independente do modo escolhido. Somente é possível abrir uma tabela em modo exclusivo se apenas o seu processo está abrindo a tabela. Somente é possível abrir a tabela em modo compartilhado se nenhum outro processo abriu a tabela em modo exclusivo. Quanto ao modo de edição, é possível abrir uma tabela em modo de edição (default), ou em modo READONLY (somente leitura). Um ALIAS de uma tabela aberta em modo de somente leitura não aceita operações de bloqueio ou alteração de dados. Uma tabela aberta em modo EXCLUSIVE não precisa usar nenhuma função de bloqueio de registro para realizar alterações. 

Ordenação de registros

Uma tabela aberta sem utilizar nenhum índice usa a ordenação do identificador de registro (ou RECNO). Trata-se de um identificador numérico único, sequencial, iniado em 1, que representa a ordem cronológica de inserção de registros. Quando criamos, abrimos ou selecionamos um índice para uso – vide funções DBCreateIndexDBSetIndexDBSetOrder – a ordem de navegação de registros corresponde a ordem binária ascendente da expressão de indice – calculada a partir dos campos informados na chave do índice em uso. Somente podemos usar a função DBSeek() se existe um indice aberto e selecionado para o ALIAS em questão. 

Acesso compartilhado e atualização de registros

Uma tabela aberta em modo compartilhado de edição comporta-se como um cursor dinâmico no Banco de Dados, ordenado pela expressão do índice em uso, com visibilidade lógica de registros total ou limitada por uma expressão de filtro. Uma operação de atualização de dados de um determinado registrro da tabela envolve as etapas de posicionamento no registro, obtenção de um bloqueio exclusivo (ou LOCK de registro), e a atualização dos valores dos campos deste registro endereçando o campo na forma ALIAS->CAMPO e usando o operador de atribuição do AdvPL ( := ) , ou ainda a função FieldPut(). Já a leitura de um valor de um campo de um registro da tabela requer apenas posicionar no registro e obter seu valor usando a expressao ALIAS->CAMPO. Nas operações de leitura do AdvPL não existe a operação de bloqueio para leitura ou bloqueio compartilhado. Qualquer processo pode obter o valor atual armazenado em um registro na base de dados, recuperado pela aplicação no momento do posicionamento do registro, inclusive se um determinado regisrtro possui um bloqueio (lock) para atualizacão. O valor retornado será sempre o último valor atualizado na base de dados. 

Deleção lógica de registros

Por compatiblidade, as RDDs implementadas no AdvPL trabalham com uma implementação diferenciada de eliminar registros. A eliminação de um regitro em particular deve primeiro obter o bloqueio deste regitro, para então ser marcado para deleção através da função DBDelete(). A eliminação física deste registro somente é realizada pelo driver ou RDD quando executado o comando PACK – que exige que a tabela em questão seja aberta em modo exclusivo. Por default qualquer registro marcado para deleção não ]e logicamente visivel para as operações de navegação ISAM – exceto para a função DBgoto(). 

Utilização de Transacionamento 

Alguns drivers ou RDDs, como a "TOPCONN" por exemplo suporta operações com transacionamento. Uma vez iniciada a transação, novos registros e alterações feitas nas tabelas abertas pela RDD somente serão efetivadas na base de dados após a finalização com sucesso (ou COMMIT) da transação. A visibilidade dos dados alterados durante a transação por outro processo depende do nivel de isolamento (DBAccess - Isolation Level) utilizado para o Banco de Dados. A maioria dos bancos de dados, por questões de adequação de comportamento com as aplicações AdvPL usam um nivel de isolamento que permite outros processos ler novos registros e conteúdos de registros alterados dentro de um processo transacionado, mesmo antes da transação ser efetivada (ou comitada) no banco de dados. A RDD TOPCONN permite o controle explicito de transacionamento através da função TCCommit(). O ambiente AdvPL usado por exemplo no ERP Microsiga delimita um bloco transacionado usando os comandos BEGIN TRANSACTION e END TRANSACTION. 

Filtros e Visibilidade logica de registros

Uma tabela aberta em modo ISAM pelo AdvPL está sujeita a um comportamento de visibilidade lógica, onde um filtro pode limitar o escopo de regitros visíveis. Desse modo, as funções de navegação somente vão encontrar ou posicionar em registros logicamente visíveis. Por exemplo, uma determinada tabela utilizando um indice e um filtro, ao executar a função DBGotop(), deve posicionar no primeiro registro visível pelo filtro na ordem atualmente em uso. A função DBSeek() – busca por indice – também respeita a visibilidade lógica de um filtro. Uma busca informando uma expressao parcial – que nao contempla todos os campos do índice — somente vai posicionar em um determinado registro caso ele atenda a condição de filtro. No momento que definimos um filtro para a tabela, o registro atualmente posicionado permanece posicionado. Somente a próxima instrução de navegação vai avaliar o filtro. Por isso, normalmente após aplicarmos um filtro em uma tabela, usamos a função DBGOTOP() para localizar e posicionar no primeiro registro que atenda a condição estabelecida, e podemos percorrer todos os registos atendidos pelo filtro com um loop While !Eof() – DbSkip() – Enddo 

Índices com expressão de filtro 

A criação de índices permite o uso de índices temporários, onde é possíve linformar uma expressão de filtro na criação do índice, para que somente sejam ordenados no índice os registros que atendam a esta condição. Os drivers baseados em implementação ISAM nativa – como DBF e CTREE – criam este índice fisicamente, permitindo que o processo atual que usa o índice criado navegue muito mais rapidamente pelos registros contemplados pelo indice do que simplesmente navegar pela tabela filtrada. A RDD TOPCONN contempla esse comportamento sem criar um indice fisico na base de dados. A função IndRegua() do Framework AdvPL do ERP Microsiga internamente se utiliza deste recurso para permitir criar índices temporários filtrados. 

RDD TOPCONN - Comportamentos diferenciados - Queries

Como a RDD TOPCONN atua sobre tabelas criadas através do DBAccess, existem funções especificas adicionais para esta RDD, que atuam sobre as tabelas em modo ISAM e diretamente no banco de dados envolvido, sendo possivel por exemplo a execução de queries para leitura de dados e execução de instruções SQL repassadas ao Banco de Dados. A abertura de uma Query no AdvPL é encapsulada pelas funções TCGenQry e TcGenQry2, onde o result-set da Query é aberto sob um ALIAS AdvPL, que possui algumas restrições de comporamento: O Alias aberto por uma QUERY é internamente aberto em modo somente letitura  (READ ONLY) e suporta a navegação apenas pelas instruções DBSKIP() – com valor positivo, leitura sempre dos próximos registros. Um ALIAS de uma Query não suporta filtros, DBSKIP para registros anteriormente lidos. O Alias de uma Query reflete um result set obtido pelo banco de dados no momento da execução da Query. A única forma de voltar para um registro já lido de uma Query é voltar para o primeiro registro ( dbgotop() ) – POREM internamente este processo re-submete a Query para o banco de dados, e o result set retornado pode ser diferente, caso algum processo tenha inserido ou alterado registros.