/* Harbour extended Field Types Type Short Code Name Width (Bytes) Description ---- ------- ----------------- ------------------------------------------------------------------- D Date 3, 4 or 8 Date M Memo 4 or 8 Memo + AutoInc 4 Auto increment = ModTime 8 Last modified date & time of this record ^ RowVers 8 Row version number; modification count of this record @ DayTime 8 Date & Time I Integer 1, 2, 3, 4 or 8 Signed Integer ( Width : )" },; T Time 4 or 8 Only time (if width is 4 ) or Date & Time (if width is 8 ) (?) V Variant 3, 4, 6 or more Variable type Field Y Currency 8 64 bit integer with implied 4 decimal B Double 8 Floating point / 64 bit binary Program : ExFldTps.prg Author : Bicahi Esgici ( esgici <at> gmail.com ) All rights reserved. 2011.10.12 A warn : While running, this program produce some .dbf and .txt file(s) and don't erase its upon close. This is because you may want inspect its. You may erase these files arbitrarily. */ PROCEDURE Main() LOCAL aOperations := { { "Width", "Testing Field Widths" },; { "Numeric Limits", "Determining Numeric Limits" },; { "Integer Limits", "Determining Integer Limits" },; { "Set/Get", "Set & read back field values" },; { "Conversion", "Convert and test signed to integer" }},; a1Oper := {},; n1Oper := 1 LOCAL aFldTypes := { { "D", "Date", "Date ( Width : 3, 4 or 8 )" } ,; { "M", "Memo", "Memo ( Width : 4 or 8 )" },; { "+", "AutoInc", "Auto increment ( Width : 4 )" },; { "=", "ModTime", "Last modified date & time of this record ( Width : 8 )" },; { "^", "RowVers", "Row version number; modification count of this record ( Width : 8 )" },; { "@", "DayTime", "Date & Time ( Width : 8 )" },; { "I", "Integer", "Signed Integer ( Width : 1, 2, 3, 4 or 8 )" },; { "T", "Time", "Only time (if width is 4 ) or Date & Time (if width is 8 )" },; { "V", "Variant", "Variable type (!) Field ( Width : 3, 4, 6 or more)" },; { "Y", "Currency", "Integer 64 bit with implied 4 decimal" },; { "B", "Double", "Floating point / 64 bit binary ( Width : 8 )" } },; a1Type := {},; n1Type := 1,; n2Type := 1 LOCAL nMColumn := 0,; // Menu Column No nMRow := 0 // Menu Row No SET WRAP ON SET MESSAGE TO 58 CENTER SET CENTURY ON * In screen resolution 1440 * 900 SetMode( 60, 150 ) seem good. * In this case value of SET MESSAGE TO will be 58 ( less 2 than nRow specified in SetMod() ). SetMode( 60, 150 ) WHILE n1Oper > 0 CLS nMSutn := 0 FOR EACH a1Oper IN aOperations @ 0, nMSutn PROMPT a1Oper[ 1 ] MESSAGE a1Oper[ 2 ] nMSutn += LEN( a1Oper[ 1 ] ) + 1 NEXT MENU TO n1Oper SWITCH n1Oper CASE 0 EXIT CASE 1 // Testing Field Widths n1Type := 1 WHILE n1Type > 0 @ 1,0 CLEAR TO 24, 80 nMRow := 2 FOR EACH a1Type IN aFldTypes @ nMRow++, 0 PROMPT a1Type[ 2 ] MESSAGE a1Type[ 3 ] NEXT a1Type MENU TO n1Type IF n1Type > 0 @ 1,0 CLEAR TO 24, 80 @ 1, 0 SAY aFldTypes[ n1Type, 2 ] COLOR "B/W" FT_Widths( aFldTypes[ n1Type ] ) ENDIF ENDDO n1Type EXIT CASE 2 // Determining Numeric Limits NumLimits() EXIT CASE 3 // Determining Integer Limits IntLimits() EXIT CASE 4 // Set & read back field values n2Type := 1 WHILE n2Type > 0 @ 1,0 CLEAR TO 24, 80 nMRow := 2 FOR EACH a1Type IN aFldTypes @ nMRow++, 36 PROMPT a1Type[ 2 ] MESSAGE a1Type[ 3 ] NEXT MENU TO n2Type IF n2Type > 0 V_SetGet( aFldTypes[ n2Type ] ) ENDIF ENDDO n1Type EXIT CASE 5 // Convert and test signed to integer SignChng() EXIT END SWITCH ENDDO n1Oper RETURN // Main() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE FT_Widths( a1Type ) // Testing Field Widths LOCAL cType := a1Type[ 1 ],; nFldNo := 0,; aStru1 := {},; aStru2 := {},; aStru3 := { { 'FldType', "C", 1, 0 },; // Type of field { 'WidtSpec', "N", 2, 0 },; // Specified width { 'Dec_Spec', "N", 2, 0 },; // Specified decimal { 'WidtAppl', "N", 2, 0 },; // Applied (by Harbour) width { 'Dec_Max', "N", 2, 0 },; // Computed maximum dec { 'Result', "C", 1, 0 } } FOR nFldNo := 1 TO 32 AADD( aStru1, { "X" + STRZERO( nFldNo, 2 ), cType, nFldNo, 0 } ) NEXT nFldNo DBCREATE( "Widths", aStru1 ) USE Widths aStru2 := DBSTRUCT() IF cType $ "IYB" AEVAL( aStru2, { | a1, i1 | aStru2[ i1, 4 ] := aStru2[ i1, 3 ] - 1 } ) ENDIF USE DBCREATE( "Widths", aStru2 ) USE Widths aStru2 := DBSTRUCT() USE DBCREATE( "Widths", aStru3 ) USE Widths FOR nFldNo := 1 TO 32 DBAPPEND() REPLACE FldType WITH aStru1[ nFldNo, 2 ],; WidtSpec WITH aStru1[ nFldNo, 3 ],; Dec_Spec WITH aStru1[ nFldNo, 4 ],; WidtAppl WITH aStru2[ nFldNo, 3 ],; Dec_Max WITH aStru2[ nFldNo, 4 ],; Result WITH IF( aStru1[ nFldNo, 3 ] # aStru2[ nFldNo, 3 ], "-", "+" ) NEXT nFldNo DBGOTOP() BROWSE() USE RETURN // FT_Widths() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE NumLimits() // Determining Numeric Limits LOCAL mBayt := 0,; nBit := 0,; nExpo := 0 * nExpos := { 8, 16, 24, 32, 64 } SET ALTE TO N_Limits SET ALTE ON ? SPACE(9), "Unsigned ( Always + )" ? "-- ------ ---------------------------" FOR nBayt := 1 TO 8 nBit := nBayt * 8 nExpo := 2^nBit ? STR( nBayt, 2 ), "2^" + PADL( nBit, 2) + " : ", TRANSFORM( nExpo, "99,999,999,999,999,999,999" ) NEXT nBayt ? ? ? PADC( "Signed ( - / + )", 80 ) ? "-- ------ -----------------------------------------------------" FOR nBayt := 1 TO 8 nBit := nBayt * 8 nExpo := 2^nBit ? STR( nBayt, 2 ), "2^" + PADL( nBit, 2) + " : ", TRANSFORM( - nExpo / 2, "99,999,999,999,999,999,999" )+; ".."+; LTRIM( TRANSFORM( nExpo / 2 - 1, "99,999,999,999,999,999,999" ) ) NEXT nBayt SET ALTE OFF SET ALTE TO MEMOEDIT( MEMOREAD( "N_Limits.TXT" ) ) RETURN // NumLimits() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE IntLimits() // Determining Integer Limits LOCAL nFldNo := 0,; aStru4 := { { 'MNMX', "C", 7, 0 },; { 'INT1', "I", 1, 0 },; { 'INT2', "I", 2, 0 },; { 'INT3', "I", 3, 0 },; { 'INT4', "I", 4, 0 },; { 'INT8', "I", 8, 0 } } DBCREATE( "IntLimits", aStru4 ) USE IntLimits DBAPPEND() REPLACE MNMX WITH "Minimum" ,; INT1 WITH -2^7 ,; INT2 WITH -2^15 ,; INT3 WITH -2^23 ,; INT4 WITH -2^31 ,; INT8 WITH -2^63 DBAPPEND() REPLACE MNMX WITH "Maximum" ,; INT1 WITH 2^7 - 1 ,; INT2 WITH 2^15 - 1 ,; INT3 WITH 2^23 - 1 ,; INT4 WITH 2^31 - 1 ,; INT8 WITH 2^63 - 513 // < 513 ---> "Error DBFNTX/1021 Data width error" DBGOTOP() @ 1,0 CLEAR TO 24, 80 SET ALTE TO IntLimits SET ALTE ON WHILE !EOF() ? ? MNMX ? '--------' FOR nFldNo := 2 TO 6 ? FIELDNAME( nFldNo ), ": ", LTRIM( TRANSFORM( FIELDGET( nFldNo ), "99,999,999,999,999,999,999" ) ) NEXT nFldNo ? SKIP ENDDO SET ALTE OFF SET ALTE TO MEMOEDIT( MEMOREAD( "IntLimits.txt" ) ) USE RETURN // IntLimits() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_NoType() // Testing NoType ( Variant ) field type LOCAL aStru5 := { { "Initial", "C", 19, 0 },; { "Internal", "V", 19, 0 },; { "ReadBack", "C", 19, 0 },; { "ReadBackTp", "C", 1, 0 } } DBCREATE( "SG_NoType", aStru5 ) USE SG_NoType DBAPPEND() REPLACE Initial WITH "String", Internal WITH "String" DBAPPEND() REPLACE Initial WITH "12345", Internal WITH 12345 DBAPPEND() REPLACE Initial WITH DTOC( DATE() ), Internal WITH DATE() DBAPPEND() REPLACE Initial WITH ".T.", Internal WITH .T. REPLACE ALL ReadBack WITH HB_ValToStr( Internal ), ReadBackTp WITH VALTYPE( Internal ) DBGOTOP() BROWSE() USE RETURN // SG_NoType() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE V_SetGet( aType ) // Set & read back field values LOCAL cType := aType[ 1 ] @ 1,0 CLEAR TO 24, 80 SWITCH cType CASE "D" // Date SG_Date() EXIT CASE "M" // Memo SG_Memo() EXIT CASE "+" // AutoInc Alert( "Read Only" ) EXIT CASE "=" // ModTime Alert( "Read Only" ) EXIT CASE "^" // RowVers Alert( "Read Only" ) EXIT CASE "@" // DayTime SG_DayTime() EXIT CASE "I" // Integer SG_Integers() EXIT CASE "T" // Time SG_DayTime() EXIT CASE "V" // Variant SG_NoType() EXIT CASE "Y" // Currency SG_Currency() EXIT CASE "B" // Double SG_Double() EXIT END SWITCH RETURN // V_SetGet() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_Date() // Date : Compare set / get LOCAL aStru6 := { { "Initial", "D", 8, 0 } ,; { "Internal3", "D", 3, 0 } ,; { "Internal4", "D", 4, 0 } ,; { "Internal8", "D", 8, 0 } ,; { "ReadBack3", "C", 12, 0 } ,; { "ReadBack4", "C", 12, 0 } ,; { "ReadBack8", "C", 12, 0 } } DBCREATE( "SG_Date", aStru6 ) USE SG_Date DBAPPEND() REPLACE Initial WITH DATE() - ( 66 * 365 + 66 / 4 ),; Internal3 WITH Initial ,; Internal4 WITH Initial ,; Internal8 WITH Initial ,; ReadBack3 WITH HB_ValToStr( Internal3 ) ,; ReadBack4 WITH HB_ValToStr( Internal4 ) ,; ReadBack8 WITH HB_ValToStr( Internal8 ) DBGOTOP() BROWSE() USE RETURN // SG_Date() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_Memo() // Set / Get test for MEMO fields LOCAL aStru7 := { { "MEMO_4", "M", 4, 0 } ,; { "MEMO_10", "M", 10, 0 } } DBCREATE( "SG_Memo", aStru7 ) USE SG_Memo DBAPPEND() REPLACE MEMO_4 WITH "MEMO field with width 4",; MEMO_10 WITH "MEMO field with width 4" DBGOTOP() BROWSE() USE RETURN // SG_Date() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_DayTime() // Set / Get test for DayTime fields LOCAL aStru8 := { { "ModTim", "=", 8, 0 } ,; { "DaTime", "@", 8, 0 } ,; // { "Time_8", "T", 8, 0 } ,; { "Time_4", "T", 4, 0 } ,; { "Time_C", "C", 12, 0 } } DBCREATE( "SG_Datime", aStru8 ) USE SG_Datime DBAPPEND() * REPLACE DaTime WITH DATE() // ==> Error DBFNTX/1020 Data type error: DATIME * REPLACE Time_4 WITH SECO() / TIME() // ==> Error DBFNTX/1020 Data type error: DATIME * REPLACE Time_8 WITH TIME() // ==> Error DBFNTX/1020 Data type error: TIME_8 * DBAPPEND() * REPLACE DaTime WITH ModTim // ==> 0000-00-00 00:00:00.000 * REPLACE Time_4 WITH ModTim // ==> Error DBFNTX/1020 Data type error: TIME_4 * REPLACE Time_8 WITH ModTim // ==> 0000-00-00 00:00:00.000 REPLACE DaTime WITH ModTim,; // ==> > 0000-00-00 00:00:00.000 Time_8 WITH ModTim,; // ==> > 0000-00-00 00:00:00.000 Time_C WITH TIME() DBGOTOP() BROWSE() USE RETURN // SG_DayTime() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_Integers() // Set / Get test for INTEGER fields LOCAL nRecno := 0,; aStru9 := { { 'INT1', "I", 1, 0 },; { 'NUM1', "N", 4, 0 },; { 'EQL1', "L", 1, 0 },; { 'INT11', "I", 1, 1 },; { 'NUM11', "N", 5, 1 },; { 'EQL11', "L", 1, 0 },; { 'INT2', "I", 2, 0 },; { 'NUM2', "N", 8, 0 },; { 'EQL2', "L", 1, 0 },; { 'INT22', "I", 8, 2 },; { 'NUM22', "N",12, 2 },; { 'EQL22', "L", 1, 0 },; { 'INT3', "I", 3, 0 },; { 'NUM3', "N", 8, 0 },; { 'EQL3', "L", 1, 0 },; { 'INT32', "I", 3, 2 },; { 'NUM32', "N",12, 2 },; { 'EQL32', "L", 1, 0 },; { 'INT4', "I", 4, 0 },; { 'NUM4', "N",12, 0 },; { 'EQL4', "L", 1, 0 },; { 'INT42', "I", 4, 2 },; { 'NUM42', "N",14, 2 },; { 'EQL42', "L", 1, 0 },; { 'INT8', "I", 8, 0 },; { 'NUM8', "N",21, 0 },; { 'EQL8', "L", 1, 0 },; { 'INT84', "I", 8, 4 },; { 'NUM84', "N",21, 4 },; { 'EQL84', "L", 1, 0 } } DBCREATE( "SG_Integers", aStru9 ) USE SG_Integers FOR nRecno := 1 TO 18 DBAPPEND() NEXT nRecno REPL ALL INT1 WITH INT( HB_RANDOM( -2^7 , 2^7 - 1 )) ,; INT11 WITH INT( HB_RANDOM( -2^7 , 2^7 - 1 )) / 10 ,; INT2 WITH INT( HB_RANDOM( -2^15, 2^15 - 1 )) ,; INT22 WITH INT( HB_RANDOM( -2^15, 2^15 - 1 )) ,; INT3 WITH INT( HB_RANDOM( -2^23, 2^23 - 1 )) ,; INT32 WITH INT( HB_RANDOM( -2^23, 2^23 - 1 )) / 100 ,; INT4 WITH INT( HB_RANDOM( -2^31, 2^31 - 1 )) ,; INT42 WITH INT( HB_RANDOM( -2^31, 2^31 - 1 )) / 100 ,; INT8 WITH INT( HB_RANDOM( -2^63, 2^63 - 513 )) ,; INT84 WITH INT( HB_RANDOM( -2^63, 2^63 - 513 )) / 10000 REPL ALL NUM1 WITH INT1, EQL1 WITH NUM1 = INT1 ,; NUM11 WITH INT11, EQL11 WITH NUM11 = INT11 ,; NUM2 WITH INT2, EQL2 WITH NUM2 = INT2 ,; NUM22 WITH INT22, EQL22 WITH NUM22 = INT22 ,; NUM3 WITH INT3, EQL3 WITH NUM3 = INT3 ,; NUM32 WITH INT32, EQL32 WITH NUM32 = INT32 ,; NUM4 WITH INT4, EQL4 WITH NUM4 = INT4 ,; NUM42 WITH INT42, EQL42 WITH NUM42 = INT42 ,; NUM8 WITH INT8, EQL8 WITH NUM8 = INT8 ,; NUM84 WITH INT84, EQL84 WITH NUM84 = INT84 DBGOTOP() BROWSE() USE RETURN // SG_Integers() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_Currency() // Set / Get test for CURRENCY fields LOCAL aStru10 := { { "Currenc", "Y", 8, 4 } ,; { "NUM2D", "N", 21, 2 } ,; { "NUM4D", "N", 21, 4 } ,; { "NUM6D", "N", 23, 6 } ,; { "NUM8D", "N", 25, 8 } } DBCREATE( "SG_Curncy", aStru10 ) USE SG_Curncy FOR nRecno := 1 TO 100 DBAPPEND() REPLACE Currenc WITH HB_RANDOM( -2^53, 2^53 ) / 10000 ,; NUM2D WITH Currenc ,; NUM4D WITH Currenc ,; NUM6D WITH Currenc ,; NUM8D WITH Currenc NEXT nRecno DBGOTOP() BROWSE() USE RETURN // SG_Currency() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SG_Double() // Set / Get test for DOUBLE ( BINARY ) fields LOCAL nRecno := 0 LOCAL aStru11 := { { "Double", "B", 8, 4 } ,; { "NUM2D", "N", 21, 2 } ,; { "NUM4D", "N", 21, 4 } ,; { "NUM6D", "N", 23, 6 } ,; { "NUM8D", "N", 25, 8 } } DBCREATE( "SG_Double", aStru11 ) USE SG_Double FOR nRecno := 1 TO 100 DBAPPEND() REPLACE Double WITH HB_RANDOM( -2^53, 2^53 ) / 10000 ,; NUM2D WITH Double ,; NUM4D WITH Double ,; NUM6D WITH Double ,; NUM8D WITH Double NEXT nRecno DBGOTOP() BROWSE() USE RETURN // SG_Double() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ PROCEDURE SignChng() // Convert and test signed to integer LOCAL nRecno := 0 LOCAL aStru12 := { { 'NUM1', "N", 3, 0 },; { 'INT1', "I", 1, 0 },; { 'RET1', "N", 3, 0 },; { 'EQL1', "L", 1, 0 },; { 'NUM2', "N", 6, 0 },; { 'INT2', "I", 2, 0 },; { 'RET2', "N", 6, 0 },; { 'EQL2', "L", 1, 0 },; { 'NUM3', "N", 9, 0 },; { 'INT3', "I", 3, 0 },; { 'RET3', "N", 9, 0 },; { 'EQL3', "L", 1, 0 },; { 'NUM4', "N", 11, 0 },; { 'INT4', "I", 4, 0 },; { 'RET4', "N", 11, 0 },; { 'EQL4', "L", 1, 0 },; { 'NUM8', "N", 21, 0 },; { 'INT8', "I", 8, 0 },; { 'RET8', "N", 21, 0 },; { 'EQL8', "L", 1, 0 } } DBCREATE( "SignChng", aStru12 ) USE SignChng FOR nRecno := 1 TO 100 DBAPPEND() REPLACE NUM1 WITH HB_RANDOM( 0, 2^8 - 1 ), INT1 WITH NUM1 - 2^7 , RET1 WITH INT1 + 2^7, EQL1 WITH NUM1 = RET1 ,; NUM2 WITH HB_RANDOM( 0, 2^16 - 1 ), INT2 WITH NUM2 - 2^15, RET2 WITH INT2 + 2^15, EQL2 WITH NUM2 = RET2 ,; NUM3 WITH HB_RANDOM( 0, 2^24 - 1 ), INT3 WITH NUM3 - 2^23, RET3 WITH INT3 + 2^23, EQL3 WITH NUM3 = RET3 ,; NUM4 WITH HB_RANDOM( 0, 2^32 - 1 ), INT4 WITH NUM4 - 2^31, RET4 WITH INT4 + 2^31, EQL4 WITH NUM4 = RET4 ,; NUM8 WITH HB_RANDOM( 0, 2^64 - 1 ), INT8 WITH NUM8 - 2^63, RET8 WITH INT8 + 2^63, EQL8 WITH NUM8 = RET8 NEXT nRecno DBGOTOP() BROWSE() USE RETURN // SignChng() *-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._ Download Source File
Pingback: What are basic data types ? | Viva Clipper !