Files
harbour-core/harbour/contrib/hbpgsql/tests/cache.prg
Viktor Szakats b937df971b 2009-03-25 14:09 UTC+0100 Viktor Szakats (harbour.01 syenar hu)
* INSTALL
    + Added HB_INC_SQLITE3

  * include/hbapi.h
    + Added HB_IS*() flavour of classic Clipper compatibility IS*()
      macros. I'd recommend everyone to start using these new ones,
      as the old ones might be deprecated in future versions.

  * Makefile
    + Added new 'external' dir to host foreign, non-Harbour code.

  + external
  + external/sqlite3
  + external/sqlite3/_sqlite3.c
  + external/sqlite3/sqlite3.c
  + external/sqlite3/sqlite3.h
  + external/sqlite3/Makefile
  - contrib/hbsqlit3/sqlite3
    + Moved sqlite3 code into its dedicated place.

  * contrib/hbsqlit3/tests/hbsqlit3.hbp
    + Added sqlite3 to liblist.

  * contrib/hbsqlit3/hbsqlit3.c
  * contrib/hbsqlit3/Makefile
    + Changed to use external headers just like other external
      dependent libs. The only difference here is that it will
      pickup the locally hosted sqlite3 source from
      external/sqlite3 if not specified by user.
    * Changed to no embed sqlite3 code anymore.
      ATTENTION: This also means that hbsqlit3 users will now
                 have to add sqlite3 lib to their liblist, since
                 this code isn't anymore embedded into hbsqlit3.

  * contrib/hbqt/hbqt_qfontcombobox.cpp
  * contrib/hbqt/hbqt_qgroupbox.cpp
  * contrib/hbqt/hbqt_qcombobox.cpp
  * contrib/hbqt/hbqt_qtoolbutton.cpp
  * contrib/hbqt/slots.h
  * contrib/hbqt/hbqt_qpushbutton.cpp
  * contrib/hbqt/hbqt_qpagesetupdialog.cpp
  * contrib/hbqt/hbqt_qprintpreviewdialog.cpp
  * contrib/hbqt/hbqt_qlabel.cpp
  * contrib/hbqt/hbqt_qinputdialog.cpp
  * contrib/hbqt/hbqt_qprogressdialog.cpp
  * contrib/hbqt/hbqt_qtoolbox.cpp
  * contrib/hbqt/hbqt_qcommandlinkbutton.cpp
  * contrib/hbqt/hbqt_qmenubar.cpp
  * contrib/hbqt/hbqt_qhboxlayout.cpp
  * contrib/hbqt/hbqt_qabstractbutton.cpp
  * contrib/hbqt/hbqt_qabstractprintdialog.cpp
  * contrib/hbqt/hbqt_qwizard.cpp
  * contrib/hbqt/hbqt_qabstractspinbox.cpp
  * contrib/hbqt/hbqt_qfont.cpp
  * contrib/hbqt/hbqt_qdial.cpp
  * contrib/hbqt/hbqt_qtablewidgetitem.cpp
  * contrib/hbqt/hbqt_qlcdnumber.cpp
  * contrib/hbqt/hbqt_qmainwindow.cpp
  * contrib/hbqt/hbqt_qprintdialog.cpp
  * contrib/hbqt/hbqt_qcalendarwidget.cpp
  * contrib/hbqt/hbqt_qabstractitemview.cpp
  * contrib/hbqt/hbqt_qaction.cpp
  * contrib/hbqt/hbqt_qspinbox.cpp
  * contrib/hbqt/hbqt_qwidget.cpp
  * contrib/hbqt/hbqt_slots.cpp
  * contrib/hbqt/hbqt_qdateedit.cpp
  * contrib/hbqt/hbqt_qcheckbox.cpp
  * contrib/hbqt/hbqt_qprogressbar.cpp
  * contrib/hbqt/hbqt_qframe.cpp
  * contrib/hbqt/hbqt_qfocusframe.cpp
  * contrib/hbqt/hbqt_qtabbar.cpp
  * contrib/hbqt/hbqt_qcqlendarwidget.cpp
  * contrib/hbqt/hbqt_qerrormessage.cpp
  * contrib/hbqt/hbqt_qfiledialog.cpp
  * contrib/hbqt/hbqt_qformlayout.cpp
  * contrib/hbqt/hbqt_qtoolbar.cpp
  * contrib/hbqt/hbqt_qdatetimeedit.cpp
  * contrib/hbqt/hbqt_qmenu.cpp
  * contrib/hbqt/hbqt_qabstractslider.cpp
  * contrib/hbqt/hbqt_qwebview.cpp
  * contrib/hbqt/hbqt_qlayout.cpp
  * contrib/hbqt/hbqt_qslider.cpp
  * contrib/hbqt/hbqt_qtableview.cpp
  * contrib/hbqt/hbqt_qfontdialog.cpp
  * contrib/hbqt/hbqt_qboxlayout.cpp
  * contrib/hbqt/hbqt_qtreeview.cpp
  * contrib/hbqt/hbqt_qtextedit.cpp
  * contrib/hbqt/hbqt_qradiobutton.cpp
  * contrib/hbqt/hbqt_qcolordialog.cpp
  * contrib/hbqt/hbqt_qapplication.cpp
  * contrib/hbqt/hbqt_qtimeedit.cpp
  * contrib/hbqt/hbqt_qsplitter.cpp
  * contrib/hbqt/hbqt_qlistview.cpp
  * contrib/hbqt/hbqt_qtabwidget.cpp
  * contrib/hbqt/hbqt_qabstractscrollarea.cpp
  * contrib/hbqt/hbqt_qvboxlayout.cpp
  * contrib/hbqt/hbqt_qdoublespinbox.cpp
  * contrib/hbqt/hbqt_qscrollbar.cpp
  * contrib/hbqt/hbqt_qscrollarea.cpp
  * contrib/hbqt/hbqt_qtablewidget.cpp
  * contrib/hbqt/hbqt_qsizegrip.cpp
  * contrib/hbqt/hbqt_qlayoutitem.cpp
  * contrib/hbqt/hbqt_qmessagebox.cpp
  * contrib/hbqt/hbqt_qlineedit.cpp
    * Formatting, indenting.
    ! ISNIL() usage removed.

  * contrib/hbwin/wapi_commctrl.c
  * contrib/hbwin/wapi_winuser.c
    ! ISNIL() usage removed.

  * contrib/hbfbird/tfirebrd.prg
  * contrib/hbpgsql/tests/simple.prg
  * contrib/hbpgsql/tests/test.prg
  * contrib/hbpgsql/tests/cache.prg
  * contrib/hbpgsql/tests/stress.prg
  * contrib/hbpgsql/tests/dbf2pg.prg
  * contrib/hbpgsql/tpostgre.prg
  * contrib/examples/uhttpd/uhttpd.prg
  * contrib/examples/uhttpd/uhttpdc.c
  * contrib/examples/terminal/trm_server.prg
    * ISNIL() usage and other code cleanup, formatting.
