实参和返回值

对于除加载 (UDL) 之外的所有 UDx 类型,工厂类会声明关联函数的实参和返回类型。为此,工厂有两种方法:

  • getPrototype() (必需):声明输入和输出类型

  • getReturnType() (有时必需):声明返回类型,包括长度和精度(适用时)

getPrototype() 方法会收到两个 ColumnTypes 参数,一个用于输入,一个用于输出。C++ 示例:字符串分词器 中的工厂接受单个输入字符串并返回字符串:

virtual void getPrototype(ServerInterface &srvInterface,
                          ColumnTypes &argTypes, ColumnTypes &returnType)
{
  argTypes.addVarchar();
  returnType.addVarchar();
}

ColumnTypes 类为每种受支持的类型提供“add”方法,例如 addVarchar()。此类支持具有 addArrayType()addRowType() 方法的复杂类型;请参阅作为实参的复杂类型。如果函数为多态函数,则可以改为调用 addAny()。然后,您负责验证输入和输出。有关实施多态 UDx 的详细信息,请参阅创建多态 UDx

getReturnType() 方法会计算返回值的最大长度。如果 Udx 返回特定大小的列(一种长度可变的返回数据类型,例如 VARCHAR)、需要精度的值或多个值,则需要实施此工厂方法。(某些 UDx 类型要求您实施该方法。)

输入是 SizedColumnTypes,其中包含输入实参类型及其长度。根据输入类型,请将以下值之一添加到输出类型:

  • CHAR、(LONG) VARCHAR、BINARY 和 (LONG) VARBINARY:返回最大长度。

  • NUMERIC 类型:指定精度和小数位数。

  • TIME 和 TIMESTAMP 值(含或不含时区):指定精度。

  • INTERVAL YEAR TO MONTH:指定范围。

  • INTERVAL DAY TO SECOND:指定精度和范围。

  • ARRAY:指定数组元素的最大数量。

使用字符串分词器时,输出为 VARCHAR 且函数可确定其最大长度:

// Tell Vertica what our return string length will be, given the input
// string length
virtual void getReturnType(ServerInterface &srvInterface,
                           const SizedColumnTypes &inputTypes,
                           SizedColumnTypes &outputTypes)
{
  // Error out if we're called with anything but 1 argument
  if (inputTypes.getColumnCount() != 1)
    vt_report_error(0, "Function only accepts 1 argument, but %zu provided", inputTypes.getColumnCount());

  int input_len = inputTypes.getColumnType(0).getStringLength();

  // Our output size will never be more than the input size
  outputTypes.addVarchar(input_len, "words");
}

作为实参的复杂类型和返回值

ColumnTypes 类支持 ARRAYROW 类型。数组包含各种元素,而行包含各种字段,两者均包含您需要描述的类型。要使用复杂类型,您需要为数组或行构建 ColumnTypes 对象,然后将其添加到表示函数输入和输出的 ColumnTypes 对象中。

在以下示例中,转换函数的输入是一个订单数组(即多个行),输出是各个行及其在数组中的位置。订单包含送货地址 (VARCHAR) 和产品 ID 数组 (INT)。

工厂的 getPrototype() 方法会先为数组和行元素创建 ColumnTypes,然后使用它们来调用 addArrayType()addRowType()


void getPrototype(ServerInterface &srv,
            ColumnTypes &argTypes,
            ColumnTypes &retTypes)
    {
        // item ID (int), to be used in an array
        ColumnTypes itemIdProto;
        itemIdProto.addInt();

        // row: order = address (varchar) + array of previously-created item IDs
        ColumnTypes orderProto;
        orderProto.addVarchar();                  /* address */
        orderProto.addArrayType(itemIdProto);     /* array of item ID */

        /* argument (input) is array of orders */
        argTypes.addArrayType(orderProto);

        /* return values: index in the array, order */
        retTypes.addInt();                        /* index of element */
        retTypes.addRowType(orderProto);          /* element return type */
    }

实参包括特定大小的类型 (VARCHAR)。getReturnType() 方法会使用类似的方法,从而使用 Fields 类在订单中构建两个字段。


