Clipper On Line • Ver Tópico - Harbour (ou xHarbour) BASICO com MYSQL
Página 1 de 2

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 20 Mai 2015 18:49
por manuel1437
Meus Caros

Ainda estou na luta para trabalhar com Harbour ou xHarbour ...

O amigo Claudio mandou um exemplo para compilar um programa simples do Clipper. Mas preciso da ajuda de vocês.

O programa aborda conceitos. Não faz parte de qualquer "solução" pré-existente. Eu montei um exemplo anexo, em Clipper, na sua forma mais simples para facilitar o aprendizado:
usando dois arquivos dbf
abertura de arquivos, uso de índices (se necessário)
com campos character, numeric com duas ou três casas e com cálculo de com campos data
uma rotina de consulta simples usando o dbedit
comandos de inclusão, alteração, exclusão, pesquisa
utilizacao de lnk para compilar varios prg

Gostaria de saber se alguém já tem experiencia usando o modo caracter (janela DOS) com mysql remoto, num servidor qualquer.
É o inicio de tudo: MODO CARACTER usando MYSQL

Imagino que o Executável fique numa pasta c:\sistemas e, alimente uma base MYSQL localizado na nuvem, em qualquer lugar do mundo.
Neste primeiro momento, não penso no ambiente gráfico. Sei que existem várias opções e até mesmo poderíamos aproveitar este modelo para facilitar comparação entre elas.

Aliás, a título de curiosidade: eu poderia usar o MYSQL e trabalhar junto com alguns DBF localizados em c:\sistemas ?
Explico: utilizo alguns dbf's temporários para preparar bases para relatorios - estaria lendo MYSQL e gravando em DBF temporário para depois fazer o trabalho da impressão

A sugestão é copiar o programa lote01.prg para lote02.prg e substituir o que é necessario para criar este cenário Caracter-MYSQL. É um modelo pequeno, mas que traz as principais rotinas que precisamos no dia-a-dia.

Com isto, poderemos ter tutoriais para cada um dos cenários que o Harbour ou xHarbour possibilita, incluindo interface gráfica, mouse, mysql ou outro bd, permitindo que mais pessoas se aventurem rapidamente neste universo. A partir disto, acredito que cada um buscará o seu próprio caminho, aprofundando o conhecimento.

Com o mesmo desafio para cada "combo", o usuario podera optar pelo que entender ser mais interessante para seu proprio uso.

De alguma forma, é o velho ACME.

Abraços, e obrigado pela compreensão. Tenho pesquisado a literatura e já li até sobre a aplicação funcionar como CGI - é preciso focar um pouco para não se perder diante de tantas possibilidades e avançar mais rapidamente. Entao, vamos partir do modelo mais basico possivel.

Abracos

Manuel

Toledo: obrigado pelo retorno por email.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 19:12
por JoséQuintas
Banco de dados não tem nada a ver com tela.
Se acompanhou meu post, estou fazendo justamente isso: DBF + MySQL ao mesmo tempo, até terminar.

Sei que não vai gostar de ler isto, mas:
Um primeiro trabalho seria melhorar os fontes, mesmo pra DBF e mesmo pra Clipper.
Isto não tem nada a ver com o fonte estar certo ou errado, ou de funcionar ou não.

Aliás, usar como exemplo pra uma coisa que falo várias vezes no fórum:
Dá pra programar pra Harbour usando o próprio Clipper.

1. Uma coisa é fazer o programa funcionar compilando com Harbour.
2. Outra coisa é melhorar o fonte, pra tornar fácil qualquer mudança.
3. E a última é acrescentar recursos.

Se puder fazer tudo de uma vez melhor, senão, uma etapa de cada vez facilita a outra.

Uma coisa que reparei:
A consulta usa um TBROWSE, com opção de mudar a ordem.
Isso vai precisar de uma rotina diferente de um relatório com as mesmas opções, e vai sempre precisar do arquivo inteiro.
Talvez não seja uma boa opção pra forma didática.
Num caso desses, minha escolha seria criar um arquivo temporário a partir da base MySQL, o que resultaria na mesma rotina de navegação.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 19:31
por JoséQuintas
Vamos lá... primeira etapa....
Aqui não funciona Clipper, porque meu Windows é 64 bits, então fui direto pro Harbour.

O compila.bat tem muitas linhas, e tem o compila.lnk em separado.
Poderia ser reduzido pra:

clipper lote01
clipper c_lote
rtlink fi lote01, c_lote


No caso do Harbour, compilei usando isto:

hbmk2 lote01, c_lote


foi de primeira.

Já se vê diferença. Na tela, aonde mostra memória disponível, apareceu 4.194.303 kb (4GB).
Provavelmente no Clipper mostre 640kb ou algo próximo, ou com Blinker 16.000kb.
Significa que memória deixou de ser problema.

Rodei direto o exemplo.
No primeiro teste, tive que usar Alt-C pra sair, porque não vi como sair.
Vai precisar algo mais no Harbour, porque usou meu default de 1.000 linhas de altura, e fica ruim de enxergar a tela.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 20:38
por JoséQuintas
Me chamou a atenção isto:

func datavol4                    // Funcao: Converte AAAAMMDD para dd/mm/aaaa
   * para chamar esta rotina:
   *        variavel = datavol4(campo texto no formato aaaammdd)
   *        a variavel acabou de ser criada como data
   *        deixar sempre SET CENTURY ON - trabalhar com 4 casas no ano
   *        quando gravar, utilizar DTOS(variavel data)
   *        portanto, no DBF o campo data sera TEXTO de 8 posicoes

   set century on
   parameters wdv_data
   w_data_dv = ctod(subst(wdv_data,7,2)+"/"+subst(wdv_data,5,2)+"/"+subst(wdv_data,1,4))

return (w_data_dv)


Não era mais fácil usar campo Date no DBF? Campo Date grava ano com 4 dígitos, e no DBF seriam usados os mesmos 8 caracteres.

Ok, tudo bem.
Considere que são mais coisas que podem ser melhoradas, não importa se é Clipper, Harbour, ou MySQL.
Se usar formato diferente, vai ter que fazer rotinas especiais, em Clipper, Harbour e pode se complicar no MySQL, ou deixar de aproveitar recursos.

Ao usar SET CENTURY ON, as datas aparecem com 4 dígitos na tela.
Isto é somente pra tela. No banco de dados sempre é gravado com 4 dígitos.

SET EPOCH TO 1920
Este é um comando pra definir um default.
Caso sejam digitados apenas 2 dígitos na data, o Clipper/Harbour vai considerar a partir de 1920.
Se digitar 21/05/15, o Clipper considera como sendo ano 2015.
Se digitar 21/05/21, o Clipper considera como sendo ano 1921.
É pra isso que serve o SET EPOCH.

Isso reforça mais ainda:
Dá pra converter pra Harbour usando o próprio Clipper.
Esta é uma mudança que poderia ser feita usando o próprio Clipper.

Porque repito isso:
Tem gente apanhando pra ir pro Harbour, ou pra usar LIB gráfica.
Tudo bem, não tenha pressa, pode ir adiantando o serviço usando Clipper.
Pode ir melhorando o fonte, e depois fica até mais fácil.
Vai melhorando o fonte, e se não compila agora, é possível que compile depois tranquilamente.

Aconteceu comigo de aprender coisas do Clipper que não conhecia antes.
Melhorar o fonte é mais importante do que qualquer outra coisa.

Isso vira um vício, então procure fazer do melhor jeito, pra não se viciar em algo que complique.

Na prática:
Ao invés do sentimento de não conseguir no Harbour, vai ter um sentimento de "estou melhorando cada vez mais".
Parece que não, mas isso faz diferença.

Não conseguir no Harbour, vai te deixar desanimado pra continuar. É só tristeza.
Melhorar os fontes, vai te deixar animado em melhorar cada vez mais. É só alegria.
Então... trabalhe com alegria.
E um testezinho no Harbour de vez em quando, não vai tirar a alegria.
Vai estar sempre indo em frente e melhorando.

Vou mostrar o fonte LOTE01.PRG sendo alterado, com o objetivo de demonstrar essa "alegria" em melhorar o fonte.
Já funcionou em Harbour, melhor ainda, mas vou me limitar ao Clipper, até ficar do "meu jeito".
Talvez alguns só entendam o que estou querendo dizer no fonte final.
Mas vou chegar aonde quer, tenha paciência.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 20:49
por JoséQuintas
Começar pelo fonte original, tirando as anotações do MySQL.
É grande (na postagem) quase 350 linhas:

clear

********************************************
@ 07,59 say "CLIPPER BASICO"

@ 03,01 say "PROC01 Clipper               ³"
@ 04,01 say "                             ³"
@ 05,01 say "PROC11 Harbour Local  DBF    ³"
@ 06,01 say "PROC12 Harbour Remoto DBF    ³"
@ 07,01 say "PROC13 Harbour Remoto MYSQL  ³"
@ 08,01 say "                             ³"
@ 09,01 say "PROC21 xHarbour Local  DBF   ³"
@ 10,01 say "PROC22 xHarbour Remoto DBF   ³"
@ 11,01 say "PROC23 xHarbour Remoto MYSQL ³"
@ 12,01 say "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

@ 16,01 say "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
@ 17,01 say "- Testando os campos b sicos ³"
@ 18,01 say "- C lculo de Data + Dias     ³"
@ 19,01 say "- Inclus„o/Altera‡„o/Exclus„o³"
@ 20,01 say "- Uso DbEdit para Consulta   ³"
@ 21,01 say "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"

******************************************************************
******************************************************************
* CLIPPER
******************************************************************
******************************************************************

***************************************************** TELA E SET BASICO
   set date brit
   set epoch to 2001
   set delete on
   @ 02,01 to 02,80
   @ 23,01 to 23,80
   set color to w/b
      @ 01,01 say space(80)
      @ 01,01 say "LOTES - Aprendizado Harbour e xHarbour"
      @ 01,70 say date()
   set color to w/n
   memoria = memory()
   @ 03,54 say memory() pict "9,999,999,999"
   @ 03,68 say "Kb Mem¢ria"
   dc = " "

