/*
 * $Id$
 */


February 2004
I.Q. David Arturo Macias Corona

Modifications to programs of harbour\contrib\hbmysql


TMySql.prg Program *****************************************

Class TMySQLRow ---------------------------------------------
- DATA new TMySQLRow:aOriValue
  Store originals values of aRow, during creation of TMySQLRow object
  Have same function of TMySQLTable:aOldValue

- TMySQLRow:New()
  Assign an copy of TMySQLRow:aRow in TMySQLRow:aOriValue

- TMySQLRow:FielPut()
  Compare ::aRow[nNum]==NIL in place of Empty(::aRow[nNum])
  Empty() can be an null string, value 0, null date, value .F.

- TMySQLRow:FieldPos()
  Reduction of code with same functionality for calculate nPos

- TMySQLRow:FieldLen()
  Return 0 in place of null string as exception value

- TMySQLRow:FieldDec()
  Return 0 in place of null string as exception value


Class TMySQLQuery -------------------------------------------
- DATA new TMySQLQuery:lBof
  Change in application of TMySQLQuery:Bof()

- DATA new TMySQLQuery:lEof
  Change in application of TMySQLQuery:Eof()

- DATA new TMySQLQuery:lFieldAsData
  Is applied for compatibility
  Use field names as DATA elements of TMySQLQuery
  Field names can match with DATA names in TMySQLQuery or
  TMySQLTable, which can substitute values and confuse operations and behaviour
  of classes
  Using TMySQLQuery:lFieldAsData := .F. can avoid this trouble

- DATA new TMySQLQuery:aRow
  Used to store fields values of current row, in
  place of fields names as DATA elements of TMySQLQuery
  All operations on fields are made using this array of values

- Method TMySQLQuery:Bof()
  Change in definition to reproduce Clipper behaviour
  BOF() true is applied when is tryed an movement before of first logical record,
  and must not be used to indicate record pointer is placed on record 1
  Previous definition cause processes like this:
     WHILE ! oQuery:BOF()
       ...
       oQuery:SKIP(-1)
     ENDD
  do not show record 1
  With new definition this behaviour are corrected

- Method TMySQLQuery:Eof()
  Change in definition to reproduce Clipper behaviour
  EOF() true is applied when is tryed an movement beyond of last logical record,
  and must not be used to indicate record pointer is placed on last record
  Previous definition cause processes like this:
     WHILE ! oQuery:EOF()
       ...
       oQuery:SKIP()
     ENDD
  do not show last record
  With new definition this behaviour are corrected
  With EOF() true, record pointer is placed in LASTREC()+1

- TMySQLQuery:New()
  Application of TMySQLQuery:lBof, TMySQLQuery:lEof, TMySQLQuery:lFieldAsData,
  TMySQLQuery:aRow

- TMySQLQuery:Skip()
  Application of TMySQLQuery:lBof, TMySQLQuery:lEof to determinate movements
  before of first and beyond of last logical records
  Only SKIP movement can set BOF() true

- TMySQLQuery:Skip()
  Apply NIL for return.  DBSKIP() return NIL

- TMySQLQuery:GetRow()
  Application of TMySQLQuery:lBof, TMySQLQuery:lEof, TMySQLQuery:lFieldAsData,
  TMySQLQuery:aRow
  = TMySQLQuery:aRow is used in place of local variable aRow
  = Default row is applied to TMySQLQuery:nCurRow, in place to move record pointer 
  position
  = TMySQLQuery:lBof, TMySQLQuery:lEof are determinated
    TMySQLQuery:bof(): pointer is placed in row 1
    TMySQLQuery:eof(): pointer is placed in TMySQLQuery:lastrec()+1
  = In TMySQLQuery:lastrec()+1 phantom record is used with null values in each
    field type

- TMySQLQuery:GetRow()
  = Correction of error caused for data type in logical and numerics types
  = Supresion of messages with Alert() and MsgInfo() which cause halting in batch processes

- TMySQLQuery:FieldPos()
  Reduction of code with same functionality for calculate nPos

- TMySQLQuery:FieldGet()
  = TMySQLQuery:aRow[nNum] is used in place of DATA variable corresponding to
  field name

- TMySQLQuery:FieldLen()
  Return 0 in place of null string as exception value

- TMySQLQuery:FieldDec()
  Return 0 in place of null string as exception value


Class TMySQLTable -------------------------------------------
- Method TMySQLTable:Update()
  = Parameters added:
  + lOldRecord: Use original values of record for locate it
  + lRefresh: refresh query to MySQL server to update information 
  selected for Client program

- Method TMySQLTable:Delete()
  = Parameters added:
  + lOldRecord: Use original values of record for locate it
  + lRefresh: refresh query to MySQL server to update information 
  selected for Client program

