SQL Scripting Support: Less known features of FWH - 3

SQL Scripting Support: Less known features of FWH - 3

Postby nageswaragunupudi » Wed Jul 31, 2013 3:58 am

Many of us are moving to use SQL databases with (x)Harbour and FWH. Whether we use ADO or DBMS specific libraries like TDolphin, TMySql, TSqlite, etc., we can not totally avoid writing SQL statements.

Unfortunately, different DBMSs implement different syntax and when we develop cross-platform application we need to write different SQL statements for differnet DBMSs.

Most common are INSERT and UPDATE statements. It is not uncommon to see postings from new entrants asking how to format numerics, dates, etc to be used in such statements.

Let us consider the simplest case of INSERT statement.

We have data in the Harbour vaiables, cCustomer, cStreet, dInvDate, nInvNo, tDeliveryTime, nQty, nAmount.
We want to insert a row, assigning these values to fields CUSTOMER, STREET, INVDATE, INVNO, DELYTIME, QTY and AMOUNT into SUPPLIES table

We would be very happy to write a statement a like this, if allowed:
Code: Select all  Expand view

INSERT INTO SUPPLIES ( CUSTOMER,STREET,INVDATE,INVNO,DELYTIME,QTY,AMOUNT ) ;
  VALUES ( cCustomer, cStreet, dInvDate, nInvNo, tDeliveryTime, nQty, nAmount )
 

But we know this is not permitted. We need to convert all values into literals that the DBMS can understand.
So, we proceed like this:

cSql := "INSERT INTO SUPPLIES ( CUSTOMER,STREET,INVDATE,INVNO,DELYTIME,QTY,AMOUNT ) VALUES ( " + ;
"'" + cCustomer + "','" + cStreet + "'.'" + Str(Year(dInvDate,4) + etc, etc, etc
and finally produce a statement like this

INSERT INTO SUPPLIES ( CUSTOMER,STREET,INVDATE,INVNO,DELYTIME,QTY,AMOUNT ) ;
VALUES ( 'Anthony', 'Barry's Street', '2013-07-05', 2034, '2013-07-03T15:20:35', 234.567, 10257.89 )

Even this is quite tedious.

This again has error because single quote is not escaped. We change 'Barry's Stret' as 'Barry''s Street' and then this works on MSSQL server.
Now this statement does not work on MySql. Oracle. etc.
We need to code the statement separately for other DBMSs in a conditional if else endif block.

Support provided by FWH:

FWH provides commands which allow us to write the code as we like to using Harbour variables. Please see the first code snippet.
These commands are provided in \fwh\include\fwsqlcmd.ch, which in turn is included in \fwh\include\adodef.ch and ado.ch.

So, we can write code like this:
Code: Select all  Expand view

#include "fivewin.ch"
#include "adodef.ch"

function Main()

   local oCn, cSql

   oCn   := FW_OpenAdoConnection( "xbrtest.mdb" )

   cSql  := SQL INSERT INTO SUPPLIES ( CUSTOMER,STREET,INVDATE,INVNO,DELYTIME,QTY,AMOUNT ) ;
            VALUES ( cCustomer, cStreet, dInvDate, nInvNo, tDeliveryTime, nQty, nAmount )
   ? cSql
   // oCn:Execute( cSql )
   oCn:Close()

return nil
 


When we connect to MSACCESS, this is the SQL statement generated by the command
// MSACCESS
INSERT INTO SUPPLIES ( [CUSTOMER],[STREET],[INVDATE],[INVNO],[DELYTIME],[QTY],[AMOUNT] )
VALUES
( 'Anthony','Barry''s Street','2013-07-05',2034,'2013-07-03 15:20:55',234.567,10257.89 )

Instead of connecting to access table, if we connect to a different DBMS, the same
statement produces different appropriate SQL statements as below:


// MYSQL
INSERT INTO SUPPLIES ( `CUSTOMER`,`STREET`,`INVDATE`,`INVNO`,`DELYTIME`,`QTY`,`AMOUNT` )
VALUES
( 'Anthony','Barry''s Street','2013-07-05',2034,'2013-07-03 15:20:55',234.567,10257.89 )

// ORACLE
INSERT INTO SUPPLIES ( CUSTOMER,STREET,INVDATE,INVNO, )
VALUES
( 'Anthony','Barry''s Street',DATE '2013-07-05',2034,TIMESTAMP '2013-07-03 15:20:55',234.567,10257.89 )


Similary a command for UPDATE also is provided: This time we check with binary data, like a photo/bmp.

Code: Select all  Expand view

#include "fivewin.ch"
#include "adodef.ch"

function Main()

   local oCn, cSql

   oCn   := FW_OpenAdoConnection( "xbrtest.mdb" )
// oCn   := FW_OpenAdoConnection( "test,db" )

   cSql  := SQL UPDATE PIX SET EMPNAME = "James", FOTO = MemoRead( "c:\fwh\bitmaps\check.bmp" ) ;
            WHERE ID = 99

   ? cSql
// oCn:Execute( cSql )
   oCn:Close()

return nil
 



// MSACCESS
UPDATE PIX SET [EMPNAME] = 'James',
[FOTO] = 0x424D160< ..other bytes...>F8F8F8
WHERE ID = 99

Now, we shall connect to SQLITE database, instead of ACCESS and see the result for the same code.

// SQLITE
UPDATE PIX SET "EMPNAME" = 'James',"
FOTO" = x'424D160<...other bytes...>F8F8F8'
WHERE ID = 99

This SQL works with SQLITE.
You can see the difference in formatting of binary data between Access and SqLite.

Using these commands for writing INSERT and UPDATE SQL statements has the advantages:

1) We can write the statement using (x)Harbour variables and expressions, the way we understand.
We need not take trouble to construct literal text for different kind of variables.

2) We need not prepare different statements for different DBMS.
Regards

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