***************************************************** ABERTURA DE ARQUIVOS
   sele a
      use lotes alias lotes
         index on lote                                to ilote1
         index on estado+lote+dt_entrada              to ilote2
         index on dt_entrada+lote                     to ilote3
         index on dt_saida+lote                       to ilote4
      set index to ilote1, ilote2, ilote3, ilote4
      go top
      set order to 1
   sele b
      use estado alias estado
         index on sigla_uf                            to iuf1
      go top
      set order to 1

***************************************************** OPERACAO
   wlote       = space(07)
   westado     = space(02)
   wdt_entrada = datavol4(space(08))
   wdias       = 0
   wdt_saida   = datavol4(space(08))
   wqtde       = 0
   wvlr_unit   = 0
   wvlr_total  = 0

   do while .t.

      msg_1 ( "Informe o LOTE                              [branco] finaliza" )
      @ 09,34 say "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
      @ 10,34 say "³ Lote....: °°°°°°          ? Pesquisa ³"
      @ 11,34 say "³                                      ³"
      @ 12,34 say "³ Estado..: °° °°°°°°°°°°°°°°°°°°°     ³"
      @ 13,34 say "³                                      ³"
      @ 14,34 say "³   Entrada       Dias     Devolu‡„o   ³"
      @ 15,34 say "³ ÄÄÄÄÄÄÄÄÄÄ      ÄÄÄÄ    ÄÄÄÄÄÄÄÄÄÄ   ³"
      @ 16,34 say "³ °°/°°/°°°°   +  °°°°  = °°/°°/°°°°   ³"
      @ 17,34 say "³                                      ³"
      @ 18,34 say "³    Qtde      Unit rio    Valor Total ³"
      @ 19,34 say "³ ÄÄÄÄÄÄÄÄÄ   ÄÄÄÄÄÄÄÄÄ   ÄÄÄÄÄÄÄÄÄÄÄÄ ³"
      @ 20,34 say "³ °°°°°°°°° x °°°°°.°°° = °°°°°°°°°.°° ³"
      @ 21,34 say "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
      @ 22,34 say "                                        "

      @ 10,46 get wlote pict "@!"
      read
      if wlote = " "
         clear
         return
      endif
      if wlote = "?"
         consulta()
         loop
      endif

      ******************************* consulta
      sele lotes
         set order to 1
         go top
      seek (wlote)

      if .not. eof()
         westado     = estado
         wdt_entrada = datavol4(dt_entrada)
         wdias       = dias
         wdt_saida   = datavol4(dt_saida)
         wqtde       = qtde
         wvlr_unit   = vlr_unit
         wvlr_total  = vlr_total

         set color to g+/n
            @ 12,46 say westado
            @ 16,36 say wdt_entrada
            @ 16,52 say wdias        pict "9999"
            @ 16,60 say wdt_saida
            @ 20,36 say wqtde        pict "9,999.999"
            @ 20,48 say wvlr_unit    pict "9,999.999"
            @ 20,60 say wvlr_total   pict "9,999,999.99"
            sele estado
               set order to 1
               go top
            seek (westado)
            if eof()
               alert ( "Erro - deveria existir o ESTADO" )
            else
               @ 12,49 say estado
            endif
            sele lotes
         set color to w/n

         msg_1 ( "Registro existente. Deseja Alterar, Excluir ou Voltar ? ... A/E/V ..." )
         @ 24,73 get dc pict "!" valid dc $ "AEV"
         read
         if upper(dc) = "V"
            loop
         elseif upper(dc) = "A"
            woquefazer = "ALT"
         elseif upper(dc) = "E"
            woquefazer = "EXC"
         endif
      else
         woquefazer = "INC"
      endif

      ******************************* exclusao
      if woquefazer = "EXC"
         msg_3 ( "Confirma a exclus„o do Lote " + rtrim(wlote) + " ? ... S/N ..." )
         if upper(dc) = "S"
            sele lotes
               set order to 1
               go top
            seek (wlote)
            if eof()
               alert ( "Erro - chamar CPD - registro n„o existe mais" )
            else
               delete
            endif
         endif
         loop
      endif

      ******************************* inclusao e alteracao
      set color to g+/n
         if woquefazer = "INC"
            @ 22,35 say "Registro Novo"
         elseif woquefazer = "ALT"
            @ 22,35 say "Edi‡„o de Registro"
         endif
      set color to w/n

      pede_campo = "01"
      preenche = "S"
      do while preenche = "S"

         if pede_campo = "01"
            msg_1 ( "Informe o ESTADO                            [branco] abandona" )
            @ 12,46 get westado pict "@!"
            read
            if westado = " "
               msg_3 ( "Deseja abandonar este registro ? ... S/N ..." )
               if upper(dc) = "S"
                  preenche = "ABANDONA"
               endif
               loop
            endif

            sele estado
               set order to 1
               go top
               seek (westado)
            if eof()
               alert ( "Estado n„o encontrado" )
               loop
            else
               set color to g+/n
                  @ 12,49 say estado
               set color to w/n
            endif
            pede_campo = "02"
         endif

         if pede_campo = "02"
            msg_1 ( "Informe a Data de Entrada                   [branco] retorna campo anterior" )
            @ 16,36 get wdt_entrada
            read
            if dtos(wdt_entrada) = space(08)
               pede_campo = "01"
            elseif wdt_entrada > date() .or. dtos(wdt_entrada) < "20150101"
               loop
            else
               pede_campo = "03"
            endif
         endif

         if pede_campo = "03"
            msg_1 ( "Informe o prazo em DIAS para devolu‡„o do lote" )
            @ 16,52 get wdias        pict "9999" valid wdias > 0
            read

            * calcula wdt_saida
            wdt_saida = wdt_entrada + wdias
            set color to g+/n
              @ 16,60 say wdt_saida
            set color to w/n
            pede_campo = "04"
         endif

         if pede_campo = "04"
            msg_1 ( "Informe a Quantidade e Pre‡o Unit rio         [zero] retorna campo anterior" )
            @ 20,36 get wqtde                pict "9,999.999" valid wqtde >= 0
            @ 20,48 get wvlr_unit            pict "9,999.999" valid wvlr_unit >= 0
            read

            if wqtde = 0
               pede_campo = "02"
            else
               * calcula wvlr_total
               wvlr_total = wqtde * wvlr_unit
               set color to g+/n
                  @ 20,60 say wvlr_total        pict "9,999,999.99"
               set color to w/n
               pede_campo = "CONFIRMA_DADOS"
            endif
         endif

         if pede_campo = "CONFIRMA_DADOS"
            msg_3 ( "Confirma os dados ? ... S/N ..." )
            if upper(dc) = "S"
               preenche = "DADOS_OK"
            else
               msg_3 ( "Deseja continuar neste registro ? ... S/N ..." )
               if upper(dc) = "S"
                  pede_campo = "01"
                  loop
               endif
               preenche = "ABANDONA"
            endif
         endif
      enddo

      if preenche = "DADOS_OK"
         if woquefazer = "INC"
            sele lotes
            go bottom
            append blank
         elseif woquefazer = "ALT"
            sele lotes
               set order to 1
               go top
            seek (wlote)
            if eof()
               alert ( "Erro - chamar CPD - registro n„o existe mais" )
               loop
            endif
         endif
         rlock()
            replace lote         with wlote
            replace estado       with westado
            replace dt_entrada   with dtos(wdt_entrada)
            replace dias         with wdias
            replace dt_saida     with dtos(wdt_saida)
            replace qtde         with wqtde
            replace vlr_unit     with wvlr_unit
            replace vlr_total    with wvlr_total
         unlock
      endif
   enddo

*****************************************************************************
*****************************************************************************
proc msg_1 (w_msg)                  // Procedure: Mensagem Sistema SEM parada

   set color to w/n
      @ 24,01 say space(80)
   set color to gr+/n
      @ 24,03 say w_msg
   set color to w/n

return

*****************************************************************************
*****************************************************************************
proc msg_2 (w_msg)                  // Procedure: Mensagem Sistema COM parada

   set color to w/n
      @ 24,01 say space(80)
   set color to gr+/n
      @ 24,03 say w_msg
      inkey(0)
   set color to w/n
      @ 24,01 say space(80)            // Limpa apos a exibicao da mensagem

return

*****************************************************************************
*****************************************************************************
proc msg_3 (w_msg)                         // Procedure: Mensagem Com Retorno
                                           //          : SIM ou NAO
   set color to w/n
      @ 24,01 say space(80)
   set color to gr+/n
      dc = " "
      @ 24,03 say w_msg get dc pict "!" valid dc $ "SNsn"
      read
   set color to w/n
      @ 24,01 say space(80)            // Limpa apos a exibicao da mensagem

return

*****************************************************************************
*****************************************************************************
func datavol4                    // Funcao: Converte AAAAMMDD para dd/mm/aaaa
   * para chamar esta rotina:
   *        variavel = datavol4(campo texto no formato aaaammdd)
   *        a variavel acabou de ser criada como data
   *        deixar sempre SET CENTURY ON - trabalhar com 4 casas no ano
   *        quando gravar, utilizar DTOS(variavel data)
   *        portanto, no DBF o campo data sera TEXTO de 8 posicoes

   set century on
   parameters wdv_data
   w_data_dv = ctod(subst(wdv_data,7,2)+"/"+subst(wdv_data,5,2)+"/"+subst(wdv_data,1,4))

return (w_data_dv)

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 20:56
por manuel1437
Caro José Quintas

