cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Weird behavior of Delete method in Macro

ELargant
Super Contributor

Dear all,

 

In Script Editor, I have written a simple MACRO like below:

 

iCounter = 0

Set oObjectsList = GetSelection("query selecting my objects")

Print oObjectsList.Count()   =======================> total = 5 for instance

For Each oListItem In oObjectsList

     oListItem.Delete("NoCheck")

     iCounter = iCounter + 1

Next

Print iCounter =================================> 2 objects deleted for instance

 

 

Question:

Why the total number of deleted object is not equal to the total number of element in the array ? (no errors are displayed in the script editor when I execute the macro and nothing in logfile). To delete all objects I need to execute the same macro several times...not cool

Real example, if I create 7 objects one after the other:

Object-1

Object-2

Object-3

Object-4

Object-5

Object-6

Object-7

     -> only objects with odd numbers are deleted when the macro is executed for the first time

     -> only Object-2 and Object-6 the second time

     -> and Object-4 the last time.

If I do the same example several times, the behavior is exactly the same.

 

But if I modify the macro with renaming the objects instead of deleting them, ALL are renamed.

So it seems that this is an "issue" about the Delete method.

It is very weird. Any idea ?

regards

Emmanuel

9 Replies

Dear cdebellegarde

Thank you for your answers very interesting and precious advices 😉

regards

Emmanuel

Hi,

Thank you for your answer.

I am running on Gbms.

regards

Emmanuel

Let's now have a look on the "renaming" issue.

You may have noticed that the behavior of the code depends on the database typology.

 

There is a explainable issue when you try to rename a collection build from an entire metaclass fetch in a non-rdbms database.

In such a repository, the index used to fetch a metaclass is the name index - it is the only index that is consistent for all the metaclasses.

You can figure that if you rename objects while fetching the collection, you modify the index while using it... and the result is unpredictable.

 

The RDMS databases use another way to fetch a metaclass to there may be no problem in this case.

 

There is no universal solution for a code that rename all the objects of a metaclass, regarding the fact that there may be a large amount of objects to rename; building a working collection may take a long time an maybe raise a memory exception.

You can nevertheless try such a code to do your job.

Another way is to rename through a collection sorted by the "_idabs" attribute: the fetch of such a collection will not depend on the name value.

 

If possible, a more efficient way  (in term of memory) may be to use a multi-pass algorithm that loops while there is something to do

 

 

 

 

 

 

 

As you all noticed above, updating a collection may cause unconsistent behavior if we are fetching the updated collection.

This problem is not reserved to mega, and the for-each documentation of vbScript explains that it can happen for any kind of collection.

The problem is that the behavior of the fetch depends on the kind of collection you are using.

If the collection is obtained through a metaassociationend, the deleted object is immediately removed from the list, and the list is now unpositionned : so which is the 'next' object ? in fact we can't decide !

Some other kind of collections have the hability of keeping deleted object; so you can fetch consistenly those collections. If you want to use a generic code, it may fail for one collection and not for the other...

 

Let's have a consistent strategy to delete objects in a collection.

The aim is to delete the collection item without fetching the collection.

 

1/ If you want to delete an entire collection obtained from a metassociationend, you can always delete the first item

 

    do

        set itm = myCol.Item(1)

        if itm.exists then itm.delete

   loop while itm.exists

 

in fact Item(1) begins a new fetch for the collection that is always consistent.

But it is dangerous : if you use this code for another kind of collection, it can raise an infinite loop !

 

2/ the more consistent - and universal - solution is to pre-build a collection involving all the objects you what do delete

 

Set collectionToDelete = GetSelection

collectionToDelete.insert myCol   ' in this example we will delete all the items of myCol

do
  set ObjToDelete = collectionToDelete.item(1)
  set foundobject = myCol.item(ObjToDelete.getid)
  if foundobject.exists then foundobject.delete
  collectionToDelete.remove ObjToDelete
Loop while collectionToDelete.count

 

in such a code you can insert a fail-proof code (for example when you have not the right to delete a specific item) and avoid an infinite loop issue, because the scanned object is always removed from the remoting collection.

 

 

 

 

 

 

 

 

  

 

 

 

 

Are you running on Gbms or Oracle/SQLServer?

 

We had some weird script behaviour in the past under SQLServer but it was because the DBA's did not install the required stored procedures. Once they were installed, we had no issues anymore

 

regards

 

stijn

ELargant
Super Contributor

Sorry for the delay....I did lot of tests 😉

I tried to execute my former macro.....I did not succeed in reproducing the bug I have given you.

 

Your example works perfectly. problem solved.

But........

I encountered a new bug that does not appear each time I execute the same Macro; not during deletion but during the renaming of an object. I know this is not the same subject but I used your piece of code for renaming object instead of deleting objects.

For i=1 To oObjectsList.Count()

     oObjectslist.item(i).SetProp  "Name", NewName

Next

I lauched 4 times the same Macro:

- first time, the bug appears after renaming 785 objects

- second time, the bug appears after renaming596 objects

- third time, after 276 objects

- last time, no bug and all objects (37873) were renamed correctly after 5h48min

As I said, I used the same Macro and each time I reused the same database.

 

The bug was:

c:\.....\MyMacro.vbs : property update Error line 148, offeset 12 :

Error(0x800ac012): object XXXXXXXXX, Property Name: Access already freed : 38546c0

It seems that there is a problem in managing objects behind the execution of the macro which is independant of the coding.

And this issue appears in a random way and not often.

My log file does not containt any additional information.

 

This is for your information.

 

As this post is solved, I gonna close it.

Thank you.

Emmanuel

 

 

 

Your code 

While oObjectsList.Count() > 0
     oObjectsList.Item(1).Delete("NoCheck")
Wend

 seems OK to me.

 

Do you always have an error using this code "for the first time" ?

If so, can you post the error log (even though I'm not sure to be able to help you on this).

And one last question, if you have errors with this code, do you have the same error with the example I gave you ?

 

Lionel

ELargant
Super Contributor

Ok I see.

Via "For Each..." the list is updated each time an element is deleted.

 

Is this additional script is correct or should be avoid ?

 

While oObjectsList.Count() > 0

     oObjectsList.Item(1).Delete("NoCheck")

Wend

 

because I used it before but I had a similar issue (but with error).

Sometime for the an object, if I launch the macro for the first time, I have an error like:

Error(0x800aa002) : object XXXXXX: Error

and if I relaunch the macro a second time without changing anything the object is deleted.

 

regards

Emmanuel


    
    

lionel
MEGA
MEGA

Hello,

 

to delete all objects from a collection, you should write

For i = 1 to oObjectsList.count
  oObjectsList.item(1).delete
Next

 or 

For i = oObjectsList.count to 1 Step -1
  oObjectsList.item(i).delete
Next

 

If you write as you did 

For Each oListItem In oObjectsList
     oListItem.Delete
Next

You will delete the first Item, and so the second item will become the first one, and when you will delete the second item you will in fact delete the third one...(you will miss half of the items in the end)

 

Regards,

 

Lionel