fe-exec.f90 Source File


Contents

Source Code


Source Code

module fe_exec_m
   implicit none
   private

   public :: PQexec
   public :: PQresultStatus
   public :: PQresultErrorMessage
   public :: PQresultVerboseErrorMessage
   public :: PQgetvalue
   public :: PQntuples
   public :: PQnfields
   public :: PQfname
   public :: PQfnumber
   public :: PQclear
   public :: PQgetisnull
   public :: PQfreemem
   public :: PQbinaryTuples
   public :: PQfformat
   public :: PQfmod
   public :: PQfsize
   public :: PQftablecol
   public :: PQftable
   public :: PQftype
   public :: PQresStatus
   public :: PQgetlength
   public :: PQnparams
   public :: PQparamtype
   public :: PQresultErrorField
   public :: PQcmdStatus
   public :: PQcmdTuples
   public :: PQoidValue

   public :: PQsendQuery
   public :: PQgetResult
   public :: PQconsumeInput
   public :: PQisBusy
   public :: PQsetnonblocking
   public :: PQisnonblocking
   public :: PQflush
   public :: PQescapeLiteral
   public :: PQescapeIdentifier

   public :: PQexecParams

   interface PQexecParams
      module procedure :: PQexecParams_int32
      module procedure :: PQexecParams_int64
   end interface

   public :: PQprepare
   interface PQprepare
      module procedure :: PQprepare_int32
      module procedure :: PQprepare_int64
   end interface

   public :: PQexecPrepared
   public :: PQdescribePrepared
   public :: PQdescribePortal

   public :: PQsendPrepare
   interface PQsendPrepare
      module procedure :: PQsendPrepare_int32
      module procedure :: PQsendPrepare_int64
   end interface 

   public :: PQsendQueryPrepared
   interface PQsendQueryPrepared
      module procedure :: PQsendQueryPrepared_text
   end interface

   public :: PQsendDescribePrepared
   public :: PQsendDescribePortal
   public :: PQpipelineStatus
   public :: PQenterPipelineMode
   public :: PQexitPipelineMode
   public :: PQpipelineSync
   public :: PQsendFlushRequest
   public :: PQsetSingleRowMode

   public :: PQsendQueryParams
   interface PQsendQueryParams 
      module procedure :: PQsendQueryParams_int32
      module procedure :: PQsendQueryParams_int64
   end interface 

   public :: PQisthreadsafe

   public :: PQmakeEmptyPGresult
   public :: PQcopyResult
   public :: PQnotifies
      

contains