Obrigado pelas respostas. O exemplo que montei, na verdade, visava ser o mais direto e linear possível, sem usar muitas funções, com o uso de muitas variáveis e algumas rotinas que devem ser condensadas através de boas técnicas de programação. Eu sabia que haveria a liberação da memória, por isso coloquei aquele memory() ali para mostrar o tamanho do ganho (aliás, num computador em que testei tinha.. 70kb de memória livre, rs).

A consulta usando o dbedit foi a última coisa que resolvi colocar, até para aproveitar para ter dois prg e assim usar um @lnk - claro que o sistema não se resolveria em dois prg (tenho sistema com mais de 250 prg, mesmo usando funções), de modo que fazer tudo numa única linha seria inviável (dai o questionamento sobre o lnk). Para falar a verdade, se tem algo que raramente uso é o dbedit - aqui eu padronizei gerar o relatorio tanto para impressora quanto para tela (que na verdade é a impressão para um arquivo padrao.txt e a visualização com um pequeno programa dos chamado lis.com, que permite exibir arquivos monstruosos com rapidez e alguns recursos). Certamente com o SQL não tem porque trafegar toda a base de dados (seria uma loucura,rs).

Você tem razão, a tela (caracter ou gráfica) não tem nada a ver com banco de dados. Mas a intenção inicial era continuar no ambiente caracter, porém acessando um mysql instalado remotamente, pois neste caso o primeiro aprendizado seria muito mais rápido e, inclusive, permitiria soluções urgentes para atender demandas de vida curta. Na segunda etapa, partiria para conhecer alguma ferramenta gráfica. Por isso que enfatizei o começo pela tela caracter + mysql.

Sobre as 1000 linhas, eu vi que existe um setmode() para criar a janela dos com um tamanho diferente do velho padrão 25x80. E o programinha tem como porta de saída deixar o campo lote em branco. Se branco, fim de programa. Ao longo do tempo, cansei de dar suporte em sistemas que usavam um fonte para inclusão, e outro para alteração do registro. Se mudasse uma regra, teria que alterá-la nos dois programas. Do jeito que montei o lote01.prg, altero esta regra uma única vez.

Mais uma vez, agradeço seu retorno. Tenho convivido com sistemas antigos ao longo destes últimos anos - para você ter idéia, dou suporte em uma plataforma chamada Superbase IV, software com banco de dados proprietário com telas gráficas que funcionam até no Windows 3.11, com algumas instruções SQL que convivem com modo linear de programação. Fiquei muito pra trás... já mexi alguma coisa com PHP, ASP ... mas confesso que faço (do meu jeito) com o velho Clipper coisas que não consigo fazer com as outras linguagens. Dai a resistência fica ainda maior. Hoje, eu me sentiria feliz em trocar o DBF pelo MYSQL num servidor lá do Japão, mesmo sabendo que tem muitas outras ferramentas. Um passo de cada vez...

Não sei se perdi alguma coisa, mas você escreveu "Se acompanhou meu post, estou fazendo justamente isso: DBF + MySQL ao mesmo tempo, até terminar." ... faltou um post ? Perdão, se puder postar o lote02.prg fazendo este tipo de acesso, é o ponto de partida que preciso para entrar no mundo Harbour.

Grande Abraço **** acabei de ver que ja postou mais duas mensagens, vou ler e responde-las imediatamente.

Manuel

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 21:10
por manuel1437
José Quintas

Eu tinha certeza de que alguém iria questionar porque não utilizar campos DATA no DBF para armazenar Datas ... é o óbvio! Sim, é verdade.

Mas a gente aprende na porrada, e se a solução dá certo, se acostumamos a ela. Quando rodava na velha Novell 3.11, eu tinha muitos, mas muitos mesmo, problemas com Corruption Detected. E isto acontecia com menor frequência (mas acontecia) com instalações na própria máquina. Descobri que 99,9% dos meus problemas aconteciam com índices compostos que usavam campos data..

Com índices string+str(valor) eu não tinha problemas
Com índices string+dtoc() ou string+dtos() ... dava CORRUPTION DETECTED.

No momento em que comecei a guardar no BD a data no formato string, usado DTOS() - ACABOU O PROBLEMA !!!! Eu posso afirmar que aquele 0,1% de corrupcao de índices está ligado a queda de energia ou então porque houve transporte de arquivos DBF sem apagar e recriar os índices. Este problema não acontecerá num MYSQl ...

Meus sistemas fazem get com 2 dígitos no ano, e fazia sentido fazer a dobradinha na virada do milênio, rs ...

Agradeço sua atenção, e o objetivo é justamente o de quebrar barreiras. Um passo de cada vez... tenho absoluta certeza que vamos desprezar muita coisa do fonte "original", mas esta transformação é interessante. Vou evoluir.

Obrigado

Manuel

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 21:36
por JoséQuintas
Esquisito isso de erro em índice com data.
Na Novell 3.11 tinha um bug que se ficasse mais de 1 semana no ar, o DBF acusava um registro a mais, dava erro em APPEND e provavelmente em índice.
Mas juntando isso da Novell com o fonte usando PROCEDURE, provavelmente esse fonte vém desde antes de existir o Clipper 5.
Antes não existia FUNCTION, e nem sei se eles estavam preparados para o ano 2000, então a opção da época seria fazer algo assim.

Seguindo...
Isto é só pra reduzir os próximos posts. Separei duas partes em função.
Já formatei... como comentei... virou vício.

Esta não vai mudar. Mostra dados na tela. Então já não vou repetir nos próximos.

STATIC FUNCTION TelaInicial()
   @ 07,59 SAY "CLIPPER BASICO"
   @ 03,01 SAY "PROC01 Clipper               ³"
   @ 04,01 SAY "                             ³"
   @ 05,01 SAY "PROC11 Harbour Local  DBF    ³"
   @ 06,01 SAY "PROC12 Harbour Remoto DBF    ³"
   @ 07,01 SAY "PROC13 Harbour Remoto MYSQL  ³"
   @ 08,01 SAY "                             ³"
   @ 09,01 SAY "PROC21 xHarbour Local  DBF   ³"
   @ 10,01 SAY "PROC22 xHarbour Remoto DBF   ³"
   @ 11,01 SAY "PROC23 xHarbour Remoto MYSQL ³"
   @ 12,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
   @ 16,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
   @ 17,01 SAY "- Testando os campos b sicos ³"
   @ 18,01 SAY "- C lculo de Data + Dias     ³"
   @ 19,01 SAY "- Inclus„o/Altera‡„o/Exclus„o³"
   @ 20,01 SAY "- Uso DbEdit para Consulta   ³"
   @ 21,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
   RETURN NIL


Esta aqui é pra abrir arquivos. O melhor nome é "AbrirArquivos()".
Alguns não sabem, mas a declaração STATIC ajuda muuuuito.
Posso ter uma AbreArquivos() em cada módulo, e uma não interfere na outra.
Isso é bom pra não ficar inventando nomes.

Se o ALIAS é igual ao nome do arquivo, não precisa (USE LOTES ALIAS LOTES).
Não lembro quando, mas já tive mensagem de erro de ALIAS EM USO por usar desse jeito.
Talvez se o arquivo já estiver aberto.
Como não interessa também área A, B, C, podemos usar SELECT 0.
E por falar nisso, faltou o CLOSE DATABASES no final do fonte principal.

STATIC FUNCTION AbreArquivos()
   SELECT 0
   USE LOTES
   INDEX ON lote                                TO ilote1
   INDEX ON estado+lote+dt_entrada              TO ilote2
   INDEX ON dt_entrada+lote                     TO ilote3
   INDEX ON dt_saida+lote                       TO ilote4
   SET INDEX TO ilote1, ilote2, ilote3, ilote4
   SELECT 0
   USE estado
   INDEX ON sigla_uf                            TO iuf1
   SET INDEX TO iuf1
   RETURN NIL


Pra isso funcionar, alterei o início do fonte, já acrescentando uma necessidade pro Harbour SetMode(25,80).
Continua funcionando no Harbour e no Clipper.

PROCEDURE Main
   set date brit
   set epoch to 2001
   set delete on
   SetMode(25,80)
   clear
   TelaInicial()
   AbreArquivos()
   @ 02,01 to 02,80
   @ 23,01 to 23,80
   ...
   CLOSE DATABASES


No Clipper, agora precisa acrescentar /n na compilação, o que é default no Harbour.

clipper lote01 c_lote /n
rtlink fi lote01 c_lote


No Harbour continua igual:

hbmk2 lote01 c_lote


Reparei numa coisa: provavelmente este fonte foi iniciado no Clipper Summer ou antes.
Antigamente o Clipper não tinha opção de criar função, e era tudo PROCEDURE, mesmo retornando valor.
Não existia FUNCTION no fonte, só PROCEDURE.
O cliente sempre pede tudo urgente, nem sempre dá tempo de revisar fontes.
Ainda mais se o sistema for grande, com muitos fontes, e cada cliente tiver o seu.

No meu caso cheguei a um único EXE pra todos os clientes. Então compensa melhorar, sempre mexo nos mesmos fontes.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 22:05
por JoséQuintas
Uma coisa que dá pra melhorar: cores
altera, volta, altera, volta
Vamos assumir a cor default do sistema como padrão.
E o SAY aceita colocar cor.

Então dá pra reduzir isto:
FUNCTION msg_1( w_msg )                  // Procedure: Mensagem Sistema SEM parada
   set color to w/n
   @ 24,01 say space(80)
   set color to gr+/n
   @ 24,03 say w_msg
   set color to w/n
   RETURN NIL


pra isto.

FUNCTION Msg_1( w_Msg )
   @ 24, 01 SAY Space(80)
   @ 24, 03 SAY w_Msg COLOR GR+/N
   RETURN NIL


Ou melhor ainda.... já mexer nos nomes.
Lembrando que em função, a variável passada é local, e podemos alterar à vontade os nomes dentro da função sem precisar mexer no resto do programa.

FUNCTION Msg( cTexto )
   @ 24, 01 SAY Space(80)
   @ 24, 03 SAY cTexto COLOR GR+/N
   RETURN NIL

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 22:26
por alxsts
Olá!

Ou melhor ainda:
FUNCTION Msg( cTexto )
      RETURN ( DispOutAt( MaxRow(), 0, PadR( "  " + Left( RTrim( cTexto ), MaxCol() - 2), MaxCol() ), "GR+/N", .F. ) )


Ou melhor ainda:
FUNCTION Msg( cTexto, nRow, nCol, cColor )
      RETURN ( DispOutAt( nRow, nCol, PadR( "  " + Left( RTrim( cTexto ), MaxCol() - 2), MaxCol() ), cColor, .F. ) )


Edit: este código evita o carregamento de todo o Get System, caso o objetivo seja apenas mostrar uma mensagem na tela.

DispotAt()

P.S.
Quintas: suas mensagens ainda estão aparecendo com o horário de verão ativo.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 22:54
por JoséQuintas
Até pensei nisso, mas apesar de ser comum pra muitos, pode parecer complicado pra quem não está acostumado.
Conheci um programador Clipper no ano passado que até hoje não sabe o que é criar função, mesmo trabalhando com Clipper desde o tempo da Novell. Então estou procurando evitar mudança radical.

Sobre o horário de verão, no Windows está marcando que vai mudar o horário em outubro.
Devo desativar mesmo estando tudo ok?

Continuando:
A alteração da mensagem Sim/Não foi mais legal.

FUNCTION msg_3(w_msg)                         // Procedure: Mensagem Com Retorno
   //          : SIM ou NAO
   @ 24,01 SAY space(80)
   dc = " "
   @ 24,03 SAY w_msg COLOR "GR+/N" get dc pict "!" valid dc $ "SNsn"
   read
   @ 24,01 SAY space(80)            // Limpa apos a exibicao da mensagem
   return NIL


Mudou pra isto:

FUNCTION MsgSimNao( cTexto )                         // Procedure: Mensagem Com Retorno
   @ 24,01 SAY space(80)
   cResposta := " "
   @ 24,03 SAY cTexto COLOR "GR+/N" GET cResposta PICTURE "!" VALID cResposta $ "SN"
   READ
   @ 24,01 SAY space(80)            // Limpa apos a exibicao da mensagem
   RETURN cResposta == "S"


Mas... qual a diferença?

- Ao olhar o fonte, MsgSimNao() tá na cara que é sim ou não
- Se tem ! na picture, significa que a digitação vai ser em maiúscula, só precisa validar maiúscula
- As cores, igual à função anterior, não precisa mais (já tinha retirado)
- Como retorna verdadeiro ou falso, já elimina variáveis do fonte que a chamar, sem falar que exigir nome de variável igual é perigoso. Sempre deveria existir a variável DC antes de chamar a função. Não poderia mudar nenhum fonte ou a função pra um nome diferente. Poderia até usar variável por referência, pra não deixar nome de variável preso. Msg("Sim ou Nao", @dc )

No fonte que a chama, antes:

Msg_2( "sim ou nao" )
IF dc = 'S" // obriga que Msg_2 use DC


Depois:

IF MsgSimNao( "Sim ou Nao" )


Lembrando:
Estou usando o fonte como exemplo.
Uma forma de substituir um "não consigo compilar com Harbour" por um "estou melhorando cada vez mais meus fontes".
Aconteça o que acontecer, seu trabalho está indo em frente e cada vez melhor.
E reduzindo fontes, cada vez menos código pra ter problema, mais fácil de alterar, e menos fonte pra converter pra alguma coisa nova.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 23:08
por alxsts
Olá!

JoséQuintas escreveu:Sobre o horário de verão, no Windows está marcando que vai mudar o horário em outubro.
Devo desativar mesmo estando tudo ok?

Você deve alterar no Painel de Controle do Usuário do próprio fórum e não do Windows. É só desmarcar a opção "Horário de Verão ativado:" na aba "Preferências do Fórum".

Quanto ao código, aí vai da preferência de cada um. Prefiro usar código compacto, com os melhores recursos da linguagem. DispOuAt() já usava desde os tempos do Clipper, apesar de ser uma função não documentada.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 21 Mai 2015 23:33
por JoséQuintas
Agora uma mudança radical nos GETS.
Usar o mais comum: todos os GETs de uma vez e ESC pra sair
Pra isso, vou ter que facilitar a validação de estado.
No fonte, depois do GET tá assim:

            sele estado
            set order TO 1
            go top
            seek (westado)
            if eof()
               alert ( "Estado n„o encontrado" )
               loop
            else
               SET COLOR TO g+/n
               @ 12,49 SAY estado
               SET COLOR TO w/n
            endif


Vou complicar um pouco também, mas só um pouco.
Criar uma função.
Na função vai pegar a área atual: Select(), pra poder selecionar estado, e depois voltar pra que estava antes.
Usar o mesmo fonte acima.

STATIC FUNCION EstadoOk( cEstado )
   LOCAL nSelect := Select(), lOk := .T.
   sele estado
   set order TO 1
   seek (westado)
   if eof()
      alert ( "Estado n„o encontrado" )
      lOk := .F.
   else
      @ 12,49 SAY estado COLOR "GR/N"
   endif
   SELECT ( nSelect )
   RETURN lOk


Isso vai permitir usar GET cEstado VALID EstadoOk( cEstado )
Com isso, não vai precisar fazer um GET de cada vez, e vai simplificar mais.

Aproveitando....
Na hora de criar funções, comece por essa parte, de retornar ao que estava antes.
Se a função precisar mudar a cor, no final volta a que estava antes.
Se a função precisar mudar área de DBF, no final volta a que estava antes.
Se mudar índice, voltar o que estava antes.
Vantagem: Não importa o que aconteça, sempre volta o que estava antes, então vai poder usar a função em qualquer outro fonte.

Tudo bem, é coisa meio básica, mas nem sempre a gente lembra de fazer isso, ou nem sempre acha que vai precisar depois.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 00:07
por JoséQuintas
Não costumo usar isso, e talvez esteja me confundindo.

SET MESSAGE TO 24 CENTER
@ 2, 3 GET variavel MESSAGE "teste"
READ


Esqueci de alguma coisa? Não está aparecendo a mensagem.
Conferi no std.ch e a sintaxe parece estar correta.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 00:19
por JoséQuintas
Deixando de lado esse imprevisto, o fonte de 75 para GET se reduziram a estas linhas:

      @ 12, 46 GET wEstado PICTURE "@!" VALID EstadoOk( wEstado ) MESSAGE "Informe o ESTADO, ESC abandona"
      @ 16, 36 GET wDt_Entrada          VALID Dtos( wDt_Entrada ) >= "20150101" .AND. wDt_Entrada <= Date() MESSAGE "Informe a Data de Entrada, ESC abandona"
      @ 16, 52 GET wDias PICTURE "9999" VALID wDias > 0 MESSAGE "Informe a qtde. de dias, ESC abandona"
      @ 16, 60 GET wDt_Saida WHEN ( wDt_Saida := wDt_Entrada + wDias, .F. )
      @ 20, 36 get wqtde                PICTURE "9,999.999" valid wqtde >= 0 MESSAGE "Informe a Quantidade, ESC abandona"
      @ 20, 48 get wvlr_unit            PICTURE "9,999.999" valid wvlr_unit >= 0 MESSAGE "Informe o valor unitário, ESC abandona"
      @ 20, 60 GET wVlr_Total PICTURE "9,999,999.99" WHEN ( wVlr_Total := wQtde * wVlr_Unit, .F. )
      READ
      Inkey(3)


MESSAGE já troca a mensagem embaixo
VALID já confere o conteúdo
A qualquer momento pode ser digitado ESC pra abandonar
Os cálculos já são feitos automaticamente usando WHEN ( calculo, .F. )
Os resultados já aparecem automaticamente, e WHEN .F. não deixa mexer
Só acrescentei um Inkey(3) pra permitir ver o total que foi calculado.

E o confirme?
O usuário pode passear à vontade nas informações, tem durante toda digitação pra conferir, acho que dá pra eliminar o confirme.
Senão... usamos a função MsgSimNao()

Muito fonte a menos pra mexer, e até que não complicou tanto.
Só nisso, reduziu de 75 linhas pra 9.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 00:38
por JoséQuintas
Só comentário: página com muitos fontes fica lenta pra editar.

Continuando...
Usei um truque básico numa parte do fonte, e mexi um pouco com as cores.

SET COLOR TO W/N,W/GR+,,,G+/N
...
@ 12,46 GET westado
@ 16,36 GET wdt_entrada
@ 16,52 GET wdias        pict "9999"
@ 16,60 GET wdt_saida
@ 20,36 GET wqtde        pict "9,999.999"
@ 20,48 GET wvlr_unit    pict "9,999.999"
@ 20,60 GET wvlr_total   pict "9,999,999.99"
CLEAR GETS


GET sem GET.
Pra que serve?
Como defini cor diferente pra GET fora de foco, o resultado é isso em cores diferentes.

Vantagem: pra mudar todas as cores, só precisa mudar a primeira linha e nada mais.
GET em foco de uma cor, GET fora de foco de outra cor, e tela de outra.
Com um único SET COLOR, já temos cores diferentes, sem precisar indicar cor no fonte.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 00:43
por JoséQuintas
Na consulta alterei pouco:

   LOCAL nSelect := Select()
   LOCAL cOrdSetFocus
   SELECT LOTES
   cOrdSetFocus := OrdSetFocus()
...
   OrdSetFocus( cOrdSetFocus )
   SELECT ( nSelect )


- guarda em que ALIAS estava posicionado quando chegou nele
- guarda a ordem usada em LOTES quando chegou nele
Depois de fazer o que precisa
- volta LOTES pra ordem que estava
- volta ao ALIAS que estava

