Rob said:
Good afternoon,
Is there any difference to using either of these at the
end of your code?
KB Article 186311 says to explicitly close recordsets to
avoid code bloat.
Does rs.Close and 'Set rs = Nothing' accomplish the same
effect? Or does rs.Close absolutely need to be used?
Also, does this also apply to databases and querydefs as
well?
Thank you in advance!
Rob
They are not exactly the same. The statement "rs.Close" calls the Close
method of the recordset object to which rs is a reference. The
statement "Set rs = Nothing" destroys the reference to that object which
is held in the variable rs. If that happens to be the only reference to
that recordset object, then destroying the reference will cause the
object itself to be destroyed, and part of the termination logic for
that object calls the Close method. So usually "Set rs = Nothing" has
the same effect as "rs.Close" followed by "Set rs = Nothing". But
consider this procedure:
'----- start of code -----
Sub FunWithRecordsets()
On Error Resume Next
Dim rs1 As DAO.Recordset
Dim rs2 As DAO.Recordset
Dim lngRC As Long
Set rs1 = CurrentDb.OpenRecordset("Table1")
Set rs2 = rs1
Debug.Print "*A*"
Err.Clear: lngRC = rs1.RecordCount
Debug.Print "rs1", TypeName(rs1), rs1 Is Nothing, Err.Number
Err.Clear: lngRC = rs2.RecordCount
Debug.Print "rs2", TypeName(rs2), rs2 Is Nothing, Err.Number
Set rs1 = Nothing
Debug.Print "*B*"
Err.Clear: lngRC = rs1.RecordCount
Debug.Print "rs1", TypeName(rs1), rs1 Is Nothing, Err.Number
Err.Clear: lngRC = rs2.RecordCount
Debug.Print "rs2", TypeName(rs2), rs2 Is Nothing, Err.Number
Set rs1 = rs2
Debug.Print "*C*"
Err.Clear: lngRC = rs1.RecordCount
Debug.Print "rs1", TypeName(rs1), rs1 Is Nothing, Err.Number
Err.Clear: lngRC = rs2.RecordCount
Debug.Print "rs2", TypeName(rs2), rs2 Is Nothing, Err.Number
rs1.Close
Debug.Print "*D*"
Err.Clear: lngRC = rs1.RecordCount
Debug.Print "rs1", TypeName(rs1), rs1 Is Nothing, Err.Number
Err.Clear: lngRC = rs2.RecordCount
Debug.Print "rs2", TypeName(rs2), rs2 Is Nothing, Err.Number
Set rs1 = Nothing
Debug.Print "*E*"
Err.Clear: lngRC = rs1.RecordCount
Debug.Print "rs1", TypeName(rs1), rs1 Is Nothing, Err.Number
Err.Clear: lngRC = rs2.RecordCount
Debug.Print "rs2", TypeName(rs2), rs2 Is Nothing, Err.Number
Set rs2 = Nothing
Debug.Print "*F*"
Err.Clear: lngRC = rs1.RecordCount
Debug.Print "rs1", TypeName(rs1), rs1 Is Nothing, Err.Number
Err.Clear: lngRC = rs2.RecordCount
Debug.Print "rs2", TypeName(rs2), rs2 Is Nothing, Err.Number
End Sub
'----- end of code -----
Running the procedure results in the following lined printed to the
Immediate Window:
------ start of output ------
*A*
rs1 Recordset False 0
rs2 Recordset False 0
*B*
rs1 Nothing True 91
rs2 Recordset False 0
*C*
rs1 Recordset False 0
rs2 Recordset False 0
*D*
rs1 Recordset False 3420
rs2 Recordset False 3420
*E*
rs1 Nothing True 91
rs2 Recordset False 3420
*F*
rs1 Nothing True 91
rs2 Nothing True 91
------ end of output ------
Just so you know, error 91 is "Object variable or With block variable
not set", and error 3420 is "Object invalid or no longer set".
As you can see, the code above has two object variables which are
initially set to the same recordset object. Setting rs1 to Nothing, as
in step B, doesn't invalidate rs2, nor does it close the recordset (we
can still read rs2.RecordCount without error). We can reassign rs1 as a
reference to that same recordset (step C). Once we've called the
recordset's Close method in step D, neither recordset variable can get
at the .RecordCount property; we get error 3420. However, neither rs1
nor rs2 is Nothing ... yet. In steps E and F we set each in turn to
Nothing, and see the results.
What does all this mean, practically? It means that you should feel
free to close any object that you opened, because you presumably know
that there's no other reference to it floating around anywhere. You
should not, as a rule, close any object you didn't open, because you
don't know for sure that that same object isn't being referred to by
some other code (not necessarily under your control) that is relying on
it being open. Most people I know believe you should make a practice of
always closing any object you opened, and never closing any object you
didn't open.
As far as setting to Nothing is concerned, you shouldn't *have* to set
any non-static, local variable to Nothing -- normal procedure exit
routines should take care of that. However, there have been reports in
the past of bugs involving Access VBA not cleaning up local object
variables. I haven't seen these bugs myself, and I'm pretty sure
they've long since been fixed, but it's not a bad habit at all to
explicitly set to Nothing any object reference you're through using.
You may as well be sure. And doing this is absolutely essential if the
object variable is static or global in scope; otherwise you may find
that Access won't close because there's a dangling object reference that
can't be cleared from memory.