!==================================================================!
!== Command Execution Functions
!== Main Functions

   !> Send query to the server and wait until receiving the result.
   function PQexec (conn, query) result(res)
      use, intrinsic :: iso_c_binding
      implicit none
      
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: query
      character(:, kind=c_char), allocatable :: c_query
      type(c_ptr) :: res
      
      interface
         ! Interface to PQexec in interfaces/libpq/fe-exec.c:
         !
         ! PGresult *PQexec(PGconn *conn, const char *query)
         !
         function c_PQ_exec (conn, query) bind(c, name='PQexec') result(pgresult)
            import c_ptr, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            
            ! To pass a string to C, declare an array of type 'character' with kind 'c_char'.
            character(1, kind=c_char), intent(in) :: query(*)

            type(c_ptr) :: pgresult
         end function c_PQ_exec
      end interface

      ! Append a C null character to the end of the query.
      c_query = query//c_null_char

      res = c_PQ_exec(conn, c_query)

      !|> Submit a command to the server and waits for the result.
      ! > 
      ! > Returns a `PGresult` pointer or possibly a null pointer.
      ! > A non-null pointer will generally be returned except in out-of-memory conditions or
      ! > serious errors such as inability to send the command to the server.
      ! > The `[[PQresultStatus]]` function should be called to check the return value for any errors
      ! > (including the value of a null pointer, in which case it will return PGRES_FATAL_ERROR).
      ! > Use `[[PQerrorMessage]]` to get more information about such errors.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXEC)

      !*### Example
      !```Fortran
      ! type(c_ptr) :: conn, res
      ! integer :: stat 
      ! 
      ! conn = PQconnectdb("dbname=postgres")
      ! !...error handling...
      !
      ! res = PQexec(conn, "select 1234;")
      ! stat = PQresultStatus(res)
      ! if (stat /= PGRES_COMMAND_OK .and. stat /= PGRES_TUPLES_OK) then
      !    print *, PQerrorMessage(conn)
      !    call PQclear(res)
      !    call PQfinish(conn)
      !    error stop
      ! end if
      !
      ! ! ... some statements ...
      ! call PQclear(res)
      !```

   end function PQexec

   ! Only TEXT format for now 
   ! a version of int32 for paramTypes
   function PQexecParams_int32 (conn, command, nParams, paramTypes, paramValues) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 
      use :: character_operations_m
      implicit none

      !*> Submits a command to the server and waits for the result, with the ability to pass 
      ! > parameters separately from the SQL command text.
      ! > 
      ! > `PQexecParams` is like [`PQexec`](../proc/pqexec.html) but offers additional functionality:
      ! > parameter values can be specified separately from the command string proper, and query results
      ! > can be requested in text or binary format.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS)

      !!@note Binary format have not been implemented yet.

       !*### Example
      !```fortran
      ! block
      !    character(:), allocatable :: command
      !    character(8) :: values(2)
      !    type(c_ptr) :: res
      ! 
      !    command = "select $1::bigint + $2::bigint;"
      !    values(1) = "300"
      !    values(2) = "500"
      !
      !    res = PQexecParams(conn, command, size(values), [0, 0], values)
      !    if (PQresultStatus(res) /= PGRES_TUPLES_OK) then
      !       print *, PQerrorMessage(conn)
      !       call PQclear(res)
      !    end if
      !    
      !    print *, PQgetvalue(res, 0, 0) ! the result "800" is expected.
      !    call PQclear(res)
      !```
      
      ! Input parameters
      !> The connection object to send the command through. 
      type(c_ptr),    intent(in) :: conn
      
      !> The SQL command string to be executed. If parameters are used, 
      !> they are referred to in the command string as `$1`, `$2`, etc.
      character(*),   intent(in) :: command

      !> The number of parameters supplied; it is the length of the arrays `paramTypes`,
      !> `paramValues`. 
      integer(int32), intent(in) :: nParams

      !> Specifies, by OID, the data types to be assigned to the parameter symbols.
      !> If any particular element in the array is zero, the server infers a data type
      !> for the parameter symbol in the same way it would do for an untyped literal string.
      integer(int32), intent(in) :: paramTypes(:)

      !> Specifies the actual values of the parameters. A empty string in this array means
      !> the corresponding parameter is null. 
      character(*),   intent(in) :: paramValues(:)    ! paramValues(nParams)
      
      ! Output pgresult 
      type(c_ptr) :: res

      ! Local variables
      integer :: i
      integer(int64), allocatable :: paramTypes_i64(:)
      
      allocate(paramTypes_i64(size(paramTypes, dim=1)))

      do i = 1, size(paramTypes, dim=1)
         paramTypes_i64(i) = int(paramTypes(i), int64)
      end do

      res = PQexecParams(conn, command, nParams, paramTypes_i64, paramValues)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS)
   end function PQexecParams_int32

   ! Only TEXT format for now 
   ! a version of int64 for paramTypes 
   function PQexecParams_int64 (conn, command, nParams, paramTypes, paramValues) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 
      use :: character_operations_m
      implicit none

       !*> Submits a command to the server and waits for the result, with the ability to pass 
      ! > parameters separately from the SQL command text.
      ! > 
      ! > `PQexecParams` is like [`PQexec`](../proc/pqexec.html) but offers additional functionality:
      ! > parameter values can be specified separately from the command string proper, and query results
      ! > can be requested in text or binary format.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS)

      !!@note Binary format have not been implemented yet.

      !*### Example
      !```fortran
      ! block
      !    character(:), allocatable :: command
      !    character(8) :: values(2)
      !    type(c_ptr) :: res
      ! 
      !    command = "select $1::bigint + $2::bigint;"
      !    values(1) = "300"
      !    values(2) = "500"
      !
      !    res = PQexecParams(conn, command, size(values), [0_8, 0_8], values)
      !    if (PQresultStatus(res) /= PGRES_TUPLES_OK) then
      !       print *, PQerrorMessage(conn)
      !       call PQclear(res)
      !    end if
      !    
      !    print *, PQgetvalue(res, 0, 0) ! the result "800" is expected.
      !    call PQclear(res)
      !```

      
      ! Input parameters
      !> The connection object to send the command through. 
      type(c_ptr),    intent(in) :: conn

      !> The SQL command string to be executed. If parameters are used, 
      !> they are referred to in the command string as `$1`, `$2`, etc.
      character(*),   intent(in) :: command

      !> The number of parameters supplied; it is the length of the arrays `paramTypes`,
      !> `paramValues`. 
      integer(int32), intent(in) :: nParams

      !> Specifies, by OID, the data types to be assigned to the parameter symbols.
      !> If any particular element in the array is zero, the server infers a data type
      !> for the parameter symbol in the same way it would do for an untyped literal string.
      integer(int64), intent(in) :: paramTypes(:)

      !> Specifies the actual values of the parameters. A empty string in this array means
      !> the corresponding parameter is null. 
      character(*),   intent(in) :: paramValues(:)    ! paramValues(nParams)

      ! Output pgresult 
      type(c_ptr) :: res

      ! Local variables
      character(:, kind=c_char), allocatable :: c_command
      type(uint32), allocatable, target :: c_paramtypes(:)      
      integer :: resultFormat
      integer :: max_len_val
      integer :: i

      ! For nParams >= 1
      interface
         function c_PQ_exec_parameters(conn, command, nParams, paramTypes, paramValues, &
                                       paramLengths, paramFormats, resultFormat) &
                     bind(c, name="PQexecParams")
            import c_ptr, c_int, uint32, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: command(*)      ! String
            integer(c_int), intent(in), value     :: nParams         ! Int scalar
            type(c_ptr), intent(in), value        :: paramTypes
            type(c_ptr), intent(in), value        :: paramValues    ! String array 
            type(c_ptr), intent(in), value        :: paramLengths    ! Int array
            type(c_ptr), intent(in), value        :: paramFormats    ! Int array
            integer(c_int), intent(in), value     :: resultFormat    ! Int scalar
            type(c_ptr) :: c_PQ_exec_parameters
         end function c_PQ_exec_parameters
      end interface


      resultFormat = 0 ! text format only for now.

      c_command =  trim(command)//c_null_char

      if (nParams >= 1) then

         max_len_val = max_length_char_array(paramValues)

         allocate(c_paramtypes(nParams))
         
         do i = 1, nParams
            c_paramtypes(i) = paramTypes(i)
         end do

         block
            character(max_len_val+1, kind=c_char), allocatable, target :: c_values(:)
            type(c_ptr), allocatable, target :: ptr_values(:)

            call cchar_array_from_strings_no_null(paramValues, c_values, max_len_val)
            call cptr_array_from_cchar_no_null(c_values, ptr_values)

            
            res = c_PQ_exec_parameters(&
                  conn, c_command, nParams, c_loc(c_paramTypes), &
                  c_loc(ptr_values(1)), c_null_ptr, c_null_ptr, resultFormat)

            ! for BINARY format
            ! res = c_PQ_exec_parameters(&
                  ! conn, command, nParams, c_paramTypes, &
                  ! ptr_values, paramLengths, paramFormats, resultFormat)


         end block 
         deallocate(c_paramtypes)
      ! for nParams == 0 
      else if (nParams == 0) then
         block
            type(c_ptr) :: null_paramTypes = c_null_ptr
            type(c_ptr) :: null_paramValues = c_null_ptr
            type(c_ptr) :: null_paramLength = c_null_ptr
            type(c_ptr) :: null_paramFormats = c_null_ptr
         
         res = c_PQ_exec_parameters(&
                        conn, c_command, nParams, &
                        null_paramTypes,   &
                        null_paramValues,  &
                        null_paramLength,  &
                        null_paramFormats, &
                        resultFormat)
         end block
      end if
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPARAMS)
   end function PQexecParams_int64

   ! --- PQprepare frontend
   function PQprepare_int32 (conn, stmtName, query, nParams, paramTypes) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 
      implicit none

      !*> Submits a request to create a prepared statement with the given parameters, and waits for completion.
      
      !*> `PQprepare` creates a prepared statement for later execution with `PQexecPrepared`.
      ! > This feature allows commands to be executed repeatedly without being parsed and
      ! > planned each time; see [PREPARE](https://www.postgresql.org/docs/current/sql-prepare.html) for details.

      !*> The function create a prepared statement named `stmtName` from the `query` string, which
      ! > must contain a single SQL command. `stmtName` can be `""` to create an unnamed statement,
      ! > in which case any pre-existing unnamed statement is automatically replaced; otherwise it is
      ! > an error if the statement name is already defined in the current session. If any parameters are used, 
      ! > they are referred to in the as `$1`, `$2`, etc. `nParams` is the number of parameters for which types
      ! > are pre-specified in the array `paramTypes`. 
      ! > `paramTypes` specifies, by OID, the data types to be assigned to the parameter symbols. 
      ! > If any particuler element in the `paramTypes` array is zero, the server assigns a data type to the
      ! > parameter symbol in the same way it would do for an untyped literal string. 
      ! > Also, the query can use parameter symbols with the numbers higher than `nParams`; data types will 
      ! > be inferred for these symbols as well. 
         ! (See [PQdescribePrepared](../proc/pqdescribeprepared.html)) for a means to find out what data types were inffered.) 
      
      !*> As with `[[PQexec]]`, the result is normally a `PGresult` object whose contents indicate server-side
      ! > success or failure. A null result indicates out-of-memory or inability to send to the command at all.
      ! > Use [`PQerrorMessage`](../proc/pqerrormessage.html) to get more information about such errors.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE)


      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName
      character(*), intent(in) :: query
      integer(int32), intent(in) :: nParams
      integer(int32), intent(in) :: paramTypes(:)

      type(c_ptr) :: res

      type(uint32), allocatable :: u_paramTypes(:)
      integer :: i, siz

      siz = size(paramTypes, dim=1)
      allocate(u_paramTypes(siz)) 
   
      do i = 1, siz
         u_paramTypes(i) = paramTypes(i)
      end do

      res = PQprepare_back(conn, stmtName, query, nParams, u_paramTypes)

   end function PQprepare_int32


   function PQprepare_int64 (conn, stmtName, query, nParams, paramTypes) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 
      implicit none

      !*> Submits a request to create a prepared statement with the given parameters, and waits for completion.
      
      !*> `PQprepare` creates a prepared statement for later execution with `PQexecPrepared`.
      ! > This feature allows commands to be executed repeatedly without being parsed and
      ! > planned each time; see [PREPARE](https://www.postgresql.org/docs/current/sql-prepare.html) for details.

      !*> The function create a prepared statement named `stmtName` from the `query` string, which
      ! > must contain a single SQL command. `stmtName` can be `""` to create an unnamed statement,
      ! > in which case any pre-existing unnamed statement is automatically replaced; otherwise it is
      ! > an error if the statement name is already defined in the current session. If any parameters are used, 
      ! > they are referred to in the as `$1`, `$2`, etc. `nParams` is the number of parameters for which types
      ! > are pre-specified in the array `paramTypes`. 
      ! > `paramTypes` specifies, by OID, the data types to be assigned to the parameter symbols. 
      ! > If any particuler element in the `paramTypes` array is zero, the server assigns a data type to the
      ! > parameter symbol in the same way it would do for an untyped literal string. 
      ! > Also, the query can use parameter symbols with the numbers higher than `nParams`; data types will 
      ! > be inferred for these symbols as well. 
      
      ! (See [PQdescribePrepared](../proc/pqdescribeprepared.html)) for a means to find out what data types were inffered.) 
      
      !*> As with [`PQexec`](../proc/pqexec.html), the result is normally a `PGresult` object whose contents indicate server-side
      ! > success or failure. A null result indicates out-of-memory or inability to send to the command at all.
      ! > Use [`PQerrorMessage`](../proc/pqerrormessage.html) to get more information about such errors.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE)

      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName
      character(*), intent(in) :: query
      integer(int32), intent(in) :: nParams
      integer(int64), intent(in) :: paramTypes(:)

      type(c_ptr) :: res

      type(uint32), allocatable :: u_paramTypes(:)
      integer :: i, siz

      siz = size(paramTypes, dim=1)
      allocate(u_paramTypes(siz))
   
      do i = 1, siz
         u_paramTypes(i) = paramTypes(i)
      end do

      res = PQprepare_back(conn, stmtName, query, nParams, u_paramTypes)
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPREPARE)
   end function PQprepare_int64


   ! --- PQprepare backend
   function PQprepare_back (conn, stmtName, query, nParams, paramTypes) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 
      use :: character_operations_m
      implicit none

      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName
      character(*), intent(in) :: query
      integer(int32), intent(in) :: nParams
      type(uint32), intent(in) :: paramTypes(:)

      type(c_ptr) :: res

      character(:, kind=c_char), allocatable :: c_stmtName
      character(:, kind=c_char), allocatable :: c_query
      type(uint32), allocatable, target :: c_paramTypes(:)
      integer :: siz

      interface
         function c_PQ_prepare (conn, stmtName, query, nParams, paramTypes) bind(c, name="PQprepare")
            import c_ptr, uint32, c_char, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: stmtName(*)
            character(1, kind=c_char), intent(in) :: query(*)
            integer(c_int), intent(in), value :: nParams
            type(c_ptr), intent(in), value :: paramTypes
            type(c_ptr) :: c_PQ_prepare
         end function c_PQ_prepare
      end interface

      ! paramTypes(:)をc_paramTypesに複製してその先頭アドレスをc_PQ_prepareに渡すことを目的とする。
      siz = size(paramTypes, dim=1)
      allocate(c_paramTypes(siz))
      c_paramTypes(:) = paramTypes(:)

      ! Null終端の文字列を用意する
      c_stmtName = trim(adjustl(stmtName))//c_null_char
      c_query = trim(query)//c_null_char

      ! c_paramTypesのアドレスを渡す。
      res = c_PQ_prepare(conn, c_stmtName, c_query, nParams, c_loc(c_paramTypes))

   end function PQprepare_back


   function PQexecPrepared (conn, stmtName, nParams, paramValues) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: character_operations_m
      implicit none

      !*> Sends a request to execute a prepared statement with given parameters, and waits for the result.
      ! > 
      ! > `PQexecPrepared` is like `[[PQexecParams]]`, but the command to be executed is spcified by
      ! > naming a previously-prepared statement, instead of giving a query string. This feature allows 
      ! > commands that will be used repeated to be parsed and planned just once, rather than each
      ! > time they are executed. The statement must have been prepared previously in the current session.
      ! >
      ! > The parameters are identical to `[[PQexecParams]]`, except that the name of a prepared statement
      ! > is given instead of a query string, and the `paramTypes` parameter is not present (it is not
      ! > needed since the prepared statement's parameter types were determined when it was created).
      ! >
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQEXECPREPARED)
      
      ! Input paramters 
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName   ! statement name
      integer(int32), intent(in) :: nParams
      character(*), intent(in) :: paramValues(:)

      ! Output pointer
      type(c_ptr) :: res

      ! Local variables
      integer(int32) :: resultFormat, max_len_val
      character(:, kind=c_char), allocatable :: c_stmtName
      type(c_ptr) :: null_paramLengths = c_null_ptr
      type(c_ptr) :: null_paramFormats = c_null_ptr
      

      interface
         function c_PQ_exec_prepared (conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat) &
            bind(c, name="PQexecPrepared")
            import c_ptr, c_int, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: stmtName(*)
            integer(c_int), intent(in), value     :: nParams
            type(c_ptr), intent(in), value        :: paramValues
            type(c_ptr), intent(in), value        :: paramLengths
            type(c_ptr), intent(in), value        :: paramFormats
            integer(c_int), intent(in), value     :: resultFormat
            type(c_ptr) :: c_PQ_exec_prepared
         end function c_PQ_exec_prepared
      end interface
      
      resultFormat = 0

      c_stmtName = trim(adjustl(stmtName))//c_null_char

      if (nParams >= 1) then
         max_len_val = max_length_char_array(paramValues)

         block
            character(max_len_val+1, kind=c_char), allocatable, target :: c_values(:)
            type(c_ptr), allocatable, target :: ptr_values(:)

            call cchar_array_from_strings_no_null(paramValues, c_values, max_len_val)
            call cptr_array_from_cchar_no_null(c_values, ptr_values)

            res = c_PQ_exec_prepared( &
                        conn, c_stmtName, nParams, &
                        c_loc(ptr_values(1)), &
                        null_paramLengths, &
                        null_paramFormats, &
                        resultFormat &
                  )
         end block

      else if (nParams == 0) then
         block
            type(c_ptr) :: null_paramValues = c_null_ptr

            res = c_PQ_exec_prepared( &
                        conn, c_stmtName, nParams, &
                        null_paramValues, &
                        null_paramLengths, &
                        null_paramFormats, &
                        resultFormat &
                  )
         end block
      end if 
   end function PQexecPrepared



   function PQdescribePrepared (conn, stmtName) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      !*> Submits a request to obtain information about the specified prepared statement, and waits for completion.

      !*> `PQdescribePrepared` allows an application to obtain information about a previously prepared statement.
      ! > 
      ! > `stmtName` can be `""` to reference the unnamed statement, otherwise it must be the name of an existing
      ! > prepared statement. On success, a `PGresult` with status `PGRES_COMMAND_OK` is returned. The `[[PQnparams]]`
      ! > and `[[PQparamtype]]` can be applied to this `PGresult` to obtain information about the parameters of the
      ! > prepared statement, and the functions `[[PQnfields]]`, `[[PQfname]]`, `[[PQftype]]` etc. provide information
      ! > about the result columns (if any) of the statement. 
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPREPARED)
      
      ! Input paramter
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName

      ! Output pointer
      type(c_ptr) :: res

      ! Local variable
      character(:, kind=c_char), allocatable :: c_stmtName

      interface
         function c_PQ_describe_prepared (conn, stmtName) bind(c, name="PQdescribePrepared")
            import c_ptr, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: stmtName(*)
            type(c_ptr) :: c_PQ_describe_prepared
         end function c_PQ_describe_prepared
      end interface

      c_stmtName = trim(adjustl(stmtName))//c_null_char

      res = c_PQ_describe_prepared(conn, c_stmtName)

   end function PQdescribePrepared


   function PQdescribePortal (conn, portalName) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      !*> Submits a request to obtain information about the specified portral, and waits for completion.
      ! > 
      ! > `PQdescribePortal` allows an application to obtain information about a previously created 
      ! > portal. (libpq does not provide any direct access to portals, but you can use this function
      ! > to inspect the properties fo a cursor created with a `DECLARE CURSOR` SQL command.)
      ! >
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQDESCRIBEPORTAL)


      ! Input parameters
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: portalName

      ! Output parameter
      type(c_ptr) :: res

      ! Local variables
      character(:, kind=c_char), allocatable :: c_portalName

      interface
         function c_PQ_describe_portal(conn, portalName) bind(c, name="PQdescribePortal")
            import c_ptr, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: portalName(*)
            type(c_ptr) :: c_PQ_describe_portal
         end function c_PQ_describe_portal
      end interface

      c_portalName = trim(adjustl(portalName))//c_null_char

      res = c_PQ_describe_portal(conn, c_portalName)

   end function PQdescribePortal


   function PQresultStatus(pgresult) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding, only: c_ptr, c_int
      implicit none
      type(c_ptr), intent(in) :: pgresult
      integer(int32) :: res

      interface
         ! Interface to PQresultStatus in interfaces/libpq/fe-exec.c:
         !
         ! ExecStatusType PQresultStatus(const PGresult *res)
         !
         function c_PQ_result_status(pgresult) bind(c, name='PQresultStatus') result(res)
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int) :: res
         end function c_PQ_result_status
      end interface
      
      res = c_PQ_result_status(pgresult)

      !*> Returns the result status of the command.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQRESULTSTATUS)
      
   end function PQresultStatus


   function PQresStatus(status) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      !*> Converts the enumerated type returned by `PQresultStatus` into a string constant describing the status code..
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQRESSTATUS)

      ! 入力
      integer(int32), intent(in) :: status
      
      ! 出力:文字列へのポインタ
      character(:), pointer :: res

      ! C関数の結果を代入するCポインタ型の変数
      type(c_ptr) :: status_description

      ! C関数へのインターフェース
      interface
         function c_PQ_res_status (status) bind(c, name="PQresStatus") result(res)
            import c_ptr, c_int
            integer(c_int), intent(in), value :: status
            type(c_ptr) :: res
         end function
      end interface

      ! C関数を呼び出して、結果のポインタをstatus_descriptionに受け取る。
      status_description = c_PQ_res_status(status)

      ! 結果のCポインタをFortranの文字列ポインタに変換する。
      res => c_to_f_charpointer(status_description)

   end function PQresStatus


   function PQresultErrorMessage(pgresult) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      implicit none
      type(c_ptr), intent(in) :: pgresult
      character(:, kind=c_char), pointer :: res

      interface
         ! Interface to PQresultErrorMessage in interface/libpq/fe-exec.c:
         !
         ! char *PQresultErrorMessage(const PGresult *res)
         !
         function c_PQ_result_error_message (res) bind(c, name='PQresultErrorMessage')
            import c_ptr
            implicit none
            type(c_ptr), intent(in), value :: res
            type(c_ptr) :: c_PQ_result_error_message
         end function c_PQ_result_error_message
      end interface

      res => c_to_f_charpointer(c_PQ_result_error_message(pgresult))

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQRESULTERRORMESSAGE)
   end function PQresultErrorMessage


   function PQresultVerboseErrorMessage(pgresult, verbosity, show_context) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      implicit none
      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: verbosity
      integer(int32), intent(in) :: show_context

      character(:, kind=c_char), pointer :: res

      interface
         function c_PQ_result_verbose_error_message (res, verbosity, show_context ) &
                                          bind(c, name='PQresultVerboseErrorMessage')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: res
            integer(c_int), intent(in), value :: verbosity, show_context
            type(c_ptr) :: c_PQ_result_verbose_error_message
         end function c_PQ_result_verbose_error_message
      end interface

      res => c_to_f_charpointer(c_PQ_result_verbose_error_message(pgresult, verbosity, show_context))

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQRESULTVERBOSEERRORMESSAGE)
   end function PQresultVerboseErrorMessage


   function PQresultErrorField(pgresult, fieldcode) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: fieldcode
      character(:, kind=c_char), pointer :: res

      interface
         ! Interface to PQresultErrorField in interface/libpq/fe-exec.c:
         !
         ! char *PQresultErrorField(const PGresult *res)
         !
         function c_PQ_result_error_field (res, fieldcode) bind(c, name='PQresultErrorField')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: res
            integer(c_int), intent(in), value :: fieldcode
            type(c_ptr) :: c_PQ_result_error_field
         end function c_PQ_result_error_field
      end interface

      res => c_to_f_charpointer(c_PQ_result_error_field(pgresult, fieldcode))

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQRESULTERRORFIELD)
   end function PQresultErrorField


   !-- Delete a PGresult
   !>> Frees the storage associated with a `PGresult`.
   !>> Every command result should be freed via `PQclear` when it is no longer needed.
   !>> 
   subroutine PQclear(res)
      use, intrinsic :: iso_c_binding
      implicit none
      
      type(c_ptr), intent(in) :: res

      interface
         ! Interface to PQclear in interface/libpq/fe-exec.c:
         !
         ! void PQclear(PGresult *res)
         !
         subroutine c_PQ_clear(res) bind(c, name='PQclear')
            import c_ptr
            implicit none
            type(c_ptr), intent(in), value :: res
         end subroutine c_PQ_clear
      end interface

      call c_PQ_clear(res)

      !*> If the argumentis a `NULL` pointer, no operation is performed.
      ! >
      ! > You can keep a `PGresult` object around for as long as you need it; it does not go away when you issue a new
      ! > command, nor even if you close the connection. 
      ! > To get rid of it, you must call `PQclear`. Failure to do this will result in memory leaks in your application.
      ! >
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCLEAR)
   end subroutine PQclear

   