Como se nada tivesse acontecido.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 00:55
por JoséQuintas
Vou parar as mudanças por aqui.
A próxima etapa vai ser alterar pra MySQL.
Como uso ADO, vai ser com ele.
O fonte pra DBF terminou assim.
#include "inkey.ch"

PROCEDURE Main
   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
   TelaInicial()
   AbreArquivos()
   @ 02,01 TO 02,80
   @ 23,01 TO 23,80
   @ 01,01 SAY space(80) COLOR "W/B"
   @ 01,01 SAY "LOTES - Aprendizado Harbour e xHarbour" COLOR "W/B"
   @ 01,70 SAY date() COLOR "W/B"
   memoria = memory()
   @ 03,54 SAY memory() pict "9,999,999,999"
   @ 03,68 SAY "Kb Mem¢ria"
   dc = " "
   // OPERACAO

   do while .t.

      wlote       = space(07)
      westado     = space(02)
      wdt_entrada = datavol4(space(08))
      wdias       = 0
      wdt_saida   = datavol4(space(08))
      wqtde       = 0
      wvlr_unit   = 0
      wvlr_total  = 0
      Msg(  "Informe o LOTE                              [branco] finaliza" )
      @ 09,34 SAY "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
      @ 10,34 SAY "³ Lote....: °°°°°°          ? Pesquisa ³"
      @ 11,34 SAY "³                                      ³"
      @ 12,34 SAY "³ Estado..: °° °°°°°°°°°°°°°°°°°°°     ³"
      @ 13,34 SAY "³                                      ³"
      @ 14,34 SAY "³   Entrada       Dias     Devolu‡„o   ³"
      @ 15,34 SAY "³ ÄÄÄÄÄÄÄÄÄÄ      ÄÄÄÄ    ÄÄÄÄÄÄÄÄÄÄ   ³"
      @ 16,34 SAY "³ °°/°°/°°°°   +  °°°°  = °°/°°/°°°°   ³"
      @ 17,34 SAY "³                                      ³"
      @ 18,34 SAY "³    Qtde      Unit rio    Valor Total ³"
      @ 19,34 SAY "³ ÄÄÄÄÄÄÄÄÄ   ÄÄÄÄÄÄÄÄÄ   ÄÄÄÄÄÄÄÄÄÄÄÄ ³"
      @ 20,34 SAY "³ °°°°°°°°° x °°°°°.°°° = °°°°°°°°°.°° ³"
      @ 21,34 SAY "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
      @ 22,34 SAY "                                        "

      @ 10,46 get wlote pict "@!"
      read
      if Empty( wlote ) .OR. LastKey() == K_ESC
         clear
         EXIT
      endif
      if wlote = "?"
         consulta()
         loop
      endif

      // consulta
      sele lotes
      seek wlote
      if .not. eof()
         westado     = estado
         wdt_entrada = datavol4(dt_entrada)
         wdias       = dias
         wdt_saida   = datavol4(dt_saida)
         wqtde       = qtde
         wvlr_unit   = vlr_unit
         wvlr_total  = vlr_total
         @ 12,46 GET westado
         @ 16,36 GET wdt_entrada
         @ 16,52 GET wdias        pict "9999"
         @ 16,60 GET wdt_saida
         @ 20,36 GET wqtde        pict "9,999.999"
         @ 20,48 GET wvlr_unit    pict "9,999.999"
         @ 20,60 GET wvlr_total   pict "9,999,999.99"
         CLEAR GETS
         EstadoOk( wEstado ) // mesma da validação
         Msg( "Registro existente. Deseja Alterar, Excluir ou Voltar ? ... A/E/V ..." )
         @ 24,73 get dc pict "!" valid dc $ "AEV"
         read
         if upper(dc) = "V" .OR. LastKey() == K_ESC
            loop
         elseif upper(dc) = "A"
            woquefazer = "ALT"
         elseif upper(dc) = "E"
            woquefazer = "EXC"
         endif
      else
         woquefazer = "INC"
      endif

      // exclusao
      if woquefazer = "EXC"
         IF MsgSimNao( "Confirma a exclus„o do Lote " + rtrim(wlote) + " ? ... S/N ..." )
            sele lotes
            seek wlote
            if eof()
               alert ( "Erro - chamar CPD - registro n„o existe mais" )
            else
               delete
            endif
         endif
         loop
      endif

      // inclusao e alteracao
      if woquefazer = "INC"
         @ 22,35 SAY "Registro Novo" COLOR "GR+/N"
      elseif woquefazer = "ALT"
         @ 22,35 SAY "Edição de Registro" COLOR "GR+/N"
      endif

      @ 12, 46 GET wEstado PICTURE "@!" VALID EstadoOk( wEstado ) MESSAGE "Informe o ESTADO, ESC abandona"
      @ 16, 36 GET wDt_Entrada          VALID Dtos( wDt_Entrada ) >= "20150101" .AND. wDt_Entrada <= Date() MESSAGE "Informe a Data de Entrada, ESC abandona"
      @ 16, 52 GET wDias PICTURE "9999" VALID wDias > 0 MESSAGE "Informe a qtde. de dias, ESC abandona"
      @ 16, 60 GET wDt_Saida WHEN ( wDt_Saida := wDt_Entrada + wDias, .F. )
      @ 20, 36 get wqtde                PICTURE "9,999.999" valid wqtde >= 0 MESSAGE "Informe a Quantidade, ESC abandona"
      @ 20, 48 get wvlr_unit            PICTURE "9,999.999" valid wvlr_unit >= 0 MESSAGE "Informe o valor unitário, ESC abandona"
      @ 20, 60 GET wVlr_Total PICTURE "9,999,999.99" WHEN ( wVlr_Total := wQtde * wVlr_Unit, .F. )
      READ
      Inkey(3)

      if LastKey() != K_ESC
         if woquefazer = "INC"
            sele lotes
            append blank
         elseif woquefazer = "ALT"
            sele lotes
            seek (wlote)
            if eof()
               alert ( "Erro - chamar CPD - registro n„o existe mais" )
               loop
            endif
         endif
         rlock()
         replace lote         with wlote
         replace estado       with westado
         replace dt_entrada   with dtos(wdt_entrada)
         replace dias         with wdias
         replace dt_saida     with dtos(wdt_saida)
         replace qtde         with wqtde
         replace vlr_unit     with wvlr_unit
         replace vlr_total    with wvlr_total
         unlock
      endif
   enddo
   CLOSE DATABASES
   RETURN

FUNCTION Msg( cTexto )
   @ 24,01 SAY space(80)
   IF cTexto != NIL
      @ 24,03 SAY cTexto COLOR "GR+/N"
   ENDIF
   RETURN NIL

FUNCTION MsgPausa( cTexto )
   Msg( cTexto )
   inkey(0)
   Msg()
   RETURN NIL

FUNCTION MsgSimNao( cTexto )
   Msg( cTexto )
   @ Row(), Col() + 2 GET cResposta PICTURE "!" VALID cResposta $ "SN"
   READ
   Msg()
   RETURN cResposta

FUNCTION datavol4( wdv_Data )
   //set century on
   w_data_dv = ctod(subst(wdv_data,7,2)+"/"+subst(wdv_data,5,2)+"/"+subst(wdv_data,1,4))
   return w_data_dv

STATIC FUNCTION TelaInicial()
   @ 07,59 SAY "CLIPPER BASICO"
   @ 03,01 SAY "PROC01 Clipper               ³"
   @ 04,01 SAY "                             ³"
   @ 05,01 SAY "PROC11 Harbour Local  DBF    ³"
   @ 06,01 SAY "PROC12 Harbour Remoto DBF    ³"
   @ 07,01 SAY "PROC13 Harbour Remoto MYSQL  ³"
   @ 08,01 SAY "                             ³"
   @ 09,01 SAY "PROC21 xHarbour Local  DBF   ³"
   @ 10,01 SAY "PROC22 xHarbour Remoto DBF   ³"
   @ 11,01 SAY "PROC23 xHarbour Remoto MYSQL ³"
   @ 12,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
   @ 16,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
   @ 17,01 SAY "- Testando os campos b sicos ³"
   @ 18,01 SAY "- C lculo de Data + Dias     ³"
   @ 19,01 SAY "- Inclus„o/Altera‡„o/Exclus„o³"
   @ 20,01 SAY "- Uso DbEdit para Consulta   ³"
   @ 21,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
   RETURN NIL

STATIC FUNCTION AbreArquivos()
   SELECT 0
   USE LOTES
   INDEX ON lote                                TO ilote1
   INDEX ON estado+lote+dt_entrada              TO ilote2
   INDEX ON dt_entrada+lote                     TO ilote3
   INDEX ON dt_saida+lote                       TO ilote4
   SET INDEX TO ilote1, ilote2, ilote3, ilote4
   SELECT 0
   USE estado
   INDEX ON sigla_uf                            TO iuf1
   SET INDEX TO iuf1
   RETURN NIL

STATIC FUNCTION EstadoOk( cEstado )
   LOCAL nSelect := Select(), lOk := .T.
   SELECT estado
   SEEK cEstado
   IF Eof()
      Alert ( "Estado não encontrado" )
      lOK := .F.
   ELSE
      @ 12,49 SAY estado COLOR "G+/N"
   ENDIF
   RETURN lOk

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 01:55
por JoséQuintas
Não testei.
Chamei o recordset de oTemporario, assim acho que fica mais claro que seria algo similar a um arquivo temporário.

#include "inkey.ch"

STATIC oConexao

