2009-05-15 12:36 UTC+0200 Viktor Szakats (harbour.01 syenar hu)

* utils/hbmk2/hbmk2.prg
    % Changed default way of updating .po files. New method supports
      incremental updates, thus much faster than previous solution.
      As a side-effect, removed from source and changed translatable
      strings won't automatically disappear from .po files.
      This new method is also much friendlier to version control
      systems, as .po entry order won't change on each minor update
      (and generate a huge commit diff).
    + Added -rebuildpo option to activate a complete rebuild of .po
      files, clearing all no more existing entries. This operation 
      will take more time, will create big diffs and it's recommended 
      to be done when doing a complete rebuild (maybe this will 
      be automatically enforced later on).
    ; With this, hbmk2 seems feature complete. (maybe C++/C mode
      switching could be added yet, it's on the TODO list)

  * bin/hb-func.sh
    * Addition of libs= entry in hbmk.cfg file will now be
      initiated by setting envvar HB_USER_LIBS_DEF (was HB_USER_LIBS),
      to avoid potential binary build problems where locally
      set HB_USER_LIBS envvar could create an unusuable (on other
      systems) builds (hbmk2 setup).

  + contrib/rddsql/readme.txt
    + Added readme (posted on the list). Work of Mindaugas.
This commit is contained in:
Viktor Szakats
2009-05-15 10:39:59 +00:00
parent 08d5d5e838
commit 0cf55690cb
4 changed files with 230 additions and 31 deletions

View File

@@ -17,6 +17,33 @@
past entries belonging to these authors: Viktor Szakats.
*/
2009-05-15 12:36 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
* utils/hbmk2/hbmk2.prg
% Changed default way of updating .po files. New method supports
incremental updates, thus much faster than previous solution.
As a side-effect, removed from source and changed translatable
strings won't automatically disappear from .po files.
This new method is also much friendlier to version control
systems, as .po entry order won't change on each minor update
(and generate a huge commit diff).
+ Added -rebuildpo option to activate a complete rebuild of .po
files, clearing all no more existing entries. This operation
will take more time, will create big diffs and it's recommended
to be done when doing a complete rebuild (maybe this will
be automatically enforced later on).
; With this, hbmk2 seems feature complete. (maybe C++/C mode
switching could be added yet, it's on the TODO list)
* bin/hb-func.sh
* Addition of libs= entry in hbmk.cfg file will now be
initiated by setting envvar HB_USER_LIBS_DEF (was HB_USER_LIBS),
to avoid potential binary build problems where locally
set HB_USER_LIBS envvar could create an unusuable (on other
systems) builds (hbmk2 setup).
+ contrib/rddsql/readme.txt
+ Added readme (posted on the list). Work of Mindaugas.
2009-05-15 12:03 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/contrib/rddads/ads1.c
! fixed typo in recent modification which caused that character fields

View File

@@ -252,8 +252,8 @@ mk_hbtools()
if [ -n "${CC_HB_USER_LDFLAGS}" ]; then
echo "ldflags=${CC_HB_USER_LDFLAGS}">> ${hb_hbmkcfg}
fi
if [ -n "${HB_USER_LIBS}" ]; then
echo "libs=${HB_USER_LIBS}">> ${hb_hbmkcfg}
if [ -n "${HB_USER_LIBS_DEF}" ]; then
echo "libs=${HB_USER_LIBS_DEF}">> ${hb_hbmkcfg}
fi
if [ "${HB_GPM_MOUSE}" = "yes" ]; then
echo "libs=gpm">> ${hb_hbmkcfg}

View File

@@ -0,0 +1,133 @@
/*
* $Id$
*/
Simple SQL Interface for Harbour
1. Introduction
Simple SQL interface implements accessing SQL query result via RDD
interface. It is not intended to be replacement for "transparent" move of
DBFCDX application to SQL world.
I want to discuss this in more detail. Many current RDDs for SQL servers
(ex. SQLRDD from xHarbour.com) tries to make a feeling you are working with
DBF file, but not with SQL database. SQL server does not support many
features, ex. RECNO(), deleted flag, file locks, record locks. These RDDs
are emulating these features to make feeling of DBF. DELETED() function is
emulated by creating additional table columns to store delete flag. Some
"hidden system" tables are used to register locking operations and emulate
record and file locks in DBF style. The idea of SQL query is also lost. If
you do a simple loop
DBUSEAREA(, "select * from my_table")
DO WHILE ! EOF()
somefunc( FIELD->some_sql_field )
DBSKIP()
ENDDO
RDD usualy will read SQL rows in portions, let's say 100 records per query.
So, hidden queries are generated. If you are using indexes these queries
are really complicated. Let's have index on FIELD1 + STR(FIELD2). A seek to
value cValue1 + STR(nValue2) will generate a query like:
SELECT * FROM my_table
WHERE (FIELD1 == cValue1 and FIELD2 >= nValue2) or FIELD1 > cValue1
ORDER BY FIELD1, FIELD2, _RECNO
LIMIT 100
After evaluation of first 100 cached records, next query will be generated:
SELECT * FROM my_table
WHERE (FIELD1 == cLastField1 and FIELD2 == nLastValue2 and _RECNO > nLastRecno) or
(FIELD1 == cLastField1 and FIELD2 > nLastValue2) or
FIELD1 > cLastValue1
ORDER BY FIELD1, FIELD2, _RECNO
LIMIT 100
To optimize these queries the SQL index expresion should be
"FIELD1,FIELD2,_RECNO", but not "FIELD1,FIELD2" as written in INDEX ON
command.
"Simple SQL interface" is too long to repeat every time I want to
address this library. I'll also use acronym "SSI" to address it.
The idea of SSI is different. It does not make hidden queries. All
queries should be made explicitly by programmer. SSI gives access to query
result via RDD interface, it does not tries to emulate DBF and be
"plug-and-play" solution for DBF to SQL migration. If you do
DBUSEAREA(, "select * from my_table")
all query (it could contain millions of records!) will be cached.
The features of SSI approach are:
- It's possible to access SQL database of other applications. Other
applications usualy does not follow agreement of "plug-and-play" SQL drivers
about additional DELETED column, _RECNO in the end of index expression, etc.
Access of SQL database of other applications is sometimes not possible.
- It's query oriented. That means a simple DO WHILE ! EOF() loop will iterate
each records once and only once. This is not true for "plug-and-play" SQL
drivers, if indexing is used. Just like in the case of loop over DBF file.
It is not guaranteed that all records are included! Yes! If key value of the
first record in index is changed to be the last record in index during the
phase of record processing, DO WHILE ! EOF() loop will iterate only this
single records even if the database contains millions of records. Your sould
do FLOCK() on DBF to guarantee the records are not changed. Do you use FLOCK()
before readonly DO WHILE ! EOF() loops? :)
2. Architecture
+-------------+
| |
| SQLMIX RDD |
| |
+-------------+
| ^
V |
+-------------+ +---------+
| |--->| |
| SQLBASE RDD | | SDD |
| |<---| |
+-------------+ +---------+
SQLBASE RDD implements basic functionality for accessing SQL query result
via RDD interface. This RDD could be used, if indexing of query result is not
necessary or all indexing is done by SQL server (by using ORDER BY clause).
SQLMIX RDD implements indexing of query result. This indexing is not
related to SQL server ORDER BY clause. SQLMIX do indexing of the query on the
client side.
SDD is acronym for Sql Database Driver. RDD is used to implement access
of different database formats like DBF, SDF, etc. SDD is used to implement
access of different SQL databases. Every SQL server (MySQL, PostgreSQL, etc.)
has a corresponding SDD. SDD driver implements a specific part of data
exchange interface between SQLBASE and SQL server.
A few additional functions are also implemented, ex. HB_SQLCONNECT().
Usualy these functions are just a shorter version of corresponding RDDINFO()
call.
3. Modifying database
SSI presents a query result via RDD interface and generates no hidden
SQL queries. So, how database can be changed? Does DBAPPEND() and FIELDPUT()
works, or is it readonly SQL interface?
DBAPPEND(), FIELDPUT() and other similiar functions work on cached query
result, i.e. query can be appended by new rows and field values can be
changed, but SQL database is not changed. DBCREATE() function can also be
used to create an "empty query result" but no table is created on SQL server.
So, SSI can also be used as implementation of "array RDD".
The programmer must call SQL command explicitly to modify SQL tables.
SSI provides a method to detect which cached rows was changed or appended.

View File

@@ -35,7 +35,7 @@
* bash script with similar purpose for gcc family.
* entry point override method and detection code for gcc.
* rtlink/blinker link script parsers.
* POTMerge(), LoadPOTFiles(), LoadPOTFilesAsHash(), GenHbl() and AutoTrans().
* POTMerge(), LoadPOTFilesAsHash(), GenHbl() and AutoTrans().
* (with local modifications by hbmk author)
*
* See COPYING for licensing terms.
@@ -95,7 +95,6 @@
/* TODO: Further clean hbmk context var usage (hbmk2 scope, project scope,
adding rest of variables). */
/* TODO: Finish C++/C mode selection. */
/* TODO: Incremental .pot to .po merge. */
/* TODO: Add a way to fallback to stop if required headers couldn't be found.
This needs a way to spec what key headers to look for. */
@@ -183,21 +182,22 @@ REQUEST hbmk_KEYW
#define _HBMK_nCOMPR 37
#define _HBMK_lRUN 38
#define _HBMK_lINC 39
#define _HBMK_lREBUILDPO 40
#define _HBMK_aPO 40
#define _HBMK_cHBL 41
#define _HBMK_aLNG 42
#define _HBMK_cPO 43
#define _HBMK_aPO 41
#define _HBMK_cHBL 42
#define _HBMK_aLNG 43
#define _HBMK_cPO 44
#define _HBMK_lDEBUGTIME 44
#define _HBMK_lDEBUGINC 45
#define _HBMK_lDEBUGSTUB 46
#define _HBMK_lDEBUGI18N 47
#define _HBMK_lDEBUGTIME 45
#define _HBMK_lDEBUGINC 46
#define _HBMK_lDEBUGSTUB 47
#define _HBMK_lDEBUGI18N 48
#define _HBMK_cCCPATH 48
#define _HBMK_cCCPREFIX 49
#define _HBMK_cCCPATH 49
#define _HBMK_cCCPREFIX 50
#define _HBMK_MAX_ 49
#define _HBMK_MAX_ 50
PROCEDURE Main( ... )
LOCAL aArgs := hb_AParams()
@@ -445,6 +445,7 @@ FUNCTION hbmk( aArgs )
hbmk[ _HBMK_nCOMPR ] := _COMPR_OFF
hbmk[ _HBMK_lRUN ] := .F.
hbmk[ _HBMK_lINC ] := .F.
hbmk[ _HBMK_lREBUILDPO ] := .F.
hbmk[ _HBMK_lDEBUGTIME ] := .F.
hbmk[ _HBMK_lDEBUGINC ] := .F.
@@ -1099,6 +1100,7 @@ FUNCTION hbmk( aArgs )
CASE cParamL == "-beep-" .OR. ;
cParamL == "-nobeep" ; s_lBEEP := .F.
CASE cParamL == "-rebuild" ; hbmk[ _HBMK_lINC ] := .T. ; hbmk[ _HBMK_lREBUILD ] := .T.
CASE cParamL == "-rebuildpo" ; hbmk[ _HBMK_lREBUILDPO ] := .T.
CASE cParamL == "-clean" ; hbmk[ _HBMK_lINC ] := .T. ; s_lCLEAN := .T.
CASE cParamL == "-inc" ; hbmk[ _HBMK_lINC ] := .T.
CASE cParamL == "-inc-" .OR. ;
@@ -2873,8 +2875,14 @@ FUNCTION hbmk( aArgs )
s_aRESSRC_TODO := s_aRESSRC
ENDIF
IF ! Empty( hbmk[ _HBMK_cPO ] ) .AND. ! Empty( s_aPRG ) .AND. Len( s_aPRG_TODO ) > 0
MakePO( hbmk, ListDirExt( s_aPRG, cWorkDir, ".pot" ) )
IF hbmk[ _HBMK_lREBUILDPO ]
IF ! Empty( hbmk[ _HBMK_cPO ] ) .AND. ! Empty( s_aPRG )
RebuildPO( hbmk, ListDirExt( s_aPRG, cWorkDir, ".pot" ) )
ENDIF
ELSE
IF ! Empty( hbmk[ _HBMK_cPO ] ) .AND. Len( s_aPRG_TODO ) > 0
UpdatePO( hbmk, ListDirExt( s_aPRG_TODO, cWorkDir, ".pot" ) )
ENDIF
ENDIF
IF Len( hbmk[ _HBMK_aPO ] ) > 0 .AND. hbmk[ _HBMK_cHBL ] != NIL .AND. ! s_lCLEAN
@@ -5081,9 +5089,9 @@ STATIC FUNCTION rtlnk_process( hbmk, cCommands, cFileOut, aFileList, aLibList, ;
RETURN .T.
/* .hbl generation */
/* .po generation */
STATIC PROCEDURE MakePO( hbmk, aPOTIN )
STATIC PROCEDURE RebuildPO( hbmk, aPOTIN )
LOCAL cLNG
LOCAL fhnd
LOCAL cPOTemp
@@ -5098,10 +5106,10 @@ STATIC PROCEDURE MakePO( hbmk, aPOTIN )
IF fhnd != F_ERROR
FClose( fhnd )
IF hbmk[ _HBMK_lDEBUGI18N ]
hbmk_OutStd( hb_StrFormat( "MakePO: file .pot list: %1$s", ArrayToList( aPOTIN, ", " ) ) )
hbmk_OutStd( hb_StrFormat( "MakePO: temp unified .po: %1$s", cPOTemp ) )
hbmk_OutStd( hb_StrFormat( "RebuildPO: file .pot list: %1$s", ArrayToList( aPOTIN, ", " ) ) )
hbmk_OutStd( hb_StrFormat( "RebuildPO: temp unified .po: %1$s", cPOTemp ) )
ENDIF
POTMerge( hbmk, aPOTIN, cPOTemp )
POTMerge( hbmk, aPOTIN, NIL, cPOTemp )
ELSE
hbmk_OutStd( I_( "Error: Cannot create temporary unified .po file." ) )
ENDIF
@@ -5109,13 +5117,13 @@ STATIC PROCEDURE MakePO( hbmk, aPOTIN )
cPOCooked := StrTran( hbmk[ _HBMK_cPO ], _LNG_MARKER, cLNG )
IF hb_FileExists( cPOCooked )
IF hbmk[ _HBMK_lDEBUGI18N ]
hbmk_OutStd( hb_StrFormat( "MakePO: updating unified .po: %1$s", cPOCooked ) )
hbmk_OutStd( hb_StrFormat( "RebuildPO: updating unified .po: %1$s", cPOCooked ) )
ENDIF
AutoTrans( hbmk, cPOTemp, { cPOCooked }, cPOCooked )
AAdd( aUpd, cLNG )
ELSE
IF hbmk[ _HBMK_lDEBUGI18N ]
hbmk_OutStd( hb_StrFormat( "MakePO: creating unified .po: %1$s", cPOCooked ) )
hbmk_OutStd( hb_StrFormat( "RebuildPO: creating unified .po: %1$s", cPOCooked ) )
ENDIF
hb_FCopy( cPOTemp, cPOCooked )
AAdd( aNew, cLNG )
@@ -5135,14 +5143,36 @@ STATIC PROCEDURE MakePO( hbmk, aPOTIN )
ENDIF
IF ! Empty( aUpd )
IF Empty( hbmk[ _HBMK_aLNG ] )
hbmk_OutStd( hb_StrFormat( I_( "Updated .po file '%1$s'" ), hbmk[ _HBMK_cPO ] ) )
hbmk_OutStd( hb_StrFormat( I_( "Rebuilt .po file '%1$s'" ), hbmk[ _HBMK_cPO ] ) )
ELSE
hbmk_OutStd( hb_StrFormat( I_( "Updated .po file '%1$s' for language(s): %2$s" ), hbmk[ _HBMK_cPO ], ArrayToList( aUpd, "," ) ) )
hbmk_OutStd( hb_StrFormat( I_( "Rebuilt .po file '%1$s' for language(s): %2$s" ), hbmk[ _HBMK_cPO ], ArrayToList( aUpd, "," ) ) )
ENDIF
ENDIF
RETURN
/* .po update */
STATIC PROCEDURE UpdatePO( hbmk, aPOTIN )
LOCAL cLNG
LOCAL aUpd := {}
FOR EACH cLNG IN iif( Empty( hbmk[ _HBMK_aLNG ] ) .OR. !( _LNG_MARKER $ hbmk[ _HBMK_cPO ] ), { _LNG_MARKER }, hbmk[ _HBMK_aLNG ] )
POTMerge( hbmk, aPOTIN, StrTran( hbmk[ _HBMK_cPO ], _LNG_MARKER, cLNG ), StrTran( hbmk[ _HBMK_cPO ], _LNG_MARKER, cLNG ) )
AAdd( aUpd, cLNG )
NEXT
IF Empty( hbmk[ _HBMK_aLNG ] )
hbmk_OutStd( hb_StrFormat( I_( "Updated .po file '%1$s'" ), hbmk[ _HBMK_cPO ] ) )
ELSE
hbmk_OutStd( hb_StrFormat( I_( "Updated .po file '%1$s' for language(s): %2$s" ), hbmk[ _HBMK_cPO ], ArrayToList( aUpd, "," ) ) )
ENDIF
RETURN
/* .hbl generation */
STATIC PROCEDURE MakeHBL( hbmk, cHBL )
LOCAL cPO
LOCAL tPO
@@ -5192,12 +5222,20 @@ STATIC PROCEDURE MakeHBL( hbmk, cHBL )
RETURN
STATIC FUNCTION LoadPOTFiles( hbmk, aFiles, lIgnoreError )
LOCAL aTrans := {}, aTrans2
STATIC FUNCTION LoadPOTFiles( hbmk, aFiles, cFileBase, lIgnoreError )
LOCAL aTrans, aTrans2
LOCAL hIndex
LOCAL cErrorMsg
LOCAL cFileName
IF ! Empty( cFileBase )
aTrans := __i18n_potArrayLoad( cFileBase, @cErrorMsg )
ENDIF
IF aTrans == NIL
aTrans := {}
ENDIF
FOR EACH cFileName IN aFiles
aTrans2 := __i18n_potArrayLoad( cFileName, @cErrorMsg )
IF aTrans2 != NIL
@@ -5237,9 +5275,9 @@ STATIC FUNCTION LoadPOTFilesAsHash( hbmk, aFiles )
RETURN hTrans
STATIC PROCEDURE POTMerge( hbmk, aFiles, cFileOut )
STATIC PROCEDURE POTMerge( hbmk, aFiles, cFileBase, cFileOut )
LOCAL cErrorMsg
LOCAL aTrans := LoadPOTFiles( hbmk, aFiles, .T. )
LOCAL aTrans := LoadPOTFiles( hbmk, aFiles, cFileBase, .T. )
IF aTrans != NIL
IF !__i18n_potArraySave( cFileOut, aTrans, @cErrorMsg )
@@ -5253,7 +5291,7 @@ STATIC PROCEDURE AutoTrans( hbmk, cFileIn, aFiles, cFileOut )
LOCAL cErrorMsg
IF !__I18N_potArraySave( cFileOut, ;
__I18N_potArrayTrans( LoadPOTFiles( hbmk, { cFileIn }, .F. ), ;
__I18N_potArrayTrans( LoadPOTFiles( hbmk, {}, cFileIn, .F. ), ;
LoadPOTFilesAsHash( hbmk, aFiles ) ), @cErrorMsg )
hbmk_OutErr( hb_StrFormat( I_( "Error: %1$s" ), cErrorMsg ) )
ENDIF
@@ -5567,6 +5605,7 @@ STATIC PROCEDURE ShowHelp( lLong )
{ "-hbl[=<output>]" , I_( "output .hbl filename. ${lng} macro is accepted in filename" ) },;
{ "-lng=<languages>" , I_( "list of languages to be replaced in ${lng} macros in .pot/.po filenames and output .hbl/.po filenames. Comma separared list:\n-lng=en-EN,hu-HU,de" ) },;
{ "-po=<output>" , I_( "create/update .po file from source. Merge it with previous .po file of the same name" ) },;
{ "-rebuildpo" , I_( "recreate .po file, thus removing all obsolete entries in it" ) },;
NIL,;
{ "-hbrun" , I_( "run target" ) },;
{ "-hbcmp|-clipper" , I_( "stop after creating the object files\ncreate link/copy hbmk to hbcmp/clipper for the same effect" ) },;