Page 1 of 2

questions manage dbf

Posted: Sat Sep 29, 2018 3:44 pm
by Silvio.Falconi
I 'm trying to create a app for network but I not remember how I must create it
because in the last 10 years I have preferred to deal with simple little programs where there was no need for the archives on the net. now I present the problem of an application that must necessarily use a shared management of the archives because it connects in the background with Telgram on the Internet and sends text messages taking information from the archives that could be used by the application

trying to manage the archive on the net I now find a test to cancel a record having opened an archives in NEW SHARED
in the old system I deleted a record and run the archive pack this way

Code: Select all

 
       ES->(DbSkip())
       nNext :=  ES->(Recno())
       ES->(DbGoto(nRecord))
       ES->(DbDelete())
       ES->(DbPack())
       ES->(DbGoto(nNext))
      if  ES->(EOF()) .or. nNext == nRecord
          ES->(DbGoBottom())
      endif
 


now if I try to make pack let me fwh sad me the dbf must be open on exclusive mode

how I can resolve it ?

this is the source when I try to erase a record

Code: Select all

 local nRecord := ES->(Recno())
      local nNext

ES->(DbSkip())
       nNext :=  ES->(Recno())
       ES->(DbGoto(nRecord))
      IF!Ocupado("ES")
           ES->(DbDelete())
           ES->(DbCommit())
           ES->(DbPack())
          ES->(DbUnlock())
        Endif
       ES->(DbGoto(nNext))
      if  ES->(EOF()) .or. nNext == nRecord
          ES->(DbGoBottom())
      endif
why I cannot make dbpack ?

If I not make dbpack on xbrowse I see the record

the function Ocupado is a function with a cicle to try to rlock the dbf

Re: questions manage dbf

Posted: Sat Sep 29, 2018 4:16 pm
by Enrico Maria Giordano
You can't pack a DBF not opened in exclusive mode. Put

Code: Select all

SET DELETED ON
at the start of your main function and you will not see the deleted records anymore.

EMG

Re: questions manage dbf

Posted: Mon Oct 01, 2018 10:00 am
by Silvio.Falconi
I still do not understand why when I have to delete a record I am forced to use rlock / dbunclock when instead I insert a record he turns the old way without rlocking
I'm using an archive with the "New shared" method
I thought a control archive in the root of the program to open in "new shared" and then the others in the "data" folder can open with

DbUseArea( [<lNewArea>] , ;
[<cRddName>] , ;
<cDatabase> , ;
[<cAlias>] , ;
[<lShared>] , ;
[<lReadonly>] , ;
[<cCodePage>] , ;
[<nConnection>] ) --> NIL

cAlias:=New_Alias(cDbf,nD)
DbUseArea(.T.,cDriver,cDbf,cAlias,.T.,.F.)


in your opinion, it could be configured to be able to use an archive and at the same time reopen it from another part

I'm afraid that I get the message "alias do not exist" this is and it was my nightmare 15 years ago for this reason I had abandoned and embraced the exclusive way

Re: questions manage dbf

Posted: Mon Oct 01, 2018 10:18 am
by dagiayunus
Silvio.Falconi wrote:I 'm trying to create a app for network but I not remember how I must create it
because in the last 10 years I have preferred to deal with simple little programs where there was no need for the archives on the net. now I present the problem of an application that must necessarily use a shared management of the archives because it connects in the background with Telgram on the Internet and sends text messages taking information from the archives that could be used by the application

trying to manage the archive on the net I now find a test to cancel a record having opened an archives in NEW SHARED
in the old system I deleted a record and run the archive pack this way

Code: Select all

 
       ES->(DbSkip())
       nNext :=  ES->(Recno())
       ES->(DbGoto(nRecord))
       ES->(DbDelete())
       ES->(DbPack())
       ES->(DbGoto(nNext))
      if  ES->(EOF()) .or. nNext == nRecord
          ES->(DbGoBottom())
      endif
 


now if I try to make pack let me fwh sad me the dbf must be open on exclusive mode

how I can resolve it ?

this is the source when I try to erase a record

Code: Select all

 local nRecord := ES->(Recno())
      local nNext

ES->(DbSkip())
       nNext :=  ES->(Recno())
       ES->(DbGoto(nRecord))
      IF!Ocupado("ES")
           ES->(DbDelete())
           ES->(DbCommit())
           ES->(DbPack())
          ES->(DbUnlock())
        Endif
       ES->(DbGoto(nNext))
      if  ES->(EOF()) .or. nNext == nRecord
          ES->(DbGoBottom())
      endif
why I cannot make dbpack ?

If I not make dbpack on xbrowse I see the record

the function Ocupado is a function with a cicle to try to rlock the dbf
The following commands require the exclusive use of a table with either SET EXCLUSIVE ON or USE...EXCLUSIVE:

