2021-03-31 21:26 UTC+0200 Aleksander Czajczynski (hb fki.pl)

* contrib/hbpgsql/hbpgsql.hbx
  * contrib/hbpgsql/postgres.c
  * contrib/hbpgsql/postgres.ch
    + add most new wrappers from this repository of Petr Chornyj:
      https://github.com/petr-ch/hbpgsql9
      Version guards have been added and "params" functions reworked
      to accept hashes instead of two arrays. Other minor corrections
      to fit into the contrib env.
    + add PQsslAttribute()
    * some existing functions were modified to make the parameter
      check (and fail if wrong) even if the underlying API is not
      available, instead of silently returning a default value.
    ; all of the above was build-tested only and some features
      require at least postgresql 8, 9 or 9.1

    + add PQlibVersion() -> <nVersion> (returns 0 for pre-9.1 postresql
versions)
      Ref: https://github.com/harbour/core/pull/127/ by @VerchenkoAG

    + PQEXECPARAMS(): add 4th parameter to set <resultFormat>
      Refs:
        https://www.postgresql.org/docs/9.1/static/libpq-exec.html
        https://groups.google.com/d/msg/harbour-users/hXhuVzU9pHA/RrDGLIiUAwAJ

    + add PQresStatus( <nNum> ) -> <cString>

    + added wrapper function
      PQresultErrorField( result, nFieldCode ) -> cString
      based on:
https://groups.google.com/d/msg/harbour-users/XSvRpbzfcHc/ztSL32fYpl4J
    + added PG_DIAG_* constants

    + added pg_encoding_to_char() wrapper to convert numeric
      encoding ID to string

    ! fixed to use hb_fopen() instead of fopen()

    + TPQserver():New(): all parameters are now optional
    ! TPQserver():New(): fixed to escape connect parameter values
    + TPQserver():New(): added 7th optional hash parameter to pass
custom
      connection parameters (e.g. SSL)
         https://www.postgresql.org/docs/devel/static/libpq-connect.html

  * contrib/hbpgsql/tests/test.prg
    + use pg_encoding_to_char(), plus some more feedback regarding
encodings

  * contrib/hbpgsql/tests/dbf2pg.prg
    + use VF IO
    + support more source field types

  ; synced with Viktor's 3.4 branch at https://github.com/vszakats/hb
    2017-02-15 15:14 UTC Viktor Szakats (vszakats users.noreply.github.com)
    2016-09-05 18:55 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2016-09-05 10:43 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2016-09-02 01:58 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2016-06-20 22:50 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2015-07-19 11:56 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2015-04-06 18:39 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2015-03-31 23:31 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2014-11-29 02:47 UTC+0100 Viktor Szakats (vszakats users.noreply.github.com)
    2014-07-08 13:21 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
    2014-02-11 18:18 UTC+0100 Viktor Szakats (vszakats users.noreply.github.com)
    ; tons of cleanups in this library, many thanks
This commit is contained in:
Viktor Szakats
2021-03-31 21:26:42 +02:00
committed by Aleksander Czajczynski
parent 864c0e6315
commit ff3a726edf
14 changed files with 1188 additions and 957 deletions

View File

@@ -7,6 +7,69 @@
Entries may not always be in chronological/commit order.
See license at the end of file. */
2021-03-31 21:26 UTC+0200 Aleksander Czajczynski (hb fki.pl)
* contrib/hbpgsql/hbpgsql.hbx
* contrib/hbpgsql/postgres.c
* contrib/hbpgsql/postgres.ch
+ add most new wrappers from this repository of Petr Chornyj:
https://github.com/petr-ch/hbpgsql9
Version guards have been added and "params" functions reworked
to accept hashes instead of two arrays. Other minor corrections
to fit into the contrib env.
+ add PQsslAttribute()
* some existing functions were modified to make the parameter
check (and fail if wrong) even if the underlying API is not
available, instead of silently returning a default value.
; all of the above was build-tested only and some features
require at least postgresql 8, 9 or 9.1
+ add PQlibVersion() -> <nVersion> (returns 0 for pre-9.1 postresql versions)
Ref: https://github.com/harbour/core/pull/127/ by @VerchenkoAG
+ PQEXECPARAMS(): add 4th parameter to set <resultFormat>
Refs:
https://www.postgresql.org/docs/9.1/static/libpq-exec.html
https://groups.google.com/d/msg/harbour-users/hXhuVzU9pHA/RrDGLIiUAwAJ
+ add PQresStatus( <nNum> ) -> <cString>
+ added wrapper function
PQresultErrorField( result, nFieldCode ) -> cString
based on: https://groups.google.com/d/msg/harbour-users/XSvRpbzfcHc/ztSL32fYpl4J
+ added PG_DIAG_* constants
+ added pg_encoding_to_char() wrapper to convert numeric
encoding ID to string
! fixed to use hb_fopen() instead of fopen()
+ TPQserver():New(): all parameters are now optional
! TPQserver():New(): fixed to escape connect parameter values
+ TPQserver():New(): added 7th optional hash parameter to pass custom
connection parameters (e.g. SSL)
https://www.postgresql.org/docs/devel/static/libpq-connect.html
* contrib/hbpgsql/tests/test.prg
+ use pg_encoding_to_char(), plus some more feedback regarding encodings
* contrib/hbpgsql/tests/dbf2pg.prg
+ use VF IO
+ support more source field types
; synced with Viktor's 3.4 branch at https://github.com/vszakats/hb
2017-02-15 15:14 UTC Viktor Szakats (vszakats users.noreply.github.com)
2016-09-05 18:55 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2016-09-05 10:43 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2016-09-02 01:58 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2016-06-20 22:50 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2015-07-19 11:56 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2015-04-06 18:39 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2015-03-31 23:31 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2014-11-29 02:47 UTC+0100 Viktor Szakats (vszakats users.noreply.github.com)
2014-07-08 13:21 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com)
2014-02-11 18:18 UTC+0100 Viktor Szakats (vszakats users.noreply.github.com)
; tons of cleanups in this library, many thanks
2021-03-31 20:38 UTC+0200 Aleksander Czajczynski (hb fki.pl)
* contrib/hbpgsql/hbpgsql.h
* contrib/hbpgsql/postgres.c

View File

