FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Clase Nativa MySql
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Clase Nativa MySql
Posted: Wed Mar 09, 2022 03:50 PM

Estimados:
Estoy tratando de migrar desde TDolphin a la clase nativa de MySql/MariaDB
Intento encontrar los m茅todos similares que utilizaba en TDolphin.
Los mismos son los siguientes:
GetRowObj() Para obtener un objeto copia el registro actual
GetBlankRow() Para obtener un objeto con los datos en blanco
GetAutoIncrement(cTable) Para obtener el pr贸ximo valor del autoincremental de una tabla
oRow para asignar un objeto obtenido previamente con GetRowObj al objeto oRs y luego hacer Save()

Otra consulta
La clase esta disponible en source\classes ? En caso de que no, donde puedo ver todos los metodos de la clase y sus variables?
Consulte este hilo viewtopic.php?f=3&t=32657&start=0 pero no se si est谩 todo lo que incluye la clase.
Agradecido de antemano

Posts: 1789
Joined: Tue Oct 11, 2005 05:01 PM
Re: Clase Nativa MySql
Posted: Wed Mar 09, 2022 05:03 PM
Los fuentes no son incluidos en source, la clase no puede heredar,
esos metodos no existenten.
la documentaci贸n esta aca

http://wiki.fivetechsoft.com/doku.php?id=fivewin_class_fwmariaconnection
http://wiki.fivetechsoft.com/doku.php?id=fivewin_class_fwmariarowset
Salu2

Carlos Vargas

Desde Managua, Nicaragua (CA)
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Clase Nativa MySql
Posted: Wed Mar 09, 2022 05:45 PM
Muchas gracias por la info Carlos.
esos metodos no existenten.

Existen algunos similares?
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
Re: Clase Nativa MySql
Posted: Wed Mar 09, 2022 05:49 PM
Instead of GetRowObj(), use
Code (fw): Select all Collapse
oRec := oQry:Record() // returns FW_Record/TDataRow Object

You may edit the oRec object using oRec:FieldName in the Gets,etc/

Instead of GetBlankRow(), use
Code (fw): Select all Collapse
oRec := oQry:Record( .t. ) // returns blank FW_Record/TDataRow objecct



oRow to assign a previously obtained object with GetRowObj to the oRs object and then Save()

This is not necessary.
After editing the existing or blank FW_Record objec, simple call
Code (fw): Select all Collapse
oRec:Save()

In case of existing records, the changes will be written to that record and in case of blank record, a new record will be appended to the rowset.

You can also use oRec:Edit()
or oQry:Edit()
or oQry:Edit( .t. )

Please try.
Regards



G. N. Rao.

Hyderabad, India
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Clase Nativa MySql
Posted: Wed Mar 09, 2022 07:51 PM
Excelente Mr. Rao!
Voy entendiendo la l贸gica.
El GetAutoIncrement(cTable) lo reemplace por una funcion propia simple:
Code (fw): Select all Collapse
FUNCTION GetAutoIncrement(cTable,cField)
RETURN oApp:oServer:QueryResult('SELECT MAX('+cField+') FROM ' + cTable) + 1

Pero no me lo deja asignar al campo
Esto funciona:
Code (fw): Select all Collapse
oRec := oQry:Record(.t.)
oRec:ciudad := "Mercedes (B)"

Esto no funciona:
Code (fw): Select all Collapse
oRec := oQry:Record(.t.)
oRec:codigo :=  GetAutoIncrement("ciudades","codigo") // Campo codigo es autoincremental

Me da el siguiente error
Code (fw): Select all Collapse
Error description: Error BASE/39  Escritura no autorizada: TDATAROW:codigo
   Args:
     [   1] = O   TDATAROW

Entiendo que debe ser porque el campo es autoincremental. Pero un registro nuevo igualmente puede tener un c贸digo libre, eso lo permite MySql.
Espero haber sido claro.
Muchas gracias por su tiempo!
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
Re: Clase Nativa MySql
Posted: Fri Mar 11, 2022 03:45 PM

Pero un registro nuevo igualmente puede tener un c贸digo libre, eso lo permite MySql.
Espero haber sido claro.
English:
But a new record can still have a free code, that is allowed by MySql. I hope I was clear.

Yes.
But this is a very unsafe practice for regular insertion of records.
We can use this feature in rate occasions like,
1) fill gaps in auto-inc values due to deletions
2) reseed the auto-increment value to a higher value. Even for this, it is more appropriate to use ALTER TABLE command than inserting a higher value.


El GetAutoIncrement(cTable) lo reemplace por una funcion propia simple:
Code (fw): Select all Collapse
FUNCTION GetAutoIncrement(cTable,cField)
RETURN oApp:oServer:QueryResult('SELECT MAX('+cField+') FROM ' + cTable) + 1



