PostgreSQL 显式非空违规检查发生在检查约束之前?
PostgreSQL explicit not-null violation check happens before the check constraint?
我正在尝试使用命名约束,以便能够从错误消息中判断出确切发生了什么以及发生在何处。例如,当我在 table "bar" 中的列 "foo" 上设置非空约束,然后尝试在其中添加具有空值的行时,我得到:
ERROR: null value in column "foo" violates not-null constraint
我没有得到 table 的名称,我无法使用此错误消息提取任何有用的信息。另一方面,当我删除 not-null 约束并添加一个 check (foo is not null)
约束(可以命名为 bar__foo__nn
之类的东西时,我立即得到 table 名称,即列名称,以及类似于非空违规的错误代码 "nn"。我什至可以解析此约束名称以提取所需的信息,以便在我的应用程序中进一步记录错误。
根据我的阅读,显式非空约束应该更有效并且允许更多优化。此外,主键必须具有明确的非空约束集。所以我尝试同时使用两者,但结果是,我只收到上面的 "default" not-null violation 错误,而没有提到我的 "custom" 命名约束违规。
是否有任何方法可以使用显式非空约束并且仍然有一些方便的方法来"customize"潜在的非空违规错误?
编辑
我没有提到,我使用 psycopg2 Python 访问数据库。我不想让这个 psycopg2 变得特定,因为我也在其他环境中使用 postgresql,并且对它在 postgresql 中的工作方式的一般概述会很有用。例如,如何在存储的 procedure/function 中提取所需的信息(table 名称和列名称)以在 postgresql 代码中(在异常子句中)以某种方式对其进行序列化,以便连接到数据库的应用程序(无论是 Python 使用 psycopg2 还是其他任何东西)在调用存储过程时都会按照我希望的方式看到错误。
您标记了 logging,所以我假设您对 PostgreSQL 日志文件感兴趣。
除非您将 log_min_error_statement
设置为 fatal
或更高,否则该语句将始终包含在错误消息中:
2020-04-02 14:40:28.253 CEST [3414] ERROR: null value in column "a1" violates not-null constraint
2020-04-02 14:40:28.253 CEST [3414] DETAIL: Failing row contains (12, null).
2020-04-02 14:40:28.253 CEST [3414] STATEMENT: INSERT INTO a VALUES (12, NULL);
提示:如果使用log_destination = csvlog
,日志文件更容易解析。
如果您对发送到客户端的消息感兴趣,这取决于您用来访问 PostgreSQL 的客户端或 API。服务器将信息与错误消息一起发送。
这是 psql
客户端的工作方式:
test=> \set VERBOSITY verbose
test=> INSERT INTO a VALUES (12, NULL);
ERROR: 23502: null value in column "a1" violates not-null constraint
DETAIL: Failing row contains (12, null).
SCHEMA NAME: laurenz
TABLE NAME: a
COLUMN NAME: a1
LOCATION: ExecConstraints, execMain.c:1960
既然您对Python感兴趣,这里有一个运行相同语句的示例程序:
#!/usr/bin/python3
from psycopg2 import connect, Error
from psycopg2.extensions import quote_ident
conn = connect("dbname=test user=laurenz")
cur = conn.cursor()
try:
cur.execute("INSERT INTO a VALUES (12, NULL)")
except Error as e:
print("Error: {}".format(e.diag.message_primary))
print("Detail: {}".format(e.diag.message_detail))
print("SQLSTATE: {}".format(e.diag.sqlstate))
print("Table: {}.{}".format(
quote_ident(e.diag.schema_name, cur),
quote_ident(e.diag.table_name, cur)
))
conn.commit()
cur.close()
conn.close()
结果是:
Error: null value in column "a1" violates not-null constraint
Detail: Failing row contains (12, null).
SQLSTATE: 23502
Table: "laurenz"."a"
我正在尝试使用命名约束,以便能够从错误消息中判断出确切发生了什么以及发生在何处。例如,当我在 table "bar" 中的列 "foo" 上设置非空约束,然后尝试在其中添加具有空值的行时,我得到:
ERROR: null value in column "foo" violates not-null constraint
我没有得到 table 的名称,我无法使用此错误消息提取任何有用的信息。另一方面,当我删除 not-null 约束并添加一个 check (foo is not null)
约束(可以命名为 bar__foo__nn
之类的东西时,我立即得到 table 名称,即列名称,以及类似于非空违规的错误代码 "nn"。我什至可以解析此约束名称以提取所需的信息,以便在我的应用程序中进一步记录错误。
根据我的阅读,显式非空约束应该更有效并且允许更多优化。此外,主键必须具有明确的非空约束集。所以我尝试同时使用两者,但结果是,我只收到上面的 "default" not-null violation 错误,而没有提到我的 "custom" 命名约束违规。
是否有任何方法可以使用显式非空约束并且仍然有一些方便的方法来"customize"潜在的非空违规错误?
编辑
我没有提到,我使用 psycopg2 Python 访问数据库。我不想让这个 psycopg2 变得特定,因为我也在其他环境中使用 postgresql,并且对它在 postgresql 中的工作方式的一般概述会很有用。例如,如何在存储的 procedure/function 中提取所需的信息(table 名称和列名称)以在 postgresql 代码中(在异常子句中)以某种方式对其进行序列化,以便连接到数据库的应用程序(无论是 Python 使用 psycopg2 还是其他任何东西)在调用存储过程时都会按照我希望的方式看到错误。
您标记了 logging,所以我假设您对 PostgreSQL 日志文件感兴趣。
除非您将 log_min_error_statement
设置为 fatal
或更高,否则该语句将始终包含在错误消息中:
2020-04-02 14:40:28.253 CEST [3414] ERROR: null value in column "a1" violates not-null constraint
2020-04-02 14:40:28.253 CEST [3414] DETAIL: Failing row contains (12, null).
2020-04-02 14:40:28.253 CEST [3414] STATEMENT: INSERT INTO a VALUES (12, NULL);
提示:如果使用log_destination = csvlog
,日志文件更容易解析。
如果您对发送到客户端的消息感兴趣,这取决于您用来访问 PostgreSQL 的客户端或 API。服务器将信息与错误消息一起发送。
这是 psql
客户端的工作方式:
test=> \set VERBOSITY verbose
test=> INSERT INTO a VALUES (12, NULL);
ERROR: 23502: null value in column "a1" violates not-null constraint
DETAIL: Failing row contains (12, null).
SCHEMA NAME: laurenz
TABLE NAME: a
COLUMN NAME: a1
LOCATION: ExecConstraints, execMain.c:1960
既然您对Python感兴趣,这里有一个运行相同语句的示例程序:
#!/usr/bin/python3
from psycopg2 import connect, Error
from psycopg2.extensions import quote_ident
conn = connect("dbname=test user=laurenz")
cur = conn.cursor()
try:
cur.execute("INSERT INTO a VALUES (12, NULL)")
except Error as e:
print("Error: {}".format(e.diag.message_primary))
print("Detail: {}".format(e.diag.message_detail))
print("SQLSTATE: {}".format(e.diag.sqlstate))
print("Table: {}.{}".format(
quote_ident(e.diag.schema_name, cur),
quote_ident(e.diag.table_name, cur)
))
conn.commit()
cur.close()
conn.close()
结果是:
Error: null value in column "a1" violates not-null constraint
Detail: Failing row contains (12, null).
SQLSTATE: 23502
Table: "laurenz"."a"