Files
harbour-core/harbour/contrib/rddsql
Viktor Szakats ff5a1d161b 2010-07-31 13:44 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* contrib/make.hbs
    % Code consolidation.
    ! Fixed recent regression, whereas now again the root project's
      .hbc file will be added to the make process in HB_BUILD_CONTRIB_DYN
      mode.
    + Changed the way filter is processed, now dependent packages will
      always be built, so there is no need to manually pick all the
      dependencies too.
    * Internal terminology cleanup.
    + Will now also rebuild the _dependencies_ in HB_BUILD_CONTRIB_DYN mode.
    - Deleted forcing English language for hbmk2 output.
    ; Regressions are possible
    ; NOTE: This dynamic stuff is a real can of worms. Virtually infinite
            combinations of dynamic vs static libs may be supported, plus
            there is ST vs MT issue, where we must decide about this at
            dynlib build time, and f.e. what happens when trying to load
            two .dlls one with was linked against MT Harbour and the other
            against ST? It's a combinatorical explosion.

  * src/vm/vmmt/Makefile
    ! Fixed missing procaddr.c causing unresolved externals when creating
      MT mode dynlibs.

  * config/global.mk
    ! Attempt to fix LD_LIBRARY_PATH problem, adding dynamic lib build
      dir to this envvar while doing the build, pls test it, I didn't.

  + contrib/hbplist
  - contrib/pkglist
    * Renamed.

  * contrib/hbct/ctwin.h
    ! Added missing HB_EXPORT.

  * contrib/xhb/xhb.hbp
  * contrib/hbgd/hbgd.hbp
    ! Added missing project references also to .hbp files.

  * utils/hbmk2/hbmk2.prg
    ! Fixed regression with mingw -hbdyn after adding new stub which
      stole the show by explicitly exporting one symbol which (due
      to autoexport function in mingw) prevented regular symbols to
      be exported. This fix will remove the exception so far applied
      to mingw/cygwin compilers where HB_DYNLIB was not used with these,
      now it's used equally on all compilers/platforms. For this to
      be effective, it should be noted that HB_EXPORT must be used
      in all public declarations, even in contrib.
    ! Fix (?) to not include MAIN proc force code when building with
      hbmaindllp.

  * contrib/xhb/thtm.prg
    % Changed hbct LTOC to simple iif()
    ; TOFIX: xhb makes reference to (deprecated) hb_symEval symbol:
             Info: resolving _hb_symEval by linking to __imp__hb_symEval (auto-import)

  * contrib/rddsql/hbrddsql.h
    ! Added HB_EXTERN_BEGIN/END
    ! Added HB_EXPORT
    ! Added extern

  * contrib/sddoci/sddoci.hbp
    ! Restored some flags present in old Makefile to make it
      work with mingw and bcc.

  * contrib/hbqt/generator/hbqtgen.prg
  * contrib/hbqt/hbqt.h
    ! Fixed to add HB_EXPORT to public declarations.
    ; TOFIX: hbqt still doesn't link in hbdyn mode.

  * contrib/hbqt/hbqt_garbage.h
  * contrib/hbqt/doc/en/*.txt
    * Regenerated.

  * contrib/hbqt/hbqt.hbc
    ! Fixed to not include QtUiTools in -hbdyn mode. It creates duplicate
      symbols at link. Maybe this is not the right fix, go figure.
      (HB_STATIC_QT mode still has to be checked)

  ; TODO: Add ${__HB_DYN__} to all .hbc files.
2010-07-31 11:51:37 +00:00
..

/*
 * $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.