A much faster Class TDataBase !!!

User avatar
Antonio Linares
Site Admin
Posts: 42750
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 110 times
Been thanked: 108 times
Contact:

A much faster Class TDataBase !!!

Post by Antonio Linares »

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

#include "fivewin.ch"#include "dbinfo.ch"function main()local o, x, nSec, n := 0, a[100], bREQUEST 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 //&&,DBFCDXREQUEST DBFFPTRDDSETDEFAULT("DBFCDX")SET AUTOPEN OFFSET DELETED ONSET CENTURY ONSET EPOCH TO( Year(Date())-50 )SET DATE BRITISH    // Formato dd-mm-aaaaSET EXCLUSIVE OFFSET SOFTSEEK OFFHB_LangSelect('ES')HB_SetCodePage("ESMWIN") // Para ordenación (arrays, cadenas, etc..)msginfo("Iniciamos")o := xDatabase()      // Nueva clase derivada de tDatabase de fivewino: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 )nextMsginfo(Seconds()-nSec, "Test de lectura de datos")// Test de velocidad en lectura con movimientosnSec := Seconds()for x=1 to 10000 o:Gotop() Do while !o:Eof()    uFunc( o:Codpro )    o:Skip() EnddonextMsginfo(Seconds()-nSec, "Test de lectura")// Test de velocidad en EscrituranSec := Seconds()for x=1 to 10000 o:Gotop() Do while !o:Eof()    o:Codpro := "Proba" + Alltrim(Str(x))    o:Skip() EnddonextMsginfo(Seconds()-nSec, "Test de escritura")return NILFUNCTION 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 )ENDCLASSMETHOD 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  endifreturn SelfMETHOD _FieldGet( nPos ) CLASS xDataBase  if ::lBuffer     //return ::aBuffer[ nPos ]     Return HB_HVALUEAT( ::aBuffer, nPos )  else     return ( ::nArea )->( FieldGet( nPos ) )  endifreturn 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  endifreturn nilMETHOD Load() CLASS xDataBase  local n  if ::lBuffer     for n = 1 to ( ::cAlias )->( FCount() )        ::aBuffer[ ::aFldNames[n] ] := ( ::cAlias )->( FieldGet( n ) )     next     if ::lOemAnsi        ::OemToAnsi()     endif  endifreturn 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  endifreturn .f.METHOD Blank() CLASS XDataBase  LOCAL a := HB_HKEYS( ::aBuffer )  if ::lBuffer     AEval( a, { |u,i| HB_HVALUEAT( ::aBuffer, i, uValBlank( u )) } )  endifreturn .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  nextreturn nilMETHOD 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  endifreturn 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  endifreturn 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
James Bott
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

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
Contact:

Post by James Bott »

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
fraxzi
Posts: 811
Joined: Tue May 06, 2008 4:28 am
Location: Philippines
Contact:

Post by fraxzi »

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
Contact:

Post by fraxzi »

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
ukoenig
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany
Contact:

Include file : hbapicls.h

Post by ukoenig »

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
fraxzi
Posts: 811
Joined: Tue May 06, 2008 4:28 am
Location: Philippines
Contact:

Post by fraxzi »

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
ukoenig
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany
Contact:

Testing

Post by ukoenig »

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
Antonio Linares
Site Admin
Posts: 42750
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 110 times
Been thanked: 108 times
Contact:

Post by Antonio Linares »

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

         if ( nField := AScan( ::aFldNames,;                             { | cField | SubStr( cMsg, 2 ) == ;                                 RTrim( SubStr( cField, 1, 9 ) ) } ) ) != 0            ::FieldPut( nField, uParam1 )

this code:

Code: Select all | Expand

         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: 42750
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 110 times
Been thanked: 108 times
Contact:

Post by Antonio Linares »

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
jlcapel
Posts: 229
Joined: Wed Oct 12, 2005 5:32 pm
Location: Valencia - España
Contact:

Post by jlcapel »

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
Maurizio
Posts: 832
Joined: Mon Oct 10, 2005 1:29 pm
Contact:

Post by Maurizio »

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

//--------------------------------------------------------------------------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)]  )    NEXTReturn 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
Antonio Linares
Site Admin
Posts: 42750
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Has thanked: 110 times
Been thanked: 108 times
Contact:

Post by Antonio Linares »

Maurizio,

Very good example, thanks :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
demont frank
Posts: 167
Joined: Thu Mar 22, 2007 11:24 am

Post by demont frank »

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

//--------------------------------------------------------------------------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)]  )    NEXTReturn 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
StefanHaupt
Posts: 824
Joined: Thu Oct 13, 2005 7:39 am
Location: Germany

Post by StefanHaupt »

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

#define C_STATUS 1....::aStruct := (::cAlias)->(dbStruct())METHOD ReadData (lNew) CLASS TComputerLOCAL aData := Array(Len(::aStruct))LOCAL i := 1DEFAULT 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 activeELSE  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]+=1ENDIFRETURN (aData)
kind regards
Stefan
Post Reply