Skip to content

Commit a8a6e85

Browse files
authored
Implements (partial) functions CURSORSETPROP() AND CURSORGETPROP() (#1954)
* Implements (partial) functions CURSORSETPROP() AND CURSORGETPROP() * Use CursorProperty enum instead of strings in CursorSetPro/CursorGetProp
1 parent ada6e9b commit a8a6e85

3 files changed

Lines changed: 264 additions & 30 deletions

File tree

src/Runtime/XSharp.VFP.Tests/CommandTests.prg

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,66 @@ BEGIN NAMESPACE XSharp.VFP.Tests
288288
TRY ; System.IO.Directory.Delete(cTempPath, TRUE) ; CATCH ; END TRY
289289
END TRY
290290
END METHOD
291+
292+
[Fact];
293+
METHOD TestCursorSetPropAndCursorGetProp() AS VOID
294+
VAR cOldDir := System.IO.Directory.GetCurrentDirectory()
295+
VAR oDir := System.IO.Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), ;
296+
"CursorPropTest_" + Guid.NewGuid():ToString("N")))
297+
VAR cTempPath := oDir:FullName
298+
299+
TRY
300+
SET DEFAULT TO (cTempPath)
301+
CREATE TABLE TmpX (Id INT, Name C(20), Active L)
302+
INSERT INTO TmpX VALUES (1, "Alice", .T.)
303+
GO TOP
304+
305+
// Default buffering is 1 (off)
306+
Assert.Equal(1, (INT) CursorGetProp("Buffering"))
307+
Assert.Equal(3, (INT) CursorGetProp("SourceType"))
308+
309+
// Set buffering to optimistic table (5)
310+
Assert.True(CursorSetProp("Buffering", 5))
311+
Assert.Equal(5, (INT) CursorGetProp("Buffering"))
312+
313+
// Set buffering to pessimistic row (2) -- by alias
314+
Assert.True(CursorSetProp("Buffering", 2, "TmpX"))
315+
Assert.Equal(2, (INT) CursorGetProp("Buffering"))
316+
317+
// Set buffering -- by workarea number
318+
Assert.True(CursorSetProp("Buffering", 3, Select()))
319+
Assert.Equal(3, (INT) CursorGetProp("Buffering"))
320+
321+
// Invalid buffering value -> FALSE
322+
Assert.False(CursorSetProp("Buffering", 0))
323+
Assert.False(CursorSetProp("Buffering", 6))
324+
Assert.False(CursorSetProp("Buffering", "abc"))
325+
326+
// Invalid alias -> FALSE for SET, NIL for GET
327+
Assert.False(CursorSetProp("Buffering", 2, "NoSuchAlias"))
328+
Assert.False(CursorGetProp("Buffering", "NoSuchAlias"))
329+
330+
// Read-only properties
331+
VAR cSrc := CursorGetProp("SourceName")
332+
Assert.True(IsString(cSrc))
333+
Assert.True(((STRING) cSrc):Contains(".DBF"))
334+
Assert.Equal("", (STRING) CursorGetProp("Database"))
335+
Assert.Equal("", (STRING) CursorGetProp("SQL"))
336+
Assert.Equal(0, (INT) CursorGetProp("ConnectHandle"))
337+
338+
// Cargo cleared on close
339+
Assert.True(CursorSetProp("Buffering", 5))
340+
XSharp.CoreDb.CloseAll()
341+
DbUseArea(TRUE, "DBFVFP", Path.Combine(cTempPath, "TmpX.dbf"), "TmpX", FALSE, FALSE)
342+
Assert.Equal(1, (INT) CursorGetProp("Buffering"))
343+
344+
FINALLY
345+
XSharp.CoreDb.CloseAll()
346+
SET DEFAULT TO (cOldDir)
347+
System.IO.Directory.SetCurrentDirectory(cOldDir)
348+
TRY ; System.IO.Directory.Delete(cTempPath, TRUE) ; CATCH ; END TRY
349+
END TRY
350+
END METHOD
291351
END CLASS
292352

293353
END NAMESPACE

src/Runtime/XSharp.VFP/Cursors/DbFunctions.prg

Lines changed: 204 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
USING System
88
USING System.Collections.Generic
99
USING System.Text
10+
USING XSharp.RDD
1011

