/* * Proyecto: xaFastReport * Fichero: FrDataset.prg * Descripción: Concector dataset para Fast Report * Autor: Ignacio Ortiz de Zúñiga * Fecha: 03/06/2013 */ #include "Xailer.ch" #include "FastReport.ch" //------------------------------------------------------------------------------ CLASS XFrDataset FROM TComponent PUBLISHED: PROPERTY oReport WRITE METHOD SetReport EDITOR PE_Component AS TFastReport PROPERTY cName WRITE SetName READ GetName PROPERTY nMaxRecsOnDesign INIT 100 PROPERTY oDsMaster WRITE SetMasterDetail EDITOR PE_COMPONENT AS TFrDataset PROPERTY aRelationFields INIT {} WRITE SetRelationFields EDITOR PE_STRINGLIST // "DetField1=MasField1;...; DetFieldN=MasterFiedlN" PROPERTY lLoadOnDemand INIT .f. EVENT OnAfterLoad( oSender ) // --> NIL EVENT OnClose( oSender ) // --> NIL EVENT OnFirst( oSender ) // --> NIL EVENT OnNext( oSender ) // --> NIL EVENT OnOpen( oSender ) // --> NIL EVENT OnPrior( oSender ) // --> NIL EVENT OnCreate( oSender ) // --> NIL PUBLIC: DATA nLoaded INIT 0 READONLY // 0 Not Loaded, 1 Design, 2 Normal METHOD New( oParent ) CONSTRUCTOR METHOD Create( oParent ) CONSTRUCTOR METHOD Free() METHOD Refresh() INLINE ::Load() METHOD IsActive() INLINE ::nDbInstance > 0 METHOD IsLoaded() INLINE ::nLoaded > 0 METHOD SetMaster( oDsMaster, aFields ) INLINE ::SetMasterDetail( oDsMaster ),; ::SetRelationFields( aFields ) METHOD ForceReload() INLINE ::nLoaded := NOT_LOADED RESERVED: DATA nDbInstance INIT 0 READONLY DATA lMasterDetail INIT .F. // Verdadero si se ha producido realmente el enlace DATA lComplete INIT .f. METHOD AfterLoad() INLINE ::OnAfterLoad() METHOD Build() VIRTUAL METHOD Load( lDesign ) INLINE ::nLoaded := IIF( lDesign, DESIGN_LOADED, FULL_LOADED ) METHOD RequestRecord() INLINE ( ::SetDBComplete(), .F. ) METHOD FieldExists( cName ) INLINE .F. METHOD ClearDB() METHOD GoFirst() VIRTUAL METHOD GoPrior() VIRTUAL METHOD GoNext() VIRTUAL PROTECTED: DATA aIFields INIT {} DATA cDefName INIT "Data" METHOD AddDataSet( cName ) METHOD SetDBComplete() INLINE ( ::lComplete := .T., ::oReport:SetDBComplete( ::nDbInstance ) ) METHOD AddField( cName, cType, nLen, lDec ) METHOD AddRecord() METHOD AddValue( cField, xValue ) METHOD GetBasicType( cType, lDec ) METHOD SetReport( oReport ) METHOD SetName( cName ) METHOD GetName() METHOD SetMasterDetail( oDbMaster ) METHOD SetRelationFields( aFields ) END CLASS //------------------------------------------------------------------------------ METHOD New( oParent ) CLASS XFrDataset ::Super:New( oParent ) IF ::oParent != Nil ::oParent:InsertComponent( Self ) ENDIF RETURN Self //------------------------------------------------------------------------------ METHOD Create( oParent ) CLASS XFrDataset LOCAL oDS LOCAL nFor LOCAL lExiste := .f. ::Super:Create( oParent ) IF ::oParent != Nil ::oParent:InsertComponent( Self ) ENDIF // Si ya existe un dataset con dicho nombre lo reutilizamos. Entendemos // que los campos no han cambiado y tan sólo hacemos un zap IF ::oReport != NIL FOR nFor := 1 TO Len( ::oReport:aDatasets ) oDS := ::oReport:aDatasets[ nFor ] IF oDS != NIL .AND. Upper( oDS:cName ) == Upper( ::cName ) lExiste := .t. Self := ::oReport:aDatasets[ nFor ] ::nLoaded := NOT_LOADED EXIT ENDIF NEXT IF !lExiste AAdd( ::oReport:aDatasets, Self ) ENDIF ENDIF ::OnCreate( lExiste ) RETURN Self //------------------------------------------------------------------------------ METHOD Free() CLASS XFrDataset ::SetReport() ::FcName := "" ::nDbInstance := 0 ::nLoaded := NOT_LOADED ::aIFields := {} RETURN ::Super:Free() //------------------------------------------------------------------------------ METHOD AddDataSet( cName ) CLASS XFrDataset UPDATE ::cName TO cName IF ::nDbInstance > 0 ::ClearDB() ENDIF ::nDbInstance := ::oReport:AddFrDataSet( ::cName ) ::aIFields := {} RETURN !Empty( ::nDbInstance ) //------------------------------------------------------------------------------ // Nota: Este método tan sólo borra los datos del dataset. No lo elimina del informe METHOD ClearDB() CLASS XFrDataset LOCAL lSuccess IF ::nDbInstance > 0 lSuccess := ::oReport:ClearDB( ::nDbInstance, .f. ) // Segundo parámetro inútil ENDIF ::nLoaded := NOT_LOADED RETURN lSuccess //------------------------------------------------------------------------------ METHOD AddField( cName, cType, nLen, lDec ) CLASS XFrDataset LOCAL nType IF Empty( cName ) cName := "FIELD" ENDIF nType := ::GetBasicType( cType, lDec ) cName := ValidName( cName, ::aIFields ) AAdd( ::aIFields, cName ) ::oReport:AddFrField( ::nDbInstance, cName, nType, nLen ) RETURN nType //------------------------------------------------------------------------------ METHOD AddRecord() CLASS XFrDataset RETURN ::oReport:AddFrRecord( ::nDbInstance ) //------------------------------------------------------------------------------ METHOD AddValue( cField, xValue ) CLASS XFrDataset RETURN ::oReport:AddFrValue( ::nDbInstance, cField, xValue ) //------------------------------------------------------------------------------ METHOD SetReport( oReport ) CLASS XFrDataset IF ::FoReport != NIL ::ClearDB( .t. ) ::FoReport:DelDataset( Self ) ENDIF ::FoReport := oReport IF oReport != NIL .AND. ::lCreated AAdd( oReport:aDatasets, Self ) ENDIF RETURN oReport //------------------------------------------------------------------------------ METHOD SetName( cName ) CLASS XFrDataset IF Empty( cName ) cName := "DATASET" ENDIF cName := StrPattern( cName, " :,.$!%&?-;{}@#()=*<>", .F. ) IF !::IsActive() .OR. ::oReport:SetDBName( ::nDbInstance, cName ) ::FcName := cName ENDIF RETURN ::FcName //------------------------------------------------------------------------------ METHOD GetName() CLASS XFrDataset LOCAL aValues := {} LOCAL oDS IF Empty( ::FcName ) .AND. ::oReport != NIL FOR EACH oDS IN ::oReport:aDatasets IF oDS != NIL .AND. !( oDS == Self ) AAdd( aValues, oDS:FcName ) ENDIF NEXT ::FcName := ValidName( ::cDefName, aValues ) ENDIF RETURN ::FcName //------------------------------------------------------------------------------ METHOD GetBasicType( cType, lDec ) CLASS XFrDataset LOCAL nType DEFAULT lDec TO .f. IF cType == NIL cType := "C" ELSEIF Len( cType ) > 1 IF Upper( cType ) == "MONEY" //Error ADS cType := "N" ELSE cType := "C" ENDIF ENDIF SWITCH cType CASE "C" nType := PROPERTY_CADENA EXIT CASE "D" CASE "T" CASE "@" nType := PROPERTY_FECHA EXIT CASE "L" nType := PROPERTY_LOGICO EXIT CASE "N" CASE "+" nType := IIF( lDec, PROPERTY_NUMERO_DOBLE, PROPERTY_NUMERO_ENTERO ) EXIT CASE "M" CASE "W" nType := PROPERTY_BLOB EXIT OTHERWISE nType := PROPERTY_BLOB EXIT END SWITCH RETURN nType //------------------------------------------------------------------------------ METHOD SetMasterDetail( oDsMaster ) CLASS XFrDataset IF ::FoDsMaster != NIL .AND. ::lMasterDetail ::oReport:ClearMasterDetail( ::FoDsMaster:cName, ::cName ) ENDIF ::FoDsMaster := oDsMaster RETURN ::FoDsMaster //------------------------------------------------------------------------------ METHOD SetRelationFields( aFields ) CLASS XFrDataset ::FaRelationFields := aFields RETURN ::FaRelationFields //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ CLASS XFrXailerDataset FROM TFrDataset PUBLISHED: PROPERTY oDataset WRITE METHOD SetDataset EDITOR PE_COMPONENT AS TDataset PROPERTY aFields INIT {"*"} WRITE METHOD SetFields EDITOR PE_StringList RESERVED: METHOD Build( cName, oDataset ) METHOD Load( lDesign ) METHOD RequestRecord() METHOD Free() METHOD FieldExists( cName ) METHOD GoFirst() INLINE ::oDataset:GoTop() METHOD GoPrior() INLINE ::oDataset:Skip( -1 ) METHOD GoNext() INLINE ::oDataset:Skip( 1 ) PROTECTED: DATA aNames INIT {} DATA cDefName INIT "Dataset" METHOD SetDataset( oDataset ) METHOD SetFields( aFields ) END CLASS //------------------------------------------------------------------------------ METHOD SetDataset( oDataset ) CLASS XFrXailerDataset IF ::IsActive() ::ClearDB( .t. ) ENDIF ::FoDataset := oDataset IF Empty( ::cName ) .AND. oDataset != NIL ::cName := oDataset:cName ENDIF ::nDbInstance := 0 ::nLoaded := NOT_LOADED ::aIFields := {} RETURN ::FoDataset //------------------------------------------------------------------------------ METHOD SetFields( aFields ) CLASS XFrXailerDataset LOCAL nFor IF ::IsActive() ::ClearDB( .t. ) ENDIF ::FaFields := aFields ::aNames := {} RETURN ::FaFields //------------------------------------------------------------------------------ METHOD Free() CLASS XFrXailerDataset ::oDataset := NIL ::aFields := {} RETURN ::Super:Free() //------------------------------------------------------------------------------ METHOD Build( cName, oDataset ) CLASS XFrXailerDataset LOCAL oField LOCAL cField, cAlias IF !Empty( oDataset ) ::oDataset := oDataset ENDIF IF !Empty( cName ) ::cName := cName ENDIF IF ::oReport == NIL .OR. ::oDataset == NIL .OR. ::IsActive() RETURN .f. ENDIF ::AddDataSet( ::cName ) IF Empty( ::aFields ) .OR. Empty( ::aFields[ 1 ] ) .OR. ::aFields[ 1 ] == "*" FOR EACH oField IN ::oDataset:aFields WITH OBJECT oField cField := :cName ::AddField( @cField, :cType, :nLen, :nDec > 0 ) Aadd( ::aNames, { oField, cField } ) END WITH NEXT FOR EACH oField IN ::oDataset:aUserFields WITH OBJECT oField cField := :cName ::AddField( @cField, :cType, :nLen, :nDec > 0 ) Aadd( ::aNames, { oField, cField } ) END WITH NEXT ELSE FOR EACH cField IN ::aFields GetFieldInfo( @cField, @cAlias ) oField := ::oDataset:oFieldByName( cField ) IF oField != NIL WITH OBJECT oField ::AddField( @cAlias, :cType, :nLen, :nDec > 0 ) Aadd( ::aNames, { oField, cAlias } ) END WITH ENDIF NEXT ENDIF RETURN .t. //------------------------------------------------------------------------------ METHOD Load( lDesign ) CLASS XFrXailerDataset LOCAL oRep, oField LOCAL aField LOCAL nDb, nMax LOCAL lCmp DEFAULT lDesign TO .f. IF ::lLoadOnDemand nMax := Max( ::nMaxRecsOnDesign, 10 ) lCmp := .f. ELSEIF lDesign .AND. ::nMaxRecsOnDesign > 0 nMax := ::nMaxRecsOnDesign lCmp := .f. ELSE lCmp := .t. ENDIF oRep := ::oReport nDb := ::nDbInstance IF Empty( ::nDbInstance ) RETURN .f. ENDIF ::ClearDB() /* Accedemos directamente a oReport para ir un poco más rápido */ WITH OBJECT ::oDataset IF !:lOpen RETURN .f. ENDIF :SaveState( .t. ) :GoTop() DO WHILE !:Eof() .AND. ( lCmp .OR. nMax-- > 0 ) oRep:AddFrRecord( nDb ) FOR EACH aField IN ::aNames WITH OBJECT aField[ 1 ] oRep:AddFrValue( nDb, aField[ 2 ], :Value ) END WITH NEXT :Skip() ENDDO :RestoreState( .t. ) END WITH IF lCmp ::SetDBComplete() ENDIF ::nLoaded := IIF( lDesign, DESIGN_LOADED, FULL_LOADED ) RETURN .t. //------------------------------------------------------------------------------ METHOD RequestRecord() CLASS XFrXailerDataset LOCAL oRep, oField LOCAL nDb, lRet, lUpd oRep := ::oReport nDb := ::nDbInstance lRet := .f. WITH OBJECT ::oDataset lUpd := :lUpdLinked :lUpdLinked := .f. IF !:Eof() oRep:AddFrRecord( nDb ) FOR EACH oField IN :aFields WITH OBJECT oField oRep:AddFrValue( nDb, :cName, :Value ) END WITH NEXT lRet := .t. :Skip() ENDIF IF :Eof() :GoBottom() ::SetDBComplete() ENDIF :lUpdLinked := lUpd IF lUpd :Refresh() ENDIF END WITH RETURN lRet //------------------------------------------------------------------------------ METHOD FieldExists( cName ) CLASS XFrXailerDataset RETURN AScan( ::aNames, {|v| Upper( v[ 2 ] ) == Upper( cName ) } ) > 0 //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ CLASS XFrArrayDataset FROM TFrDataset PUBLISHED: PROPERTY aFields INIT {} WRITE METHOD SetFields EDITOR PE_StringList PUBLIC: PROPERTY aData INIT {} WRITE METHOD SetData PROPERTY nIndex INIT 0 READONLY PROPERTY lLoadOnDemand INIT .f. READONLY RESERVED: METHOD Build( cName, oDataset ) METHOD Load( lDesign ) METHOD Free() METHOD FieldExists( cName ) METHOD GoFirst() INLINE ::nIndex := 1 METHOD GoPrior() INLINE ::nIndex -- METHOD GoNext() INLINE ::nIndex ++ PROTECTED: DATA aNames INIT {} DATA cDefName INIT "Array" METHOD SetFields( aFields ) METHOD SetData( aData ) END CLASS //------------------------------------------------------------------------------ METHOD SetFields( aFields ) CLASS XFrArrayDataset LOCAL nFor IF ::IsActive() ::ClearDB( .t. ) ENDIF IF PCount() > 0 aFields := AClone( aFields ) ENDIF FOR nFor := 1 TO Len( aFields ) IF ValType( aFields[ nFor ] ) == "A" aFields[ nFor ] := aFields[ nFor, 1 ] + "," + aFields[ nFor, 2 ] + "," + ; LTrim(Str( aFields[ nFor, 3 ] ) ) + "," + ; LTrim(Str( aFields[ nFor, 4 ] ) ) ENDIF NEXT ::FaFields := aFields ::aNames := {} RETURN ::FaFields //------------------------------------------------------------------------------ METHOD SetData( aData ) CLASS XFrArrayDataset IF ::IsActive() ::ClearDB( .t. ) ENDIF ::FaData := aData ::nIndex := 1 RETURN ::FaData //------------------------------------------------------------------------------ METHOD Free() CLASS XFrArrayDataset ::aFields := {} ::aData := {} ::aNames := {} RETURN ::Super:Free() //------------------------------------------------------------------------------ METHOD Build( cName, aData ) CLASS XFrArrayDataset LOCAL aFields LOCAL cField, cType, nLen, nDec, nFor IF !Empty( aData ) ::aData := aData ENDIF IF !Empty( cName ) ::cName := cName ENDIF DEFAULT ::aFields TO {} IF ::oReport == NIL .OR. Empty( ::aFields ) .OR. ::IsActive() RETURN .f. ENDIF ::AddDataSet( ::cName ) aFields := ::aFields ::aNames := {} FOR nFor := 1 TO Len( aFields ) cField := hb_tokenGet( aFields[ nFor ], 1, "," ) cType := hb_tokenGet( aFields[ nFor ], 2, "," ) nLen := Val( hb_tokenGet( aFields[ nFor ], 3, "," ) ) nDec := Val( hb_tokenGet( aFields[ nFor ], 4, "," ) ) DEFAULT cField TO "Field" + LTrim( Str( nFor ) ) IF Empty( cType ) IF Len( ::aData ) > 0 .AND. Len( ::aData[ 1 ] ) <= nFor .AND. ::aData[ 1, nFor ] != NIL cType := ValType( ::aData[ 1, nFor ] ) ELSE cType := "C" ENDIF ELSEIF Len( cType ) > 1 IF Upper( cType ) == "MONEY" //Error ADS cType := "N" ELSE cType := "C" ENDIF ENDIF IF Empty( nLen ) SWITCH cType CASE "C" CASE "M" CASE "W" nLen := 65000 EXIT CASE "N" CASE "+" nLen := 15 EXIT CASE "L" nLen := 1 EXIT CASE "D" CASE "T" CASE "@" nLen := 8 EXIT END SWITCH ENDIF ::AddField( @cField, cType, nLen, nDec > 0 ) AAdd( ::aNames, cField ) NEXT RETURN .t. //------------------------------------------------------------------------------ METHOD Load( lDesign ) CLASS XFrArrayDataset LOCAL oRep, oField LOCAL aData, aRow, aNames, xValue LOCAL nDb, nPos, nMax DEFAULT lDesign TO .f. IF lDesign .AND. ::nMaxRecsOnDesign > 0 nMax := ::nMaxRecsOnDesign ELSE lDesign := .F. ENDIF oRep := ::oReport aData := ::aData aNames := ::aNames nDb := ::nDbInstance IF Empty( ::nDbInstance ) RETURN .f. ENDIF ::ClearDB( .f. ) /* Accedemos directamente a oReport para ir un poco más rápido */ FOR EACH aRow IN aData oRep:AddFrRecord( nDb ) nPos := 1 FOR EACH xValue IN aRow oRep:AddFrValue( nDb, aNames[ nPos++ ], xValue ) NEXT IF lDesign .AND. nMax-- < 0 EXIT ENDIF NEXT ::nLoaded := IIF( lDesign, DESIGN_LOADED, FULL_LOADED ) ::nIndex := nPos - 1 RETURN .t. //------------------------------------------------------------------------------ METHOD FieldExists( cName ) CLASS XFrArrayDataset RETURN AScan( ::aNames, {|v| Upper( v ) == Upper( cName ) } ) > 0 //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ CLASS XFrDbfDataset FROM TFrDataset PUBLISHED: PROPERTY aFields INIT {} WRITE METHOD SetFields EDITOR PE_StringList RESERVED: METHOD Build( cName, oDataset ) METHOD Load( lDesign ) METHOD RequestRecord() METHOD Free() METHOD FieldExists( cName ) METHOD GoFirst() INLINE (::cAlias)->( DbGoTop() ) METHOD GoPrior() INLINE (::cAlias)->( DbSkip( -1 ) ) METHOD GoNext() INLINE (::cAlias)->( DbSkip( 1 ) ) PROTECTED: DATA aNames INIT {} DATA cAlias INIT "" DATA cDefName INIT "Dbf" METHOD SetFields( aFields ) END CLASS //------------------------------------------------------------------------------ METHOD SetFields( aFields ) CLASS XFrDbfDataset IF ::IsActive() ::ClearDB( .t. ) ENDIF IF aFields == NIL aFields := { "*" } ELSEIF ValType( aFields ) == "C" aFields := { aFields } ENDIF ::FaFields := aFields ::aNames := {} RETURN ::FaFields //------------------------------------------------------------------------------ METHOD Free() CLASS XFrDbfDataset ::aFields := {} ::aNames := {} RETURN ::Super:Free() //------------------------------------------------------------------------------ METHOD Build( cName, aFields ) CLASS XFrDbfDataset LOCAL cAlias, cField, cType, cFrName LOCAL nLen, nDec, nFor IF !Empty( aFields ) ::aFields := aFields ENDIF IF !Empty( cName ) ::cName := cName ENDIF IF ::oReport == NIL .OR. Empty( ::aFields ) .OR. ::IsActive() RETURN .f. ENDIF ::AddDataSet( ::cName ) aFields := CheckMarks( ::aFields ) ::aNames := {} FOR nFor := 1 TO Len( aFields ) cField := aFields[ nFor ] IF GetDbfFieldInfo( @cField, @cAlias, @cType, @nLen, @nDec, @cFrName ) IF nFor == 1 ::cAlias := cAlias ::cDefName := cAlias ENDIF ::AddField( @cFrName, cType, nLen, nDec > 0 ) AAdd( ::aNames, { cFrName, FieldWBlock( cField, Select( cAlias ) ) } ) ENDIF NEXT RETURN .t. //------------------------------------------------------------------------------ METHOD Load( lDesign ) CLASS XFrDbfDataset LOCAL oRep, xValue LOCAL aNames LOCAL cOldAlias LOCAL nDb, nRecno, nLen, nFor, nMax LOCAL lCmp DEFAULT lDesign TO .f. IF ::lLoadOnDemand nMax := Max( ::nMaxRecsOnDesign, 10 ) lCmp := .f. ELSEIF lDesign .AND. ::nMaxRecsOnDesign > 0 nMax := ::nMaxRecsOnDesign lCmp := .f. ELSE lCmp := .t. ENDIF oRep := ::oReport aNames := ::aNames nDb := ::nDbInstance nLen := Len( aNames ) IF Empty( ::nDbInstance ) RETURN .f. ENDIF ::ClearDB() /* Accedemos directamente a oReport para ir un poco más rápido */ cOldAlias := Alias() IF Select( ::cAlias ) == 0 Select( cOldAlias ) RETURN .f. ELSE DbSelectArea( ::cAlias ) ENDIF IF lCmp nRecno := Recno() ENDIF GO TOP DO WHILE !Eof() .AND. ( lCmp .OR. nMax-- > 0 ) oRep:AddFrRecord( nDb ) FOR nFor := 1 TO nLen xValue := Eval( aNames[ nFor, 2 ] ) oRep:AddFrValue( nDb, aNames[ nFor, 1 ], xValue ) NEXT SKIP ENDDO IF lCmp ::SetDBComplete() DBGoTo( nRecno ) ENDIF DbSelectArea( cOldAlias ) ::nLoaded := IIF( lDesign, DESIGN_LOADED, FULL_LOADED ) RETURN .t. //------------------------------------------------------------------------------ METHOD RequestRecord() CLASS XFrDbfDataset LOCAL oRep, xValue LOCAL aNames LOCAL nDb, nLen, nFor LOCAL lRet oRep := ::oReport aNames := ::aNames nDb := ::nDbInstance nLen := Len( aNames ) lRet := .F. IF !(::cAlias)->( Eof() ) oRep:AddFrRecord( nDb ) FOR nFor := 1 TO nLen xValue := Eval( aNames[ nFor, 2 ] ) oRep:AddFrValue( nDb, aNames[ nFor, 1 ], xValue ) NEXT lRet := .T. (::cAlias)->( DbSkip() ) ENDIF IF (::cAlias)->( Eof() ) ::SetDBComplete() ENDIF RETURN lRet //------------------------------------------------------------------------------ METHOD FieldExists( cName ) CLASS XFrDbfDataset RETURN AScan( ::aNames, {|v| Upper( v[ 1 ] ) == Upper( cName ) } ) > 0 //------------------------------------------------------------------------------ STATIC FUNCTION GetDbfFieldInfo( cField, cAlias, cType, nLen, nDec, cName ) LOCAL cOldAlias LOCAL nAt, nPos nAt := At( "->", cField ) IF nAt = 0 cAlias := Alias() ELSE cAlias := Left( cField, nAt - 1 ) cField := SubStr( cField, nAt + 2 ) ENDIF IF Empty( cAlias ) RETURN .f. ENDIF nAt := At( " AS ", Upper( cField ) ) IF nAt > 0 cName := SubStr( cField, nAt + 4 ) cField := Left( cField, nAt - 1 ) ELSE cName := cField ENDIF cOldAlias := Alias() IF Select( cAlias ) == 0 Select( cOldAlias ) RETURN .f. ELSE DbSelectArea( cAlias ) ENDIF nPos := FieldPos( cField ) IF Empty( nPos ) DbSelectArea( cOldAlias ) RETURN .f. ENDIF cType := Left( FieldType( nPos ), 1 ) nLen := FieldLen( nPos ) nDec := FieldDec( nPos ) DbSelectArea( cOldAlias ) RETURN .t. //------------------------------------------------------------------------------ STATIC FUNCTION GetFieldInfo( cField, cAlias ) LOCAL nAt nAt := At( " AS ", Upper( cField ) ) IF nAt > 0 cAlias := SubStr( cField, nAt + 4 ) cField := Left( cField, nAt - 1 ) ELSE cAlias := cField ENDIF RETURN .t. //------------------------------------------------------------------------------ STATIC FUNCTION CheckMarks( aFields ) LOCAL aList := {}, aInfo, aTemp LOCAL cField, cAlias LOCAL nAt FOR EACH cField IN aFields IF Right( cField, 1 ) == "*" IF ( nAt := At( "->", cField ) ) > 0 cAlias := Left( cField, nAt - 1 ) aInfo := (cAlias)->( DBStruct() ) cAlias += "->" ELSE cAlias := "" aInfo := DBStruct() ENDIF FOR EACH aTemp IN aInfo AAdd( aList, cAlias + aTemp[ 1 ] ) NEXT ELSE AAdd( aList, cField ) ENDIF NEXT RETURN aList //------------------------------------------------------------------------------ STATIC FUNCTION ValidName( cName, aNames ) LOCAL nVal, nPos, nLen DO WHILE Ascan( aNames, {|v| Upper( v ) == Upper( cName ) } ) > 0 nLen := nPos := Len( cName ) nVal := 0 DO WHILE nPos > 0 .AND. IsDigit( Substr( cName, nPos, 1 ) ) nPos -- ENDDO IF nPos < nLen nVal := Val( Substr( cName, nPos + 1 ) ) cName := Substr( cName, 1, nPos ) ENDIF cName += lTrim( Str( ++ nVal ) ) ENDDO RETURN cName