!== Retrieving Query Result Information

   function PQntuples(pgresult) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      implicit none
      type(c_ptr), intent(in) :: pgresult
      integer(int32) :: res

      interface
         ! Interface to PQntuples in interface/libpq/fe-exec.c:
         !
         ! int PQntuples(const PGresult *res)
         !
         function c_PQ_n_tuples (pgresult) bind(c, name='PQntuples')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int) :: c_PQ_n_tuples
         end function c_PQ_n_tuples
      end interface

      res = c_PQ_n_tuples(pgresult)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQNTUPLES)
   end function PQntuples


   function PQnfields(pgresult) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      implicit none
      type(c_ptr), intent(in) :: pgresult
      integer(int32) :: res

      interface
         ! Interface to PQnfields in interface/libpq/fe-exec.c:
         !
         ! int PQnfields(const PGresult *res)
         !
         function c_PQ_n_fields (pgresult) bind(c, name='PQnfields')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int) :: c_PQ_n_fields
         end function c_PQ_n_fields
      end interface

      res = c_PQ_n_fields(pgresult)
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQNFIELDS)
   end function PQnfields


   function PQfname(pgresult, field_num) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_fortran_env, only:int32
      use, intrinsic :: iso_c_binding, only: c_ptr, c_int, c_char
      implicit none
      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: field_num
      character(:, kind=c_char), pointer :: res

      interface
         ! Interface to PQfname in src/interface/libpq/fe-exec.c:
         !
         ! char *PQfname(const PGresult *res, int field_num)
         function c_PQ_field_name (pgresult, c_field_num) bind(c, name='PQfname')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: c_field_num
            type(c_ptr) :: c_PQ_field_name
         end function c_PQ_field_name
      end interface
      
      res => c_to_f_charpointer(c_PQ_field_name(pgresult, field_num ))

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFNAME)
   end function PQfname

   
   function PQfnumber (pgresult, column_name)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      implicit none
      
      type(c_ptr), intent(in) :: pgresult
      character(*), intent(in) :: column_name
      character(:, kind=c_char), allocatable :: c_column_name
      integer :: PQfnumber

      interface 
         function c_PQ_field_number(pgresult, c_name) bind(c, name='PQfnumber') &
                                                      result(res)
            import c_ptr, c_int, c_char
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            character(1, kind=c_char), intent(in) :: c_name(*)
            integer(c_int) :: res
         end function c_PQ_field_number
      end interface

      c_column_name = trim(adjustl(column_name))//c_null_char

      PQfnumber = c_PQ_field_number(pgresult, c_column_name)
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFNUMBER)
   end function PQfnumber

   
   function PQftable (pgresult, column_number) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      use :: unsigned_m 

      ! 入力
      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: column_number

      ! 出力結果
      integer(int64) :: res

      ! カラムの属するテーブルのOidを格納する変数を宣言する。
      type(uint32) :: oid

      ! C関数 PQftableへのインターフェースを定義する。
      interface
         function c_PQ_field_table(pgresult, column_number) bind(c, name="PQftable")
            import uint32, c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult          ! PostgreSQLの結果オブジェクト
            integer(c_int), intent(in), value :: column_number  ! カラム番号
            type(uint32) :: c_PQ_field_table                    ! 戻り値は符号なし整数型
         end function 
      end interface

      ! C関数を呼び出して、Oidを取得する。
      oid = c_PQ_field_table(pgresult, column_number)

      ! カラムのOidを整数型に変換して結果に格納する。
      res = cast_to_int64(oid)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFTABLE)
   end function PQftable


   function PQftablecol (pgresult, column_number) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: column_number
      integer(int32) :: res

      interface
         function c_PQ_field_table_column(pgresult, column_number) &
                                 bind(c, name="PQftablecol") result(res)
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: column_number
            integer(c_int) :: res
         end function c_PQ_field_table_column
      end interface

      res = c_PQ_field_table_column(pgresult, column_number)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFTABLECOL)
   end function PQftablecol


   !>> Returns the format code indicating the format of the given column.
   !>> Column numbers start at `0`.
   !>> 
   function PQfformat (pgresult, column_number) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: column_number
      integer(int32) :: res

      interface
         function c_PQ_field_format (pgresult, column_number) &
                                 bind(c, name="PQfformat") result(res)
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: column_number
            integer(c_int) :: res
         end function c_PQ_field_format
      end interface

      res = c_PQ_field_format(pgresult, column_number)

      !*> Format code zero indicates textual data representatiion, while format code one indicates binary
      ! > representation. (Other codes are reserved for future definition.)
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFFORMAT)
   end function PQfformat


   function PQftype(pgresult, column_number) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      use :: unsigned_m 

      ! 入力
      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: column_number

      ! 出力結果
      integer(int64) :: res

      ! カラムに関連したデータ型を返す。返される整数はその型の内部的なOID番号である。
      type(uint32) :: oid

      interface
         function c_PQ_field_type (pgresult, column_number) bind(c, name="PQftype")
            import uint32, c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: column_number
            type(uint32) :: c_PQ_field_type
         end function c_PQ_field_type
      end interface

      ! C関数を呼び出して、Oidを取得する。
      oid = c_PQ_field_type(pgresult, column_number)

      ! カラムのOidを64ビット整数型に変換して結果を格納する。
      res = cast_to_int64(oid)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFTYPE)
   end function PQftype
   

   function PQfmod(pgresult, column_number) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: column_number
      integer(int32) :: res

      interface
         function c_PQ_field_modifier (pgresult, column_number) &
                                 bind(c, name="PQfmod") result(res)
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: column_number
            integer(c_int) :: res
         end function c_PQ_field_modifier
      end interface

      res = c_PQ_field_modifier(pgresult, column_number)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFMOD)
   end function PQfmod


   function PQfsize (pgresult, column_number) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: column_number
      integer(int32) :: res

      interface
         function c_PQ_field_size (pgresult, column_number) &
                                 bind(c, name="PQfsize") result(res)
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: column_number
            integer(c_int) :: res
         end function c_PQ_field_size
      end interface

      res = c_PQ_field_size(pgresult, column_number)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQFSIZE)
   end function PQfsize


   !>> Return `.true.` if the PQresult contains binary data and `.false.` if it contains text data.
   !>>
   function PQbinaryTuples (pgresult)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(int32) :: res
      logical :: PQbinaryTuples

      interface
         function c_PQ_binary_tuples (pgresult) &
                                 bind(c, name="PQbinaryTuples") result(res)
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int) :: res
         end function c_PQ_binary_tuples
      end interface
         
      res = c_PQ_binary_tuples(pgresult)
      
      if (res == 1) then
         PQbinaryTuples = .true.

      else
         PQbinaryTuples = .false.

      end if

      !*> This function is deprecated (except for its use in connection with `COPY`), because it is possible
      ! > for a single `PGresult` to contain text data in some columns and binary data in others.
      ! > `[[PQfformat]]` is preferred.
      ! > `PQbinaryTuples` returns `1` only if all columns of the result are binary (format 1).
      ! >
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQBINARYTUPLES)
   end function PQbinaryTuples

  

   function PQgetvalue (pgresult, tuple_num, field_num)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(c_int), intent(in) :: tuple_num, field_num
      character(:, c_char), pointer :: PQgetvalue

      interface
         ! Interface to PQgetvalue in interface/libpq/fe-exec.c:
         !
         ! char *PQgetvalue(const PGresult *res, int tup_num, int field_num)
         !
         function c_PQ_get_value (res, tup_num, field_num) &
                                           bind(c, name='PQgetvalue')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: res
            integer(c_int), intent(in), value :: tup_num, field_num
            type(c_ptr):: c_PQ_get_value
         end function c_PQ_get_value
      end interface
      
      ! 
      PQgetvalue => &
         c_to_f_charpointer( &
            c_PQ_get_value( pgresult, tuple_num, field_num) &
         )

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQGETVALUE)
   end function PQgetvalue


   function PQgetisnull (pgresult, row_number, column_number)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      
      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: row_number, column_number
      logical :: PQgetisnull

      interface
         function c_PQ_get_is_null (res, row_number, column_number) bind(c, name="PQgetisnull")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: res
            integer(c_int), intent(in), value :: row_number
            integer(c_int), intent(in), value :: column_number
            integer(c_int) :: c_PQ_get_is_null
         end function c_PQ_get_is_null
      end interface

      block
         integer :: func_result

         func_result = c_PQ_get_is_null(pgresult, row_number, column_number)

         PQgetisnull = .false.

         if (func_result == 0) then 
            PQgetisnull = .false.
         
         else if (func_result == 1 ) then
            PQgetisnull = .true.
         end if
         
      end block

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQGETISNULL)
   end function PQgetisnull


   function PQgetlength(pgresult)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding

      type(c_ptr), intent(in) :: pgresult

      integer(int32) :: PQgetlength

      interface
         function c_PQ_get_length (pgresult) bind(c, name="PQgetlength")
            import c_int, c_ptr
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int) :: c_PQ_get_length
         end function c_PQ_get_length
      end interface

      PQgetlength = c_PQ_get_length(pgresult)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQGETLENGTH)
   end function PQgetlength

      
   function PQnparams(pgresult)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      implicit none

      type(c_ptr), intent(in) :: pgresult
      integer(int32) :: PQnparams

      interface
         function c_PQ_nparams (pgresult) bind(c, name="PQnparams")
            import c_int, c_ptr
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int) :: c_PQ_nparams
         end function 
      end interface

      PQnparams = c_PQ_nparams(pgresult)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQNPARAMS)
   end function PQnparams

   
   function PQparamtype(pgresult, param_number) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 

      type(c_ptr), intent(in) :: pgresult
      integer(int32), intent(in) :: param_number

      integer(int64) :: res

      type(uint32) :: oid

      interface 
         function c_PQ_parameter_type(pgresult, param_number) bind(c, name="PQparamtype") result(res)
            import uint32, c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            integer(c_int), intent(in), value :: param_number
            type(uint32) :: res
         end function c_PQ_parameter_type
      end interface

      oid = c_PQ_parameter_type(pgresult, param_number)

      res = cast_to_int64(oid)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQPARAMTYPE)
   end function PQparamtype
      
   