@@ -1,7 +1,7 @@
/*
* PostgreSQL RDBMS wrapper header.
*
* Copyright 2010 Viktor Szakats (vszakats.net/harbour) (GC support)
* Copyright 2010 Viktor Szakats (vsz.me/hb) (GC support)
* Copyright 2003 Rodrigo Moreno rodrigo_moreno@yahoo.com
*
* This program is free software; you can redistribute it and/or modify
@@ -84,9 +84,10 @@
HB_EXTERN_BEGIN
extern HB_EXPORT void hb_PGconn_ret( PGconn * p );
extern HB_EXPORT PGconn * hb_PGconn_par( int iParam );
extern HB_EXPORT void hb_PGresult_ret( PGresult * p );
extern HB_EXPORT void hb_PGconn_ret( PGconn * p );
extern HB_EXPORT PGconn * hb_PGconn_par( int iParam );
extern HB_EXPORT void hb_PGresult_ret( PGresult * p );
extern HB_EXPORT PGresult * hb_PGresult_par( int iParam );
HB_EXTERN_END

View File

@@ -25,12 +25,20 @@ DYNAMIC hb_PQCopyFromWA
DYNAMIC lo_export
DYNAMIC lo_import
DYNAMIC lo_unlink
DYNAMIC pg_encoding_to_char
DYNAMIC PQbackendPID
DYNAMIC PQbinaryTuples
DYNAMIC PQcancel
DYNAMIC PQclientEncoding
DYNAMIC PQcmdStatus
DYNAMIC PQcmdTuples
DYNAMIC PQconnectdb
DYNAMIC PQconnectdbparams
DYNAMIC PQconnectionNeedsPassword
DYNAMIC PQconnectionUsedPassword
DYNAMIC PQconnectPoll
DYNAMIC PQconnectStart
DYNAMIC PQconnectStartParams
DYNAMIC PQconsumeInput
DYNAMIC PQdb
DYNAMIC PQerrorMessage
@@ -56,14 +64,19 @@ DYNAMIC PQgetvalue
DYNAMIC PQhost
DYNAMIC PQisBusy
DYNAMIC PQisnonblocking
DYNAMIC PQisthreadsafe
DYNAMIC PQlastrec
DYNAMIC PQlibVersion
DYNAMIC PQmetadata
DYNAMIC PQnfields
DYNAMIC PQntuples
DYNAMIC PQoidStatus
DYNAMIC PQoidValue
DYNAMIC PQoptions
DYNAMIC PQparameterStatus
DYNAMIC PQpass
DYNAMIC PQping
DYNAMIC PQpingParams
DYNAMIC PQport
DYNAMIC PQprepare
DYNAMIC PQprotocolVersion
@@ -71,7 +84,11 @@ DYNAMIC PQputCopyData
DYNAMIC PQputCopyEnd
DYNAMIC PQrequestCancel
DYNAMIC PQreset
DYNAMIC PQresetPoll
DYNAMIC PQresetStart
DYNAMIC PQresStatus
DYNAMIC PQresult2array
DYNAMIC PQresultErrorField
DYNAMIC PQresultErrorMessage
DYNAMIC PQresultStatus
DYNAMIC PQsendQuery
@@ -80,6 +97,9 @@ DYNAMIC PQsetClientEncoding
DYNAMIC PQsetdbLogin
DYNAMIC PQsetErrorVerbosity
DYNAMIC PQsetnonblocking
DYNAMIC PQsocket
DYNAMIC PQsslAttribute
DYNAMIC PQsslInUse
DYNAMIC PQstatus
DYNAMIC PQtrace
DYNAMIC PQtracecreate

View File

@@ -2,7 +2,7 @@
* PostgreSQL RDBMS low-level (client API) interface code.
*
* Copyright 2016 P.Chornyj <myorg63@mail.ru>
* Copyright 2010-2016 Viktor Szakats (vszakats.net/harbour) (GC support, etc)
* Copyright 2010-2016 Viktor Szakats (vsz.me/hb) (GC support, etc)
* Copyright 2003 Rodrigo Moreno rodrigo_moreno@yahoo.com
*
* This program is free software; you can redistribute it and/or modify
@@ -227,9 +227,51 @@ static FILE * hb_FILE_par( int iParam )
#endif
/*
* Connection handling functions
*/
/* Get the version of the libpq library in use */
HB_FUNC( PQLIBVERSION )
{
#if PG_VERSION_NUM >= 90100
hb_retni( PQlibVersion() );
#else
hb_retni( 0 );
#endif
}
/* Connection handling functions */
/* 31.1. Database Connection Control Functions
The following functions deal with making a connection to a PostgreSQL backend server. */
HB_FUNC( PQCONNECTDBPARAMS )
{
PHB_ITEM pParam = hb_param( 1, HB_IT_HASH );
int len;
if( pParam && ( len = ( int ) hb_hashLen( pParam ) ) > 0 )
{
#if PG_VERSION_NUM >= 90000
const char ** paramKeyValues = ( const char ** ) hb_xgrab( sizeof( char * ) * len );
const char ** paramValValues = ( const char ** ) hb_xgrab( sizeof( char * ) * len );
int pos;
for( pos = 0; pos < len; ++pos )
{
paramKeyValues[ pos ] = hb_itemGetCPtr( hb_hashGetKeyAt( pParam, pos + 1 ) );
paramValValues[ pos ] = hb_itemGetCPtr( hb_hashGetValueAt( pParam, pos + 1 ) );
}
hb_PGconn_ret( PQconnectdbParams( paramKeyValues, paramValValues, hb_parl( 2 ) ) );
hb_xfree( ( void * ) paramKeyValues );
hb_xfree( ( void * ) paramValValues );
#else
hb_retptr( NULL );
#endif
}
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQCONNECTDB )
{
@@ -251,6 +293,54 @@ HB_FUNC( PQSETDBLOGIN )
hb_parcx( 7 ) /* pwd */ ) );
}
HB_FUNC( PQCONNECTSTARTPARAMS )
{
PHB_ITEM pParam = hb_param( 1, HB_IT_HASH );
int len;
if( pParam && ( len = ( int ) hb_hashLen( pParam ) ) > 0 )
{
#if PG_VERSION_NUM >= 90000
const char ** paramKeyValues = ( const char ** ) hb_xgrab( sizeof( char * ) * len );
const char ** paramValValues = ( const char ** ) hb_xgrab( sizeof( char * ) * len );
int pos;
for( pos = 0; pos < len; ++pos )
{
paramKeyValues[ pos ] = hb_itemGetCPtr( hb_hashGetKeyAt( pParam, pos + 1 ) );
paramValValues[ pos ] = hb_itemGetCPtr( hb_hashGetValueAt( pParam, pos + 1 ) );
}
hb_PGconn_ret( PQconnectStartParams( paramKeyValues, paramValValues, hb_parl( 2 ) ) );
hb_xfree( ( void * ) paramKeyValues );
hb_xfree( ( void * ) paramValValues );
#else
hb_retptr( NULL );
#endif
}
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQCONNECTSTART )
{
if( HB_ISCHAR( 1 ) )
hb_PGconn_ret( PQconnectStart( hb_parc( 1 ) ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQCONNECTPOLL )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQconnectPoll( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQRESET )
{
PGconn * conn = hb_PGconn_par( 1 );
@@ -261,16 +351,71 @@ HB_FUNC( PQRESET )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQPROTOCOLVERSION )
HB_FUNC( PQRESETSTART )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQprotocolVersion( conn ) );
PQresetStart( conn );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQRESETPOLL )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQresetPoll( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQPINGPARAMS )
{
PHB_ITEM pParam = hb_param( 1, HB_IT_HASH );
int len;
if( pParam && ( len = ( int ) hb_hashLen( pParam ) ) > 0 )
{
#if PG_VERSION_NUM >= 90100
const char ** paramKeyValues = ( const char ** ) hb_xgrab( sizeof( char * ) * len );
const char ** paramValValues = ( const char ** ) hb_xgrab( sizeof( char * ) * len );
int pos;
for( pos = 0; pos < len; ++pos )
{
paramKeyValues[ pos ] = hb_itemGetCPtr( hb_hashGetKeyAt( pParam, pos + 1 ) );
paramValValues[ pos ] = hb_itemGetCPtr( hb_hashGetValueAt( pParam, pos + 1 ) );
}
hb_retni( PQpingParams( paramKeyValues, paramValValues, hb_parl( 3 ) ) );
hb_xfree( ( void * ) paramKeyValues );
hb_xfree( ( void * ) paramValValues );
#else
hb_retptr( NULL );
#endif
}
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQPING )
{
if( HB_ISCHAR( 1 ) )
#if PG_VERSION_NUM >= 90100
hb_retni( PQping( hb_parc( 1 ) ) );
#else
hb_ret();
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/* 31.2. Connection Status Functions.
These functions can be used to interrogate the status of an existing database connection object. */
HB_FUNC( PQCLIENTENCODING )
{
PGconn * conn = hb_PGconn_par( 1 );
@@ -361,6 +506,38 @@ HB_FUNC( PQOPTIONS )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQRESULTERRORFIELD )
{
PGresult * res = hb_PGresult_par( 1 );
if( res )
#if PG_VERSION_NUM >= 70400
hb_retc( PQresultErrorField( res, hb_parni( 2 ) ) );
#else
hb_retc_null();
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQRESSTATUS )
{
hb_retc( PQresStatus( ( ExecStatusType ) hb_parnl( 1 ) ) );
}
/* 31.2. Connection Status Functions.
These functions can be used to interrogate the status of an existing database connection object. */
HB_FUNC( PQSTATUS )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQstatus( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQTRANSACTIONSTATUS )
{
PGconn * conn = hb_PGconn_par( 1 );
@@ -371,6 +548,40 @@ HB_FUNC( PQTRANSACTIONSTATUS )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQPARAMETERSTATUS )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retc( PQparameterStatus( conn, hb_parcx( 2 ) ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQPROTOCOLVERSION )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQprotocolVersion( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQSERVERVERSION )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
#if PG_VERSION_NUM >= 80000
hb_retni( PQserverVersion( conn ) );
#else
hb_retni( 0 );
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQERRORMESSAGE )
{
PGconn * conn = hb_PGconn_par( 1 );
@@ -381,19 +592,83 @@ HB_FUNC( PQERRORMESSAGE )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQSTATUS )
HB_FUNC( PQSOCKET )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQstatus( conn ) );
hb_retni( PQsocket( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/*
* Query handling functions
*/
HB_FUNC( PQBACKENDPID )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQbackendPID( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQCONNECTIONNEEDSPASSWORD )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
#if PG_VERSION_NUM >= 80300
hb_retl( PQconnectionNeedsPassword( conn ) ? HB_TRUE : HB_FALSE );
#else
hb_ret();
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQCONNECTIONUSEDPASSWORD )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
#if PG_VERSION_NUM >= 80300
hb_retl( PQconnectionUsedPassword( conn ) ? HB_TRUE : HB_FALSE );
#else
hb_ret();
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQSSLINUSE )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
#if PG_VERSION_NUM >= 90500
hb_retl( PQsslInUse( conn ) ? HB_TRUE : HB_FALSE );
#else
hb_ret();
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQSSLATTRIBUTE )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
#if PG_VERSION_NUM >= 90500
hb_retc( PQsslAttribute( conn, hb_parcx( 2 ) ) );
#else
hb_retc_null();
#endif
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/* Query handling functions */
HB_FUNC( PQEXEC )
{
@@ -420,7 +695,7 @@ HB_FUNC( PQEXECPARAMS )
for( i = 0; i < n; ++i )
paramvalues[ i ] = hb_arrayGetCPtr( aParam, i + 1 );
hb_PGresult_ret( PQexecParams( conn, hb_parcx( 2 ), n, NULL, paramvalues, NULL, NULL, 1 ) );
hb_PGresult_ret( PQexecParams( conn, hb_parcx( 2 ), n, NULL, paramvalues, NULL, NULL, hb_parnidef( 4, 1 ) ) );
hb_xfree( ( void * ) paramvalues );
}
@@ -725,7 +1000,7 @@ HB_FUNC( PQESCAPESTRING )
hb_retc_buffer( dest );
}
HB_FUNC( PQESCAPEBYTEA ) /* deprecated */
HB_FUNC( PQESCAPEBYTEA ) /* deprecated */
{
if( HB_ISCHAR( 1 ) )
{
@@ -777,7 +1052,7 @@ HB_FUNC( PQBINARYTUPLES )
PGresult * res = hb_PGresult_par( 1 );
if( res )
hb_retl( PQbinaryTuples( res ) );
hb_retl( PQbinaryTuples( res ) ? HB_TRUE : HB_FALSE );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
@@ -837,7 +1112,7 @@ HB_FUNC( PQGETISNULL )
PGresult * res = hb_PGresult_par( 1 );
if( res )
hb_retl( PQgetisnull( res, hb_parni( 2 ) - 1, hb_parni( 3 ) - 1 ) );
hb_retl( PQgetisnull( res, hb_parni( 2 ) - 1, hb_parni( 3 ) - 1 ) ? HB_TRUE : HB_FALSE );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
@@ -872,9 +1147,7 @@ HB_FUNC( PQNFIELDS )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/*
* Asynchronous functions
*/
/* Asynchronous functions */
HB_FUNC( PQSENDQUERY )
{
@@ -901,7 +1174,7 @@ HB_FUNC( PQCONSUMEINPUT )
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retl( PQconsumeInput( conn ) );
hb_retl( PQconsumeInput( conn ) ? HB_TRUE : HB_FALSE );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
@@ -936,12 +1209,14 @@ HB_FUNC( PQFLUSH )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/* Set blocking/nonblocking connection to the backend */
HB_FUNC( PQSETNONBLOCKING )
{
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retl( PQsetnonblocking( conn, hb_parl( 2 ) ) );
hb_retl( PQsetnonblocking( conn, hb_parl( 2 ) ) ? HB_TRUE : HB_FALSE );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
@@ -951,19 +1226,17 @@ HB_FUNC( PQISNONBLOCKING )
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retl( PQisnonblocking( conn ) );
hb_retl( PQisnonblocking( conn ) ? HB_TRUE : HB_FALSE );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/*
* Trace Connection handling functions
*/
/* Trace Connection handling functions */
HB_FUNC( PQTRACECREATE ) /* not a direct wrapper */
{
#ifdef NODLL
hb_FILE_ret( fopen( hb_parcx( 1 ), "w+b" ) );
hb_FILE_ret( hb_fopen( hb_parcx( 1 ), "w+b" ) );
#else
hb_retptr( NULL );
#endif
@@ -1006,9 +1279,7 @@ HB_FUNC( PQSETERRORVERBOSITY )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
/*
* Large Object functions
*/
/* Large Object functions */
HB_FUNC( LO_IMPORT )
{
@@ -1040,20 +1311,6 @@ HB_FUNC( LO_UNLINK )
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( PQSERVERVERSION )
{
#if PG_VERSION_NUM >= 80000
PGconn * conn = hb_PGconn_par( 1 );
if( conn )
hb_retni( PQserverVersion( conn ) );
else
hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#else
hb_retni( 0 );
#endif
}
HB_FUNC( PQGETCANCEL )
{
#if PG_VERSION_NUM >= 80000
@@ -1079,7 +1336,7 @@ HB_FUNC( PQCANCEL )
errbuf[ 0 ] = '\0';
hb_retl( PQcancel( cancel, errbuf, sizeof( errbuf ) - 1 ) == 1 );
hb_retl( PQcancel( cancel, errbuf, sizeof( errbuf ) - 1 ) ? HB_TRUE : HB_FALSE );
hb_storc( errbuf, 2 );
}
@@ -1173,6 +1430,22 @@ HB_FUNC( PQPUTCOPYEND )
#endif
}
HB_FUNC( PG_ENCODING_TO_CHAR )
{
hb_retc( pg_encoding_to_char( hb_parni( 1 ) ) );
}
/* 31.19 Behavior in Threaded Programs */
HB_FUNC( PQISTHREADSAFE )
{
#if PG_VERSION_NUM >= 80200
hb_retl( PQisthreadsafe() ? HB_TRUE : HB_FALSE );
#else
hb_retl( HB_FALSE );
#endif
}
#if 0
TODO: Implement Full Large Objects Support

View File

@@ -2,7 +2,7 @@
* PostgreSQL RDBMS low-level (client API) interface code.
*
* Copyright 2016 P.Chornyj <myorg63@mail.ru>
* Copyright 2014 Viktor Szakats (vszakats.net/harbour)
* Copyright 2014 Viktor Szakats (vsz.me/hb)
* Copyright 2003 Rodrigo Moreno rodrigo_moreno@yahoo.com
*
* This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,13 @@
#define CONNECTION_SSL_STARTUP 7
#define CONNECTION_NEEDED 8
/* PQconnectPoll(), PQresetPoll() */
#define PGRES_POLLING_FAILED 0
#define PGRES_POLLING_READING 1
#define PGRES_POLLING_WRITING 2
#define PGRES_POLLING_OK 3
#define PGRES_POLLING_ACTIVE 4
/* PQresultStatus() */
#define PGRES_EMPTY_QUERY 0
#define PGRES_COMMAND_OK 1
@@ -86,4 +93,34 @@
#define HBPG_META_TABLECOL 6
#define HBPG_META_LEN_ 6
/* PQsetErrorVerbosity() */
#define PQERRORS_TERSE 0
#define PQERRORS_DEFAULT 1
#define PQERRORS_VERBOSE 2
/* PQping() */
#define PQPING_OK 0 /* server is accepting connections */
#define PQPING_REJECT 1 /* server is alive but rejecting connections */
#define PQPING_NO_RESPONSE 2 /* could not establish connection */
#define PQPING_NO_ATTEMPT 3 /* connection not attempted (bad params) */
/* PQresultErrorField() fieldcode parameters */
#define PG_DIAG_SEVERITY hb_BCode( "S" )
#define PG_DIAG_SQLSTATE hb_BCode( "C" )
#define PG_DIAG_MESSAGE_PRIMARY hb_BCode( "M" )
#define PG_DIAG_MESSAGE_DETAIL hb_BCode( "D" )
#define PG_DIAG_MESSAGE_HINT hb_BCode( "H" )
#define PG_DIAG_STATEMENT_POSITION hb_BCode( "P" )
#define PG_DIAG_INTERNAL_POSITION hb_BCode( "p" )
#define PG_DIAG_INTERNAL_QUERY hb_BCode( "q" )
#define PG_DIAG_CONTEXT hb_BCode( "W" )
#define PG_DIAG_SCHEMA_NAME hb_BCode( "s" )
#define PG_DIAG_TABLE_NAME hb_BCode( "t" )
#define PG_DIAG_COLUMN_NAME hb_BCode( "c" )
#define PG_DIAG_DATATYPE_NAME hb_BCode( "d" )
#define PG_DIAG_CONSTRAINT_NAME hb_BCode( "n" )
#define PG_DIAG_SOURCE_FILE hb_BCode( "F" )
#define PG_DIAG_SOURCE_LINE hb_BCode( "L" )
#define PG_DIAG_SOURCE_FUNCTION hb_BCode( "R" )
#endif

View File

@@ -274,8 +274,8 @@ HB_FUNC( HB_PQCOPYFROMWA )
static const char * sc_szDelim = ",";
const char * szTable = hb_parcx( 2 );
PHB_ITEM pWhile = hb_param( 3, HB_IT_BLOCK );
PHB_ITEM pFor = hb_param( 4, HB_IT_BLOCK );
PHB_ITEM pWhile = hb_param( 3, HB_IT_EVALITEM );
PHB_ITEM pFor = hb_param( 4, HB_IT_EVALITEM );
PHB_ITEM pFields = hb_param( 5, HB_IT_ARRAY );
HB_ULONG nCount = hb_parnldef( 6, 0 );
HB_BOOL str_rtrim = hb_parldef( 7, HB_TRUE );
@@ -296,8 +296,7 @@ HB_FUNC( HB_PQCOPYFROMWA )
pItem = hb_itemNew( NULL );
context = ( pgCopyContext * ) hb_xgrab( sizeof( pgCopyContext ) );
memset( context, 0, sizeof( pgCopyContext ) );
context = ( pgCopyContext * ) hb_xgrabz( sizeof( pgCopyContext ) );
context->buffer = ( char * ) hb_xgrab( sizeof( char ) * nBufLen * 1400 );
context->position = 0;

View File

@@ -1,18 +1,21 @@
/*
* This sample show howto use asynchronous/nonblocking queries
*/
/* This sample show howto use asynchronous/non-blocking queries */
#require "hbpgsql"
#include "inkey.ch"
PROCEDURE Main( cServer, cDatabase, cUser, cPass )
PROCEDURE Main( cHost, cDatabase, cUser, cPass )
LOCAL conn
CLS
? "Connect", conn := PQconnectdb( "dbname = " + cDatabase + " host = " + cServer + " user = " + cUser + " password = " + cPass + " port = 5432" )
? "Connect", conn := PQconnectdb( ;
"dbname = '" + hb_defaultValue( cDatabase, "postgres" ) + "' " + ;
"host = '" + hb_defaultValue( cHost, "localhost" ) + "' " + ;
"user = '" + hb_defaultValue( cUser, hb_UserName() ) + "' " + ;
"password = '" + hb_defaultValue( cPass, "" ) + "' " + ;
"port = 5432" )
? "Conection status", PQerrorMessage( conn ), PQstatus( conn )
@@ -22,9 +25,9 @@ PROCEDURE Main( cServer, cDatabase, cUser, cPass )
RETURN
PROCEDURE Query( conn, cQuery, lCancel )
STATIC PROCEDURE Query( conn, cQuery, lCancel )
LOCAL pCancel, cErrMsg := Space( 30 )
LOCAL pCancel, cErrMsg := ""
LOCAL res, x, y, cTime
? "PQSendQuery", PQsendQuery( conn, cQuery )
@@ -32,20 +35,16 @@ PROCEDURE Query( conn, cQuery, lCancel )
cTime := Time()
CLEAR TYPEAHEAD
DO WHILE Inkey() != K_ESC
DO WHILE hb_keyStd( Inkey() ) != K_ESC
DevPos( Row(), 20 )
DevOut( "Processing: " + ElapTime( cTime, Time() ) )
DevOut( "Processing:", ElapTime( cTime, Time() ) )
Inkey( 1 )
IF lCancel
IF .T.
pCancel := PQgetCancel( conn )
? "Canceled: ", PQcancel( pCancel, @cErrMsg ), cErrMsg
pCancel := NIL
ELSE
? PQrequestCancel( conn ) /* Deprecated */
ENDIF
pCancel := PQgetCancel( conn )
? "Canceled:", PQcancel( pCancel, @cErrMsg ), cErrMsg
pCancel := NIL
ENDIF
IF PQconsumeInput( conn )
@@ -55,15 +54,17 @@ PROCEDURE Query( conn, cQuery, lCancel )
ENDIF
ENDDO
IF Inkey() != K_ESC
IF hb_keyStd( Inkey() ) != K_ESC
? "PQgetResult", hb_ValToExp( res := PQgetResult( conn ) )
FOR x := 1 TO PQlastrec( res )
?
FOR y := 1 TO PQfcount( res )
?? PQgetvalue( res, x, y ), " "
IF ! Empty( res )
FOR x := 1 TO PQlastrec( res )
?
FOR y := 1 TO PQfcount( res )
?? PQgetvalue( res, x, y ), " "
NEXT
NEXT
NEXT
ENDIF
ELSE
? "Canceling Query", PQrequestCancel( conn )
ENDIF

View File

@@ -1,56 +1,49 @@
/*
* This samples show how to use dbf to cache postgres records.
*/
/* This samples show how to use dbf to cache postgres records. */
#require "hbpgsql"
#define DB_ALIAS 1
#define DB_FILE 2
#define DB_QUERY 3
#define DB_ROW 4
#define DB_FETCH 5
#define DB_ALIAS 1 // Table Name
#define DB_QUERY 2 // Object Query
#define DB_ROW 3 // Current Row
#define DB_FETCH 4 // Fetch Status
STATIC s_oServer
STATIC s_aTableTemp := {}
STATIC s_aTempDBF := {}
THREAD STATIC t_oServer
THREAD STATIC t_aTableTemp := {}
PROCEDURE Main( cServer, cDatabase, cUser, cPass )
PROCEDURE Main( cHost, cDatabase, cUser, cPass )
LOCAL i
LOCAL cQuery
IF SQLConnect( cServer, cDatabase, cUser, cPass )
IF SQLConnect( cHost, hb_defaultValue( cDatabase, "postgres" ), cUser, cPass )
QuickQuery( "DROP TABLE test" )
cQuery := "CREATE TABLE test ( "
cQuery += " codigo integer primary key, "
cQuery += " descri char(50), "
cQuery += " email varchar(50) ) "
SQLQuery( cQuery )
SQLQuery( "CREATE TABLE test (" + ;
" codigo integer primary key," + ;
" descri char(50)," + ;
" email varchar(50) )" )
SQLOpen( "nomes", "SELECT * FROM test" )
FOR i := 1 TO 50
APPEND BLANK
REPLACE codigo WITH i
REPLACE descri WITH "test " + Str( i )
dbAppend()
nomes->codigo := i
nomes->descri := "test " + hb_ntos( i )
NEXT
SQLApplyUpdates()
cQuery := "SELECT * FROM test WHERE codigo >= :1 ORDER BY codigo"
cQuery := SQLPrepare( cQuery, 1 )
SQLOpen( "nomes", cQuery )
SQLOpen( "nomes", SQLPrepare( "SELECT * FROM test WHERE codigo >= :1 ORDER BY codigo", 1 ) )
DO WHILE ! Eof()
? RecNo(), nomes->Codigo, nomes->descri, nomes->email
IF RecNo() == 10
DELETE
dbDelete()
ENDIF
IF RecNo() == 20
REPLACE email WITH "teste"
nomes->email := "teste"
ENDIF
SQLFetch()
@@ -63,7 +56,6 @@ PROCEDURE Main( cServer, cDatabase, cUser, cPass )
RETURN
/* Put theses functions in a library */
FUNCTION SQLApplyUpdates()
@@ -76,11 +68,9 @@ FUNCTION SQLApplyUpdates()
LOCAL lError := .F.
LOCAL cError
i := AScan( s_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } )
IF ( i := AScan( t_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } ) ) > 0
IF i != 0
oQuery := s_aTableTemp[ i ][ 3 ]
oQuery := t_aTableTemp[ i ][ DB_QUERY ]
FOR i := 1 TO LastRec()
@@ -88,7 +78,7 @@ FUNCTION SQLApplyUpdates()
IF i > oQuery:LastRec()
/* Verifica se eh um registro novo */
/* Check if it's a new record */
IF ! Deleted()
oRow := oQuery:GetBlankRow()
@@ -100,44 +90,32 @@ FUNCTION SQLApplyUpdates()
NEXT
oQuery:Append( oRow )
cError := oQuery:ErrorMsg()
lError := oQuery:NetErr()
ENDIF
ELSE
oRow := oQuery:GetRow( i )
lUpdate := .F.
IF Deleted()
oQuery:Delete( oRow )
cError := oQuery:ErrorMsg()
lError := oQuery:NetErr()
ELSE
/* Update if any of the fields have changed */
/* Faz update, mas compara quais campos sao diferentes */
lUpdate := .F.
FOR x := 1 TO FCount()
IF oRow:FieldPos( FieldName( x ) ) != 0
IF ! ( FieldGet( x ) == oRow:FieldGet( FieldName( x ) ) )
oRow:FieldPut( FieldName( x ), FieldGet( x ) )
lUpdate := .T.
ENDIF
IF oRow:FieldPos( FieldName( x ) ) != 0 .AND. ;
! FieldGet( x ) == oRow:FieldGet( FieldName( x ) )
oRow:FieldPut( FieldName( x ), FieldGet( x ) )
lUpdate := .T.
ENDIF
NEXT
IF lUpdate
oQuery:Update( oRow )
cError := oQuery:ErrorMsg()
lError := oQuery:NetErr()
ENDIF
ENDIF
ENDIF
@@ -149,68 +127,43 @@ FUNCTION SQLApplyUpdates()
ENDIF
IF lError
Alert( cError )
? cError
ENDIF
RETURN ! lError
PROCEDURE SQLCloseTemp( cAlias )
LOCAL x
IF ! Empty( Select( cAlias ) )
IF Select( cAlias ) != 0
( cAlias )->( dbCloseArea() )
ENDIF
x := AScan( s_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } )
IF ! Empty( x )
ADel( s_aTableTemp, x )
// ASize( s_aTableTemp, Len( s_aTableTemp ) - 1 )
IF ( x := AScan( t_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } ) ) > 0
hb_ADel( t_aTableTemp, x, .F. /* .T. */ )
ENDIF
RETURN
PROCEDURE SQLGarbageCollector()
LOCAL i
LOCAL item
LOCAL oQuery
dbCloseAll()
FOR i := 1 TO Len( s_aTableTemp )
/* Apaga arquivos dbfs criados */
FErase( s_aTableTemp[ i ][ DB_FILE ] )
oQuery := s_aTableTemp[ i ][ DB_QUERY ]
IF oQuery != NIL
FOR EACH item IN t_aTableTemp
IF ( oQuery := item[ DB_QUERY ] ) != NIL
oQuery:Destroy()
ENDIF
NEXT
FOR i := 1 TO Len( s_aTempDBF )
IF hb_FileExists( s_aTempDBF[ i ] )
FErase( s_aTempDBF[ i ] )
ENDIF
IF hb_FileExists( StrTran( s_aTempDBF[ i ], ".tmp", ".dbf" ) )
FErase( StrTran( s_aTempDBF[ i ], ".tmp", ".dbf" ) )
ENDIF
IF hb_FileExists( StrTran( s_aTempDBF[ i ], ".tmp", ".dbt" ) )
FErase( StrTran( s_aTempDBF[ i ], ".tmp", ".dbt" ) )
ENDIF
NEXT
s_aTableTemp := {}
s_aTempDBF := {}
ASize( t_aTableTemp, 0 )
RETURN
FUNCTION SQLFetch( fetchall )
FUNCTION SQLFetch( lFetchAll )
LOCAL oQuery
LOCAL oRow
@@ -219,26 +172,24 @@ FUNCTION SQLFetch( fetchall )
LOCAL nPos
LOCAL lEof := .F.
hb_default( @Fetchall, .F. )
hb_default( @lFetchAll, .F. )
/* Procura pela tabela no array */
i := AScan( s_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } )
/* Search for table in array */
IF ( i := AScan( t_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } ) ) > 0
IF i != 0
/* Traz registros da base de dados */
/* Get database records */
oQuery := t_aTableTemp[ i ][ DB_QUERY ]
nPos := t_aTableTemp[ i ][ DB_ROW ] + 1
oQuery := s_aTableTemp[ i ][ DB_QUERY ]
nPos := s_aTableTemp[ i ][ DB_ROW ] + 1
IF Fetchall
s_aTableTemp[ i ][ DB_FETCH ] := .T.
IF lFetchAll
t_aTableTemp[ i ][ DB_FETCH ] := .T.
ENDIF
IF oQuery:LastRec() >= nPos
y := nPos
DO WHILE nPos <= iif( FetchAll, oQuery:LastRec(), y )
DO WHILE nPos <= iif( lFetchAll, oQuery:LastRec(), y )
oRow := oQuery:GetRow( nPos )
dbAppend()
@@ -246,7 +197,7 @@ FUNCTION SQLFetch( fetchall )
FieldPut( FieldPos( oRow:FieldName( x ) ), oRow:FieldGet( x ) )
NEXT
s_aTableTemp[ i ][ DB_ROW ] := nPos
t_aTableTemp[ i ][ DB_ROW ] := nPos
nPos++
ENDDO
@@ -260,7 +211,6 @@ FUNCTION SQLFetch( fetchall )
RETURN lEof
PROCEDURE SQLFetchAll()
SQLFetch( .T. )
@@ -268,25 +218,19 @@ PROCEDURE SQLFetchAll()
RETURN
FUNCTION SQLOpen( cAlias, cQuery, xFetch, cOrder )
LOCAL cFile
LOCAL Result := .T.
LOCAL x
LOCAL s_oServer
LOCAL oServer
LOCAL oQuery
LOCAL aStrudbf
LOCAL lFetch
s_oServer := SQLCurrentServer()
oServer := SQLCurrentServer()
cAlias := Upper( cAlias )
/* Procura por query na area temporaria */
x := AScan( s_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } )
IF ! Empty( x )
oQuery := s_aTableTemp[ x ][ 3 ]
/* Search by query in temporary area */
IF ( x := AScan( t_aTableTemp, {| aVal | aVal[ DB_ALIAS ] == cAlias } ) ) > 0
oQuery := t_aTableTemp[ x ][ DB_QUERY ]
oQuery:Destroy()
ENDIF
@@ -297,28 +241,18 @@ FUNCTION SQLOpen( cAlias, cQuery, xFetch, cOrder )
ENDIF
ENDIF
cQuery := cQuery
oQuery := s_oServer:Query( cQuery )
oQuery := oServer:Query( cQuery )
IF oQuery:NetErr()
Alert( oQuery:ErrorMsg() )
? oQuery:ErrorMsg()
RETURN .F.
ENDIF
IF Empty( Select( cAlias ) )
/* Pega estrutura da base de dados */
aStrudbf := oQuery:Struct()
/* Cria tabela */
cFile := TempFile()
dbCreate( cFile, aStrudbf )
/* Abre Tabela */
dbUseArea( .T., NIL, cFile, cAlias, .F. )
IF Select( cAlias ) == 0
hb_dbCreateTemp( cAlias, oQuery:Struct() )
ELSE
Select( cAlias )
ZAP
dbSelectArea( cAlias )
hb_dbZap()
ENDIF
IF xFetch != NIL
@@ -327,182 +261,165 @@ FUNCTION SQLOpen( cAlias, cQuery, xFetch, cOrder )
lFetch := .F.
ENDIF
/* Se nao houver query na area temporaria entao adiciona, caso contrario, apenas atualiza */
IF Empty( x )
AAdd( s_aTableTemp, { ;
cAlias, ; // Table Name
cFile, ; // Temporary File Name
oQuery, ; // Object Query
0, ; // Current Row
lFetch } ) // Fetch Status
/* If there is no query in the temporary area then add, otherwise just refresh. */
IF x == 0
AAdd( t_aTableTemp, { ;
cAlias, ; // DB_ALIAS
oQuery, ; // DB_QUERY
0, ; // DB_ROW
lFetch } ) // DB_FETCH
ELSE
s_aTableTemp[ x ][ DB_QUERY ] := oQuery
s_aTableTemp[ x ][ DB_ROW ] := 0
s_aTableTemp[ x ][ DB_FETCH ] := lFetch
t_aTableTemp[ x ][ DB_QUERY ] := oQuery
t_aTableTemp[ x ][ DB_ROW ] := 0
t_aTableTemp[ x ][ DB_FETCH ] := lFetch
ENDIF
/* Traz registros da base de dados */
/* Get database records */
SQLFetch( lFetch )
IF lFetch
dbGoTop()
ENDIF
RETURN result
RETURN .T.
FUNCTION SQLConnect( cServer, cDatabase, cUser, cPassword, cSchema )
FUNCTION SQLConnect( cHost, cDatabase, cUser, cPassword, cSchema )
LOCAL lRetval := .T.
s_oServer := TPQServer():New( cServer, cDatabase, cUser, cPassWord, 5432, cSchema )
IF s_oServer:NetErr()
Alert( s_oServer:ErrorMsg() )
t_oServer := TPQServer():New( cHost, cDatabase, cUser, cPassword, 5432, cSchema )
IF t_oServer:NetErr()
? t_oServer:ErrorMsg()
lRetval := .F.
ENDIF
s_oServer:lAllCols := .F.
t_oServer:lAllCols := .F.
RETURN lRetval
PROCEDURE SQLDestroy()
IF s_oServer != NIL
s_oServer:Destroy()
IF t_oServer != NIL
t_oServer:Destroy()
ENDIF
RETURN
FUNCTION SQLCurrentServer
RETURN s_oServer
RETURN t_oServer
FUNCTION SQLQuery( cQuery )
LOCAL oQuery := s_oServer:Query( cQuery )
LOCAL oQuery := t_oServer:Query( cQuery )
IF oQuery:NetErr()
Alert( cQuery + ":" + oQuery:ErrorMsg() )
? cQuery + ":" + oQuery:ErrorMsg()
ENDIF
RETURN oQuery
FUNCTION SQLExecQuery( cQuery )
LOCAL oQuery
LOCAL result := .T.
LOCAL oQuery := t_oServer:Query( cQuery )
oQuery := s_oServer:Query( cQuery )
IF oQuery:NetErr()
Alert( "Cannot execute " + cQuery + ":" + oQuery:ErrorMsg() )
result := .F.
ELSE
oQuery:Destroy()
? "Cannot execute", cQuery + ":" + oQuery:ErrorMsg()
RETURN .F.
ENDIF
RETURN result
oQuery:Destroy()
RETURN .T.
FUNCTION SQLPrepare( cQuery, ... )
LOCAL i, x
IF PCount() >= 2
/* Limpa espacos desnecessarios */
DO WHILE At( Space( 2 ), cQuery ) != 0
/* Remove unnecessary whitespace */
DO WHILE Space( 2 ) $ cQuery
cQuery := StrTran( cQuery, Space( 2 ), Space( 1 ) )
ENDDO
/* Coloca {} nos parametros */
/* Place {} in the parameters */
FOR i := 1 TO PCount() - 1
IF ! Empty( x := At( ":" + hb_ntos( i ), cQuery ) )
IF ( x := At( ":" + hb_ntos( i ), cQuery ) ) > 0
cQuery := Stuff( cQuery, x, 0, "{" )
cQuery := Stuff( cQuery, x + Len( hb_ntos( i ) ) + 2, 0, "}" )
ENDIF
NEXT
/* Substitui parametros por valores passados */
/* Replace parameters with values */
FOR i := 2 TO PCount()
x := hb_PValue( i )
IF x != NIL .AND. Empty( x )
DO CASE
CASE x != NIL .AND. Empty( x )
x := "null"
ELSEIF HB_ISNUMERIC( x )
CASE HB_ISNUMERIC( x )
x := hb_ntos( x )
ELSEIF HB_ISDATE( x )
x := DToQ( x )
CASE HB_ISDATE( x )
x := "'" + hb_DToC( x, "yyyy-mm-dd" ) + "'"
ELSEIF HB_ISLOGICAL( x )
CASE HB_ISLOGICAL( x )
x := iif( x, "'t'", "'f'" )
ELSEIF HB_ISSTRING( x )
CASE HB_ISSTRING( x )
x := SToQ( RTrim( x ) )
ELSE
OTHERWISE
x := "null"
ENDIF
ENDCASE
cQuery := StrTran( cQuery, "{:" + hb_ntos( i - 1 ) + "}", x )
NEXT
ENDIF
cQuery := StrTran( cQuery, "==", "=" )
cQuery := StrTran( cQuery, "!=", "<>" )
cQuery := StrTran( cQuery, ".and.", "and" )
cQuery := StrTran( cQuery, ".or.", "or" )
cQuery := StrTran( cQuery, ".not.", "not" )
RETURN hb_StrReplace( cQuery, { ;
"==" => "=" , ;
"!=" => "<>" , ;
".and." => "and" , ;
".or." => "or" , ;
".not." => "not" } )
RETURN cQuery
/* Pega resultado de uma sequence */
/* Get next result of a sequence */
FUNCTION SQLSequence( Sequence_name )
RETURN Val( QuickQuery( "SELECT nextval(" + SToQ( sequence_name ) + ")" ) )
PROCEDURE SQLStartTrans()
IF PQtransactionStatus( s_oServer:pDB ) != PQTRANS_INTRANS
s_oServer:StartTransaction()
IF PQtransactionStatus( t_oServer:pDB ) != PQTRANS_INTRANS
t_oServer:StartTransaction()
ENDIF
RETURN
FUNCTION SQLInTrans()
RETURN PQtransactionStatus( s_oServer:pDB ) == PQTRANS_INTRANS
RETURN PQtransactionStatus( t_oServer:pDB ) == PQTRANS_INTRANS
PROCEDURE SQLCommitTrans()
s_oServer:Commit()
t_oServer:Commit()
RETURN
PROCEDURE SQLRollbackTrans()
s_oServer:rollback()
t_oServer:rollback()
RETURN
/* Faz querie que retorna apenas 1 valor de coluna */
/* Do query that returns only 1 column value */
FUNCTION QuickQuery( cQuery )
LOCAL pQuery
LOCAL result := ""
LOCAL temp, aTemp
LOCAL x, y
pQuery := PQexec( s_oServer:pDB, cQuery )
LOCAL pQuery := PQexec( t_oServer:pDB, cQuery )
IF PQresultStatus( pQuery ) == PGRES_TUPLES_OK
IF PQlastrec( pQuery ) != 0
@@ -525,51 +442,5 @@ FUNCTION QuickQuery( cQuery )
RETURN result
PROCEDURE MakeDBF( cAlias, aStructure, aIndex )
LOCAL cFile, i, cIndex, cKey
hb_default( @aIndex, {} )
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( s_aTempDBF, cIndex )
NEXT
AAdd( s_aTempDBF, cFile )
RETURN
FUNCTION TempFile( cPath, cExt )
LOCAL cString
hb_default( @cPath, hb_DirTemp() )
hb_default( @cExt, "tmp" )
cString := cPath + StrZero( Int( hb_Random( Val( StrTran( Time(), ":" ) ) ) ), 8 ) + "." + cExt
DO WHILE hb_FileExists( cString )
cString := cPath + StrZero( Int( hb_Random( Val( StrTran( Time(), ":" ) ) ) ), 8 ) + "." + cExt
ENDDO
RETURN cString
FUNCTION DToQ( cData )
RETURN "'" + Str( Year( cData ), 4 ) + "-" + StrZero( Month( cData ), 2 ) + "-" + StrZero( Day( cData ), 2 ) + "'"
FUNCTION SToQ( cData )
RETURN "'" + cData + "'"

