Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

What to do to avoid database being "corrupted"? 5

Status
Not open for further replies.

Mandy_crw

Programmer
Jul 23, 2020
585
PH
I have revised and revised my app, i have five database opened every time my app is opened, two application actually, all databases are shared by the two applications... in my exit i usually add a line Clear all, close database then programatically shuts down the computer... but lately, twice actually, two of the databases are always corrupt when the app is opened in the next day.... is there anything that i have to add to exit so i can avoid my database being corrupted? Thanks everyone... God bless.....
 
Ok Chriss Thank you so much... thanks for the enlightenment... all the while i thought when an App is closed in another computer all database are also closed...

Hi steve... i have this code in my program to backup my table smsrec, and it is done everytime the app is close at the end of work hours in the afternoon... im just wondering what happens to the backup in the next day if the system sees there is already a backupsmsrec file in the current directory? will it over write it automatically? or will it create anothe file with desame name plus a "copy"included? Thanks Steve...
Code:
CLOSE DATABASES 

CREATE TABLE Backupsmsrec(IDNUM C(10), EndBack N(10))

USE smsrec EXCLUSIVE ALIAS rek
COPY STRUCTURE TO backupsmsrec.dbf

USE Backupsmsrec
APPEND FROM smsrec
USE smsrec
ZAP
 
Mandy said:
...will it over write it automatically?..
Hi Mandy,
My first reaction was a little presumptious: Try it and see what happens.

A couple of other things occur to me. First, I agree doing your backup near the END of the day is better than the BEGINNING of the next day, as many do. My reason is more bad things are likely to happen at bootup than at shutdown. Just my experience.

Second, It would be better to put the backup file somewhere else other than your working directory. Preferably off the computer away from internet access (which can access YOU as well as the other way around).
A simple solution is to put the backup on a thumb drive, then pull the drive and store it in a safe place. These days the "cloud" is a preferred solution. "Cloud" just means someone else's server. There may be privacy & cost issues there.

Your code should work, and yes, Backupsmrec.dbf will be overwritten, not automatically copied with an alternate name. After you USE smrec..., You could COPY TO (MyBackupLocation) instead of COPY STRUCTURE...

