Página 1 de 1

Incluir 1 campo novo na estrutura do dbf

Enviado: 01 Nov 2007 21:15
por asimoes
Amigos,

Se já houver 1 tópico sobre o assunto me perdoem, neste caso me informem por favor.

Existe alguma rotina pronta para incluir um campo novo na estrutura de um dbf?

[]´s :{

Enviado: 02 Nov 2007 01:49
por rochinha
Amiguinho

Esta tarefa não é dificil, mas exige cuidados:

Primeiro voce eve pegar a estrutura do arquivo em questão usando a função DBStruct() que devolve em um Array a estrutura completa.

O Array é multidimensional, ou seja, é um Array contendo vários outros Arrays que contem os dados de cada campo.

Código: Selecionar todos

ESTRU_DBF := { { "IDLOG"  , "N",  5, 0 } , ;
                         { "DATA"   , "D",  8, 0 } , ;
                         { "HORA"   , "C",  8, 0 } , ;
                         { "USUARIO", "C", 20, 0 } , ;
                         { "ACAO"   , "C", 20, 0 } , ;
                         { "MODULO" , "C", 20, 0 } }
Adicione a este Array os Array contendo os campos que voce quer incluir.

Código: Selecionar todos

...
   AADD( ESTRU_DBF, { "CAMPO1", "N", 5, 2 } )
   AADD( ESTRU_DBF, { "CAMPO2", "D", 8, 0 } )
...
Faça uma cópia do arquivo em questão ante de mudar sua estrutura.
Crie então a nova estrutura.

Código: Selecionar todos

ESTRU_DBF := { { "IDLOG"  , "N",  5, 0 } , ;
                         { "DATA"   , "D",  8, 0 } , ;
                         { "HORA"   , "C",  8, 0 } , ;
                         { "USUARIO", "C", 20, 0 } , ;
                         { "ACAO"   , "C", 20, 0 } , ;
                         { "MODULO" , "C", 20, 0 } }
AADD( ESTRU_DBF, { "CAMPO1", "N", 5, 2 } )
AADD( ESTRU_DBF, { "CAMPO2", "D", 8, 0 } )
DBCREATE( "novodbf",ESTRU_DBF )
Verifique se o novo arquivo existe:

Código: Selecionar todos

...
if file( "novodbf.dbf" )
...
Faça o transporte dos dados da estrutura antiga para a nova estrutura:

Código: Selecionar todos

...
USE novodbf EXCLUSIVE
APPEND FROM antigo
...
O boleto lhe será enviado em seu email, hehehe!

Enviado: 02 Nov 2007 02:24
por Stanis Luksys
Opa, é bem por aí mesmo...

Eu tenho uma função que faz isso no meu sistema. Tirei umas rotinas externas, dei uma enxugada e o que ficou é mais ou menos isso:

Código: Selecionar todos

procedure addField( file, field, type, len, dec )

	use &file new
	aStruct := dbStruct( file )

	// campo já existe
	if fieldPos( field ) != 0
		close &file
		alert( "Erro em "+ProcName()+". Campo "+field+" existe na tabela "+file+"!" )
		return
	endif
	close &file
	
	aAdd( aStruct, { field, type, len, dec } )
	dbCreate( "temp", aStruct )
	
	use temp new
	append from &file
	close temp
	
	fErase( file+".dbf" )
	fRename( "temp.dbf", file+".dbf" )
	
	return
Para usa-la basta fazer assim:

Código: Selecionar todos

addField( "clientes", "campo", "C", 30, 0 )

Precisaria ver se a tabela existe e essas coisas, no meu caso já avalio isso na função que abre os arquivos...

Espero que ajude...

Enviado: 02 Nov 2007 13:34
por asimoes
Valeu Stanis,

Era isso mesmo que eu estava precisando.

[]´s
Stanis Luksys escreveu:Opa, é bem por aí mesmo...

Eu tenho uma função que faz isso no meu sistema. Tirei umas rotinas externas, dei uma enxugada e o que ficou é mais ou menos isso:

Código: Selecionar todos

procedure addField( file, field, type, len, dec )

	use &file new
	aStruct := dbStruct( file )

	// campo já existe
	if fieldPos( field ) != 0
		close &file
		alert( "Erro em "+ProcName()+". Campo "+field+" existe na tabela "+file+"!" )
		return
	endif
	close &file
	
	aAdd( aStruct, { field, type, len, dec } )
	dbCreate( "temp", aStruct )
	
	use temp new
	append from &file
	close temp
	
	fErase( file+".dbf" )
	fRename( "temp.dbf", file+".dbf" )
	
	return
Para usa-la basta fazer assim:

Código: Selecionar todos

addField( "clientes", "campo", "C", 30, 0 )

Precisaria ver se a tabela existe e essas coisas, no meu caso já avalio isso na função que abre os arquivos...

Espero que ajude...

Enviado: 02 Nov 2007 23:45
por clodoaldomonteiro
A função do Stanis é muito boa mesmo. Muito bem elaborada.

Pode-se até colocá-la dentro do sistema e fazer com que ele verifique a base de dados quando entrar no sistema, assim atualização fica automática, bom para quem tem muitos clientes ou o sistema instalado em várias máquinas.

É a inteligência acima de tudo. :{

Enviado: 03 Nov 2007 22:44
por rochinha
Amiguinhos

O João Frazato manda sua versão de rotina de atualização de bases para vossa apreciação.

Código: Selecionar todos

PUBLIC LISTADBF := {}
XJAF_ARRUMAR    := .t.  // Carrega por parametro no meu caso pois executo somente quando necessario
TIPODRIVER      := '.CDX'



Cria_Dbf01()

//---------------------------------------------------------------------
Function Cria_Dbf01()
      CARQCDX := "TESTE"+TIPODRIVER
      CARQDBF := "TESTE.DBF"

      Estru := { {"Registr", "N", 10,0 },;
                 {"Data"   , "D",  8,0 },;
                 {"Hora"   , "C", 10,0 },;
                 {"Texto"  , "C", 50,0 } }

      AADD(LISTADBF,{CARQCDX,CARQDBF})

      Ver_Dbf('TESTE.DBF',ESTRU)

      If ! File("TESTE.dbf")
           MSG("AGUARDE.... CRIANDO "+CARQDBF)
           Dbcreate("TESTE.dbf",Estru)

           Use Teste
               For x:= 1 to 1000
                   Append Blank
                   Repla Registr    With x
                   Repla data       With date()
                   Repla hora       With Time()
                   Repla Texto      With StrZero(x,10)+Dtoc(Date())+Time()
               Next
      Endif
Return Nil


//------------------------------------------------------
Static Function Ver_Dbf(cDbf,cMatriz)
Local cArquivo    := cDbf
Local nTotCompos  := 0
Local DadoCampo   := {}
Local cCampos     := {}
Local cPesq
Local b
If XJAF_ARRUMAR==.F.
   Return .t.
ENDIF


If ! File(cArquivo)
     Return nil
Endif

//--- Carregando Estrutura do Dbf
       Close All
       Close All
       Sele 1
            Use (cArquivo) Alias _Arq

       Sele _Arq

       nTotCompos := FCount()
       DadoCampo  := DbStruct()
       cCampos    := {}
       Close all

       For B:=1 to nTotCompos
            cFields := ALLTRIM(Upper(DadoCampo[b,1]))+;
                       Upper(DadoCampo[b,2])+;
                       Str(DadoCampo[b,3],7)+;
                       Str(DadoCampo[b,4],7)

             Aadd(cCampos,cFields ) // ,DadoCampo[b,2],DadoCampo[b,3],DadoCampo[b,4]} )
       Next
       cErros := {}
       For x:= 1 to Len(cMatriz)
           cPesq   := ALLTRIM(Upper(cMatriz[x,1]))+;
                       upper(cMatriz[x,2])+;
                       Str(cMatriz[x,3],7)+;
                       Str(cMatriz[x,4],7)
           nPos   := Ascan(cCampos,cPesq)
           If nPos == 0
              cMsg := "Falta Campo :"+cPesq
              aadd(cErros,cMsg)
           Endif
       Next
       If Len(cErros) > 0
          Cri_Dbf_Estru(cArquivo,cMatriz)
       Endif
Return nil
//--------------------------------------
Static Function Cri_Dbf_Estru(cDbf,cEstru)
Local nSize     := Len(cDbf)
Local cNomeFile := Substr(cDbf,1,nSize-4)
Local cLocal    := ""
If File(cLocal+cNomeFile+'.Tmp')
   Delete File (cLocal+cNomeFile+'.Tmp')
Endif
Dbcreate(cNomeFile+'.Tmp',cEstru)

CLOSE ALL
CLOSE ALL
SET DELETED OFF
MSG("AGUARDE.... Arrumando Arquivo "+cDbf)
SELE 1
     USE (cNomeFile+'.Tmp')
     Set index to 
     Append from (cDbf)

SET DELETED ON
CLOSE ALL
CLOSE ALL
CLOSE ALL
Delete File (cLocal+cDbf)
Rename (cLocal+cNomeFile+'.Tmp') to (cLocal+cDbf )
Close all
If File(cNomeFile+'.cdx')
   Delete File (cNomeFile+'.cdx')
Endif
CLOSE ALL
CLOSE ALL
Return nil



//------------------------------------------------------------
STATIC FUNCTION MSG(XTEXTO)
CLEAR
@ 24,00 SAY PADC(XTEXTO,80) COLOR("RR+/W")
RETURN NIL

Enviado: 05 Nov 2007 09:40
por Pablo César
Acho que mais uma forma de verificar se o sistema de tal cliente precisa atualização ou alteração de estrutura de dados é verificando a versão do sistema de tal cliente. Eu tenho como procedimento MANDATÓRIO, alterar a versão do sistema TODA vez que seja alterado o código do sistema. Claro que o número da versão é composto 99.99.999.9999 parece muito complexo, mas esta informção para o usuário pode ser apresentada nos primeiros dígitos mas a verificação de sistema para sistema faria por completo.

Enviado: 05 Nov 2007 10:56
por Stanis Luksys
Pablo César escreveu:Acho que mais uma forma de verificar se o sistema de tal cliente precisa atualização ou alteração de estrutura de dados é verificando a versão do sistema de tal cliente.
Eu utilizo para isso um arquivo extra de validação (o mesmo que protege anti-pirataria), e a data do executável.

Mas independente disso, na minha função de abrir arquivos eu já avalio se o DBF está completo, seus atributos, se não falta campos, etc e tal. Se faltar campo, utilizo uma função parecida com a que postei aqui. Esta do meu exemplo está bem limitada, foi só a título de exemplo mesmo.

Falou!

Enviado: 06 Nov 2007 12:27
por rochinha
Amiguinho

Como voces criam o seu método de numeração de versão.

No meu caso eu uso Data Invertida(DTOS()) mais um sequencial, exemplo:

20071127-475

Meu sistema ao entrar em operação faz uma verificação pela sua função LiveUpdate que verifica o conteudo de um arquivo em meu site e compara com a informação de revisão gravada em meu sistema.

Ele compara esteas informações, apresenta ao usuário uma mensagem, pergunta se o mesmo quer fazer atualização e se SIM baixa do FTP, derruba a aplicação e executa o INSTALL.

Após instalado, o sistema é executado e outras funções internas são disparadas, recriação de estruturas e indices. Geralmente eu só executo a re-estruturação quando estou no local. Automaticamente só é verificada a falta de arquivos novos e os mesmos são criados.

Para gerar meu codigo de revisão, um pequeno programinha Clipper, cria a chave sequencial, usando minha função PsqControle(disponivel na sessão código-fonte), gera um arquivo .PRG contendo a função REVISAO, apaga o REVISAO.OBJ e compila o sistema.

Desta forma eu automatizo meu processo de revisão.