PROCEDURE Main
   ConfiguraConexao()
   oConexao: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
   TelaInicial()
   @ 02,01 TO 02,80
   @ 23,01 TO 23,80
   @ 01,01 SAY space(80) COLOR "W/B"
   @ 01,01 SAY "LOTES - Aprendizado Harbour e xHarbour" COLOR "W/B"
   @ 01,70 SAY date() COLOR "W/B"
   memoria = memory()
   @ 03,54 SAY memory() pict "9,999,999,999"
   @ 03,68 SAY "Kb Mem¢ria"
   dc = " "
   // OPERACAO

   do while .t.

      wlote       = space(07)
      westado     = space(02)
      wdt_entrada = datavol4(space(08))
      wdias       = 0
      wdt_saida   = datavol4(space(08))
      wqtde       = 0
      wvlr_unit   = 0
      wvlr_total  = 0
      Msg(  "Informe o LOTE                              [branco] finaliza" )
      @ 09,34 SAY "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
      @ 10,34 SAY "³ Lote....: °°°°°°          ? Pesquisa ³"
      @ 11,34 SAY "³                                      ³"
      @ 12,34 SAY "³ Estado..: °° °°°°°°°°°°°°°°°°°°°     ³"
      @ 13,34 SAY "³                                      ³"
      @ 14,34 SAY "³   Entrada       Dias     Devolu‡„o   ³"
      @ 15,34 SAY "³ ÄÄÄÄÄÄÄÄÄÄ      ÄÄÄÄ    ÄÄÄÄÄÄÄÄÄÄ   ³"
      @ 16,34 SAY "³ °°/°°/°°°°   +  °°°°  = °°/°°/°°°°   ³"
      @ 17,34 SAY "³                                      ³"
      @ 18,34 SAY "³    Qtde      Unit rio    Valor Total ³"
      @ 19,34 SAY "³ ÄÄÄÄÄÄÄÄÄ   ÄÄÄÄÄÄÄÄÄ   ÄÄÄÄÄÄÄÄÄÄÄÄ ³"
      @ 20,34 SAY "³ °°°°°°°°° x °°°°°.°°° = °°°°°°°°°.°° ³"
      @ 21,34 SAY "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
      @ 22,34 SAY "                                        "

      @ 10,46 get wlote pict "@!"
      read
      if Empty( wlote ) .OR. LastKey() == K_ESC
         clear
         EXIT
      endif
      if wlote = "?"
         consulta()
         loop
      endif

      // consulta
      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
         @ 12,46 GET westado
         @ 16,36 GET wdt_entrada
         @ 16,52 GET wdias        pict "9999"
         @ 16,60 GET wdt_saida
         @ 20,36 GET wqtde        pict "9,999.999"
         @ 20,48 GET wvlr_unit    pict "9,999.999"
         @ 20,60 GET wvlr_total   pict "9,999,999.99"
         CLEAR GETS
         EstadoOk( wEstado ) // mesma da validação
         Msg( "Registro existente. Deseja Alterar, Excluir ou Voltar ? ... A/E/V ..." )
         @ 24,73 get dc pict "!" valid dc $ "AEV"
         read
         if upper(dc) = "V" .OR. LastKey() == K_ESC
            loop
         elseif upper(dc) = "A"
            woquefazer = "ALT"
         elseif upper(dc) = "E"
            woquefazer = "EXC"
         endif
      else
         woquefazer = "INC"
      endif
      oTemporario:Close()
      // exclusao
      if woquefazer = "EXC"
         IF MsgSimNao( "Confirma a exclus„o do Lote " + rtrim(wlote) + " ? ... S/N ..." )
            oTemporario := oConexao:Execute( "SELECT COUNT(*) AS QTD FROM LOTES WHERE LOTE=" + Ltrim( Str( wLote ) ) )
            IF oTemporario:Fields( "QTD" ):Value == 0
               alert ( "Erro - chamar CPD - registro n„o existe mais" )
            else
               oConexao:Execute( "DELETE FROM LOTES WHERE LOTE=" + Ltrim( Str( wLote ) ) )
            endif
            oTemporario:Close()
         endif
         loop
      endif

      // inclusao e alteracao
      if woquefazer = "INC"
         @ 22,35 SAY "Registro Novo" COLOR "GR+/N"
      elseif woquefazer = "ALT"
         @ 22,35 SAY "Edição de Registro" COLOR "GR+/N"
      endif

      @ 12, 46 GET wEstado PICTURE "@!" VALID EstadoOk( wEstado ) MESSAGE "Informe o ESTADO, ESC abandona"
      @ 16, 36 GET wDt_Entrada          VALID Dtos( wDt_Entrada ) >= "20150101" .AND. wDt_Entrada <= Date() MESSAGE "Informe a Data de Entrada, ESC abandona"
      @ 16, 52 GET wDias PICTURE "9999" VALID wDias > 0 MESSAGE "Informe a qtde. de dias, ESC abandona"
      @ 16, 60 GET wDt_Saida WHEN ( wDt_Saida := wDt_Entrada + wDias, .F. )
      @ 20, 36 get wqtde                PICTURE "9,999.999" valid wqtde >= 0 MESSAGE "Informe a Quantidade, ESC abandona"
      @ 20, 48 get wvlr_unit            PICTURE "9,999.999" valid wvlr_unit >= 0 MESSAGE "Informe o valor unitário, ESC abandona"
      @ 20, 60 GET wVlr_Total PICTURE "9,999,999.99" WHEN ( wVlr_Total := wQtde * wVlr_Unit, .F. )
      READ
      Inkey(3)

      if LastKey() != K_ESC
         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 ) ) )
      endif
   enddo
   oConexao:Close()
   RETURN

FUNCTION Msg( cTexto )
   @ 24,01 SAY space(80)
   IF cTexto != NIL
      @ 24,03 SAY cTexto COLOR "GR+/N"
   ENDIF
   RETURN NIL

FUNCTION MsgPausa( cTexto )
   Msg( cTexto )
   inkey(0)
   Msg()
   RETURN NIL

FUNCTION MsgSimNao( cTexto )
   Msg( cTexto )
   @ Row(), Col() + 2 GET cResposta PICTURE "!" VALID cResposta $ "SN"
   READ
   Msg()
   RETURN cResposta

FUNCTION datavol4( wdv_Data )
   //set century on
   w_data_dv = ctod(subst(wdv_data,7,2)+"/"+subst(wdv_data,5,2)+"/"+subst(wdv_data,1,4))
   return w_data_dv

STATIC FUNCTION TelaInicial()
   @ 07,59 SAY "CLIPPER BASICO"
   @ 03,01 SAY "PROC01 Clipper               ³"
   @ 04,01 SAY "                             ³"
   @ 05,01 SAY "PROC11 Harbour Local  DBF    ³"
   @ 06,01 SAY "PROC12 Harbour Remoto DBF    ³"
   @ 07,01 SAY "PROC13 Harbour Remoto MYSQL  ³"
   @ 08,01 SAY "                             ³"
   @ 09,01 SAY "PROC21 xHarbour Local  DBF   ³"
   @ 10,01 SAY "PROC22 xHarbour Remoto DBF   ³"
   @ 11,01 SAY "PROC23 xHarbour Remoto MYSQL ³"
   @ 12,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
   @ 16,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
   @ 17,01 SAY "- Testando os campos b sicos ³"
   @ 18,01 SAY "- C lculo de Data + Dias     ³"
   @ 19,01 SAY "- Inclus„o/Altera‡„o/Exclus„o³"
   @ 20,01 SAY "- Uso DbEdit para Consulta   ³"
   @ 21,01 SAY "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"
   RETURN NIL

STATIC FUNCTION EstadoOk( cEstado )
   LOCAL oTemporario, lOk := .T.
   oTemporario := oConexao:Execute( [SELECT * FROM ESTADO WHERE ESTADO='] + cEstado + ['] )
   IF oTemporario:RecordCount() == 0
      Alert ( "Estado não encontrado" )
      lOK := .F.
   ELSE
      @ 12,49 SAY oTemporario:Fields( "ESTADO" ):Value COLOR "G+/N"
   ENDIF
   oTemporario:Close()
   RETURN lOk

STATIC FUNCTION ConfiguraConexao()
   oConexao := win_OleCreateObject( "ADODB.Connection" )
   oConexao:ConnectionString := "Driver={MySQL ODBC 3.51 Driver};Server=NomeServidor;" + ;
      "Option=131072;Stmt=;Database=NomeBanco;User ID=NomeUsuario;Password=Senha;Collation=latin1;"
   oConexao:CursorLocation    := 3   // local recordset
   oConexao:CommandTimeOut    := 120 // seconds
   oConexao:ConnectionTimeOut := 120 // seconds
   RETURN NIL


Considerações:

oTemporario:Fields( "NOME" ):Value
Isso equivale a pegar o conteúdo do campo chamado NOME

oTemporario:RecordCount()
O próprio nome já diz. Contador de registros. Quantos registros foram retornados.
Uma diferença no ADO é que não se pode testar EOF em arquivo vazio., dá erro. A saída é usar o RecordCount()

oTemporario:Close()
Seria o equivalente a apagar o temporário. Na prática não existe nada em disco.

oTemporario := oConexao:Execute( ... )
Vai executar o comando na conexão. O retorno vai ser o equivalente a um arquivo temporário contendo registros ou não.

oConexao:Open()
Abre a conexão, é por essa conexão que o terminal conversa com o servidor, e vice-versa.

oConexao:Close()
Encerra a conexão.

INSERT INTO LOTES ( CAMPO ) VALUES ( VALOR )
Inclui um registro na tabela LOTES, gravando no CAMPO o VALOR.

UPDATE LOTES SET CAMPO=VALOR WHERE LOTE=x
Atualiza no arquivo LOTES, aonde o LOTE for número x, alterando o CAMPO para VALOR

DELETE FROM LOTES WHERE LOTE=x
Apaga do arquivo LOTES, aonde o LOTE for número x

De resto, no SQL string é entre aspas simples, e número é direto o número.
Por isso no comando SQL tem que acrescentar aspas, ou transformar o número em string pra ter a linha de comando.

No meu caso, preferi usar funções pra esse tipo de coisa.
Exemplo: StringSql( campo )

FUNCTION StringSql( cCampo )
   RETURN ['] + cCampo + [']