CONVERT
DELETE TAG
INDEX...TAG
MODIFY STRUCTURE
PACK
REINDEX
ZAP

Re: questions manage dbf

Posted: Mon Oct 01, 2018 1:29 pm
by Enrico Maria Giordano
Silvio.Falconi wrote:I still do not understand why when I have to delete a record I am forced to use rlock / dbunclock when instead I insert a record he turns the old way without rlocking
Because APPEND BLANK automatically locks the newly created record. You still need to unlock it at the end of the assignment operation.

EMG

Re: questions manage dbf

Posted: Mon Oct 01, 2018 1:33 pm
by Enrico Maria Giordano
Silvio.Falconi wrote:in your opinion, it could be configured to be able to use an archive and at the same time reopen it from another part
Yes, but you have to use a different alias to reopen the same DBF. Try using TDatabase class that automatically handles all those alias complexities.

EMG

Re: questions manage dbf

Posted: Mon Oct 01, 2018 7:54 pm
by Silvio.Falconi
thanks Enrico,

I'm rehearsing to see if I can manage at least one customer on the net

This happens to me this evening

I have opened the customer file with

Code: Select all

DbUseArea(.T.,cDriver,cDir+cDbf,cAlias,.T.,.F.)
I made the indexes only two one for the field "FIRST" the other for "LAST"


Image





insert a First such as "FALCONI"

the valid function attached to the get does not find the name and then makes me save the new record

now I want to delete the record "falconi"

and I execute the command with

Code: Select all

      IF!Occupato(oDCli)
           (oDCli)->(DbDelete())
           (oDCli)->(DbCommit())
           (oDCli)->(DbUnlock())
       ENDIF
the "Occupato" function is a cycle to call the rlock function where is is not rlock wait 5 sec

OK THE RECORD IS DELETE


Now I want to do another test and insert the name "Falconi" again, Obviously without leaving the customer screen

when I insert the name "Falconi" the valid finds me the name and tells me existing record

It is possible that at the time of cancellation the index does not refresh and therefore the procedure always keeps the name in memory and finds it?

Re: questions manage dbf

Posted: Mon Oct 01, 2018 7:57 pm
by Silvio.Falconi
Sorry,
there was another record with "Falconi" .... mhm sorry , It seemed strange to me :)

Re: questions manage dbf

Posted: Mon Oct 01, 2018 8:27 pm
by Silvio.Falconi
So,
to insert a record the procedure inserts it

but when I have to modify or delete a record , I have to use rlock / dbunclock

I cannot use dbpack when I open on share mode

I must use SET DELETE ON if I want not show the delete record into xbrowse

and I must index with the clausole FOR .not. Deleted()


I delete the command dbpack from mine sources but I need it or not ?

I not understood where i can make dbpack because when open the customer.dbf with emagdbu I see also the delete records

Image


where I can use dpack ?

I must create a a new function where I can index all files and I can make dbpack and I must sure no user is on line

Re: questions manage dbf

Posted: Mon Oct 01, 2018 8:51 pm
by Enrico Maria Giordano
Silvio.Falconi wrote:where I can use dpack ?

I must create a a new function where I can index all files and I can make dbpack and I must sure no user is on line
Yes.

EMG

Re: questions manage dbf

Posted: Tue Oct 02, 2018 2:50 pm
by Rick Lipkin
Silvo

Re-Writing for a shared network multi-user environment takes a bit of skill .. I have exclusively moved to ADO and do not need these functions .. here are my DBFCDX network functions that may help you ...

Rick Lipkin

Code: Select all

/* LOGICAL NETUSE( CDATABASE, LOPENMODE, NSECONDS )

  CHARACTER CDATABASE      - NAME OF DATABASE
  LOGICAL LOPENMODE        - OPEN MODE .T. exclusive  .F. shared
  NUMERIC NSECONDS         - NUMBER OF SECONDS TO WAIT  0 forever

  RETURN  .T. if successful,  .F. if not

  SAMPLE CALL  IF NETUSE( "CALLS", .F., 5 )
*/
//------------------------------
Func NETUSE( CDATABASE, LOPENMODE, NSECONDS )

LOCAL FOREVER, RESTART, WAIT_TIME, YESNO

RESTART := .T.
FOREVER := ( NSECONDS = 0 )
YESNO   := {"Yes" , "No"}

DO WHILE RESTART

   WAIT_TIME := NSECONDS

   DO WHILE ( FOREVER .OR. WAIT_TIME > 0 )

      IF LOPENMODE
         USE ( CDATABASE ) via "DBFCDX" EXCLUSIVE
      ELSE
         USE ( CDATABASE ) via "DBFCDX" SHARED
      ENDIF

      IF .NOT. NETERR()
         RETURN(.T.)
      ENDIF
      INKEY(1)
      WAIT_TIME--

   ENDDO

   * lock failed, ask to continue

   IF MsgYesNo( "Cannot lock " + CDATABASE + ", retry ?" )
   ELSE
      EXIT
   ENDIF

