COPY TO not following SET DEFAULT TO in xHb (solved)

COPY TO not following SET DEFAULT TO in xHb (solved)

Postby hua » Thu Jun 20, 2024 10:38 am

WIth the latest xHarbour, I noticed when I create a dbf file using COPY TO, it didn't follow the path I set in SET DEFAULT TO.
This will create a Dos error 2 at the next line that attempt to USE the dbf because USE will search in SET DEFAULT TO path

Most likely this is due to something at my environment since I don't see others reporting it

Anyone has any idea on how to find what's going on?
Thanks
Last edited by hua on Tue Jun 25, 2024 8:57 am, edited 1 time in total.
FWH 11.08/FWH 19.12
BCC5.82/BCC7.3
xHarbour/Harbour
hua
 
Posts: 1072
Joined: Fri Oct 28, 2005 2:27 am

Re: COPY TO not following SET DEFAULT TO

Postby Rick Lipkin » Thu Jun 20, 2024 12:59 pm

Hua

I create a folder on each local workstation hard drive and I always look for that folder when I start my application .. C:\Dbtmp and that is where I create all my temp files like .dbfs for reports ... so I always know where I can create and delete my temp files.

Rick Lipkin
User avatar
Rick Lipkin
 
Posts: 2666
Joined: Fri Oct 07, 2005 1:50 pm
Location: Columbia, South Carolina USA

Re: COPY TO not following SET DEFAULT TO

Postby hua » Thu Jun 20, 2024 7:22 pm

Thanks for the reply Rick.
It's not the storage scheme that is in doubt here since this is a pre-existing software.

It's just that this error pops up when I recompiled with the latest xHarbour. I don't get this error when I tested with latest Harbour but I got a different error with it.
FWH 11.08/FWH 19.12
BCC5.82/BCC7.3
xHarbour/Harbour
hua
 
Posts: 1072
Joined: Fri Oct 28, 2005 2:27 am

Re: COPY TO not following SET DEFAULT TO

Postby karinha » Thu Jun 20, 2024 7:52 pm

A small example, can you show it via programming?

Gracias, tks.

Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7831
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: COPY TO not following SET DEFAULT TO

Postby karinha » Thu Jun 20, 2024 8:02 pm

Code: Select all  Expand view  RUN

#include "FiveWin.ch"

FUNCTION Main()

   USE Sales NEW

   COPY TO C:\TEMP\TempHua

RETURN NIL
 


Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7831
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: COPY TO not following SET DEFAULT TO

Postby hua » Fri Jun 21, 2024 2:16 am

As a workaround, I amended my COPY TO command as such
Code: Select all  Expand view  RUN

COPY TO (AddDefPath(cTmpFile)) FOR &( cFilter )
USE (cTmpFile) NEW
*--------------------------------------------
function AddDefPath(cDbf)
  local cPath := set(_SET_DEFAULT)
return cPath+"\"+cDbf
FWH 11.08/FWH 19.12
BCC5.82/BCC7.3
xHarbour/Harbour
hua
 
Posts: 1072
Joined: Fri Oct 28, 2005 2:27 am

Re: COPY TO not following SET DEFAULT TO

Postby karinha » Fri Jun 21, 2024 11:58 am

Code: Select all  Expand view  RUN

// C:\FWH\SAMPLES\HUATO2.PRG

#Include "FiveWin.ch"

ANNOUNCE RDDSYS
REQUEST DBFCDX, DBFFPT

FUNCTION Main()

   LOCAL cPath, cTmpFile, cDbfCopy, cFilter

   cPath    := "C:\TEMP\"
   cTmpFile := "
SALES.DBF"
   cDbfCopy := "
TEMPHUA.DBF"
   cFilter  := "
