Jump to content
Fivewin Brasil

SqlRdd - Alteração de estrutura das tabelas (ChangeStruct)


Edu

Recommended Posts

Prezados,

Boa tarde!

Estou usando SqlRdd com banco de dados MYSQL e estou implementando uma rotina de alteração de estrutura das tabelas.

Eu vi que o SQLRDD tem a função ChangeStruct(), porém não consegui fazer funcionar. Alguém tem uma rotina semelhante que possa me ajudar?

Grato.

Link to comment
Share on other sites

Boa tarde, ai está o que eu uso, resumidamente:

AAdd( aCampos, { "c001fili_", "c", 04, 00, " " } ) // codigo da empresa
AAdd( aCampos, { "c001codi_", "c", 06, 00, " " } ) // codigo
AAdd( aCampos, { "c001aliq_", "n", 18, 03, 0 } ) // % aliquota
AAdd( aCampos, { "c001redu_", "n", 18, 03, 0 } ) // % de reducao
AAdd( aCampos, { "c001obse_", "c", 80, 00, " " } ) // observacoes

SW_ChangeStruct( "arq001", aCampos )

*******************************************************************************************
*******************************************************************************************
/*
* Altera a estrutura de uma tabela
*/
*******************************************************************************************
*******************************************************************************************
FUNCTION SW_ChangeStruct( cTable, aNew )
LOCAL lRet := .T.
LOCAL aOld
LOCAL cName, cType, nDec, nCols, cNull, nLen, cStr, cAfter, cDef
LOCAL nLenOld, nDecOld, a
LOCAL oSql := SR_GetConnection()
LOCAL cSql := ""
LOCAL cStrDef,nAt,aArray

cTable := Upper( cTable )

IF cTable <> NIL .AND. ValType( aNew ) == "A" .AND. Len( aNew ) > 0

DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cSql := "Select * from " + cTable + " LIMIT 1 "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cSql := "Select TOP 1 * from " + cTable
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cSql := "Select * from " + cTable + " WHERE ROWNUM < 2 "
OTHERWISE ; cSql := "Select * from " + cTable
ENDCASE

oSql:Execute( cSql )

oSql:IniFields( .F. )
aOld := oSql:AFields
cStr := ""

nCols := Len( aNew )

FOR a := 1 TO nCols

SysRefresh() // reapresentar os controles

cName := Upper( aNew[ a, 1 ] )
cType := aNew[ a, 2 ]
nLen := aNew[ a, 3 ]
nDec := aNew[ a, 4 ]
cStrDef := aNew[ a, 5 ]
cAfter := ""
cDef := ""
cNull := "NOT NULL "

IF Upper( cType ) <> "D"

// descobrir qual a coluna a ser alterada
nAt := AScan( aOld, { | x | AllTrim( Upper( x[ 1 ] ) ) == AllTrim( Upper( cName ) ) } )
IF nAt > 0

// Verificar se o tamanho e decimal dos campos foram alterados
nLenOld := aOld[ nAt, 3 ]
nDecOld := aOld[ nAt, 4 ]

IF nLen <> nLenOld // tamanho diferente


cStr += "ALTER TABLE " + cTable + " "

DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " MODIFY COLUMN " + cName + " "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " ALTER COLUMN " + cName + " "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " MODIFY " + cName + " "
ENDCASE

DO CASE
CASE Upper( cType ) == "D"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " date " ; cDef := "DEFAULT '00000000' "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " smalldatetime " ; cDef := "DEFAULT (GetDate()) "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " date " ; cDef := "DEFAULT SYSDATE "
ENDCASE

CASE Upper( cType ) == "N"

DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " double(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := IF( cStrDef <> 0, "DEFAULT "+AllTrim(Str(cStrDef)),"DEFAULT 0 " )
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " decimal(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := "DEFAULT 0 "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " number(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := "DEFAULT 0 "
ENDCASE

CASE Lower( cType ) == "c"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " char(" + AllTrim( Str( nLen, 3 ) ) + ") " ; cDef := IF( Len(cStrDef) > 0, "DEFAULT '"+AllTrim(cStrDef)+"'","DEFAULT ' ' " )
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " char(" + AllTrim( Str( nLen, 3 ) ) + ") " ; cDef := " "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " char(" + AllTrim( Str( nLen, 3 ) ) + ") " ; cDef := "DEFAULT ' ' "
ENDCASE

CASE Lower( cType ) == "m"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " MEDIUMBLOB " ; cDef := "" //IF( Len(cStrDef) > 0, "DEFAULT '"+AllTrim(Str(cStrDef))+"'","DEFAULT ' ' " )
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " TEXT " ; cDef := ""
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " LONG " ; cDef := "DEFAULT ' ' "
ENDCASE
ENDCASE
IF Upper( oSistema:cDbDriver_ ) == "ORACLE"
cStr += cAfter
cStr += cDef
cStr += cNull
cStr := Lower( cStr ) + ";"
ELSE
cStr += cNull
cStr += cDef
cStr += cAfter
cStr := Lower( cStr ) + ";"
ENDIF

ELSE

// somente verificar se o decimal é diferente
IF Upper( cType ) <> "C" .AND. Upper( cType ) <> "D" // tipo char e data nao temn decimal
IF nDec <> nDecOld

cStr += "ALTER TABLE " + cTable + " "

DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " MODIFY COLUMN " + cName + " "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " ALTER COLUMN " + cName + " "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " MODIFY " + cName + " "
ENDCASE

DO CASE
CASE Lower( cType ) == "d"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " date " ; cDef := "DEFAULT '00000000' "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " smalldatetime " ; cDef := "DEFAULT (GetDate()) "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " date " ; cDef := "DEFAULT sysdate "
ENDCASE

CASE Lower( cType ) == "n"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " double(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := IF( cStrDef <> 0, "DEFAULT "+AllTrim(Str(cStrDef)),"DEFAULT 0 " )
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " decimal(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := "DEFAULT 0 "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " NUMBER(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := "DEFAULT 0 "
ENDCASE

CASE Lower( cType ) == "c"
cStr += " char(" + AllTrim( Str( nLen, 3 ) ) + ") " ; cDef := IF( Len(cStrDef) > 0, "DEFAULT '"+AllTrim(Str(cStrDef))+"'","DEFAULT ' ' " )

CASE Lower( cType ) == "m"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " MEDIUMBLOB " ; cDef := "" //IF( Len(cStrDef) > 0, "DEFAULT '"+AllTrim(Str(cStrDef))+"'","DEFAULT ' ' " )
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " TEXT " ; cDef := ""
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " LONG " ; cDef := "DEFAULT ' ' "
ENDCASE
ENDCASE
IF Upper( oSistema:cDbDriver_ ) == "ORACLE"
cStr += cAfter
cStr += cDef
cStr += cNull
cStr := Lower( cStr ) + ";"
ELSE
cStr += cNull
cStr += cDef
cStr += cAfter
cStr := Lower( cStr ) + ";"
ENDIF
ENDIF
ENDIF
ENDIF

ELSE // else do at > 0

//nao achou o campo, criar o campo nao encontrado
cStr += "ALTER TABLE " + cTable + " "
cStr += " ADD " + cName + " "
IF a > 1
IF Upper( oSistema:cDbDriver_ ) == "MYSQL"
cAfter := " AFTER " + aNew[ a - 1, 1 ] + " "
ENDIF
ENDIF

DO CASE
CASE Lower( cType ) == "d"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " date " ; cDef := "DEFAULT '00000000' "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " smalldatetime " ; cDef := "DEFAULT (GetDate()) "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " DATE " ; cDef := "DEFAULT SYSDATE "
ENDCASE

CASE Lower( cType ) == "n"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " double(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := IF( cStrDef <> 0, "DEFAULT "+AllTrim(Str(cStrDef)),"DEFAULT 0 " )
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " decimal(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := "DEFAULT 0 "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " NUMBER(" + AllTrim( Str( nLen, 3 ) ) + "," + AllTrim( Str( nDec ) ) + ") " ; cDef := "DEFAULT 0 "
ENDCASE

CASE Lower( cType ) == "c" ; cStr += " char(" + AllTrim( Str( nLen ) ) + ") " ; cDef := IF( Len(cStrDef) > 0 , "DEFAULT '"+AllTrim(cStrDef)+"'","DEFAULT ' ' " )

CASE Lower( cType ) == "m"
DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " MEDIUMBLOB " ; cDef := "" /* IF( Len(cStrDef) > 0, "DEFAULT '"+AllTrim(Str(cStrDef))+"'","DEFAULT ' ' " )*/ ; cNull := ""
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " TEXT " ; cDef := ""
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " LONG " ; cDef := "DEFAULT ' ' "
ENDCASE
ENDCASE
IF Upper( oSistema:cDbDriver_ ) == "ORACLE"
cStr += cAfter
cStr += cDef
cStr += cNull
cStr := Lower( cStr ) + ";"
ELSE
cStr += cNull
cStr += cDef
cStr += cAfter
cStr := Lower( cStr ) + ";"
ENDIF
ENDIF

ELSE // se for tipo DATA

// descobrir qual a coluna a ser inserida
nAt := AScan( aOld, { | x | AllTrim( Upper( x[ 1 ] ) ) == AllTrim( Upper( cName ) ) } )
IF nAt = 0 //nao achou o campo, criar o campo nao encontrado
cStr += "ALTER TABLE " + cTable + " "
cStr += " ADD " + cName + " "
IF a > 1
IF Upper( oSistema:cDbDriver_ ) == "MYSQL"
cAfter := " AFTER " + aNew[ a - 1, 1 ] + " "
ENDIF
ENDIF

DO CASE
CASE Upper( oSistema:cDbDriver_ ) == "MYSQL" ; cStr += " date " ; cDef := "DEFAULT '00000000' "
CASE Upper( oSistema:cDbDriver_ ) == "MSSQLSERVER" ; cStr += " smalldatetime " ; cDef := "DEFAULT (GetDate()) "
CASE Upper( oSistema:cDbDriver_ ) == "ORACLE" ; cStr += " DATE " ; cDef := "DEFAULT SYSDATE "
ENDCASE

IF Upper( oSistema:cDbDriver_ ) == "ORACLE"
cStr += cAfter
cStr += cDef
cStr += cNull
cStr := Lower( cStr ) + ";"
ELSE
cStr += cNull
cStr += cDef
cStr += cAfter
cStr := Lower( cStr ) + ";"
ENDIF
ENDIF

ENDIF

NEXT a

cStr := AllTrim( cStr )

IF Len( cStr ) > 0
aArray := ListAsArray( cStr , ";" )
IF Len( aArray ) > 0
FOR a := 1 TO Len( aArray )
IF Len( aArray[ a ] ) > 0
IF ! SWExecSql( Upper(aArray[ a ]),.F. )
lRet := .F.
EXIT
ENDIF
ENDIF
NEXT a
ENDIF
ENDIF
ENDIF

RETURN( lRet )

Link to comment
Share on other sites

Eu utilizo um método que, para mim, é infalível.

Verifico se houve alguma alteração na estrutura. Se houve:

• Renomeio a tabela atual para um nome temporário;

• Crio a tabela com a nova estrutura;

• Importo todos os dados da tabela renomeada para a tabela atual;

• Excluo a tabela renomeada.

As funções abaixo exemplificam isso:

1 - Exemplo de como crio as tabelas:

   // Criação da tabela de vendedores
   aEstr:={}
   AADD( aEstr ,{ "COD", "N", 10, 0 } ) // Codigo
   AADD( aEstr ,{ "NOM", "C", 40, 0 } ) // Apelido
   AADD( aEstr ,{ "END", "C", 40, 0 } ) // Endereço
   AADD( aEstr ,{ "TEL", "C", 40, 0 } ) // Telefones
   AADD( aEstr ,{ "FUN", "C", 40, 0 } ) // Cargo / Função
   AADD( aEstr ,{ "PSW", "C", 32, 0 } ) // Senha (MD5)
   IF ! SR_ExistTable( "pessoal" )
      TRY
         dbCreate( "pessoal", aEstr, cRDD )
      CATCH oErr
         ShowMsgTray("Erro ao tentar criar a tabela 'pessoal'. Favor verificar as configurações de banco de dados.","Erro")
         IF FileWrite(".\errorlog\erro.txt", oErr:Description)
            WAITRUN( GetEnv( "ComSpec" )+" /C NOTEPAD .\errorlog\erro.txt", 0)
         ENDIF
      END
   else
      lChg := ChkStruct("pessoal", aEstr, oSql, nErr, nPos)
   ENDIF

2 - Função que criei para modificar a estrutura:

STATIC FUNCTION ChkStruct(cTable, aStruct, oSql, nErr, nPos)
   LOCAL lStrOk := .T., cComm, aNewStr, aOldStr, aChange, aImport, cImport
   aNewStr := aStruct
   AADD(aNewStr, {"SR_RECNO", "N", 20, 0}) // SQLRDD acrescenta este campo ao criar a tabela

   cSay := "Verificando a tabela '"+cTable+"'"
   oSay:SetText(cSay)
   oSay:Refresh()

   IF ! l_Check ; RETURN .T.; ENDIF
   
   // Obter a estrutura da tabela atual.
   nErr := 0
   TRY
      cComm := "SELECT * FROM "+cTable+" LIMIT 1"
      nErr := oSql:execute( cComm )
      oSql:iniFields(.f.)
      aOldStr := oSql:aFields // Para pegar a estrutura
   CATCH
      ShowMsgTray("Não foi possível testar a tabela '"+cTable+"'", "Aviso")
      SysWait(1)
      RETURN .T.
   END TRY

   // Comparar com a estrutura de aStruct
   lChangd := .F.
   aChange := {}
   aImport := {}
   cImport := ""
   TRY
      FOR nX := 1 TO LEN(aNewStr) // Verifica se foi acrescentado algum campo ou se mudou o tamanho de algum.
          cFild:=aNewStr[nX,1]
          cType:=aNewStr[nX,2]
          cSize:=STRZERO(aNewStr[nX,3], 4)
          cDeci:=STRZERO(aNewStr[nX,4], 3)
          nElem := ASCAN(aOldStr, {|aNro| aNro[1] == cFild})
          IF nElem > 0
             IF cType != aOldStr[nElem,2] .OR. ;
                cSize != STRZERO(aOldStr[nElem,3], 4) .OR. ;
                cDeci != STRZERO(aOldStr[nElem,4], 3)
                lChangd := .T. // Mudou o tamanho de um campo
                aadd(aChange, {cFild, "Modificou a estrutura"})
             ENDIF
          ELSE
             lChangd := .T. // Foi removido algum campo
             aadd(aChange, {cFild, "Campo acrescentado"})
          ENDIF
      NEXT
      FOR nX := 1 TO LEN(aOldStr) // Verifica se foi excluindo algum compo
          cFild := aOldStr[nX,1]
          nElem := ASCAN(aNewStr, {|aNro| aNro[1] == cFild})
          IF nElem = 0
             lChangd := .T. // Algum campo foi removido
             aadd(aChange, {cFild, "Campo removido"})
          ELSE
             AADD(aImport, cFild) // Para pegar só os campos que existem nas duas tabelas.
          ENDIF
      NEXT
      IF lChangd
         // Determinar quais campos serão importados da tabela temporária
         FOR nX := 1 TO LEN(aImport)
             IF ! EMPTY(cImport) ; cImport += ", " ; ENDIF
             cImport += aImport[nX]
         NEXT
      ENDIF
   CATCH
      ShowMsgTray("Não foi possível testar a tabela '"+cTable+"'", "Aviso")
      SysWait(1)
      RETURN .T.
   END TRY

   // Excluir a tabela temporária, se existir
   TRY
      IF SR_ExistTable( cTable+"_old" )
         SR_DropTable(cTable+"_old")
      ENDIF
   CATCH oErr
      ShowMsgTray("Não foi possível excluir a tabela '"+cTable+"_old"+"'", "Erro.")
      SysWait(1)
      RETURN .T.
   END TRY

   // Renomear a tabela atual para tabela temporária
   IF lChangd
      IF ! SR_RenameTable(cTable, cTable+"_old")
         lChangd := .F.
      ENDIF
   ENDIF
   
   // Criar tabela atual com a nova estrutura
   IF lChangd
      TRY
         SR_DropTable(cTable) // Já foi renomeada.
      CATCH oErr
      END TRY
      TRY
         dbCreate(cTable, aStruct, cRDD )
      CATCH oErr
         SR_RenameTable(cTable+"_old", cTable) // Se não conseguir criar a tabela, recuperar a anterior.
         lChangd := .f.
         ShowMsgTray("Erro ao tentar modificar a tabela '"+cTable+"'.","Erro")
      END TRY
   ENDIF

   // Importar dados da tabela temporária
   nErr := 0
   IF lChangd
      cComm := "INSERT INTO "+cTable+" ("+cImport+") "+;
               "SELECT "+cImport+" FROM "+cTable+"_old"
      nErr := oSql:execute( cComm )
      IF nErr != 0
         ShowMsgTray("Erro ao tentar recuperar os dados da tabela '"+cTable+"_old"+"'.","Erro")
      ENDIF
   ENDIF
   
   // Excluir a tabela temporária
   TRY
      SR_DropTable(cTable+"_old")
   CATCH oErr
   END TRY
RETURN( lStrOk )
Link to comment
Share on other sites

Eu utilizo um método que, para mim, é infalível.

Verifico se houve alguma alteração na estrutura. Se houve:

• Renomeio a tabela atual para um nome temporário;

• Crio a tabela com a nova estrutura;

• Importo todos os dados da tabela renomeada para a tabela atual;

• Excluo a tabela renomeada.

As funções abaixo exemplificam isso:

1 - Exemplo de como crio as tabelas:

   // Criação da tabela de vendedores
   aEstr:={}
   AADD( aEstr ,{ "COD", "N", 10, 0 } ) // Codigo
   AADD( aEstr ,{ "NOM", "C", 40, 0 } ) // Apelido
   AADD( aEstr ,{ "END", "C", 40, 0 } ) // Endereço
   AADD( aEstr ,{ "TEL", "C", 40, 0 } ) // Telefones
   AADD( aEstr ,{ "FUN", "C", 40, 0 } ) // Cargo / Função
   AADD( aEstr ,{ "PSW", "C", 32, 0 } ) // Senha (MD5)
   IF ! SR_ExistTable( "pessoal" )
      TRY
         dbCreate( "pessoal", aEstr, cRDD )
      CATCH oErr
         ShowMsgTray("Erro ao tentar criar a tabela 'pessoal'. Favor verificar as configurações de banco de dados.","Erro")
         IF FileWrite(".\errorlog\erro.txt", oErr:Description)
            WAITRUN( GetEnv( "ComSpec" )+" /C NOTEPAD .\errorlog\erro.txt", 0)
         ENDIF
      END
   else
      lChg := ChkStruct("pessoal", aEstr, oSql, nErr, nPos)
   ENDIF

2 - Função que criei para modificar a estrutura:

STATIC FUNCTION ChkStruct(cTable, aStruct, oSql, nErr, nPos)
   LOCAL lStrOk := .T., cComm, aNewStr, aOldStr, aChange, aImport, cImport
   aNewStr := aStruct
   AADD(aNewStr, {"SR_RECNO", "N", 20, 0}) // SQLRDD acrescenta este campo ao criar a tabela

   cSay := "Verificando a tabela '"+cTable+"'"
   oSay:SetText(cSay)
   oSay:Refresh()

   IF ! l_Check ; RETURN .T.; ENDIF
   
   // Obter a estrutura da tabela atual.
   nErr := 0
   TRY
      cComm := "SELECT * FROM "+cTable+" LIMIT 1"
      nErr := oSql:execute( cComm )
      oSql:iniFields(.f.)
      aOldStr := oSql:aFields // Para pegar a estrutura
   CATCH
      ShowMsgTray("Não foi possível testar a tabela '"+cTable+"'", "Aviso")
      SysWait(1)
      RETURN .T.
   END TRY

   // Comparar com a estrutura de aStruct
   lChangd := .F.
   aChange := {}
   aImport := {}
   cImport := ""
   TRY
      FOR nX := 1 TO LEN(aNewStr) // Verifica se foi acrescentado algum campo ou se mudou o tamanho de algum.
          cFild:=aNewStr[nX,1]
          cType:=aNewStr[nX,2]
          cSize:=STRZERO(aNewStr[nX,3], 4)
          cDeci:=STRZERO(aNewStr[nX,4], 3)
          nElem := ASCAN(aOldStr, {|aNro| aNro[1] == cFild})
          IF nElem > 0
             IF cType != aOldStr[nElem,2] .OR. ;
                cSize != STRZERO(aOldStr[nElem,3], 4) .OR. ;
                cDeci != STRZERO(aOldStr[nElem,4], 3)
                lChangd := .T. // Mudou o tamanho de um campo
                aadd(aChange, {cFild, "Modificou a estrutura"})
             ENDIF
          ELSE
             lChangd := .T. // Foi removido algum campo
             aadd(aChange, {cFild, "Campo acrescentado"})
          ENDIF
      NEXT
      FOR nX := 1 TO LEN(aOldStr) // Verifica se foi excluindo algum compo
          cFild := aOldStr[nX,1]
          nElem := ASCAN(aNewStr, {|aNro| aNro[1] == cFild})
          IF nElem = 0
             lChangd := .T. // Algum campo foi removido
             aadd(aChange, {cFild, "Campo removido"})
          ELSE
             AADD(aImport, cFild) // Para pegar só os campos que existem nas duas tabelas.
          ENDIF
      NEXT
      IF lChangd
         // Determinar quais campos serão importados da tabela temporária
         FOR nX := 1 TO LEN(aImport)
             IF ! EMPTY(cImport) ; cImport += ", " ; ENDIF
             cImport += aImport[nX]
         NEXT
      ENDIF
   CATCH
      ShowMsgTray("Não foi possível testar a tabela '"+cTable+"'", "Aviso")
      SysWait(1)
      RETURN .T.
   END TRY

   // Excluir a tabela temporária, se existir
   TRY
      IF SR_ExistTable( cTable+"_old" )
         SR_DropTable(cTable+"_old")
      ENDIF
   CATCH oErr
      ShowMsgTray("Não foi possível excluir a tabela '"+cTable+"_old"+"'", "Erro.")
      SysWait(1)
      RETURN .T.
   END TRY

   // Renomear a tabela atual para tabela temporária
   IF lChangd
      IF ! SR_RenameTable(cTable, cTable+"_old")
         lChangd := .F.
      ENDIF
   ENDIF
   
   // Criar tabela atual com a nova estrutura
   IF lChangd
      TRY
         SR_DropTable(cTable) // Já foi renomeada.
      CATCH oErr
      END TRY
      TRY
         dbCreate(cTable, aStruct, cRDD )
      CATCH oErr
         SR_RenameTable(cTable+"_old", cTable) // Se não conseguir criar a tabela, recuperar a anterior.
         lChangd := .f.
         ShowMsgTray("Erro ao tentar modificar a tabela '"+cTable+"'.","Erro")
      END TRY
   ENDIF

   // Importar dados da tabela temporária
   nErr := 0
   IF lChangd
      cComm := "INSERT INTO "+cTable+" ("+cImport+") "+;
               "SELECT "+cImport+" FROM "+cTable+"_old"
      nErr := oSql:execute( cComm )
      IF nErr != 0
         ShowMsgTray("Erro ao tentar recuperar os dados da tabela '"+cTable+"_old"+"'.","Erro")
      ENDIF
   ENDIF
   
   // Excluir a tabela temporária
   TRY
      SR_DropTable(cTable+"_old")
   CATCH oErr
   END TRY
RETURN( lStrOk )

Ariston

Boa noite

Me corrija se eu estiver enganando e já de antemão, desculpe a minha ignorância, a forma do seu método de alteração, está mais voltada/semelhante as alterações em DBF (Offline), enquanto a anterior está para SQL, ou seja, enquanto a anterior pode ser executada em tempo real inclisive com a possibilidade da tabela em uso, enquanto o seu sofrerá efeito somente se o sistema estiver inoperante ou a tabela não estiver em uso.

[]s,

Link to comment
Share on other sites

Realmente é bem parecido com o método que uso para alterar estrutura de DBF, embora adaptada para SQLRDD e só funciona com bancos de dados relacionais (MySQL, Firebird, etc)

Ainda não testei em um momento que outros usuários estivessem usando as tabelas. Carece testar e fazer as devidas correções em caso de erro.

Qualquer modificação, favor postar aqui.

Agradeço.

Edu, favor entrar em contato por email para eu poder ajudar melhor: airston.ap@hotmail.com

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...