!== Retrieving Other Result Information

   function PQcmdStatus(pgresult) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      !*> Returns the command status tag from the SQL command that generated the `PGresult`.
      ! > 
      ! > Commonly this is just the name of the command, but it might include additional data such as the number
      ! > of rows processed. 
      ! > The caller should not free the result directly. It will be freed when the associated `PGresult` handle
      ! > is passed to `PQclear`.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCMDSTATUS)

      type(c_ptr), intent(in) :: pgresult
      character(:), allocatable, target, save :: str
      character(:), pointer :: res

      interface
         function c_PQ_command_status(pgresult) bind(c, name="PQcmdStatus")
            import c_ptr
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            type(c_ptr) :: c_PQ_command_status
         end function c_PQ_command_status
      end interface

      call c_char_to_f_string(c_PQ_command_status(pgresult), str)

      res => str
      
   end function PQcmdStatus


   function PQcmdTuples (pgresult) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      !*> Returns the number of rows affected by the SQL command.
      ! > 
      ! > This function returns a string containning the number of rows affected by the SQL statement 
      ! > that generated the `PGresult`.
      ! > This function can only be used following the execution of a `SELECT`, `CREATE`, `TABLE AS`, `INSERT`,
      ! > `UPDATE`, `DELETE`, `MERGE`, `MOVE`, `FETCH`, or `COPY` statement, or an `EXECUTE` of a prepared
      ! > query that contains an `INSERT`, `UPDATE`, `DELETE`, or `MERGE` statement.
      ! > IF the command that generated the `PGresult` was anything else, `PQcmdTuples` returns an empty string.
      ! > The caller should not free the return value directly. It will be freed when the associated `PGresult`
      ! > handle is passed to [[PQclear]].
      ! >
      ! >  cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQCMDTUPLES)
      
      ! Input parameters
      type(c_ptr), intent(in) :: pgresult

      ! Output parameters
      character(:), pointer :: res

      ! ローカル変数の宣言
      character(:), allocatable, target, save :: str
      type(c_ptr), save :: cptr
      

      interface
         function c_PQ_command_tuples(pgresult) bind(c, name="PQcmdTuples")
            import c_ptr
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            type(c_ptr) :: c_PQ_command_tuples
         end function c_PQ_command_tuples
      end interface

      cptr = c_PQ_command_tuples(pgresult)

      call c_char_to_f_string(cptr, str)

      res => str

   end function PQcmdTuples


   function PQoidValue(pgresult) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      use :: unsigned_m 

      type(c_ptr), intent(in) :: pgresult
      integer(int64) :: res

      interface
         function c_PQ_oid_value(pgresult) bind(c, name="PQoidValue")
            import c_ptr, uint32
            implicit none
            type(c_ptr), intent(in), value :: pgresult
            type(uint32) :: c_PQ_oid_value
         end function c_PQ_oid_value
      end interface

      res = cast_to_int64(c_PQ_oid_value(pgresult))

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQOIDVALUE)
   end function PQoidValue
   