Além de evitar erro nos abrir/fechar aspas, já coloco tratamento de alguns caracteres especiais.

No browse, teria que fazer uma conversão total de oTemporario pra DBF.

dbCreate( "TEMP", ...estrutura )
USE TEMP
oTemporario := oConexao:Execute( "SELECT * FROM LOTES" )
IF oTemporario:RecordCount() > 0
   DO WHILE .NOT. oTemporario:Eof()
      APPEND BLANK
      REPLACE temp->Lote WITH oTemporario:Fields( "LOTE" ):Value, ;
         temp->Dt_Entrada WITH oTemporario:Fields( "DT_ENTRADA" ):Value, ;
         ...
      oTemporario:MoveNext()
   ENDDO
ENDIF
oTemporario:Close()


oTemporario:MoveNext() é o equivalente de SKIP.

No momento com ADO estou usando esse esquema, estilo arquivo temporário, e convertendo se necessário.

Ah sim... a compilação do fonte final em Harbour:

hbmk2 lote01 c_lote hbwin.hbc

O outro fonte c_Lote:
Teria que ter a rotina acima, e o restante fica igual, mas tendo que criar os índices também como temporários.
A diferença é não ter que salvar/retornar área em uso, porque não existe.

Pra arquivos gigantes, o ideal seria primeiro pedir algum tipo de filtro, para só depois mostrar para o usuário.
O que mudaria pro temporário, seria sua criação mais rápida, com menos registros.

oTemporario := "SELECT * FROM LOTES WHERE DT_ENTRADA >= '20150101' AND DT_ENTRADA <= '20150131'"

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 02:09
por JoséQuintas
Apesar de já ter dito antes, talvez seja melhor escrever de novo:
Esse modo é sem usar nenhuma biblioteca do Harbour, não depende de nada adicional.
Por isso o browse precisa da conversão.

Se usar alguma biblioteca do Harbour, pode ser que facilite alguma coisa.
Quando testei RDDADO deu erro no browse, então preferi ir em frente sem depender de nada, só de mim mesmo.
Sobre bibliotecas do Harbour pra isso, aí vai de quem use pra poder passar informações.

Mas seria interessante pra todos, talvez até pra mim mesmo, que usuários de LIBs mostrassem esse último fonte em DBF (mais enxuto) convertido pra alguma LIB existente no Harbour.

Pelo jeito é uma boa hora pra divulgar, já que o interesse em MySQL está aumentando.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 02:20
por JoséQuintas
Último comentário:
No fonte inicial, haviam duas validações de estado, uma no SAY e outra no GET.
Enxugar o fonte antes, reduziu isso pra uma única função.
E na hora de transformar isso pra MySQL, foi só transformar num único lugar.

Ou seja, é como se eu já estivesse melhorando pro MySQL antes mesmo de mexer com ele.

E não tem como eu não repetir:
Melhorando os fontes, está melhorando pra qualquer coisa que fizer depois.
Se um único fonte já fez diferença, um aplicativo inteiro com muitos fontes vai fazer muito mais diferença.

Este foi o motivo de eu ter usado esse fonte como exemplo.
Acho que serviu bem pra demonstrar que nem sempre sair convertendo é uma melhor opção.
E o tempo de conversão depende muito de como está o fonte.

Tá desanimando pra converter porque tá difícil...
Tudo bem: vá melhorando o fonte, que já vai estar adiantando o serviço, e vai ficar animado.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 22 Mai 2015 09:23
por JoséQuintas
Faltou fechar parênteses na no insert.

 oConexao:Execute( "INSERT INTO LOTES ( LOTE ) VALUES ( " + Ltrim( Str( wLote ) ) )


Isso vai gerar INSERT INTO LOTES ( LOTE ) VALUES ( 1

Faltou somar ")"

 oConexao:Execute( "INSERT INTO LOTES ( LOTE ) VALUES ( " + Ltrim( Str( wLote ) ) + ")" )


Sobre o horário, no painel de controle estava horário de Brasília, horário de verão desativado.
Ativei, depois mudei pra horário do Atlântico, depois voltei pra horário de Brasília..
Por último voltei ao que estava no início e ficou certo.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 23 Mai 2015 12:45
por JoséQuintas
Mais um comentário, sobre as rotinas de mensagem:

FUNCTION Msg( cTexto ) 
    @ 24,01 SAY space(80)
    IF cTexto != NIL
       @ 24,03 SAY cTexto COLOR "GR+/N"
    ENDIF
    RETURN NIL
   
FUNCTION MsgPausa( cTexto )
    Msg( cTexto )
    inkey(0)
    Msg()
    RETURN NIL
   
FUNCTION MsgSimNao( cTexto )
    Msg( cTexto )
    @ Row(), Col() + 2 GET cResposta PICTURE "!" VALID cResposta $ "SN"
    READ
    Msg()
    RETURN cResposta


Ok, dá pra simplificar mais, mas mesmo assim o resultado é:

Msg() acabou sendo usada pra mostrar mensagem, e limpar mensagem. E é usada pelas outras.
MsgPausa() e MsgSimNao() nem sequer sabem aonde é que a mensagem aparece.
Se quiser mudar o aplicativo pra mostrar a mensagem em uma posição diferente, basta alterar Msg()

Se alterar pra modo gráfico, de repente poderia colocar as mensagens em uma barra de status, bastando alterar a função Msg()

A Sim/Não também poderia ser trocada para a equivalente do Windows, já em modo gráfico.

Que coisa legal. Estávamos preparando até pra ambiente gráfico, sem nem pensar nisso.

Ah... mas eu preciso muitos SimNão, e usar direto no IF não dá, e posso precisar do "S" ou "N" pra replace...
Ok. Se for usar a mesma rotina de Sim/Nao, poderia fazer assim.
lContribuinte  := MsgSimNao( "Contribuinte ICMS Sim ou Não" )
lConfirma := MsgSimNao( "Tem certeza" )
IF lConfirma
   REPLACE CLIENTE->Contribuinte WITH iif( lContribuinte, "S", "N" )
ENDIF


Como saber se estou simplificando ou complicando?
Imagine ensinar alguém a usar suas funções.
Se for complicado ensinar uma função simples, então talvez sua função esteja complicada.
Se pra voce mesmo usar, voce tiver que ficar olhando detalhes da função ou variáveis, talvez ela esteja complicada - a não ser que realmente seja uma função que faz trabalho complicado e por isso precisa muitos detalhes.

A antiga função pra Sim/Não não estava boa.
Porque?
Era um simples Sim ou Não, mesmo assim precisava olhar na função que precisava de uma variável chamada DC.
Se é uma mensagem de Sim ou Não, mais fácil ela retornar "S" ou "N", ou verdadeiro/falso, o que a torna auto-explicativa.

Se o que estiver fazendo, estiver facilitando seu serviço, é sinal de que você está no caminho certo.

Melhorar fonte é:
- melhorar pra Harbour, sem mexer com Harbour
- melhorar pra parte gráfica, sem mexer com parte gráfica
- Facilitar programar, que é facilitar nosso trabalho

Na correria esquecemos disso, porque isso não faz diferença para o cliente.
Mas faz pra nós.
Evoluir na programação não significa trocar editor de texto, ou linguagem de programação.
Significa cada vez ser mais fácil programar.

Isso não tem a ver com anos de prática, tem a ver com "por em prática".
Não espere que seja mais fácil programar, faça ser mais fácil.
(Isso me lembrou a cena do Matriz da luta de karatê... rs)

Fui muito repetitivo e filosófico no post, mas acho que foi pra uma boa causa.
Espero que ajude algum usuário do fórum.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 31 Mai 2015 23:43
por manuel1437
Quintas e Amigos - Boa Noite

Quintas, MUITO OBRIGADO pela disposição em ensinar. Vou evoluir, com certeza.

1) Apanhei um pouco com a conexão com o Mysql ... Resolvi então limpar todo o programa e fazer um novo teste, que também não funcionou. Talvez algo esteja faltando em meu computador (XP), não sei. Utilizo uma outra ferramenta nesta maquina, chamada Scriptcase, que acessa a base MYSQL externa normalmente. Repeti exatamente o endereco da base MYSQL, o nome do Banco de Dados, o Usuario e a Senha de acesso. Nao coloquei aspas para identificar estas informacoes na String Conexao. Lá eu tinha que informar a Porta.

No site www.connectionstrings.com (muito bom, por sinal), vi como adicionar a porta 3306 na String de Conexão que você passou. E nada...

Error WINOLE/1007 [Microsoft][ODBC Driver Manager]
Nome da fonte de dados nao encontrado e nenhum driver padrao especificado (0x800004005): Microsoft OLE DB Provider for ODBC Drivers
(DOS Error -2147352567)

Até que descobri, rs... nao tinha o Driver ODBC instalado na minha maquina...
http://www.connectionstrings.com/mysql-
secao -download/ - instalei e resolveu meus problemas - ja enxergo via ADO o mysql remoto

Eu tinha gravado a tabela no MYSQL com o nome "cadastro" ... o programa ainda apresentava erros, ate perceber que no programa a instrucao SQL estava CADASTRO.
Coloquei em minuscula e ... resolveu ! CaseSensitive ... gravei os registros, alterei e exclui...

Outra coisa diferente do Clipper: o "alert" do erro estava aparecendo muito abaixo, criando uma barra de rolagem gigantesca na janela DOS.
Nao coloquei o SET MODE, mas estranhei este comportamento.
Uma duvida: no Clipper estavamos limitados a 25x80, agora eu posso fazer uma janela bem maior e usar @lin,col para aproveitar este espaco?

=============================================

Mas, pesquisando no Forum, tambem acabei encontrando por acaso uma discussao sadia entre ADO e SQLMIX (o Amigo Itamar pode ajudar com SQLMIX ?)