1112
INTERNAL FUNCTION _DoInArea<T>(uArea as Usual, action as @@Func<T>, defaultValue as T, cFunction as STRING, nArg as DWORD) as T
1213
IF IsNil(uArea)
@@ -354,24 +355,212 @@ INTERNAL FUNCTION _AreaFromParam(uArea AS USUAL) AS DWORD
354355

355356
RETURN 0
356357

358+
INTERNAL CLASS _WorkareaCargo
359+
export fldState AS Dictionary<INT, BYTE>
360+
EXPORT cursorProps AS Dictionary<CursorProperty, OBJECT>
361+
362+
CONSTRUCTOR()
363+
fldState := Dictionary<INT, BYTE>{}
364+
cursorProps := Dictionary<CursorProperty, OBJECT>{}
365+
END CONSTRUCTOR
366+
END CLASS
367+
368+
INTERNAL FUNCTION _GetWorkareaCargo(nArea AS DWORD) AS _WorkareaCargo
369+
VAR oCargo := RuntimeState.Workareas:GetCargo(nArea)
370+
IF oCargo IS _WorkareaCargo VAR cargo
371+
RETURN cargo
372+
ENDIF
373+
VAR newCargo := _WorkareaCargo{}
374+
RuntimeState.Workareas:SetCargo(nArea, newCargo)
375+
RETURN newCargo
376+
357377
INTERNAL FUNCTION _GetFldStateFromCargo(nArea AS DWORD, nField AS INT) AS BYTE
358-
LOCAL cargo AS Dictionary<INT,BYTE>
359-
LOCAL oCargo := RuntimeState.Workareas:GetCargo(nArea) AS OBJECT
360-
IF oCargo IS Dictionary<INT,BYTE> VAR dict
361-
LOCAL b AS BYTE
362-
IF dict:TryGetValue(nField, REF b)
363-
RETURN b
364-
ENDIF
378+
VAR cargo := _GetWorkareaCargo(nArea)
379+
LOCAL b as BYTE
380+
if cargo:fldState:TryGetValue(nField, REF b)
381+
return b
365382
ENDIF
366383
RETURN 1
367384