!== Escaping Strings for Inclusion in SQL Commands

   function PQescapeLiteral (conn, str, length, errmsg) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env

      ! Input parameters
      type(c_ptr), intent(in) :: conn
      character(*),intent(in) :: str
      integer(c_size_t), intent(in) :: length
      character(*), intent(inout), optional :: errmsg

      ! Output variable
      character(:), pointer :: res

      ! Declare local variables
      integer(c_size_t) :: len                           ! Actual length of the input string
      character(:, kind=c_char), allocatable :: c_str    ! C-style string 
      character(:), allocatable, target, save :: result_string ! Target for the result string
      type(c_ptr) :: cptr                                ! Pointer to the result from the C func.
      
      ! Define an interface for the C func.
      interface
         function c_PQ_escape_literal (conn, str, length) bind(c, name="PQescapeLiteral")
            import c_ptr, c_size_t, c_char 
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: str(*)
            integer(c_size_t), intent(in), value :: length
            type(c_ptr) :: c_PQ_escape_literal
         end function c_PQ_escape_literal
      end interface

      ! Initialize the result pointer variable
      res => null()

      ! Remove trailing spaces from the input string and assign it to c_str.
      ! Zero-type termination in not required for PQescapeLiteral.
      ! 引数の末尾の空白を除去して、c_strに代入する。PQescapeLiteralに限ってはゼロバイト終端は不要である。
      c_str = trim(str)

      ! Get the actual length of the string
      ! 実際の文字列の長さをローカル変数に取得する。
      len = len_trim(str)

      ! If the given length 'length' is too small, write a warging to 'errmsg'.
      ! 与えられた長さlengthが小さすぎる場合、errmsgに警告を書き込む。
      if (length < len) then
         if (present(errmsg)) then
            write(errmsg, *) "Warning: the length is too small for the string."
         end if
      end if 

      ! Call the C func. and assign the result's char ponter to 'cptr'
      ! C関数を呼び出し、結果のcharポインタをcptrに代入する。
      cptr = c_PQ_escape_literal(conn, c_str, length)

      ! if 'cptr' is a Null pointer, return to the caller. 
      ! In this case, the C func. leaves a message in 'conn' object.
      ! cptrがNullポインタの場合、呼び出し元に戻る。このときconnオブジェクトにメッセージを残す。
      if (.not. c_associated(cptr)) return 

      ! Store the result of the C func. in 'result_string'
      ! C関数の結果を文字列result_stringに格納する。
      call c_char_to_f_string(cptr, result_string)

      ! Associate the return value pointer.
      ! 戻り値のポインタを関連付ける。
      res => result_string

      ! Free the memory allocated in C.
      ! Cで割り付けられたメモリを解放する。
      call PQfreemem(cptr)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQESCAPELITERAL)
   end function PQescapeLiteral


   ! この関数の構造は上のPQescapeLiteralとほとんど同じなので、それに含まれるコメントも参照されたい
   ! The structure of this function closely resembles that of the `PQescapeLiteral`,
   ! and the comments included in it should also be referenced.
   function PQescapeIdentifier (conn, str, length, errmsg) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env

      ! Input parameters
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: str
      integer(c_size_t), intent(in) :: length
      character(*), intent(inout), optional :: errmsg

      ! Output variable
      character(:), pointer :: res

      ! Declare local variable
      integer(c_size_t) :: len
      character(:, kind=c_char), allocatable :: c_str
      character(:), allocatable, target, save :: result_string
      type(c_ptr) :: cptr

      ! Define an interface for the C func.
      interface
         function c_PQ_escape_identifier(conn, str, length) bind(c, name="PQescapeIdentifier")
            import c_ptr, c_size_t, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: str(*)
            integer(c_size_t), intent(in), value :: length
            type(c_ptr) :: c_PQ_escape_identifier
         end function c_PQ_escape_identifier
      end interface

      res => null()

      c_str = trim(str)

      len = len_trim(str)

      if (length < len) then
         if (present(errmsg)) then
            write(errmsg, *) "Warning: the length is too small for the string."
         end if
      end if

      cptr = c_PQ_escape_identifier(conn, c_str, length)

      if (.not. c_associated(cptr)) return

      call c_char_to_f_string(cptr, result_string)

      res => result_string 
      
      call PQfreemem(cptr)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-PQESCAPEIDENTIFIER)
   end function PQescapeIdentifier

   ! function PQescapeStringConn

   ! function PQescapeByteConn
   ! function PQunescapeBytea