View File

@@ -47,27 +47,26 @@
#require "hbpgsql"
#include "inkey.ch"
#include "fileio.ch"
#include "inkey.ch"
#include "hbextcdp.ch"
PROCEDURE Main( ... )
PROCEDURE Main()
LOCAL cTok
LOCAL cHostName := "localhost"
LOCAL cUser := "postgres"
LOCAL cPassWord := ""
LOCAL cDataBase, cTable, cFile
LOCAL aDbfStruct, i
LOCAL cHostName
LOCAL cUser
LOCAL cPassword
LOCAL cDatabase := "postgres", cTable, cFile
LOCAL i
LOCAL lCreateTable := .F.
LOCAL oServer, oTable, oRecord
LOCAL cField
LOCAL sType
LOCAL dType
LOCAL cTypeDB
LOCAL cTypePG
LOCAL cValue
LOCAL nCommit := 100
LOCAL nHandle
LOCAL hFile
LOCAL nCount := 0
LOCAL nRecno := 0
LOCAL lTruncate := .F.
@@ -75,80 +74,48 @@ PROCEDURE Main( ... )
LOCAL cPath := "public"
Set( _SET_DATEFORMAT, "yyyy-mm-dd" )
SET DELETE ON
Set( _SET_DELETED, .T. )
rddSetDefault( "DBFDBT" )
IF PCount() < 6
help()
QUIT
ENDIF
i := 1
/* Scan parameters and setup workings */
DO WHILE i <= PCount()
cTok := hb_PValue( i++ )
DO CASE
CASE cTok == "-h"
cHostName := hb_PValue( i++ )
CASE cTok == "-d"
cDataBase := hb_PValue( i++ )
CASE cTok == "-t"
cTable := hb_PValue( i++ )
CASE cTok == "-f"
cFile := hb_PValue( i++ )
CASE cTok == "-u"
cUser := hb_PValue( i++ )
CASE cTok == "-p"
cPassWord := hb_PValue( i++ )
CASE cTok == "-c"
lCreateTable := .T.
CASE cTok == "-x"
lTruncate := .T.
CASE cTok == "-s"
lUseTrans := .T.
CASE cTok == "-m"
nCommit := Val( hb_PValue( i++ ) )
CASE cTok == "-r"
nRecno := Val( hb_PValue( i++ ) )
CASE cTok == "-e"
cPath := hb_PValue( i++ )
CASE cTok == "-cp"
hb_cdpSelect( hb_PValue( i++ ) )
FOR i := 1 TO PCount()
SWITCH hb_PValue( i )
CASE "-h" ; cHostName := hb_PValue( ++i ) ; EXIT
CASE "-d" ; cDatabase := hb_PValue( ++i ) ; EXIT
CASE "-t" ; cTable := AllTrim( hb_PValue( ++i ) ) ; EXIT
CASE "-f" ; cFile := hb_PValue( ++i ) ; EXIT
CASE "-u" ; cUser := hb_PValue( ++i ) ; EXIT
CASE "-p" ; cPassword := hb_PValue( ++i ) ; EXIT
CASE "-c" ; lCreateTable := .T. ; EXIT
CASE "-x" ; lTruncate := .T. ; EXIT
CASE "-s" ; lUseTrans := .T. ; EXIT
CASE "-m" ; nCommit := Val( hb_PValue( ++i ) ) ; EXIT
CASE "-r" ; nRecno := Val( hb_PValue( ++i ) ) ; EXIT
CASE "-e" ; cPath := hb_PValue( ++i ) ; EXIT
CASE "-cp" ; Set( _SET_DBCODEPAGE, hb_PValue( ++i ) ) ; EXIT
OTHERWISE
help()
QUIT
ENDCASE
ENDDO
RETURN
ENDSWITCH
NEXT
// create log file
IF ( nHandle := FCreate( RTrim( cTable ) + ".log" ) ) == F_ERROR
? "Cannot create log file"
QUIT
IF Empty( cTable ) .OR. cFile == ""
help()
RETURN
ENDIF
USE ( cFile ) SHARED
aDbfStruct := dbStruct()
// create log file
IF ( hFile := hb_vfOpen( cTable + ".log", FO_CREAT + FO_TRUNC + FO_WRITE ) ) == NIL
? "Cannot create log file"
RETURN
ENDIF
oServer := TPQServer():New( cHostName, cDatabase, cUser, cPassWord, NIL, cPath )
USE ( cFile ) SHARED READONLY
oServer := TPQServer():New( cHostName, cDatabase, cUser, cPassword, , cPath )
IF oServer:NetErr()
? oServer:ErrorMsg()
QUIT
RETURN
ENDIF
oServer:lallCols := .F.
@@ -158,18 +125,18 @@ PROCEDURE Main( ... )
oServer:DeleteTable( cTable )
IF oServer:NetErr()
? oServer:ErrorMsg()
FWrite( nHandle, "Error: " + oServer:ErrorMsg() + hb_eol() )
FClose( nHandle )
QUIT
hb_vfWrite( hFile, "Error: " + oServer:ErrorMsg() + hb_eol() )
hb_vfClose( hFile )
RETURN
ENDIF
ENDIF
oServer:CreateTable( cTable, aDbfStruct )
oServer:CreateTable( cTable, dbStruct() )
IF oServer:NetErr()
? oServer:ErrorMsg()
FWrite( nHandle, "Error: " + oServer:ErrorMsg() + hb_eol() )
FClose( nHandle )
QUIT
hb_vfWrite( hFile, "Error: " + oServer:ErrorMsg() + hb_eol() )
hb_vfClose( hFile )
RETURN
ENDIF
ENDIF
@@ -177,75 +144,57 @@ PROCEDURE Main( ... )
oServer:Execute( "truncate table " + cTable )
IF oServer:NetErr()
? oServer:ErrorMsg()
FWrite( nHandle, "Error: " + oServer:ErrorMsg() + hb_eol() )
FClose( nHandle )
QUIT
hb_vfWrite( hFile, "Error: " + oServer:ErrorMsg() + hb_eol() )
hb_vfClose( hFile )
RETURN
ENDIF
ENDIF
oTable := oServer:Query( "SELECT * FROM " + cTable + " LIMIT 1" )
IF oTable:NetErr()
Alert( oTable:ErrorMsg() )
FWrite( nHandle, "Error: " + oTable:ErrorMsg() + hb_eol() )
FClose( nHandle )
QUIT
? oTable:ErrorMsg()
hb_vfWrite( hFile, "Error: " + oTable:ErrorMsg() + hb_eol() )
hb_vfClose( hFile )
RETURN
ENDIF
IF lUseTrans
oServer:StartTransaction()
ENDIF
FWrite( nHandle, "Start: " + Time() + hb_eol() )
hb_vfWrite( hFile, "Start: " + Time() + hb_eol() )
? "Start: ", Time()
? "Start:", Time()
?
IF ! Empty( nRecno )
IF nRecno != 0
dbGoto( nRecno )
ENDIF
DO WHILE ! Eof() .AND. Inkey() != K_ESC .AND. ( Empty( nRecno ) .OR. nRecno == RecNo() )
DO WHILE ! Eof() .AND. hb_keyStd( Inkey() ) != K_ESC .AND. ( nRecno == 0 .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 )
cTypeDB := Left( hb_FieldType( FieldPos( cField ) ), 1 )
cTypePG := oRecord:FieldType( i )
cValue := FieldGet( FieldPos( cField ) )
IF cValue != NIL
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 := hb_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. )
ENDIF
IF cTypePG != cTypeDB
DO CASE
CASE cTypePG == "C" .AND. cTypeDB $ "NIYF8BZ24" ; cValue := hb_ntos( cValue )
CASE cTypePG == "C" .AND. cTypeDB == "D" ; cValue := DToC( cValue )
CASE cTypePG == "C" .AND. cTypeDB $ "T@" ; cValue := hb_TToC( cValue )
CASE cTypePG == "C" .AND. cTypeDB == "L" ; cValue := iif( cValue, "S", "N" )
CASE cTypePG == "N" .AND. cTypeDB $ "CQ" ; cValue := Val( cValue )
CASE cTypePG == "N" .AND. cTypeDB == "D" ; cValue := Val( DToS( cValue ) )
CASE cTypePG == "N" .AND. cTypeDB == "L" ; cValue := iif( cValue, 1, 0 )
CASE cTypePG == "D" .AND. cTypeDB $ "CQ" ; cValue := CToD( cValue )
CASE cTypePG == "D" .AND. cTypeDB $ "NIYF8BZ24" ; cValue := hb_SToD( hb_ntos( cValue ) )
CASE cTypePG == "L" .AND. cTypeDB $ "NIYF8BZ24" ; cValue := ! Empty( cValue )
CASE cTypePG == "L" .AND. cTypeDB $ "CQ" ; cValue := AllTrim( cValue ) $ "YySs1"
ENDCASE
ENDIF
IF cValue != NIL
@@ -262,18 +211,18 @@ PROCEDURE Main( ... )
IF oTable:NetErr()
?
? "Error Record: ", RecNo(), Left( oTable:ErrorMsg(), 70 )
? "Error Record:", RecNo(), Left( oTable:ErrorMsg(), 70 )
?
FWrite( nHandle, "Error at record: " + hb_ntos( RecNo() ) + " Description: " + oTable:ErrorMsg() + hb_eol() )
hb_vfWrite( hFile, "Error at record: " + hb_ntos( RecNo() ) + " Description: " + oTable:ErrorMsg() + hb_eol() )
ELSE
nCount++
ENDIF
dbSkip()
IF ( nCount % nCommit ) == 0
IF nCount % nCommit == 0
DevPos( Row(), 1 )
DevOut( "imported recs: " + Str( nCount ) )
DevOut( "imported recs:", hb_ntos( nCount ) )
IF lUseTrans
oServer:commit()
@@ -282,41 +231,38 @@ PROCEDURE Main( ... )
ENDIF
ENDDO
IF ( nCount % nCommit ) != 0
IF lUseTrans
oServer:commit()
ENDIF
IF nCount % nCommit != 0 .AND. lUseTrans
oServer:commit()
ENDIF
FWrite( nHandle, "End: " + Time() + ", records in dbf: " + hb_ntos( RecNo() ) + ", imported recs: " + hb_ntos( nCount ) + hb_eol() )
hb_vfWrite( hFile, "End: " + Time() + ", records in dbf: " + hb_ntos( RecNo() ) + ", imported recs: " + hb_ntos( nCount ) + hb_eol() )
? "End: ", Time()
?
? "End:", Time()
FClose( nHandle )
hb_vfClose( hFile )
dbCloseAll()
CLOSE ALL
oTable:Destroy()
oServer:Destroy()
RETURN
PROCEDURE Help()
STATIC 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"
? "-h hostname"
? "-u user"
? "-p password"
? "-d name of database to use (default: postgres)"
? "-t name of table to add records to (required)"
? "-c delete existing table and create a new one"
? "-f name of .dbf file to import"
? "-f name of .dbf file to import (required)"
? "-x truncate table before append records"
? "-s use transaction"
? "-m commit interval"
? "-r insert only record number"
? "-e search path"
? ""
?
RETURN

