2007-03-23 04:05 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/bin/pack_src.sh
+ harbour/contrib/pgsql/Changelog
+ harbour/contrib/pgsql/Makefile
+ harbour/contrib/pgsql/README
+ harbour/contrib/pgsql/make_b32.bat
+ harbour/contrib/pgsql/makefile.bc
+ harbour/contrib/pgsql/pgrdd.prg
+ harbour/contrib/pgsql/postgres.c
+ harbour/contrib/pgsql/postgres.ch
+ harbour/contrib/pgsql/tpostgre.prg
+ harbour/contrib/pgsql/tstpgrdd.prg
+ harbour/contrib/pgsql/tests/Makefile
+ harbour/contrib/pgsql/tests/async.prg
+ harbour/contrib/pgsql/tests/cache.prg
+ harbour/contrib/pgsql/tests/dbf2pg.prg
+ harbour/contrib/pgsql/tests/simple.prg
+ harbour/contrib/pgsql/tests/stress.prg
+ harbour/contrib/pgsql/tests/test.prg
+ added Postgres SQL library - code borrowed from xHarbour
* harbour/source/rtl/empty.c
+ added support for HASH items
* harbour/source/rtl/itemseri.c
+ added SYMBOL items serialization
This commit is contained in:
@@ -8,6 +8,33 @@
|
||||
2002-12-01 13:30 UTC+0100 Foo Bar <foo.bar@foobar.org>
|
||||
*/
|
||||
|
||||
2007-03-23 04:05 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
|
||||
* harbour/bin/pack_src.sh
|
||||
+ harbour/contrib/pgsql/Changelog
|
||||
+ harbour/contrib/pgsql/Makefile
|
||||
+ harbour/contrib/pgsql/README
|
||||
+ harbour/contrib/pgsql/make_b32.bat
|
||||
+ harbour/contrib/pgsql/makefile.bc
|
||||
+ harbour/contrib/pgsql/pgrdd.prg
|
||||
+ harbour/contrib/pgsql/postgres.c
|
||||
+ harbour/contrib/pgsql/postgres.ch
|
||||
+ harbour/contrib/pgsql/tpostgre.prg
|
||||
+ harbour/contrib/pgsql/tstpgrdd.prg
|
||||
+ harbour/contrib/pgsql/tests/Makefile
|
||||
+ harbour/contrib/pgsql/tests/async.prg
|
||||
+ harbour/contrib/pgsql/tests/cache.prg
|
||||
+ harbour/contrib/pgsql/tests/dbf2pg.prg
|
||||
+ harbour/contrib/pgsql/tests/simple.prg
|
||||
+ harbour/contrib/pgsql/tests/stress.prg
|
||||
+ harbour/contrib/pgsql/tests/test.prg
|
||||
+ added Postgres SQL library - code borrowed from xHarbour
|
||||
|
||||
* harbour/source/rtl/empty.c
|
||||
+ added support for HASH items
|
||||
|
||||
* harbour/source/rtl/itemseri.c
|
||||
+ added SYMBOL items serialization
|
||||
|
||||
2007-03-22 12:55 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
|
||||
* harbour/common.mak
|
||||
* updated for new files - please check
|
||||
|
||||
@@ -338,6 +338,24 @@ $hb_collect contrib/odbc/*.ch
|
||||
$hb_collect contrib/odbc/*.prg
|
||||
$hb_collect contrib/odbc/*.txt
|
||||
|
||||
# CONTRIB\PGSQL
|
||||
$hb_collect contrib/pgsql/[mM]akefile*
|
||||
$hb_collect contrib/pgsql/Changelog
|
||||
$hb_collect contrib/pgsql/README
|
||||
$hb_collect contrib/pgsql/*.[ch]
|
||||
$hb_collect contrib/pgsql/*.ch
|
||||
$hb_collect contrib/pgsql/*.prg
|
||||
$hb_collect contrib/pgsql/*.txt
|
||||
$hb_collect contrib/pgsql/*.bat
|
||||
|
||||
# CONTRIB\MYSQL
|
||||
$hb_collect contrib/mysql/[mM]akefile*
|
||||
$hb_collect contrib/mysql/*.[ch]
|
||||
$hb_collect contrib/mysql/*.ch
|
||||
$hb_collect contrib/mysql/*.prg
|
||||
$hb_collect contrib/mysql/*.txt
|
||||
$hb_collect contrib/mysql/*.bat
|
||||
|
||||
# CONTRIB\BTREE
|
||||
$hb_collect contrib/btree/[mM]akefile*
|
||||
$hb_collect contrib/btree/*.[ch]
|
||||
|
||||
250
harbour/contrib/pgsql/Changelog
Normal file
250
harbour/contrib/pgsql/Changelog
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Use this format for the entry headers:
|
||||
YYYY-MM-DD HH:MM UTC[-|+]hhmm Your Full Name <your_email@address>
|
||||
For example:
|
||||
2002-12-01 23:12 UTC+0100 Foo Bar <foo.bar@foobar.org>
|
||||
*/
|
||||
|
||||
2007-03-22 21:30 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
|
||||
* xharbour/contrib/pgsql/postgres.c
|
||||
! fixed code which was accessing item internals in function PQMETADATA
|
||||
% optimized function PQMETADATA by eliminating repeated array resizing
|
||||
|
||||
2005-10-08 12:40 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/postgres.c
|
||||
! Fixed return problem with lo_import
|
||||
|
||||
2005-07-05 19:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/TPostgres.prg
|
||||
! Fixed problem with pg8 changes for treatment of double precision and real
|
||||
|
||||
2005-06-01 20:30 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/postgres.c
|
||||
! Add control version for pg74x.
|
||||
|
||||
2005-05-21 11:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/TPostgres.prg
|
||||
+ Add 3 new methods, traceOn(), TraceOff(), SetVerbosity()
|
||||
* xharbour/contrib/pgsql/postgres.c
|
||||
+ Add New Functions:
|
||||
PQcreatetrace
|
||||
PQclosetrace
|
||||
PQtrace
|
||||
PQuntrace
|
||||
PQseterrorverbosity
|
||||
PQprotocolversion
|
||||
PQserverversion
|
||||
PQclientencoding
|
||||
PQsetclientencoding
|
||||
PQsetdblogin
|
||||
PQdb
|
||||
PQuser
|
||||
PQpass
|
||||
PQhost
|
||||
PQport
|
||||
PQtty
|
||||
PQoptions
|
||||
PQoidvalue
|
||||
PQoidstatus
|
||||
PQbinarytuples
|
||||
PQftable
|
||||
PQftype
|
||||
PQfname
|
||||
PQfmod
|
||||
PQfsize
|
||||
PQgetisnull
|
||||
PQfnumber
|
||||
PQntuples
|
||||
PQnfields
|
||||
PQgetcancel
|
||||
PQcancel
|
||||
PQfreecancel
|
||||
PQsetnonblocking
|
||||
PQisnonblocking
|
||||
lo_Unlink
|
||||
lo_Import
|
||||
lo_Export
|
||||
* xharbour/contrib/pgsql/tests/test.prg
|
||||
* xharbour/contrib/pgsql/tests/async.prg
|
||||
* xharbour/contrib/pgsql/tests/simple.prg
|
||||
+ Add more samples of using new functions
|
||||
|
||||
2005-03-12 12:20 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/TPostgres.prg
|
||||
! Fixed bug with ValueToString, thanks to Marco Aurelio.
|
||||
|
||||
2005-03-01 12:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
+ xharbour/contrib/pgsql/postgres.c
|
||||
! Add new function to handle binary escape string/quoted strings
|
||||
|
||||
2005-02-08 12:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/TPostgres.prg
|
||||
! Fixed bug in Append Method, regarding where clause, thanks to Marco Aurelio.
|
||||
|
||||
2005-02-02 11:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* xharbour/contrib/pgsql/TPostgres.prg
|
||||
! Add Destroy Methods
|
||||
|
||||
2005-01-12 23:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
+ xharbour/contrib/pgsql/postgres.c
|
||||
! Add new function to handle escape string/quoted strings
|
||||
|
||||
2004-12-15 10:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
+ xharbour/contrib/pgsql/postgres.c
|
||||
! Add new functions to handle the result of affected rows
|
||||
+ xharbour/contrib/pgsql/TPostgres.prg
|
||||
! Add new property, rows
|
||||
|
||||
2004-10-14 10:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
- xharbour/contrib/pgsql/TPostgres.prg
|
||||
! Removed function removespaces. It's not necessary remove unused spaces in query.
|
||||
|
||||
2004-09-29 18:30 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
+ xharbour/contrib/pgsql/postgres.c
|
||||
! Add new function PQreset, This function will close the connection
|
||||
to the server and attempt to reestablish a new connection to the
|
||||
same server, using all the same parameters previously used.
|
||||
This may be useful for error recovery if a working connection is lost.
|
||||
* xharbour/contrib/pgsql/README
|
||||
! Updated
|
||||
* xharbour/contrib/pgsql/makefile.bc
|
||||
! Updated
|
||||
|
||||
2004-09-06 22:00 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
|
||||
* xharbour/contrib/pgsql/postgres.c
|
||||
* initialize some variables which could not be uninitialized on some
|
||||
errors in PG or bad user parameters and cause GPF - I only fix it
|
||||
on C level - the same should be done for .prg returned values to
|
||||
not confuse .prg programmers on errors (if any).
|
||||
|
||||
2004-08-25 21:50 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed bugs with numeric/decimal fields when field was created with numeric() without parameters
|
||||
|
||||
2004-07-13 11:30 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
* Improved control over error messages
|
||||
! Fixed small bugs
|
||||
* tests/dbf2pg.prg
|
||||
* tests/cache.prg
|
||||
! changed to handle error messages
|
||||
|
||||
2004-06-22 15:40 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed bug regading primary keys, but with arrays
|
||||
+ tests/cache.prg
|
||||
! Sample, how to use .dbf as postgres record cache
|
||||
|
||||
2004-06-18 10:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed bug regading primary keys
|
||||
|
||||
2004-06-11 19:26 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed Date convertion bugs
|
||||
|
||||
2004-05-19 11:30 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed Schema bug
|
||||
|
||||
2004-05-04 19:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed bug select from procedures/funtion
|
||||
|
||||
2004-05-03 11:15 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed bug with numeric/decimal
|
||||
dbf store "." as part os field size, postgres doesn't, so, when decimal add + 1 in length
|
||||
|
||||
2004-05-02 18:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* postgres.c
|
||||
+ Add new functions for handling asynchronous/nonblocking queries
|
||||
! Fixed warnings
|
||||
+ tests/async.prg
|
||||
+ sample showing howto use the asynchronous queries
|
||||
|
||||
2004-04-30 15:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
+ postgres.ch
|
||||
+ Add new file with database definitions
|
||||
* TPostgres.prg
|
||||
* Changed fieldget parameters, fixed bug when parameter field is char
|
||||
* tests/simple.prg
|
||||
* tests/stress.prg
|
||||
* tests/test.prg
|
||||
! Fix some bugs
|
||||
* tests/dbf2pg.prg
|
||||
! Add new features and new parameter, like use transaction, commit interval, etc.
|
||||
|
||||
2004-04-25 14:33 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed (INSERT, DELETE, UPDATE) result error when row is updated
|
||||
|
||||
2004-04-25 14:33 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
! Fixed schema bugs
|
||||
|
||||
2004-04-25 16:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* postgres.c
|
||||
+ Add new function to handle error message
|
||||
* Changed pointer functions
|
||||
* TPostgres.prg
|
||||
+ Add Schema support
|
||||
! Some fix and improve initial query
|
||||
* tests/test.prg
|
||||
! Changed sample to handle connection and result messages
|
||||
|
||||
2004-04-05 14:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* postgres.c
|
||||
+ Add new functions to handle connection and result set
|
||||
* Changed pointer return
|
||||
|
||||
* TPostgres.prg
|
||||
* Changed to handle the status of connection and querys
|
||||
* Changed Fieldget, Fieldtype, Fielddec, Fieldlen, to handle char field name
|
||||
|
||||
2004-03-12 14:45 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
* Method Fieldget, fixed problem text field with null
|
||||
|
||||
2004-03-06 10:50 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
* Changed DataToSql, when empty date, should return null
|
||||
* Contributed by Joao Fonseca
|
||||
|
||||
2004-03-04 11:15 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
* Changed method GetBlank(), resulting nil class on previous errors
|
||||
|
||||
2004-03-02 16:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* TPostgres.prg
|
||||
* Add new property lallCols. Used to send only changed columns or not changed
|
||||
|
||||
2004-02-16 14:00 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* Modified makefile.bc to user PG_DIR var
|
||||
* Modified TPostgres.prg
|
||||
* Changed ISCHAR to ISCHARACTER
|
||||
* Modified samples/stress.prg
|
||||
* Changed ISCHAR to ISCHARACTER
|
||||
* Contributed by Eduardo Fenandez
|
||||
|
||||
2004-01-07 11:20 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* Modified make_b32.bat and makefile.bc, now it's working properly.
|
||||
|
||||
2004-01-07 10:50 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* Clean tab and spaces align
|
||||
|
||||
2004-01-04 17:40 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* Add function PQExecParams
|
||||
* This will be usefull on Append/Updated TPostgres Methods to avoid scaping strings
|
||||
|
||||
2004-01-04 10:10 UTC-0300 Luiz Rafael Culik<culikr@brturbo.com>
|
||||
* All Files recommited (trash on source file( chr(13))
|
||||
* postgres.c Xharbour sources should only include "hbapi.h" clipper
|
||||
compatible headers( extend.api and item.api) should now be used
|
||||
on xharbour modules
|
||||
|
||||
2004-01-02 15:05 UTC-0300 Rodrigo Moreno <rodrigo_moreno@yahoo.com>
|
||||
* INITIAL RELEASE
|
||||
18
harbour/contrib/pgsql/Makefile
Normal file
18
harbour/contrib/pgsql/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
ROOT = ../../
|
||||
|
||||
C_SOURCES=\
|
||||
postgres.c \
|
||||
|
||||
PRG_SOURCES=\
|
||||
tpostgre.prg \
|
||||
|
||||
LIBNAME=hbpg
|
||||
|
||||
include $(TOP)$(ROOT)config/lib.cf
|
||||
|
||||
ifeq ($(HB_COMPILER),mingw32)
|
||||
CFLAGS := $(CFLAGS) -I/postgres/include
|
||||
else
|
||||
CFLAGS := $(CFLAGS) -I/usr/local/pgsql/include -I/usr/local/pgsql/include/libpq -I/usr/include/pgsql
|
||||
endif
|
||||
51
harbour/contrib/pgsql/README
Normal file
51
harbour/contrib/pgsql/README
Normal file
@@ -0,0 +1,51 @@
|
||||
$Id$
|
||||
|
||||
README 23/12/2003 - Harbour Low Level api for Postgres RDBMS
|
||||
|
||||
It's to be seem like Harbour TMysql routines.
|
||||
|
||||
|
||||
IMPORTANT
|
||||
---------
|
||||
The class TPostgres, only works with versions 7.4.x or greater, because some methods use information_schema and
|
||||
New PQexecParams, which use protocol 3.0 and this protocol is only compatible with 7.4 versions.
|
||||
|
||||
BORLAND BCC
|
||||
-----------
|
||||
Using this library with bcc, you will need import library, ex: implib libpq.lib libpq.dll or (advice this) build your own
|
||||
Postgres Library.
|
||||
|
||||
Go to postgres directory \postgresql-7.4.5\src\interfaces\libpq
|
||||
|
||||
Edit bcc32.mak and change the default borland directory for your needs. Example: BCB=c:\Borland\Bcc55
|
||||
|
||||
change postgresql-7.4.5\src\include\pg_config.h.win32 to pg_config.h
|
||||
|
||||
after this
|
||||
|
||||
make -f bcc32.mak
|
||||
|
||||
Now look at \postgresql-7.4.5\src\interfaces\libpq\Release, you will find the all .libs and .dlls
|
||||
|
||||
If want use the dll, link in your aplication blibpqdll.lib and send blibpq.dll together with your aplication
|
||||
|
||||
If you don't wanna use .dll link blibpq.lib, that's it.
|
||||
|
||||
LINUX GCC
|
||||
----------
|
||||
On Linux you will need link libpq or references by pq.
|
||||
For full api documentation look at:
|
||||
http://www.postgresql.org/docs/current/static/libpq.html
|
||||
|
||||
FILES:
|
||||
postgres.c - Low level api
|
||||
tpostgre.prg - Class implementation, it's to be seems like TMysql.
|
||||
tests\simple.prg - Simple test class
|
||||
tests\stress.prg - Stress test
|
||||
tests\cache.prg - Show hot to use .dbf as pg cache, like TDataset for Delphi.
|
||||
|
||||
TODO:
|
||||
|
||||
That's all folks and sorry my poor english
|
||||
|
||||
Rodrigo Moreno - rodrigo_moreno@yahoo.com
|
||||
30
harbour/contrib/pgsql/make_b32.bat
Normal file
30
harbour/contrib/pgsql/make_b32.bat
Normal file
@@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
|
||||
if "%1" == "clean" goto CLEAN
|
||||
if "%1" == "CLEAN" goto CLEAN
|
||||
|
||||
:BUILD
|
||||
|
||||
make -fmakefile.bc %1 %2 %3 > make_b32.log
|
||||
if errorlevel 1 goto BUILD_ERR
|
||||
|
||||
:BUILD_OK
|
||||
|
||||
copy ..\..\lib\b32\libhbpg.lib ..\..\lib\*.* > nul
|
||||
goto EXIT
|
||||
|
||||
:BUILD_ERR
|
||||
|
||||
notepad make_b32.log
|
||||
goto EXIT
|
||||
|
||||
:CLEAN
|
||||
|
||||
if exist ..\..\lib\b32\libhbpg.lib del ..\..\lib\b32\libhbpg.lib
|
||||
if exist ..\..\lib\b32\libhbpg.bak del ..\..\lib\b32\libhbpg.bak
|
||||
if exist ..\..\obj\b32\postgres.obj del ..\..\obj\b32\postgres.obj
|
||||
if exist ..\..\obj\b32\TPostgres.c del ..\..\obj\b32\TPostgres.c
|
||||
if exist ..\..\obj\b32\TPostgres.obj del ..\..\obj\b32\TPostgres.obj
|
||||
goto EXIT
|
||||
|
||||
:EXIT
|
||||
31
harbour/contrib/pgsql/makefile.bc
Normal file
31
harbour/contrib/pgsql/makefile.bc
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
# makefile for Borland C/C++ 32 bits
|
||||
# Building of libhbpg.lib - Harbour API to postgres
|
||||
|
||||
# Postgresql running under Cygwin/Windows, unmark the line bellow to compile.
|
||||
# PG_DIR = ..\..\..\cygwin\usr\src\postgresql-7.4.5
|
||||
|
||||
PG_DIR = C:\PostgreSQL
|
||||
|
||||
INCLUDE_DIR = ..\..\include
|
||||
INCLUDE_PQ = $(PG_DIR)\include
|
||||
|
||||
BIN_DIR = c:\xharbour\bin
|
||||
OBJ_DIR = ..\..\obj\b32
|
||||
LIB_DIR = ..\..\lib\b32
|
||||
|
||||
$(LIB_DIR)\libhbpg.lib : \
|
||||
$(OBJ_DIR)\TPostgres.obj \
|
||||
$(OBJ_DIR)\postgres.obj
|
||||
|
||||
$(OBJ_DIR)\TPostgres.c : TPostgres.prg
|
||||
$(OBJ_DIR)\TPostgres.obj : $(OBJ_DIR)\TPostgres.c
|
||||
$(OBJ_DIR)\postgres.obj : postgres.c
|
||||
|
||||
.c.obj:
|
||||
bcc32 $(CLIBFLAGS) -c -O2 -I$(INCLUDE_DIR) -I$(INCLUDE_PQ) -DHB_OS_WIN_32_USED -DPG_DIAG_INTERNAL_POSITION -o$@ $<
|
||||
tlib $(LIB_DIR)\libhbpg.lib -+$@,,
|
||||
|
||||
.prg.c:
|
||||
$(BIN_DIR)\harbour.exe $< -q0 -a -w -es2 -gc0 -n -i$(INCLUDE_DIR) -o$@
|
||||
|
||||
395
harbour/contrib/pgsql/pgrdd.prg
Normal file
395
harbour/contrib/pgsql/pgrdd.prg
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* PostgreSQL RDD
|
||||
*
|
||||
* Copyright 2006 Lorenzo Fiorini <lorenzo_fiorini / at / teamwork / dot / it>
|
||||
* www - http://www.harbour-project.org
|
||||
* www - http://www.xharbour.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
||||
*
|
||||
* As a special exception, the Harbour Project gives permission for
|
||||
* additional uses of the text contained in its release of Harbour.
|
||||
*
|
||||
* The exception is that, if you link the Harbour libraries with other
|
||||
* files to produce an executable, this does not by itself cause the
|
||||
* resulting executable to be covered by the GNU General Public License.
|
||||
* Your use of that executable is in no way restricted on account of
|
||||
* linking the Harbour library code into it.
|
||||
*
|
||||
* This exception does not however invalidate any other reasons why
|
||||
* the executable file might be covered by the GNU General Public License.
|
||||
*
|
||||
* This exception applies only to the code released by the Harbour
|
||||
* Project under the name Harbour. If you copy code from other
|
||||
* Harbour Project or Free Software Foundation releases into a copy of
|
||||
* Harbour, as the General Public License permits, the exception does
|
||||
* not apply to the code that you add in this way. To avoid misleading
|
||||
* anyone as to the status of such modified files, you must delete
|
||||
* this exception notice from them.
|
||||
*
|
||||
* If you write modifications of your own for Harbour, it is your choice
|
||||
* whether to permit this exception to apply to your modifications.
|
||||
* If you do not wish that, delete this exception notice.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an experimental RDD for xharbour/contrib/pgsql interface.
|
||||
* It has been created to test the possibilities of usrrdd.
|
||||
* It doesn't support many functions and commands and many things could be optimized.
|
||||
*/
|
||||
|
||||
#include "rddsys.ch"
|
||||
#include "usrrdd.ch"
|
||||
#include "fileio.ch"
|
||||
#include "error.ch"
|
||||
#include "dbstruct.ch"
|
||||
#include "common.ch"
|
||||
|
||||
#define AREA_QUERY 1
|
||||
#define AREA_ROW 2
|
||||
#define AREA_APPEND 3
|
||||
|
||||
#define AREA_LEN 3
|
||||
|
||||
ANNOUNCE PGRDD
|
||||
|
||||
STATIC s_aConnections := {}
|
||||
|
||||
FUNCTION DBPGCONNECTION( cConnString )
|
||||
|
||||
LOCAL aParams
|
||||
LOCAL oServer
|
||||
LOCAL nConn
|
||||
|
||||
aParams := HB_ATOKENS( cConnString, ";" )
|
||||
|
||||
asize( aParams, 6 )
|
||||
|
||||
oServer := TPQServer():New( aParams[1], aParams[2], aParams[3], aParams[4], aParams[5], aParams[6] )
|
||||
|
||||
IF oServer:NetErr()
|
||||
alert( oServer:ErrorMsg() )
|
||||
RETURN FAILURE
|
||||
ELSE
|
||||
aadd( s_aConnections, oServer )
|
||||
nConn := len( s_aConnections )
|
||||
ENDIF
|
||||
|
||||
RETURN nConn
|
||||
|
||||
FUNCTION DBPGCLEARCONNECTION( nConn )
|
||||
|
||||
LOCAL oServer
|
||||
|
||||
oServer := s_aConnections[ nConn ]
|
||||
|
||||
oServer:Close()
|
||||
|
||||
s_aConnections[ nConn ] := nil
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
/*
|
||||
* non work area methods receive RDD ID as first parameter
|
||||
* Methods INIT and EXIT does not have to execute SUPER methods - these is
|
||||
* always done by low level USRRDD code
|
||||
*/
|
||||
STATIC FUNCTION PG_INIT( nRDD )
|
||||
|
||||
USRRDD_RDDDATA( nRDD )
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
/*
|
||||
* methods: NEW and RELEASE receive pointer to work area structure
|
||||
* not work area number. It's necessary because the can be executed
|
||||
* before work area is allocated
|
||||
* these methods does not have to execute SUPER methods - these is
|
||||
* always done by low level USRRDD code
|
||||
*/
|
||||
STATIC FUNCTION PG_NEW( pWA )
|
||||
|
||||
USRRDD_AREADATA( pWA, array( AREA_LEN ) )
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_OPEN( nWA, aOpenInfo )
|
||||
LOCAL aField, oError, lError, cError, nResult
|
||||
LOCAL oServer, oQuery, aStruct, aFieldStruct
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
lError := .F.
|
||||
|
||||
if !empty( aOpenInfo[ UR_OI_CONNECT ] ) .and. aOpenInfo[ UR_OI_CONNECT ] <= len( s_aConnections )
|
||||
oServer := s_aConnections[ aOpenInfo[ UR_OI_CONNECT ] ]
|
||||
endif
|
||||
|
||||
if !empty( oServer )
|
||||
oServer:lAllCols := .F.
|
||||
oQuery := oServer:Query( aOpenInfo[ UR_OI_NAME ] )
|
||||
lError := oQuery:NetErr()
|
||||
cError := oQuery:ErrorMsg()
|
||||
else
|
||||
lError := .T.
|
||||
cError := "Invalid connection handle"
|
||||
endif
|
||||
|
||||
IF lError
|
||||
oError := ErrorNew()
|
||||
oError:GenCode := EG_OPEN
|
||||
oError:SubCode := 1000
|
||||
oError:Description := HB_LANGERRMSG( EG_OPEN ) + ", " + cError
|
||||
oError:FileName := aOpenInfo[ UR_OI_NAME ]
|
||||
oError:CanDefault := .T.
|
||||
UR_SUPER_ERROR( nWA, oError )
|
||||
RETURN FAILURE
|
||||
ELSE
|
||||
aWAData[ AREA_QUERY ] := oQuery
|
||||
ENDIF
|
||||
|
||||
UR_SUPER_SETFIELDEXTENT( nWA, oQuery:nFields )
|
||||
|
||||
aStruct := oQuery:Struct()
|
||||
|
||||
FOR EACH aFieldStruct IN aStruct
|
||||
|
||||
aField := ARRAY( UR_FI_SIZE )
|
||||
aField[ UR_FI_NAME ] := aFieldStruct[ DBS_NAME ]
|
||||
aField[ UR_FI_TYPE ] := aFieldStruct[ DBS_TYPE ]
|
||||
aField[ UR_FI_TYPEEXT ] := 0
|
||||
aField[ UR_FI_LEN ] := aFieldStruct[ DBS_LEN ]
|
||||
aField[ UR_FI_DEC ] := aFieldStruct[ DBS_DEC ]
|
||||
UR_SUPER_ADDFIELD( nWA, aField )
|
||||
|
||||
NEXT
|
||||
|
||||
/* Call SUPER OPEN to finish allocating work area (f.e.: alias settings) */
|
||||
nResult := UR_SUPER_OPEN( nWA, aOpenInfo )
|
||||
|
||||
RETURN nResult
|
||||
|
||||
STATIC FUNCTION PG_CLOSE( nWA )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
aWAData[ AREA_QUERY ]:Close()
|
||||
|
||||
RETURN UR_SUPER_CLOSE( nWA )
|
||||
|
||||
STATIC FUNCTION PG_GETVALUE( nWA, nField, xValue )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
if !empty( aWAData[ AREA_ROW ] )
|
||||
xValue := aWAData[ AREA_ROW ]:FieldGet( nField )
|
||||
else
|
||||
xValue := aWAData[ AREA_QUERY ]:FieldGet( nField )
|
||||
endif
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_PUTVALUE( nWA, nField, xValue )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
if empty( aWAData[ AREA_ROW ] )
|
||||
aWAData[ AREA_ROW ] := aWAData[ AREA_QUERY ]:GetRow()
|
||||
endif
|
||||
|
||||
aWAData[ AREA_ROW ]:FieldPut( nField, xValue )
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_SKIP( nWA, nRecords )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
if !empty( aWAData[ AREA_ROW ] )
|
||||
PG_FLUSH( nWA )
|
||||
endif
|
||||
|
||||
aWAData[ AREA_QUERY ]:Skip( nRecords )
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_GOTOP( nWA )
|
||||
RETURN PG_GOTO( nWA, 1 )
|
||||
|
||||
STATIC FUNCTION PG_GOBOTTOM( nWA )
|
||||
RETURN PG_GOTO( nWA, -1 )
|
||||
|
||||
STATIC FUNCTION PG_GOTOID( nWA, nRecord )
|
||||
RETURN PG_GOTO( nWA, nRecord )
|
||||
|
||||
STATIC FUNCTION PG_GOTO( nWA, nRecord )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
if !empty( aWAData[ AREA_ROW ] )
|
||||
PG_FLUSH( nWA )
|
||||
endif
|
||||
|
||||
if nRecord < 0
|
||||
nRecord := aWAData[ AREA_QUERY ]:nLastRec
|
||||
elseif nRecord == 0
|
||||
nRecord := aWAData[ AREA_QUERY ]:nRecno
|
||||
endif
|
||||
|
||||
aWAData[ AREA_QUERY ]:Goto( nRecord )
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_RECCOUNT( nWA, nRecords )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
nRecords := aWAData[ AREA_QUERY ]:nLastRec
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_BOF( nWA, lBof )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
lBof := aWAData[ AREA_QUERY ]:lBof
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_EOF( nWA, lEof )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
lEof := aWAData[ AREA_QUERY ]:lEof
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_RECID( nWA, nRecNo )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
nRecno := aWAData[ AREA_QUERY ]:nRecNo
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_DELETED( nWA, lDeleted )
|
||||
lDeleted := .F.
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_FLUSH( nWA )
|
||||
LOCAL oError
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
LOCAL nRecno
|
||||
|
||||
if aWAData[ AREA_ROW ] != nil
|
||||
if !empty( aWAData[ AREA_APPEND ] )
|
||||
aWAData[ AREA_QUERY ]:Append( aWAData[ AREA_ROW ] )
|
||||
else
|
||||
nRecno := aWAData[ AREA_QUERY ]:nRecNo
|
||||
aWAData[ AREA_QUERY ]:Update( aWAData[ AREA_ROW ] )
|
||||
endif
|
||||
|
||||
IF aWAData[ AREA_QUERY ]:lError
|
||||
oError := ErrorNew()
|
||||
oError:GenCode := EG_DATATYPE
|
||||
oError:SubCode := 3000
|
||||
oError:Description := HB_LANGERRMSG( EG_DATATYPE ) + ", " + aWAData[ AREA_QUERY ]:ErrorMsg()
|
||||
UR_SUPER_ERROR( nWA, oError )
|
||||
RETURN FAILURE
|
||||
ENDIF
|
||||
|
||||
/*
|
||||
* The :Refresh() below costs a lot in term of performance.
|
||||
* It redo the select to include inserts and updates.
|
||||
* It is the only solution I've found so far to simulate dbf behaviour
|
||||
*/
|
||||
aWAData[ AREA_QUERY ]:Refresh( .T., .F. )
|
||||
|
||||
if !empty( aWAData[ AREA_APPEND ] )
|
||||
aWAData[ AREA_APPEND ] := .F.
|
||||
nRecno := aWAData[ AREA_QUERY ]:nLastRec
|
||||
endif
|
||||
|
||||
aWAData[ AREA_ROW ] := nil
|
||||
|
||||
PG_GOTO( nWA, nRecno )
|
||||
|
||||
endif
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_APPEND( nWA, nRecords )
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
aWAData[ AREA_ROW ] := aWAData[ AREA_QUERY ]:GetBlankRow()
|
||||
|
||||
aWAData[ AREA_APPEND ] := .T.
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
STATIC FUNCTION PG_DELETE( nWA )
|
||||
LOCAL oError
|
||||
LOCAL aWAData := USRRDD_AREADATA( nWA )
|
||||
|
||||
aWAData[ AREA_ROW ] := aWAData[ AREA_QUERY ]:GetRow()
|
||||
|
||||
aWAData[ AREA_QUERY ]:Delete( aWAData[ AREA_ROW ] )
|
||||
|
||||
IF aWAData[ AREA_QUERY ]:lError
|
||||
oError := ErrorNew()
|
||||
oError:GenCode := EG_DATATYPE
|
||||
oError:SubCode := 2000
|
||||
oError:Description := HB_LANGERRMSG( EG_DATATYPE ) + ", " + aWAData[ AREA_QUERY ]:ErrorMsg()
|
||||
UR_SUPER_ERROR( nWA, oError )
|
||||
RETURN FAILURE
|
||||
ENDIF
|
||||
|
||||
aWAData[ AREA_ROW ] := nil
|
||||
|
||||
RETURN SUCCESS
|
||||
|
||||
/*
|
||||
* This function have to exist in all RDD and then name have to be in
|
||||
* format: <RDDNAME>_GETFUNCTABLE
|
||||
*/
|
||||
FUNCTION PGRDD_GETFUNCTABLE( pFuncCount, pFuncTable, pSuperTable, nRddID )
|
||||
LOCAL cSuperRDD := NIL /* NO SUPER RDD */
|
||||
LOCAL aMyFunc[ UR_METHODCOUNT ]
|
||||
|
||||
aMyFunc[ UR_INIT ] := ( @PG_INIT() )
|
||||
aMyFunc[ UR_NEW ] := ( @PG_NEW() )
|
||||
aMyFunc[ UR_OPEN ] := ( @PG_OPEN() )
|
||||
aMyFunc[ UR_GETVALUE ] := ( @PG_GETVALUE() )
|
||||
aMyFunc[ UR_PUTVALUE ] := ( @PG_PUTVALUE() )
|
||||
aMyFunc[ UR_SKIP ] := ( @PG_SKIP() )
|
||||
aMyFunc[ UR_GOTO ] := ( @PG_GOTO() )
|
||||
aMyFunc[ UR_GOTOID ] := ( @PG_GOTOID() )
|
||||
aMyFunc[ UR_GOTOP ] := ( @PG_GOTOP() )
|
||||
aMyFunc[ UR_GOBOTTOM ] := ( @PG_GOBOTTOM() )
|
||||
aMyFunc[ UR_RECCOUNT ] := ( @PG_RECCOUNT() )
|
||||
aMyFunc[ UR_RECID ] := ( @PG_RECID() )
|
||||
aMyFunc[ UR_BOF ] := ( @PG_BOF() )
|
||||
aMyFunc[ UR_EOF ] := ( @PG_EOF() )
|
||||
aMyFunc[ UR_DELETED ] := ( @PG_DELETED() )
|
||||
aMyFunc[ UR_FLUSH ] := ( @PG_FLUSH() )
|
||||
aMyFunc[ UR_APPEND ] := ( @PG_APPEND() )
|
||||
aMyFunc[ UR_DELETE ] := ( @PG_DELETE() )
|
||||
aMyFunc[ UR_CLOSE ] := ( @PG_CLOSE() )
|
||||
|
||||
RETURN USRRDD_GETFUNCTABLE( pFuncCount, pFuncTable, pSuperTable, nRddID, ;
|
||||
cSuperRDD, aMyFunc )
|
||||
|
||||
INIT PROC PG_INIT()
|
||||
rddRegister( "PGRDD", RDT_FULL )
|
||||
RETURN
|
||||
|
||||
|
||||
866
harbour/contrib/pgsql/postgres.c
Normal file
866
harbour/contrib/pgsql/postgres.c
Normal file
@@ -0,0 +1,866 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* xHarbour Project source code:
|
||||
* PostgreSQL RDBMS low level (client api) interface code.
|
||||
*
|
||||
* Copyright 2003 Rodrigo Moreno rodrigo_moreno@yahoo.com
|
||||
* www - http://www.xharbour.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
||||
*
|
||||
* As a special exception, the Harbour Project gives permission for
|
||||
* additional uses of the text contained in its release of Harbour.
|
||||
*
|
||||
* The exception is that, if you link the Harbour libraries with other
|
||||
* files to produce an executable, this does not by itself cause the
|
||||
* resulting executable to be covered by the GNU General Public License.
|
||||
* Your use of that executable is in no way restricted on account of
|
||||
* linking the Harbour library code into it.
|
||||
*
|
||||
* This exception does not however invalidate any other reasons why
|
||||
* the executable file might be covered by the GNU General Public License.
|
||||
*
|
||||
* This exception applies only to the code released by the Harbour
|
||||
* Project under the name Harbour. If you copy code from other
|
||||
* Harbour Project or Free Software Foundation releases into a copy of
|
||||
* Harbour, as the General Public License permits, the exception does
|
||||
* not apply to the code that you add in this way. To avoid misleading
|
||||
* anyone as to the status of such modified files, you must delete
|
||||
* this exception notice from them.
|
||||
*
|
||||
* If you write modifications of your own for Harbour, it is your choice
|
||||
* whether to permit this exception to apply to your modifications.
|
||||
* If you do not wish that, delete this exception notice.
|
||||
*
|
||||
* See doc/license.txt for licensing terms.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hbapi.h"
|
||||
#include "hbapiitm.h"
|
||||
#include "libpq-fe.h"
|
||||
|
||||
#define _CLIPDEFS_H
|
||||
#if defined(HB_OS_WIN_32_USED)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define VARHDRSZ 4
|
||||
#define BOOLOID 16
|
||||
#define INT8OID 20
|
||||
#define INT2OID 21
|
||||
#define INT4OID 23
|
||||
#define TEXTOID 25
|
||||
#define OIDOID 26
|
||||
#define FLOAT4OID 700
|
||||
#define FLOAT8OID 701
|
||||
#define CASHOID 790
|
||||
#define BPCHAROID 1042
|
||||
#define VARCHAROID 1043
|
||||
#define DATEOID 1082
|
||||
#define TIMEOID 1083
|
||||
#define TIMESTAMPOID 1114
|
||||
#define TIMESTAMPTZOID 1184
|
||||
#define TIMETZOID 1266
|
||||
#define BITOID 1560
|
||||
#define VARBITOID 1562
|
||||
#define NUMERICOID 1700
|
||||
|
||||
#define INV_WRITE 0x00020000
|
||||
#define INV_READ 0x00040000
|
||||
|
||||
#ifndef HB_PGVERSION
|
||||
# ifdef PG_DIAG_INTERNAL_POSITION
|
||||
# define HB_PGVERSION 0x0800
|
||||
# else
|
||||
# define HB_PGVERSION 0x0700
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Connection handling functions
|
||||
*/
|
||||
|
||||
HB_FUNC( PQCONNECT )
|
||||
{
|
||||
char conninfo[128];
|
||||
PGconn *conn;
|
||||
|
||||
if( hb_pcount() == 5 )
|
||||
sprintf( conninfo, "dbname = %s host = %s user = %s password = %s port = %i",
|
||||
hb_parcx(1), hb_parcx(2), hb_parcx(3), hb_parcx(4), (int) hb_parni(5) );
|
||||
|
||||
conn = PQconnectdb( conninfo );
|
||||
hb_retptr( conn );
|
||||
}
|
||||
|
||||
HB_FUNC( PQSETDBLOGIN )
|
||||
{
|
||||
const char *pghost;
|
||||
const char *pgport;
|
||||
const char *pgoptions;
|
||||
const char *pgtty;
|
||||
const char *dbName;
|
||||
const char *login;
|
||||
const char *pwd;
|
||||
|
||||
pghost = hb_parcx(1);
|
||||
pgport = hb_parcx(2);
|
||||
pgoptions = hb_parcx(3);
|
||||
pgtty = hb_parcx(4);
|
||||
dbName = hb_parcx(5);
|
||||
login = hb_parcx(6);
|
||||
pwd = hb_parcx(8);
|
||||
|
||||
if (hb_pcount() == 7)
|
||||
hb_retptr( ( PGconn * ) PQsetdbLogin( pghost, pgport, pgoptions, pgtty, dbName, login, pwd) );
|
||||
}
|
||||
|
||||
HB_FUNC(PQCLOSE)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
PQfinish(( PGconn * ) hb_parptr(1));
|
||||
}
|
||||
|
||||
HB_FUNC(PQRESET)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
PQreset(( PGconn * ) hb_parptr(1));
|
||||
}
|
||||
|
||||
HB_FUNC(PQPROTOCOLVERSION)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni(PQprotocolVersion(( PGconn * ) hb_parptr(1)));
|
||||
}
|
||||
|
||||
HB_FUNC(PQCLIENTENCODING)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni(PQclientEncoding(( PGconn * ) hb_parptr(1)));
|
||||
}
|
||||
|
||||
HB_FUNC(PQSETCLIENTENCODING)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retni(PQsetClientEncoding(( PGconn * ) hb_parptr(1), hb_parcx(2)));
|
||||
}
|
||||
|
||||
HB_FUNC(PQDB)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQdb( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQUSER)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQuser( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQPASS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQpass( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQHOST)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQhost( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQPORT)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQport( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQTTY)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQtty( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQOPTIONS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQoptions( ( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
/*
|
||||
* Query handling functions
|
||||
*/
|
||||
|
||||
HB_FUNC(PQCLEAR)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
PQclear(( PGresult * ) hb_parptr(1));
|
||||
}
|
||||
|
||||
HB_FUNC(PQEXEC)
|
||||
{
|
||||
PGresult *res = NULL;
|
||||
|
||||
if (hb_pcount() == 2)
|
||||
res = PQexec(( PGconn * ) hb_parptr(1), hb_parcx(2));
|
||||
|
||||
hb_retptr( res );
|
||||
}
|
||||
|
||||
HB_FUNC(PQEXECPARAMS)
|
||||
{
|
||||
PGresult *res = NULL;
|
||||
const char **paramvalues;
|
||||
int i;
|
||||
long n;
|
||||
|
||||
PHB_ITEM aParam;
|
||||
|
||||
if (hb_pcount() == 3)
|
||||
{
|
||||
aParam = hb_param(3,HB_IT_ARRAY);
|
||||
|
||||
n = hb_arrayLen(aParam);
|
||||
|
||||
paramvalues = (const char **) hb_xgrab( sizeof( char *) * n );
|
||||
|
||||
for (i=0;i < n;i++)
|
||||
paramvalues[i] = hb_arrayGetCPtr( aParam, i + 1 );
|
||||
|
||||
res = PQexecParams(( PGconn * ) hb_parptr(1), hb_parcx(2), n, NULL, paramvalues, NULL, NULL, 1);
|
||||
|
||||
hb_xfree(paramvalues);
|
||||
}
|
||||
hb_retptr( res );
|
||||
}
|
||||
|
||||
HB_FUNC(PQFCOUNT)
|
||||
{
|
||||
PGresult *res;
|
||||
int nFields = 0;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
{
|
||||
res = ( PGresult * ) hb_parptr(1);
|
||||
|
||||
if (PQresultStatus(res) == PGRES_TUPLES_OK)
|
||||
nFields = PQnfields(res);
|
||||
}
|
||||
|
||||
hb_retni(nFields);
|
||||
}
|
||||
|
||||
HB_FUNC(PQLASTREC)
|
||||
{
|
||||
PGresult *res;
|
||||
int nRows = 0;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
{
|
||||
res = ( PGresult * ) hb_parptr(1);
|
||||
|
||||
if (PQresultStatus(res) == PGRES_TUPLES_OK)
|
||||
nRows = PQntuples(res);
|
||||
}
|
||||
hb_retni(nRows);
|
||||
}
|
||||
|
||||
HB_FUNC(PQGETVALUE)
|
||||
{
|
||||
PGresult *res;
|
||||
int nRow, nCol;
|
||||
|
||||
if (hb_pcount() == 3)
|
||||
{
|
||||
res = ( PGresult * ) hb_parptr(1);
|
||||
|
||||
if (PQresultStatus(res) == PGRES_TUPLES_OK)
|
||||
{
|
||||
nRow = hb_parni(2) - 1;
|
||||
nCol = hb_parni(3) - 1;
|
||||
|
||||
if (! PQgetisnull(res, nRow, nCol))
|
||||
hb_retc(PQgetvalue(res, nRow, nCol));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC(PQGETLENGTH)
|
||||
{
|
||||
PGresult *res;
|
||||
int nRow, nCol;
|
||||
int result = 0;
|
||||
|
||||
if (hb_pcount() == 3)
|
||||
{
|
||||
res = ( PGresult * ) hb_parptr(1);
|
||||
|
||||
if (PQresultStatus(res) == PGRES_TUPLES_OK)
|
||||
{
|
||||
nRow = hb_parni(2) - 1;
|
||||
nCol = hb_parni(3) - 1;
|
||||
|
||||
result = PQgetlength(res, nRow, nCol);
|
||||
}
|
||||
}
|
||||
hb_retni(result);
|
||||
}
|
||||
|
||||
HB_FUNC( PQMETADATA )
|
||||
{
|
||||
PGresult *res;
|
||||
if( hb_parinfo( 1 ) )
|
||||
{
|
||||
res = ( PGresult * ) hb_parptr( 1 );
|
||||
if( PQresultStatus( res ) == PGRES_TUPLES_OK )
|
||||
{
|
||||
int nFields = PQnfields( res ), i;
|
||||
PHB_ITEM pResult = hb_itemArrayNew( nFields ), pField;
|
||||
|
||||
for( i = 0; i < nFields; i++ )
|
||||
{
|
||||
char buf[256];
|
||||
Oid type_oid = PQftype( res, i );
|
||||
int typemod = PQfmod( res, i );
|
||||
int length = 0;
|
||||
int decimal = 0;
|
||||
|
||||
switch( type_oid )
|
||||
{
|
||||
case BITOID:
|
||||
if( typemod >= 0 )
|
||||
length = ( int ) typemod;
|
||||
strcpy( buf, "bit" );
|
||||
break;
|
||||
|
||||
case BOOLOID:
|
||||
length = 1;
|
||||
strcpy( buf, "boolean" );
|
||||
break;
|
||||
|
||||
case BPCHAROID:
|
||||
if( typemod >= 0 )
|
||||
length = ( int ) ( typemod - VARHDRSZ );
|
||||
strcpy( buf, "character" );
|
||||
break;
|
||||
|
||||
case FLOAT4OID:
|
||||
strcpy( buf, "real" );
|
||||
break;
|
||||
|
||||
case FLOAT8OID:
|
||||
strcpy( buf, "double precision" );
|
||||
break;
|
||||
|
||||
case INT2OID:
|
||||
strcpy( buf, "smallint" );
|
||||
break;
|
||||
|
||||
case INT4OID:
|
||||
strcpy( buf, "integer" );
|
||||
break;
|
||||
|
||||
case OIDOID:
|
||||
strcpy( buf, "bigint" );
|
||||
break;
|
||||
|
||||
case INT8OID:
|
||||
strcpy( buf, "bigint" );
|
||||
break;
|
||||
|
||||
case NUMERICOID:
|
||||
length = ( ( typemod - VARHDRSZ ) >> 16 ) & 0xffff;
|
||||
decimal = ( typemod - VARHDRSZ ) & 0xffff;
|
||||
strcpy( buf, "numeric" );
|
||||
break;
|
||||
|
||||
case DATEOID:
|
||||
strcpy( buf, "date" );
|
||||
break;
|
||||
|
||||
case TIMEOID:
|
||||
case TIMETZOID:
|
||||
strcpy( buf, "timezone" );
|
||||
break;
|
||||
|
||||
case TIMESTAMPOID:
|
||||
case TIMESTAMPTZOID:
|
||||
strcpy( buf, "timestamp" );
|
||||
break;
|
||||
|
||||
case VARBITOID:
|
||||
if( typemod >= 0 )
|
||||
length = (int) typemod;
|
||||
strcpy( buf, "bit varying" );
|
||||
break;
|
||||
|
||||
case VARCHAROID:
|
||||
if( typemod >= 0 )
|
||||
length = ( int ) ( typemod - VARHDRSZ );
|
||||
strcpy( buf, "character varying" );
|
||||
break;
|
||||
|
||||
case TEXTOID:
|
||||
strcpy(buf, "text");
|
||||
break;
|
||||
|
||||
case CASHOID:
|
||||
strcpy( buf, "money" );
|
||||
break;
|
||||
|
||||
default:
|
||||
strcpy( buf, "not supported" );
|
||||
break;
|
||||
}
|
||||
|
||||
pField = hb_arrayGetItemPtr( pResult, i + 1 );
|
||||
hb_arrayNew ( pField, 6 );
|
||||
hb_itemPutC ( hb_arrayGetItemPtr( pField, 1 ), PQfname( res, i ) );
|
||||
hb_itemPutC ( hb_arrayGetItemPtr( pField, 2 ), buf );
|
||||
hb_itemPutNI( hb_arrayGetItemPtr( pField, 3 ), length );
|
||||
hb_itemPutNI( hb_arrayGetItemPtr( pField, 4 ), decimal );
|
||||
hb_itemPutNL( hb_arrayGetItemPtr( pField, 5 ), PQftable( res, i ) );
|
||||
hb_itemPutNI( hb_arrayGetItemPtr( pField, 6 ), PQftablecol( res, i ) );
|
||||
}
|
||||
hb_itemRelease( hb_itemReturnForward( pResult ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC(PQTRANSACTIONSTATUS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni(PQtransactionStatus(( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQERRORMESSAGE)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQerrorMessage(( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQSTATUS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni(PQstatus(( PGconn * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQRESULTERRORMESSAGE)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQresultErrorMessage(( PGresult * ) hb_parptr(1)));
|
||||
}
|
||||
|
||||
HB_FUNC(PQRESULTSTATUS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni(PQresultStatus(( PGresult * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQCMDSTATUS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQcmdStatus( (PGresult *) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQCMDTUPLES)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc(PQcmdTuples( (PGresult *) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQESCAPESTRING)
|
||||
{
|
||||
char *source;
|
||||
char *dest;
|
||||
size_t size;
|
||||
|
||||
source = hb_parcx(1);
|
||||
dest = (char *) hb_xgrab( strlen(source) * 2 + 1);
|
||||
size = strlen(source);
|
||||
|
||||
PQescapeString(dest, source, size);
|
||||
|
||||
hb_retc(dest);
|
||||
hb_xfree( (char *) dest);
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQESCAPEBYTEA)
|
||||
{
|
||||
char *from;
|
||||
char *to;
|
||||
size_t from_length;
|
||||
size_t to_length;
|
||||
|
||||
from = hb_parcx(1);
|
||||
from_length = strlen(from);
|
||||
to_length = strlen(from) * 5 + 1;
|
||||
|
||||
to = PQescapeBytea(from, from_length, &to_length);
|
||||
hb_retc(to);
|
||||
PQfreemem(to);
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQUNESCAPEBYTEA)
|
||||
{
|
||||
char *from;
|
||||
size_t to_length;
|
||||
|
||||
from = PQunescapeBytea(hb_parcx(1), &to_length);
|
||||
hb_retclen(from, to_length);
|
||||
PQfreemem(from);
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQOIDVALUE)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retnl( ( Oid ) PQoidValue(( PGresult * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQOIDSTATUS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retc( PQoidStatus(( PGresult * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQBINARYTUPLES)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retl( PQbinaryTuples(( PGresult * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQFTABLE)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retnl( ( Oid ) PQftable(( PGresult * ) hb_parptr(1), hb_parni(2) - 1 ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQFTYPE)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retnl( ( Oid ) PQftype(( PGresult * ) hb_parptr(1), hb_parni(2) - 1 ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQFNAME)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retc( PQfname(( PGresult * ) hb_parptr(1), hb_parni(2) - 1 ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQFMOD)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retni( PQfmod(( PGresult * ) hb_parptr(1), hb_parni(2) - 1 ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQFSIZE)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retni( PQfsize(( PGresult * ) hb_parptr(1), hb_parni(2) - 1 ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQGETISNULL)
|
||||
{
|
||||
if (hb_pcount() == 3)
|
||||
hb_retl( PQgetisnull(( PGresult * ) hb_parptr(1), hb_parni(2) - 1 , hb_parni(3) - 1));
|
||||
}
|
||||
|
||||
HB_FUNC(PQFNUMBER)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retni( PQfnumber(( PGresult * ) hb_parptr(1), hb_parcx(2) ) + 1);
|
||||
}
|
||||
|
||||
HB_FUNC(PQNTUPLES)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retnl( PQntuples(( PGresult * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
HB_FUNC(PQNFIELDS)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retnl( PQnfields(( PGresult * ) hb_parptr(1) ));
|
||||
}
|
||||
|
||||
/*
|
||||
* Asynchronous functions
|
||||
*/
|
||||
|
||||
HB_FUNC(PQSENDQUERY)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (hb_pcount() == 2)
|
||||
res = PQsendQuery(( PGconn * ) hb_parptr(1), hb_parcx(2));
|
||||
|
||||
hb_retl( res );
|
||||
}
|
||||
|
||||
HB_FUNC(PQGETRESULT)
|
||||
{
|
||||
PGresult *res = NULL;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
res = PQgetResult(( PGconn * ) hb_parptr(1));
|
||||
|
||||
/* when null, no more result to catch */
|
||||
if (res)
|
||||
hb_retptr( res );
|
||||
}
|
||||
|
||||
HB_FUNC(PQCONSUMEINPUT)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
res = PQconsumeInput(( PGconn * ) hb_parptr(1));
|
||||
|
||||
hb_retl( res );
|
||||
}
|
||||
|
||||
HB_FUNC(PQISBUSY)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
res = PQisBusy(( PGconn * ) hb_parptr(1));
|
||||
|
||||
hb_retl( res );
|
||||
}
|
||||
|
||||
HB_FUNC(PQREQUESTCANCEL) /* deprecated */
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
res = PQrequestCancel(( PGconn * ) hb_parptr(1));
|
||||
|
||||
hb_retl( res );
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQFLUSH)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni( PQflush(( PGconn * ) hb_parptr(1)) );
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(PQSETNONBLOCKING)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
hb_retl( PQsetnonblocking( ( PGconn * ) hb_parptr(1), hb_parl(2) ) );
|
||||
}
|
||||
|
||||
HB_FUNC(PQISNONBLOCKING)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retl( PQisnonblocking( ( PGconn * ) hb_parptr(1) ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Trace Connection handling functions
|
||||
*/
|
||||
|
||||
HB_FUNC(PQCREATETRACE)
|
||||
{
|
||||
FILE * pFile;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
{
|
||||
pFile = fopen( hb_parcx(1), "w+b");
|
||||
|
||||
if (pFile != NULL)
|
||||
hb_retptr( ( FILE * ) pFile );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC(PQCLOSETRACE)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
fclose( ( FILE * ) hb_parptr(1) );
|
||||
}
|
||||
|
||||
HB_FUNC(PQTRACE)
|
||||
{
|
||||
if (hb_pcount() == 2)
|
||||
PQtrace( ( PGconn * ) hb_parptr(1), ( FILE * ) hb_parptr(2) );
|
||||
}
|
||||
|
||||
HB_FUNC(PQUNTRACE)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
PQuntrace( ( PGconn * ) hb_parptr(1) );
|
||||
}
|
||||
|
||||
HB_FUNC(PQSETERRORVERBOSITY)
|
||||
{
|
||||
/* PQERRORS_TERSE 0
|
||||
PQERRORS_DEFAULT 1
|
||||
PQERRORS_VERBOSE 2
|
||||
*/
|
||||
|
||||
if (hb_pcount() == 2)
|
||||
hb_retni( ( PGVerbosity ) PQsetErrorVerbosity( ( PGconn * ) hb_parptr(1), ( PGVerbosity ) hb_parni(2) ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Large Object functions
|
||||
*/
|
||||
|
||||
|
||||
HB_FUNC(LO_IMPORT)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hb_pcount() == 2)
|
||||
ret = lo_import( ( PGconn * ) hb_parptr(1), hb_parcx(2) );
|
||||
|
||||
hb_retni(ret);
|
||||
}
|
||||
|
||||
HB_FUNC(LO_EXPORT)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hb_pcount() == 3)
|
||||
{
|
||||
ret = lo_export( ( PGconn * ) hb_parptr(1), ( Oid ) hb_parnl(2), hb_parcx(3) );
|
||||
|
||||
if (ret != 1)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
hb_retl(ret);
|
||||
}
|
||||
|
||||
HB_FUNC(LO_UNLINK)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (hb_pcount() == 2)
|
||||
{
|
||||
ret = lo_unlink( ( PGconn * ) hb_parptr(1), ( Oid ) hb_parnl(2) );
|
||||
|
||||
if (ret != 1)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
hb_retl(ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if HB_PGVERSION >= 0x0800
|
||||
|
||||
HB_FUNC(PQSERVERVERSION)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retni(PQserverVersion(( PGconn * ) hb_parptr(1)));
|
||||
}
|
||||
|
||||
HB_FUNC(PQGETCANCEL)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
hb_retptr( ( PGcancel * ) PQgetCancel( ( PGconn * ) hb_parptr(1) ) );
|
||||
}
|
||||
|
||||
HB_FUNC(PQCANCEL)
|
||||
{
|
||||
char errbuf[256];
|
||||
int ret = 0;
|
||||
|
||||
if (hb_parinfo(1))
|
||||
if (PQcancel( ( PGcancel * ) hb_parptr(1), errbuf, 255) == 1)
|
||||
{
|
||||
ret = 1;
|
||||
hb_storc( errbuf, 2 );
|
||||
}
|
||||
|
||||
hb_retl(ret);
|
||||
}
|
||||
|
||||
HB_FUNC(PQFREECANCEL)
|
||||
{
|
||||
if (hb_parinfo(1))
|
||||
PQfreeCancel( ( PGcancel * ) hb_parptr(1) ) ;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
TODO: Implement Full Large Objects Support
|
||||
TODO: Implement Prepared Query handling
|
||||
|
||||
extern int lo_open(PGconn *conn, Oid lobjId, int mode);
|
||||
extern int lo_close(PGconn *conn, int fd);
|
||||
extern int lo_read(PGconn *conn, int fd, char *buf, size_t len);
|
||||
extern int lo_write(PGconn *conn, int fd, char *buf, size_t len);
|
||||
extern int lo_lseek(PGconn *conn, int fd, int offset, int whence);
|
||||
extern Oid lo_creat(PGconn *conn, int mode);
|
||||
extern int lo_tell(PGconn *conn, int fd);
|
||||
|
||||
PGresult *PQprepare(PGconn *conn,
|
||||
const char *stmtName,
|
||||
const char *query,
|
||||
int nParams,
|
||||
const Oid *paramTypes);
|
||||
|
||||
|
||||
PGresult *PQexecPrepared(PGconn *conn,
|
||||
const char *stmtName,
|
||||
int nParams,
|
||||
const char * const *paramValues,
|
||||
const int *paramLengths,
|
||||
const int *paramFormats,
|
||||
int resultFormat);
|
||||
|
||||
int PQsendQueryParams(PGconn *conn,
|
||||
const char *command,
|
||||
int nParams,
|
||||
const Oid *paramTypes,
|
||||
const char * const *paramValues,
|
||||
const int *paramLengths,
|
||||
const int *paramFormats,
|
||||
int resultFormat);
|
||||
|
||||
int PQsendPrepare(PGconn *conn,
|
||||
const char *stmtName,
|
||||
const char *query,
|
||||
int nParams,
|
||||
const Oid *paramTypes);
|
||||
|
||||
int PQsendQueryPrepared(PGconn *conn,
|
||||
const char *stmtName,
|
||||
int nParams,
|
||||
const char * const *paramValues,
|
||||
const int *paramLengths,
|
||||
const int *paramFormats,
|
||||
int resultFormat);
|
||||
|
||||
*/
|
||||
28
harbour/contrib/pgsql/postgres.ch
Normal file
28
harbour/contrib/pgsql/postgres.ch
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#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
|
||||
32
harbour/contrib/pgsql/tests/Makefile
Normal file
32
harbour/contrib/pgsql/tests/Makefile
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
ifeq ($(HB_MAIN),)
|
||||
HB_MAIN = std
|
||||
endif
|
||||
|
||||
ROOT = ../../../
|
||||
|
||||
CONTRIBS=\
|
||||
postgres \
|
||||
|
||||
PRG_SOURCES=\
|
||||
test.prg \
|
||||
|
||||
PRG_MAIN=\
|
||||
test.prg
|
||||
|
||||
LIBS=\
|
||||
debug \
|
||||
vm \
|
||||
rtl \
|
||||
lang \
|
||||
rdd \
|
||||
rtl \
|
||||
vm \
|
||||
macro \
|
||||
common \
|
||||
pq \
|
||||
|
||||
include $(TOP)$(ROOT)config/bin.cf
|
||||
72
harbour/contrib/pgsql/tests/async.prg
Normal file
72
harbour/contrib/pgsql/tests/async.prg
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* This sample show howto use asynchronous/nonblocking queries
|
||||
*
|
||||
*/
|
||||
|
||||
Function main()
|
||||
Local conn
|
||||
|
||||
CLEAR SCREEN
|
||||
|
||||
? "Connect", conn := PQConnect('test', 'localhost', 'user', 'pass', 5432)
|
||||
|
||||
? "Conection status", PQerrorMessage(conn), PQstatus(conn)
|
||||
|
||||
Query( conn, 'SELECT codigo, descri FROM client limit 100', .f. )
|
||||
Query( conn, 'SELECT codigo, descri FROM fornec limit 100', .f. )
|
||||
Query( conn, 'SELECT pedido, vlrped FROM pedido', .t. )
|
||||
|
||||
PQclose(conn)
|
||||
|
||||
return nil
|
||||
|
||||
Procedure Query( conn, cQuery, lCancel )
|
||||
Local pCancel, cErrMsg := space(30)
|
||||
Local res, aTemp, i, x, y, xTime
|
||||
|
||||
? "PQSendQuery", PQsendQuery(conn, cQuery)
|
||||
|
||||
xTime := time()
|
||||
CLEAR TYPEAHEAD
|
||||
|
||||
do while inkey() != 27
|
||||
DevPos(Row(), 20)
|
||||
DevOut("Processing: " + Elaptime(xtime, time()))
|
||||
|
||||
inkey(1)
|
||||
|
||||
if lCancel
|
||||
if .t.
|
||||
pCancel := PQgetCancel(conn)
|
||||
? "Canceled: ", PQcancel( pCancel, @cErrMsg ), cErrMsg
|
||||
PQfreeCancel(pCancel)
|
||||
|
||||
else
|
||||
? PQrequestCancel(conn) // Deprecated
|
||||
endif
|
||||
endif
|
||||
|
||||
if PQconsumeInput(conn)
|
||||
if ! PQisBusy(conn)
|
||||
exit
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
|
||||
if inkey() != 27
|
||||
? "PQgetResult", valtoprg(res := PQgetResult(conn))
|
||||
|
||||
for x := 1 to PQlastrec(res)
|
||||
?
|
||||
for y := 1 to PQfcount(res)
|
||||
?? PQgetvalue(res, x, y), " "
|
||||
next
|
||||
next
|
||||
|
||||
PQclear(res)
|
||||
else
|
||||
? "Canceling Query", PQrequestCancel(conn)
|
||||
endif
|
||||
Return
|
||||
648
harbour/contrib/pgsql/tests/cache.prg
Normal file
648
harbour/contrib/pgsql/tests/cache.prg
Normal file
@@ -0,0 +1,648 @@
|
||||
/*
|
||||
* $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()
|
||||
Local i
|
||||
Local cQuery
|
||||
Local conn, res
|
||||
|
||||
SetMode( 25, 80 )
|
||||
|
||||
if SQLConnect( '127.0.0.1', 'test', 'sysadm', 'masterkey' )
|
||||
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:Error()
|
||||
|
||||
lError := oQuery:NetErr()
|
||||
|
||||
endif
|
||||
|
||||
ELSE
|
||||
|
||||
|
||||
|
||||
oRow := oQuery:GetRow(i)
|
||||
|
||||
lUpdate := .F.
|
||||
|
||||
|
||||
|
||||
IF Deleted()
|
||||
|
||||
oQuery:Delete(oRow)
|
||||
|
||||
cError := oQuery:Error()
|
||||
|
||||
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:Error()
|
||||
|
||||
lError := oQuery:NetErr()
|
||||
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
END
|
||||
|
||||
|
||||
|
||||
if lError
|
||||
|
||||
exit
|
||||
|
||||
end
|
||||
|
||||
NEXT
|
||||
|
||||
END
|
||||
|
||||
|
||||
IF lError
|
||||
Alert(cError)
|
||||
END
|
||||
|
||||
Return ! lError
|
||||
|
||||
|
||||
Procedure SQLCloseTemp( cAlias )
|
||||
Local x
|
||||
|
||||
IF ! Empty(Select(cAlias))
|
||||
CLOSE &calias
|
||||
END
|
||||
|
||||
x := ASCAN(aTableTemp, {|aVal| aVal[DB_ALIAS] == cAlias})
|
||||
|
||||
IF ! Empty(x)
|
||||
ADel( aTableTemp, x )
|
||||
//ASize( aTableTemp, Len(aTableTemp) - 1 )
|
||||
END
|
||||
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 ! ISNIL(oQuery)
|
||||
oQuery:Destroy()
|
||||
END
|
||||
|
||||
NEXT
|
||||
|
||||
FOR i := 1 TO Len(aTempDBF)
|
||||
IF File(aTempDBF[i])
|
||||
FErase(aTempDBF[i])
|
||||
END
|
||||
|
||||
IF File(strtran(aTempDBF[i], '.tmp', '.dbf'))
|
||||
FErase(strtran(aTempDBF[i], '.tmp', '.dbf'))
|
||||
END
|
||||
|
||||
IF File(strtran(aTempDBF[i], '.tmp', '.dbt'))
|
||||
FErase(strtran(aTempDBF[i], '.tmp', '.dbt'))
|
||||
END
|
||||
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.
|
||||
end
|
||||
|
||||
IF oQuery:Lastrec() >= nPos
|
||||
|
||||
y := nPos
|
||||
|
||||
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++
|
||||
end
|
||||
|
||||
ELSE
|
||||
// Posiciona registro no eof
|
||||
DBSkip()
|
||||
|
||||
END
|
||||
|
||||
lEof := nPos > oQuery:Lastrec()
|
||||
END
|
||||
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()
|
||||
END
|
||||
|
||||
IF ISNIL(cQuery)
|
||||
cQuery := 'SELECT * FROM ' + cAlias + ' ORDER BY ' + cOrder
|
||||
END
|
||||
|
||||
cQuery := cQuery
|
||||
oQuery := oServer:Query(cQuery)
|
||||
|
||||
IF oQuery:NetErr()
|
||||
Alert(oQuery:Error())
|
||||
RETURN .F.
|
||||
END
|
||||
|
||||
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
|
||||
|
||||
END
|
||||
|
||||
IF ! ISNIL(xFetch)
|
||||
lFetch := xFetch
|
||||
ELSE
|
||||
lFetch := .F.
|
||||
END
|
||||
|
||||
/* 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
|
||||
|
||||
END
|
||||
|
||||
/* Traz registros da base de dados */
|
||||
SQLFetch(lFetch)
|
||||
|
||||
IF lFetch
|
||||
DBGotop()
|
||||
END
|
||||
|
||||
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:Error())
|
||||
lRetval := .f.
|
||||
end
|
||||
oServer:lAllCols := .F.
|
||||
Return lRetval
|
||||
|
||||
|
||||
Procedure SQLDestroy()
|
||||
if ! ISNIL(oServer)
|
||||
oServer:Destroy()
|
||||
end
|
||||
return
|
||||
|
||||
|
||||
Function SQLCurrentServer
|
||||
Return oServer
|
||||
|
||||
|
||||
Function SQLQuery( cQuery )
|
||||
Local oQuery
|
||||
|
||||
oQuery := oServer:Query(cQuery)
|
||||
IF oQuery:NetErr()
|
||||
Alert(cQuery + ':' + oQuery:Error())
|
||||
END
|
||||
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:Error())
|
||||
|
||||
result := .F.
|
||||
|
||||
ELSE
|
||||
oQuery:Destroy()
|
||||
|
||||
END
|
||||
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 := PValue(i)
|
||||
|
||||
if ! ISNIL(x) .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'
|
||||
end
|
||||
|
||||
cQuery := strtran(cQuery, '{:' + ltrim(str(i-1)) + '}', x)
|
||||
next
|
||||
end
|
||||
|
||||
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 := ''; END
|
||||
|
||||
IF ';' $ xDirectory
|
||||
xDirectory := LEFT( xDirectory, AT( ';', xDirectory ) - 1 )
|
||||
END
|
||||
|
||||
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
|
||||
END
|
||||
Return cString
|
||||
|
||||
|
||||
Function DtoQ(cData)
|
||||
Return "'" + Str(Year(cData),4) + "-" + StrZero(Month(cData), 2) + "-" + StrZero(Day(cData), 2) + "'"
|
||||
|
||||
Function StoQ(cData)
|
||||
Return "'" + cData + "'"
|
||||
|
||||
325
harbour/contrib/pgsql/tests/dbf2pg.prg
Normal file
325
harbour/contrib/pgsql/tests/dbf2pg.prg
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Harbour Project source code:
|
||||
* dbf2pg.prg - converts a .dbf file into a Postgres table
|
||||
*
|
||||
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
|
||||
* www - http://www.harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
||||
*
|
||||
* As a special exception, the Harbour Project gives permission for
|
||||
* additional uses of the text contained in its release of Harbour.
|
||||
*
|
||||
* The exception is that, if you link the Harbour libraries with other
|
||||
* files to produce an executable, this does not by itself cause the
|
||||
* resulting executable to be covered by the GNU General Public License.
|
||||
* Your use of that executable is in no way restricted on account of
|
||||
* linking the Harbour library code into it.
|
||||
*
|
||||
* This exception does not however invalidate any other reasons why
|
||||
* the executable file might be covered by the GNU General Public License.
|
||||
*
|
||||
* This exception applies only to the code released by the Harbour
|
||||
* Project under the name Harbour. If you copy code from other
|
||||
* Harbour Project or Free Software Foundation releases into a copy of
|
||||
* Harbour, as the General Public License permits, the exception does
|
||||
* not apply to the code that you add in this way. To avoid misleading
|
||||
* anyone as to the status of such modified files, you must delete
|
||||
* this exception notice from them.
|
||||
*
|
||||
* If you write modifications of your own for Harbour, it is your choice
|
||||
* whether to permit this exception to apply to your modifications.
|
||||
* If you do not wish that, delete this exception notice.
|
||||
*
|
||||
* The Original file was ported from Mysql and changed by Rodrigo Moreno rodrigo_moreno@yahoo.com
|
||||
*
|
||||
*/
|
||||
|
||||
#include "inkey.ch"
|
||||
#include "common.ch"
|
||||
|
||||
#define CRLF chr(13) + chr(10)
|
||||
|
||||
procedure main(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20)
|
||||
|
||||
local cTok, nTok := 1
|
||||
local cHostName := "localhost"
|
||||
local cUser := "postgres"
|
||||
local cPassWord := ""
|
||||
local cDataBase, cTable, cFile
|
||||
local aDbfStruct, i
|
||||
local lCreateTable := .F.
|
||||
local oServer, oTable, oRecord
|
||||
Local cField
|
||||
Local sType
|
||||
Local dType
|
||||
Local cValue
|
||||
Local nCommit := 100
|
||||
Local nHandle
|
||||
Local nCount := 0
|
||||
Local nRecno := 0
|
||||
Local lTruncate := .F.
|
||||
Local lUseTrans := .F.
|
||||
Local cPath := 'public'
|
||||
|
||||
SET CENTURY ON
|
||||
SET EPOCH TO 1960
|
||||
SET DELETE ON
|
||||
SET DATE FORMAT "dd/mm/yyyy"
|
||||
|
||||
rddSetDefault( "DBFDBT" )
|
||||
|
||||
if PCount() < 6
|
||||
help()
|
||||
quit
|
||||
endif
|
||||
|
||||
i := 1
|
||||
// Scan parameters and setup workings
|
||||
while (i <= PCount())
|
||||
|
||||
cTok := PValue(i++)
|
||||
|
||||
do case
|
||||
case cTok == "-h"
|
||||
cHostName := PValue(i++)
|
||||
|
||||
case cTok == "-d"
|
||||
cDataBase := PValue(i++)
|
||||
|
||||
case cTok == "-t"
|
||||
cTable := PValue(i++)
|
||||
|
||||
case cTok == "-f"
|
||||
cFile := PValue(i++)
|
||||
|
||||
case cTok == "-u"
|
||||
cUser := PValue(i++)
|
||||
|
||||
case cTok == "-p"
|
||||
cPassWord := PValue(i++)
|
||||
|
||||
case cTok == "-c"
|
||||
lCreateTable := .T.
|
||||
|
||||
case cTok == "-x"
|
||||
lTruncate := .T.
|
||||
|
||||
case cTok == "-s"
|
||||
lUseTrans := .T.
|
||||
|
||||
case cTok == "-m"
|
||||
nCommit := val(PValue(i++))
|
||||
|
||||
case cTok == "-r"
|
||||
nRecno := val(PValue(i++))
|
||||
|
||||
case cTok == "-e"
|
||||
cPath := PValue(i++)
|
||||
|
||||
otherwise
|
||||
help()
|
||||
quit
|
||||
endcase
|
||||
enddo
|
||||
|
||||
// create log file
|
||||
if (nHandle := FCreate(Trim(cTable) + '.log')) == -1
|
||||
? 'Cannot create log file'
|
||||
quit
|
||||
endif
|
||||
|
||||
USE (cFile) SHARED
|
||||
aDbfStruct := DBStruct()
|
||||
|
||||
oServer := TPQServer():New(cHostName, cDatabase, cUser, cPassWord, nil, cPath)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
quit
|
||||
endif
|
||||
|
||||
oServer:lallCols := .F.
|
||||
|
||||
if lCreateTable
|
||||
if oServer:TableExists(cTable)
|
||||
oServer:DeleteTable(cTable)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
FWrite( nHandle, "Error: " + oServer:Error() + CRLF )
|
||||
FClose( nHandle )
|
||||
quit
|
||||
endif
|
||||
endif
|
||||
oServer:CreateTable(cTable, aDbfStruct)
|
||||
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
FWrite( nHandle, "Error: " + oServer:Error() + CRLF )
|
||||
FClose( nHandle )
|
||||
quit
|
||||
endif
|
||||
endif
|
||||
|
||||
if lTruncate
|
||||
oServer:Execute('truncate table ' + cTable)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
FWrite( nHandle, "Error: " + oServer:Error() + CRLF )
|
||||
FClose( nHandle )
|
||||
quit
|
||||
endif
|
||||
endif
|
||||
|
||||
oTable := oServer:Query("SELECT * FROM " + cTable + " LIMIT 1")
|
||||
if oTable:NetErr()
|
||||
Alert(oTable:Error())
|
||||
FWrite( nHandle, "Error: " + oTable:Error() + CRLF )
|
||||
FClose( nHandle )
|
||||
quit
|
||||
endif
|
||||
|
||||
if lUseTrans
|
||||
oServer:StartTransaction()
|
||||
endif
|
||||
|
||||
FWrite( nHandle, "Start: " + time() + CRLF )
|
||||
|
||||
? "Start: ", time()
|
||||
?
|
||||
|
||||
if ! Empty(nRecno)
|
||||
dbgoto(nRecno)
|
||||
endif
|
||||
|
||||
while ! eof() .and. Inkey() <> K_ESC .and. (empty(nRecno) .or. nRecno == recno())
|
||||
oRecord := oTable:GetBlankRow()
|
||||
|
||||
for i := 1 to oTable:FCount()
|
||||
cField := lower(oTable:FieldName(i))
|
||||
sType := fieldtype(fieldpos(cField))
|
||||
dType := oRecord:Fieldtype(i)
|
||||
cValue := fieldget(fieldpos(cField))
|
||||
|
||||
if ! ISNIL(cValue)
|
||||
if dType != sType
|
||||
if dType == 'C' .and. sType == 'N'
|
||||
cValue := Str(cValue)
|
||||
|
||||
elseif dType == 'C' .and. sType == 'D'
|
||||
cValue := DtoC(cValue)
|
||||
|
||||
elseif dType == 'C' .and. sType == 'L'
|
||||
cValue := IIF( cValue, "S", "N" )
|
||||
|
||||
elseif dType == 'N' .and. sType == 'C'
|
||||
cValue := val(cValue)
|
||||
|
||||
elseif dType == 'N' .and. sType == 'D'
|
||||
cValue := Val(DtoS(cValue))
|
||||
|
||||
elseif dType == 'N' .and. sType == 'L'
|
||||
cValue := IIF( cValue, 1, 0 )
|
||||
|
||||
elseif dType == 'D' .and. sType == 'C'
|
||||
cValue := CtoD(cValue)
|
||||
|
||||
elseif dType == 'D' .and. sType == 'N'
|
||||
cValue := StoD(Str(cValue))
|
||||
|
||||
elseif dType == 'L' .and. sType == 'N'
|
||||
cValue := ! Empty(cValue)
|
||||
|
||||
elseif dType == 'L' .and. sType == 'C'
|
||||
cValue := IIF( alltrim(cValue) $ "YySs1", .T., .F. )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if ! ISNIL(cValue)
|
||||
if oRecord:Fieldtype(i) == 'C' .or. oRecord:Fieldtype(i) == 'M'
|
||||
oRecord:FieldPut(i, hb_oemtoansi(cValue))
|
||||
else
|
||||
oRecord:FieldPut(i, cValue)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
next
|
||||
|
||||
oTable:Append(oRecord)
|
||||
|
||||
if oTable:NetErr()
|
||||
?
|
||||
? "Error Record: ", recno(), left(oTable:Error(),70)
|
||||
?
|
||||
FWrite( nHandle, "Error at record: " + Str(recno()) + " Description: " + oTable:Error() + CRLF )
|
||||
else
|
||||
nCount++
|
||||
endif
|
||||
|
||||
dbSkip()
|
||||
|
||||
if (nCount % nCommit) == 0
|
||||
DevPos(Row(), 1)
|
||||
DevOut("imported recs: " + Str(nCount))
|
||||
|
||||
if lUseTrans
|
||||
oServer:commit()
|
||||
oServer:StartTransaction()
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
|
||||
if (nCount % nCommit) != 0
|
||||
if lUseTrans
|
||||
oServer:commit()
|
||||
endif
|
||||
endif
|
||||
|
||||
FWrite( nHandle, "End: " + time() + ", records in dbf: " + ltrim(str(recno())) + ", imported recs: " + ltrim(str(nCount)) + CRLF )
|
||||
|
||||
? "End: ", time()
|
||||
?
|
||||
|
||||
FClose( nHandle )
|
||||
|
||||
close all
|
||||
oTable:Destroy()
|
||||
oServer:Destroy()
|
||||
return
|
||||
|
||||
|
||||
procedure Help()
|
||||
|
||||
? "dbf2pg - dbf file to PostgreSQL table conversion utility"
|
||||
? "-h hostname (default: localhost)"
|
||||
? "-u user (default: root)"
|
||||
? "-p password (default no password)"
|
||||
? "-d name of database to use"
|
||||
? "-t name of table to add records to"
|
||||
? "-c delete existing table and create a new one"
|
||||
? "-f name of .dbf file to import"
|
||||
? "-x truncate table before append records"
|
||||
? "-s use transaction"
|
||||
? "-m commit interval"
|
||||
? "-r insert only record number"
|
||||
? "-e search path"
|
||||
|
||||
? ""
|
||||
|
||||
return
|
||||
180
harbour/contrib/pgsql/tests/simple.prg
Normal file
180
harbour/contrib/pgsql/tests/simple.prg
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.ch"
|
||||
|
||||
Function main()
|
||||
Local oServer, oQuery, oRow, i, x, aTables, aStruct, aKey
|
||||
|
||||
Local cHost := 'localhost'
|
||||
Local cDatabase := 'test'
|
||||
Local cUser := 'user'
|
||||
Local cPass := 'pass'
|
||||
Local cQuery
|
||||
|
||||
oServer := TPQServer():New(cHost, cDatabase, cUser, cPass)
|
||||
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
quit
|
||||
end
|
||||
|
||||
oServer:SetVerbosity(2)
|
||||
oServer:traceon('lixo.log')
|
||||
|
||||
? 'Tables...'
|
||||
|
||||
For x := 1 to 1
|
||||
aTables := oServer:ListTables()
|
||||
|
||||
For i := 1 to Len(aTables)
|
||||
? aTables[i]
|
||||
next
|
||||
Next
|
||||
|
||||
if oServer:TableExists('TEST')
|
||||
? oQuery := oServer:Execute('DROP TABLE Test')
|
||||
|
||||
oQuery:Destroy()
|
||||
end
|
||||
|
||||
? 'Creating test table...'
|
||||
cQuery := 'CREATE TABLE test('
|
||||
cQuery += ' Code integer not null primary key, '
|
||||
cQuery += ' dept Integer, '
|
||||
cQuery += ' Name Varchar(40), '
|
||||
cQuery += ' Sales boolean, '
|
||||
cQuery += ' Tax Float4, '
|
||||
cQuery += ' Salary Double Precision, '
|
||||
cQuery += ' Budget Numeric(12,2), '
|
||||
cQuery += ' Discount Numeric (5,2), '
|
||||
cQuery += ' Creation Date, '
|
||||
cQuery += ' Description text ) '
|
||||
|
||||
oQuery := oServer:Query(cQuery)
|
||||
|
||||
if oQuery:neterr()
|
||||
? oQuery:Error()
|
||||
end
|
||||
|
||||
oQuery:Destroy()
|
||||
|
||||
? 'Structure of test table'
|
||||
aStruct := oServer:TableStruct('test')
|
||||
|
||||
For i := 1 to Len(aStruct)
|
||||
?
|
||||
For x := 1 to Len(aStruct[i])
|
||||
?? aStruct[i,x], " "
|
||||
Next
|
||||
next
|
||||
|
||||
? 'Inserting, declared transaction control '
|
||||
oServer:StartTransaction()
|
||||
|
||||
For i := 1 to 10
|
||||
cQuery := "INSERT INTO test(code, dept, name, sales, tax, salary, budget, Discount, Creation, Description) "
|
||||
cQuery += "VALUES( " + str(i) + ", 2, 'TEST', 'y', 5, 3000, 1500.2, 7.5, '12-22-2003', 'Short Description about what ? ')"
|
||||
|
||||
oQuery := oServer:Query(cQuery)
|
||||
|
||||
if oQuery:neterr()
|
||||
? oQuery:error()
|
||||
end
|
||||
|
||||
oQuery:destroy()
|
||||
Next
|
||||
|
||||
oServer:Commit()
|
||||
|
||||
oQuery := oServer:Query('SELECT code, name, description, sales FROM test')
|
||||
|
||||
|
||||
aStruct := oQuery:Struct()
|
||||
|
||||
For i := 1 to Len(aStruct)
|
||||
? aStruct[i,1], aStruct[i,2], aStruct[i,3], aStruct[i,4]
|
||||
Next
|
||||
|
||||
aKey := oQuery:GetKeyField()
|
||||
|
||||
? "Fields: ", oQuery:Fcount(), "Primary Key: ", aKey[1]
|
||||
|
||||
oRow := oQuery:Blank()
|
||||
|
||||
? oRow:FCount(), ;
|
||||
oRow:Fieldpos('sales'), ;
|
||||
oRow:Fieldget(1), ;
|
||||
oRow:Fieldname(2), ;
|
||||
oRow:Fieldtype(1), ;
|
||||
oRow:Fielddec(1), ;
|
||||
oRow:Fieldlen(1)
|
||||
|
||||
oRow:Fieldput(1, 150)
|
||||
oRow:Fieldput(2, 'MY TEST')
|
||||
|
||||
? oRow:Fieldget(1), oRow:Fieldget(2)
|
||||
|
||||
? oRow:aRow[1], oRow:aRow[2], oRow:aOld[1], oRow:aOld[2]
|
||||
|
||||
? oQuery:Append(oRow)
|
||||
|
||||
? oQuery:error()
|
||||
|
||||
DO WHILE ! oQuery:Eof()
|
||||
? oQuery:Recno(),;
|
||||
oQuery:Fieldpos('code'),;
|
||||
oQuery:Fieldget(oQuery:Fieldpos('code')), ;
|
||||
oQuery:Fieldget(4), ;
|
||||
oQuery:Fieldget(2), ;
|
||||
oQuery:Fieldname(1),;
|
||||
oQuery:Fieldtype(1), ;
|
||||
oQuery:Fielddec(1), ;
|
||||
oQuery:Fieldlen(1),;
|
||||
oQuery:Fieldget(3)
|
||||
|
||||
if oQuery:Recno() == 50
|
||||
oRow := oQuery:getrow()
|
||||
|
||||
oRow:Fieldput(2, 'My Second test')
|
||||
? 'Update: ', oQuery:Update(oRow)
|
||||
end
|
||||
|
||||
if oQuery:Recno() == 60
|
||||
oRow := oQuery:getrow()
|
||||
? 'Delete: ', oQuery:Delete(oRow)
|
||||
end
|
||||
|
||||
oQuery:Skip()
|
||||
|
||||
END
|
||||
|
||||
oQuery:Refresh()
|
||||
|
||||
For i := 1 to oQuery:Lastrec()
|
||||
oRow := oQuery:getrow(i)
|
||||
|
||||
? i, oRow:Fieldget(oRow:Fieldpos('code')), ;
|
||||
oRow:Fieldget(4), ;
|
||||
oRow:Fieldget(2), ;
|
||||
oRow:Fieldname(1),;
|
||||
oRow:Fieldtype(1), ;
|
||||
oRow:Fielddec(1), ;
|
||||
oRow:Fieldlen(1),;
|
||||
oRow:Fieldget(i, 3)
|
||||
|
||||
END
|
||||
|
||||
oQuery:Destroy()
|
||||
|
||||
oServer:Destroy()
|
||||
|
||||
? "Closing..."
|
||||
|
||||
return nil
|
||||
|
||||
|
||||
|
||||
131
harbour/contrib/pgsql/tests/stress.prg
Normal file
131
harbour/contrib/pgsql/tests/stress.prg
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* VERY IMPORTANT: Don't use this querys as sample, they are used for stress tests !!!
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.ch"
|
||||
#include "../postgres.ch"
|
||||
|
||||
Function Main()
|
||||
Local conn, res, oRow, i, x
|
||||
|
||||
Local cServer := '192.168.1.20'
|
||||
Local cDatabase := 'test'
|
||||
Local cUser := 'rodrigo'
|
||||
Local cPass := 'moreno'
|
||||
Local cQuery
|
||||
|
||||
CLEAR SCREEN
|
||||
|
||||
? 'Connecting....'
|
||||
conn := PQconnect(cDatabase, cServer, cUser, cPass, 5432)
|
||||
|
||||
? PQstatus(conn), PQerrormessage(conn)
|
||||
|
||||
if PQstatus(conn) != CONNECTION_OK
|
||||
quit
|
||||
endif
|
||||
|
||||
? 'Dropping table...'
|
||||
|
||||
res := PQexec(conn, 'DROP TABLE test')
|
||||
PQclear(res)
|
||||
|
||||
? 'Creating test table...'
|
||||
cQuery := 'CREATE TABLE test('
|
||||
cQuery += ' Code integer not null primary key, '
|
||||
cQuery += ' dept Integer, '
|
||||
cQuery += ' Name Varchar(40), '
|
||||
cQuery += ' Sales boolean, '
|
||||
cQuery += ' Tax Float4, '
|
||||
cQuery += ' Salary Double Precision, '
|
||||
cQuery += ' Budget Numeric(12,2), '
|
||||
cQuery += ' Discount Numeric (5,2), '
|
||||
cQuery += ' Creation Date, '
|
||||
cQuery += ' Description text ) '
|
||||
|
||||
res := PQexec(conn, cQuery)
|
||||
PQclear(res)
|
||||
|
||||
res := PQexec(conn, 'SELECT code, dept, name, sales, salary, creation FROM test')
|
||||
PQclear(res)
|
||||
|
||||
res := PQexec(conn, 'BEGIN')
|
||||
PQclear(res)
|
||||
|
||||
For i := 1 to 10000
|
||||
@ 15,0 say 'Inserting values....' + str(i)
|
||||
|
||||
cQuery := 'INSERT INTO test(code, dept, name, sales, salary, creation) '
|
||||
cQuery += 'VALUES( ' + str(i) + ',' + str(i+1) + ", 'DEPARTMENT NAME " + strzero(i) + "', 'y', " + str(300.49+i) + ", '2003-12-28' )"
|
||||
|
||||
res := PQexec(conn, cQuery)
|
||||
PQclear(res)
|
||||
|
||||
if mod(i,100) == 0
|
||||
? res := PQexec(conn, 'COMMIT')
|
||||
? PQclear(res)
|
||||
|
||||
? res := PQexec(conn, 'BEGIN')
|
||||
? PQclear(res)
|
||||
end
|
||||
Next
|
||||
|
||||
For i := 5000 to 7000
|
||||
@ 16,0 say 'Deleting values....' + str(i)
|
||||
|
||||
cQuery := 'DELETE FROM test WHERE code = ' + str(i)
|
||||
res := PQexec(conn, cQuery)
|
||||
PQclear(res)
|
||||
|
||||
if mod(i,100) == 0
|
||||
res := PQexec(conn, 'COMMIT')
|
||||
PQclear(res)
|
||||
|
||||
res := PQexec(conn, 'BEGIN')
|
||||
PQclear(res)
|
||||
end
|
||||
Next
|
||||
|
||||
For i := 2000 to 3000
|
||||
@ 17,0 say 'Updating values....' + str(i)
|
||||
|
||||
cQuery := 'UPDATE FROM test SET salary = 400 WHERE code = ' + str(i)
|
||||
res := PQexec(conn, cQuery)
|
||||
PQclear(res)
|
||||
|
||||
if mod(i,100) == 0
|
||||
res := PQexec(conn, 'COMMIT')
|
||||
PQclear(res)
|
||||
|
||||
res := PQexec(conn, 'BEGIN')
|
||||
PQclear(res)
|
||||
end
|
||||
Next
|
||||
|
||||
res := PQexec(conn, 'SELECT sum(salary) as sum_salary FROM test WHERE code between 1 and 4000')
|
||||
|
||||
if PQresultStatus(res) == PGRES_TUPLES_OK
|
||||
@ 18,0 say 'Sum values....' + PQgetvalue(res, 1, 1)
|
||||
end
|
||||
|
||||
PQclear(res)
|
||||
|
||||
x := 0
|
||||
For i := 1 to 4000
|
||||
res := PQexec(conn, 'SELECT salary FROM test WHERE code = ' + str(i))
|
||||
|
||||
if PQresultStatus(res) == PGRES_TUPLES_OK
|
||||
x += val(PQgetvalue(res, 1, 1))
|
||||
|
||||
@ 19,0 say 'Sum values....' + str(x)
|
||||
end
|
||||
Next
|
||||
|
||||
? "Closing..."
|
||||
PQclose(conn)
|
||||
|
||||
return nil
|
||||
102
harbour/contrib/pgsql/tests/test.prg
Normal file
102
harbour/contrib/pgsql/tests/test.prg
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../postgres.ch"
|
||||
|
||||
Function main()
|
||||
Local conn, res, aTemp, i, x,y, pFile
|
||||
Local cDb := 'test'
|
||||
Local cUser := 'user'
|
||||
Local cPass := 'pass'
|
||||
|
||||
CLEAR SCREEN
|
||||
|
||||
conn := PQsetdbLogin( 'localhost', "5432", NIL, NIL, cDb, cUser, cPass)
|
||||
? PQdb(conn), PQuser(conn), PQpass(conn), PQhost(conn), PQport(conn), PQtty(conn), PQoptions(conn)
|
||||
? PQClose(conn)
|
||||
|
||||
conn := PQConnect(cDb, 'localhost', cuser, cpass, 5432)
|
||||
|
||||
? PQstatus(conn), PQerrormessage(conn)
|
||||
|
||||
if PQstatus(conn) != CONNECTION_OK
|
||||
quit
|
||||
endif
|
||||
|
||||
? "Blocking: ", PQisnonblocking(conn), PQsetnonblocking(conn, .t.), PQisnonblocking(conn)
|
||||
|
||||
pFile := PQcreatetrace( 'trace.log' )
|
||||
PQtrace( conn, pFile )
|
||||
|
||||
? "Verbose: ", PQsetErrorVerbosity(conn, 2)
|
||||
|
||||
? "Protocol: ", PQprotocolVersion(conn), ;
|
||||
" Server Version: ", PQserverVersion(conn), ;
|
||||
" Client Encoding: ", PQsetClientEncoding(conn, "ASCII"), ;
|
||||
"New encode: ", PQclientEncoding(conn)
|
||||
|
||||
? PQdb(conn), PQuser(conn), PQpass(conn), PQhost(conn), PQport(conn), PQtty(conn), PQoptions(conn)
|
||||
|
||||
res := PQexec('drop table products')
|
||||
? PQresultStatus(res), PQresultErrorMessage(res)
|
||||
PQclear(res)
|
||||
|
||||
res := PQexec('create table products ( product_no numeric(10), name varchar(20), price numeric(10,2) )')
|
||||
? PQresultStatus(res), PQresultErrorMessage(res)
|
||||
PQclear(res)
|
||||
|
||||
res := PQexecParams(conn, 'insert into products(product_no, name, price) values ($1, $2, $3)', {'2', 'bread', '10.95'})
|
||||
? "Oid Row: ", PQoidValue(res), PQoidStatus(res)
|
||||
|
||||
if PQresultStatus(res) != PGRES_COMMAND_OK
|
||||
? PQresultStatus(res), PQresultErrorMessage(res)
|
||||
endif
|
||||
PQclear(res)
|
||||
|
||||
res := PQexec(conn, 'select price, name, product_no as "produto" from products')
|
||||
|
||||
if PQresultStatus(res) != PGRES_TUPLES_OK
|
||||
? PQresultStatus(res), PQresultErrorMessage(res)
|
||||
endif
|
||||
|
||||
? "Binary: ", PQbinaryTuples(res)
|
||||
? "Rows: ", PQntuples(res), "Cols: ", PQnfields(res)
|
||||
? PQfname(res, 1), PQftable(res, 1), PQftype(res, 1), PQfnumber(res, "name"), PQfmod(res, 1), PQfsize(res, 1), PQgetisnull(res,1,1)
|
||||
|
||||
aTemp := PQmetadata(res)
|
||||
|
||||
for x := 1 to len(aTemp)
|
||||
? "Linha 1: "
|
||||
for y := 1 to 6
|
||||
?? aTemp[x,y], ", "
|
||||
next
|
||||
next
|
||||
|
||||
? PQFcount(res)
|
||||
|
||||
? PQlastrec(res)
|
||||
|
||||
? PQGetvalue(res,1, 2)
|
||||
|
||||
? PQclear(res)
|
||||
|
||||
? "Large Objects, always should be in a transaction..."
|
||||
|
||||
res := PQexec(conn, 'begin')
|
||||
PQclear(res)
|
||||
|
||||
? (x := lo_Import( conn, 'test.prg' ))
|
||||
? lo_Export( conn, x, 'test.new' )
|
||||
? lo_Unlink( conn, x )
|
||||
|
||||
res := PQexec(conn, 'commit')
|
||||
PQclear(res)
|
||||
|
||||
PQuntrace( conn )
|
||||
PQclosetrace( pFile )
|
||||
PQClose(conn)
|
||||
return nil
|
||||
|
||||
1321
harbour/contrib/pgsql/tpostgre.prg
Normal file
1321
harbour/contrib/pgsql/tpostgre.prg
Normal file
File diff suppressed because it is too large
Load Diff
90
harbour/contrib/pgsql/tstpgrdd.prg
Normal file
90
harbour/contrib/pgsql/tstpgrdd.prg
Normal file
@@ -0,0 +1,90 @@
|
||||
/* The aim of this test is to check the same RDD functions and statements against a dbf file
|
||||
and the same dbf imported into a PostgreSQL database.
|
||||
Replace <...> with your data and configuration.
|
||||
*/
|
||||
|
||||
|
||||
procedure main()
|
||||
|
||||
local nConn
|
||||
|
||||
set deleted on
|
||||
|
||||
request DBFCDX
|
||||
request PGRDD
|
||||
|
||||
use <table> index <index> exclusive via "dbfcdx"
|
||||
|
||||
set order to 1
|
||||
|
||||
test_code( "DBF" )
|
||||
|
||||
use
|
||||
|
||||
nConn := dbpgconnection( "<host>;<database>;<user>;<password>;<port>;<scheme>" )
|
||||
|
||||
/* if you want to update and insert data you need at least a primary key */
|
||||
|
||||
use "select <fields,...> from <table> order by <same order as dbf>" alias <table> via "pgrdd" connection nConn
|
||||
|
||||
test_code( "SQL" )
|
||||
|
||||
use
|
||||
|
||||
dbpgclearconnection( nConn )
|
||||
|
||||
return
|
||||
|
||||
function test_code( cMode )
|
||||
|
||||
local xTemp
|
||||
|
||||
<table>->( dbgotop() )
|
||||
? <table>-><field1>, <table>-><field2>, <table>-><field3>
|
||||
<table>->( dbgobottom() )
|
||||
? <table>-><field1>, <table>-><field2>, <table>-><field3>
|
||||
/* goto 100 has different meaning */
|
||||
<table>->( dbgoto( 100 ) )
|
||||
? <table>-><field1>, <table>-><field2>, <table>-><field3>
|
||||
xTemp := <table>-><field3>
|
||||
replace <table>-><field3> with "*** replaced ***"
|
||||
? <table>-><field1>, <table>-><field2>, <table>-><field3>
|
||||
replace <table>-><field3> with xTemp
|
||||
dbcommit() // the real write is made via dbcommit() so it is needed
|
||||
? <table>-><field1>, <table>-><field2>, <table>-><field3>
|
||||
? eof()
|
||||
dbgobottom()
|
||||
dbskip()
|
||||
? eof()
|
||||
? bof()
|
||||
dbgotop()
|
||||
dbskip(-1)
|
||||
? bof()
|
||||
|
||||
dbappend()
|
||||
replace <table>-><field1> with <"9">
|
||||
replace <table>-><field2> with <"999999">
|
||||
replace <table>-><field3> with <"APPENDED">
|
||||
dbcommit()
|
||||
|
||||
// recno() has different meaning, in SQL it is the number of the row and change for every select */
|
||||
? <table>->( recno() ), <table>-><field1>, <table>-><field2>, <table>-><field3>
|
||||
|
||||
wait
|
||||
|
||||
cls
|
||||
|
||||
BROWSE()
|
||||
|
||||
dbgobottom()
|
||||
replace <table>-><field3> with "REPLACED"
|
||||
dbcommit()
|
||||
dbgobottom()
|
||||
|
||||
BROWSE()
|
||||
|
||||
delete for <table>-><field1> = "9"
|
||||
|
||||
return nil
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ HB_FUNC( EMPTY )
|
||||
hb_retl( hb_arrayLen( pItem ) == 0 );
|
||||
break;
|
||||
|
||||
case HB_IT_HASH:
|
||||
hb_retl( hb_hashLen( pItem ) == 0 );
|
||||
break;
|
||||
|
||||
case HB_IT_STRING:
|
||||
case HB_IT_MEMO:
|
||||
hb_retl( hb_strEmpty( hb_itemGetCPtr( pItem ), hb_itemGetCLen( pItem ) ) );
|
||||
|
||||
@@ -79,6 +79,7 @@ UCHAR [ 1 ] - item type
|
||||
18. HASH16 2+n
|
||||
19. HASH32 4+n
|
||||
20. CYCLIC REFERENCE 4
|
||||
21. SYMBOL 1+n
|
||||
*/
|
||||
|
||||
#define HB_SERIAL_NIL 0
|
||||
@@ -102,6 +103,7 @@ UCHAR [ 1 ] - item type
|
||||
#define HB_SERIAL_HASH16 18
|
||||
#define HB_SERIAL_HASH32 19
|
||||
#define HB_SERIAL_REF 20
|
||||
#define HB_SERIAL_SYMBOL 21
|
||||
|
||||
#include "hbapi.h"
|
||||
#include "hbapiitm.h"
|
||||
@@ -150,6 +152,10 @@ static ULONG hb_itemSerialSize( PHB_ITEM pItem )
|
||||
ulSize = 9;
|
||||
break;
|
||||
|
||||
case HB_IT_SYMBOL:
|
||||
ulSize = 2 + strlen( hb_itemGetSymbol( pItem )->szName );
|
||||
break;
|
||||
|
||||
case HB_IT_STRING:
|
||||
case HB_IT_MEMO:
|
||||
ulLen = hb_itemGetCLen( pItem );
|
||||
@@ -202,6 +208,7 @@ static UCHAR * hb_serializeItem( PHB_ITEM pItem, UCHAR * pBuffer )
|
||||
ULONG ulLen, u;
|
||||
LONG l;
|
||||
double d;
|
||||
char * szVal;
|
||||
|
||||
switch( hb_itemType( pItem ) )
|
||||
{
|
||||
@@ -272,6 +279,17 @@ static UCHAR * hb_serializeItem( PHB_ITEM pItem, UCHAR * pBuffer )
|
||||
}
|
||||
break;
|
||||
|
||||
case HB_IT_SYMBOL:
|
||||
szVal = hb_itemGetSymbol( pItem )->szName;
|
||||
ulLen = strlen( szVal );
|
||||
if( ulLen > 0xFF )
|
||||
ulLen = 0xFF;
|
||||
*pBuffer++ = HB_SERIAL_SYMBOL;
|
||||
*pBuffer++ = ( UCHAR ) ulLen;
|
||||
memcpy( pBuffer, szVal, ulLen );
|
||||
pBuffer += ulLen;
|
||||
break;
|
||||
|
||||
case HB_IT_STRING:
|
||||
case HB_IT_MEMO:
|
||||
ulLen = hb_itemGetCLen( pItem );
|
||||
@@ -391,6 +409,7 @@ static UCHAR * hb_deserializeArray( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulLen
|
||||
static UCHAR * hb_deserializeItem( PHB_ITEM pItem, UCHAR * pBuffer )
|
||||
{
|
||||
ULONG ulLen;
|
||||
char * szVal;
|
||||
|
||||
switch( *pBuffer++ )
|
||||
{
|
||||
@@ -444,6 +463,14 @@ static UCHAR * hb_deserializeItem( PHB_ITEM pItem, UCHAR * pBuffer )
|
||||
pBuffer += 3;
|
||||
break;
|
||||
|
||||
case HB_SERIAL_SYMBOL:
|
||||
ulLen = *pBuffer++;
|
||||
szVal = hb_strndup( ( char * ) pBuffer, ulLen );
|
||||
hb_itemPutSymbol( pItem, hb_dynsymGetSymbol( szVal ) );
|
||||
hb_xfree( szVal );
|
||||
pBuffer += ulLen;
|
||||
break;
|
||||
|
||||
case HB_SERIAL_STRING8:
|
||||
ulLen = *pBuffer++;
|
||||
hb_itemPutCL( pItem, ( char * ) pBuffer, ulLen );
|
||||
@@ -530,6 +557,7 @@ static BOOL hb_deserializeTest( UCHAR ** pBufferPtr, ULONG * pulSize )
|
||||
case HB_SERIAL_DOUBLE:
|
||||
ulSize = 9;
|
||||
break;
|
||||
case HB_SERIAL_SYMBOL:
|
||||
case HB_SERIAL_STRING8:
|
||||
ulSize = 1 + ( ulSize >= 2 ? *pBuffer : ulSize );
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user