异常处理语句

本章介绍GSQL语言如何对程序异常进行响应,以及如何让用户自定义异常处理的方式。异常是指运行时错误。 GSQL语言同时支持内置系统异常和用户自定义异常。 内置异常包括GSQL语言异常(例如超出范围的值,错误的数据类型和非法操作),以及其他TigerGraph组件或操作系统中出现的错误。

GSQL 还支持用户自定义异常响应,也称为异常处理。 本节介绍用户自定义异常的方法:

异常响应的默认方式

在执行查询期间发生异常时,默认响应如下:

  • 查询不再执行任何语句; 它会退出。

  • 如果使用的是RUN QUERY命令执行查询,则将显示错误消息。

  • 如果是通过调用GET /query REST++ 接口的方式运行查询,则输出将是一个简单的JSON对象。 一些错误拥有错误代码(code)字段,另一些错误则没有改字段:

下面的示例演示了两个常见的错误:数据类型错误和分母为零错误。 首先我们定义一个简单的查询,然后用查询的输入的参数除以100.0。

然后我们测试三个运算:

  1. 一个有效的输入 (例如 n1 = 7)

  2. 输入错误的数据类型 (例如n1 = "A")

  3. 除以零 (例如n1 = 0)

首先,我们使用GSQL接口进行测试。 当查询运行且没有错误时,则输出一个JSON格式的值。 但如果存在异常,则仅显示错误消息。

将查询作为REST ++接口运行时情况略有不同。 输出的结果始终为JSON格式。

自定义异常的响应方式

如果某种异常常发生在特定的语句块中,则查询的编写人员可以指定该响应的具体内容。

以下语句类型可用于指定用户自定义异常的条件或响应。

  • 用EXCEPTION声明语句给用户自定义异常命名。

  • 用RAISE语句来表示一个用户自定义异常的发生。

  • 用TRY ... EXCEPTION语句在查询主体层语句中定义和应用一个用户自定义异常处理动作。无论在先前有或没有EXCEPTION和RAISE语句,该语句都能使用。

EXCEPTION 的声明

要使用用户自定义的异常,我们必须首先声明它。 异常声明语句声明用户自定义异常的类型,名称和id。 自定义异常的id号的errorCode必须大于40,000。 小于40,000的数字预留给系统内置异常。异常语句必须放在累加器声明语句之后,任何查询主体层语句之前。 一个查询中,用户可以声明多个异常类型。

RAISE 语句

RAISE语句用于判断用户自定义异常的发生。 示例中的exceptVarName必须是之前已经声明过的异常之一。 我们也可以选择是否需要自定义异常发生时报告的错误消息。 执行RAISE语句后,查询动作的工作流会发生变化。 如果RAISE语句不在TRY子句中,则查询以默认的响应结束,返回由该异常类型和该RAISE语句所定义的错误代码和错误消息。 如果RAISE语句在TRY子句中,则查询动作会跳转到TRY子句的EXCEPTION部分。

RAISE语句本身不包括定义异常的发生条件。 通常,用户会使用IF ... THEN语句实现该逻辑,并将RAISE语句放在THEN子句中。

下面的示例定义并检查了两种类型的异常:空输入集(40001)和无匹配边(40002)。 请记住,系统允许的最小代码是40001。

用TRY...EXCEPTION 语句自定义异常处理动作

TRY ... EXCEPTION语句允许用户自行定义异常处理动作,并将其添加到一个查询主体层语句中的某个语句块中。 TRY ...EXCEPTION语句可以嵌套在TRY语句块或EXCEPTION语句块中。

TRY ... EXCEPTION是一个嵌套两个语句块的复合句。第一个语句块(TRY)定义了自定义的错误处理动作,是一个查询主体层语句。第二个 (EXCEPTION)语句块包含了一系列的WHEN ... THEN子句。每个子句都指定一个异常类型,并表明了在发生该异常时需要采取的动作。用户还可以选择添加ELSE子句,用于处理所有其他的异常。下面的文字和流程图详细说明了TRY ...EXCEPTION的详细工作机制。

当TRY语句块中发生异常时,执行流程会跳过TRY的剩余部分并直接跳转到EXCEPTION语句块。这表明 GSQL正在寻求与该异常类型匹配的处理程序。在THEN或ELSE子句中执行完对应的处理后,执行过程将跳过EXCEPTION语句块的其余部分并继续执行END后面的语句。但是,如果没有匹配到合适的WHEN或ELSE处理程序,则向用户通告该异常,即在退出EXCEPTION之后,该查询仍然保持在RAISE的状态。如果该TRY ... EXCEPTION语句块是嵌套在另一个TRY语句块之内的,则该异常处理过程会在上层语句中重复执行,直到该异常最终被处理,或是所有的TRY ... EXCEPTION语句块都处理结束。

最后,如果未处理的异常不包含在一个TRY语句块内,则该查询将中止,输出该异常的默认处理响应。

情况 1: 如果在外层TRY语句中的条件1(cond1)为真,

  • 激活A选项(即RAISE A),并直接跳转到外层EXCEPTION 语句块.

由ELSE HandStmtsZ 语句处理.

情况2: 如果在内层TRY语句中的条件2(cond2)为真,

  • 激活A选项(即RAISE A),并直接跳转到内层的EXCEPTION 语句块.

由handStmtsX语句处理;

情况3: 如果在内层TRY语句中的条件3(cond3)为真,

  • 激活B选项(即RAISE B),并跳转到内部的EXCEPTION语句块。由于此时没有找到合适的处理方法,所以该异常被传播,并同时跳转到外层的EXCEPTION语句块,并在此处被handStmtsY语句处理。

自定义处理的示例:

以下示例是改进过的的最短路径查询。它用于查找计算机网络中从源到目标的所有路径。它使用广度优先算法,当在深度N处找到至少一条路径时,它便停在N处,否则就遍历整个图形。下列三个条件会引发它的异常并使搜索中止:

  1. 发现某条边的连接速度为负(由已损坏的数据导致)。

  2. 发现某条边的连接速度极慢(同样的,由已损坏的数据导致)。

  3. 图形中未找到符合要求的路径(搜索已经结束,但我们不打印结果)。

如附录D中的数据所示:

  • 任何通过了c1的搜索都将看到负边。

  • 任何通过了c12的搜索都会看到负边和慢边。

  • 任何通过了c14的搜索都会看到负边。

下面所示的5种情况的结果中:包含1个有效搜索和3种异常情况各一个。第5种与第4种情况相同,只不过第5种未启用异常处理。

异常处理的流程图

以下的流程图详述了触发和处理异常的所有情况,同时包含了用户自定义异常和系统内置异常: