DBF Structure

How I can obtain structure info of a DBF ?

 

PROC MAIN()
 
   SETMODE( 25, 80 )
   CLS
 
   USE ..\datas\TEST1
? "No Field Name T Size Dec"
   ? "-- ------------ - ----- ---"
 
   FOR nFld := 1 TO FCOUNT()
       * or : FIELDNUM( FIELDNAME( nFld ) 
       ? STR( nFld, 2, 0 ),; // CT Database Function
         PAD( FIELDNAME( nFld ), 12 ),; // Standard dBASE function
         FIELDTYPE( nFld ),; // CT Database Function
         STR( FIELDSIZE( nFld ), 5, 0 ),; // CT Database Function
         STR( FIELDDECI( nFld ), 3, 0 ) // CT Database Function
    NEXT nFld
 
    ? 
    WAIT "EOF DBF_Struct.prg"
 
RETURN // MAIN.DBF_Struct.prg"

Format of xBase Files

xBase File Format Description

CURSORs

Beside classical “position indicator” meaning, in database jargon CURSOR means  CURrent Set Of Records; or Current Selected set of records.

If a whole table is in use with all records, this table may be considered as a cursor. But when talking about a cursor, this means in general, “selected” records.  A CURSOR may be real a table as a disk file, or a temporary table in memory.

Since “current” means temporary usage, for this purpose, for a temporary table in memory, using a uniform array may be a god way.  Of course this way is limited by size (record count) of table.  When conditions are available, using CURSOR may be more usable than direct using of a table.

In real life conditions building a cursor requires some “selection” process and may be quite complex, such as compiling data various sources, applying some selection criteria, and building a table (data set) with totally new structure may be required. These details are out of this article.  We will work here only using an array as cursor, or simply using an array as a table.

So, first step is transfer data from a table to an array. Again, size (record count) of table is critical in this process.

Let’s look the sample .prg :

/*
CURSORs

*/
PROCEDURE Main()
   SET DATE GERM
   SET CENT ON

   USE CUSTOMER

   aCustomers := {} // Declare / define an empty cursor: an uniform array

   WHILE .NOT. EOF()
      a1Record := ARRAY( FCOUNT() ) 
      AEVAL( a1Record, { | x1, nI1 | a1Record[ nI1 ] := FIELDGET( nI1 ) } )
      AADD( aCustomers, a1Record )
      DBSKIP()
   ENDDO

   ?
   ? "Traversing cursor :"
   ?

   a1Record := {}

   FOR EACH a1Record IN aCustomers
      ? 
      AEVAL( a1Record, { | x1 | QQOUT( x1, '' ) } )
   NEXT
   ?
   ? "Locating a specific record in an array by key :"
   ?

   nRecord := ASCAN( aCustomers, { | a1Record | a1Record[ 1 ] == "CC003" } )
   ?
   AEVAL( aCustomers[ nRecord ], { | x1 | QQOUT( x1, '' ) } )
/* 
 At this point, data in the cursor may be edited via forms 
 ( one form for each row of cursor) or via a TBRowse.

 After getting user confirmation ( do you save all modifications you made ? )
 the cursor may require write back to the orijinal source, that is the table.

 */

    ?
    ? "Write back the cursor to table :"
    ?

    DBGOTOP()
    FOR EACH a1Record IN aCustomers
       ? RECN()
       AEVAL( a1Record, { | x1, nI1 | FIELDPUT( nI1, x1 ), QQOUT( nI1 ) } )
       DBSKIP()
    NEXT 

    ? "That's all ! ... "

    @ MAXROW(), 0
    WAIT "EOF Cursors.prg"

RETURN // Cursors.Main()

cursors

Harbour New Data types

Data type & Syntax extensions in Harbour

In addition to Clipper’s scalar ( Character, Number, Date, Logical, MEMO, Nil ) and complex ( array, CodeBlock )  data types; Harbour has extended data types: pointer as scalar and object and hach as complex type.

For standard data types please refer here and/or here.

In database files (tables) data types of fields are predefined in structure of table.

For extended field types please refer here.

For data items other than fields (such as variables and manifest constants); in general, type of data  determined automatically by system, when assigning a value. The first basic way of this, is assigning a “literal” value.

For a working sample about constants please refer here.

cString := "This is a string" // A character string enclosed by a string delimiter
nNumber := 123.45 // A numeric value combined digits, decimal point and a sign ( + / - )
lTrue   := .T. // A T (tYy) or F (fNn) letter enclosed by two periods (.)
aArray  := {} // Arrays can be assigned literally by enclosed with curly brace

In addition to this basic literal value notations, Harbour has also extended notations:

– Data Types determined by special prefixs

— 0x… : Hexadecimal constant

  nNumber := 0x0A  // 0x prefix implies the string as Hexadecimal String  
                   // and type of resulting value become as Numeric (N) 
  ? nNumber, VALTYPE( nNumber ) // 10 N

— 0d… date constant

    dDate_1 := 0d20121225  // 0d prefix implies the string a date string 
                           // ( instead of using CTOD() )
                           // and type of resulting value become as Date (D) 
    ? dDate_1, VALTYPE( dDate_1 ) // 25.12.2012 D

– Special literal string formats

— d”…” : Date constant

dDate_2 := d"2012-12-26" ? dDate_2, VALTYPE( dDate_2 ) // 26.12.2012 D

— t”…” : Time constant

tTime_1 := dDate_2 + t”01:31:06″

? tTime_1, VALTYPE( tTime_1 ) // 26.12.2012 01:31:06.000 T

— e”…” : Escape sequences

Escape sequences are used to define certain special characters within string literals.

( Prefix by “\” escape sequence codes within that string )

The following escape sequences are available in C and C++ language :

Escape
sequence Description            Representation

   '     single quote          byte 0x27
   "     double quote          byte 0x22
   ?     question mark         byte 0x3f
         backslash             byte 0x5c

         null character        byte 0x00
   a     audible bell          byte 0x07
   b     backspace             byte 0x08
   f     form feed - new page  byte 0x0c
   n     line feed - new line  byte 0x0a
   r     carriage return       byte 0x0d
   t     horizontal tab        byte 0x09
   v     vertical tab          byte 0x0b

   nnn   arbitrary octal value byte nnn
   xnn   arbitrary hexadecimal value byte nn

   unnnn arbitrary Unicode value.
          May result in several characters. code point U+nnnn
   Unnnnnnnn arbitrary Unicode value.
           May result in several characters. code point U+nnnnnnnn

Note that all sequences not available in Harbour.

For the new complex data type Hash, there is a literally assigning way :

hHash := { => }    // => sign indicates the hash

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

PROCEDURE Main()
SET CENT ON
SET DATE GERM
CLS

* Data Types determined by special prefixs

** 0x... : Hexadecimal constant

nNumber := 0x0A // 0x prefix implies the string as Hexadecimal String 
// and type of resulting value become as Numeric(D)
? nNumber, VALTYPE( nNumber ) // 10 N
** 0d... date constant 

 dDate_1 := 0d20121225 // 0d prefix implies the string a date string 
                       // ( instead of using CTOD() )
                       // and type of resulting value become as Date (D) 

? dDate_1, VALTYPE( dDate_1 ) // 25.12.2012 D
* Special literal string formats
** d"..." : Date constant
dDate_2 := d"2012-12-26"
? dDate_2, VALTYPE( dDate_2 ) // 26.12.2012 D 

** t"..." : Time constant
tTime_1 := dDate_2 + t"01:31:06"
? tTime_1, VALTYPE( tTime_1 ) // 26.12.2012 01:31:06.000 T

** e"..." : Escape sequences 

? e"This is\na string\nformatted by\nEscape sequences \x21

/* The result : 
This is
a string
formatted by
Escape sequences !
*/
@ MAXROW(), 0 WAIT "EOF DTS_Exts.prg" 
RETURN // DTS_Exts.Main() 

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DTS_Exts

Strong Relation

Build strong relationships

Basics of building databases, indexs and relations.