A much faster Class TDataBase !!!

A much faster Class TDataBase !!!

Postby Antonio Linares » Fri Dec 19, 2008 12:59 pm

Jose Luis Capel from Aicom company has greatly enhanced FiveWin Class TDataBase making it around three times faster!!!

As a special gift from Santa (thanks Jose Luis!) here you have it to start using it. It has been tested with Harbour in PC and Pocket PC. Your feedback is welcome :-)
Code: Select all  Expand view
#include "fivewin.ch"
#include "dbinfo.ch"


function main()

local o, x, nSec, n := 0, a[100], b

REQUEST HB_LANG_ES // Para establecer español para Mensajes, fechas, etc..
REQUEST HB_CODEPAGE_ESMWIN // Para establecer código de página a Español
(Ordenación, etc..)
REQUEST DBFCDX //&&,DBFCDX
REQUEST DBFFPT
RDDSETDEFAULT("DBFCDX")
SET AUTOPEN OFF
SET DELETED ON
SET CENTURY ON
SET EPOCH TO( Year(Date())-50 )
SET DATE BRITISH    // Formato dd-mm-aaaa
SET EXCLUSIVE OFF
SET SOFTSEEK OFF

HB_LangSelect('ES')
HB_SetCodePage("ESMWIN") // Para ordenación (arrays, cadenas, etc..)

msginfo("Iniciamos")
o := xDatabase()      // Nueva clase derivada de tDatabase de fivewin
o:New( "CLI01.dbf")
o:lShared := .F.
o:Open()
o:lBuffer := .f.
nSec := Seconds()
// Test de velocidad en lectura de datos. Ahorro aproximado del 50%

nSec := Seconds()
for x=1 to 1000000
uFunc( o:Codpro )
next
Msginfo(Seconds()-nSec, "Test de lectura de datos")

// Test de velocidad en lectura con movimientos
nSec := Seconds()

for x=1 to 10000
o:Gotop()
Do while !o:Eof()
    uFunc( o:Codpro )
    o:Skip()
Enddo
next
Msginfo(Seconds()-nSec, "Test de lectura")


// Test de velocidad en Escritura
nSec := Seconds()
for x=1 to 10000
o:Gotop()
Do while !o:Eof()
    o:Codpro := "Proba" + Alltrim(Str(x))
    o:Skip()
Enddo
next
Msginfo(Seconds()-nSec, "Test de escritura")
return NIL

FUNCTION uFunc(u);Return NIL

////////////////////////////////////////////////////////////////////////////
/
CLASS xDatabase FROM tDatabase
    METHOD SetArea()
    METHOD Load()
    METHOD CancelUpdate()   INLINE ::lBuffer := .F.

    MESSAGE FieldGet METHOD _FieldGet( nField )
    MESSAGE FieldPut METHOD _FieldPut( nField, uVal )

    METHOD Blank()
    METHOD Modified()
    METHOD SaveBuff()

    MESSAGE OemToAnsi METHOD _OemToAnsi()

    METHOD HashAddMember()
    ERROR HANDLER ONERROR( uParam1 )

ENDCLASS

METHOD SetArea( nWorkArea ) CLASS xDatabase

  local n, oClass, aDatas := {}, aMethods := {}


  ::nArea     = nWorkArea
  ::cAlias    = Alias( nWorkArea )
  ::cFile     = Alias( nWorkArea )

  if ::Used()
     ::cFile     = ( nWorkArea )->( DbInfo( DBI_FULLPATH ) )
     ::cDriver   = ( nWorkArea )->( RddName() )
     ::lShared   = ( nWorkArea )->( DbInfo( DBI_SHARED ) )

     #ifdef __HARBOUR__
        ::lReadOnly = ( nWorkArea )->( DbInfo( DBI_ISREADONLY ) )
     #else
        DEFAULT ::lReadOnly := .f.
     #endif

     DEFAULT ::lBuffer   := .t.
     DEFAULT ::lOemAnsi  := .f.

     DEFAULT ::bNetError := { || MsgStop( "Record in use", "Please, retry"
) }

     ::aStruct   = ( ::cAlias )->( DbStruct() )
     ::aFldNames = {}
     ::aBuffer := hb_HSetCaseMatch( hb_Hash(), .F. )

     for n = 1 to ( ::cAlias )->( FCount() )
        AAdd( ::aFldNames, ( ::cAlias )->( FieldName( n ) ) )
        ::HashAddMember( {( ::cAlias )->( FieldName( n ) )},;
                          ( ::cAlias )->( FieldType( n ) ),;
                          ( ::cAlias )->( FieldGet( n ) ),;
                          ::aBuffer )
     next
     hb_HSetAutoAdd( ::aBuffer, .f. )
     if ::lOemAnsi
        ::OemToAnsi()
     endif
     #ifdef __XPP__
        if ClassObject( Alias() ) == nil
           ClassCreate( Alias(), { TDataBase() }, aDatas, aMethods )
        // else
        //   ::this = Self
        endif
     #endif
  endif

