This section describes how the GSQL language responds to exceptions and supports user-defined exception handling . An exception is a run-time error. The GSQL language supports both built-in system exceptions and user-defined exceptions. Built-in exceptions include GSQL language exceptions (such as out-of-range value, wrong data type, and illegal operation), and errors arising in other TigerGraph components or from the operation system.
The GSQL query language also supports user-defined exception responses, also known as exception handling. This section covers the following syntax for user-defined exception behavior:
When an exception occurs during the execution of a query, the default response is the following:
The query will not execute any more statements; it will exit.
If the query was run using the RUN QUERY command, then an error message will be displayed.
If the query was run by invoking the GET /query REST++ endpoint, then the output will be a simple JSON object. Some errors have a error "code" field; others do no t:
The example below show two common errors: wrong data type and divide-by-zero. First we define a simple query that divides 100.0 by the query's input parameter.
We then test three cases:
A valid input (such as n1 = 7)
Wrong data type (n1 = "A")
Divide by zero (n1 = 0)
First we test using the GSQL interface. When the query runs without error, the output is in JSON format. Where there is a built-in exception, however, only an error message is displayed.
The situation is a little different when running the query as a REST++ endpoint. The output is always in JSON format.
A query author can specify what should be the response if a particular type of exception occurs within a particular specified block of statements.
The following statement types are available to specify a user-defined exception condition or a user-defined exception response.
The EXCEPTION Declaration Statement names a user-defined exception.
The RAISE Statement indicates that one of the user-defined exceptions has occurred.
The TRY…EXCEPTION Statement is used to define and apply user-defined exception handling to a block of query-body statements. This can be used with or without preceding user-defined EXCEPTION and RAISE statements.
To use a user-defined exception, it must first be declared. An exception declaration statement declares a user-defined exception type, assigning a name and identification number. The id number errorCode must be greater than 40,000. Numbers 40,000 and lower are reserved for system exceptions. Exception statements must be placed before any query-body statements, after accumulator declaration statements . A query can declare multiple exception types.
The RAISE statement announces that a user-defined exception has just occurred. The exceptVarName must match one of the exceptions that was previously declared. An optional error message can be specified. Once the RAISE statement is executed, the flow of execution changes. If the RAISE statement is not within a TRY clause, then the query ends with the default exception response, using the error code and error message defined by the exception type and RAISE statements. If the RAISE is within a TRY statement, then execution jumps to the EXCEPTION handling clause of the TRY statement.
A RAISE statement itself does not include the conditions that define the exception. Typically, the user will use an IF…THEN statement and place the RAISE statement within the THEN clause.
The example below defines and checks for two types of exceptions: an empty input set (40001) and no matching edges (40002). Remember that the minimum allowed code number is 40001.
The TRY…EXCEPTION Statement is used to define and apply user-defined exception handling to a block of query-body statements. A TRY...EXCEPTION statement can be nested within a TRY block or EXCEPTION block.
The TRY…EXCEPTION Statement is a compound statement containing two blocks. The first block (TRY) consists of the query-body statements for which custom error handling should be applied. The second block (EXCEPTION) contains a series of WHEN…THEN exception handling clauses. Each exception handling clause names an exception type and specifies what actions to take in the event of the exception. An optional ELSE clause contains handling statements for all other exceptions. The following text and visual flowchart details how the TRY... EXCEPTION block handles an exception.
When an exception occurs within a TRY block, the flow of execution skips the remainder of the TRY block and jumps to the EXCEPTION block. The GSQL flow now seeks to match the exception type with a handler. After executing the handling statements in the THEN or ELSE clause, the flow skips the remainder of the EXCEPTION block and continues with the statement following the END statement. However, if there is no matching WHEN or ELSE handler, then the exception is propagated. That is, the RAISE state is maintained after exiting the EXCEPTION block. If the TRY...EXCEPTION block is nested inside another TRY block, then the handling process is repeated at this upper level. This repeats until either the exception is handled or there are no more TRY...EXCEPTION blocks.
Finally, if the unhandled exception is not within a TRY block, then the the query is aborted, and the default exception response is the output.
Case 1: If cond1 is true in the outer TRY block,
RAISE A and jump to the output EXCEPTION block.
Handled by ELSE HandStmtsZ.
Case 2: If cond2 is true in the inner TRY block,
RAISE A and jump to the inner EXCEPTION block.
Handled by handStmtsX;
Case 3: If cond3 is true in the inner TRY block,
RAISE B and jump to the inner EXCEPTION block. There is no matching handler here, so propagate the exception. Jump to the outer EXCEPTION block. Handled by handStmtsY.
Custom Handling Example:
The following example is a modified shortest path query. It looks for all paths from a source to a target in a computer network. It uses breadth-first search and stops at depth N when it has found at least one path at depth N, or it has searched the entire graph. There are three conditions which will cause it to RAISE an exception and abort the search:
Seeing an edge with a negative connection speed (because the graph has bad data).
Seeing an edge with a very slow connection speed (again because the graph has bad data).
If no path was found in the graph (the search is already over, but we skip printing results).
Note that cases 1 and 2 do NOT mean that a negative or slow speed edge is actually on a shortest path, only that the query noticed a bad edge during its search. Also, because we cannot RAISE within the SELECT block, we use a workaround: set an integer variable with an error code. Immediately after the SELECT block, test the integer variable and RAISE exceptions as needed.
As the data in Appendix D show:
Any search passing through c1 will see negative edges.
Any search passing through c12 will see negative and slow edges.
Any search passing through c14 will see negative edges.
The results for 5 cases are shown: 1 valid search plus each of the 3 exception conditions. The 5th case is the same as the 4th, but exception handling is not enabled.
The flowchart below summarizes all the cases for triggering and handling exceptions, both user-defined and built-in.