View File

@@ -0,0 +1,75 @@
#require "hbpgsql"
PROCEDURE Main( cHost, cDatabase, cUser, cPass )
LOCAL nVersion
CLS
? "The function PQlibVersion() returns", nVersion := PQlibVersion()
?
IF nVersion < 90100
? "Function PQping() not supported."
QUIT
ENDIF
hb_default( @cHost, "localhost" )
hb_default( @cDatabase, "postgres" )
hb_default( @cUser, hb_UserName() )
hb_default( @cPass, "" )
/* PQping() reports the status of the server.
It accepts connection parameters identical to those of PQconnectdb().
It is not, however, necessary to supply correct user name, password,
or database name values to obtain the server status. */
HB_SYMBOL_UNUSED( cDatabase )
HB_SYMBOL_UNUSED( cUser )
HB_SYMBOL_UNUSED( cPass )
/* the ConnInfo string can be empty to use ALL default parameters */
PingTest( "" )
/* 'database' is not allowed parameter key, you can find the currently
recognized parameter key words on
https://www.postgresql.org/docs/9.1/static/libpq-connect.html */
PingTest( ;
"host = localhost" + " " + ;
"database = test" )
/* the default port for Postgres is 5432, but we can try connect to an
alternate port and see what happens. */
PingTest( ;
"host = " + cHost + " " + ;
"port = " + "3333" )
/* next attempt */
PingTest( ;
"host = " + cHost + " " + ;
"hostaddr = " + "127.0.0.1" + " " + ;
"port = " + "5432" + " " + ;
"connect_timeout = " + "10" )
RETURN
STATIC PROCEDURE PingTest( cConnInfo )
? "cConnInfo is", '"' + cConnInfo + '"'
? "PQPing( cConnInfo ) returns:", GetPingResult( PQPing( cConnInfo ) )
?
RETURN
STATIC FUNCTION GetPingResult( n )
LOCAL aMsg := { ;
{ "PQPING_OK" , "Server is accepting connections" }, ;
{ "PQPING_REJECT" , "Server is alive but rejecting connections" }, ;
{ "PQPING_NO_RESPONSE", "Could not establish connection" }, ;
{ "PQPING_NO_ATTEMPT" , "Connection not attempted (bad params)" } }
IF n >= 0 .AND. n < Len( aMsg )
RETURN aMsg[ n + 1 ][ 1 ] + " " + aMsg[ n + 1 ][ 2 ]
ENDIF
RETURN ""