368385
INTERNAL FUNCTION _SetFldStateInCargo(nArea AS DWORD, nField AS INT, nState AS BYTE) AS VOID
369-
LOCAL oCargo := RuntimeState.Workareas:GetCargo(nArea) AS OBJECT
370-
LOCAL dict AS Dictionary<INT,BYTE>
371-
IF oCargo IS Dictionary<INT,BYTE> VAR existing
372-
dict := existing
373-
ELSE
374-
dict := Dictionary<INT,BYTE>{}
375-
RuntimeState.Workareas:SetCargo(nArea, dict)
386+
VAR cargo := _GetWorkareaCargo(nArea)
387+
cargo:fldState[nField] := nState
388+
389+
INTERNAL STATIC CLASS _CursorPropDefaults
390+
INTERNAL STATIC _defaults AS Dictionary<CursorProperty, OBJECT>
391+
392+
STATIC CONSTRUCTOR
393+
_defaults := Dictionary<CursorProperty, OBJECT>{}
394+
_defaults:Add(CursorProperty.Buffering, 1)
395+
_defaults:Add(CursorProperty.AutoIncError, FALSE)
396+
_defaults:Add(CursorProperty.FetchMemo, FALSE)
397+
_defaults:Add(CursorProperty.FetchSize, 100)
398+
_defaults:Add(CursorProperty.MapBinary, FALSE)
399+
_defaults:Add(CursorProperty.MapVarchar, FALSE)
400+
_defaults:Add(CursorProperty.MaxRecords, -1)
401+
_defaults:Add(CursorProperty.Refresh, -2)
402+
_defaults:Add(CursorProperty.CompareMemo, TRUE)
403+
_defaults:Add(CursorProperty.FetchAsNeeded, FALSE)
404+
_defaults:Add(CursorProperty.Prepared, FALSE)
405+
_defaults:Add(CursorProperty.SendUpdates, FALSE)
406+
_defaults:Add(CursorProperty.UpdateType, 1)
407+
_defaults:Add(CursorProperty.WhereType, 3)
408+
_defaults:Add(CursorProperty.UseMemoSize, 255)
409+
_defaults:Add(CursorProperty.BatchUpdateCount, 1)
410+
END CONSTRUCTOR
411+
412+
INTERNAL STATIC METHOD GetDefault(prop AS CursorProperty) AS OBJECT
413+
LOCAL result AS OBJECT
414+
IF _defaults:TryGetValue(prop, REF result)
415+
return result
416+
ENDIF
417+
RETURN NIL
418+
END METHOD
419+
420+
INTERNAL STATIC METHOD SetDefault(prop AS CursorProperty, oValue AS OBJECT) AS VOID
421+
_defaults[prop] := oValue
422+
END METHOD
423+
END CLASS
424+
425+
INTERNAL FUNCTION _GetCursorProp(nArea AS DWORD, prop AS CursorProperty) AS OBJECT
426+
VAR cargo := _GetWorkareaCargo(nArea)
427+
LOCAL result AS OBJECT
428+
if cargo:cursorProps:TryGetValue(prop, REF result)
429+
RETURN result
430+
ENDIF
431+
432+
RETURN _CursorPropDefaults.GetDefault(prop)
433+
434+
INTERNAL FUNCTION _SetCursorProp(nArea AS DWORD, prop AS CursorProperty, oValue AS OBJECT) AS VOID
435+
LOCAL cargo AS _WorkareaCargo
436+
cargo := _GetWorkareaCargo(nArea)
437+
cargo:cursorProps[prop] := oValue
438+
439+
440+
/// <include file="VFPDocs.xml" path="Runtimefunctions/cursorsetprop/*" />
441+
[FoxProFunction("CURSORSETPROP", FoxFunctionCategory.CursorAndTable, FoxEngine.WorkArea, FoxFunctionStatus.Partial, FoxCriticality.High)];
442+
FUNCTION CursorSetProp(cProperty, eExpression, uArea) AS LOGIC CLIPPER
443+
IF !IsString(cProperty)
444+
RETURN FALSE
445+
ENDIF
446+
VAR cProp := (STRING) cProperty
447+
VAR nProp := GetCursorProperty(cProp)
448+
VAR prop := (CursorProperty) nProp
449+
VAR lSessionDefault := IsNumeric(uArea) .AND. (INT) uArea == 0
450+
IF lSessionDefault
451+
IF nProp == (LONG) CursorProperty.Buffering
452+
IF IsNumeric(eExpression)
453+
VAR nVal := (INT) eExpression
454+
IF nVal < 1 .OR. nVal > 5
455+
RETURN FALSE
456+
ENDIF
457+
ELSE
458+
RETURN FALSE
459+
ENDIF
460+
ENDIF
461+
_CursorPropDefaults.SetDefault(prop, eExpression)
462+
RETURN TRUE
376463
ENDIF
377-
dict[nField] := nState
464+
VAR nArea := _AreaFromParam(uArea)
465+
IF nArea == 0
466+
RETURN FALSE
467+
ENDIF
468+
VAR nOldArea := RuntimeState.CurrentWorkarea
469+
RuntimeState.CurrentWorkarea := nArea
470+
TRY
471+
IF !Used()
472+
RETURN FALSE
473+
ENDIF
474+
SWITCH prop
475+
CASE CursorProperty.Buffering
476+
IF !IsNumeric(eExpression)
477+
RETURN FALSE
478+
ENDIF
479+
LOCAL nBuff := (INT) eExpression AS INT
480+
IF nBuff < 1 .OR. nBuff > 5
481+
RETURN FALSE
482+
ENDIF
483+
_SetCursorProp(nArea, CursorProperty.Buffering, nBuff)
484+
RETURN TRUE
485+
CASE CursorProperty.AutoIncError
486+
IF !IsLogic(eExpression)
487+
RETURN FALSE
488+
ENDIF
489+
_SetCursorProp(nArea, CursorProperty.AutoIncError, eExpression)
490+
RETURN TRUE
491+
CASE CursorProperty.Refresh
492+
IF !IsNumeric(eExpression)
493+
RETURN FALSE
494+
ENDIF
495+
_SetCursorProp(nArea, CursorProperty.Refresh, eExpression)
496+
RETURN TRUE
497+
OTHERWISE
498+
_SetCursorProp(nArea, prop, eExpression)
499+
RETURN TRUE
500+
END SWITCH
501+
FINALLY
502+
RuntimeState.CurrentWorkarea := nOldArea
503+
END TRY
504+
505+
/// <include file="VFPDocs.xml" path="Runtimefunctions/cursorgetprop/*" />
506+
[FoxProFunction("CURSORGETPROP", FoxFunctionCategory.CursorAndTable, FoxEngine.WorkArea, FoxFunctionStatus.Partial, FoxCriticality.High)];
507+
FUNCTION CursorGetProp(cProperty, uArea) AS USUAL CLIPPER
508+
IF !IsString(cProperty)
509+
RETURN NIL
510+
ENDIF
511+
VAR cProp := (STRING) cProperty
512+
VAR nProp := GetCursorProperty(cProp)
513+
VAR prop := (CursorProperty) nProp
514+
VAR lSessionDefault := IsNumeric(uArea) .AND. (INT) uArea == 0
515+
IF lSessionDefault
516+
RETURN _CursorPropDefaults.GetDefault(prop)
517+
ENDIF
518+
VAR nArea := _AreaFromParam(uArea)
519+
IF nArea == 0
520+
RETURN FALSE
521+
ENDIF
522+
VAR nOldArea := RuntimeState.CurrentWorkarea
523+
RuntimeState.CurrentWorkarea := nArea
524+
TRY
525+
IF !Used()
526+
RETURN FALSE
527+
ENDIF
528+
SWITCH prop
529+
CASE CursorProperty.SourceType
530+
RETURN 3
531+
CASE CursorProperty.SourceName
532+
RETURN DbInfo(DBI_FULLPATH)
533+
CASE CursorProperty.Database
534+
RETURN ""
535+
CASE CursorProperty.SQL
536+
RETURN ""
537+
CASE CursorProperty.ConnectHandle
538+
RETURN 0
539+
CASE CursorProperty.ConnectName
540+
RETURN ""
541+
CASE CursorProperty.Tables
542+
RETURN ""
543+
CASE CursorProperty.KeyFieldList
544+
RETURN ""
545+
CASE CursorProperty.UpdatableFieldList
546+
RETURN ""
547+
CASE CursorProperty.UpdateNameList
548+
RETURN ""
549+
CASE CursorProperty.ParameterList
550+
RETURN ""
551+
CASE CursorProperty.RecordsFetched
552+
RETURN -1
553+
CASE CursorProperty.FetchIsComplete
554+
RETURN TRUE
555+
CASE CursorProperty.ADOBookmark
556+
RETURN NIL
557+
CASE CursorProperty.ADOCodePage
558+
RETURN 0
559+
CASE CursorProperty.ADORecordset
560+
RETURN NIL
561+
OTHERWISE
562+
RETURN _GetCursorProp(nArea, prop)
563+
END SWITCH
564+
FINALLY
565+
RuntimeState.CurrentWorkarea := nOldArea
566+
END TRY