!=================================================================!
!== Asynchronous Command Processing

   !|> Submits a command to the server without waiting for the result(s).
   ! > `1` is returned if the command was successfully dispatched and
   ! > `0` if not (in which case, use PQerrorMessage to get more information about the failure).
   !
   function PQsendQuery (conn, command) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: command

      integer(int32) :: res
      character(:), allocatable :: c_command

      interface
         function c_PQ_send_query (conn, c_command) bind(c, name="PQsendQuery")
            import c_ptr, c_char, c_int
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: c_command(*)
            integer(c_int) :: c_PQ_send_query
         end function c_PQ_send_query
      end interface


      c_command = trim(command)//c_null_char

      res = c_PQ_send_query(conn, c_command)

      !*> After successfully calling `PQsendQuery`, call `[[PQgetResult]]` one or more times
      ! > to obtain the results. `PQsendQuery` cannot be called again (on the same connection)
      ! > until `[[PQgetResult]]` has returned a null pointer, indicating that the command is done.

      !*> In pipeline mode, this function is disallowed.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDQUERY)

      !*### Example
      !```Fortran
      !   type(c_ptr) :: conn
      !   type(c_ptr) :: res
      !   character(:), allocatable :: command
      !   integer :: ires
      !
      !   conn = PQconnectdb("dbname=postgres")
      !   (...error handling...)
      !
      !   ires = PQsendQuery(conn, command)
      !   if (ires /= 1) then
      !      print *, PQerrorMessage(conn)
      !   end if
      !
      !   res = PQgetResult(conn)
      !
      !   do while (c_associated(res))
      !
      !      if (PQresultStatus(res) /= PGRES_TUPLES_OK) then
      !         print *, PQerrorMessage(conn)
      !      end if
      !
      !      print *, PQgetvalue(res, 0, 0)
      !      call PQclear(res)
      !      
      !      res = PQgetResult(conn)
      !
      !   end do
      !```

   end function PQsendQuery

   ! 戻り値はinteger(4)なのでPQexecParamsとは別に実装する
   ! This function sends a prepared SQL query to a PostgreSQL connection asynchronously,
   ! separate from PQexecParams.
   function PQsendQueryParams_back (conn, command, nParams, paramTypes, paramValues) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      use :: unsigned_m 
      use :: character_operations_m

      ! Input parameters
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: command
      integer(int32), intent(in) :: nParams

      type(uint32), intent(in) :: paramTypes(:)
      character(*), intent(in) :: paramValues(:)

      ! Output integer
      integer(int32) :: res

      ! Local variables
      character(:, kind=c_char), allocatable :: c_command
      type(uint32), allocatable, target :: c_paramTypes(:)
      integer(int32) :: resultFormat
      integer(int32) :: max_len_val
      type(c_ptr) :: cptr_paramTypes
      type(c_ptr) :: null_paramLengths = c_null_ptr
      type(c_ptr) :: null_paramFormats = c_null_ptr

      ! For nParams >= 1
      interface
         function c_PQ_send_query_parameters(conn, command, nParams, paramTypes, paramValues, &
                     paramLengths, paramFormats, resultFormat) &
                     bind(c, name="PQsendQueryParams")
            import c_ptr, c_int, uint32, c_char
            implicit none
            type(c_ptr),    intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: command(*)
            integer(c_int), intent(in), value :: nParams
            type(c_ptr),    intent(in), value :: paramTypes
            type(c_ptr),    intent(in), value :: paramValues
            type(c_ptr),    intent(in), value :: paramLengths
            type(c_ptr),    intent(in), value :: paramFormats
            integer(c_int), intent(in), value :: resultFormat
            integer(c_int) :: c_PQ_send_query_parameters
         end function c_PQ_send_query_parameters
      end interface 

      ! For nParams == 0
      interface
         function c_PQ_send_query_parameters_zero(conn, command, nParams, paramTypes, paramValues,&
                     paramLengths, paramFormats, resultFormat) &
                     bind(c, name="PQsendQueryParams")
            import c_ptr, c_int, uint32, c_char
            implicit none
            type(c_ptr),    intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: command(*)
            integer(c_int), intent(in), value :: nParams
            type(c_ptr),    intent(in), value :: paramTypes
            type(c_ptr),    intent(in), value :: paramValues
            type(c_ptr),    intent(in), value :: paramLengths
            type(c_ptr),    intent(in), value :: paramFormats
            integer(c_int), intent(in), value :: resultFormat
            integer(c_int) :: c_PQ_send_query_parameters_zero
         end function c_PQ_send_query_parameters_zero
      end interface 

      resultFormat = 0 ! text format only for now.

      c_command =  trim(command)//c_null_char

      if (nParams >= 1) then

         max_len_val = max_length_char_array(paramValues)

         allocate(c_paramTypes(nParams))

         c_paramTypes(:) = paramTypes(:)

         cptr_paramTypes = c_loc(c_paramTypes)

         block
            character(max_len_val+1, kind=c_char), allocatable, target :: c_values(:)
            type(c_ptr), allocatable, target :: ptr_values(:)
            

            call cchar_array_from_strings_no_null(paramValues, c_values, max_len_val)
            call cptr_array_from_cchar_no_null(c_values, ptr_values)

            res = c_PQ_send_query_parameters(&
                     conn, c_command, nParams, &
                     cptr_paramTypes, &
                     c_loc(ptr_values(1)), &
                     null_paramLengths, &
                     null_paramFormats, &
                     resultFormat &
                     )
         end block
      
      else if (nParams == 0) then
         block
            type(c_ptr) :: null_paramTypes = c_null_ptr
            type(c_ptr) :: null_paramValues = c_null_ptr
            
            res = c_PQ_send_query_parameters_zero( &
                     conn, c_command, nParams, &
                     null_paramTypes, &
                     null_paramValues, &
                     null_paramLengths, &
                     null_paramFormats, &
                     resultFormat &
                  )

         end block
      end if

   end function PQsendQueryParams_back


   !>> Submit a command and separate parameter to the server without waiting for the result(s).
   function PQsendQueryParams_int32 (conn, command, nParams, paramTypes, paramValues) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 

      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: command
      integer(int32), intent(in) :: nParams

      integer(int32), intent(in) :: paramTypes(:)
      character(*), intent(in) :: paramValues(:)

      integer(int32) :: res

      integer :: i, siz
      type(uint32), allocatable :: u_paramTypes(:)
      
      siz = size(paramTypes, dim=1)

      allocate(u_paramTypes(siz))

      do i = 1, siz
         u_paramTypes(i) = paramTypes(i)
      end do

      res = PQsendQueryParams_back(conn, command, nParams, u_paramTypes, paramValues)

      !*> This is equivalent to [`PQsendQuery`](../proc/pqsendquery.html), except that query parameters can be specified
      ! > separately form the query string. 
      ! > This function's parameters are handled identically [`PQexecParams`](../interface/pqexecparams.html).
      ! > Like [`PQexecParams`](../interface/pqexecparams.html), it allows only one command in the query.
      ! 
      ! >  cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDQUERYPARAMS)
   end function PQsendQueryParams_int32

   !>> Submit a command and separate parameter to the server without waiting for the result(s).
   function PQsendQueryParams_int64 (conn, command, nParams, paramTypes, paramValues) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 

      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: command
      integer(int32), intent(in) :: nParams

      integer(int64), intent(in) :: paramTypes(:)
      character(*), intent(in) :: paramValues(:)

      integer(int32) :: res

      integer :: i, siz
      type(uint32), allocatable :: u_paramTypes(:)
      
      siz = size(paramTypes, dim=1)

      allocate(u_paramTypes(siz))

      do i = 1, siz
         u_paramTypes(i) = paramTypes(i)
      end do

      res = PQsendQueryParams_back(conn, command, nParams, u_paramTypes, paramValues)

      !*> This is equivalent to [`PQsendQuery`](../proc/pqsendquery.html), 
      ! > except that query parameters can be specified
      ! > separately form the query string. 
      ! > This function's parameters are handled identically [`PQexecParams`](../interface/pqexecparams.html).
      ! > Like [`PQexecParams`](../interface/pqexecparams.html), it allows only one command in the query.
      ! 
      ! >  cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDQUERYPARAMS)
   end function PQsendQueryParams_int64

      
   ! 戻り値はinteger(4)なのでPQprepareとは別に実装する
   !> This function sends a prepared SQL query to a PostgreSQL connection asynchronously,
   !> separate from PQprepare.
   ! Inputs:
   !  - conn: PostgreSQL connection pointer
   !  - stmtName: Name for prepared statement
   !  - query: SQL query string
   !  - nParams : Number of parameters in the query
   !  - paramTypes: Array of parameter types
   ! Outputs:
   !  - res: Result code (integer, 1 or 0)
   !
   function PQsendPrepare_back (conn, stmtName, query, nParams, paramTypes) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: unsigned_m 
      use :: character_operations_m
      implicit none

      ! Input parameters
      type(c_ptr), intent(in) :: conn
      character(*),intent(in) :: stmtName
      character(*), intent(in) :: query
      integer(int32), intent(in) :: nParams
      type(uint32), intent(in) :: paramTypes(:)

      ! Output variable
      integer(int32) :: res      

      character(:, kind=c_char), allocatable :: c_stmtName
      character(:, kind=c_char), allocatable :: c_query
      type(uint32), allocatable, target :: c_paramTypes(:)
      integer :: siz

      interface
         function c_PQ_send_prepare (conn, stmtName, query, nParams, paramTypes) bind(c, name="PQsendPrepare")
            import c_ptr, uint32, c_char, c_int
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: stmtName(*)
            character(1, kind=c_char), intent(in) :: query(*)
            integer(c_int), intent(in), value :: nParams
            type(c_ptr), intent(in), value :: paramTypes 
            integer(c_int) :: c_PQ_send_prepare
         end function c_PQ_send_prepare
      end interface

      ! paramTypes(:)をc_paramTypesに複製してその先頭アドレスをc_PQ_send_prepareに渡すことを目的とする。
      siz = size(paramTypes, dim=1)
      allocate(c_paramTypes(siz))
      c_paramTypes(:) = paramTypes(:)

      ! Null終端の文字列を用意する
      c_stmtName = trim(adjustl(stmtName))//c_null_char
      c_query = trim(query)//c_null_char

      ! c_paramTypesのアドレスを渡し、戻り値は
      res = c_PQ_send_prepare(conn, c_stmtName, c_query, nParams, c_loc(c_paramTypes))
      
   end function PQsendPrepare_back

   !|> Sends a request to create a prepared statement with the given parameters, without waiting for completion.
   ! >
   ! > This is an asynchronous version of `PQprepare`:
   ! > it returns `1` if it was able to dispatch the request, and `0` if not.
   ! > After a successfull call, call [`PQgetResult`](../proc/pqgetresult.html) to determine whether the server successfully created the prepared statement. 
   ! > The function's parameters are handled identically to `PQprepare`.
   ! > 
   ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDPREPARE)
   function PQsendPrepare_int32(conn, stmtName, query, nParams, paramTypes) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      use :: unsigned_m 
      implicit none
      
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName
      character(*), intent(in) :: query
      integer(int32), intent(in) :: nParams
      integer(int32), intent(in) :: paramTypes(:)

      integer(int32) :: res

      type(uint32), allocatable :: u_paramTypes(:)
      integer :: i, siz

      siz = size(paramTypes, dim=1)
      allocate(u_paramTypes(siz))

      do i = 1, siz
         u_paramTypes(i) = paramTypes(i)
      end do

      res = PQsendPrepare_back(conn, stmtName, query, nParams, u_paramTypes)


   end function PQsendPrepare_int32

   !|> Sends a request to create a prepared statement with the given parameters, without waiting for completion.
   ! >
   ! > This is an asynchronous version of `PQprepare`:
   ! > it returns `1` if it was able to dispatch the request, and `0` if not.
   ! > After a successfull call, call [`PQgetResult`](../proc/pqgetresult.html) to determine whether the server successfully created the prepared statement. 
   ! > The function's parameters are handled identically to `PQprepare`.
   ! > 
   ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDPREPARE)
   function PQsendPrepare_int64(conn, stmtName, query, nParams, paramTypes) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      use :: unsigned_m 
      implicit none
      
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName
      character(*), intent(in) :: query
      integer(int32), intent(in) :: nParams
      integer(int64), intent(in) :: paramTypes(:)

      integer(int32) :: res

      type(uint32), allocatable :: u_paramTypes(:)
      integer :: i, siz

      siz = size(paramTypes, dim=1)
      allocate(u_paramTypes(siz))

      do i = 1, siz
         u_paramTypes(i) = int(paramTypes(i))
      end do

      res = PQsendPrepare_back(conn, stmtName, query, nParams, u_paramTypes)
   
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDPREPARE)
   end function PQsendPrepare_int64


   function PQsendQueryPrepared_text (conn, stmtName, nParams, paramValues) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      use :: character_operations_m

      ! Input paramters
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName
      integer(int32), intent(in) :: nParams
      character(*), intent(in) :: paramValues(:)

      ! Output integer
      integer(int32) :: res

      ! Local variales
      integer(int32) :: resultFormat, max_len_val
      character(:, kind=c_char), allocatable :: c_stmtName
      type(c_ptr) :: null_paramLengths = c_null_ptr
      type(c_ptr) :: null_paramFormats = c_null_ptr

      interface
         function c_PQ_send_query_prepared (conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat) &
                     bind(c, name="PQsendQueryPrepared")
            import c_ptr, c_int, c_char
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: stmtName(*)
            integer(c_int), intent(in), value     :: nParams
            type(c_ptr), intent(in), value        :: paramValues
            type(c_ptr), intent(in), value        :: paramLengths
            type(c_ptr), intent(in), value        :: paramFormats
            integer(c_int), intent(in), value     :: resultFormat
            integer(c_int) :: c_PQ_send_query_prepared
         end function c_PQ_send_query_prepared
      end interface

      interface
         function c_PQ_send_query_prepared_zero (conn, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat) &
                     bind(c, name="PQsendQueryPrepared")
            import c_ptr, c_int, c_char
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: stmtName(*)
            integer(c_int), intent(in), value     :: nParams
            type(c_ptr), intent(in), value        :: paramValues
            type(c_ptr), intent(in), value        :: paramLengths
            type(c_ptr), intent(in), value        :: paramFormats
            integer(c_int), intent(in), value     :: resultFormat
            integer(c_int) :: c_PQ_send_query_prepared_zero
         end function c_PQ_send_query_prepared_zero
      end interface
         
      resultFormat = 0
      res = 0

      c_stmtName = trim(adjustl(stmtName))//c_null_char

      if (nParams >= 1) then
         max_len_val = max_length_char_array(paramValues)

         block
            character(max_len_val+1, kind=c_char), allocatable, target :: c_values(:)
            type(c_ptr), allocatable, target :: ptr_values(:)

            call cchar_array_from_strings_no_null(paramValues, c_values, max_len_val)
            call cptr_array_from_cchar_no_null(c_values, ptr_values)

            res = c_PQ_send_query_prepared( &
                     conn, c_stmtName, nParams, &
                     c_loc(ptr_values(1)), &
                     null_paramLengths, &
                     null_paramFormats, &
                     resultFormat &
                  )
         end block

      else if (nParams == 0 ) then
         block
            type(c_ptr) :: null_paramValues = c_null_ptr

            res = c_PQ_send_query_prepared_zero( &
                     conn, c_stmtName, nParams, &
                     null_paramValues,  &
                     null_paramLengths, &
                     null_paramFormats, &
                     resultFormat &
                  )
         end block
      end if 

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDQUERYPREPARED)
   end function PQsendQueryPrepared_text


   function PQsendDescribePrepared (conn, stmtName) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      ! Input paramters
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: stmtName

      ! Output integer
      integer(int32) :: res

      ! Local variable
      character(:, kind=c_char), allocatable :: c_stmtName

      interface
         function c_PQ_send_describe_prepared (conn, stmtName) bind(c, name="PQsendDescribePrepared")
            import c_ptr, c_char, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char) :: stmtName(*)
            integer(c_int) :: c_PQ_send_describe_prepared
         end function c_PQ_send_describe_prepared
      end interface

      ! Initialize the result variable
      res = 1

      ! Trim and left-align 'stmtName', then append a null termination character.
      c_stmtName = trim(adjustl(stmtName))//c_null_char

       ! Call the C function 'PQsendDescribePrepared' with the converted stmtName.
      res = c_PQ_send_describe_prepared(conn, c_stmtName)


   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDDESCRIBEPREPARED)
   end function PQsendDescribePrepared


   function PQsendDescribePortal (conn, portalName) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      ! Input paramters
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: portalName

      ! Output integer
      integer(int32) :: res

      ! Local variable
      character(:, kind=c_char), allocatable :: c_portalName

      interface
         function c_PQ_send_describe_portal (conn, portalName) bind(c, name="PQsendDescribePortal")
            import c_ptr, c_char, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char) :: portalName(*)
            integer(c_int) :: c_PQ_send_describe_portal
         end function c_PQ_send_describe_portal
      end interface

      ! Initialize the result variable
      res = 1

      ! Trim and left-align 'portalName', then append a null termination character.
      c_portalName = trim(adjustl(portalName))//c_null_char

      ! Call the C function 'PQsendDescribePortral' with the converted portralName.
      res = c_PQ_send_describe_portal(conn, c_portalName)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSENDDESCRIBEPORTAL)
   end function PQsendDescribePortal


   function PQgetResult (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      type(c_ptr) :: res

      interface
         function c_PQ_get_result(conn) bind(c, name="PQgetResult")
            import c_ptr
            type(c_ptr), intent(in), value :: conn
            type(c_ptr) :: c_PQ_get_result
         end function c_PQ_get_result
      end interface

      !*> Waits for the next result from a prior `[[PQsendQuery]]`, `[[PQsendQueryParams]]`, `[[PQsendPrepare]]`,
      ! > `[[PQsendQueryPrepared]]`, `[[PQsendDescribePrepared]]`, `[[PQsendDescribePortal]]`, or `[[PQpipelineSync]]` call,
      ! > and returns it.  A null pointer is returned when the command is complete and there will be no more results.
      
      !*> `PQgetResult` must be called repeatedly until it returns a null pointer, indicating that the command is done.
      ! > (If called when no command is active, `PQgetResult` will just return a null pointer at once.)
      ! > Each non-null result from `PQgetResult` should be processed using  the same `PGresult` accessor functions
      ! > prebiously described. Don't forget to free each result object with `PQclear` when done with it.
      ! > Note that `PQgetResult` will block only if a command is active and the necessary response data has not yet
      ! > been read by `[[PQconsumeInput]]`.

      !*> In pipeline mode, `PQgetResult` will return normally unless an error occurs; for any subsequent query sent
      ! > after the one that caused the error unit (and excluding) the next synchronization point, a special result of 
      ! > type `PGRES_PIPELINE_ABORTED` will be returned, and a null pointer will be returned after it.
      ! > When the pipeline synchronization point is reached, a result of type `PGRES_PIPELINE_SYNC` will be returned.
      ! > The result of the next query after the synchronization point follows immediately (that is, no null pointer
      ! > is returned after the synchronization point).
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQGETRESULT)

      res = c_PQ_get_result(conn)
   end function PQgetResult
   
   !>> If input is available from the server, consume it.
   !>> 
   function PQconsumeInput (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      Interface
         function c_PQ_consume_input (conn) bind(c, name="PQconsumeInput")
            import c_ptr, c_int
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_consume_input
         end function c_PQ_consume_input
      end interface

      res = c_PQ_consume_input(conn)

      !*> `PQconsumeInput` normally returns `1` indicating "no error", but returns `0` if there was some kind of 
      ! > trouble (in which case `[[PQerrorMessage]]` can be consulted). Note that the result does not say whether any
      ! > input data was actually collected. After calling `PQconsumeInput`, the application can check `[[PQisBusy]]`
      ! > and/or `[[PQnotifies]]` to see if their state has changed.
      ! > 
      ! > cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQCONSUMEINPUT)
   end function PQconsumeInput
      

   function PQisBusy(conn) result(isBusy)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env

      type(c_ptr), intent(in) :: conn
      integer(int32) :: res
      logical :: isBusy

      interface 
         function c_PQ_is_busy (conn) bind(c, name="PQisBusy")
            import c_ptr, c_int
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_is_busy
         end function c_PQ_is_busy
      end interface

      isBusy = .false.

      res = c_PQ_is_busy(conn)

      if (res == 1) then
         isBusy = .true.
      else if (res == 0) then
         isBusy = .false.
      end if

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQISBUSY)
   end function PQisBusy


   
   function PQsetnonblocking (conn, arg) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32), intent(in) :: arg

      integer(int32) :: res

      interface
         function c_PQ_set_nonblocking (conn, arg) bind(c, name="PQsetnonblocking")
            import c_ptr, c_int
            type(c_ptr), intent(in), value :: conn
            integer(c_int), intent(in), value :: arg
            integer(c_int) :: c_PQ_set_nonblocking
         end function c_PQ_set_nonblocking
      end interface

      res = c_PQ_set_nonblocking(conn, arg)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQSETNONBLOCKING)
   end function PQsetnonblocking


   function PQisnonblocking (conn) result(isNonblocking)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res
      logical :: isNonblocking

      interface
         function c_PQ_is_nonblocking(conn) bind(c, name="PQisnonblocking")
            import c_ptr, c_int
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_is_nonblocking
         end function c_PQ_is_nonblocking
      end interface

      res = c_PQ_is_nonblocking(conn)

      if (res == 1) then 
         isNonblocking = .true.
      else if (res == 0) then
         isNonblocking = .false. 
      end if 

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQISNONBLOCKING)
   end function PQisnonblocking


   function PQflush (conn)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: PQflush

      interface
         function c_PQ_flush(conn) bind(c, name="PQflush")
            import c_ptr, c_int
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_flush
         end function c_PQ_flush
      end interface

      PQflush = c_PQ_flush(conn)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-async.html#LIBPQ-PQFLUSH)
   end function PQflush