return Self

METHOD _FieldGet( nPos ) CLASS xDataBase

  if ::lBuffer
     //return ::aBuffer[ nPos ]
     Return HB_HVALUEAT( ::aBuffer, nPos )
  else
     return ( ::nArea )->( FieldGet( nPos ) )
  endif

return nil
//--------------------------------------------------------------------------
-//

METHOD _FieldPut( nPos, uValue ) CLASS xDataBase

  local lLocked  := .f.

  if ::lBuffer
     //::aBuffer[ nPos ] := uValue
     HB_HVALUEAT( ::aBuffer, nPos, uValue )
  else
     if ::lShared
        if ! ::lReadOnly
           if ::IsRecLocked( ::RecNo() ) .or. ( lLocked := ::RecLock(
::RecNo() ) )
              ( ::nArea )->( FieldPut( nPos, uValue ) )
              if lLocked
                 ::Commit()
                 ::RecUnLock( ::RecNo() )
              endif
           else
              if ! Empty( ::bNetError )
                 return Eval( ::bNetError, Self )
              endif
           endif
        endif
     else
        ( ::nArea )->( FieldPut( nPos, uValue ) )
     endif
  endif

return nil

METHOD Load() CLASS xDataBase

  local n

  if ::lBuffer
     for n = 1 to ( ::cAlias )->( FCount() )
        ::aBuffer[ ::aFldNames[n] ] := ( ::cAlias )->( FieldGet( n ) )
     next

     if ::lOemAnsi
        ::OemToAnsi()
     endif
  endif

return nil

//--------------------------------------------------------------------------
--//

METHOD Modified() CLASS XDataBase

  local n

  if ::lBuffer
     for n := 1 to Len( ::aFldNames )

        if ! ( ::cAlias )->( FieldGet( n ) ) == ::aBuffer[ ::aFldNames[n] ]
           return .t.
        endif
     next
  endif

return .f.

METHOD Blank() CLASS XDataBase

  LOCAL a := HB_HKEYS( ::aBuffer )
  if ::lBuffer
     AEval( a, { |u,i| HB_HVALUEAT( ::aBuffer, i, uValBlank( u )) } )
  endif

return .f.

METHOD _OemToAnsi() CLASS XDataBase

  local n

  for n = 1 to Len( ::aFldNames )
     if ValType( ::aBuffer[ ::aFldNames[n] ] ) == "C"
        ::aBuffer[ ::aFldNames[n] ] := OemToAnsi( ::aBuffer[ ::aFldNames[n]
] )
     endif
  next

return nil

METHOD SaveBuff() CLASS XDataBase

  local n

  if ::lBuffer
     for n := 1 to Len( ::aFldNames )
        if ::lOemAnsi .and. ValType( ::aBuffer[ ::aFldNames[n] ] ) == "C"
           ( ::nArea )->( FieldPut( n, AnsiToOem( ::aBuffer[ ::aFldNames[n]
] ) ) )
        else
           ( ::nArea )->( FieldPut( n, ::aBuffer[ ::aFldNames[n] ] ) )
        endif
     next
  endif

return nil


****************************************************************************
************************************
* Descripción :
* Parámetros  : Ninguno
* Fecha       : 06/21/06
* Autor       : Equipo de desarrollo de Aicom
****************************************************************************
************************************
  METHOD HashAddMember( aName, cType, uInit, oObj ) CLASS xDataBase
//--------------------------------------------------------------------------
------------------------------------
  local cName

  if !( cType == nil )

     switch Upper( Left( cType, 1 ) )

        case "S" // STRING

             if uInit == nil
                uInit := ""
             endif

             exit

        case "N" // NUMERIC

             if uInit == nil
                uInit := 0
             endif

             exit

        case "L" // LOGICAL

             if uInit == nil
                uInit := .f.
             endif

             exit

        case "D" // DATE

             if uInit == nil
                uInit := CtoD( "" )
             endif

             exit

        case "C" // CODEBLOCK

             if uInit == nil
                uInit := { || nil }
             endif

             exit

        case "A" // ARRAY

             if uInit == nil
                uInit := {}
             endif

             exit

     end switch

  endif

