SQL geometry::STGeomFromText throwing error and stopping job - sql

Folks,
Got an odd one for you.
I've got a stored procedure I use to parse some tabular data to create proper SQL geometry objects.
The SP makes use of the function MakeValid().
In my case I have found some objects that fail the test. These do not break the stored procedure however. The Stored procedure is happy to run and simply show the error in the results.
Msg 6522, Level 16, State 1, Line 257 A .NET Framework error occurred
during execution of user-defined routine or aggregate "geometry":
System.FormatException: 24306:
However when I execute this SP in a scheduled job, the first time it encounters one of these exceptions the job fails and the SP stops running.
I'm actually not sure what to do here. I've tried a TRY..CATCH block but this doesn't stop the error being raised and the job exits anyway.
So while it's a MakeValid function that's raising the error I would imagine an SP that encounters a function error would cause the same issue.
Any thoughts how I might handle this? BTW I have no control over the input quality other than to flag the errors and then go back and repair them. I'd still like the rest of the valid records to be processed though.
Here's the operable section of code.
SET #GEOM = geometry::STGeomFromText(#GEOMWKT, 4326)
IF #GEOM.STIsValid() = 0
BEGIN
BEGIN TRY
SET #GEOM = #GEOM.MakeValid()
END TRY
BEGIN CATCH
Print 'Error here'
END CATCH
END
Here is an example of an invalid geometry that throws an error.
SET #GEOM = geometry::STGeomFromText('LINESTRING(-121.895652 37.37225, -121.895652 37.37225)', 4326)
Thanks for any and all assistance.

I'm having a hard time validating that this will work for you (i.e. my local instance is too good at calling MakeValid()), but this might just work for you.
using Microsoft.SqlServer.Server;
using Microsoft.SqlServer.Types;
using System.Data.SqlTypes;
public partial class UserDefinedFunctions
{
[SqlFunction]
public static SqlGeometry TryMakeValid_geometry(SqlGeometry g)
{
SqlGeometry r;
try
{
r = g.MakeValid();
}
catch (System.Exception)
{
r = SqlGeometry.Null;
}
return r;
}
[SqlFunction]
public static SqlGeometry TryParseWKT_geometry(SqlString wkt)
{
SqlGeometry r;
try
{
r = SqlGeometry.Parse(wkt).MakeValid();
}
catch
{
r = SqlGeometry.Null;
}
return r;
}
}
Deploy this CLR to your database and call the function with your geometry instance. It should return NULL if the call to MakeValid() fails.

OK this is the answer that I'm going with but significant credit goes to Ben Thul for the CLR which achieves the same result using a different method.
The realisation is more correctly understanding the question. I made two mistakes. The first was not realising the error I was trying to catch was outside the TRY..CATCH block. The second was believing I needed to try and validate the WKB expression of the geometry. In fact, the following method allows the validation of the WKT before attempting to create a WKB. The following method identifies the invalid WKT, sets a TRUE/FALSE condition. With the WKT validated a valid WKB can be safely created.
Once I understood the question asking the right question turned up the solution here.
https://gis.stackexchange.com/questions/66642/detecting-invalid-wkt-in-text-column-in-sql-server
I have adapted the code to suit my implementation.
/*REVISED CODE*/
DECLARE #valid bit
DECLARE #GEOMWKT varchar(max)
DECLARE #GEOM geometry
Set #GEOMWKT = 'LINESTRING(-121.895652 37.37225, -121.895652 37.37225)'-- Test faulty value
Set #valid = 1
--Test WKT
BEGIN TRY --The is the test here.
SET #valid = geometry::STGeomFromText(#GEOMWKT, 4326).STIsValid()--We don't try to
END TRY --MakeValid(). No point.
BEGIN CATCH
SET #valid = 0
END CATCH
--Now that we know whether the WKT will pass or fail we can operate in a known
--state and avoid raising an error
IF #valid = 1
BEGIN
SET #GEOM = geometry::STGeomFromText(#GEOMWKT, 4326)--Safely create a valid WKB
END
ELSE
BEGIN
SET #GEOM = geometry::STGeomFromText('POINT EMPTY', 4326)-- Set geometry to empty on fail
Print 'Geometry Fail'
END

Related

Is there a Denodo 8 VQL function or line of VQL for throwing an error in a VDP scheduler job?