!=================================================================!
!== Pipeline Mode
   
   function PQpipelineStatus (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none

      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      interface
         function c_PQ_pipeline_status (conn) bind(c, name="PQpipelineStatus")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_pipeline_status
         end function c_PQ_pipeline_status
      end interface
      
      res = c_PQ_pipeline_status(conn)
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-pipeline-mode.html#LIBPQ-PQPIPELINESTATUS)
   end function PQpipelineStatus


   function PQenterPipelineMode (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      interface
         function c_PQ_enter_pipeline_mode (conn) bind(c, name="PQenterPipelineMode")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_enter_pipeline_mode
         end function c_PQ_enter_pipeline_mode
      end interface 

      res = c_PQ_enter_pipeline_mode(conn)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-pipeline-mode.html#LIBPQ-PQPIPELINEMODE)
   end function PQenterPipelineMode


   function PQexitPipelineMode (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      interface
         function c_PQ_exit_pipeline_mode (conn) bind(c, name="PQexitPipelineMode")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_exit_pipeline_mode
         end function c_PQ_exit_pipeline_mode
      end interface 

      res = c_PQ_exit_pipeline_mode(conn)
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-pipeline-mode.html#LIBPQ-PQEXITPIPELINEMODE)
   end function PQexitPipelineMode


   function PQpipelineSync (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      interface
         function c_PQ_pipeline_sync (conn) bind(c, name="PQpipelineSync")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_pipeline_sync
         end function c_PQ_pipeline_sync
      end interface 

      res = c_PQ_pipeline_sync(conn)
      !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-pipeline-mode.html#LIBPQ-PQPIPELINESYNC)
   end function PQpipelineSync


   function PQsendFlushRequest (conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      interface
         function c_PQ_send_flush_request (conn) bind(c, name="PQsendFlushRequest")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_send_flush_request
         end function c_PQ_send_flush_request
      end interface 

      res = c_PQ_send_flush_request(conn)

      !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-pipeline-mode.html#LIBPQ-PQSENDFLUSHREQUEST)
   end function PQsendFlushRequest



!=================================================================!
!== Retrieving Query Result Row-by-Row
   function PQsetSingleRowMode(conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32) :: res

      interface
         function c_PQ_set_single_row_mode (conn) bind(c, name="PQsetSingleRowMode")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int) :: c_PQ_set_single_row_mode
         end function c_PQ_set_single_row_mode
      end interface

      res = c_PQ_set_single_row_mode(conn)
   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-single-row-mode.html#LIBPQ-PQSETSINGLEROWMODE)   
   end function PQsetSingleRowMode

!=================================================================!
!== Asynchronous Notification
   
   function PQnotifies(conn) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      type(c_ptr) :: res

      interface
         function c_PQ_notifies (conn) bind(c, name="PQnotifies")
            import 
            implicit none
            type(c_ptr), intent(in), value :: conn
            type(c_ptr) :: c_PQ_notifies
         end function c_PQ_notifies
      end interface

      res = c_PQ_notifies(conn)

   end function PQnotifies



!=================================================================!
!== Functions Associated with the COPY Command
   
   function PQputCopyData(conn, buffer, nbytes) result(res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      character(*), intent(in) :: buffer
      integer(int32), intent(in) :: nbytes

      integer(int32) :: res

      character(:, kind=c_char), allocatable, target :: c_buff

      interface
         function c_PQ_put_copy_data(conn, buffer, nbytes) bind(c, name='PQputCopyData')
            import c_ptr, c_int, c_char
            implicit none
            type(c_ptr), intent(in), value :: conn
            character(1, kind=c_char), intent(in) :: buffer(*)
            integer(c_int), intent(in), value :: nbytes
            integer(c_int) :: c_PQ_put_copy_data
         end function
      end interface

      c_buff = trim(adjustl(buffer))//c_null_char

      res = c_PQ_put_copy_data(conn, c_buff, nbytes)

   end function PQputCopyData


   function PQputCopyEnd(conn, errormsg) result(res)
      use :: character_operations_m
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      implicit none

      type(c_ptr), intent(in) :: conn
      character(*), intent(out) :: errormsg
      integer(int32) :: res

      type(c_ptr) :: c_errmsg
      character(:, kind=c_char), pointer :: char_ptr

      interface
         function c_PQ_put_copy_end(conn, errormsg) bind(c, name='PQputCopyEnd')
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            type(c_ptr), intent(in), value :: errormsg
            integer(c_int) :: c_PQ_put_copy_end
         end function c_PQ_put_copy_end
      end interface

      res = c_PQ_put_copy_end(conn, c_errmsg)

      char_ptr => c_to_f_charpointer(c_errmsg)

      errormsg = trim(adjustl(char_ptr))
      
   end function PQputCopyEnd


   function PQgetCopyData(conn, buffer, async) result(res)
      use, intrinsic :: iso_fortran_env
      use, intrinsic :: iso_c_binding
      implicit none
      
      type(c_ptr), intent(in) :: conn
      character(*), intent(out) :: buffer
      logical, intent(in) :: async

      integer(c_int) :: c_async
      character(len=256, kind=c_char), target :: c_buffer
      type(c_ptr) :: cptr

      integer(int32) :: res

      interface
         function c_PQ_get_copy_data(conn, buffer, async) bind(c, name='PQgetCopyData')
            import c_ptr, c_int
            type(c_ptr), intent(in), value :: conn
            type(c_ptr), intent(out) :: buffer
            integer(c_int), intent(in), value :: async
            integer(c_int) :: c_PQ_get_copy_data
         end function c_PQ_get_copy_data
      end interface

      if (async) then
         c_async = 1
      else
         c_async = 0 
      end if 

      cptr = c_loc(c_buffer)

      res = c_PQ_get_copy_data(conn, cptr, c_async)

      buffer = trim(c_buffer)
 
   end function PQgetCopyData

!=================================================================!
!== Miscellaneous Functions
   subroutine PQfreemem(cptr)
      use, intrinsic :: iso_c_binding
      implicit none
      type(c_ptr), intent(in) :: cptr

      interface
         subroutine c_PQ_free_memory (cptr) bind(c, name="PQfreemem")
            import c_ptr
            implicit none
            type(c_ptr), intent(in), value :: cptr
         end subroutine c_PQ_free_memory
      end interface

      call c_PQ_free_memory(cptr)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQFREEMEM)
   end subroutine PQfreemem


   function PQmakeEmptyPGresult (conn, status) result(res)
      use :: enumerators_t
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      integer(int32), intent(in) :: status

      type(c_ptr) :: res

      interface
         function c_PQ_make_empty_PGresult (conn, status) bind(c, name="PQmakeEmptyPGresult")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            integer(c_int), intent(in), value :: status
            type(c_ptr) :: c_PQ_make_empty_PGresult
         end function
      end interface

      if ( 0 <= status .and. status <= PGRES_PIPELINE_ABORTED) then
         res = c_PQ_make_empty_PGresult(conn, status)
      else
         res = c_null_ptr
      end if

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQMAKEEMPTYRESULT)
   end function PQmakeEmptyPGresult


   function PQcopyResult(conn, res)
      use, intrinsic :: iso_c_binding
      use, intrinsic :: iso_fortran_env
      implicit none
      
      type(c_ptr), intent(in) :: conn
      type(c_ptr), intent(in) :: res

      type(c_ptr) :: PQcopyResult

      interface
         function c_PQ_copy_result(conn, res) bind(c, name="PQcopyResult")
            import c_ptr, c_int
            implicit none
            type(c_ptr), intent(in), value :: conn
            type(c_ptr), intent(in), value :: res
            type(c_ptr) :: c_PQ_copy_result
         end function c_PQ_copy_result
      end interface

      PQcopyResult = c_PQ_copy_result(conn, res)

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQCOPYRESULT)
   end function PQcopyResult


   !> Get the threadsafety status of the current running libpq library.
   function PQisthreadsafe()
      use, intrinsic :: iso_c_binding
      implicit none
      
      integer :: result
      logical :: PQisthreadsafe

      interface
         function c_PQ_is_threadsafe() bind(c, name="PQisthreadsafe")
            import c_int
            implicit none
            integer(c_int) :: c_PQ_is_threadsafe
         end function c_PQ_is_threadsafe
      end interface

      result = c_PQ_is_threadsafe()

      if (result == 1) then
         PQisthreadsafe = .true.
      else
         PQisthreadsafe = .false.
      end if

   !! cf. [PostgreSQL Documentation](https://www.postgresql.org/docs/current/libpq-threading.html#LIBPQ-PQISTHREADSAFE)
   end function PQisthreadsafe


end module fe_exec_m