/*
 * PostgreSQL RDBMS low-level (client API) interface code.
 *
 * Copyright 2016 P.Chornyj <myorg63@mail.ru>
 * 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
 * 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 program; see the file LICENSE.txt.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
 *
 * 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.
 *
 */

#include "hbpgsql.h"

#include "hbapierr.h"
#include "hbapiitm.h"

static HB_GARBAGE_FUNC( PGconn_release )
{
   void ** ph = ( void ** ) Cargo;

   /* Check if pointer is not NULL to avoid multiple freeing */
   if( ph && *ph )
   {
      /* Destroy the object */
      PQfinish( ( PGconn * ) *ph );

      /* set pointer to NULL to avoid multiple freeing */
      *ph = NULL;
   }
}

static const HB_GC_FUNCS s_gcPGconnFuncs =
{
   PGconn_release,
   hb_gcDummyMark
};

void hb_PGconn_ret( PGconn * p )
{
   if( p )
   {
      void ** ph = ( void ** ) hb_gcAllocate( sizeof( PGconn * ), &s_gcPGconnFuncs );

      *ph = p;

      hb_retptrGC( ph );
   }
   else
      hb_retptr( NULL );
}

PGconn * hb_PGconn_par( int iParam )
{
   void ** ph = ( void ** ) hb_parptrGC( &s_gcPGconnFuncs, iParam );

   return ph ? ( PGconn * ) *ph : NULL;
}

static HB_GARBAGE_FUNC( PGresult_release )
{
   void ** ph = ( void ** ) Cargo;

   /* Check if pointer is not NULL to avoid multiple freeing */
   if( ph && *ph )
   {
      /* Destroy the object */
      PQclear( ( PGresult * ) *ph );

      /* set pointer to NULL to avoid multiple freeing */
      *ph = NULL;
   }
}

static const HB_GC_FUNCS s_gcPGresultFuncs =
{
   PGresult_release,
   hb_gcDummyMark
};

void hb_PGresult_ret( PGresult * p )
{
   if( p )
   {
      void ** ph = ( void ** ) hb_gcAllocate( sizeof( PGresult * ), &s_gcPGresultFuncs );

      *ph = p;

      hb_retptrGC( ph );
   }
   else
      hb_retptr( NULL );
}

PGresult * hb_PGresult_par( int iParam )
{
   void ** ph = ( void ** ) hb_parptrGC( &s_gcPGresultFuncs, iParam );

   return ph ? ( PGresult * ) *ph : NULL;
}

#if PG_VERSION_NUM >= 80000

static HB_GARBAGE_FUNC( PGcancel_release )
{
   void ** ph = ( void ** ) Cargo;

   /* Check if pointer is not NULL to avoid multiple freeing */
   if( ph && *ph )
   {
      /* Destroy the object */
      PQfreeCancel( ( PGcancel * ) *ph );

      /* set pointer to NULL to avoid multiple freeing */
      *ph = NULL;
   }
}

static const HB_GC_FUNCS s_gcPGcancelFuncs =
{
   PGcancel_release,
   hb_gcDummyMark
};

static void hb_PGcancel_ret( PGcancel * p )
{
   if( p )
   {
      void ** ph = ( void ** ) hb_gcAllocate( sizeof( PGcancel * ), &s_gcPGcancelFuncs );

      *ph = p;

      hb_retptrGC( ph );
   }
   else
      hb_retptr( NULL );
}

static PGcancel * hb_PGcancel_par( int iParam )
{
   void ** ph = ( void ** ) hb_parptrGC( &s_gcPGcancelFuncs, iParam );

   return ph ? ( PGcancel * ) *ph : NULL;
}

#endif

#ifdef NODLL

static HB_GARBAGE_FUNC( FILE_release )
{
   void ** ph = ( void ** ) Cargo;

   /* Check if pointer is not NULL to avoid multiple freeing */
   if( ph && *ph )
   {
      /* Destroy the object */
      fclose( ( FILE * ) *ph );

      /* set pointer to NULL to avoid multiple freeing */
      *ph = NULL;
   }
}