void getReturnType(ServerInterface &srv,
            const SizedColumnTypes &argTypes,
            SizedColumnTypes &retTypes)
    {
        Fields itemIdElementFields;
        itemIdElementFields.addInt("item_id");

        Fields orderFields;
        orderFields.addVarchar(32, "address");
        orderFields.addArrayType(itemIdElementFields[0], "item_id");
        // optional third arg: max length, default unbounded

        /* declare return type */
        retTypes.addInt("index");
        static_cast<Fields &>(retTypes).addRowType(orderFields, "element");

        /* NOTE: presumably we have verified that the arguments match the prototype, so really we could just do this: */
        retTypes.addInt("index");
        retTypes.addArg(argTypes.getColumnType(0).getElementType(), "element");
    }

要在 UDx 处理方法中访问复杂类型,请使用 ArrayReaderArrayWriterStructReaderStructWriter 类。

请参阅“ C++ 示例:使用复杂类型”,了解使用数组的多态函数。

工厂的 getPrototype() 方法会先使用 makeType()addType() 方法,为行及其元素创建和构造 ColumnTypes。然后,该方法会调用 addType() 方法,以将这些构造的 ColumnTypes 添加到 arg_typesreturn_type 对象:


def getPrototype(self, srv_interface, arg_types, return_type):
    # item ID (int), to be used in an array
    itemIdProto = vertica_sdk.ColumnTypes.makeInt()

    # row (order): address (varchar) + array of previously-created item IDs
    orderProtoFields = vertica_sdk.ColumnTypes.makeEmpty()
    orderProtoFields.addVarchar()  # address
    orderProtoFields.addArrayType(itemIdProto) # array of item ID
    orderProto = vertica_sdk.ColumnTypes.makeRowType(orderProtoFields)

    # argument (input): array of orders
    arg_types.addArrayType(orderProto)

    # return values: index in the array, order
    return_type.addInt();                        # index of element
    return_type.addRowType(orderProto);          # element return type

工厂的 getReturnType() 方法会使用 makeInt()makeEmpty() 方法来创建 SizedColumnTypes,然后使用 addVarchar()addArrayType() 方法构建两个行字段。请注意,addArrayType() 方法会将数组元素的最大数量指定为 1024。 getReturnType() 然后,将这些构造的 SizedColumnTypes 添加到表示返回类型的对象中。


def getReturnType(self, srv_interface, arg_types, return_type):
    itemsIdElementField = vertica_sdk.SizedColumnTypes.makeInt("item_id")

    orderFields = vertica_sdk.SizedColumnTypes.makeEmpty()
    orderFields.addVarchar(32, "address")
    orderFields.addArrayType(itemIdElementField, 1024, "item_ids")

    # declare return type
    return_type.addInt("index")
    return_type.addRowType(orderFields, "element")

    '''
    NOTE: presumably we have verified that the arguments match the prototype, so really we could just do this:
    return_type.addInt("index")
    return_type.addArrayType(argTypes.getColumnType(0).getElementType(), "element")
    '''

要在 UDx 处理方法中访问复杂类型,请使用 ArrayReaderArrayWriterRowReaderRowWriter 类。有关详细信息,请参阅Python SDK

有关使用复杂类型的标量函数,请参阅Python 示例:矩阵乘法

处理不同数量和类型的实参

使用过载或多态性,您可以创建处理多个签名的 UDx,甚至还可以创建接受由用户提供给它们的所有实参的 UDx。

您可以使 UDx 过载,方法是将同一个 SQL 函数名称分配给多个工厂类,每个工厂类会定义一个唯一的函数签名。当用户在查询中使用该函数名称时,Vertica 会尝试将函数调用的签名与工厂的 getPrototype() 方法所声明的签名进行匹配。如果 UDx 需要接受几个不同签名(例如,接受两个必需参数和一个可选参数),则这是可用的最佳技术。

或者,您可以编写一个多态函数,以写入一个工厂方法而非多个工厂方法,并声明它接受任何数量和类型的实参。当用户在查询中使用函数名称时,Vertica 会调用您的函数,而不考虑签名。为换取这种灵活性,UDx 的主要“process”方法必须确定它是否可以接受各种实参并在无法接受时发出错误。

所有 UDx 类型都可以使用多态输入。转换函数和分析函数也可以使用多态输出。这意味着 getPrototype() 可以声明返回类型“any”并在运行时设置实际返回类型。例如,在输入中返回最大值的函数将返回与输入类型相同的类型。