If you use my thumbdrive suggestion, you could create a folder on the thumb drive which contains the current date in its name before backing up. Then include that name in your COPY command, e.g.
Code:
COPY TO ('E:\'+ADDBS(DTOC(DATE()))+'smsrec').

That way you restore from a date of your choice.

Hope this all makes some sense to you.

Steve




 
I forgot: To use the backup folder, you would of course need to create it first. That could be
MKDIR ('E:\'+DTOC(DATE()))

Steve
 
Hi Chriss... While i was going over through the code, ive seen the locate on this part... can i remove the "locate" for i already have the scan? Thanks Chriss

Code:
 This.Enabled=.F.
      Select pendlog
      Locate
      Scan For Alltrim(Upper(pendlog.Status)) == "PENDING"
         Replace Status With "Transferred"
endscan
 
Mandy,

LOCATE on its own positions the record pointer at the first "logical" record, that is, the first record that is not deleted and is not excluded from a filter. SCAN FOR always starts at that same first logical record. So, on that basis, the LOCATE would appear to be redundant in this case.

But on a more general point, when faced with questions like this, don't be afraid to try it for yourself. Simply remove the LOCATE and see what happens.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Yes, that's unnecessary. I first thought about SCAN REST, but that's nonsense for this task. If you refer to the code I was giving, the endscan comes way later, though. And would need to be within the code section in our post. You don't just want to do this, or do you?

Code:
This.Enabled=.F.
Select pendlog
Scan For Alltrim(Upper(pendlog.Status)) == "PENDING"
   Replace Status With "Transferred"
Endscan
Because then you change the status without actually doing what the status "transferred" promises has been done.
Besides in this case this could be done with one update, the reason to do a scan loop here is you wan to execute an insert into sendlog for each processed pendlog record, that can't be done with an UPDATE SQL.

Chriss
 
Thank you Mike... im just afraid to do things sometimes for i am thinking of destroying the app... but next time i will try... Godbless....

Hi Chriss... actually all codes that you have suggested were all in my program / code... and its working now... i just highlighted the "locate" thats why i have removed some parts, and put the endscan to close scan command... Thank you Chriss always...
 
im just afraid to do things sometimes for i am thinking of destroying the app.

You're right to be cautious, Mandy, but it is highly unlikely that you will actually destroy - or otherwise harm - your app just by trying different ideas.

When experimenting with different bits of code, a common trick is to use commenting. So, in this case, if you wanted to try running without the LOCATE, you could simply make the LOCATE into a comment (by putting [tt]*[/tt] at the start of the line). Then, if you decide to keep the relevant code, just remove the commenting. If you don't want to keep it, just delete the line.

A slight variation on the above, which I employ myself, is always to put three [tt]*[/tt]s at the start of the code that I am commenting out. That way, I can see at a glance which comments represent experimental code and which ones are genuine comments. Every so often, I go through my code looking for commented-out stuff that can be safely removed.

For more substantial changes, it would also make sense to take a backup first. You don't need to back up the whole app, in that case - just make a copy of the PRG or form or whatever that you are working on.

One other technique to consider: Create a minimum dummy application, solely for the purpose of experimenting. I've been doing this for years. I've got an app which I call Trials, which simply displays a couple of forms and reports. When I want to try something out, I just modify an appropriate form, or create a new one. The app lives in its own directory. It doesn't matter if it gets lost or damaged, so I don't back it up, and once in while I delete it and start again.

Just a few ideas to think about.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Ok Mike i’ll definitely do those suggestions.. from now on i’ll do commenting and do dummy… thank you so much Mike…
 
Hi Steve… i would like to add the current date to my backup file. Like “SMS6262022” where 6262022 is the date today, how would i add the date? I’ve used SMS + alltrim(dtoc(date()) but it returned an error variable sms is not found… please help… thanks…
 
Mandy,

As Chris said, use quotes around SMS.

You could also use 'SMS' + DTOC({^2022/o6/26},1) for convenience. That will give you SMS20220622 as the file name. Future backups will then be in date order. Check DTOC() in Help.

If you have many dbfs to back up, you may want to put each day's backup in its own folder. Name the folders with the date.

Steve

p.s. For current date you could simplify it to 'SMS' + DTOC(DATE(),1)


 
Hi Chriss and Steve... Thanks... i got it... its now working...

Code:
 CLOSE DATABASES
				
				CREATE TABLE 'SMS' + ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE()))) (IDNUM C(10), EndBack N(10))
				
				USE sms EXCLUSIVE ALIAS tsulat
				COPY STRUCTURE TO 'SMS' + ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))
				
				USE 'SMS' + ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))
				APPEND FROM SMS
				
					IF DIRECTORY('C:\INFOWAVE 2021\dbf\'+ ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE()))))
						COPY TO ADDBS("C:\Infowave 2021\DBF\"+ ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))) ;
						+ 'Sms' + ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))
					ELSE
						MKDIR ('C:\INFOWAVE 2021\dbf\'+ ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE()))))
						COPY TO ADDBS("C:\Infowave 2021\DBF\"+ ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))) +;
						 'Sms' + ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))
					ENDIF 

				CLOSE DATABASES
 
Hi Mandy,

if this suits you, fine. You could remove a lot of repetition, though, if you follow Mike Lewi's advice to use DTOC() or use DTOS(). If you absolutely insist on MMDDDYYYY format, then that's also possible with SET DATE TO DMY and SET SEPARATOR '', but the least you can do is store the current date in that format into a variable tcToday and use that in all furhter code. Then it's not only less cluttered, it only becomes readable again, once you do that:

Code:
Local tcToday
tcToday = ALLTRIM(STR((MONTH(DATE())))) + ALLTRIM(STR(DAY(DATE()))) + ALLTRIM(STR(YEAR(DATE())))