static const HB_GC_FUNCS s_gcFILEFuncs =
{
   FILE_release,
   hb_gcDummyMark
};

static void hb_FILE_ret( FILE * p )
{
   if( p )
   {
      void ** ph = ( void ** ) hb_gcAllocate( sizeof( FILE * ), &s_gcFILEFuncs );

      *ph = p;

      hb_retptrGC( ph );
   }
   else
      hb_retptr( NULL );
}

static FILE * hb_FILE_par( int iParam )
{
   void ** ph = ( void ** ) hb_parptrGC( &s_gcFILEFuncs, iParam );

   return ph ? ( FILE * ) *ph : NULL;
}

#endif

/* 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 )
{
   if( HB_ISCHAR( 1 ) )
      hb_PGconn_ret( PQconnectdb( hb_parc( 1 ) ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* NOTE: Deprecated */
HB_FUNC( PQSETDBLOGIN )
{
   hb_PGconn_ret( PQsetdbLogin( hb_parcx( 1 ) /* pghost */,
                                hb_parcx( 2 ) /* pgport */,
                                hb_parcx( 3 ) /* pgoptions */,
                                hb_parcx( 4 ) /* pgtty */,
                                hb_parcx( 5 ) /* dbName */,
                                hb_parcx( 6 ) /* login */,
                                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 );

   if( conn )
      PQreset( conn );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQRESETSTART )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( 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 );

   if( conn )
      hb_retni( PQclientEncoding( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQSETCLIENTENCODING )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( PQsetClientEncoding( conn, hb_parcx( 2 ) ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQDB )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQdb( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQUSER )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQuser( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQPASS )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQpass( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQHOST )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQhost( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQPORT )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQport( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQTTY )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQtty( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQOPTIONS )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retc( PQoptions( conn ) );
   else
      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 );

   if( conn )
      hb_retni( PQtransactionStatus( conn ) );
   else
      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 );

   if( conn )
      hb_retc( PQerrorMessage( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQSOCKET )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( PQsocket( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

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 )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_PGresult_ret( PQexec( conn, hb_parcx( 2 ) ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQEXECPARAMS )
{
   PGconn * conn   = hb_PGconn_par( 1 );
   PHB_ITEM aParam = hb_param( 3, HB_IT_ARRAY );

   if( conn && aParam )
   {
      int n = ( int ) hb_arrayLen( aParam );

      if( ! n )
         hb_PGresult_ret( PQexec( conn, hb_parcx( 2 ) ) );
      else
      {
         int 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( PQexecParams( conn, hb_parcx( 2 ), n, NULL, paramvalues, NULL, NULL, hb_parnidef( 4, 1 ) ) );

         hb_xfree( ( void * ) paramvalues );
      }
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFCOUNT )  /* not a direct wrapper */
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
   {
      int nFields = 0;

      if( PQresultStatus( res ) == PGRES_TUPLES_OK )
         nFields = PQnfields( res );

      hb_retni( nFields );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQLASTREC )  /* not a direct wrapper */
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
   {
      int nRows = 0;

      if( PQresultStatus( res ) == PGRES_TUPLES_OK )
         nRows = PQntuples( res );

      hb_retni( nRows );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQGETVALUE )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
   {
      if( PQresultStatus( res ) == PGRES_TUPLES_OK )
      {
         int nRow = hb_parni( 2 ) - 1;
         int nCol = hb_parni( 3 ) - 1;

         if( ! PQgetisnull( res, nRow, nCol ) )
            hb_retc( PQgetvalue( res, nRow, nCol ) );
         else
            hb_ret();
      }
      else
         hb_ret();
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQGETLENGTH )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
   {
      int result = 0;

      if( PQresultStatus( res ) == PGRES_TUPLES_OK )
      {
         int nRow = hb_parni( 2 ) - 1;
         int nCol = hb_parni( 3 ) - 1;

         result = PQgetlength( res, nRow, nCol );
      }

      hb_retni( result );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* PQmetadata() positions for array returned */
#define HBPG_META_FIELDNAME  1
#define HBPG_META_FIELDTYPE  2
#define HBPG_META_FIELDLEN   3
#define HBPG_META_FIELDDEC   4
#define HBPG_META_TABLE      5
#define HBPG_META_TABLECOL   6
#define HBPG_META_LEN_       6

HB_FUNC( PQMETADATA )  /* not a direct wrapper */
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
   {
      if( PQresultStatus( res ) == PGRES_TUPLES_OK )
      {
         int      nFields = PQnfields( res ), i;
         PHB_ITEM pResult = hb_itemArrayNew( nFields );

         for( i = 0; i < nFields; i++ )
         {
            char buf[ 256 ];
            int  typemod = PQfmod( res, i );
            int  length  = 0;
            int  decimal = 0;

            PHB_ITEM pField;

            switch( PQftype( res, i ) )
            {
               case BITOID:
                  if( typemod >= 0 )
                     length = ( int ) typemod;
                  hb_strncpy( buf, "bit", sizeof( buf ) - 1 );
                  break;

               case BOOLOID:
                  length = 1;
                  hb_strncpy( buf, "boolean", sizeof( buf ) - 1 );
                  break;

               case BPCHAROID:
                  if( typemod >= 0 )
                     length = ( int ) ( typemod - VARHDRSZ );
                  hb_strncpy( buf, "character", sizeof( buf ) - 1 );
                  break;

               case FLOAT4OID:
                  hb_strncpy( buf, "real", sizeof( buf ) - 1 );
                  break;

               case FLOAT8OID:
                  hb_strncpy( buf, "double precision", sizeof( buf ) - 1 );
                  break;

               case INT2OID:
                  hb_strncpy( buf, "smallint", sizeof( buf ) - 1 );
                  break;

               case INT4OID:
                  hb_strncpy( buf, "integer", sizeof( buf ) - 1 );
                  break;

               case INT8OID:
               case OIDOID:
                  hb_strncpy( buf, "bigint", sizeof( buf ) - 1 );
                  break;

               case NUMERICOID:
                  length  = ( ( typemod - VARHDRSZ ) >> 16 ) & 0xffff;
                  decimal = ( typemod - VARHDRSZ ) & 0xffff;
                  hb_strncpy( buf, "numeric", sizeof( buf ) - 1 );
                  break;

               case DATEOID:
                  hb_strncpy( buf, "date", sizeof( buf ) - 1 );
                  break;

               case TIMEOID:
               case TIMETZOID:
                  hb_strncpy( buf, "timezone", sizeof( buf ) - 1 );
                  break;

               case TIMESTAMPOID:
               case TIMESTAMPTZOID:
                  hb_strncpy( buf, "timestamp", sizeof( buf ) - 1 );
                  break;

               case VARBITOID:
                  if( typemod >= 0 )
                     length = ( int ) typemod;
                  hb_strncpy( buf, "bit varying", sizeof( buf ) - 1 );
                  break;

               case VARCHAROID:
                  if( typemod >= 0 )
                     length = ( int ) ( typemod - VARHDRSZ );
                  hb_strncpy( buf, "character varying", sizeof( buf ) - 1 );
                  break;

               case TEXTOID:
                  hb_strncpy( buf, "text", sizeof( buf ) - 1 );
                  break;

               case CASHOID:
                  hb_strncpy( buf, "money", sizeof( buf ) - 1 );
                  break;

               case NAMEOID:
                  hb_strncpy( buf, "name", sizeof( buf ) - 1 );
                  break;

               default:
                  hb_strncpy( buf, "not supported", sizeof( buf ) - 1 );
                  break;
            }

            pField = hb_arrayGetItemPtr( pResult, i + 1 );
            hb_arrayNew( pField, HBPG_META_LEN_ );
            hb_arraySetC(  pField, HBPG_META_FIELDNAME, PQfname( res, i ) );
            hb_arraySetC(  pField, HBPG_META_FIELDTYPE, buf );
            hb_arraySetNI( pField, HBPG_META_FIELDLEN, length );
            hb_arraySetNI( pField, HBPG_META_FIELDDEC, decimal );
            hb_arraySetNL( pField, HBPG_META_TABLE, PQftable( res, i ) );
            hb_arraySetNI( pField, HBPG_META_TABLECOL, PQftablecol( res, i ) );
         }

         hb_itemReturnRelease( pResult );
      }
      else
         hb_reta( 0 );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQRESULT2ARRAY )  /* not a direct wrapper */
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
   {
      if( PQresultStatus( res ) == PGRES_TUPLES_OK )
      {
         int nRows = PQntuples( res ), nRow;
         int nCols = PQnfields( res ), nCol;

         PHB_ITEM pResult = hb_itemArrayNew( nRows );

         for( nRow = 0; nRow < nRows; nRow++ )
         {
            PHB_ITEM pRow = hb_arrayGetItemPtr( pResult, nRow + 1 );
            hb_arrayNew( pRow, nCols );
            for( nCol = 0; nCol < nCols; nCol++ )
               hb_arraySetC( pRow, nCol + 1, PQgetvalue( res, nRow, nCol ) );
         }

         hb_itemReturnRelease( pResult );
      }
      else
         hb_reta( 0 );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQRESULTERRORMESSAGE )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retc( PQresultErrorMessage( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQRESULTSTATUS )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retni( PQresultStatus( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQCMDSTATUS )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retc( PQcmdStatus( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQCMDTUPLES )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retc( PQcmdTuples( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQESCAPESTRING )
{
   const char * source = hb_parcx( 1 );
   HB_SIZE      size   = strlen( source );
   char *       dest   = ( char * ) hb_xgrab( size * 2 + 1 );

   PQescapeString( dest, source, ( size_t ) size );

   hb_retc_buffer( dest );
}

HB_FUNC( PQESCAPEBYTEA )  /* deprecated */
{
   if( HB_ISCHAR( 1 ) )
   {
      size_t from_length = ( size_t ) hb_parclen( 1 );
      size_t to_length   = from_length * 5 + 1;
      unsigned char * to = PQescapeBytea( ( const unsigned char * ) hb_parc( 1 ), from_length, &to_length );
      hb_retclen( ( char * ) to, ( HB_SIZE ) to_length );
      PQfreemem( to );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQUNESCAPEBYTEA )
{
   if( HB_ISCHAR( 1 ) )
   {
      size_t to_length;
      unsigned char * from = PQunescapeBytea( ( const unsigned char * ) hb_parc( 1 ), &to_length );
      hb_retclen( ( char * ) from, ( HB_SIZE ) to_length );
      PQfreemem( from );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQOIDVALUE )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retnl( ( Oid ) PQoidValue( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQOIDSTATUS )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retc( PQoidStatus( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQBINARYTUPLES )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retl( PQbinaryTuples( res ) ? HB_TRUE : HB_FALSE );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFTABLE )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retnl( ( Oid ) PQftable( res, hb_parni( 2 ) - 1 ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFTYPE )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retnl( ( Oid ) PQftype( res, hb_parni( 2 ) - 1 ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFNAME )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retc( PQfname( res, hb_parni( 2 ) - 1 ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFMOD )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retni( PQfmod( res, hb_parni( 2 ) - 1 ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFSIZE )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retni( PQfsize( res, hb_parni( 2 ) - 1 ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQGETISNULL )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      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 );
}

HB_FUNC( PQFNUMBER )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retni( PQfnumber( res, hb_parcx( 2 ) ) + 1 );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQNTUPLES )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retnl( PQntuples( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQNFIELDS )
{
   PGresult * res = hb_PGresult_par( 1 );

   if( res )
      hb_retnl( PQnfields( res ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* Asynchronous functions */

HB_FUNC( PQSENDQUERY )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retl( PQsendQuery( conn, hb_parcx( 2 ) ) ? HB_TRUE : HB_FALSE );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQGETRESULT )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_PGresult_ret( PQgetResult( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQCONSUMEINPUT )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retl( PQconsumeInput( conn ) ? HB_TRUE : HB_FALSE );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQISBUSY )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retl( PQisBusy( conn ) ? HB_TRUE : HB_FALSE );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQREQUESTCANCEL ) /* deprecated */
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retl( PQrequestCancel( conn ) ? HB_TRUE : HB_FALSE );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQFLUSH )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( PQflush( conn ) );
   else
      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_TRUE : HB_FALSE );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQISNONBLOCKING )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( 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 */

HB_FUNC( PQTRACECREATE )  /* not a direct wrapper */
{
#ifdef NODLL
   hb_FILE_ret( hb_fopen( hb_parcx( 1 ), "w+b" ) );
#else
   hb_retptr( NULL );
#endif
}

HB_FUNC( PQTRACE )
{
#ifdef NODLL
   PGconn * conn   = hb_PGconn_par( 1 );
   FILE *   trfile = hb_FILE_par( 2 );

   if( conn && trfile )
      PQtrace( conn, trfile );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#endif
}

HB_FUNC( PQUNTRACE )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      PQuntrace( conn );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* PQERRORS_TERSE   0
   PQERRORS_DEFAULT 1
   PQERRORS_VERBOSE 2
 */
HB_FUNC( PQSETERRORVERBOSITY )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( ( PGVerbosity ) PQsetErrorVerbosity( conn, ( PGVerbosity ) hb_parni( 2 ) ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* Large Object functions */

HB_FUNC( LO_IMPORT )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( lo_import( conn, hb_parcx( 2 ) ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( LO_EXPORT )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retl( lo_export( conn, ( Oid ) hb_parnl( 2 ), hb_parcx( 3 ) ) == 1 );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( LO_UNLINK )
{
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retl( lo_unlink( conn, ( Oid ) hb_parnl( 2 ) ) == 1 );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQGETCANCEL )
{
#if PG_VERSION_NUM >= 80000
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_PGcancel_ret( PQgetCancel( conn ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#else
   hb_retptr( NULL );
#endif
}

HB_FUNC( PQCANCEL )
{
#if PG_VERSION_NUM >= 80000
   PGcancel * cancel = hb_PGcancel_par( 1 );

   if( cancel )
   {
      char errbuf[ 256 ];

      errbuf[ 0 ] = '\0';

      hb_retl( PQcancel( cancel, errbuf, sizeof( errbuf ) - 1 ) ? HB_TRUE : HB_FALSE );

      hb_storc( errbuf, 2 );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#else
   hb_retl( HB_FALSE );
   hb_storc( NULL, 2 );
#endif
}

HB_FUNC( PQESCAPEBYTEACONN )
{
#if PG_VERSION_NUM >= 80000
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn && HB_ISCHAR( 2 ) )
   {
      size_t from_length = hb_parclen( 2 );
      size_t to_length   = from_length * 5 + 1;

      unsigned char * to = PQescapeByteaConn( conn, ( unsigned const char * ) hb_parc( 2 ), from_length, &to_length );
      hb_retclen( ( char * ) to, ( HB_SIZE ) to_length );
      PQfreemem( to );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#else
   hb_retc_null();
#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 ), ( int ) n, ( const char * const * ) paramvalues, NULL, NULL, 1 ) );

      hb_xfree( ( void * ) paramvalues );
   }
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

HB_FUNC( PQPUTCOPYDATA )
{
#if PG_VERSION_NUM >= 80000
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( PQputCopyData( conn, hb_parcx( 2 ), ( int ) hb_parclen( 2 ) ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#else
   hb_retc_null();
#endif
}

HB_FUNC( PQPUTCOPYEND )
{
#if PG_VERSION_NUM >= 80000
   PGconn * conn = hb_PGconn_par( 1 );

   if( conn )
      hb_retni( PQputCopyEnd( conn, NULL ) );
   else
      hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
#else
   hb_retc_null();
#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
 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 );

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 );

#endif