return NIL


#pragma BEGINDUMP

#include "windows.h"
#include "hbapi.h"
#include "hbapierr.h"
#include "hbapiitm.h"
#include "hbapicls.h"
#include "hbvm.h"
#include "hbdate.h"
#include "hboo.ch"
#include "hbapirdd.h"
#include "hbstack.h"
#include "hbapilng.h"

char * AicomGetmessage();

HB_FUNC_STATIC( XDATABASE_ONERROR )
{


       char * cMessage       = AicomGetmessage() ;
       PHB_ITEM pSelf        = hb_stackSelfItem();
       BOOL bBuffer          = hb_itemGetL( hb_objSendMsg(pSelf, "LBUFFER",
0) );
       PHB_ITEM pValue       = hb_param(1,HB_IT_ANY);
       const char *cKey      = ( *cMessage == '_'  ?  (cMessage+1) :
cMessage ) ;


       if( bBuffer)
       {
              PHB_ITEM pHash = hb_objSendMsg(pSelf,"ABUFFER",0);
              PHB_ITEM pKey  = hb_itemPutC( hb_itemNew(NULL), cKey );

               if( *cMessage == '_' )
               {
       // Con esto asignamos un valor al buffer
                       if( pHash && pKey && pValue )
                       {
                               hb_hashAdd( pHash, pKey, pValue );
                               hb_itemRelease( pKey );
                       }
                       else
                           hb_errRT_BASE( EG_ARG, 1123, NULL,
HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
               } else
               {
                       // Esto devuelve el valor del buffer
                       PHB_ITEM pDest = hb_hashGetItemPtr( pHash, pKey,
HB_HASH_AUTOADD_ACCESS );
                       hb_itemRelease( pKey );
                       if(pDest)
                           hb_itemReturn(pDest);
                       else
                           hb_errRT_BASE( EG_BOUND, 1132, NULL,
hb_langDGetErrorDesc( EG_ARRACCESS ), 2, pHash, pValue );
               }
       }
       else
       {
               int iAreaAnt    = hb_rddGetCurrentWorkAreaNumber();
// Area anterior
               int iAreaAct    = hb_itemGetNI( hb_objSendMsg(pSelf,
"NAREA", 0 ) );    // Buscamos actual
               AREAP pArea     = ( AREAP )
hb_rddGetCurrentWorkAreaPointer();              // Necesitamos pArea
               USHORT uiField  = hb_rddFieldIndex( pArea, cKey );
// FieldPos ( cFieldName )
               hb_rddSelectWorkAreaNumber( iAreaAct ) ;
// Seleccionamos area actual

               if(uiField)
               {
                       if( *cMessage == '_' )
                       {
                       // Asignamos el valor
                               if( pValue && !HB_IS_NIL( pValue ) )
                               {
                                       if( SELF_PUTVALUE( pArea, uiField,
pValue ) == SUCCESS )
                                       {
                                               hb_itemReturn( pValue );
                                       }
                               }
                       } else
                       {
                       // Devolvemos el valor del campo
                               PHB_ITEM pItem = hb_itemNew( NULL );
                               if( pArea ) // && uiField )
                               {
                                       SELF_GETVALUE( pArea, uiField, pItem
);
                               }
                               hb_itemReturnRelease( pItem );
                       }
                       hb_rddSelectWorkAreaNumber( iAreaAnt ) ;
// Seleccionamos area anterior
               } else
               {
                       hb_errRT_DBCMD(( *cMessage == '_' ? 1005 : 1004 ),
0, "Field not found", cKey );
               }

       }
}

char * AicomGetmessage()
{
// Thanks to Przemek
long lOffset = hb_stackBaseProcOffset( 0 ); 
char * cMessage =  (char *)hb_itemGetSymbol( hb_stackItem( lOffset ) )->szName; 
return cMessage ;
}
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42080
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Postby James Bott » Fri Dec 19, 2008 8:35 pm

Antonio,

I am getting the errors below when I try to compile the test program. I am using FWH 8.08/xHarbour (the xHarbour that came with FWH).

I don't seem to have the file hbapicls.h on my computer (I did a search to make sure it wasn't a path issue).

