I have an application that includes the use of a single record file that contains various settings, ie. paths to various data files, program options, program activation details. My issue is that my code is not allowing the record to be saved. I am using Clarion9 with Topspeed data files. The file name is S_SysData
The code I am using to open the record at the Window Events > Opening Windows embed point is as follows:
! Initial Entry to S_SysData
!----------------------------
IF Records(S_SysData) = 0 !If no record
Access:S_SysData.Insert() !add blank entry
END
Set(S_SysData)
Access:S_SysData.Next()
The code I am using to close the record at the Control Event > Ok button > Accepted is as follows:
!Update Last Modified Date Time & User
!-------------------------------------
SYD:RMD = TODAY()
SYD:RMT = CLOCK()
SYD:RMB = 'SYSADMIN'
Access:S_SysData.Update()
BREAK
The error message I get when trying to save the record is "An error (Record Not Available (33)) was experienced when making changes to the M:\APP02\DATA\S_SysData file.
What should I have done to ensure the record was available?
Additionally, the Insert() can fail if you have some field validations on your DCT and you’re adding an empty record.
It’s better to use the ADD function…
Most file actions will trigger an errorcode of some kind. Check for errors as you go.
PROGRAM
MyFileName CSTRING(FILE:MaxFilePath+1)
S_SysData FILE,DRIVER('TOPSPEED'),PRE(SYS),CREATE,NAME(MyFileName)
RECORD RECORD
RMD LONG
RMT LONG
RMB STRING(60)
Note STRING(100)
END
END
MAP
END
CODE
MyFileName = LONGPATH('.\SysData.tps') ! Assuming for this example that we're not in a protected area here
LOOP 2 TIMES
OPEN(S_SysData)
CASE ERRORCODE()
OF 2 ! File not found
CREATE(S_SysData)
IF ERRORCODE()
MESSAGE('Could not create "' & MyFileName & '"|' & ERROR())
RETURN
END
CYCLE
OF 0
BREAK
ELSE
MESSAGE('Could not open "' & MyFileName & '"|' & ERROR())
RETURN
END
END
SET(S_SysData)
NEXT(S_SysData)
IF ERRORCODE()
SYS:RMD = TODAY()
SYS:RMT = CLOCK()
SYS:RMB = 'SYSADMIN'
ADD(S_SysData)
IF ERRORCODE()
MESSAGE('Could not add a record to "' & MyFileName & '"|' & ERROR())
RETURN
END
END
SYS:Note = 'Last Run ' & CLIP(LEFT(FORMAT(TODAY(), @d2b))) & ' ' & CLIP(LEFT(FORMAT(CLOCK(),@t1)))
PUT(S_SysData)
IF ERRORCODE()
MESSAGE('There was a problem writing the record: ' & ERROR() & ' ' & ERRORCODE())
RETURN
END
MESSAGE('SYS:RMD=' & FORMAT(SYS:RMD,@d2b) & '|SYS:RMT=' & FORMAT(SYS:RMT,@t3) & '|SYS:RMB=' & SYS:RMB & '|SYS:Note=" ' & CLIP(SYS:Note) & '"')
RETURN
You can override the field validation in the global embeds File, Field section with an low priority Return Level:Benign, even better you can wrap that Return Level:Benign in a condition to make field validation optional based on the conditions coded for.
I said it was off-topic because it doesn’t help your original problem. But to elaborate on my comment it is my belief that a “System” file is better structured with several fields and a key that points to the info you need. e.g.
Then, when you want a value you get it by finding the Sys:PropertyNameKey.
I believe this is preferable to a single record containing all your values because, with Topspeed in particular, you need to change your dct and rebuild your file every time you add a new value to your System file.
And in my unwashed youth (before even SOAP) I included several spare LONGs and a large STRING that I could OVER when I needed to add new configuration items.
One way to handle this is to create normal Form template procedure that handles the file updates.
Then you just need to create a Source procedure that does the things a Browse does in the Insert and Change buttons.
This code was written on my phone and from memory so others please note what’s wrong:
Access:S_SysData.Open()
Access:S_SysData.UseFile() ! So file is opened for Clarion statements
IF Records(S_SysData) = 0 !If no record
GET(S_SysData,0)
CLEAR(S_SysData )
GlobalRequest = InsertRecord
ELSE
Set(S_SysData)
WATCH(S_SysData) !Form optimistic concurrency
Next(S_SysData)
GlobalRequest = ChangeRecord
END
S_SysData_FormProcedure()
Access:S_SysData.Close()
RETURN
Hi,
I use a single record for control in my program - all the way from Clarion for DOS to C11.
I supply the application with a single record in the file. I do not let the system add it.
After my Main Window opens I call a routine - first to make sure the expiration date is not exceeded:
CK_EXPIRE ROUTINE !MAKE SURE THE PROGRAM HAS NOT EXPIRED
share(maindATA)
get(maindata,1)
CLOSE(MAINDATA)
if mai:expire <> ' ' ! if date entered
if today() - mai:expire > 0 !expired
halt(0,'THIS PROGRAM HAS EXPIRED')
.
.
Then I call my CONTROL record and modify settings - again, one record - no inserts - only edits:
ctl_check ROUTINE !check status
DAYNAME = 'DAY' & (SUB(YEAR(TODAY()),-2,2)) !****SET TO current YEAR
SUMNAME = 'SUM' & (SUB(YEAR(TODAY()),-2,2)) !****SET TO current YEAR
share(control)
LOOP
HOLD(CONTROL)
Set(CONTROL)
Next(control) ! no access
IF ERRORCODE() = 43 | !HELD
OR CON:REPAIR !OR = 1 --> REPAIR IN PROGRESS
RELEASE(CONTROL)
CYCLE
ELSE
if CON:date <> today() !if not todays date
if CON:ctlstatus =6 !ERROR CODE FOR NOT DAYJOURNAL NOT PRINTED
MEM:STATUS = 6
release(control)
do err_6 !will return after screen show
.
share(DAYJOURN)
share(SUMMARY)
set(dayjourn)
previous(dayjourn)
if error() then stop('error getting previous dayjournal').
Access:DAYJOURN.Close()
set(summary)
previous(summary)
if error() then stop('error getting previous summary').
CLOSE(SUMMARY)
if day:tdate <> sum:date !journal was not printed for previous date
RELEASE(CONTROL)
DO NOT_DONE
else
IF TODAY() < SUM:DATE !IF SYSTEM DATE IS BEFORE THE LAST RECORD
release(control)
do w_date
!@@@ return !** Check for return value required **
.
CON:date = today()
CON:ctlstatus = 0 !set to no records added
MEM:STATUS = 0
CON:ACTIVE = 0 !NO ACTIVE STATIONS RESET IN CASE DUMP OUT ON BREAK OR ERROR!
.
else !if it is todays date
if CON:ctlstatus = 0 !no records added yet
MEM:STATUS = 0
elsif CON:ctlstatus =1 !records added
MEM:STATUS = 1
elsif CON:ctlstatus =5 !dayjournal already printed for today
MEM:STATUS = 5
elsif CON:ctlstatus =6 !ERROR CODE FOR NOT DAYJOURNAL NOT PRINTED
MEM:STATUS = 6
release(control)
do err_6 !will return after screen show
.
.
PUT(CONTROL)
RELEASE(CONTROL)
CLOSE(CONTROL)
BREAK
. .
This simple code just keeps chugging on in my windows app.
Ron
Per the Help on HOLD you will not get Error 43 “Record Is Already Held”
unless you use HOLD(file, Time Out Seconds).
Your code will wait forever for the record to be released. It would be good to check for other Errors. Like maybe the file did not open, or is corrupt.