go-goracle/goracle

Object references not being handled correctly

anthony-tuininga opened this issue · 5 comments

When fetching objects from the database, a reference is not retained by the Object structure, which means that once the statement is released the object is no longer valid and you get the error DPI-1002: invalid dpiObject handle.

The following changes resolve this issue but please feel free to adjust the code as needed to fit your style.

diff --git a/obj.go b/obj.go
index d5d017b..b603679 100644
--- a/obj.go
+++ b/obj.go
@@ -469,6 +469,9 @@ func wrapObject(c *conn, objectType *C.dpiObjectType, object
        if objectType == nil {
                return nil, errors.New("objectType is nil")
        }
+    if rc := C.dpiObject_addRef(object); rc == C.DPI_FAILURE {
+               return nil, c.getError()
+    }
        o := &Object{
                ObjectType: ObjectType{dpiObjectType: objectType, conn: c},
                dpiObject:  object,

Note that there is a similar issue for dequeuing objects from a queue. I'll provide an error report for that after Oracle OpenWorld is over if that hint isn't sufficient!

Thanks for the care!

It's (only) called when retrieving dpiObject from a result set.
Is it needed in other cases? For example when we get it from an object's attribute (through dpiData) ?
Or only in this case?

Yes, it will be needed in other cases. The patch was for the example I was working on, but if you create a structure that stores an object reference that is intended to be used independently of the source you need to add a reference; otherwise, it will depend on the lifetime of the source. In the case of fetching, that will only be as long as the statement remains open. In the case of an attribute, that will only be as long as the object it came from remains valid. I'd suggest adding similar code in that situation and simply telling your users that they need to use defer Object.Close() to ensure that the reference is removed when it is no longer needed. I hope that makes sense?

What about dpiObjectType_createObject in NewObject?
As far as I looked, dpiObjectType_createObject does not call addRef.

I've added a dbiObject_addRef call to Data.GetObject.

What about dpiObjectType_createObject in NewObject?

That creates the initial reference for the object -- so no need to call dpiObject_addRef() there!