src/Runtime/XSharp.VFP/ToDo-C.prg

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,6 @@ FUNCTION CreateOffline (ViewName , cPath)
4444
THROW NotImplementedException{}
4545
// RETURN FALSE
4646

47-
/// <summary>-- todo --</summary>
48-
/// <include file="VFPDocs.xml" path="Runtimefunctions/cursorgetprop/*" />
49-
[FoxProFunction("CURSORGETPROP", FoxFunctionCategory.CursorAndTable, FoxEngine.WorkArea, FoxFunctionStatus.Stub, FoxCriticality.High)];
50-
FUNCTION CursorGetProp (cProperty , uArea)
51-
THROW NotImplementedException{}
52-
// RETURN NIL
53-
54-
55-
/// <summary>-- todo --</summary>
56-
/// <include file="VFPDocs.xml" path="Runtimefunctions/cursorsetprop/*" />
57-
[FoxProFunction("CURSORSETPROP", FoxFunctionCategory.CursorAndTable, FoxEngine.WorkArea, FoxFunctionStatus.Stub, FoxCriticality.High)];
58-
FUNCTION CursorSetProp (cProperty , eExpression, uArea)
59-
THROW NotImplementedException{}
60-
// RETURN FALSE
61-
6247
/// <summary>-- todo --</summary>
6348
/// <include file="VFPDocs.xml" path="Runtimefunctions/cursortoxml/*" />
6449
[FoxProFunction("CURSORTOXML", FoxFunctionCategory.General, FoxEngine.RuntimeCore, FoxFunctionStatus.Stub, FoxCriticality.Medium)];

0 commit comments

Comments
 (0)