ENDDO

RETURN(.F.)

//--------------------------
func ADDREC( NWAITSECONDS )


LOCAL LFOREVER, WAIT_TIME, RESTART, YESNO

APPEND BLANK
IF .NOT. NETERR()
   RETURN .T.
ENDIF

RESTART  := .T.
LFOREVER := ( NWAITSECONDS = 0 )
YESNO    := {"Yes", "No"}

DO WHILE RESTART

   WAIT_TIME := NWAITSECONDS
   DO WHILE ( LFOREVER .OR. WAIT_TIME > 0 )
      APPEND BLANK
      IF .NOT. NETERR()
         RETURN .T.
      ENDIF
      INKEY(.5)                      // wait 1/2 second to try again
      WAIT_TIME = WAIT_TIME - .5
   ENDDO

   *  if failed ask user to continue

   IF MsgYesNo( "Cannot add Record, retry ?" )
   ELSE
      EXIT
   ENDIF

ENDDO

RETURN .F.

//-----------------------------
func RECLOCK( NSECONDS )


LOCAL LFOREVER, RESTART, WAIT_TIME, YESNO

IF RLOCK()
   RETURN .T.        // LOCKED
ENDIF

RESTART  := .T.
LFOREVER := ( NSECONDS = 0 )
YESNO    := {"Yes" , "No"}

DO WHILE RESTART

   WAIT_TIME := NSECONDS
   DO WHILE ( LFOREVER .OR. WAIT_TIME > 0 )

      IF RLOCK()
         RETURN (.T.)
      ENDIF

      INKEY(.5)
      WAIT_TIME = WAIT_TIME - .5

   ENDDO

    * lock failed

   IF MsgYesNo( "Cannot lock Record, retry ?" )
   ELSE
      EXIT
   ENDIF

ENDDO

RETURN(.F.)
 

Re: questions manage dbf

Posted: Tue Oct 02, 2018 2:59 pm
by Enrico Maria Giordano
Rick Lipkin wrote:Silvo

Re-Writing for a shared network multi-user environment takes a bit of skill ..
Yes, it's not easy at all. Bad locking strategy could cause slowness, duplicated keys and other unpleasant things.

EMG

Re: questions manage dbf

Posted: Tue Oct 02, 2018 3:16 pm
by Rick Lipkin
Enrico
Yes, it's not easy at all. Bad locking strategy could cause slowness, duplicated keys and other unpleasant things.

EMG
I ( pretty much ) gave up on dbf\cdx because of the opportunistic locking issues and dbCommit() and workstation update visabilities on certain networks .. As you tutored me many years ago .. .mdb ( ms access ) is a good ADO solution for portable multi-user network apps .. Ms Sql Server is my choice for Enterprise corporate tables.

I only use dbf\cdx for writing reports and I where I need to create a ( local ) temporary table and I always create those tables on demand and open the .dbf exclusively .. I think the worst problem using dbf\cdx is the opportunistic locking issues that just destroy application speed and performance .. and this issue is random in nature and YOU ( the developer ) are always blamed for this issue which is beyond your control ..

Rick Lipkin

Re: questions manage dbf

Posted: Wed Oct 03, 2018 10:24 am
by Silvio.Falconi
everyone has their own situations, then the functions when we try them all turn then when one puts them in the big applications are created the problems, I never trusted to manage the archives in a local network for the countless problems that there are...

It's not so easy .

I created a "Netuse" type function but a little different management in order to open a dbf in specific folders

I have a difficult situation. it's not easy

I have a dbf named Dbase.dbf where I inserted all the dbf / cdx and more
when I do oDCli: = Open_Dbf ("Customer",. t..f.aIdx, .t.) means that the archive is in the folder. \ 2013 \ data if instead I make Open_dbf ("dbase") the file is in root obviously oDli is the area in which I open the file

in this way I also open the indexes that are stored in dbase.dbf

I do so since I work with clipper


I have a data folder divided for years eg 2013 and inside this folder other folders like: date, Doc, Pdf, Xls, Xml, Zip

Generally the archives are in the folder. \ Data \

The general archives I have to call them from the root of the application

So with Apri_Dbf / chiudi_Dbf (cdbf, calias) I manage the openings and the closures

With Busy () I see if the archive is busy or not with rlock and I wait for a cycle of 5 seconds

Now the problem is that I have to do a function inmodo to index all files and do the dbpack but I have the problem of checking if users are online

Re: questions manage dbf

Posted: Thu Oct 04, 2018 3:55 pm
by James Bott
Silvio,

As I mentioned in my post in another thread of yours, you really need to start using database objects. All of these problems will go away.

No more dealing with workareas, locking/unlocking, committing, opening and closing files, etc.

James