It is not as simple as that. Even MySql server does not know the next autoinc value, till the time it actually inserts the record in the table.
Between the moment server answers the query "SELECT MAX(fld) FROM table" and the time the new record is actually inserted, several other users might have already inserted several records and this insertion will result in an error.

Note: We are not discussing single user applications here.

Let us see this example. There is a small table with these records.
Code (fw): Select all Collapse
ID FLD1 FLD2
 1 AA   AAAA
 2 BB   BBBB

ID is the auto-increment primary field.

User-A and User-B (and may be more users) are running our application inserting new transactions.

Both users A and B (and also other users) will assume the next autoinc id will be 3, using the above function.
Mr. A is about to commit his new record with this sql statement
Code (fw): Select all Collapse
INSERT INTO table (ID,FLD1,FLD2) VALUES ( 3, 'CC','CCCC' )

Just a split second before, User-B inserts his new data with
Code (fw): Select all Collapse
INSERT INTO table (ID,FLD1,FLD2) VALUES ( 3, 'DD','DDDD' )

User-B's insertion will be successful.
But User-A's insertion fails with an error.

Note: The problem remains the same even if we read auto_increment value from the table_schema.

So, the safe practice as well as widely adopted practice is to insert the record without any value to auto-inc field and then get the LAST_INSERT_ID to inform the user.

By default, the RowSet class treats auto-increment field as read-only. TDatarow inherts the readonly attribute from the RowSet object.

In my next post I will explain how to over-ride this default behavior.
Regards



G. N. Rao.

Hyderabad, India
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Clase Nativa MySql
Posted: Mon Mar 14, 2022 11:02 AM
Muy clara su explicaci贸n Mr. Rao, y es as铆 como ud. lo indica.
Igualmente, siguiendo su ejemplo, el error se puede capturar con un TRY CATCH e indic谩rselo al usuario:
Code (fw): Select all Collapse
TRY
  oCn:BeginTransaction()
  oQry:Save()
  oCn:CommitTransaction()
CATCH oError
  MsgStop("Error al grabar"+CHR(10)+oError:description,"Error")
  oCn:RollBack()
END TRY

Esto est谩 bien?
De esta manera le puedo mostrar al usuario y dejarle elegir que id poner, y controlar por programa si el c贸digo ya existe.
Entiendo perfectamente que no es la mejor pr谩ctica, pero es v谩lida si se controla correctamente.
El problema me surge cuando las tablas ya est谩n definidas y son usadas por otros sistemas que no puedo modificar (comparto tablas entre sistemas web y mis aplicaciones).
En mi caso, ser铆a de mucha utilidad poder anular esa comportamiento por default
Desde ya muchas gracias
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
Re: Clase Nativa MySql
Posted: Wed Mar 16, 2022 03:37 AM
cmsoft wrote:
Igualmente, siguiendo su ejemplo, el error se puede capturar con un TRY CATCH e indic谩rselo al usuario:
Code (fw): Select all Collapse
TRY
聽 oCn:BeginTransaction()
聽 oQry:Save()
聽 oCn:CommitTransaction()
CATCH oError
聽 MsgStop("Error al grabar"+CHR(10)+oError:description,"Error")
聽 oCn:RollBack()
END TRY

Esto est谩 bien?


TRY/CATCH construct not only does not work but can be misleading too because the FWH lib does not raise Runtime Error for any MySql error.

oRs:Save() returns true/false for success/failure and the execution goes to the next line, i.e., commit transaction and oCn:RollBack() is never executed.

Also for saving to single table, transactions are not necessary.

Recommended:
Code (fw): Select all Collapse
if oRs:Save()
   // Success
   // appropriate code
else
   // failure
   oCn:ShowError() // optional
   // suitable action on failure
endif


OR

Code (fw): Select all Collapse
oCn:lShowErrors := .t.
if oRs:Save()
   // success
else
   // failure. Automatic error message
endif




We need to use Transactions when saving changes to two or more RowSets simultaneously. (i.e., either all should be saved or none):

Code (fw): Select all Collapse
oCn:lShowErrors := .t. // can be a global setting
oCn:BeginTransaction()
if oRs1:Save() .and. oRs2:Save() .and. ;
   oRs3:Save() .and. oRs4:Save()
   oCn:CommitTransaction()
else
   oCn:RollBack()
endif


Note: if one of the Save()s fails with an error, automatic error message is displayed and subsequent Save()s are not executed and RollBack() is executed.
Regards



G. N. Rao.