View File

@@ -2,15 +2,13 @@
PROCEDURE Main( cHost, cDatabase, cUser, cPass )
LOCAL oServer, oQuery, oRow, i, x, aTables, aStruct
LOCAL cQuery, oQuery, oRow, i, x
LOCAL cQuery
oServer := TPQServer():New( cHost, cDatabase, cUser, cPass )
LOCAL oServer := TPQServer():New( cHost, hb_defaultValue( cDatabase, "postgres" ), cUser, cPass )
IF oServer:NetErr()
? oServer:ErrorMsg()
QUIT
RETURN
ENDIF
oServer:SetVerbosity( 2 )
@@ -18,32 +16,29 @@ PROCEDURE Main( cHost, cDatabase, cUser, cPass )
? "Tables..."
FOR x := 1 TO 1
aTables := oServer:ListTables()
FOR i := 1 TO Len( aTables )
? aTables[ i ]
NEXT
FOR EACH i IN oServer:ListTables()
? i
NEXT
IF oServer:TableExists( "TEST" )
? oQuery := oServer:Execute( "DROP TABLE Test" )
IF oServer:TableExists( "test" )
? oQuery := oServer:Execute( "DROP TABLE test" )
oQuery:Destroy()
ENDIF
? "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 ) "
cQuery := ;
"CREATE TABLE test(" + ;
" Code integer not null primary key," + ;
" dept Integer," + ;
" Name Varchar(40)," + ;
" Sales boolean," + ;
" Tax Float4," + ;
" Salary Double Precision," + ;
" Budget Numeric(12,2)," + ;
" Discount Numeric(5,2)," + ;
" Creation Date," + ;
" Description text )"
oQuery := oServer:Query( cQuery )
@@ -54,21 +49,20 @@ PROCEDURE Main( cHost, cDatabase, cUser, cPass )
oQuery:Destroy()
? "Structure of test table"
aStruct := oServer:TableStruct( "test" )
FOR i := 1 TO Len( aStruct )
FOR EACH i IN oServer:TableStruct( "test" )
?
FOR x := 1 TO Len( aStruct[ i ] )
?? aStruct[ i ][ x ], " "
FOR EACH x IN i
?? x, ""
NEXT
NEXT
? "Inserting, declared transaction control "
? "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) " + ;
"VALUES( " + Str( i ) + ", 2, 'TEST', 'y', 5, 3000, 1500.2, 7.5, '2003-12-17', 'Short Description about what ? ')"
"VALUES( " + hb_ntos( i ) + ", 2, 'TEST', 'y', 5, 3000, 1500.2, 7.5, '2003-12-17', 'Short Description about what ?')"
oQuery := oServer:Query( cQuery )
@@ -83,13 +77,11 @@ PROCEDURE Main( cHost, cDatabase, cUser, cPass )
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 ]
FOR EACH i IN oQuery:Struct()
? i[ 1 ], i[ 2 ], i[ 3 ], i[ 4 ]
NEXT
? "Fields: ", oQuery:FCount()
? "Fields:", oQuery:FCount()
oRow := oQuery:Blank()
@@ -130,12 +122,12 @@ PROCEDURE Main( cHost, cDatabase, cUser, cPass )
oRow := oQuery:getrow()
oRow:FieldPut( 2, "My Second test" )
? "Update: ", oQuery:Update( oRow )
? "Update:", oQuery:Update( oRow )
ENDIF
IF oQuery:RecNo() == 60
oRow := oQuery:getrow()
? "Delete: ", oQuery:Delete( oRow )
? "Delete:", oQuery:Delete( oRow )
ENDIF
oQuery:Skip()

