COPY TO ARRAY problems II
don´t know if the mentioned problems have already been fixed ...
-
The func __BuildFieldList() uses XSharp.VFP.Functions.ALen() instead of XSharp.Rt.Functions.ALen() Without the changes - see the comments in the modified __BuildFieldList() code - an InvalidCastException is thrown.
-
The COPY to ARRAY command is translated to a DbCopyToArray() call. But the order of the written DbCopyToArray() parameters doesn´t work - see the comments in the sample code.
-
It´s possible to declare LIKE and EXCEPT fields, but currently both are ignored.
To make the COPY TO ARRAY command - at least partially - work , i modified the result pattern. ( see the #define USE_THIS_COPY_TO_ARRAY_COMMAND )
Using the modified command something like:
COPY TO ARRAY aResult1 FOR a->Last = "G"
results no longer in:
aResult1 := DbCopyToArray( { }, NULL_STRING , NULL_STRING , {||a->Last="G"} , , , , .F. , .F. )
but in this code:
aResult1 := DbCopyToArray( { }, {||a->Last="G"} , , , , .F. , .F. , NULL_STRING , NULL_STRING )
regards Karl-Heinz
// 2.9.1.1 build + Fox dialect
//
// /Memvar+ /ppo+
USING System.Collections.Generic
USING XSharp.RDD.Support
// #define USE_THIS_COPY_TO_ARRAY_COMMAND
#ifdef USE_THIS_COPY_TO_ARRAY_COMMAND
#command COPY TO ARRAY <arrayName> [FIELDS <f1> [,<fn> ] ] ;
[LIKE <%include%>] [EXCEPT <%exclude%> ] ;
[FOR <FOR>] ;
[WHILE <WHILE>] ;
[NEXT <NEXT>] ;
[RECORD <rec>] ;
[<rest:REST>] ;
[<noopt: NOOPTIMIZE>] ;
[ALL] ;
;
=> <arrayName> := DbCopyToArray( ;
{<(f1)>[, <(fn)> ]}, ;
<{FOR}>, <{WHILE}>, <NEXT>, <rec>, <.rest.>, ;
<.noopt.> , #<include>, #<exclude> ;
)
#endif
FUNCTION Start( ) AS VOID
LOCAL cPfad, cDbf AS STRING
LOCAL i AS DWORD
LOCAL aFields, aValues AS ARRAY
LOCAL dDate AS date
// ? RddSetDefault() // "DBFVFP"
cPfad := "D:\TEST\"
cDBF := cPfad + "FooArray"
dDate := Today()
aFields := { { "LAST" , "C" , 10 , 0 } , { "FIRST" , "C" , 10 , 0 } , { "DATE" , "D" , 8 , 0 } }
// -------------------
DbCreate( cDBF , AFields)
DbUseArea( ,,cDBF )
aValues := { "G1" , "A1" , "G2" , "G3" , "C1" , "D3" , "E56" , "G45"}
FOR i := 1 TO ALen ( aValues )
DbAppend()
FieldPut ( 1 , aValues [ i ] )
FieldPut ( 2 , "First" + NTrim ( i ) )
FieldPut ( 3 , dDate ++ )
NEXT
DbCloseArea()
DbUseArea ( ,, cDbf )
// -------------
PRIVATE aResult1 // yes, this works ;-)
// Dimension aResult1(1)
// ----------------------------------
COPY TO ARRAY aResult1 FOR a->Last = "G"
? IIF ( aResult1 IS __FOXARRAY , "aResult1 contains a FoxArray" , "aResult1 contains no FoxArray" )
?
//
// The - unchanged - command is translated to:
// aResult1 := DbCopyToArray( { }, NULL_STRING , NULL_STRING , {||a->Last="G"} , , , , .F. , .F. )
// but the DbCopyToArray() signature is:
// FUNCTION DbCopyToArray(aFieldList, cbForCondition, cbWhileCondition, nNext,nRecord, lRest, lNoOptimize) AS ARRAY CLIPPER
// This parameter order gives the expected result.
// aResult1 := DbCopyToArray( {}, {||_Field->Last="G"} ) // <----------
// ------------------------------
// DbGoTop()
// COPY TO ARRAY aResult1 fields LAST NEXT 3
//
// The -unchanged- command is translated to:
// aResult1 := DbCopyToArray( { "LAST" }, NULL_STRING , NULL_STRING , , , 3 , , .F. , .F. )
// but the DbCopyToArray() signature is:
// FUNCTION DbCopyToArray(aFieldList, cbForCondition, cbWhileCondition, nNext,nRecord, lRest, lNoOptimize) AS ARRAY CLIPPER
//
// This parameter order gives the expected result.
// aResult1 := DbCopyToArray( { "LAST" }, , , 3 ) // <-------------
// ---------------------------
ShowArray ( aResult1 )
// ------------------
DbCloseArea()
RETURN
// ---------------------------
// required X# runtime sources
// ---------------------------
INTERNAL FUNCTION DbCopyToArraySingleRecord(aFields AS IList<STRING> ) AS ARRAY // unchanged
LOCAL result AS ARRAY
result := ArrayNew(aFields:Count)
FOR VAR i := 1 TO aFields:Count
result[i] := __FieldGet(aFields[i-1])
NEXT
RETURN result
FUNCTION DbCopyToArray(aFieldList, cbForCondition, cbWhileCondition, nNext,nRecord, lRest, lNoOptimize) AS ARRAY CLIPPER // unchanged
VAR aFields := __BuildFieldList(aFieldList, FALSE)
LOCAL aResult := {} AS ARRAY
DbEval( {|| AAdd(aResult, DbCopyToArraySingleRecord(aFields)) }, cbForCondition, cbWhileCondition, nNext,nRecord, lRest, lNoOptimize )
RETURN aResult
INTERNAL FUNCTION __BuildFieldList(aFieldList AS USUAL, lIncludeMemo AS LOGIC) AS IList<STRING> // modified !
VAR selected := List<STRING>{}
// The current "ALen(aFieldList)>0" causes an InvalidCastException because XSharp.VFP.Functions.ALen() is used
// instead of XSharp.Rt.Functions.ALen()
//
// To make it work i replaced the line:
// IF IsArray(aFieldList) .and. ALen(aFieldList) > 0
// with this one:
IF IsArray(aFieldList) .and. XSharp.RT.Functions.ALen(aFieldList) > 0
FOREACH cFld AS STRING IN aFieldList
selected:Add(cFld:ToString())
NEXT
RETURN selected
ENDIF
LOCAL fCount AS DWORD
fCount := FCount()
FOR VAR nFld := 1u TO fCount
LOCAL lInclude AS LOGIC
LOCAL cType := NIL AS USUAL
VoDb.FieldInfo(DBS_TYPE, nFld,@cType)
SWITCH (STRING) cType
CASE "M"
lInclude := lIncludeMemo
CASE "G"
lInclude := FALSE
OTHERWISE
lInclude := TRUE
END SWITCH
IF lInclude
LOCAL oVar := NULL AS OBJECT
VoDb.FieldInfo( DBS_STRUCT, nFld, REF oVar)
VAR oFld := (RddFieldInfo) oVar
IF oFld:Alias != NULL
selected:Add(oFld:Alias:ToUpperInvariant())
ELSE
selected:Add(oFld:Name:ToUpperInvariant())
ENDIF
ENDIF
NEXT
RETURN selected