My goal is to load a cache when there is new data available. Data is loaded into the source table once a day but at an unpredictable time.
I've been trying to set up a data availability trigger VDP scheduler job like described in this Denodo community post:
https://community.denodo.com/answers/question/details?questionId=9060g0000004FOtAAM&title=Run+Scheduler+Job+Based+on+Value+from+a+Query
The post describes creating a scheduler job to fail whenever the condition is not satisfied. Now the only way I've found to force an error on certain conditions is to just use (1/0) and this doesn't always work for some reason. I was wondering if there is way to do this with a function like in normal SQL, couldn't find anything in the Denodo documentation.
This is what my code currently looks like:
--Trigger job
SELECT CASE
WHEN (
data_in_cache = current_data
)
THEN 1 % 0
ELSE 1
END
FROM database.table;
The cache job waits for the trigger job to be successful so the cache will only load when the data in the cache is outdated. This doesn't always work even though I feel it should.
Hoping someone has a function or line of VQL to make Denodo scheduler VDP job result in an error.
This would be easy by creating a custom function that, when executed, just throws an Exception. It doesn't need to be an Exception, you could create your own Exception to see it in the error trace. In any case, it could be something like this...
#CustomElement(type = CustomElementType.VDPFUNCTION, name = "ERROR_SAMPLE_FUNCTION")
public class ErrorSampleVdpFunction {
#CustomExecutor
public CustomArrayValue errorSampleFunction() throws Exception {
throw new Exception("This is an error");
}
}
So you will use it like:
--Trigger job SELECT CASE WHEN ( data_in_cache = current_data ) THEN errorSampleFunction() ELSE 1 END FROM database.table;

How do you throw Lua error up?

Is it possible to throw a Lua error from a function to be handled by the script calling the function?
For example the following will throw an error at indicated comment
local function aSimpleFunction(...)
string.format(...) -- Error is indicated to be here
end
aSimpleFunction("An example function: %i",nil)
But what I would rather do is catch the error and throw out a custom error by the function caller
local function aSimpleFunction(...)
if pcall(function(...)
string.format(...)
end) == false then
-- I want to throw a custom error to whatever is making the call to this function
end
end
aSimpleFunction("An example function: %i",nil) -- Want the error to start unwinding here
The intention being that in my actual use cases my functions would be more complicated and I would like to provide more meaningful error messages
The stack level of an error can be specified when throwing a new error
error("Error Message") -- Throws at the current stack
error("Error Message",2) -- Throws to the caller
error("Error Message",3) -- Throws to the caller after that
Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.
Using the example given in the question
local function aSimpleFunction(...)
if pcall(function(...)
string.format(...)
end) == false then
error("Function cannot format text",2)
end
end
aSimpleFunction("An example function: %i",nil) --Error appears here
Use the error function.
error("something went wrong!")
Catching an error is as simple as using pcall
My_Error()
--Error Somehow
end
local success,err = pcall(My_Error)
if not success then
error(err)
end
Undoubtedly you're asking how this works. Well pcall runs a function in a protected thread (protected-call) and returns a bool, if it ran successfully, and a value (what it returned/the error).
Also don't think this means arguments to the function are impossible, simply pass them to pcall as well:
My_Error(x)
print(x)
--Error Somehow
end
local success,err = pcall(My_Error, "hi")
if not success then
error(err)
end
For more error handling control, see http://www.lua.org/manual/5.3/manual.html#2.3 and http://wiki.roblox.com/index.php?title=Function_dump/Basic_functions#xpcall

reading user input in PL/SQL in Java