Re: SQL Scripting Support: Less known features of FWH - 3

Postby elvira » Wed Jul 31, 2013 8:35 am

Great!!.

Thank you Mr. Rao for helping us with the change to ADO.
elvira
 
Posts: 516
Joined: Fri Jun 29, 2012 12:49 pm

Re: SQL Scripting Support: Less known features of FWH - 3

Postby devtuxtla » Wed Jul 31, 2013 9:18 pm

Hi Mr. Rao

Excellent solution.

You could add the behavior that SQLRDD for logically deleted records?

SQLRDD adds a field called sr_deleted which controls the records to be deleted or retrieved in a SELECT statement

sr_deleted = "T" when records are deleted, this has allowed the compatibly with DBFCDX in has been very useful.

thanks
Visite Chiapas, el paraiso de México.
devtuxtla
 
Posts: 392
Joined: Tue Jul 29, 2008 1:55 pm

Re: SQL Scripting Support: Less known features of FWH - 3

Postby elvira » Thu Aug 01, 2013 8:48 am

Hello devtuxtla,

I don´t see the point in your feature.

In ADO, when you delete a record, it is physically deleted.

Please, see samples\adoxb.prg and class TDataRow().

SQLRDD also caused me too much trouble. In addition, their indexes are too slow. Using oRs:Sort or select ... order by is very very fast.

Best regards
elvira
 
Posts: 516
Joined: Fri Jun 29, 2012 12:49 pm

Re: SQL Scripting Support: Less known features of FWH - 3

Postby devtuxtla » Sun Aug 04, 2013 5:05 am

Hi Elvira.

Thanks for your comments. However, our applications requieres that records are NOT physically erased, as the driver DBFCDX do.

For audit purposes, we want to know what happened with the information, although this has been deleted.

For this reason I ask, if this functionality can not be added to the utility with ADO, making compatible with SQLRDD behavior.

regards
Visite Chiapas, el paraiso de México.
devtuxtla
 
Posts: 392
Joined: Tue Jul 29, 2008 1:55 pm

Re: SQL Scripting Support: Less known features of FWH - 3

Postby nageswaragunupudi » Sun Aug 04, 2013 5:59 am

devtuxtla wrote:Hi Elvira.

Thanks for your comments. However, our applications requieres that records are NOT physically erased, as the driver DBFCDX do.

For audit purposes, we want to know what happened with the information, although this has been deleted.

For this reason I ask, if this functionality can not be added to the utility with ADO, making compatible with SQLRDD behavior.

regards

This is to be implemented by the programmer. The FW Ado or Sql function have nothing to do with it.

We can have one more column say with name "DELETED" or similar. And in the program we mark this field .T. for deletion instead of calling oRs:Delete().

When we read we write SQL as "SELECT * FROM MYTABLE WHERE DELETED=0"

Generally Audit Trials are generated through Triggers in the SQL programming environment, capturing all modifications including deletions with Username and datetime.
Regards

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

Re: SQL Scripting Support: Less known features of FWH - 3

Postby nageswaragunupudi » Sat Feb 18, 2017 3:00 am

This is a 4 year old posting but is relevant even now.

In addition, now we can also use the function FW_AdoApplyParams( cSql, aParams )

Please note that we can use this function even if we are using TDolphin, TMySql or ADO (for any RDBMS). By default, this function uses MySql syntax. If we open any ado source using FW_OpenAdoConnection(), then this function uses syntax appropriate for that RDBMS.

Example:
Code: Select all  Expand view

   cSql  := "UPDATE `photos` SET `name` = ?, `photo` = ? WHERE `id` = ?"
//OR
   cSql  := "UPDATE `photos` SET `name` = &1, `photo` = &2 WHERE `id` = &3"
   cSql2 := FW_AdoApplyParams( cSql, { cName, MEMOREAD( cJpgFile ), 90 } )
   oCn:Execute( cSql2 )
 
Regards

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


Return to FiveWin for Harbour/xHarbour

Who is online

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