Clase Nativa MySql

Clase Nativa MySql

Postby cmsoft » Wed Mar 09, 2022 3: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
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby carlos vargas » Wed Mar 09, 2022 5: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)
User avatar
carlos vargas
 
Posts: 1721
Joined: Tue Oct 11, 2005 5:01 pm
Location: Nicaragua

Re: Clase Nativa MySql

Postby cmsoft » Wed Mar 09, 2022 5:45 pm

Muchas gracias por la info Carlos.
esos metodos no existenten.

Existen algunos similares?
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby nageswaragunupudi » Wed Mar 09, 2022 5:49 pm

Instead of GetRowObj(), use
Code: Select all  Expand view  RUN

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: Select all  Expand view  RUN

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: Select all  Expand view  RUN

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
User avatar
nageswaragunupudi
 
Posts: 10663
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Clase Nativa MySql

Postby cmsoft » Wed Mar 09, 2022 7:51 pm

Excelente Mr. Rao!
Voy entendiendo la lógica.
El GetAutoIncrement(cTable) lo reemplace por una funcion propia simple:
Code: Select all  Expand view  RUN
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: Select all  Expand view  RUN

oRec := oQry:Record(.t.)
oRec:ciudad := "Mercedes (B)"
 

Esto no funciona:
Code: Select all  Expand view  RUN

oRec := oQry:Record(.t.)
oRec:codigo :=  GetAutoIncrement("ciudades","codigo") // Campo codigo es autoincremental
 

Me da el siguiente error
Code: Select all  Expand view  RUN
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!
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby nageswaragunupudi » Fri Mar 11, 2022 3: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: Select all  Expand view  RUN

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: Select all  Expand view  RUN

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: Select all  Expand view  RUN

INSERT INTO table (ID,FLD1,FLD2) VALUES ( 3, 'CC','CCCC' )
 

Just a split second before, User-B inserts his new data with
Code: Select all  Expand view  RUN

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
User avatar
nageswaragunupudi
 
Posts: 10663
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Clase Nativa MySql

Postby cmsoft » 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: Select all  Expand view  RUN

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
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby nageswaragunupudi » Wed Mar 16, 2022 3:37 am

cmsoft wrote:Igualmente, siguiendo su ejemplo, el error se puede capturar con un TRY CATCH e indicárselo al usuario:
Code: Select all  Expand view  RUN

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: Select all  Expand view  RUN
if oRs:Save()
   // Success
   // appropriate code
else
   // failure
   oCn:ShowError() // optional
   // suitable action on failure
endif
 


OR

Code: Select all  Expand view  RUN
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: Select all  Expand view  RUN
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
User avatar
nageswaragunupudi
 
Posts: 10663
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Clase Nativa MySql

Postby cmsoft » 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: Select all  Expand view  RUN

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: Select all  Expand view  RUN

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?
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby nageswaragunupudi » Thu Mar 17, 2022 4: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: Select all  Expand view  RUN

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: Select all  Expand view  RUN

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: Select all  Expand view  RUN

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
User avatar
nageswaragunupudi
 
Posts: 10663
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Clase Nativa MySql

Postby cmsoft » Thu Mar 17, 2022 3: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)
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby nageswaragunupudi » Thu Mar 17, 2022 5:00 pm

Then, your present TRY/CATCH constructs should continue to work, when enclosed between oCn:lThrowError := .t. and .f. like this.
Code: Select all  Expand view  RUN
oCn:lThrowError := .t.
YOUR PRESENT TRY/CATCH CODE
oCn:lThrowError := .f.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10663
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Clase Nativa MySql

Postby cmsoft » Thu Mar 17, 2022 6:00 pm

Excelente Mr. Rao... Eso me evita bastante cambios en mis codigos existentes...
Muchas gracias!
User avatar
cmsoft
 
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Clase Nativa MySql

Postby carlos vargas » Fri Jul 15, 2022 12:30 am

esto no esta funcionando, no revienta el error en el catch... (maria16.prg modificado)

Code: Select all  Expand view  RUN
// 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)
User avatar
carlos vargas
 
Posts: 1721
Joined: Tue Oct 11, 2005 5:01 pm
Location: Nicaragua

Re: Clase Nativa MySql

Postby carlos vargas » 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)
User avatar
carlos vargas
 
Posts: 1721
Joined: Tue Oct 11, 2005 5:01 pm
Location: Nicaragua

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 37 guests