logo
vbRad Home
Source Code
Book Reviews
Forum
Links
About Us
Contribute

Compare Databases with SQL Effects Clarity
 
 Clone ADO Recordsets The Right Way

Posted on
7/12/2001
Author:
Robert Gelb
Email:
Not Shown
Applies To OS:
All
Product:
N/A



Related Articles
Clone Recordset Structure

See Also: Clone Recordset Structure

Contrary to popular belief, Recordset.Clone doesn't actually clone the recordset. It doesn't actually create a new object in memory - it simply returns a reference to the original recordset with the option of making the reference read-only. To verify this claim, simply delete a record from the cloned recordset and you will see that the .RecordCount on the original recordset also decreases.

So how do you actually make a true clone of the recordset with no dependencies or dangling references? One way is to save the recordset to file via the .Save method and then read it into another recordset. However, this method is very costly and time-consuming because ADO has to write the entire recordset structure, including field types and every property and every piece of data to disk. The proper answer is in the rarely used ADODB.Stream object. It turns out that you can save the entire recordset to this object (which is in memory) and then restore to another recordset. Check out the code below.

Note that ADO contains a bug which shows up when using this method. When opening a recordset from a Stream object, the recordset retains all of the memory allocated to the Stream object, in addition to allocating its own. Subsequently setting the Stream object to Nothing does nothing. However, when a Recordset object is deallocated, all the memory, including that of the dead Stream object is deallocated as well. So, not a horrible bug, but something to keep in mind when you have multiple users accessing your cloning code on the web server. I've talked to the developer inside Microsoft on the ADO team who thought that this was not a bug, but rather a design decision. Let me explain: Recordset assumes that since it was created from the IStream interface, it may be asked in the future to stream it elsewhere using this interface. Thus rather than having to recreate this interface, it simply streams the IStream memory chunk it has been created by. I think, this behavior is a bug and if it indeed was a design decision, then it was a bad design decision.

For example, if you want to clone a really large recordset which normally takes 110 MB of RAM (11000 rows and 650 columns), you will end up "leaking" 50 MB. Your total consumption of RAM will be 270 MB (110 MB for the original RS, 110 MB for the cloned RS and 50 MB that was absorbed from the Stream object).



Add the following function to Module, Class or Form

Public Function Clone(ByVal oRs As ADODB.Recordset, _
    Optional ByVal LockType As ADODB.LockTypeEnum = adLockUnspecified) As ADODB.Recordset
	
    Dim oStream As ADODB.Stream
    Dim oRsClone As ADODB.Recordset
    
    'save the recordset to the stream object
    Set oStream = New ADODB.Stream
    oRs.Save oStream
    
    'and now open the stream object into a new recordset
    Set oRsClone = New ADODB.Recordset
    oRsClone.Open oStream, , , LockType
    
    'return the cloned recordset
    Set Clone = oRsClone
	
    'release the reference
    Set oRsClone = Nothing
End Function
Remarks

  • The function assumes that the original recordset exists (i.e. not equal to Nothing)




Add Your Comment  

Name: Email Address: all fields optional
Notify me via email when someone responds to this message (valid email required).

Enter the word:
 



Comments
#1. By ML. Posted on 11/30/2006 9:00:26 PM
Thank you for your article. It saved me loads of time. And it was done the right way!!

#2. By fw. Posted on 7/31/2007 2:50:14 AM
Clear/Robust/Effective...Thanks

#3. By fh. Posted on 11/24/2007 7:27:49 AM
Thanks - just what I needed

#4. By Kiwo. Posted on 2/29/2008 4:30:28 PM
Thanks, just what i was serching for

#5. By nityanand. Posted on 5/1/2008 3:03:18 PM
Dear Sir,

This is really very nice .

but can u please mail me how can we do same thing in vb.net 2003

kind Regards,
nitya