2009-03-25 13:22:38 +00:00

646 lines
13 KiB
Plaintext

/*
* $Id$
*/
/*
* This samples show how to use dbf to cache postgres records.
*/
#include "common.ch"
#define CONNECTION_OK 0
#define CONNECTION_BAD 1
#define CONNECTION_STARTED 2
#define CONNECTION_MADE 3
#define CONNECTION_AWAITING_RESPONSE 4
#define CONNECTION_AUTH_OK 5
#define CONNECTION_SETENV 6
#define CONNECTION_SSL_STARTUP 7
#define CONNECTION_NEEDED 8
#define PGRES_EMPTY_QUERY 0
#define PGRES_COMMAND_OK 1
#define PGRES_TUPLES_OK 2
#define PGRES_COPY_OUT 3
#define PGRES_COPY_IN 4
#define PGRES_BAD_RESPONSE 5
#define PGRES_NONFATAL_ERROR 6
#define PGRES_FATAL_ERROR 7
#define PQTRANS_IDLE 0
#define PQTRANS_ACTIVE 1
#define PQTRANS_INTRANS 2
#define PQTRANS_INERROR 3
#define PQTRANS_UNKNOWN 4
#define DB_ALIAS 1
#define DB_FILE 2
#define DB_QUERY 3
#define DB_ROW 4
#define DB_FETCH 5
STATIC oServer
STATIC aTableTemp := {}
STATIC aTempDBF := {}
Function Main( cServer, cDatabase, cUser, cPass )
Local i
Local cQuery
Local conn, res
SetMode( 25, 80 )
if SQLConnect( cServer, cDatabase, cUser, cPass )
QuickQuery('DROP TABLE test')
cQuery := 'CREATE TABLE test ( '
cQuery += ' codigo integer primary key, '
cQuery += ' descri char(50), '
cQuery += ' email varchar(50) ) '
SQLQuery(cQuery)
SQLOpen( 'nomes', 'SELECT * FROM test')
for i := 1 to 50
append blank
replace codigo with i
replace descri with 'test ' + str(i)
next
SQLApplyUpdates()
cQuery := 'SELECT * FROM test WHERE codigo >= :1 ORDER BY codigo'
cQuery := SQLPrepare( cQuery, 1 )
SQLOpen( 'nomes', cQuery)
Do while ! Eof()
? recno(), nomes->Codigo, nomes->descri, nomes->email
if recno() == 10
delete
endif
if recno() == 20
REPLACE email WITH 'teste'
endif
SQLFetch()
enddo
SQLApplyUpdates()
endif
Return SQLGarbageCollector()
/* Put theses functions in a library */
Function SQLApplyUpdates()
Local cAlias := Upper(Alias())
Local i, x
Local aField := {}
Local oQuery
Local oRow
Local lUpdate
Local lError := .F.
Local cError
i := ASCAN(aTableTemp, {|aVal| aVal[DB_ALIAS] == cAlias})
IF i != 0
oQuery := aTableTemp[i, 3]
FOR i := 1 TO Lastrec()
DBGoto(i)
IF i > oQuery:Lastrec()
/* Verifica se eh um registro novo */
if ! Deleted()
oRow := oQuery:GetBlankRow()
FOR x := 1 TO FCount()
if oRow:Fieldpos( Fieldname(x) ) != 0
oRow:FieldPut(Fieldname(x), Fieldget(x))
endif
NEXT
oQuery:Append(oRow)
cError := oQuery:ErrorMsg()
lError := oQuery:NetErr()
endif
ELSE
oRow := oQuery:GetRow(i)
lUpdate := .F.
IF Deleted()
oQuery:Delete(oRow)
cError := oQuery:ErrorMsg()
lError := oQuery:NetErr()
ELSE
/* Faz update, mas compara quais campos sao diferentes */
FOR x := 1 TO Fcount()
if oRow:Fieldpos( Fieldname(x) ) != 0
if .not. (Fieldget(x) == oRow:Fieldget(Fieldname(x)))
oRow:Fieldput(Fieldname(x), Fieldget(x))
lUpdate := .t.
endif
endif
NEXT
IF lUpdate
oQuery:Update(oRow)
cError := oQuery:ErrorMsg()
lError := oQuery:NetErr()
ENDIF
ENDIF
ENDIF
if lError
exit
endif
NEXT
ENDIF
IF lError
Alert(cError)
ENDIF
Return ! lError
Procedure SQLCloseTemp( cAlias )
Local x
IF ! Empty(Select(cAlias))
CLOSE &calias
ENDIF
x := ASCAN(aTableTemp, {|aVal| aVal[DB_ALIAS] == cAlias})
IF ! Empty(x)
ADel( aTableTemp, x )
//ASize( aTableTemp, Len(aTableTemp) - 1 )
ENDIF
Return
Procedure SQLGarbageCollector()
Local i
Local oQuery
DBCloseAll()
FOR i := 1 TO Len(aTableTemp)
/* Apaga arquivos dbfs criados */
FErase(aTableTemp[i, DB_FILE])
oQuery := aTableTemp[i, DB_QUERY]
IF oQuery != NIL
oQuery:Destroy()
ENDIF
NEXT
FOR i := 1 TO Len(aTempDBF)
IF File(aTempDBF[i])
FErase(aTempDBF[i])
ENDIF
IF File(strtran(aTempDBF[i], '.tmp', '.dbf'))
FErase(strtran(aTempDBF[i], '.tmp', '.dbf'))
ENDIF
IF File(strtran(aTempDBF[i], '.tmp', '.dbt'))
FErase(strtran(aTempDBF[i], '.tmp', '.dbt'))
ENDIF
NEXT
aTableTemp := {}
aTempDBF := {}
Return
Function SQLFetch( fetchall )
Local oQuery
Local oRow
Local cAlias := Upper(Alias())
Local i, x, y
Local nPos := 0
Local lEof := .F.
Local cString := ""
Local aStruct
Default Fetchall TO .f.
/* Procura pela tabela no array */
i := ASCAN(aTableTemp, {|aVal| aVal[DB_ALIAS] == cAlias})
IF i != 0
/* Traz registros da base de dados */
oQuery := aTableTemp[i, DB_QUERY]
nPos := aTableTemp[i, DB_ROW] + 1
if Fetchall
aTableTemp[i, DB_FETCH] := .t.
endif
IF oQuery:Lastrec() >= nPos
y := nPos
do while nPos <= IIF( FetchAll, oQuery:Lastrec(), y )
oRow := oQuery:GetRow(nPos)
DBAppend()
FOR x := 1 TO oRow:FCount()
FieldPut( FieldPos( oRow:FieldName(x) ), oRow:FieldGet(x) )
NEXT
aTableTemp[i, DB_ROW] := nPos
nPos++
enddo
ELSE
// Posiciona registro no eof
DBSkip()
ENDIF
lEof := nPos > oQuery:Lastrec()
ENDIF
return lEof
Procedure SQLFetchAll()
SQLFetch(.t.); DBGotop()
Return
Function SQLOpen( cAlias, cQuery, xFetch )
Local cFile
Local Result := .t.
Local i, x
Local oServer
Local oQuery
Local aStrudbf
Local lFetch
Local cOrder
oServer := SQLCurrentServer()
cAlias := Upper(cAlias)
/* Procura por query na area temporaria */
x := ASCAN(aTableTemp, {|aVal| aVal[DB_ALIAS] == cAlias})
IF ! Empty(x)
oQuery := aTableTemp[x, 3]
oQuery:Destroy()
ENDIF
IF cQuery == NIL
cQuery := 'SELECT * FROM ' + cAlias + ' ORDER BY ' + cOrder
ENDIF
cQuery := cQuery
oQuery := oServer:Query(cQuery)
IF oQuery:NetErr()
Alert(oQuery:ErrorMsg())
RETURN .F.
ENDIF
IF Empty(Select(cAlias))
/* Pega estrutura da base de dados */
aStrudbf := oQuery:Struct()
/* Cria tabela */
cFile := TempFile()
DBCreate( cFile, aStrudbf )
/* Abre Tabela */
DBUseArea(.T., NIL, cFile, cAlias, .F.)
ELSE
SELECT &cAlias
Zap
ENDIF
IF xFetch != NIL
lFetch := xFetch
ELSE
lFetch := .F.
ENDIF
/* Se nao houver query na area temporaria entao adiciona, caso contrario, apenas atualiza */
IF Empty(x)
AADD( aTableTemp, { cAlias,; // Table Name
cFile,; // Temporary File Name
oQuery,; // Object Query
0,; // Current Row
lFetch } ) // Fetch Status
ELSE
aTableTemp[ x, DB_QUERY ] := oQuery
aTableTemp[ x, DB_ROW ] := 0
aTableTemp[ x, DB_FETCH ] := lFetch
ENDIF
/* Traz registros da base de dados */
SQLFetch(lFetch)
IF lFetch
DBGotop()
ENDIF
Return result
Function SQLConnect( cServer, cDatabase, cUser, cPassword, cSchema )
Local lRetval := .t.
oServer := TPQServer():New(cServer, cDatabase, cUser, cPassWord, 5432, cSchema)
if oServer:NetErr()
Alert(oServer:ErrorMsg())
lRetval := .f.
endif
oServer:lAllCols := .F.
Return lRetval
Procedure SQLDestroy()
if oServer != NIL
oServer:Destroy()
endif
return
Function SQLCurrentServer
Return oServer
Function SQLQuery( cQuery )
Local oQuery
oQuery := oServer:Query(cQuery)
IF oQuery:NetErr()
Alert(cQuery + ':' + oQuery:ErrorMsg())
ENDIF
Return oQuery
Function SQLExecQuery( cQuery )
Local oQuery
Local result := .T.
oQuery := oServer:Query(cQuery)
IF oQuery:NetErr()
Alert('Nao foi possível executar ' + cQuery + ':' + oQuery:ErrorMsg())
result := .F.
ELSE
oQuery:Destroy()
ENDIF
Return result
Function SQLPrepare( cQuery, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10,;
x11, x12, x13, x14, x15, x16, x17, x18, x19, x20,;
x21, x22, x23, x24, x25, x26, x27, x28, x29, x30,;
x31, x32, x33, x34, x35, x36, x37, x38, x39, x40,;
x41, x42, x43, x44, x45, x46, x47, x48, x49, x50,;
x51, x52, x53, x54, x55, x56, x57, x58, x59, x60,;
x61, x62, x63, x64, x65, x66, x67, x68, x69, x70,;
x71, x72, x73, x74, x75, x76, x77, x78, x79, x80,;
x81, x82, x83, x84, x85, x86, x87, x88, x89, x90,;
x91, x92, x93, x94, x95, x96, x97, x98, x99, x100)
Local i, x
if Pcount() >= 2
/* Limpa espacos desnecessarios */
do while at( Space(2), cQuery ) != 0
cQuery := strtran( cQuery, Space(2), Space(1) )
enddo
/* Coloca {} nos parametros */
for i := 1 to Pcount() - 1
if ! empty(x := at( ':' + ltrim(str(i)), cQuery))
cQuery := stuff( cQuery, x, 0, '{' )
cQuery := stuff( cQuery, x + len(ltrim(str(i))) + 2, 0, '}' )
endif
next
/* Substitui parametros por valores passados */
for i := 2 to PCount()
x := hb_PValue(i)
if x != NIL .and. Empty(x)
x := 'null'
elseif valtype(x) == 'N'
x := ltrim(str(x))
elseif valtype(x) == 'D'
x := DtoQ(x)
elseif valtype(x) == 'L'
x := IIF( x, "'t'", "'f'" )
elseif valtype(x) == "C" .or. valtype(x) == 'M'
x := StoQ(Trim(x))
else
x := 'null'
endif
cQuery := strtran(cQuery, '{:' + ltrim(str(i-1)) + '}', x)
next
endif
cQuery := strtran(cQuery, '==', '=')
cQuery := strtran(cQuery, '!=', '<>')
cQuery := strtran(cQuery, '.and.', 'and')
cQuery := strtran(cQuery, '.or.', 'or')
cQuery := strtran(cQuery, '.not.', 'not')
Return cQuery
/* Pega resultado de uma sequence */
Function SQLSequence( Sequence_name )
Local nValue
nValue := Val(QuickQuery("SELECT nextval(" + StoQ(sequence_name) + ")" ))
Return nValue
Function SQLStartTrans()
if PQtransactionstatus(oServer:pDB) != PQTRANS_INTRANS
oServer:StartTransaction()
endif
Return nil
Function SQLInTrans( lStart )
Local result
result := (PQtransactionstatus(oServer:pDB) == PQTRANS_INTRANS)
Return result
Function SQLCommitTrans()
oServer:Commit()
Return nil
Function SQLRollbackTrans()
oServer:rollback()
Return nil
/* Faz querie que retorna apenas 1 valor de coluna */
Function QuickQuery( cQuery )
Local pQuery
Local result := ""
Local temp, aTemp
Local x, y
pQuery := PQexec( oServer:pDB, cQuery )
if PQresultstatus(pQuery) == PGRES_TUPLES_OK
if PQLastrec(pQuery) != 0
if PQFcount(pQuery) == 1 .and. PQLastrec(pQuery) == 1
temp := PQGetValue( pQuery, 1, 1 )
result := iif( temp == NIL, "", temp )
else
result := {}
for x := 1 to PQLastrec(pQuery)
aTemp := {}
for y := 1 to PQfcount(pQuery)
temp := PQGetValue( pQuery, x, y )
aadd( aTemp, iif( temp == NIL, "", temp ) )
next
aadd(result, aTemp)
next
endif
endif
endif
PQclear(pQuery)
Return result
Procedure MakeDBF( cAlias, aStructure, aIndex )
Local cFile, i, cIndex, cKey
Default aIndex TO {}
cFile := TempFile()
DBCreate( cFile, aStructure )
/* Abre Tabela */
DBUseArea(.T., NIL, cFile, cAlias, .F.)
For i := 1 to Len(aIndex)
cKey := aIndex[i]
cIndex := TempFile()
Index On &cKey To &cIndex
aadd( aTempDBF, cIndex)
Next
AADD( aTempDBF, cFile )
return
Function DirTmp()
Local xDirectory
xDirectory := IIF(Empty(Getenv("TMP")), Getenv("TEMP"), Getenv("TMP"))
IF Empty(xDirectory)
xDirectory := ''
ENDIF
IF ';' $ xDirectory
xDirectory := LEFT( xDirectory, AT( ';', xDirectory ) - 1 )
ENDIF
RETURN xDirectory + IIF( Right(xDirectory, 1) != '\' .and. ! Empty(xDirectory), '\', '' )
Function TempFile( cPath, cExt )
Local cString
Default cPath to DirTmp(),;
cExt to 'tmp'
cString := cPath + strzero(int(hb_random(val(strtran(time(), ":", "")))), 8) + '.' + cExt
DO WHILE File( cString )
cString := cPath + strzero(int(hb_random(val(strtran(time(), ":", "")))), 8) + '.' + cExt
ENDDO
Return cString
Function DtoQ(cData)
Return "'" + Str(Year(cData),4) + "-" + StrZero(Month(cData), 2) + "-" + StrZero(Day(cData), 2) + "'"
Function StoQ(cData)
Return "'" + cData + "'"