# 36.8.错误处理

36.8.1. 设置回调

36.8.2. sqlca

36.8.3.SQLSTATE与。SQLCODE

本节介绍如何在嵌入式SQL程序中处理异常情况和警告。这里有两个非专用设施。

  • 回调可以配置为使用无论何时命令
  • 有关错误或警告的详细信息可从sqlca变量

# 36.8.1.设置回调

捕捉错误和警告的一个简单方法是设置在特定情况发生时执行的特定操作。一般来说:

EXEC SQL WHENEVER condition action;

*条件*可以是以下内容之一:

SQLERROR

每当SQL语句执行过程中出现错误时,就会调用指定的操作。

SQLWARNING

每当SQL语句执行期间出现警告时,就会调用指定的操作。

找不到

每当SQL语句检索或影响零行时,就会调用指定的操作。(这种情况不是错误,但您可能有兴趣专门处理它。)

*行动*可以是以下内容之一:

持续

这实际上意味着该条件被忽略。这是默认设置。

后藤*标签*
去*标签*

跳转到指定的标签(使用C后藤声明)。

SQLPRINT

将消息打印到标准错误。这对于简单的程序或原型设计过程很有用。无法配置消息的详细信息。

停止

呼叫出口(1),将终止该程序。

一定要休息

执行C语句打破。这只能在循环或循环中使用转换声明。

继续

执行C语句持续。这只能在循环语句中使用。如果执行,将导致控制流返回到循环的顶部。

打电话*名称* (*阿格斯*)
做*名称* (*阿格斯*)

使用指定的参数调用指定的C函数。(这个用法与呼叫在正常的PostgreSQL语法中。)

SQL标准只提供了这些操作持续后藤(及).

下面是一个您可能希望在简单程序中使用的示例。当出现警告时,它会打印一条简单的消息,当出现错误时,它会中止程序:

EXEC SQL WHENEVER SQLWARNING SQLPRINT;
EXEC SQL WHENEVER SQLERROR STOP;

声明EXEC SQL是SQL预处理器的指令,而不是C语句。它设置的错误或警告操作适用于出现在处理程序设置点下方的所有嵌入式SQL语句,除非在第一个操作之间为相同条件设置了不同的操作EXEC SQL以及导致这种情况的SQL语句,而不管C程序中的控制流如何。因此,以下两个C程序节选都不会产生预期效果:

/*
 * WRONG
 */
int main(int argc, char *argv[])
{
    ...
    if (verbose) {
        EXEC SQL WHENEVER SQLWARNING SQLPRINT;
    }
    ...
    EXEC SQL SELECT ...;
    ...
}
/*
 * WRONG
 */
int main(int argc, char *argv[])
{
    ...
    set_error_handler();
    ...
    EXEC SQL SELECT ...;
    ...
}

static void set_error_handler(void)
{
    EXEC SQL WHENEVER SQLERROR STOP;
}

# 36.8.2.sqlca

为了实现更强大的错误处理功能,嵌入式SQL接口提供了一个名为sqlca(SQL通信区域)具有以下结构:

struct
{
    char sqlcaid[8];
    long sqlabc;
    long sqlcode;
    struct
    {
        int sqlerrml;
        char sqlerrmc[SQLERRMC_LEN];
    } sqlerrm;
    char sqlerrp[8];
    long sqlerrd[6];
    char sqlwarn[8];
    char sqlstate[5];
} sqlca;

(在多线程程序中,每个线程都会自动获取自己的sqlca.这与标准C全局变量的处理类似呃不.)

sqlca包括警告和错误。如果在语句执行过程中出现多个警告或错误,则sqlca将只包含关于最后一个的信息。

如果最后一条SQL语句中没有出现错误,sqlca。sqlcode将是0和sqlca。sqlstate"00000".如果出现警告或错误,则sqlca。sqlcode将是消极的sqlca。sqlstate将不同于"00000".肯定的sqlca。sqlcode指示无害条件,例如上次查询返回的行数为零。sqlcodesqlstate是两种不同的错误代码方案;详情如下。

如果最后一条SQL语句成功,则sqlca。sqlerrd[1]包含已处理行的OID(如果适用),以及sqlca。sqlerrd[2]包含已处理或返回的行数(如果适用于该命令)。

如果出现错误或警告,sqlca。sqlerrm。sqlerrmc将包含一个描述错误的字符串。田野sqlca。sqlerrm。sqlerrml包含存储在中的错误消息的长度sqlca。sqlerrm。sqlerrmc(结果)斯特伦(),对C程序员来说不是很有趣)。请注意,有些消息太长,无法放入固定大小sqlerrmc大堆它们将被截断。

如果出现警告,sqlca。sqlwarn[2]即将W(在所有其他情况下,它设置为与W)如果sqlca。sqlwarn[1]即将W,然后在将值存储在宿主变量中时将其截断。sqlca。sqlwarn[0]即将W如果任何其他元素被设置为指示警告。