Hyderabad, India
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Clase Nativa MySql
Posted: Wed Mar 16, 2022 11:42 AM
Excelente su explicaci贸n Mr. Rao. Veo que la l贸gica de la librer铆a nativa es bastante diferente a la de la clase Dolphin. Es cuesti贸n de cambiar el modelo de programaci贸n.
El mismo criterio se aplicia a una instrucci贸n Execute?
Esto estar铆a mal:
Code (fw): Select all Collapse
TRY
聽 oCn:BeginTransaction()
聽 oCn:Execute(cSql1)
聽 oCn:Execute(cSql2)
聽 oCn:Execute(cSql3)
聽 oCn:CommitTransaction()
CATCH oError
聽 MsgStop("Error al grabar"+CHR(10)+oError:description,"Error")
聽 oCn:RollBack()
END TRY

Deber铆a ser as铆 ?
Code (fw): Select all Collapse
oCn:lShowErrors := .t. // can be a global setting
oCn:BeginTransaction()
if oCn:Execute(cSql1) .and. oCn:Execute(cSql2) .and. ;
聽 聽oCn:Execute(cSql3)
聽 聽oCn:CommitTransaction()
else
聽 聽oCn:RollBack()
endif

Quiero ir entendiendo la l贸gica, por eso la consulta...

Editado
Veo que execute devuelve :
a) nulo si no hay resultado o si ocurri贸 un error.
En caso de error, oCn:nError y oCn:cError proporcionan la informaci贸n del error.
Opcionalmente, configurar lShowError muestra el error o el resultado de la instrucci贸n sql,
b) Num茅rico: en caso de inserci贸n, actualizaci贸n, etc., indicando las filas afectadas
c) Si el resultado es un conjunto de resultados, se devuelve como matriz Multi-Dim
Como recomienda que deber铆a ser el proceso indicado?
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
Re: Clase Nativa MySql
Posted: Thu Mar 17, 2022 04:56 AM
Execute(...) method does not return true or false.
Execute( "SELECT ... " ) returns an array of selected values.
Execute( "UPDATE .." OR "INSERT..." ) returns number of records affected.
Only test: if oCn:nError == 0; success; else; fail; endif

Now, different ways:

Sample - 1:
Code (fw): Select all Collapse
oCn:lShowErrors := .t. // global setting

oCn:BeginTransaction()
lSuccess := .t.
for each cSql in { cSql1, cSql2, ... cSqlN }
聽 聽oCn:Execute( cSql )
聽 聽if oCn:nError != 0
聽 聽 聽 lSucess := .f.
聽 聽 聽 EXIT
聽 聽endif
next
if lSuccess
聽 聽oCn:CommitTransaction()
else
聽 聽oCn:RollBack()
endif


Sample - 2:
Code (fw): Select all Collapse
oCn:lShowErrors := .t. // global setting

TRY
聽 聽oCn:BeginTransaction()
聽 聽for each cSql in { cSql1, cSql2, ... cSqlN }
聽 聽 聽 oCn:Execute( cSql )
聽 聽 聽 if oCn:nError != 0
聽 聽 聽 聽 聽THROW()
聽 聽 聽 endif
聽 聽next
聽 聽oCn:CommitTransaction()
CATCH
聽 聽oCn:RollBack()
END


Sample - 3:
FWH 21.11 onwards only:
If the flag oCn:lThrowError (default .F.) is set to .T., method Execute() raises Run-time error, in case of any server error. We request to use this flag only locally when using transactions.
Code (fw): Select all Collapse
oCn:lShowErrors := .t. // global setting
oCn:lThrowError := .t. // local setting
TRY
聽 聽oCn:BeginTransaction()
聽 聽for each cSql in { cSql1, cSql2, ... cSqlN }
聽 聽 聽 oCn:Execute( cSql )
聽 聽next
聽 聽oCn:CommitTransaction()
CATCH
聽 聽oCn:RollBack()
END
oCn:lThrowError := .f.


May I know your FWH version?
Regards



G. N. Rao.

Hyderabad, India
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Clase Nativa MySql
Posted: Thu Mar 17, 2022 03:14 PM

Muchas gracias Mr. Rao.
Mi version la acabo de actualizar la semana pasada por la ultima
Compiler version: Harbour 3.2.0dev (r2008190002)
FiveWin version: FWH 21.11
C compiler version: Borland/Embarcadero C++ 7.0 (32-bit)

Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
Re: Clase Nativa MySql
Posted: Thu Mar 17, 2022 05:00 PM
Then, your present TRY/CATCH constructs should continue to work, when enclosed between oCn:lThrowError := .t. and .f. like this.
Code (fw): Select all Collapse
oCn:lThrowError := .t.
YOUR PRESENT TRY/CATCH CODE
oCn:lThrowError := .f.
Regards



G. N. Rao.

Hyderabad, India
Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Clase Nativa MySql
Posted: Thu Mar 17, 2022 06:00 PM

Excelente Mr. Rao... Eso me evita bastante cambios en mis codigos existentes...
Muchas gracias!