- Method TMySQLTable:Append()
  = Parameters added:
  + lRefresh: refresh query to MySQL server to update information 
  selected for Client program

- Method TMySQLTable:GetBlankRow()
  = Parameters added:
  + lSetValues: apply values as if they belong to current row

- New Method TMySQLTable:SetBlankRow()
  Apply TMySQLTable:GetBlankRow( .T. ), with true value for lSetValues

- TMySQLTable:Skip()
  Apply NIL for return.  DBSKIP() return NIL

- TMySQLTable:Update(oRow, lOldRecord, lRefresh)
  = Application of TMySQLRow:aOriValue, TMySQLTable:aRow
  = Application of parameters:
  + lOldRecord, default .F.
    In case of lOldRecord application:
    * Using current row: Use values of TMySQLQuery:aOldValue
    * Using given row: Use values of TMySQLRow:aOriValue
    Locating is based in matching of values of ALL fields, 
    using original values of row
    WARNING: If there are more than one row matching in ALL fields, then
    all this rows with common values will be changed

    This approach is applied to help in row locating when there are not indexes, 
    or primary key are not enought to determinate record unicity. 
    But, can not be guaranted record correspondence if there are many equals
    This is an alternative to use of TMySQLRow/TMySQLTable:MakePrimaryKeyWhere(), because
    this last is based in fields belonging to an primary key

  + lRefresh, default .T.
    Refresh query to MySQL server to update information selected for Client program
    Is very convenient in case of information changes

  = Same record pointer is keep
  
  = For an given row, TMySQLRow:aOriValue is updated with current values of
  TMySQLRow:aRow

- TMySQLTable:Delete(oRow, lOldRecord, lRefresh)
  = Application of TMySQLRow:aOriValue, TMySQLTable:aRow
  = Application of parameters:
  + lOldRecord, default .F.
    In case of lOldRecord application:
    * Using current row: Use values of TMySQLQuery:aOldValue
    * Using given row: Use values of TMySQLRow:aOriValue
    Locating is based in matching of values of ALL fields, 
    using original values of row
    WARNING: If there are more than one row matching in ALL fields, then
    all this rows with common values will be changed

    This approach is applied to help in row locating when there are not indexes, 
    or primary key are not enought to determinate record unicity. 
    But, can not be guaranted record correspondence if there are many equals
    This is an alternative to use of TMySQLRow/TMySQLTable:MakePrimaryKeyWhere(), because
    this last is based in fields belonging to an primary key

  + lRefresh, default .T.
    Refresh query to MySQL server to update information selected for Client program
    Is very convenient in case of information changes

  = Same record pointer is keep
  
  = For an given row, TMySQLRow:aOriValue is updated with current values of
  TMySQLRow:aRow

- Metodo TMySQLTable:Append(oRow, lRefresh)
  = Application of TMySQLRow:aOriValue, TMySQLTable:aRow
  = Application of parameters:
  + lRefresh, default .T.
    Refresh query to MySQL server to update information selected for Client program
    Is very convenient in case of information changes

  = Record pointer is placed in TMySQLTable:lastrec()+1, before query refresh
    Observation: even with many tests, I was unable to determinate in which way
    set MySQL server position of inserted row. Without indexes, in times
    were inserted behind to current pointer, while in other times
    were inserted in positions located at 1200 or 1300 rows relative to current pointer,
    or at end of table (around 2880 rows)

  = For an given row, TMySQLRow:aOriValue is updated with current values of
  TMySQLRow:aRow
  Too, TMySQLRow:aDirty and TMySQLRow:aOldValue are reseted


- TMySQLTable:GetBlankRow(lSetValues)
  = Application of parameters:
  + lSetValues, default .F.
  This method give an TMySQLRow object with default values for data type in each field
  As created row IS NOT current row of TMySQLTable object,
  then must not be modified values of TMySQLTable:aRow and TMySQLTable:aOldValue
  In case of need to make this modification, as if empty file is wanted current row of
  table, then this parameter can be applied with true value
  or with new method TMySQLTable:SetBlankRow()

- TMySQLTable:FielPut()
  = Comparar ::aRow[nNum]==NIL en vez de Empty(::aRow[nNum])
  Compare ::aRow[nNum]==NIL in place of Empty(::aRow[nNum])
  Empty() can be an null string, value 0, empty date, value .F.
  = TMySQLTable:aRow[nNum] is applied to store field value
  = Based in TMySQLTable:lFieldAsData, is updated DATA element of TMySQLTable
  corresponding to field name


Program TSqlBrw.prg ************************************

- Skipper()
  Modification of movement control in order to apply new definitions of 
  TMySQLQuery:Bof() and TMySQLQuery:Eof()

