diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 0d0e62d7fe..468738cc57 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,19 @@ The license applies to all entries newer than 2009-04-28. */ +2010-11-21 20:42 UTC+0100 Viktor Szakats (harbour.01 syenar.hu) + * contrib/hbpgsql/postgres.c + + Added PQPREPARE(), PQEXECPREPARED(). Based on code donated by + Lorenzo Fiorini. Modified to compile with current Harbour, + changed parameter handling and error checking, and changed + to return GC collected result pointer. (I didn't make any + tests, so pls do) + + * contrib/hbpgsql/hbpgsql.hbp + - contrib/hbpgsql/pgrdd.prg + - contrib/hbpgsql/tests/tstpgrdd.prg + - Deleted experimental USRRDD for PGSQL. + 2010-11-21 19:38 UTC+0100 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbsqlit3/hbsqlit3.hbp + contrib/hbsqlit3/hdbcsqlt.prg @@ -33,7 +46,7 @@ + Some formatting. ; TOFIX: These hbpgsql functions are required, but they are not yet - implemented in Harbour SVN: + implemented in Harbour SVN: [DONE] PQPREPARE() PQEXECPREPARED() @@ -44,7 +57,7 @@ Called from TSQLTSTATEMENT:EXECUTEQUERY(0) Called from MAIN(91) - ; TODO: Delete PQRDD experimental RDD from pgsql. + ; TODO: Delete PQRDD experimental RDD from hbpgsql. [DONE] ; TODO: Rename classes to begin with HDBC* ; TODO: Somehow we should ensure the class layout doesn't deviate from a common standard. F.e. by inheritance, or I don't know if @@ -381,7 +394,7 @@ ! Fixed various ages-old bugs in recipient list handling. ; TOFIX: BEWARE to all users. BCC is NOT actually blind in this implementation. If someone has an idea how to fix this - bug, pls shout. + bug, pls shout. [DONE] 2010-11-18 12:21 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/contrib/hbct/bitnum.c @@ -868,7 +881,7 @@ ; TODO: rework current rendering solution. Thinking about callback based solution, to give it a smoother layout. Current system has too much interdependencies and - too much redundancy even in renderer "plugins". + too much redundancy even in renderer "plugins". [DONE] * utils/hbmk2/hbmk2.prg + Readded PathNormalize() calls missed after prev modif. @@ -973,8 +986,8 @@ ; TODO: (my todo list with low priority) - 2-digit and 5-digit supplemental barcodes for EAN13 - draw EAN, UPC barcode in native format - - 2D barcode support - - PDF417 + - 2D barcode support [DONE] + - PDF417 [DONE] ; If someone has real scanner it would be nice to do tests and get feedback. diff --git a/harbour/contrib/hbpgsql/hbpgsql.hbp b/harbour/contrib/hbpgsql/hbpgsql.hbp index 7d735a53a1..7b5fd5a407 100644 --- a/harbour/contrib/hbpgsql/hbpgsql.hbp +++ b/harbour/contrib/hbpgsql/hbpgsql.hbp @@ -29,5 +29,4 @@ postgres.c tpostgre.prg -pgrdd.prg hdbcpg.prg diff --git a/harbour/contrib/hbpgsql/pgrdd.prg b/harbour/contrib/hbpgsql/pgrdd.prg deleted file mode 100644 index a7bc67d1a4..0000000000 --- a/harbour/contrib/hbpgsql/pgrdd.prg +++ /dev/null @@ -1,392 +0,0 @@ -/* - * $Id$ - */ - -/* - * Harbour Project source code: - * PostgreSQL RDD - * - * Copyright 2006 Lorenzo Fiorini - * www - http://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 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 "hbusrrdd.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 - -THREAD STATIC t_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() - RETURN HB_FAILURE - ELSE - AAdd( t_aConnections, oServer ) - nConn := Len( t_aConnections ) - ENDIF - - RETURN nConn - -FUNCTION DBPGCLEARCONNECTION( nConn ) - - LOCAL oServer := t_aConnections[ nConn ] - - oServer:Close() - - t_aConnections[ nConn ] := NIL - - RETURN HB_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 HB_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 HB_SUCCESS - -STATIC FUNCTION PG_OPEN( nWA, aOpenInfo ) - LOCAL aField, oError, lError, cError, nResult - LOCAL oServer, oQuery, aStruct, aFieldStruct - - LOCAL aWAData := USRRDD_AREADATA( nWA ) - - IF ! Empty( aOpenInfo[ UR_OI_CONNECT ] ) .AND. aOpenInfo[ UR_OI_CONNECT ] <= Len( t_aConnections ) - oServer := t_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 HB_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 HB_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 HB_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 HB_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 HB_SUCCESS - -STATIC FUNCTION PG_RECCOUNT( nWA, nRecords ) - LOCAL aWAData := USRRDD_AREADATA( nWA ) - - nRecords := aWAData[ AREA_QUERY ]:nLastRec - - RETURN HB_SUCCESS - -STATIC FUNCTION PG_BOF( nWA, lBof ) - LOCAL aWAData := USRRDD_AREADATA( nWA ) - - lBof := aWAData[ AREA_QUERY ]:lBof - - RETURN HB_SUCCESS - -STATIC FUNCTION PG_EOF( nWA, lEof ) - LOCAL aWAData := USRRDD_AREADATA( nWA ) - - lEof := aWAData[ AREA_QUERY ]:lEof - - RETURN HB_SUCCESS - -STATIC FUNCTION PG_RECID( nWA, nRecNo ) - LOCAL aWAData := USRRDD_AREADATA( nWA ) - - nRecno := aWAData[ AREA_QUERY ]:nRecNo - - RETURN HB_SUCCESS - -STATIC FUNCTION PG_DELETED( nWA, lDeleted ) - HB_SYMBOL_UNUSED( nWA ) - lDeleted := .F. - RETURN HB_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 HB_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 HB_SUCCESS - -STATIC FUNCTION PG_APPEND( nWA, nRecords ) - LOCAL aWAData := USRRDD_AREADATA( nWA ) - - HB_SYMBOL_UNUSED( nRecords ) - - aWAData[ AREA_ROW ] := aWAData[ AREA_QUERY ]:GetBlankRow() - - aWAData[ AREA_APPEND ] := .T. - - RETURN HB_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 HB_FAILURE - ENDIF - - aWAData[ AREA_ROW ] := NIL - - RETURN HB_SUCCESS - -/* - * This function have to exist in all RDD and then name have to be in - * format: _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 diff --git a/harbour/contrib/hbpgsql/postgres.c b/harbour/contrib/hbpgsql/postgres.c index 607b4c0186..5e2fdcbc42 100644 --- a/harbour/contrib/hbpgsql/postgres.c +++ b/harbour/contrib/hbpgsql/postgres.c @@ -1266,6 +1266,39 @@ HB_FUNC( PQESCAPEBYTEACONN ) #endif } +HB_FUNC( PQPREPARE ) +{ + PGconn * conn = hb_PGconn_par( 1 ); + + if( conn ) + hb_PGresult_ret( PQprepare( conn, hb_parcx( 2 ), hb_parcx( 3 ), hb_parni( 4 ), NULL ) ); + else + hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + +HB_FUNC( PQEXECPREPARED ) +{ + PGconn * conn = hb_PGconn_par( 1 ); + + if( conn ) + { + PHB_ITEM aParam = hb_param( 3, HB_IT_ARRAY ); + HB_SIZE n = hb_arrayLen( aParam ); + HB_SIZE i; + + const char ** paramvalues = ( const char ** ) hb_xgrab( sizeof( char * ) * n ); + + for( i = 0; i < n; ++i ) + paramvalues[ i ] = hb_arrayGetCPtr( aParam, i + 1 ); + + hb_PGresult_ret( PQexecPrepared( conn, hb_parcx( 2 ), n, ( const char * const * ) paramvalues, NULL, NULL, 1 ) ); + + hb_xfree( paramvalues ); + } + else + hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + /* TODO: Implement Full Large Objects Support @@ -1279,21 +1312,6 @@ 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, diff --git a/harbour/contrib/hbpgsql/tests/tstpgrdd.prg b/harbour/contrib/hbpgsql/tests/tstpgrdd.prg deleted file mode 100644 index 88ceaf993c..0000000000 --- a/harbour/contrib/hbpgsql/tests/tstpgrdd.prg +++ /dev/null @@ -1,95 +0,0 @@ -/* - * $Id$ - */ - -/* 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. -*/ - -#if 0 - -PROCEDURE Main() - - LOCAL nConn - - SET DELETED ON - - REQUEST DBFCDX - REQUEST PGRDD - - USE INDEX EXCLUSIVE VIA "dbfcdx" - - SET ORDER TO 1 - - test_code( "DBF" ) - - USE - - nConn := dbpgconnection( ";;;;;" ) - - /* if you want to update and insert data you need at least a primary key */ - - USE "select FROM
ORDER BY " ALIAS
VIA "pgrdd" CONNECTION NCONN - - test_code( "SQL" ) - - USE - - dbpgclearconnection( nConn ) - - RETURN - -PROCEDURE test_code( cMode ) - - LOCAL xTemp - -
->( dbGoTop() ) - ?
->,
->,
-> -
->( dbGoBottom() ) - ?
->,
->,
-> - /* goto 100 has different meaning */ -
->( dbGoto( 100 ) ) - ?
->,
->,
-> - xTemp :=
-> - REPLACE
-> WITH "*** replaced ***" - ?
->,
->,
-> - REPLACE
-> WITH xTemp - dbCommit() // the real write is made via dbCommit() so it is needed - ?
->,
->,
-> - ? Eof() - dbGoBottom() - dbSkip() - ? Eof() - ? Bof() - dbGoTop() - dbSkip( -1 ) - ? Bof() - - dbAppend() - REPLACE
-> WITH <"9"> - REPLACE
-> WITH <"999999"> - REPLACE
-> WITH <"APPENDED"> - dbCommit() - - // RecNo() has different meaning, in SQL it is the number of the row and change for every select */ - ?
->( RecNo() ),
->,
->,
-> - - WAIT - - CLS - - Browse() - - dbGoBottom() - REPLACE
-> WITH "REPLACED" - dbCommit() - dbGoBottom() - - Browse() - - DELETE FOR
-> = "9" - - RETURN - -#endif