DATE"

   IF .NOT. lIsDir( cPath )

      MsgInfo( cPath + "
not found" )

      RETURN NIL

   ENDIF

   IF FILE( "
C:\TEMP\TEMPHUA.DBF" )

      DELETE FILE( "
C:\TEMP\TEMPHUA.DBF" )

   ENDIF

   USE ( cTmpFile ) NEW

   COPY FIELDS &cFilter TO ( cPath ) + cDbfCopy

   CLOSE DATABASES

   IF FILE( "
C:\TEMP\TEMPHUA.DBF" )

      MsgInfo( "
I'm a good copy.", "Listo:" )

   ENDIF

RETURN NIL

// FIN / END - kapiabafwh@gmail.com


Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7831
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: COPY TO not following SET DEFAULT TO

Postby Enrico Maria Giordano » Fri Jun 21, 2024 7:28 pm

hua wrote:WIth the latest xHarbour, I noticed when I create a dbf file using COPY TO, it didn't follow the path I set in SET DEFAULT TO.
This will create a Dos error 2 at the next line that attempt to USE the dbf because USE will search in SET DEFAULT TO path

Most likely this is due to something at my environment since I don't see others reporting it

Anyone has any idea on how to find what's going on?
Thanks


There is nothing in the docs indicating that it should follow SET DEFAULT TO path. And, by the way, there was no significant changes in the xHarbour source code related to that command:

https://github.com/xHarbour-org/xharbour/blob/main/ChangeLog

Anyway, if you can provide me the full xHarbour build that works fine for you and a simple PRG example to test here, I'll investigate the problem.
User avatar
Enrico Maria Giordano
 
Posts: 8718
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: COPY TO not following SET DEFAULT TO

Postby Otto » Fri Jun 21, 2024 9:33 pm

Hello Hua,

I recently spent some time working on direct access to the DBF.

You could build a much more powerful COPY TO command yourself. Where "Filter" is in the code, you can easily add which fields you want to export, and where "Search" is, any condition.

Target and format can also be easily added.

Best regards,
Otto

Code: Select all  Expand view  RUN


// DBFToTXT
#include "FiveWin.ch"


PROCEDURE Main
    LOCAL cFilePath := "c:\fwh\samples\Data\database.dbf"
    LOCAL cName := "clark"
    LOCAL aResult

    aResult := FindNameInDbf(cFilePath, cName)
   
    IF !EMPTY(aResult)
        WriteRecordsToFile(aResult, "c:\fwh\samples\Data\output.txt")
    ENDIF
   
RETURN

FUNCTION FindNameInDbf(cFilePath, cName)
    LOCAL nHandle := FOPEN(cFilePath)
    LOCAL cHeader := SPACE(32)
    LOCAL nHeaderSize, nRecordSize, nNumRecords
    LOCAL aFieldDescriptors := {}
    LOCAL aFieldOffsets := {}
    LOCAL nOffset := 0
    LOCAL cFieldDescriptor, cFieldName
    LOCAL nFieldLength
    LOCAL nNameOffset, nNameLength
    LOCAL aMatchingRecords := {}
    LOCAL cRecord, cExtractedName
    LOCAL hField, hRecordData
    LOCAL i, j
    LOCAL cFieldValue
    LOCAL hFieldDescriptor := { => }
    LOCAL nFound := 0
    LOCAL cFileData
     LOCAL nVersion
     LOCAL nYear
     LOCAL nMonth
     LOCAL nDay
     LOCAL LastUpdate
     
     
    Msginfo("Start Suche")

    IF nHandle == -1
        ? "Konnte die Datei nicht öffnen."
        RETURN {}
    ENDIF

    // Read entire file into memory
    cFileData := MEMOREAD(cFilePath)

    // Header lesen
    cHeader := LEFT(cFileData, 32)
   
    // Byte-Interpretation der Header-Daten
    nNumRecords := (ASC(SUBSTR(cHeader, 5, 1)) + (ASC(SUBSTR(cHeader, 6, 1)) * 256) + (ASC(SUBSTR(cHeader, 7, 1)) * 65536) + (ASC(SUBSTR(cHeader, 8, 1)) * 16777216))
    nHeaderSize := (ASC(SUBSTR(cHeader, 9, 1)) + (ASC(SUBSTR(cHeader, 10, 1)) * 256))
    nRecordSize := (ASC(SUBSTR(cHeader, 11, 1)) + (ASC(SUBSTR(cHeader, 12, 1)) * 256))

    // Felddeskriptoren lesen
    FOR i := 33 TO nHeaderSize STEP 32
        cFieldDescriptor := SUBSTR(cFileData, i, 32)
        IF ASC(LEFT(cFieldDescriptor, 1)) == 13
            EXIT
        ENDIF
        cFieldName := RTRIM(SUBSTR(cFieldDescriptor, 1, 11))
        nFieldLength := ASC(SUBSTR(cFieldDescriptor, 17, 1))
        AADD(aFieldDescriptors, { "name" => cFieldName, "length" => nFieldLength })
    NEXT

    // Feld-Offsets berechnen
    FOR i := 1 TO LEN(aFieldDescriptors)
        hFieldDescriptor := aFieldDescriptors[i]
        AADD(aFieldOffsets, { hFieldDescriptor["name"], nOffset, hFieldDescriptor["length"] })
        nOffset += hFieldDescriptor["length"]
    NEXT
   
    nNameOffset := AScan(aFieldOffsets, { |a| LEFT(a[1], 10) = "LAST" })
    nNameLength := aFieldOffsets[nNameOffset, 3]


    // FILTER, welche Felder
    aFieldDescriptors := {}
    AADD(aFieldDescriptors, { "name" => "FIRST", "length" => 20 })
    AADD(aFieldDescriptors, { "name" => "LAST", "length" => 20 })
    xbrowse(aFieldDescriptors)



    // Process records
    FOR i := 1 TO nNumRecords
         cRecord := SUBSTR(cFileData, nHeaderSize + (i - 1) * nRecordSize + 1, nRecordSize)
       cExtractedName :=   ALLTRIM(LOWER( SUBSTR(cRecord, aFieldOffsets[nNameOffset, 2] + 1, nNameLength) ))
     
 
    // Search    
   
    IF cExtractedName = cName
            nFound += 1

            hRecordData := { "recno" => i }
            nOffset := 0

            FOR j := 1 TO LEN(aFieldDescriptors)
                hField := aFieldDescriptors[j]
               
                cFieldValue := (SUBSTR(cRecord, nOffset + 2, hField["length"]))
                hRecordData[hField["name"]] := cFieldValue
                nOffset += hField["length"]
            NEXT

            AADD(aMatchingRecords, hRecordData)
           
     ENDIF

    NEXT

    xbrowse(aMatchingRecords)

    RETURN(aMatchingRecords)
   
 FUNCTION WriteRecordsToFile(aRecords, cFilePath)
    LOCAL nHandle := FCREATE(cFilePath)
    LOCAL cLine
    LOCAL hRecord
    LOCAL cFieldName
    LOCAL cValue

    IF nHandle == -1
        ? "Konnte die Datei nicht erstellen."
        RETURN NIL
    ENDIF

    FOR EACH hRecord IN aRecords

        cLine := ""
       
        FOR cFieldName := 1 TO LEN(hRecord)
       
            IF HGetKeyAt(hRecord, cFieldName) != "recno"
                cValue := hRecord[HGetKeyAt(hRecord, cFieldName)]
                cLine += cValue + CHR(9) // Tab-separated

               
            ENDIF
        NEXT
        cLine := RTRIM(cLine) + CRLF
        FWRITE(nHandle, cLine)
    NEXT

    FCLOSE(nHandle)
    ? "Datei erfolgreich erstellt: ", cFilePath
RETURN NIL

// Funktion zum rechtsbündigen Auffüllen eines Strings auf eine bestimmte Länge
FUNCTION PadR(cText, nLength)
RETURN SUBSTR(cText + SPACE(nLength), 1, nLength)



 
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
User avatar
Otto
 
Posts: 6336
Joined: Fri Oct 07, 2005 7:07 pm

Re: COPY TO not following SET DEFAULT TO

Postby Otto » Fri Jun 21, 2024 9:36 pm

The design of the report selection I will make for myself as in this gif.

Image
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
User avatar
Otto
 
Posts: 6336
Joined: Fri Oct 07, 2005 7:07 pm

Re: COPY TO not following SET DEFAULT TO

Postby karinha » Sat Jun 22, 2024 2:18 pm

Meister Otto, ausgezeichnet! Glückwunsch!
Master Otto, excellent! Congratulations!

Code: Select all  Expand view  RUN

// C:\FWH\SAMPLES\DBFTOTXT.PRG

#include "FiveWin.ch"

PROCEDURE Main

   LOCAL cFilePath := "..\samples\Data\database.dbf"
   LOCAL cName     := "clark"
   LOCAL aResult

   aResult := FindNameInDbf( cFilePath, cName )

   IF .NOT. Empty( aResult )

      WriteRecordsToFile( aResult, "..\samples\Data\output.txt" )

   ENDIF

RETURN NIL

FUNCTION FindNameInDbf( cFilePath, cName )

   LOCAL nHandle := FOpen( cFilePath )
   LOCAL cHeader := Space( 32 )
   LOCAL nHeaderSize, nRecordSize, nNumRecords
   LOCAL aFieldDescriptors := {}
   LOCAL aFieldOffsets := {}
   LOCAL nOffset := 0
   LOCAL cFieldDescriptor, cFieldName
   LOCAL nFieldLength
   LOCAL nNameOffset, nNameLength
   LOCAL aMatchingRecords := {}
   LOCAL cRecord, cExtractedName
   LOCAL hField, hRecordData
   LOCAL i, j
   LOCAL cFieldValue
   LOCAL hFieldDescriptor := { => }
   LOCAL nFound := 0
   LOCAL cFileData
   LOCAL nVersion
   LOCAL nYear
   LOCAL nMonth
   LOCAL nDay
   LOCAL LastUpdate

   // Msginfo( "Start Suche" ) // Start search
   Msginfo( "Start search" )   // German Language

   IF nHandle == -1

      ? "Konnte die Datei nicht öffnen." // Could not open the file.
      ? "Could not open the file." // German Language

      RETURN {} // ??? NIL ?

   ENDIF

   // Read entire file into memory
   cFileData := MemoRead( cFilePath )

   // Header lesen
   cHeader := Left( cFileData, 32 )

   // Byte-Interpretation der Header-Daten
   nNumRecords := ( Asc( SubStr( cHeader, 5, 1 ) ) + ( Asc( SubStr( cHeader, 6, 1 ) ) * 256 ) + ( Asc( SubStr( cHeader, 7, 1 ) ) * 65536 ) + ( Asc( SubStr( cHeader, 8, 1 ) ) * 16777216 ) )
   nHeaderSize := ( Asc( SubStr( cHeader, 9, 1 ) ) + ( Asc( SubStr( cHeader, 10, 1 ) ) * 256 ) )
   nRecordSize := ( Asc( SubStr( cHeader, 11, 1 ) ) + ( Asc( SubStr( cHeader, 12, 1 ) ) * 256 ) )

   // Felddeskriptoren lesen
   FOR i := 33 TO nHeaderSize STEP 32

      cFieldDescriptor := SubStr( cFileData, i, 32 )

      IF Asc( Left( cFieldDescriptor, 1 ) ) == 13
         EXIT
      ENDIF

      cFieldName := RTrim( SubStr( cFieldDescriptor, 1, 11 ) )
      nFieldLength := Asc( SubStr( cFieldDescriptor, 17, 1 ) )

      AAdd( aFieldDescriptors, { "name" => cFieldName, "length" => nFieldLength } )

   NEXT

   // Feld-Offsets berechnen
   FOR i := 1 TO Len( aFieldDescriptors )

      hFieldDescriptor := aFieldDescriptors[ i ]

      AAdd( aFieldOffsets, { hFieldDescriptor[ "name" ], nOffset, hFieldDescriptor[ "length" ] } )

      nOffset += hFieldDescriptor[ "length" ]

   NEXT

   nNameOffset := AScan( aFieldOffsets, {| a | Left( a[ 1 ], 10 ) = "LAST" } )
   nNameLength := aFieldOffsets[ nNameOffset, 3 ]

   // FILTER, welche Felder
   aFieldDescriptors := {}

   AAdd( aFieldDescriptors, { "name" => "FIRST", "length" => 20 } )
   AAdd( aFieldDescriptors, { "name" => "LAST", "length" => 20 } )

   xbrowse( aFieldDescriptors )

   // Process records
   FOR i := 1 TO nNumRecords

      cRecord := SubStr( cFileData, nHeaderSize + ( i - 1 ) * nRecordSize + 1, nRecordSize )
      cExtractedName :=   AllTrim( Lower( SubStr( cRecord, aFieldOffsets[ nNameOffset, 2 ] + 1, nNameLength ) ) )

      // Search

      IF cExtractedName = cName

         nFound += 1

         hRecordData := { "recno" => i }
         nOffset     := 0

         FOR j := 1 TO Len( aFieldDescriptors )

            hField := aFieldDescriptors[ j ]

            cFieldValue := ( SubStr( cRecord, nOffset + 2, hField[ "length" ] ) )

            hRecordData[ hField[ "name" ] ] := cFieldValue

            nOffset += hField[ "length" ]

         NEXT

         AAdd( aMatchingRecords, hRecordData )

      ENDIF

   NEXT

   xbrowse( aMatchingRecords )

RETURN( aMatchingRecords )

FUNCTION WriteRecordsToFile( aRecords, cFilePath )

   LOCAL nHandle := FCreate( cFilePath )
   LOCAL cLine
   LOCAL hRecord
   LOCAL cFieldName
   LOCAL cValue

   IF nHandle == -1

      // ? "Konnte die Datei nicht erstellen." // Could not create the file.
      ? "Could not create the file."           // German Language

      RETURN NIL

   ENDIF

   FOR EACH hRecord IN aRecords

      cLine := ""

      FOR cFieldName := 1 TO Len( hRecord )

         IF HGetKeyAt( hRecord, cFieldName ) != "recno"

            cValue := hRecord[ HGetKeyAt( hRecord, cFieldName ) ]

            cLine += cValue + Chr( 9 ) // Tab-separated

         ENDIF

      NEXT

      cLine := RTrim( cLine ) + CRLF

      FWrite( nHandle, cLine )

   NEXT

   FClose( nHandle )

   // ? "Datei erfolgreich erstellt: ", cFilePath // File created successfully:
   ? "File created successfully:: ", cFilePath

RETURN NIL
// Funktion zum rechtsbündigen Auffüllen eines Strings auf eine bestimmte Länge
FUNCTION PadR( cText, nLength )

RETURN SubStr( cText + Space( nLength ), 1, nLength )

// FIN / END
 


Gracias, tks.

Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7831
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: COPY TO not following SET DEFAULT TO

Postby hua » Mon Jun 24, 2024 2:45 am

Hi Enrico,

Enrico Maria Giordano wrote:There is nothing in the docs indicating that it should follow SET DEFAULT TO path. And, by the way, there was no significant changes in the xHarbour source code related to that command:

https://github.com/xHarbour-org/xharbour/blob/main/ChangeLog

Anyway, if you can provide me the full xHarbour build that works fine for you and a simple PRG example to test here, I'll investigate the problem.



The COPY TO behaviour is based on this SET DEFAULT TO's description from Clipper's Norton Guide
SET DEFAULT sets the drive and directory where the application program
creates and saves files, with the exception of temporary files and files
created with the low-level file functions.

SET DEFAULT does not change the DOS drive and directory. When
attempting to access files, the DEFAULT drive and directory are searched
first. To set additional search paths for file access, use SET PATH.


I'll try to create a self-contained example to see whether I can replicate the buggy behaviour
FWH 11.08/FWH 19.12
BCC5.82/BCC7.3
xHarbour/Harbour
hua
 
Posts: 1072
Joined: Fri Oct 28, 2005 2:27 am

Re: COPY TO not following SET DEFAULT TO

Postby Otto » Mon Jun 24, 2024 10:27 am

direct access

This direct access to the DBF files has potential.

It makes it very easy to quickly perform complex database queries.

I did a speed test for COPY TO against the test database with the 200,000 records.

Direct access is 46 ms faster, or 5.58%.

I will now perform further tests with my own data.

Image

Image

Image
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
User avatar
Otto
 
Posts: 6336
Joined: Fri Oct 07, 2005 7:07 pm

Re: COPY TO not following SET DEFAULT TO

Postby Enrico Maria Giordano » Mon Jun 24, 2024 3:24 pm

Enrico Maria Giordano wrote:Anyway, if you can provide me the full xHarbour build that works fine for you and a simple PRG example to test here, I'll investigate the problem.


Ok, I managed to replicate the problem and found that with Harbour it works fine. I'll try to fix the bug, thank you.
User avatar
Enrico Maria Giordano
 
Posts: 8718
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: COPY TO not following SET DEFAULT TO

Postby Enrico Maria Giordano » Mon Jun 24, 2024 3:50 pm

I think I found the bug:

Code: Select all  Expand view  RUN
2009-08-27 20:53 UTC-0430 Ron Pinkas <ron.pinkas/at/xharbour.com>
   * source/rdd/dbcmd.c
     * Hack to __DBCOPY() to explicitly prefix target file with the current path
       to to avoid inadvertent override of file in the SET PATH folder.

       /*
          NOTE: RDD authors please review if this is the correct place for such hack.
        */


I'm going to borrow the correct code from Harbour.
User avatar
Enrico Maria Giordano
 
Posts: 8718
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: PabloHarbour and 48 guests