田野sqlcaid, sqlabc, sqlerrp,以及sqlerrdsqlwarn目前没有有用的信息。

结构sqlca未在SQL标准中定义,但在其他几个SQL数据库系统中实现。这些定义在核心上是相似的,但是如果你想编写可移植的应用程序,那么你应该仔细研究不同的实现。

下面是一个结合使用无论何时sqlca,打印出sqlca当错误发生时。在安装更“用户友好”的错误处理程序之前,这可能对调试或原型化应用程序很有用。

EXEC SQL WHENEVER SQLERROR CALL print_sqlca();

void
print_sqlca()
{
    fprintf(stderr, "==== sqlca ====\n");
    fprintf(stderr, "sqlcode: %ld\n", sqlca.sqlcode);
    fprintf(stderr, "sqlerrm.sqlerrml: %d\n", sqlca.sqlerrm.sqlerrml);
    fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc);
    fprintf(stderr, "sqlerrd: %ld %ld %ld %ld %ld %ld\n", sqlca.sqlerrd[0],sqlca.sqlerrd[1],sqlca.sqlerrd[2],
                                                          sqlca.sqlerrd[3],sqlca.sqlerrd[4],sqlca.sqlerrd[5]);
    fprintf(stderr, "sqlwarn: %d %d %d %d %d %d %d %d\n", sqlca.sqlwarn[0], sqlca.sqlwarn[1], sqlca.sqlwarn[2],
                                                          sqlca.sqlwarn[3], sqlca.sqlwarn[4], sqlca.sqlwarn[5],
                                                          sqlca.sqlwarn[6], sqlca.sqlwarn[7]);
    fprintf(stderr, "sqlstate: %5s\n", sqlca.sqlstate);
    fprintf(stderr, "===============\n");
}

结果可能如下所示(此处是由于表名拼写错误导致的错误):

==== sqlca ====
sqlcode: -400
sqlerrm.sqlerrml: 49
sqlerrm.sqlerrmc: relation "pg_databasep" does not exist on line 38
sqlerrd: 0 0 0 0 0 0
sqlwarn: 0 0 0 0 0 0 0 0
sqlstate: 42P01
===============

# 36.8.3. SQLSTATE与。SQLCODE

田野sqlca。sqlstatesqlca。sqlcode有两种不同的方案提供错误代码。两者都是从SQL标准派生的,但是SQLCODE在标准的SQL-92版本中被标记为已弃用,并在以后的版本中被删除。因此,强烈建议使用新的应用程序SQLSTATE.

SQLSTATE是一个五字符数组。这五个字符包含数字或大写字母,代表各种错误和警告条件的代码。SQLSTATE具有层次结构:前两个字符表示条件的一般类,后三个字符表示一般条件的子类。成功状态由代码指示00000这个SQLSTATE代码大部分是在SQL标准中定义的。PostgreSQL server本机支持SQLSTATE错误代码;因此,通过在所有应用程序中使用此错误代码方案,可以实现高度一致性。有关更多信息,请参阅附录A.

SQLCODE,不推荐使用的错误代码方案,是一个简单的整数。值0表示成功,正值表示附加信息成功,负值表示错误。SQL标准只定义正值+100,这表示上一个命令返回或影响了零行,而没有特定的负值。因此,该方案只能实现较差的可移植性,并且没有分层代码分配。过去,PostgreSQL的嵌入式SQL处理器分配了一些特定的SQLCODE下面列出了它们的数值和符号名。请记住,这些都不能移植到其他SQL实现中。简化将应用程序移植到SQLSTATE方案,对应的SQLSTATE也被列出。然而,这两个方案之间没有一对一或一对多映射(实际上是多对多映射),因此您应该咨询全球SQLSTATE登录附录A在每种情况下。

这些是指定的SQLCODE价值观:

0 (ECPG_无错误)

表示没有错误。(SQLSTATE 00000)

100 (未找到ECPG_)

这是一种无害的情况,表明最后一个命令检索或处理了零行,或者您位于光标的末尾。(SQLSTATE 02000)

在循环中处理光标时,可以使用以下代码来检测何时中止循环,如下所示:

while (1)
{
    EXEC SQL FETCH ... ;
    if (sqlca.sqlcode == ECPG_NOT_FOUND)
        break;
}

但是无论何时找不到,都要打破有效地在内部实现了这一点,所以明确地写出来通常没有好处。

-12 (ECPG内存不足)

表示虚拟内存已耗尽。数值定义为-埃诺姆(SQLSTATE YE001)

-200 (ECPG_不支持)

指示预处理器生成了库不知道的内容。也许您正在运行预处理器和库的不兼容版本。(SQLSTATE YE002)

-201 (ECPG_太多_参数)

这意味着命令指定的主机变量比命令预期的多。(SQLSTATE 07001或07002)

-202 (ECPG_参数太少)