Regards,
James



Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
XDbase.c:
Error E2209 XDbase.prg 353: Unable to open include file 'hbapicls.h'
Warning W8065 XDbase.prg 367: Call to function 'AicomGetmessage' with no prototype in function HB_FUN_XDATABASE_ONERROR
Warning W8065 XDbase.prg 386: Call to function 'hb_hashAdd' with no prototype in function HB_FUN_XDATABASE_ONERROR
Error E2451 XDbase.prg 390: Undefined symbol 'HB_ERR_FUNCNAME' in function HB_FUN_XDATABASE_ONERROR
Error E2451 XDbase.prg 394: Undefined symbol 'HB_HASH_AUTOADD_ACCESS' in function HB_FUN_XDATABASE_ONERROR
Warning W8065 XDbase.prg 394: Call to function 'hb_hashGetItemPtr' with no prototype in function HB_FUN_XDATABASE_ONERROR
Warning W8069 XDbase.prg 394: Nonportable pointer conversion in function HB_FUN_XDATABASE_ONERROR
Warning W8065 XDbase.prg 446: Call to function 'hb_stackBaseProcOffset' with no prototype in function AicomGetmessage
*** 3 errors in Compile ***
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
Fatal: Unable to open file 'XDBASE.OBJ'
Last edited by James Bott on Sat Dec 20, 2008 2:51 am, edited 1 time in total.
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby James Bott » Fri Dec 19, 2008 8:44 pm

Antonio,

It seems there were lots of wordwraps put into the code when it was posted in the message. I can fix most of them, but I am not sure about the C syntax. Can you email me a zipped copy of the original PRG?

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby fraxzi » Sat Dec 20, 2008 1:30 am

Mr. Antonio,

I suggest that this class be included/updated with FHW8.11 so I (we) can start downloading the 8.11....


2Cents!



P.S.
- ....before my 2 months update expires :lol: :lol: :lol:


Happy Holidays!


Regards,
Last edited by fraxzi on Sat Dec 20, 2008 7:15 am, edited 1 time in total.
Kind Regards,
Frances

Fivewin for xHarbour v18.07
xHarbour v1.2.3.x
BCC 7.3 + PellesC8 ( Resource Compiler only)
ADS 10.1 / MariaDB
Crystal Reports 8.5/9.23 DE
xMate v1.15
User avatar
fraxzi
 
Posts: 811
Joined: Tue May 06, 2008 4:28 am
Location: Philippines

Postby fraxzi » Sat Dec 20, 2008 1:53 am

I have this error during compilation using xMate:

Image


Also, I can't find some files like "hbapicls.h" on my development directory...


Regards,
Last edited by fraxzi on Sat Dec 20, 2008 2:14 am, edited 1 time in total.
Kind Regards,
Frances

Fivewin for xHarbour v18.07
xHarbour v1.2.3.x
BCC 7.3 + PellesC8 ( Resource Compiler only)
ADS 10.1 / MariaDB
Crystal Reports 8.5/9.23 DE
xMate v1.15
User avatar
fraxzi
 
Posts: 811
Joined: Tue May 06, 2008 4:28 am
Location: Philippines

Include file : hbapicls.h

Postby ukoenig » Sat Dec 20, 2008 2:03 am

Hello,

this file You can find in => HARBOUR/include ( not xHARBOUR )


/*
* $Id: hbapicls.h 8359 2008-04-22 02:51:18Z druzus $
*/