Vamos lá. Eis o programa anexo, que:
1) Abre Base
2) Gravacao
gravar 15 registros (coloquei um diferenciador no nome, Jose 1, Jose 2, Jose 3.... Jose 15), todos com idade 30
fiz no clipper um exemplo de inclusao com vetores. A ideia de usar os 3 vetores da Maria x é criar os 3 registros numa unica instrucao INSERT
3) Alteracao
alterar a idade o "Jose 11" para 50
4) Exclusao
excluir o "Jose 7"
5) Consulta e exibicao
listar todos os que tem idade 30 .. ou seja, 13 registros Jose ...
nao vira o Jose 11 pq tem 50 anos, e nao vira o "Jose 7", que foi excluido
e nao vira as Marias, que tem 25 anos...

ou seja, com isto a gente trabalha com as 4 operacoes indispensaveis la com o BD

Fiz o teste no ADO com INCLUSAO (so Jose), ALTERACAO e EXCLUSAO estao ok ... faltou a parte da consulta

Voce pode pegar o mesmo exemplo e escrever nele, no IF do ADO. Fiz um IF para separar o que existe para DBF e a instrucao equivalente no ADO e SQLMIX

Peco ao Itamar fazer o mesmo com o SQLMIX.

Estou usando o Harbour que baixei de http://sourceforge.net/projects/harbour ... p_redirect

Grande Abraco, agora eu aprendo, rs

Manuel

** Ao digitar este post, vi na Secao Harbour uma otima noticia, sob o titulo "PRG sendo executado na web como um PHP"

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 01 Jun 2015 01:13
por JoséQuintas
Com um modelo já pronto em DBF e ADO, acabou fazendo outro.... esquisito.
Acabou voltando a ter algo desnecessário: GOTO TOP antes do SEEK.
Fazer direto no post a consulta que falta:

wpesq = 30
if wbanco = "DBF"
   *************** CLIPPER ************************
   sele cadastro
       set order to 2
       go top
   seek (wpesq)
   lin = 1
   do while idade = wpesq .and. .not. eof()
      @ lin,01 say nome
      @ lin,25 say dtnasc
      @ lin,37 say idade     pict "99"                   
      lin = lin + 1
      skip
   enddo
elseif wbanco = "ADO"
   ****************** ADO / HARBOUR ***************
   wsql = "SELECT * FROM cadastro WHERE IDADE = " + NumericSql(wpesq) + " ORDER BY IDADE"
   oTemporario := oConexao:Execute( wsql )
   IF oTemporario:RecordCount() > 0
      nLin := 1
      DO WHILE .NOT. oTemporario:Eof()
         @ lin,01 say oTemporario:Fields( "NOME" ):Value
         @ lin,25 say oTemporario:Fields( "DTNASC" ):Value
         @ lin,37 say oTemporario:Fields( "IDADE" ):Value pict "99"                   
         lin = lin + 1
         oTemporario:MoveNext()
      enddo
   ENDIF
   oTemporario:Close()


Mais uma coisa: DATA
Pra evitar problemas com formato de data, melhor no SQL usar ano-mes-dia, e pra facilitar, uma função DateSql()
E em SQL não existe data em branco, então a saída é deixar vazio com NULL.
É óbvio que precisa algo parecido na leitura.

FUNCTION DateSql( dData )
   LOCAL cText
   IF Empty( dData )
      cText := "NULL"
   ELSE
      cText := ['] + Transform( Dtos( dData ), "@R 9999-99-99" ) + [']
   ENDIF
   RETURN cText


Sobre o nome em minúsculas: No Linux é obrigatório respeitar o "case". No Windows o default é minúsculas, mesmo que coloque em maiúsculas.
Sobre o SetMode(): Sim, no Harbour pode usar o que quiser, ao contrário do Clipper que fica limitado aos tamanhos padrão do DOS: 25x80, 28x80, 43x80, 50x80

Nota:
No ADO o programa conversa direto com a informação do banco de dados, então qualquer tipo diferente precisa tratar.
Apesar de não parecer, é como se você estivesse criando sua própria biblioteca ADO, começando por StringSql(), NumericSql() e DateSql().
Por um lado tem que criar essas funções, mas por outro lado nossa bilbioteca vai ser do nosso jeito.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 01 Jun 2015 05:54
por JoséQuintas
Não sei se pode fazer diferença na escolha.
ASP, VB e VBScript e VBA são semelhantes.
ASP é a linguagem usada em servidor de páginas de internet, VBScript está presente em páginas de internet e no próprio Windows, VBA está presente no pacote Office, e VB é o compilador da Microsoft.

Aqui uma das rotinas que uso no meu webservice de CEP.

SUB BuscaCepSql( cpCep, cpEndereco, cpBairro, cpCidade, cpUf, cpInfInc)
   DIM Conexao, Registro
   DIM cSql
   SET Conexao = Server.CreateObject("ADODB.Connection")
   Conexao.Open "Driver={MySQL ODBC 5.1 Driver}; DATABASE=database; SERVER=server; UID=usuario; PASSWORD=senha;"
   SET Registro = server.CreateObject("ADODB.Recordset")
   cSql = "SELECT * FROM JPCEP WHERE CPCEP = '" + cpCep + "'"
   Registro.Open cSql, Conexao
   IF NOT Registro.Eof THEN
      cpEndereco = Registro.Fields("CPENDERECO").Value
      cpEndereco = Rtrim(Ltrim(cpEndereco))
      cpBairro = Registro.Fields("CPBAIRRO").Value
      cpCidade = Registro.Fields("CPCIDADE").Value
      cpUf = Registro.Fields("CPUF").Value
      cpInfInc = Registro.Fields("CPINFINC").Value
   END IF
   IF cpInfInc < "2012/07/17 22:36" THEN
      cpInfInc = "0000/00/00"
   END IF
   Registro.close
   SET Registro = Nothing
   Conexao.Close
   SET Conexao = Nothing
END SUB


E a equivalente em Harbour

FUNCTION BuscaCepSql( cpCep, cpEndereco, cpBairro, cpCidade, cpUf, cpInfInc)
   LOCAL Conexao, Registro
   LOCAL cSql
   Conexao := win_OleCreateObject("ADODB.Connection")
   Conexao:Open( "Driver={MySQL ODBC 5.1 Driver}; DATABASE=database; SERVER=server; UID=usuario; PASSWORD=senha;" )
   Registro := win_OleCreateObject("ADODB.Recordset")
   cSql := "SELECT * FROM JPCEP WHERE CPCEP = '" + cpCep + "'"
   Registro:Open( cSql, Conexao )
   IF .NOT. Registro:Eof()
      cpEndereco := Registro:Fields("CPENDERECO"):Value
      cpEndereco := Rtrim(Ltrim(cpEndereco))
      cpBairro := Registro:Fields("CPBAIRRO"):Value
      cpCidade := Registro:Fields("CPCIDADE"):Value
      cpUf := Registro:Fields("CPUF"):Value
      cpInfInc := Registro:Fields("CPINFINC"):Value
   ENDIF
   IF cpInfInc < "2012/07/17 22:36"
      cpInfInc := "0000/00/00"
   ENDIF
   Registro:close()
   Conexao:Close()
   RETURN NIL


Só mesmo pequenas diferenças entre as linguagens de programação.
Mas a parte de ADO é praticamente idêntica.
Tudo isso está disponível no Windows, incluindo o ADO, é só usar.

Só pra mostrar que o ADO é isso, não importa qual seja a linguagem de programação.
E se a escolha for pela quantidade de pessoas que usam ADO... não dá pra considerar apenas os usuários Harbour.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 01 Jun 2015 06:20
por JoséQuintas
Só pra lembrar:
Pode usar ADO com DBFs também.
Ao invés/além de instalar o "driver" ( odbc ) pra MySQL, pode instalar do ADS, e usar ADS Local.
Só altera a string de conexão.
A partir daí, pode usar comandos SQL normalmente para DBFs.
Assim, aprende por etapas, começando por ADO + SQL em DBFs, e depois altera pra MySQL só trocando a string de conexão, e ajustando alguma particularidade do MySQL.

São três coisas distintas:
- ADO que se comunica com qualquer tipo de banco de dados, ou alguma biblioteca que pode ou não usar ADO
- Comandos SQL, que podem ser usados com qualquer tipo de banco de dados, ou biblioteca que use comandos SQL
- MySQL (uso cliente/servidor)

ADO trabalha com "arquivo temporário em memória" no padrão ADO.
Algumas bibliotecas do Harbour convertem esse arquivo temporário pra DBF.

A classe MySql mais antiga no Harbour converte em um tipo um array, e se comunica usando as DLLs do MySql.
Era muito recomendada antigamente, mas deixou de ser, apesar de continuar existindo.
Pra base de dados e pra parte gráfica, as opiniões no Harbour se dividem, como já deve ter percebido.

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 15 Out 2020 17:32
por GilmarDalantonia
Boa Tarde
procurando em exemplo de mysql com harbour console, encontre essas postagens aqui de vcs... estou seguindo os exemplo do J.Quintas, mas esta dando erro na hr de compilar... estou usando o compila.bat da forma como foi colocado no post

hbmk2 lote01, c_lote
retorna isso

D:\grp\Harbour\Teste>hbmk2 lote01, c_lote
hbmk2: Processando op‡äes do ambiente: -comp=mingw
Harbour 3.2.0dev (r1405061532)
Copyright (c) 1999-2014, http://harbour-project.org/

No code generated.

o q estou fazendo de errado ?

Harbour (ou xHarbour) BASICO com MYSQL

MensagemEnviado: 16 Out 2020 10:41
por JoséQuintas
GilmarDalantonia escreveu:compila.bat da forma como foi colocado no post


Esqueça BATs, pelo menos durante a fase de testes, ou até saber mexer com BAT.
o BAT pode esconder outras coisas.

A única mensagem foi "no code generated".
Mais nenhuma?

Isso apenas diz que não compilou, mas não diz porque.