这意味着命令指定的主机变量比命令预期的少。(SQLSTATE 07001或07002)

-203 (ECPG太多比赛)

这意味着查询返回了多行,但语句只准备存储一个结果行(例如,因为指定的变量不是数组)。(SQLSTATE 21000)

-204 (ECPG_INT_格式)

主机变量的类型为智力数据库中的数据是另一种类型,包含的值不能解释为智力.图书馆使用strtol()为了这次转换。(SQLSTATE 42804)

-205 (ECPG_UINT_格式)

主机变量的类型为无符号整型数据库中的数据是另一种类型,包含的值不能解释为无符号整型.图书馆使用斯特图尔()为了这次转换。(SQLSTATE 42804)

-206 (ECPG_浮点格式)

主机变量的类型为浮动数据库中的数据属于另一种类型,并且包含一个不能解释为浮动.图书馆使用斯特罗德()为了这次转换。(SQLSTATE 42804)

-207 (ECPG_数字_格式)

主机变量的类型为数字的数据库中的数据是另一种类型,包含一个不能解释为数字的价值(SQLSTATE 42804)

-208 (ECPG_间隔_格式)

主机变量的类型为间隔数据库中的数据属于另一种类型,并且包含一个不能解释为间隔价值(SQLSTATE 42804)

-209 (ECPG_日期_格式)

主机变量的类型为日期数据库中的数据是另一种类型,包含一个不能解释为日期价值(SQLSTATE 42804)

-210 (ECPG_时间戳_格式)

主机变量的类型为时间戳数据库中的数据是另一种类型,包含一个不能解释为时间戳价值(SQLSTATE 42804)

-211 (ECPG_CONVERT_BOOL)

这意味着主机变量的类型为布尔数据库中的数据既不是“不”也没有“f”(SQLSTATE 42804)

-212 (ECPG_空)

发送到PostgreSQL server的语句为空。(这通常不会发生在嵌入式SQL程序中,因此可能指向内部错误。)(SQLSTATE YE002)

-213 (ECPG_缺失_指示器)

返回了null值,但未提供null指示符变量。(SQLSTATE 22002)

-214 (ECPG_无_阵列)

在需要数组的地方使用了普通变量。(SQLSTATE 42804)

-215 (ECPG_数据_非_数组)

数据库在需要数组值的地方返回了一个普通变量。(SQLSTATE 42804)

-216 (ECPG_阵列_插入)

无法将该值插入数组。(SQLSTATE 42804)

-220 (ECPG_NO_CONN)

程序试图访问一个不存在的连接。(SQLSTATE 08003)

-221 (ECPG_NOT_CONN)

程序试图访问一个确实存在但尚未打开的连接。(这是一个内部错误。)(SQLSTATE YE002)

-230 (ECPG_无效_STMT)

您试图使用的声明尚未准备好。(SQLSTATE 26000)

-239 (ECPG_INFORMIX_复制_密钥)

重复密钥错误,违反唯一约束(Informix兼容模式)。(SQLSTATE 23505)

-240 (ECPG_未知_描述符)

找不到指定的描述符。您试图使用的声明尚未准备好。(SQLSTATE 33000)

-241 (ECPG_无效_描述符_索引)

指定的描述符索引超出范围。(SQLSTATE 07009)

-242 (ECPG_未知_描述符_项目)

请求的描述符项无效。(这是一个内部错误。)(SQLSTATE YE002)

-243 (ECPG_VAR_NOT_NUMERIC)

在执行动态语句期间,数据库返回一个数值,而宿主变量不是数值。(SQLSTATE 07006)

-244 (ECPG_VAR_NOT_CHAR)

在执行动态语句期间,数据库返回一个非数值,而宿主变量是数值。(SQLSTATE 07006)

-284 (ECPG_INFORMIX_SUBSELECT_NOT_ONE)

子查询的结果不是单行(Informix兼容模式)。(SQLSTATE 21000)

-400 (ECPG_PGSQL)

PostgreSQL server导致的某些错误。该消息包含来自PostgreSQL server的错误消息。

-401 (ECPG_TRANS)

PostgreSQL server表示我们无法启动、提交或回滚事务。(SQLSTATE 08007)

-402 (ECPG_连接)

与数据库的连接尝试未成功。(SQLSTATE 08001)

-403 (ECPG_重复_键)

重复密钥错误,违反唯一约束。(SQLSTATE 23505)

-404 (ECPG_SUBSELECT_NOT_ONE)

子查询的结果不是单行。(SQLSTATE 21000)

-602 (ECPG_警告_未知_门户)

指定的游标名称无效。(SQLSTATE 34000)

-603 (ECPG_警告_在_事务中)

交易正在进行中。(SQLSTATE 25001)

-604 (ECPG_警告_无交易)

没有活动的(正在进行的)事务。(SQLSTATE 25P01)

-605 (ECPG_警告_门户_存在)

已指定现有的游标名称。(SQLSTATE 42P03)