View File

@@ -1,10 +1,8 @@
/*
* VERY IMPORTANT: Don't use this querys as sample, they are used for stress tests !!!
*/
/* IMPORTANT: Don't use these queries as sample, they are used for stress tests!!! */
#require "hbpgsql"
PROCEDURE Main( cServer, cDatabase, cUser, cPass )
PROCEDURE Main( cHost, cDatabase, cUser, cPass )
LOCAL conn, res, i, x
@@ -12,13 +10,18 @@ PROCEDURE Main( cServer, cDatabase, cUser, cPass )
CLS
? "Connecting...."
conn := PQconnectdb( "dbname = " + cDatabase + " host = " + cServer + " user = " + cUser + " password = " + cPass + " port = 5432" )
? "Connecting..."
conn := PQconnectdb( ;
"dbname = '" + hb_defaultValue( cDatabase, "postgres" ) + "' " + ;
"host = '" + hb_defaultValue( cHost, "localhost" ) + "' " + ;
"user = '" + hb_defaultValue( cUser, hb_UserName() ) + "' " + ;
"password = '" + hb_defaultValue( cPass, "" ) + "' " + ;
"port = 5432" )
? PQstatus( conn ), PQerrorMessage( conn )
IF PQstatus( conn ) != CONNECTION_OK
QUIT
RETURN
ENDIF
? "Dropping table..."
@@ -26,55 +29,57 @@ PROCEDURE Main( cServer, cDatabase, cUser, cPass )
PQexec( conn, "DROP TABLE test" )
? "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 ) "
cQuery := ;
"CREATE TABLE test(" + ;
" Code integer not null primary key," + ;
" dept Integer," + ;
" Name Varchar(40)," + ;
" Sales boolean," + ;
" Tax Float4," + ;
" Salary Double Precision," + ;
" Budget Numeric(12,2)," + ;
" Discount Numeric(5,2)," + ;
" Creation Date," + ;
" Description text )"
PQexec( conn, cQuery )
PQexec( conn, "SELECT code, dept, name, sales, salary, creation FROM test" )
PQexec( conn, "BEGIN" )
?
FOR i := 1 TO 10000
@ 15, 0 SAY "Inserting values...." + Str( i )
@ 15, 0 SAY "Inserting values... " + hb_ntos( i )
cQuery := "INSERT INTO test(code, dept, name, sales, salary, creation) " + ;
"VALUES( " + Str( i ) + "," + Str( i + 1 ) + ", 'DEPARTMENT NAME " + StrZero( i ) + "', 'y', " + Str( 300.49 + i ) + ", '2003-12-28' )"
"VALUES( " + hb_ntos( i ) + "," + hb_ntos( i + 1 ) + ", 'DEPARTMENT NAME " + StrZero( i ) + "', 'y', " + hb_ntos( 300.49 + i ) + ", '2003-12-28' )"
PQexec( conn, cQuery )
IF Mod( i, 100 ) == 0
IF i % 100 == 0
? PQexec( conn, "COMMIT" )
? PQexec( conn, "BEGIN" )
ENDIF
NEXT
FOR i := 5000 TO 7000
@ 16, 0 SAY "Deleting values...." + Str( i )
@ 16, 0 SAY "Deleting values... " + hb_ntos( i )
cQuery := "DELETE FROM test WHERE code = " + Str( i )
cQuery := "DELETE FROM test WHERE code = " + hb_ntos( i )
PQexec( conn, cQuery )
IF Mod( i, 100 ) == 0
IF i % 100 == 0
PQexec( conn, "COMMIT" )
PQexec( conn, "BEGIN" )
ENDIF
NEXT
FOR i := 2000 TO 3000
@ 17, 0 SAY "Updating values...." + Str( i )
@ 17, 0 SAY "Updating values... " + hb_ntos( i )
cQuery := "UPDATE FROM test SET salary = 400 WHERE code = " + Str( i )
cQuery := "UPDATE FROM test SET salary = 400 WHERE code = " + hb_ntos( i )
PQexec( conn, cQuery )
IF Mod( i, 100 ) == 0
IF i % 100 == 0
PQexec( conn, "COMMIT" )
PQexec( conn, "BEGIN" )
ENDIF
@@ -83,21 +88,20 @@ PROCEDURE Main( cServer, cDatabase, cUser, cPass )
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 )
@ 18, 0 SAY "Sum values... " + PQgetvalue( res, 1, 1 )
ENDIF
x := 0
FOR i := 1 TO 4000
res := PQexec( conn, "SELECT salary FROM test WHERE code = " + Str( i ) )
res := PQexec( conn, "SELECT salary FROM test WHERE code = " + hb_ntos( i ) )
IF PQresultStatus( res ) == PGRES_TUPLES_OK
x += Val( PQgetvalue( res, 1, 1 ) )
@ 19, 0 SAY "Sum values...." + Str( x )
@ 19, 0 SAY "Sum values... " + hb_ntos( x )
ENDIF
NEXT
? "Closing..."
conn := NIL
RETURN