Besides that, you create the table twice with CREATE TABLE and COPY STRUCTURE. I should have already addressed that when you posted your backup code at 20 Jun 22 06:39. Steve told you to do COPY TO ('E:\'+ADDBS(DTOC(DATE()))+'smsrec') and that's done instead of your code, the only requirement for COPY TO is you have opened what you want to COPY TO the destination file. and that needs an MDIR first, but no CREATE TABLE nor COPY STRUCTURE. If you do that, you even create the table three times.

I'd even make this one step easier and make a backup by a COPY FILE command.

So this is all you need for backup:
Code:
Local tcToday
tcToday = DTOS(DATE())
If !Directory('C:\INFOWAVE 2021\dbf\'+ tcToday)
   MKDIR ('C:\INFOWAVE 2021\dbf\'+tcToday)
Endif
USE sms EXCLUSIVE alias tsulat && just to ensure you have exclusive access and copy without modifications done while copying
COPY FILE (ForceExt(dbf('tsulat'),'*') To ('C:\INFOWAVE 2021\dbf\'+tcToday+'\sms.*)
Which copies dbf, fpt (if it exsits), and cdx (if it exists). Even better copy a whole folder with *.* instead of sms.* by using
Code:
COPY FILE (Justpath(dbf('tsulat'))+'\*.* ) To ('C:\INFOWAVE 2021\dbf\'+tcToday+'\*.*')

CAUTION: If you have subfolders you also need to backup, then backup methods outside of VFP are more appropriate, i.e. backups are a system built-in functionality, you can make use of the OS, here. Since your current backup only copies the sms.dbf, I assume that's not the case. But keep in mind a simple data directory with no subfolders is copied with only one COPY FILE command also in VFP, thanks to the *.* file name pattern you can apply to both source and destination. of COPY FILE.

Steve Meyerson said:
more bad things are likely to happen at bootup than at shutdown.
I disagree with that, by the way. A process that's at the end can have quite some things worn out, in the worst case unclosed file handles, dangling object references, pending garbage collection and many more things that you can guarantee not exist at start of a program.

There still are good reasons to do a backup as last action of your application instead of backup at start. Mainly simply, that all the time before the start there is no backup, you create a backup directly after work is finished. But it could be done completely separate outside of your application by a scheduled task that would copy a data directory to a backup folder. It pays to learn about scheduled tasks, not only for the aspect of a backup, any task you could do regularly is worth considering to be scheduled. You have many options to do this at start, time based, but also at the end, when a process stops running and many more scenarios of which some also are very handy for the backup task.

Besides, you could temporarily delete the file share so you can be sure there is no usage of files through LAN again. Because even if you checked you can get all files exclusive, next moment that can become invalid again. After backup is done, the share can be reestablished. The command to use is the shell command NET SHARE to both create and delete shares (with the /DELETE option), which you can use by RUN.

IIRC you talked about end of a shift is mid day, so we're not talking about end of work of all employees or, again IIRC teachers in this case. I could assume this software is about the main time of a school in the morning and so the software usage stops mid day, in the afternoon other software or other features are used.


You could also inverse the task and implement something that shuts down clients when you want to shut down the server. I understand that your motivation is to actually keep the server up while files are still used, which is a sign your application is still used. But that file usage might be just having a file open and not doing anything. That relates back to detecting the idle state. You have all, at least most ingredients for that.

The ideal case is to remove the share while you have all files in exclusive access to prove no shared usage. Then you guarantee no further starts and new file access could be made and then you can be confident deleting the share cuts no file access, the only file access is by you, locally. With no share, nothing can be done to the files while the backup is done. And then it also doesn't matter whether you shutdown after the backup or allow users back in after reestablishing the file share. You establish a kind of floodgate this way.

Chriss
 
Hi Chriss Thank you for elaborating it again to me.. i appreciate so much...
Code:
 if you follow Mike Lewi's advice to use DTOC()
I followed the DTOC Chriss but what happes is that it creates three folders, first folder is the month (6), inside the month folder it created another folder named the day (26) and lastly inside the day folder it created a folder named year(2022) that's why i've used the way its so long...

Code:
 If you do that, you even create the table three times.

Oh thats why, i was wondering why do i have a copy @ my root directory where the app was ran aside from the copy in the specified folder Chris... So I shall remove the create table.... Thanks Chriss....
 
Mike was pointing you to DTOC(DATE()[highlight #FCE94F],1[/highlight]) that creates a string of digits without slashes or backslashes. The ,1 is important here, it's not a typo. Of course, you get several directories when the slashes of a date are interpreted as creating subfolders. Windows uses backslashes in file names, but also accepts and interprets slashes as director separator. The only thing DTOC(DATE(),1) or simpler DTOS(DATE()) won't do is create the digits in the order you want, but it should only matter that the directory names will differ each day. The advantage of the format YYYYMMDD produced is, that folders sorted by name are also sorted by creation date. It's not a big advantage, since you can also sort by date anyway. But no, that was not Mikes error, he explicitly recommended the ,1 option.

Mandy said:
why do i have a copy @ my root directory where the app was ran aside from the copy in the specified folder

Well, I'd say you overwrite what CREATE TABLE creates twice, but the COPY TO might go into application root and not into the destination folder, that's true.

Anyway, there is no need to create an empty table and copy data, you just copy the files.


Chriss
 
Yes Chriss I might have overlooked the number 1 in Mike's suggestion.... Thanks Chriss and Mike....
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top