I have some TSQL that takes in WKT representations of geography and processes them.
Part of the processing is to check that they are valid bits of WKT before using them.
To do this I use the STIsValid() fucntion. When this function sees WKT with coordinates it considers are invalid it returns 0 (you can then make them valid with .MakeValid().
But, if it sees something that is clearly not WKT it throws an error, e.g.
geography::STGeomFromText('I_AM_NOT_WKT', 4326).STIsValid() = 0
Gives:
System.FormatException: 24114: The label I_AM_NOT_WKT in the input well-known text (WKT) is not valid.
Rather than try to write something that pre validates WKT to get it to a level that SQL can check, I decided to use a TRY CATCH block to get the records with bad WKT without crashing the routine. This works fine. The problem is if I do that it invalidates the transaction I've got going.
This is the basic structure of my TSQL:
BEGIN TRY
BEGIN TRANSACTION
…
--Doing some stuff
…
TRY
Is the current string valid WKT format (test using STIsValid())
NO?
Make the string valid using .MakeValid()
END TRY
CATCH
--The string was not valid WKT format
-- It's bad so write it to the bad table. !!! This causes the error !!!
END CATCH
…
--doing more stuff
…
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
END CATCH
As soon as I get a bad WKT string to test the whole transaction is doomed and therefore as soon as I try to write to the bad table I get the error:
" The current transaction cannot be committed and cannot support operations that write to the log file"
Which is to be expected.
My question is, is there a way to prevent the CATCH block invalidating my transaction? Or can anyone see another way around this?
Thanks
This is an extension of an old question of mine where the answer wasn't quite what I was asking. What I'm doing is executing SQL Script on an MS SQL Server database. This script may or may not return any recordsets. The problem is that the way that ADO components work, at least to my knowledge, I can only explicitly request one or the other.
If I know a query will return data, I use TADOQuery.Open
If I know a query will not return data, I use TADOConnection.Execute
If I don't know whether query will return data or not... ???
How can I execute any query and read the response to determine whether it has any recordsets or not so I can read that recordset?
What I've tried:
Calling TADOQuery.Open, but raises exception if there's no recordset
Calling TADOQuery.ExecSql, but never returns any data
Calling TADOConnection.Execute, but never returns any data
Using Option 3 and reverting to Option 1 on exceptions, but this is double the work (script files over 38,000 lines) and kinda nasty.
Using TADOCommand.Execute, but keeps raising "Parameter object is improperly defined. Inconsistent or incomplete information was provided" on creating some stored procedures (which otherwise don't happen when using TADOConnection.Execute).
Calling TADOConnection.Execute overload which returns _Recordset, but then the TADOConnection.Errors returns empty (and I depend on this).
Just as some background, the purpose is to implement something like the SQL Query tool in the SQL Server Management Studio. It allows you to execute any SQL script, and if it returns any recordsets, it displays them, otherwise it just displays output messages. The tool I'm working on automatically breaks SQL Script at GO statements, and executes each individual block separately. Some of those blocks might return data, and others might not. It's already obvious that I cannot make this determination prior to execution, so I'm looking for a way to go ahead with the execution and observe the result. TADOConnection.Execute provides some useful information, including the Errors (or output messages).
As of now, the only option I have is to supply an option in the user interface to allow the user to choose which type of execution to use - but this is what I'm trying to eliminate.
EDIT
The TADOCommand.Execute method is the closest to what I want. However, it fails on some bits of script which otherwise work perfectly fine using TADOConnection.Execute. See #5 above in "What I've tried". I almost wrote that as my answer, until I found this error happens on almost everything.
EDIT
After posting my answer below, I then came to learn that the Errors property no longer returns anything when I use this other overload of Execute. See #6 above in "What I've tried".
Calling...
ADOConnection1.Execute('select * from something', cmdText, []);
...does not return anything in ADOConnection1.Errors, whereas...
var
R: Integer;
begin
ADOConnection1.Execute('select * from something', R);
...does return messages in ADOConnection1.Errors, which is what I need, but yet, doesn't return any recordsets.
EDIT: Not the right solution
I discovered my solution finally after digging even deeper. The answer is to use the TADOConnection.Execute() overload which supports returning the recordset:
function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
Then, just assign the resulting _Recordset to the Recordset property of supported dataset components.
var
RS: _Recordset;
begin
RS := ADOConnection1.Execute('select * from something', cmdText, []);
if Assigned(RS) then begin
ADODataset1.Recordset:= RS;
...
end;
end;
The downside is that you cannot use the other overload which supports returning the RowsAffected. Also, nothing is returned in the Errors property of the TADOConnection when using this overload version of Execute, whereas the other one does. But that other doesn't return a recordset.
I have the following code:
if (complex) then
read(unitvector) (CoefC(jl),jl=1,NV)
endif
Where a user indicates if the data is a collection of complex numbers. Now, if the user indicates that it is, but it actually isn't, i get error 67 (input requires too much data). How can i trap that, so i can write that perhaps a user made a mistake. I was thinking it would look something like:
read(unitvector, ioStat=iocplx) (CoefC(jl),jl=1,NV)
but where would i put the "if" to check for the error?
That depends on the overall logic of the program, we cannot tell you the best way for you from such small code snippet. You can try something like (not tested):
if (complex) then
read(unitvector, ioStat=iocplx) (CoefC(jl),jl=1,NV)
if (iocplx/=0) stop "Error reading the complex data."
end if
or
if (complex) then
read(unitvector, ioStat=iocplx) (CoefC(jl),jl=1,NV)
if (iocplx/=0) then
write(*,*) "Error reading the complex data, triung real."
complex = .false.
backspace(unitvector)
read(unitvector, ioStat=ioreal) (CoefR(jl),jl=1,NV)
if (ioreal/=0) then
stop "Error reading real data."
end if
end if
end if
But you really did not specify what you want, stop the program and write a meaningful message? Read data some other way? Everything is possible and we do not have a crystal ball.
I'm working on refactoring a decently large project, and I'm interested in searching out and reducing Code Clone for better standardization as well as ease of development.
I've got a code snippet that keeps coming up in "Exact Matches" (using Visual Studio 2012's
"Find Code Clones" feature).
Here it is:
End If
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using
End Using
Return Nothing
Basically, I have a whole host of similar functions (similar in structure but not in actual function) that all open with something like this:
Const sql As String = ...
Using cn As SqlConnection...
Using cmd As SqlCommand(sql,cn)
... Maybe add some SqlParameters
cn.Open()
... Something with cmd.Execute...
Now, I recognize that the first code block is IDENTICAL across many, many methods, but I can't figure out a way to pull that code out, write it once and simply call it each time I need that functionality. It seems to me that there is too much control flow occurring.
So, I'm stumped as to how to fix this (and I'm only assuming that I can "fix" this because Microsoft has identified it as "cloned code").
I'm thinking of something along the lines of making a small number of functions that do the same type of thing (like returning a count from a table, returning a top value, etc...) and only really differ by the SQL that is executed. That could be a bit tricky, though, since sometimes the parameters (type and number) differ.
Any thoughts?
I wouldn't concern yourself with those. Your common-sense first impression is correct. While, technically speaking, the syntax is repeated multiple times, it is not really a repetition of logic or an algorithm of any kind. That's not to say there's no way to reduce that repetition, it's just that by doing so, you will likely end up with a worse design in your code.
For instance, you could create a single method that does all the setup and tear-down and then just calls a method in the middle that actually uses the connection to do the work, such as:
Public Function PerformDbTask(task As IMyDbTask)
Using cn As SqlConnection...
Using cmd As SqlCommand = cn.CreateCommand()
Try
cn.Open()
task.Perform(cmd)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using
End Using
Return Nothing
End Function
However, what have you really gained? Probably not much at all, yet you've lost a lot of flexibility. So, unless that kind of design is actually necessary for what you are trying to do, I wouldn't waste time trying to solve a problem that doesn't exist.
You could create a class that implements a builder pattern, that winds up looking like
Dim list =
SqlBuilder.Query("SELECT ...")
.WithConnection("...connection string...")
.WithParameter(userName)
.WithParameter(lastTrackId)
.RetrieveTopRows(10)
Your problem is you are using a clone detector that matches token sequences (thus it matches the end-of-block sequences you exhibited), as opposed to clone detectors that match code structures. While the token sequence is technically a clone, it isn't an interesting clone. Token clone detectors produce many many "false positive" clones like this, which simply waste your time.
It is easier to build token sequence detectors, which is why they built that into MS Studio.
If you want better detectors, you have to step outside of Studio.
You should look into clone detectors that match on abstract syntax trees. They don't produce this kind of false positive, and they can find clones with complex parameters (as opposed to single-token parameters).
You should also understand that just because something has been identified as a clone, that it is not always easy or possible to refactor it away. The language you have may not have sufficiently strong abstraction mechanisms to handle that case.
I have process that needs to create a bunch of records in the database and roll everything back if anything goes wrong. What I want to do is this:
Public Structure Result
Public Success as Boolean
Public Message as String
End Structure
Private _Repository as IEntityRepository
Public Function SaveOrganization( _
ByVal organization As rv_o_Organization) As Result
Dim result = Result.Empty
_Repository.Connection.Open()
_Repository.Transaction = _Repository.Connection.BeginTransaction()
''//Performs validation then saves it to the database
''// using the current transaction
result = SaveMasterOrganization(organization.MasterOrganization)
If (Not result.Success) Then
GoTo somethingBadHappenedButNotAnException
End If
''//Performs validation then saves it to the database
''//using the current transaction
result = SaveOrganziation(dbOrg, organization)
If (Not result.Success) Then GoTo somethingBadHappenedButNotAnException
somethingBadHappenedButNotAnException:
_Repository.Transaction.Commit()
_Repository.Connection.Close()
Return result
End Sub
Is this an ok use of the GoTo statement, or just really bad design? Is there a more elegant solution? Hopefully this sample is able to get the point across
If you have to ask, don't do it.
For your specific code, you could do it like this:
Public Function SaveOrganization(ByVal organization As rv_o_Organization) As Result
Dim result As Result = Result.Empty
_Repository.Connection.Open()
_Repository.Transaction = _Repository.Connection.BeginTransaction()
'Performs validation then saves it to the database
'using the current transaction
result = SaveMasterOrganization(organization.MasterOrganization)
'Performs validation then saves it to the database
'using the current transaction
If result.Success Then result = SaveOrganziation(dbOrg, organization)
_Repository.Transaction.Commit()
_Repository.Connection.Close()
Return result
End Sub
Goto has such a terrible reputation that it will cause other developers to instantly think poorly of your code. Even if you can demonstrate that using a goto was the best design choice - you'll have to explain it again and again to anyone who sees your code.
For the sake of your own reputation, just don't do it.
Really bad design. Yes.
There might be some extreme edge cases where it is applicable, but almost unequivocally, no, do not use it.
In this specific case, you should be using the Using statement to handle this in a better manner. Generally, you would create a class which would implement IDisposable (or use one that already does) and then handle cleanup in the Dispose method. In this case, you would close the connection to the database (apparently, it is reopened again from your design).
Also, I would suggest using the TransactionScope class here as well, you can use that to scope your transaction and then commit it, as well as auto-abort in the face of exceptions.
The only time you should use a goto, is when there is no other alternative.
The only way to find out if there are no other alternatives is to try them all.
In your particular example, you should use try...finally instead, like this (sorry, I only know C#)
void DoStuff()
{
Connection connection = new Connection();
try
{
connection.Open()
if( SomethingBadHappened )
return;
}
finally
{
connection.Close();
}
}
I would say extremely sparingly. Anytime I have had to think about using a GOTO statement, I try and refactor the code. The only exception I can think of was in vb with the statement On Error Goto.
There is nothing inherently wrong with goto, but this isn't a very ideal use of it. I think you are putting too fine a point on the definition of an exception.
Just throw a custom exception and put your rollback code in there. I would assume you would also want to rollback anyway if a REAL exception occured, so you get double duty out of it that way too.
Gotos are simply an implementation detail. A try/catch is much like a goto (an inter-stack goto at that!) A while loop (or any construct) can be written with gotos if you want. Break and early return statements are the most thinly disguised gotos of them all--they are blatant(and some people dislike them because of the similarity)
So technically there is nothing really WRONG with them, but they do make for more difficult code. When you use the looping structures, you are bound to the area of your braces. There is no wondering where you are actually going to, searching or criss-crossing.
On top of that, they have a REALLY BAD rep. If you do decide to use one, even in the best of possible cases, you'll have to defend your decision against everyone who ever reads your code--and many of those people you'll be defending against won't have the capability to make the judgment call themselves, so you're encouraging bad code all around.
One solution for your case might be to use the fact that an early return is the same as a goto (ps. Worst psuedocode ever):
dbMethod() {
start transaction
if(doWriteWorks())
end Transaction success
else
rollback transaction
}
doWriteWorks() {
validate crap
try Write crap
if Fail
return false
validate other crap
try Write other crap
if Fail
return false
return true
}
I think this pattern would work in VB, but I haven't used it since VB 3 (around the time MS bought it) so if transactions are somehow bound to the executing method context or something, then I dunno. I know MS tends to bind the database very closely to the structure of the code or else I wouldn't even consider the possibility of this not working...
I use goto's all the time in particular places, for example right above a Try Catch, in case a you prompt the user, "Retry?, Cancel", if retry then Goto StartMyTask: and increment the Current Try of Maximum retries depending on the scenario.
They're also handy in for each loops.
For each Items in MyList
If VaidationCheck1(Item) = false then goto SkipLine
If ValidationCheck(Item) = false then goto skipline
'Do some logic here, that can be avoided by skipping it to get better performance.
'I use then like short circuit operands, why evaluate more than you actually have to?
SkipLine:
Next
I wouldn't substitute them for functions and make really huge blocks of long code, just in little places where they can really help, mostly to skip over things.
Everytime I've seen a goto used, simple refactoring could have handle it. I'd reccomend never using it unless you "know" that you have to use it
I'm tempted to say never, but I suppose there is always one case where it may be the best solution. However, I've programmed for the last 20 years or so without using a Goto statement and can't foresee needing one any time soon.
Why not wrap each function call in a try catch block and when that is done, if one of your exceptions are thrown, you can catch it and close the connection. This way, you avoid the GOTO statement altogether.
In short, the GOTO statement is NOT a good thing, except in unusual situations, and even then it is usually a matter of refactoring to avoid it. Don't forget, it is a leftover from early languages, in this case BASIC.
I'd say use very sparingly as it's generally associated with introducing spagetti code. Try using methods instead of Labels.
A good case I think for using GOTO is to create a flow through select which is available in C# but not VB.
The go to statement has a tendency to make the program flow difficult to understand. I cannot remember using it during the last ten years, except in visual basic 6 in combination with "on error".
Your use of the go to is acceptable as far as I am concerned, because the program flow is very clear. I don't think using try ... catch would improve things much, because you would need to throw the exceptions on the locations where the go tos are now.
The formatting, however, is not very appealing:-)
I would change the name of the go to label to something else, because this location is also reached when everything is successful. clean_up: would be nice.
Eh, there was a decent use for it in VBscript/ASP for handling errors. We used it to return error handling back to ASP once we were done using on error resume next.
in .net? Heavens, no!
Everyone says avoid it but why.
The GOTO syntax is a jump statement in assembly - very efficient.
Main reason to avoid it is code readability. You need to find the GOTO label in the code which is hard to eyeball.
Some people think that it might cause memory leaks but I've seen that experts say that this is not true in .NET.