/*
* Harbour Project source code:
* Harbour class API
*
* Copyright 2006 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://www.harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/

....
....

Regards
Uwe :lol:
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Postby fraxzi » Sat Dec 20, 2008 2:13 am

Dear Uwe,


Sorry for that. I'm using xHarbour only. 8)


Is there a way to compile this class using xHarbour (build.6195 from Fivetech) :?:


Regards,
Kind Regards,
Frances

Fivewin for xHarbour v18.07
xHarbour v1.2.3.x
BCC 7.3 + PellesC8 ( Resource Compiler only)
ADS 10.1 / MariaDB
Crystal Reports 8.5/9.23 DE
xMate v1.15
User avatar
fraxzi
 
Posts: 811
Joined: Tue May 06, 2008 4:28 am
Location: Philippines

Testing

Postby ukoenig » Sat Dec 20, 2008 12:20 pm

Hello < fraxzi >
It seems, that it is not working with XHARBOUR.

Antonio's description :
As a special gift from Santa (thanks Jose Luis!) here you have it to start using it. It has been tested with

Harbour in PC and Pocket PC.
----------------------------------

Your feedback is welcome.

Regards
Uwe :lol:
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Postby Antonio Linares » Sat Dec 20, 2008 2:47 pm

James, Uwe, Frances,

I have not tested this code myself yet. But reviewing it, I see that it uses hashes to avoid the AScan that we do from the method OnError().

For xHarbour users, we could test these improvements:

To avoid the AScan(), we can do instead of:
Code: Select all  Expand view
         if ( nField := AScan( ::aFldNames,;
                             { | cField | SubStr( cMsg, 2 ) == ;
                                 RTrim( SubStr( cField, 1, 9 ) ) } ) ) != 0
            ::FieldPut( nField, uParam1 )

this code:
Code: Select all  Expand view
         if ( nField := ::FieldPos( SubStr( cMsg, 2 ) ) ) != 0
            ::FieldPut( nField, uParam1 )
Last edited by Antonio Linares on Sat Dec 20, 2008 3:25 pm, edited 1 time in total.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42080
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Postby Antonio Linares » Sat Dec 20, 2008 2:50 pm

Also, I wonder if hashes are faster than calling FieldPos().

I guess that FieldPos() may be quite similar in speed as hashes.

Of course we could also get speed improvement porting OnError() to C code as Jose Luis does.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42080
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Postby jlcapel » Sat Dec 20, 2008 7:14 pm

Hi to all,

Well... this class was only created and tested in Harbour for PPC.

Let me explain a little what this class do.

We have done two type of enhancements. First we have changed arrays from abuffer to hashes. This change allow eliminate all ascans (which normally slow down performance). The second change is about error handler. Error handler is now in low level, that is, in C.

In our tests we have noticed that in assigning and setting values to/from now are about 4 or 5 times faster than with original tDatabase.

For example, this test:

FOR x := 1 TO 50000
oDb:MyField := "somevalue"
NEXT

in original tdatabase needs 35 seconds to complete whilst with new class it only needs 9 seconds (tests done on PPC emulator)

The rest of the class remains unchanged. As you can see, this class inherits from tDatabase. This is because for testing purposes it is easier to change from xDatabase to tDatabase instead of changing .mak files.

And about xHarbour... well I shall take a look next week (if I have time enought).

I hope you'll enjoy it.

Regards,
José Luis Capel
User avatar
jlcapel
 
Posts: 229
Joined: Wed Oct 12, 2005 5:32 pm
Location: Valencia - España

Postby Maurizio » Mon Dec 22, 2008 8:40 am

Hi

Work directly on the DBF is 4/5 time faster that work with TDATABSE .
I use this function ( with xHarbour ) for load and save the date in a hash .

Regards Maurizio
Code: Select all  Expand view
//--------------------------------------------------------------------------

Function MAin()
Local aVArs
USE "CLI01.dbf"
aVars := LoadDbf()

aVars:CODPRO := "ABCD"

SaveDbf(aVars)
use
Return nil

Function LoadDbf()  // Scatter()
  Local  aVars := {=>}
  LOcal nField := FCount()
  LOcal nX := 1
  FOR nX  := 1 TO  nField
      aVars[FIELDNAME(nX)] := FieldGet(nX)
  NEXT

Return aVars

//--------------------------------------------------------------------------
Function  SaveDbf(aVArs)     //Gather(aVars)
    lOCAL Nx  := 1
    FOR Nx  := 1 TO  LEN(aVars)
            FieldPut(nX,aVArs[FIELDNAME(nX)]  )
    NEXT
Return TRUE

//--------------------------------------------------------------------------
Function  Blank(aVars) 
   local i,nX
   i := len(aVars)
   for nX :=1 to i
     do case
        case valtype(aVars[FIELDNAME(nX)]) == "C" ; aVars[FIELDNAME(nX)] := space(len(aVars[FIELDNAME(nX)]))
        case valtype(aVars[FIELDNAME(nX)]) == "N" ; aVars[FIELDNAME(nX)] := 0
        case valtype(aVars[FIELDNAME(nX)]) == "D" ; aVars[FIELDNAME(nX)] := CTOD("00-00-00")
        case valtype(aVars[FIELDNAME(nX)]) == "M" ; aVars[FIELDNAME(nX)] := space(200)
        case valtype(aVars[FIELDNAME(nX)]) == "L" ; aVars[FIELDNAME(nX)] := .F.
     endcase
   next
  Return  aVars






User avatar
Maurizio
 
Posts: 824
Joined: Mon Oct 10, 2005 1:29 pm

Postby Antonio Linares » Mon Dec 22, 2008 10:23 am

Maurizio,

Very good example, thanks :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42080
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Postby demont frank » Mon Dec 22, 2008 12:33 pm

Maurizio wrote:Hi

Work directly on the DBF is 4/5 time faster that work with TDATABSE .
I use this function ( with xHarbour ) for load and save the date in a hash .

Regards Maurizio
Code: Select all  Expand view
//--------------------------------------------------------------------------

Function MAin()
Local aVArs
USE "CLI01.dbf"
aVars := LoadDbf()

aVars:CODPRO := "ABCD"

SaveDbf(aVars)
use
Return nil

Function LoadDbf()  // Scatter()
  Local  aVars := {=>}
  LOcal nField := FCount()
  LOcal nX := 1
  FOR nX  := 1 TO  nField
      aVars[FIELDNAME(nX)] := FieldGet(nX)
  NEXT

Return aVars

//--------------------------------------------------------------------------
Function  SaveDbf(aVArs)     //Gather(aVars)
    lOCAL Nx  := 1
    FOR Nx  := 1 TO  LEN(aVars)
            FieldPut(nX,aVArs[FIELDNAME(nX)]  )
    NEXT
Return TRUE

//--------------------------------------------------------------------------
Function  Blank(aVars) 
   local i,nX
   i := len(aVars)
   for nX :=1 to i
     do case
        case valtype(aVars[FIELDNAME(nX)]) == "C" ; aVars[FIELDNAME(nX)] := space(len(aVars[FIELDNAME(nX)]))
        case valtype(aVars[FIELDNAME(nX)]) == "N" ; aVars[FIELDNAME(nX)] := 0
        case valtype(aVars[FIELDNAME(nX)]) == "D" ; aVars[FIELDNAME(nX)] := CTOD("00-00-00")
        case valtype(aVars[FIELDNAME(nX)]) == "M" ; aVars[FIELDNAME(nX)] := space(200)
        case valtype(aVars[FIELDNAME(nX)]) == "L" ; aVars[FIELDNAME(nX)] := .F.
     endcase
   next
  Return  aVars


Maybe
Local aVars := {=>}

Better is
LOCAL aVars := TAssociativeArray()

Then we can use fieldname OR fieldnumber

aVars:CODPRO := "ABCD"

Can also written as

aVars["CODPRO"] := "ABCD"
// didn't know your syntax

OR

aVars[1] := "ABCD" supposing it is the first field


Frank
demont frank
 
Posts: 167
Joined: Thu Mar 22, 2007 11:24 am

Postby StefanHaupt » Mon Dec 22, 2008 4:09 pm

Hi,

I´m using a similar method for reading dbf´s, but I additionally check the type of each field to get a default values and to resize teh len of of the arrayelement to the size of the field. For every array element there is a define

Maybe it´s usefull for somebody

Code: Select all  Expand view
#define C_STATUS 1
....
::aStruct := (::cAlias)->(dbStruct())


METHOD ReadData (lNew) CLASS TComputer

LOCAL aData := Array(Len(::aStruct))
LOCAL i := 1

DEFAULT lNew := .F.

IF lNew

  FOR i := 1 TO LEN (::aStruct)
    DO CASE
    CASE ::aStruct[i,DBS_TYPE]=="N"
      aData[i] := 0
    CASE ::aStruct[i,DBS_TYPE]=="C"
      aData[i] := SPACE (::aStruct[i,DBS_LEN])
    CASE ::aStruct[i,DBS_TYPE]=="L"
      aData[i] := .F.
    CASE ::aStruct[i,DBS_TYPE]=="D"
      aData[i] := CTOD ("  .  .    ")
    CASE ::aStruct[i,DBS_TYPE]=="M"
      aData[i] := SPACE (1024)
    OTHERWISE
      aData[i] := SPACE (10)
    ENDCASE
  NEXT
  aData[C_STATUS] := 1  // bei Neueinträgen immer active
ELSE

  FOR i := 1 TO LEN (::aStruct)
    IF ::aStruct[i,DBS_TYPE]=="M"
      aData[i] := PADR ( (::cAlias)->(FIELDGET(i)),1024)
    ELSE
      aData[i] := IIF (::aStruct[i,DBS_TYPE]=="C",;
                       PADR ( (::cAlias)->(FIELDGET(i)),::aStruct[i,DBS_LEN]),;
                       (::cAlias)->(FIELDGET(i)) )
    ENDIF
  NEXT

  aData[C_TYP]+=1

ENDIF


RETURN (aData)
kind regards
Stefan
StefanHaupt
 
Posts: 824
Joined: Thu Oct 13, 2005 7:39 am
Location: Germany

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 75 guests