View File

@@ -1,37 +1,39 @@
#require "hbpgsql"
PROCEDURE Main()
PROCEDURE Main( cHost, cDatabase, cUser, cPass )
LOCAL conn, res, aTemp, x, y, pFile
LOCAL cDb := "test"
LOCAL cUser := "user"
LOCAL cPass := "pass"
LOCAL conn, res, x, y, pFile
CLS
conn := PQsetdbLogin( "localhost", "5432", NIL, NIL, cDb, cUser, cPass )
conn := PQsetdbLogin( cHost, "5432", , , cDatabase, cUser, cPass )
? PQdb( conn ), PQuser( conn ), PQpass( conn ), PQhost( conn ), PQport( conn ), PQtty( conn ), PQoptions( conn )
conn := PQconnectdb( "dbname = " + cDb + " host = localhost user = " + cUser + " password = " + cPass + " port = 5432" )
conn := PQconnectdb( ;
"dbname = '" + hb_defaultValue( cDatabase, "postgres" ) + "' " + ;
"host = '" + hb_defaultValue( cHost, "localhost" ) + "' " + ;
"user = '" + hb_defaultValue( cUser, hb_UserName() ) + "' " + ;
"password = '" + hb_defaultValue( cPass, "" ) + "' " + ;
"port = 5432" )
? PQstatus( conn ), PQerrorMessage( conn )
IF PQstatus( conn ) != CONNECTION_OK
QUIT
RETURN
ENDIF
? "Blocking: ", PQisnonblocking( conn ), PQsetnonblocking( conn, .T. ), PQisnonblocking( conn )
? "Blocking:", PQisnonblocking( conn ), PQsetnonblocking( conn, .T. ), PQisnonblocking( conn )
pFile := PQtracecreate( "trace.log" )
pFile := PQtracecreate( hb_DirBase() + "trace.log" )
PQtrace( conn, pFile )
? "Verbose: ", PQsetErrorVerbosity( conn, 2 )
? "Verbose:", PQsetErrorVerbosity( conn, 2 )
? ;
"Protocol: ", PQprotocolVersion( conn ), ;
" Server Version: ", PQserverVersion( conn ), ;
" Client Encoding: ", PQsetClientEncoding( conn, "ASCII" ), ;
"New encode: ", PQclientEncoding( conn )
? "Protocol:", PQprotocolVersion( conn )
? "Server version:", PQserverVersion( conn )
? "Client encoding (old):", pg_encoding_to_char( PQclientEncoding( conn ) )
? "Set client encoding:", PQsetClientEncoding( conn, "UTF-8" )
? "Client encoding (new):", pg_encoding_to_char( PQclientEncoding( conn ) )
? PQdb( conn ), PQuser( conn ), PQpass( conn ), PQhost( conn ), PQport( conn ), PQtty( conn ), PQoptions( conn )
@@ -42,8 +44,8 @@ PROCEDURE Main()
res := PQexec( conn, "create table products ( product_no numeric(10), name varchar(20), price numeric(10,2) )" )
? PQresultStatus( res ), PQresultErrorMessage( 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 )
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 )
@@ -55,16 +57,15 @@ PROCEDURE Main()
? PQresultStatus( res ), PQresultErrorMessage( res )
ENDIF
? "Binary: ", PQbinaryTuples( res )
? "Rows: ", PQntuples( res ), "Cols: ", PQnfields( res )
? "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 EACH x IN PQmetadata( res )
? "Line 1:", ""
FOR y := 1 TO 6
?? aTemp[ x ][ y ], ", "
?? x[ y ], ",", ""
NEXT
NEXT

File diff suppressed because it is too large Load Diff