Posts: 1789
Joined: Tue Oct 11, 2005 05:01 PM
Re: Clase Nativa MySql
Posted: Fri Jul 15, 2022 12:30 AM
esto no esta funcionando, no revienta el error en el catch... (maria16.prg modificado)

Code (fw): Select all Collapse
// parent and 2 childs

#include "fivewin.ch"

function Main()

聽 聽local oCn, o
聽 聽local oRsState, oRsCity, oRsCust
聽 聽local oBrwState, oBrwCity, oBrwCust
聽 聽local oDlg, oFont

聽 聽oCn 聽 := FW_DemoDB()
聽 聽//oCn:lShowErrors 聽 := .t.
聽 聽
聽 聽MsgRun( "Reading tables", "Please Wait...", ;
聽 聽<||
聽 聽 聽 oCn:lThrowError := .t.
聽 聽 聽 try
聽 聽 聽 聽 oRsState := oCn:RowSet( "SELECT * FROM states ORDER BY name" )
聽 聽 聽 聽 oRsCity 聽:= oCn:RowSet( "SELECT id, state, city FROM customer ORDER BY state, city" ) //es customers
聽 聽 聽 聽 oRsCust 聽:= oCn:RowSet( "SELECT id, state, CONCAT_WS( ', ', first, last ) AS Name FROM customers ORDER by state,Name" )
聽 聽 聽 catch o
聽 聽 聽 聽 聽?o:Description
聽 聽 聽 聽 聽return nil
聽 聽 聽 end
聽 聽 聽 oCn:lThrowError := .f.
聽 聽 聽 oRsCity:SetFilter( "STATE = ?", { oRsState:code } )
聽 聽 聽 oRsCust:SetFilter( "STATE = ?", { oRsState:code } ) 聽 聽 聽
聽 聽 聽 return nil
聽 聽> )

聽 聽DEFINE FONT oFont NAME "Segoe UI" SIZE 0,-10 PTS
聽 聽DEFINE DIALOG oDlg SIZE 700,600 PIXEL TRUEPIXEL FONT oFont ;
聽 聽 聽 TITLE "MARIADB - PARENT WITH TWO CHILD TABLES"
聽 聽RELEASE FONT oFont

聽 聽@ 20,20 XBROWSE oBrwState SIZE 300,-20 PIXEL OF oDlg DATASOURCE oRsState ;
聽 聽 聽 COLUMNS "NAME","CODE" CELL LINES NOBORDER

聽 聽WITH OBJECT oBrwState
聽 聽 聽 :SetGroupHeader( "PARENT", 1, 2 )
聽 聽 聽 :nStretchCol 聽 := 1
聽 聽 聽 :lHScroll 聽 聽 聽:= .f.
聽 聽 聽 :bChange 聽 聽 聽 := <||
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 oRsCity:ReFilter( { oRsState:code } )
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 oRsCust:ReFilter( { oRsState:code } )
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 oBrwCity:Refresh()
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 oBrwCust:Refresh()
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 return nil
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 >
聽 聽 聽 :CreateFromCode()
聽 聽END

聽 聽@ 20,300 XBROWSE oBrwCity SIZE 400,260 PIXEL OF oDlg DATASOURCE oRsCity ;
聽 聽 聽 COLUMNS "STATE","CITY" CELL LINES NOBORDER

聽 聽WITH OBJECT oBrwCity
聽 聽 聽 :SetGroupHeader( "CHILD-1", 1, 2 )
聽 聽 聽 :nStretchCol 聽 := 2
聽 聽 聽 :lHScroll 聽 聽 聽:= .f.
聽 聽 聽 :CreateFromCode()
聽 聽END

聽 聽@ 280,300 XBROWSE oBrwCust SIZE 400,-20 PIXEL OF oDlg DATASOURCE oRsCust ;
聽 聽 聽 COLUMNS "STATE","NAME" CELL LINES NOBORDER

聽 聽WITH OBJECT oBrwCust
聽 聽 聽 :SetGroupHeader( "CHILD-2", 1, 2 )
聽 聽 聽 :nStretchCol 聽 := 2
聽 聽 聽 :lHScroll 聽 聽 聽:= .f.
聽 聽 聽 :CreateFromCode()
聽 聽END

聽 聽ACTIVATE DIALOG oDlg CENTERED
聽 聽oCn:Close()

return nil
Salu2

Carlos Vargas

Desde Managua, Nicaragua (CA)
Posts: 1789
Joined: Tue Oct 11, 2005 05:01 PM
Re: Clase Nativa MySql
Posted: Fri Jul 15, 2022 12:39 AM

Rao, es necesario implementarlo en los RowSet, Query, por ejemplo usar el ejemplo maria16.prg original, y da error en el oRsCity:setfilter dado que oRsCity es nil, ya que fallo el RecSet.

Salu2

Carlos Vargas

Desde Managua, Nicaragua (CA)