0
votes

I'm studying Julia and I'm trying to write a libpq (the PostgreSQL C library) wrapper.

The C PQconnectdb function starts a PostgreSQL connection, and returns a pointer to the connection struct. The connection struct is not exposed by libpq, since it is not useful. When the connection finishes, it must be closed using the C function PQfinish which, among other things, takes care to free the struct memory.

So I guess I should call the PQfinish function when the connection get finalized by the GC, which this is the purpose of the following code (Julia version: 0.3.0-744~ubuntu13.10.1):

module LibPQ

  typealias PGconn Ptr{Void}

  function pgconn_finalizer(x::PGconn)
    ccall( (:PQfinish, "libpq"), Void, (PGconn,), x )
    println("finalized")
  end

  c = ccall( (:PQconnectdb, "libpq"), PGconn, (Ptr{Uint8},), "connection params" )

  finalizer(c, pgconn_finalizer)

  println(c)

  gc()

end

But I get this error:

$ julia libpq.jl
ERROR: objects of type Ptr{None} cannot be finalized
 in finalizer at base.jl:103
 in include at boot.jl:240
while loading ./libpq.jl, in expression starting on line 12

I guess I should use another type for the PGconn typealias, but I can't figure out which one. Any idea?

1
The C way to do this is to declare a forward-reference to a struct that you don't define later. So you do something like extern struct PGConn; typedef struct PGConn PGConn;. This gives you a named handle for the type instead of a void pointer, but you can't do anything with it except pass it around.Craig Ringer
Yes, but the issue is about Juliamdesantis
Sure; approaches in one language often translate somewhat usefully for another, though, or at least suggest a way forward. I wasn't saying you could do exactly the same thing (otherwise it'd be an answer).Craig Ringer
Oh ok, if I got what you mean (my english skills are poor) the concept you expressed is actually the solution, that is type PGconn ...mdesantis

1 Answers

3
votes

As a julia-dev mailing list post suggested, the solution is to declare a new type with a pointer handle, which will be freed by PQfinish, as in the code shown below:

module LibPQ

  type PGconn
    handle::Ptr{Void}
  end

  function pgconn_finalizer(c::PGconn)
    if c.handle != C_NULL
      ccall( (:PQfinish, "libpq"), Void, (Ptr{Void},), c.handle )
      c.handle = C_NULL
    end
    println("finalized")
  end

  c = ccall( (:PQconnectdb, "libpq"), PGconn, (Ptr{Uint8},), "connection params" )

  finalizer(c, pgconn_finalizer)

  println(c)

  gc()

end