处理错误
如果 UDx 遇到无法恢复的错误,它应报告错误并终止。如何做到这一点取决于编写时所用的语言:
-
C++:考虑使用发送消息中所述的 API,它比本主题中描述的错误处理更具表现力。或者,您可以使用
vt_report_error
宏来报告错误并退出。该宏使用以下两个参数:错误号和错误消息字符串。错误号和消息都会显示在 Vertica 向用户报告的错误中。错误号并不由 Vertica 定义。您可以随意使用任何值。 -
Java:实例化并引发
UdfException
,它会将数字代码和消息字符串报告给用户。 -
Python:考虑使用发送消息中所述的 API,它比本主题中描述的错误处理更具表现力。或者,引发内置到 Python 语言中的异常;SDK 不包含特定于 UDx 的异常。
-
R:使用
stop
来停止执行并显示一条消息。
异常或停止会导致包含函数调用的事务被回滚。
以下示例演示了错误处理:
以下函数会将两个整数相除。为了防止除数为零,它会测试第二个参数并在为零时设为失败:
class Div2ints : public ScalarFunction
{
public:
virtual void processBlock(ServerInterface &srvInterface,
BlockReader &arg_reader,
BlockWriter &res_writer)
{
// While we have inputs to process
do
{
const vint a = arg_reader.getIntRef(0);
const vint b = arg_reader.getIntRef(1);
if (b == 0)
{
vt_report_error(1,"Attempted divide by zero");
}
res_writer.setInt(a/b);
res_writer.next();
}
while (arg_reader.next());
}
};
加载和调用函数演示了用户所看到的错误。隔离和非隔离模式使用不同的错误号。
=> CREATE LIBRARY Div2IntsLib AS '/home/dbadmin/Div2ints.so';
CREATE LIBRARY
=> CREATE FUNCTION div2ints AS LANGUAGE 'C++' NAME 'Div2intsInfo' LIBRARY Div2IntsLib;
CREATE FUNCTION
=> SELECT div2ints(25, 5);
div2ints
----------
5
(1 row)
=> SELECT * FROM MyTable;
a | b
----+---
12 | 6
7 | 0
12 | 2
18 | 9
(4 rows)
=> SELECT * FROM MyTable WHERE div2ints(a, b) > 2;
ERROR 3399: Error in calling processBlock() for User Defined Scalar Function
div2ints at Div2ints.cpp:21, error code: 1, message: Attempted divide by zero
在以下示例中,如果任一实参为 NULL,则 processBlock()
方法将引发异常:
@Override
public void processBlock(ServerInterface srvInterface,
BlockReader argReader,
BlockWriter resWriter)
throws UdfException, DestroyInvocation
{
do {
// Test for NULL value. Throw exception if one occurs.
if (argReader.isLongNull(0) || argReader.isLongNull(1) ) {
// No nulls allowed. Throw exception
throw new UdfException(1234, "Cannot add a NULL value");
}
当 UDx 引发异常时,正在运行 UDx 的从属进程会将错误报告回 Vertica 并退出。Vertica 将向用户显示包含于异常中的错误消息和堆栈跟踪:
=> SELECT add2ints(2, NULL);
ERROR 3399: Failure in UDx RPC call InvokeProcessBlock(): Error in User Defined Object [add2ints], error code: 1234
com.vertica.sdk.UdfException: Cannot add a NULL value
at com.example.Add2intsFactory$Add2ints.processBlock(Add2intsFactory.java:37)
at com.vertica.udxfence.UDxExecContext.processBlock(UDxExecContext.java:700)
at com.vertica.udxfence.UDxExecContext.run(UDxExecContext.java:173)
at java.lang.Thread.run(Thread.java:662)
在此示例中,如果其中一个实参小于 100,则 Python UDx 会引发错误:
while(True):
# Example of error checking best practices.
product_id = block_reader.getInt(2)
if product_id < 100:
raise ValueError("Invalid Product ID")
错误会生成如下消息:
=> SELECT add2ints(prod_cost, sale_price, product_id) FROM bunch_of_numbers;
ERROR 3399: Failure in UDx RPC call InvokeProcessBlock(): Error calling processBlock() in User Defined Object [add2ints]
at [/udx/PythonInterface.cpp:168], error code: 0,
message: Error [/udx/PythonInterface.cpp:385] function ['call_method']
(Python error type [<class 'ValueError'>])
Traceback (most recent call last):
File "/home/dbadmin/py_db/v_py_db_node0001_catalog/Libraries/02fc4af0ace6f91eefa74baecf3ef76000a0000000004fc4/pylib_02fc4af0ace6f91eefa74baecf3ef76000a0000000004fc4.py",
line 13, in processBlock
raise ValueError("Invalid Product ID")
ValueError: Invalid Product ID
在此示例中,如果数据帧的第三列与指定的产品 ID 不匹配,则 R UDx 会引发错误:
Calculate_Cost_w_Tax <- function(input.data.frame) {
# Must match the Product ID 11444
if ( !is.numeric(input.data.frame[, 3]) == 11444 ) {
stop("Invalid Product ID!")
} else {
cost_w_tax <- data.frame(input.data.frame[, 1] * input.data.frame[, 2])
}
return(cost_w_tax)
}
Calculate_Cost_w_TaxFactory <- function() {
list(name=Calculate_Cost_w_Tax,
udxtype=c("scalar"),
intype=c("float","float", "float"),
outtype=c("float"))
}
错误会生成如下消息:
=> SELECT Calculate_Cost_w_Tax(item_price, tax_rate, prod_id) FROM Inventory_Sales_Data;
vsql:sql_test_multiply.sql:21: ERROR 3399: Failure in UDx RPC call InvokeProcessBlock():
Error calling processBlock() in User Defined Object [mul] at
[/udx/RInterface.cpp:1308],
error code: 0, message: Exception in processBlock :Invalid Product ID!
要报告有关错误的其他诊断信息,您可以在引发异常之前将消息写入日志文件(请参阅日志)。
您的 UDx 不得使用其未引发的异常。拦截服务器异常可能会导致数据库不稳定。