I see the "fieldtypenames" code in db.pas indeed. And learned something new about something really not needed.. because TField.Fieldtype is commonly used for that and fieldtypenames also brings another string comparision which I don't doubt is slower than testing an enumerated type.
I would say: forget about the fieldtypenames and test for TField.Datatype.
BTW: the DBGrid has columns. I expect if you loop through columns and free them one by one, the grid is cleared.
But if you need to free and re-create a DBGrid because you have trouble with the columns, you really have some error somewhere. Like said: the dbrid refreshes its columns on a tdataset.open.
It's simple: My code doesn't produce the error you try to work around.
In your case, if you would use else if statements, only the one matching would be executed, or if you use begin..end you can use exit to get out of the loop, and if you use the case statement, also only the matching code is executed.
I hope you are aware that the event is triggered from somewhere in a unit where there it is expected that the code after the event is also executed. Your goto (if there is no more code than I have seen) does not bring you back to the point where you called it, so the code after the part triggering the event is never executed. Don't be supprised to see very unwanted behaviour. If not in this event, it will be in others.
If you don't believe what I say (because I have only 4 days of Lazarus and 15 years of Delphi):
http://www.delphibasics.co.uk/RTL.asp?Name=Goto&ExpandCode1=Yes(btw: the link says in red that goto should NEVER be used in modern languages)
My 5 cents, the rest is up to you.