I am running a database and trying to do all data handling through PS/SQL, and the thing is that once I establish the connection, I have this code, but it fails with the error of
SQLException:Invalid SQL type: sqlKind = UNINITIALIZED
The reason why I am executing it in java is because my assignment tells me that java will handle some things (that I haven't included here), but as for everything else (data manipulation and error checking), it must be handled by oracle. Honestly this harsh restriction sounds silly to me.
The intent of the code below is to read user input via an anonymous block and then print it to the DBMS output, though I'm not sure if that is even possible.
Can anyone help me to fix this?
try {
CallableStatement cs = dbConnection.prepareCall("" +
"DECLARE" +
"myMessage varchar2 (20);" +
"BEGIN" +
"myMessage := '&myMessage';" +
"DBMS_OUTPUT.PUT_LINE(myMessage);" +
"END;");
cs.execute();
} catch (SQLException x) {
System.out.println("SQLException:" + x.getMessage());
}

delphi has ExecSQL succeeded or failed

Hello i've this function to update my Access DB using TUniQuery :
var
Res:Boolean;
begin
Res:=false;
try
with MyQuery do
begin
Active := false;
SQL.Clear;
SQL.Add('Update MYTABLE');
SQL.Add('set username='+QuotedStr(NewUserName));
SQL.Add(',password='+QuotedStr(NewPassword));
SQL.Add('where username='+QuotedStr(ACurrentUserName));
ExecSQL;
Res:=true;
end;
except
Res:=False;
end ;
Result:=Res;
end;
Is the use of Try ... except enough to KNOW when " ExecSQL " succeeds or fails ?
or is there any other better approach ?
thank you
You may want to consider your update succeeded if no exception is raised. It means the database is responsive and parsed and executed your statement without syntax errors.
In a statement like shown, you may also want to be sure that exactly one row was updated, because I assume that's your intention.
To check that, you can resort to the result of the ExecSQL method, which returns the number of rows affected by the execution of the statement. So, you may change your code to this:
begin
with MyQuery do
begin
Active := false;
SQL.Clear;
SQL.Add('Update MYTABLE');
SQL.Add('set username='+QuotedStr(NewUserName));
SQL.Add(',password='+QuotedStr(NewPassword));
SQL.Add('where username='+QuotedStr(ACurrentUserName));
Result := ExecSQL = 1; //exactly 1 row updated
end;
end;
I also changed the unconditional exception handler, since it may not be the proper site to eat any exception, and also removed the local variable to store the Result, since that really is not necessary.
After reading your added text and re-thinking your question:
Is the use of Try ... except enough to KNOW when " ExecSQL " succeeds or fails ?
You really have to change your mind about exception handling and returning a boolean from this routine. Exceptions were introduced as a whole new concept on how to address exceptional and error situations on your programs, but you're killing this whole new (and IMHO better) approach and resorting to the old way to return a value indicating success or failure.
Particularly a try/exception block that eats any exception is a bad practice, since you will be killing exceptions that may be raised for too many reasons: out of memory, network problems like connection lost to database, etc.
You have to re-think your approach and handle these exceptional or error conditions at the appropriate level on your application.
My advise is:
change this from a function to a procedure, the new contract is: it returns only if succeded, otherwise an exception is raised.
if an exception occurs let it fly out of the routine and handle that situation elsewhere
raise your own exception in case no exactly 1 row is updated
change the query to use parameters (avoiding sql injection)
The routine may look like this:
procedure TMySecurityManager.ChangeUserNameAndPassword();
begin
MyQuery.SQL.Text := 'Update MYTABLE'
+ ' set username = :NewUserName'
+ ' , password = :NewPassword'
+ ' where username = :username';
MyQuery.Params.ParamByName('NewUserName').AsString := NewUserName;
MyQuery.Params.ParamByName('NewPassword').AsString := NewPassword;
MyQuery.Params.ParamByName('username').AsString := ACurrentUserName;
if MyQuery.ExecSQL <> 1 then
raise EUpdateFailed.Create('A internal error occurred while updating the username and password');
//EUpdateFailed is a hypotetical exception class you defined.
end;

A simple transaction doesn't work on SQL Server 2005

I am doing this in SQL Server 2005. I have a table, there is only one column of type int, o you cannot insert char in it.
DECLARE #intErrorCode INT
BEGIN TRAN
Update TestTable set A='a' where A=3 --UPDATE TO CHAR, FAIL
SELECT #intErrorCode = ##ERROR
IF (#intErrorCode <> 0) GOTO PROBLEM
COMMIT TRAN
PROBLEM:
IF (#intErrorCode <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
END
I am expecting to see 'Unexpected error occurred!' as result.
But what I actually see is:
Conversion failed when converting the varchar value 'a' to data type int.
It seems that my SQL Server doesn't take my code as a transaction at all... It hit the fail line and quit running right after that.
What am I doing wrong here?
First use Try catch blocks instead.
However, no sql error trapping will work for all types of errors.
Read about error handling using the try catch block in Books online and you will see a discussion of what types of errors are not trapped.
Also it is better to return the actual error than a general message usually. It is much easier to track down teh error issue when you know the real error.