Tutorial de ADO
Moderador: Moderadores
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Na época que comecei, fez falta um tutorial desse tipo.
Por enquanto é a parte teórica.
Se preocupe em entender do que se trata, e deixe a parte de como usar pra depois.
Usar é mais simples do que entender.
Nos tempos do Clipper, o único tipo de biblioteca que conhecemos foi do tipo LIB, que linqueditamos ao programa.
O Blinker acrescentou ao Clipper um recurso muito conhecido do Windows, que foi poder gerar/usar DLLs.
A DLL é como se fosse uma parte do EXE, mas diferente das antigas overlays, com vida própria.
Era possível compilar o EXE ou a DLL de forma separada, podendo trocar qualquer uma das duas partes depois.
Vantagens: mais prático compilar partes menores, e partes poderiam ser compartilhadas por vários programas.
Como Clipper é 16 bits, de qualquer forma não pode aproveitar as muitas DLLs existentes no Windows.
O Windows é cheio de DLLs, todas prontas pra uso, com funções diversas.
As DLLs podem ser divididas em 2 tipos:
- As que são instaladas no Windows, e ficam prontas pra uso, como a do Excel ou Internet Explorer.
- As que NÃO são instaladas no WIndows, como a BLAT.DLL
Como a DLL pode ser de qualquer linguagem (até em Clipper), não significa que qualquer programa pode acessar qualquer DLL.
Além de outras coisas, algumas linguagens tem tipos de variáveis que outras não tem.
O ADO é uma bilbioteca que vém instalada no Windows, pronta pra uso.
Foi criado para que o acesso a qualquer banco de dados seja feito sempre da mesma forma, sem precisar conhecer os detalhes de cada banco de dados.
Há várias formas de usar o ADO, e há muitos recursos, mas não é o objetivo deste tutorial mostrar tudo.
Qualquer coisa, há vários manuais na internet, pra quem quiser se aprofundar ainda mais.
É bom entender o que é objeto, propriedades, métodos e coleções, pra fazer uso dos manuais que se encontram na internet.
No mundo Clipper conhecemos variável, função.
Variável podendo conter string, número, data, etc.
Função, que faz parte do programa.
Inventaram uma variável que pode conter tudo ao mesmo tempo: variável e função.
Deram o nome pra isso de objeto.
É diferente de biblioteca, porque podemos alterar qualquer conteúdo desse objeto - mesmo o que seria uma função.
É como criar um programa, com rotinas, e poder trocar as rotinas, isso durante a execução, sem compilar/linqueditar.
E as variáveis e funções do objeto recebem o nome de propriedades e métodos.
É como se fosse a mesma coisa com nome trocado, mas por causa do funcionamento diferente, recebeu outro nome.
Também tem a coleção, que poderia ser comparado a um array.
Só pra comparação, dbStruct() retorna uma coleção, onde cada item da coleção se refere a um campo do arquivo.
Então, objeto é um pacote que pode conter suas variáveis e funções, e até mesmo outros objetos.
Geralmente usamos uma variável pra armazenar esse "pacote".
No Harbour podemos criar objetos, são as classes. E podemos usar objetos prontos.
Um pacote dipsonível no Windows é o ADO.
Dentro do ADO temos alguns objetos:
Connection - Contém as funções pra "conversar" com a base de dados.
Recordset - Poderíamos comparar com um DBF, mas tem formato próprio.
Pra não depender de nada, esses objetos contém funções que podem ser usadas pra acesso.
Comparando Clipper ao ADO:
Em Clipper, dbStruct() retorna uma coleção contendo cada campo do arquivo com nome, tipo, tamanho, decimais.
Em ADO, Fields(), retorna uma coleção contendo esse tipo de informação, além de funções relacionadas.
Por enquanto é a parte teórica.
Se preocupe em entender do que se trata, e deixe a parte de como usar pra depois.
Usar é mais simples do que entender.
Nos tempos do Clipper, o único tipo de biblioteca que conhecemos foi do tipo LIB, que linqueditamos ao programa.
O Blinker acrescentou ao Clipper um recurso muito conhecido do Windows, que foi poder gerar/usar DLLs.
A DLL é como se fosse uma parte do EXE, mas diferente das antigas overlays, com vida própria.
Era possível compilar o EXE ou a DLL de forma separada, podendo trocar qualquer uma das duas partes depois.
Vantagens: mais prático compilar partes menores, e partes poderiam ser compartilhadas por vários programas.
Como Clipper é 16 bits, de qualquer forma não pode aproveitar as muitas DLLs existentes no Windows.
O Windows é cheio de DLLs, todas prontas pra uso, com funções diversas.
As DLLs podem ser divididas em 2 tipos:
- As que são instaladas no Windows, e ficam prontas pra uso, como a do Excel ou Internet Explorer.
- As que NÃO são instaladas no WIndows, como a BLAT.DLL
Como a DLL pode ser de qualquer linguagem (até em Clipper), não significa que qualquer programa pode acessar qualquer DLL.
Além de outras coisas, algumas linguagens tem tipos de variáveis que outras não tem.
O ADO é uma bilbioteca que vém instalada no Windows, pronta pra uso.
Foi criado para que o acesso a qualquer banco de dados seja feito sempre da mesma forma, sem precisar conhecer os detalhes de cada banco de dados.
Há várias formas de usar o ADO, e há muitos recursos, mas não é o objetivo deste tutorial mostrar tudo.
Qualquer coisa, há vários manuais na internet, pra quem quiser se aprofundar ainda mais.
É bom entender o que é objeto, propriedades, métodos e coleções, pra fazer uso dos manuais que se encontram na internet.
No mundo Clipper conhecemos variável, função.
Variável podendo conter string, número, data, etc.
Função, que faz parte do programa.
Inventaram uma variável que pode conter tudo ao mesmo tempo: variável e função.
Deram o nome pra isso de objeto.
É diferente de biblioteca, porque podemos alterar qualquer conteúdo desse objeto - mesmo o que seria uma função.
É como criar um programa, com rotinas, e poder trocar as rotinas, isso durante a execução, sem compilar/linqueditar.
E as variáveis e funções do objeto recebem o nome de propriedades e métodos.
É como se fosse a mesma coisa com nome trocado, mas por causa do funcionamento diferente, recebeu outro nome.
Também tem a coleção, que poderia ser comparado a um array.
Só pra comparação, dbStruct() retorna uma coleção, onde cada item da coleção se refere a um campo do arquivo.
Então, objeto é um pacote que pode conter suas variáveis e funções, e até mesmo outros objetos.
Geralmente usamos uma variável pra armazenar esse "pacote".
No Harbour podemos criar objetos, são as classes. E podemos usar objetos prontos.
Um pacote dipsonível no Windows é o ADO.
Dentro do ADO temos alguns objetos:
Connection - Contém as funções pra "conversar" com a base de dados.
Recordset - Poderíamos comparar com um DBF, mas tem formato próprio.
Pra não depender de nada, esses objetos contém funções que podem ser usadas pra acesso.
Comparando Clipper ao ADO:
Em Clipper, dbStruct() retorna uma coleção contendo cada campo do arquivo com nome, tipo, tamanho, decimais.
Em ADO, Fields(), retorna uma coleção contendo esse tipo de informação, além de funções relacionadas.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Vamos ao que interessa: como usar.
Pra conversar com o banco de dados, precisa da conexão.
É a única ligação entre o programa e o banco de dados, como se fosse uma linha telefônica, ou uma janela do Skype.
Para um programa inteiro, pode ser usada uma única conexão com o banco de dados.
Nela indicamos localização (que pode ser IP ou diretório), usuário, senha, tipo de banco de dados, etc.
É o principal objeto, porque vai dizer exatamente como encontrar a base de dados, e como deverá ser usada.
Como é objeto, contém suas "variáveis" e suas "rotinas"
A primeira coisa é configurar essas "variáveis" de acordo com a base de dados.
Aqui uso assim para o MySql:
O que são essas "variáveis" (propriedades):
:ConnectionString é a string de conexão, é o texto que indica tudo sobre a base de dados. Tanto faz se é MySQL, DBF por ADS, Postgress. Cada banco de dados vai ter sua própria string. No caso do ADS, Excel e Access, por exemplo, vai conter também o nome do diretório. No caso do MySQL contém IP do servidor, porta de comunicação, nome do banco de dados, usuário, senha, e até configurações extras.
:CursorLocation indica se o recordset (arquivo temporário) vai ser criado no servidor ou no terminal
:CommandTimeOut indica o tempo limite pra esperar uma resposta
:ConnectionTimeOut indica o tempo limite pra esperar conectar
Pra conversar com o banco de dados, precisa da conexão.
É a única ligação entre o programa e o banco de dados, como se fosse uma linha telefônica, ou uma janela do Skype.
Para um programa inteiro, pode ser usada uma única conexão com o banco de dados.
Nela indicamos localização (que pode ser IP ou diretório), usuário, senha, tipo de banco de dados, etc.
É o principal objeto, porque vai dizer exatamente como encontrar a base de dados, e como deverá ser usada.
Código: Selecionar todos
oConexao := win_OleCreateObject( "ADODB.Connection" )
A primeira coisa é configurar essas "variáveis" de acordo com a base de dados.
Aqui uso assim para o MySql:
Código: Selecionar todos
cnConnection:= win_OleCreateObject( "ADODB.Connection" )
cnConnection:ConnectionString := "Driver={MySQL ODBC 3.51 Driver};Server=" + cServer + ";" + "Port=" + Ltrim( Str( nPort ) ) + ;
";Stmt=;Database=" + cDatabase + ";User ID=" + cUser + ";Password=" + cPassword + ";Collation=latin1;" + ;
"UseCompression;" // Option=131072;
cnConnection:CursorLocation := adUseClient // local recordset
cnConnection:CommandTimeOut := 120 // seconds
cnConnection:ConnectionTimeOut := 120 // seconds
:ConnectionString é a string de conexão, é o texto que indica tudo sobre a base de dados. Tanto faz se é MySQL, DBF por ADS, Postgress. Cada banco de dados vai ter sua própria string. No caso do ADS, Excel e Access, por exemplo, vai conter também o nome do diretório. No caso do MySQL contém IP do servidor, porta de comunicação, nome do banco de dados, usuário, senha, e até configurações extras.
:CursorLocation indica se o recordset (arquivo temporário) vai ser criado no servidor ou no terminal
:CommandTimeOut indica o tempo limite pra esperar uma resposta
:ConnectionTimeOut indica o tempo limite pra esperar conectar
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Métodos (funções) da conexão:
:Open() - pra ativar/abrir
:Close() - pra desativar/fechar
:Execute() - pra executar um comando
Não parece, mas só esses três e está tudo resolvido.
Pode abrir no início do aplicativo, e fechar antes de encerrar o aplicativo.
No restante, é Execute(). Qualquer coisa que vá fazer com o banco de dados, é Execute().
Compare o Execute() com uma janela do Skype. Vai mandar uma mensagem ao banco de dados, e ele vai te responder.
:Open() - pra ativar/abrir
:Close() - pra desativar/fechar
:Execute() - pra executar um comando
Não parece, mas só esses três e está tudo resolvido.
Pode abrir no início do aplicativo, e fechar antes de encerrar o aplicativo.
No restante, é Execute(). Qualquer coisa que vá fazer com o banco de dados, é Execute().
Compare o Execute() com uma janela do Skype. Vai mandar uma mensagem ao banco de dados, e ele vai te responder.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Esqueci de mencionar no início:
Apesar de ser pra ADO, pode servir pra entender o básico da comunicação cliente/servidor.
Também pra entender o básico de objetos, propriedades, métodos e coleção - vai ter muito nos manuais da internet
Também pra entender o básico de DLLs, algumas vezes chamadas de componentes, activex, etc. devido a características de cada um
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
No meu caso, pra deixar um fonte mais limpo, criei uma função que faz a configuração para MySql.
Deixar separado, assim deixa o restante mais claro.
Deixar separado, assim deixa o restante mais claro.
Código: Selecionar todos
FUNCTION MySqlConnection( cServer, nPort, cDatabase, cUser, cPassword )
LOCAL cnConnection
cnConnection:= win_OleCreateObject( "ADODB.Connection" )
cnConnection:ConnectionString := "Driver={MySQL ODBC 3.51 Driver};Server=" + cServer + ";" + "Port=" + Ltrim( Str( nPort ) ) + ;
";Stmt=;Database=" + cDatabase + ";User ID=" + cUser + ";Password=" + cPassword + ";Collation=latin1;" + ;
"UseCompression;" // Option=131072;
cnConnection:CursorLocation := adUseClient // local recordset
cnConnection:CommandTimeOut := 120 // seconds
cnConnection:ConnectionTimeOut := 120 // seconds
RETURN cnConnection
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Agora o aplicativo:
Isso é pra ficar claro a parte importante.
No uso, pode ter uma única conexão pro aplicativo inteiro.
No meu uso prático, esse foi o melhor jeito.
O Harbour não era assim no início, mas depois mudaram.
Por incrível que pareça, isto pode gerar problemas:
Não existe limite para conexões abertas no Windows.
Conexão fechada não existe, porque uma vez fechada ela some.
Mas existem "half-open connections" que são conexões em fase de abertura ou em fase de fechamento.
Esse limite é baixo, então precisa tomar cuidado pra não travar tudo.
Não sei se é coisa apenas do Windows, mas existe um tempo adicional antes de fechar de vez, o que a deixa em estado de "half-open".
Quem usa Emule, Torrent e afins, já deve ter visto algo sobre isso.
Passou do limite, vai ficando numa fila de espera, correndo o risco de travar tudo.
Por isso simplifiquei, e abro/fecho no início e final do aplicativo.
O detalhe é que pra ser conexão única, essa variável precisa estar disponível a todos os módulos, mesmo em multithread.
Cada um já deve ter uma solução pronta pra isso: PUBLIC, STATIC, função, etc.
Código: Selecionar todos
PROCEDURE Main
oConexao := MySqlConnection( cIP, nPort, cDatabase, cUser, cPassword )
oConexao:Open()
...
oConexao:Close()
RETURN
No uso, pode ter uma única conexão pro aplicativo inteiro.
No meu uso prático, esse foi o melhor jeito.
O Harbour não era assim no início, mas depois mudaram.
Por incrível que pareça, isto pode gerar problemas:
Código: Selecionar todos
FOR nCont = 1 TO 10000
oConexao:Open()
oConexao:Close()
NEXT
Conexão fechada não existe, porque uma vez fechada ela some.
Mas existem "half-open connections" que são conexões em fase de abertura ou em fase de fechamento.
Esse limite é baixo, então precisa tomar cuidado pra não travar tudo.
Não sei se é coisa apenas do Windows, mas existe um tempo adicional antes de fechar de vez, o que a deixa em estado de "half-open".
Quem usa Emule, Torrent e afins, já deve ter visto algo sobre isso.
Passou do limite, vai ficando numa fila de espera, correndo o risco de travar tudo.
Por isso simplifiquei, e abro/fecho no início e final do aplicativo.
O detalhe é que pra ser conexão única, essa variável precisa estar disponível a todos os módulos, mesmo em multithread.
Cada um já deve ter uma solução pronta pra isso: PUBLIC, STATIC, função, etc.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Até aqui sabemos abrir, fechar, falta o resto - o Execute()
Como eu disse antes, é como se fossem mensagens no Skype.
Essas mensagens são em comandos SQL, que no geral obedecem um padrão.
Como os bancos de dados são diferentes, pode existir alguma variação, dependendo do recurso a mais que quiser.
O Execute() vai enviar mensagem, e pode trazer uma resposta. Tudo depende de qual comando enviou.
A resposta pode ser justamente o recordset - o "arquivo temporário".
Agora exemplos simbólicos, já que algumas coisas dependem de detalhes específicos de cada base de dados.
Notem que a partir daqui, tem a ver com comandos SQL.
Criar uma tabela, o que seria equivalente a criar um DBF:
Incluir um ou mais registros:
Excluir:
Alterar:
Pesquisar:
O pesquisar expande as possibilidades, porque não se limita a apenas aos campos existentes.
Poderia pesquisar a soma de todos os campos valor.
E como essa soma não tem nome definido, podemos chamá-la de soma, pra facilitar depois.
Como eu disse antes, é como se fossem mensagens no Skype.
Essas mensagens são em comandos SQL, que no geral obedecem um padrão.
Como os bancos de dados são diferentes, pode existir alguma variação, dependendo do recurso a mais que quiser.
O Execute() vai enviar mensagem, e pode trazer uma resposta. Tudo depende de qual comando enviou.
A resposta pode ser justamente o recordset - o "arquivo temporário".
Agora exemplos simbólicos, já que algumas coisas dependem de detalhes específicos de cada base de dados.
Notem que a partir daqui, tem a ver com comandos SQL.
Criar uma tabela, o que seria equivalente a criar um DBF:
Código: Selecionar todos
oConexao:Execute( "CREATE TABLE minhatabela ( CODIGO NUMERIC(5), NOME CHAR(30), VALOR NUMERIC(12,2) )" )
Código: Selecionar todos
oConexao:Execute( "INSERT INTO minhatabela ( CODIGO, NOME ) VALUES ( 5, 'TESTE', 10 )" )
Código: Selecionar todos
oConexao:Execute( "DELETE FROM minhatabela WHERE CODIGO=5" )
Código: Selecionar todos
oConexao:Execute( "ALTER TABLE minhatabela SET NOME='TESTE2' WHERE CODIGO=5" )
Código: Selecionar todos
oTemporario := oConexao:Execute( "SELECT * FROM minhatabela" )
Poderia pesquisar a soma de todos os campos valor.
E como essa soma não tem nome definido, podemos chamá-la de soma, pra facilitar depois.
Código: Selecionar todos
oTemporario := oConexao:Execute( "SELECT SUM(VALOR) AS SOMA FROM minhatabela" )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Sobre os comandos SQL, a variedade é infinita, então vai ter que pesquisar tudo que é opção, conforme for precisando.
Principalmente para o comando SELECT.
O que precisa saber é:
Passou a ter um gerenciador de banco de dados, um "programa" que trabalha para o seu programa.
Seu programa manda a mensagem, e o servidor manda a resposta.
Seu programa pede: eu quero as vendas para clientes de São Paulo, totalizadas por cliente, mas me interessa apenas as vendas acima de 2.000, e quero em ordem alfabética de cliente.
E o servidor manda isso pronto para o programa.
Não compensa fazer isso igual DBF.
Imagine o programa pedindo a lista de todos os clientes, todas as vendas, para o próprio programa selecionar o que interessa, totalizar, indexar, etc.
Se pode vir pronto, é menos processamento no terminal, e menos informações pela rede.
Mesmo que precise de um comando grande pra enviar ao servidor, a resposta vai ser pequena, então vale a pena.
A título de curiosidade, seria um comando parecido com este, dependendo da configuração das bases de dados, poderia até ser menor.
Qual informação vai retornar, que será o conteúdo do recordset (como arquivo temporário)
CODCLI, CLIENTES.NOME AS NOMECLI, SUM(VALOR) AS SOMA
De onde ela vém:
VENDAS
Criando um relacionamento com a tabela de clientes pra pegar o nome (caso não tenha feito isso no servidor)
INNER JOIN CLIENTES ON CODCLI = CLIENTES.CODCLI
Um filtro:
WHERE VALOR > 2000
Como vai agrupar pra totalizar:
GROUP BY CODCLI
E a ordem final:
ORDER BY NOMECLI
Tem variações nesse comando, por exemplo o servidor identificar CODCLI nas duas tabelas e já relacionar, ou já ter sido definido no servidor, mas aí é cada um pesquisar o que há de disponível na base de dados que escolher.
Principalmente para o comando SELECT.
O que precisa saber é:
Passou a ter um gerenciador de banco de dados, um "programa" que trabalha para o seu programa.
Seu programa manda a mensagem, e o servidor manda a resposta.
Seu programa pede: eu quero as vendas para clientes de São Paulo, totalizadas por cliente, mas me interessa apenas as vendas acima de 2.000, e quero em ordem alfabética de cliente.
E o servidor manda isso pronto para o programa.
Não compensa fazer isso igual DBF.
Imagine o programa pedindo a lista de todos os clientes, todas as vendas, para o próprio programa selecionar o que interessa, totalizar, indexar, etc.
Se pode vir pronto, é menos processamento no terminal, e menos informações pela rede.
Mesmo que precise de um comando grande pra enviar ao servidor, a resposta vai ser pequena, então vale a pena.
A título de curiosidade, seria um comando parecido com este, dependendo da configuração das bases de dados, poderia até ser menor.
Código: Selecionar todos
oConexao:Execute( "SELECT CODCLI, CLIENTES.NOME AS NOMECLI, SUM(VALOR) AS SOMA FROM " + ;
"VENDAS INNER JOIN CLIENTES ON CODCLI = CLIENTES.CODCLI WHERE VALOR > 2000 GROUP BY CODCLI ORDER BY NOMECLI" )
CODCLI, CLIENTES.NOME AS NOMECLI, SUM(VALOR) AS SOMA
De onde ela vém:
VENDAS
Criando um relacionamento com a tabela de clientes pra pegar o nome (caso não tenha feito isso no servidor)
INNER JOIN CLIENTES ON CODCLI = CLIENTES.CODCLI
Um filtro:
WHERE VALOR > 2000
Como vai agrupar pra totalizar:
GROUP BY CODCLI
E a ordem final:
ORDER BY NOMECLI
Tem variações nesse comando, por exemplo o servidor identificar CODCLI nas duas tabelas e já relacionar, ou já ter sido definido no servidor, mas aí é cada um pesquisar o que há de disponível na base de dados que escolher.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Agora vém a parte de usar o recordset, o "arquivo temporário" (que não é arquivo físico).
Como disse antes, o recordset não é apenas informação, tem também funções.
Então uma opção é usar diretamente, através das funções ADO.
Usar o último exemplo, onde o SELECT foi CODCLI, CLIENTES.NOME AS NOMECLI, SUM(VALOR) AS SOMA
Significa que os campos serão CODCLI, NOME e SOMA
Como disse antes, o recordset não é apenas informação, tem também funções.
Então uma opção é usar diretamente, através das funções ADO.
Usar o último exemplo, onde o SELECT foi CODCLI, CLIENTES.NOME AS NOMECLI, SUM(VALOR) AS SOMA
Significa que os campos serão CODCLI, NOME e SOMA
Código: Selecionar todos
DO WHILE .NOT. oTemporario:Eof()
? oTemporario:Fields( "CODCLI" ):Value
? oTemporario:Fields( "NOME" ):Value
? oTemporario:Fields( "SOMA" ):Value
oTemporario:MoveNext()
ENDDO
oTemporario:Close()
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Outra opção, que estou usando para facilitar, é converter esse recordset em DBF.
Com ou sem ADO, as LIBs do Harbour costumam fazer isso, muitas vezes on-the-fly, conforme vai usando a informação retornada.
Já devem ter visto algo parecido com isto:
Significa que o comando SQL está sendo executado e o retorno está sendo usado como se fosse um DBF.
No caso do ADO, algo equivalente poderia ser:
E a função ConverteDbf() seria a única a ter o tratamento de ADO.
Ou até usar #define ou #command ou #translate pra deixar mais transparente ainda.
Mas infelizmente não sei usar essas coisas direito.
Basicamente é isso.
O que precisa?
Como qualquer outra opção, precisa do programa específico da base de dados, geralmente chamada ODBC.
Se for MySQL, o ODBC de MySQL.
Se for ADS pra DBF, o ODBC de ADS, e no Windows 64 bits precisa de uma configuração adicional que não descobri qual é
Até faz um pouco de sentido ser mais complicado pra DBF e outros tipos de odbc de uso local.
Imagine um programa acessar o ODBC de DBF, e salvar um DBF com o nome de C:\windows\system32\algumacoisa.
Tudo bem, muita coisa já melhorou na segurança do Windows pra evitar isso, mas... continua sendo considerado um risco à segurança...
Então a opção de DBF ainda existe, só precisa pesquisar.
Notas:
Na prática testei ADS no XP 32 bits e no W7 64 bits. No XP continua como sempre foi.
Na pesquisa disso na internet, há muita referência sobre acesso a bases de dados por uma "engine" Microsoft que deixou de vir pronta pra uso em 64 bits, o que leva a deduzir que o uso do ADS faz uso disso.
Com ou sem ADO, as LIBs do Harbour costumam fazer isso, muitas vezes on-the-fly, conforme vai usando a informação retornada.
Já devem ter visto algo parecido com isto:
Código: Selecionar todos
USE ( "SELECT * FROM CLIENTES" ) ALIAS CLIENTES
No caso do ADO, algo equivalente poderia ser:
Código: Selecionar todos
cDBF := ConverteDbf( oConexao:Execute( "comandoSQL" ) )
USE ( cDbf ) ALIAS CLIENTES
Ou até usar #define ou #command ou #translate pra deixar mais transparente ainda.
Mas infelizmente não sei usar essas coisas direito.
Basicamente é isso.
O que precisa?
Como qualquer outra opção, precisa do programa específico da base de dados, geralmente chamada ODBC.
Se for MySQL, o ODBC de MySQL.
Se for ADS pra DBF, o ODBC de ADS, e no Windows 64 bits precisa de uma configuração adicional que não descobri qual é
Até faz um pouco de sentido ser mais complicado pra DBF e outros tipos de odbc de uso local.
Imagine um programa acessar o ODBC de DBF, e salvar um DBF com o nome de C:\windows\system32\algumacoisa.
Tudo bem, muita coisa já melhorou na segurança do Windows pra evitar isso, mas... continua sendo considerado um risco à segurança...
Então a opção de DBF ainda existe, só precisa pesquisar.
Notas:
Na prática testei ADS no XP 32 bits e no W7 64 bits. No XP continua como sempre foi.
Na pesquisa disso na internet, há muita referência sobre acesso a bases de dados por uma "engine" Microsoft que deixou de vir pronta pra uso em 64 bits, o que leva a deduzir que o uso do ADS faz uso disso.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Tutorial de ADO
José, ótima informação sobre o ADO. Parabéns!
Clipper 5.2e / Blinker 5.1 / Harbour 3.2 / GTwvg
Tutorial de ADO
Boa tarde! estou usando como base este código abaixo pra leitura e gravação em Msyql, cara tá show, o problema é só identificar o sucesso ou não da conecção, quanto tudo funciona blz, só que preciso saber quando deu algum problema ao conectar ou executar propriamente o comando, segue exemplo abaixo, grava em 2 bancos ao mesmo tempo.
Frazato
Frazato
Código: Selecionar todos
#include "inkey.ch"
STATIC oConexaoFlex, oConexaoBridge
PROCEDURE Main
ConfiguraConexaoFlex()
oConexaoFlex:Open()
ConfiguraConexaoBridge()
oConexaoBridge:Open()
SET CENTURY ON
SET DATE BRITISH
SET EPOCH TO 2001
SET DELETE ON
SET MESSAGE TO 24 CENTER
SetMode( 25, 80 )
SET COLOR TO W/N,W/GR+,,,G+/N
CLS
Do while .t.
ccodigo := space(5)
nPreco := 0
@ 09,09 SAY 'Carga de Preco/Online GZ Flex / BrigeDB'
@ 10,10 say 'Digite o codigo :' Get cCodigo pict '99999'
@ 11,10 say 'Digite o Preco Venda :' Get nPreco pict '@EZ 999,999.99'
read
If LastKey()==27
exit
Endif
VerProdutos(cCodigo,nPreco)
Enddo
oConexaoFlex:Close()
oConexaoBridge:Close()
Quit // Forca Saida
*oTemporario := oConexao:Execute( "SELECT * FROM LOTES WHERE LOTE=" + Ltrim( Str( wLote ) ) )
*IF oTemporario:RecordCount() != 0
* westado = oTemporario:Fields( "ESTADO" ):Value
* wdt_entrada = datavol4( oTemporario:Fields( "DT_ENTRADA" ):Value )
* wdias = oTemporario:Fields( "DIAS" ):Value
* wdt_saida = datavol4( oTemporario:Fields( "DT_SAIDA" ):Value )
* wqtde = oTemporario:Fields( "QTDE" ):Value
* wvlr_unit = oTemporario:Fields( "VLR_UNIT" ):Value
* wvlr_total = oTemporario:Fields( "VLR_TOTAL" ):Value
*endif
*oTemporario:Close()
// exclusao
* if woquefazer = "INC"
* oConexao:Execute( "INSERT INTO LOTES ( LOTE ) VALUES ( " + Ltrim( Str( wLote ) ) )
* endif
* oConexao:Execute( [UPDATE LOTES SET ] + ;
* [ESTADO='] + wEstado + [', ] + ;
* [DT_ENTRADA='] + Dtos( wDt_Entrada ) + [', ] + ;
* [DIAS=] + Ltrim( Str( wDias ) ) + [, ] + ;
* [DT_SAIDA="] + Dtos( wDt_Saida ) + [", ] + ;
* [QTDE=] + Ltrim( Str( wQtde ) ) + [, ] + ;
* [VLR_UNIT=] + Ltrim( Str( wVlr_Unit ) ) + [, ] + ;
* [VLR_TOTAL=] + Ltrim( Str( wVlr_Total ) ) + [ ) ] + ;
* [WHERE LOTE=] + Ltrim( Str( wLote ) ) )
oConexao:Close()
RETURN
//--- Coneccao com o banco do Gz
//------------------------------------------------------------
STATIC FUNCTION ConfiguraConexaoFlex()
Centra('Aguarde..... Conectando Bando Dados...GZFLEX...')
oConexaoFlex := win_OleCreateObject( "ADODB.Connection" )
oConexaoFlex:ConnectionString := "Driver={MySQL ODBC 3.51 Driver};Server=LocalHost;" + ;
"Option=131072;Stmt=;Database=concentdb;User ID=root;Password=mestre;Collation=latin1;"
oConexaoFlex:CursorLocation := 3 // local recordset
oConexaoFlex:CommandTimeOut := 120 // seconds
oConexaoFlex:ConnectionTimeOut := 120 // seconds
centra('Aguarde..... Conectando Bando Dados...GZFLEX...')
RETURN NIL
//--- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
STATIC FUNCTION ConfiguraConexaoBridge()
Centra('Aguarde..... Conectando Bando Dados...GZFLEX...')
oConexaoBridge := win_OleCreateObject( "ADODB.Connection" )
oConexaoBridge:ConnectionString := "Driver={MySQL ODBC 3.51 Driver};Server=LocalHost;" + ;
"Option=131072;Stmt=;Database=bridgedb;User ID=root;Password=mestre;Collation=latin1;"
oConexaoBridge:CursorLocation := 3 // local recordset
oConexaoBridge:CommandTimeOut := 120 // seconds
oConexaoBridge:ConnectionTimeOut := 120 // seconds
RETURN NIL
//------------------------------------------------
Static Function VerProdutos(cPesq,nPrecoVenda)
LOCAL oTemporario, lOk := .T.
Local ccodigo := Alltrim(Str(val(cPesq)))
Local cVenda := Alltrim(Str(nPrecoVenda))
centra('Gravando produto Bando de dados....'+cPesq)
oTemporario := oConexaoFlex:Execute( [SELECT * FROM ESTOQUE WHERE CDPROD=]+cCodigo )
IF oTemporario:RecordCount() == 0
Alert ( "Estado não encontrado" )
lOK := .F.
ELSE
@ 12,12 SAY oTemporario:Fields( "descricao" ):Value COLOR "G+/N"
@ 13,12 say oTemporario:Fields( "termvenda" ):Value COLOR "G+/N"
oConexaoFlex:Execute( [UPDATE Estoque SET ] + ;
[termvenda=] + cVenda+[,]+ ;
[descpdv='Alterado via JAF']+ ;
[WHERE cdProd=] + cCodigo )
//alert("INSERT INTO SOLICITACAO (TABELA) VALUES ('estoque')")
cVerCondicao := 'p.cdprod = #@#'+Space(20-Len(cCodigo))+cCodigo+'#@#'
oConexaoBridge:Execute( [INSERT INTO solicitacao (TABELA,TIPO,IP,PORTA,USUARIO,CONDICAO) VALUES ('estoque','CP','192.168.27.106','1202','JAF ONLINE',']+cvercondicao+[')])
ENDIF
oTemporario:Close()
RETURN lOk
Function Centra(c)
@ 24,00 say c
Return nil
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
A checagem seria no Open()
Ou se for usar isso muitas vezes:
De quebra, pode acrescentar pra mostrar possíveis mensagens de erro.
Código: Selecionar todos
lOpen := .F.
BEGIN SEQUENCE
Conexao:Open()
lOpen := .T.
END SEQUENCE
IF .NOT. lOpen
Mensagem( "Não conseguiu abrir" )
QUIT
ENDIF
Código: Selecionar todos
IF .NOT. OpenConn( Conexao )
Mensagem( "Não conseguiu abrir" )
QUIT
ENDIF
FUNCTION OpenConn( Conexao )
LOCAL lOpen := .F.
Mensagem( "Abrindo Conexão" )
BEGIN SEQUENCE
Conexao:Open()
lOpen := .T.
END SEQUENCE
RETURN lOpen
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Tutorial de ADO
Código: Selecionar todos
ConfiguraConexaoFlex()
BEGIN SEQUENCE WITH {| oErr | Break( oErr ) }
oConexaoFlex:Open()
RECOVER
Alert('Erro ao conectar o Banco!')
Return nil
END SEQUENCE
ConfiguraConexaoBridge()
BEGIN SEQUENCE WITH {| oErr | Break( oErr ) }
oConexaoBridge:Open()
RECOVER
Alert('Erro ao conectar o Banco!')
Return nil
END SEQUENCE
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Tutorial de ADO
Mas com essas, como o programa vai saber se falhou?
Faltou retornar verdadeiro ou falso, pro programa decidir o que fazer.
Mais um detalhe:
Abre uma, deu erro, encerra.
Abre uma, ok, vai em frente.
Abre a outra, deu erro, fecha a primeira antes de encerrar.
Faltou retornar verdadeiro ou falso, pro programa decidir o que fazer.
Mais um detalhe:
Abre uma, deu erro, encerra.
Abre uma, ok, vai em frente.
Abre a outra, deu erro, fecha a primeira antes de encerrar.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/

