Utsav
Utsav

Reputation: 5918

Exception/Error Handling in q kdb -- Alternative of Try-Catch-Finally(Java)/Try-Except-Finally(Python)

As we have try-catch in java, I can find trap-at in q kdb.
But my requirement is of try-catch-finally i.e in try block I'm opening odbc connection and in finally I want to close odbc connection.

Sudo code:

try{
  con=openODBCConnection(dbName);
  //n statements;
}catch(Exception e){
   catchingNotSoImpException(e)
}finally{
 closeODBCCon(con);
}

Upvotes: 1

Views: 7153

Answers (2)

Ryan McCarron
Ryan McCarron

Reputation: 909

This is a fairly generic approach to using try-catch-finally logic in kdb, which separates out the try-catch, always runs the "finally" function. This returns the output if successful in either the try or the catch if necessary, or the error code if both try and catch have broken, allowing (potentially) more useful investigation and/or security on breaks:

tcf:{[t;c;f] 
    r:@[(1b;)value@;t;@[(1b;)c@;;(0b;)::]];
    f[]; 
    $[r 0;r 1;'`$r 1]}

The top line is the "try-catch" portion.

@[(1b;)value@;t;@[(1b;)c@;;(0b;)::]]

The function is called like so:

tcf[(tryfunc;1;`a);catchfunc;finallyfunc]

so the input has to be something that can be value'd in kdb - symbol, function and argument list, or string.

This can be used as-is, but for an explanation:

The key portion of logic here are the projections of (1b;) and (0b;) together with @ on the value or c functions tell that operation to wait on input - so within the first part:

(1b;)value@

waits for the input t - if the value operation succeeds, (1b;correctOutput) is returned, i.e. the projection is executed.

If that fails, the error is passed to

@[(1b;)c@;;(0b;)::]

Which is basically the same thing, but instead of value, it uses the catch function, c. This is a projection which takes the input passed from the failed value before, then applies the same operations as above. Failed output is passed to a global null ::.

This ensures the data structure r has a leading 1b if either the try or catch was successful, and a 0b if both failed.

The finally function is then run, and the return is either the successful answer or a thrown error in the case of double failure.

Examples using similar definitions to Rahul's answer:

q)tryfunc
{x+y}
q)workingcatchfunc
{show "catch";100}
q)brokencatchfunc
{show "catch";1+`a}
q)finallyfunc
{show"finally"}
q)tcf[(tryfunc;1;1);workingcatchfunc;finallyfunc]
"finally"
2
q)tcf[(tryfunc;1;`a);workingcatchfunc;finallyfunc]
"catch"
"finally"
100
q)tcf[(tryfunc;1;`a);brokencatchfunc;finallyfunc]
"catch"
"finally"
'type

This works with functions taking any number of arguments also:

q)tcf[(monot;1);brokencatchfunc;finallyfunc]
"finally"
10
q)tcf[(monot;`);brokencatchfunc;finallyfunc]
"catch"
"finally"
'type

Upvotes: 9

Rahul
Rahul

Reputation: 3969

There is no finally block in KDB. One approach to get functionality closer to this in KDB is to write a function for final block and call it in both try and catch. This will not guarantee that this function will be executed always but will cover most of the cases.

q)finally:{show "finally"}
q)try:{show "try"; show x+y;finally[]}
q)catch:{show "catch"; finally[]}
q).[try;1 2;catch]
Output:
"try"
3
"finally"

Now, it is important where you call the finally function inside try and catch. The order of call could change the behavior. My suggestion is to call it at the last and always return result from finally function. If there is any return value from try or catch functions then pass that value to finally function. This will reduce the chances of errors, make code simple and also remove other overheads like call ordering issue.

Example of a return value from try block:

q) finally:{show "finally"; :x}
q) try:{show "try";r:x+y;finally r}
q) catch:{show "catch"; finally[]}
q) .[tyr;1 2;catch]
Output
"try"
"finally"
3

Upvotes: 2

Related Questions