1

我正在尝试使用 cgo 在 Go 中编写一个 MySQL UDF,其中我有一个基本的功能,但是有一些我无法弄清楚的点点滴滴,因为我不知道一些 C 变量是什么去。

这是我用 C 编写的一个示例,它强制将 MySQL 参数之一的类型设置为 int

my_bool unhex_sha3_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if (args->arg_count != 2) {
        strcpy(message, "`unhex_sha3`() requires 2 parameters: the message part, and the bits");
        return 1;
    }

    args->arg_type[1] = INT_RESULT;

    initid->maybe_null = 1; //can return null

    return 0;
}

这很好用,但后来我尝试用 Go 中的其他函数做同样/类似的事情,就像这样

//export get_url_param_init
func get_url_param_init(initid *C.UDF_INIT, args *C.UDF_ARGS, message *C.char) C.my_bool {
    if args.arg_count != 2 {
        message = C.CString("`get_url_param` require 2 parameters: the URL string and the param name")
        return 1
    }

    (*args.arg_type)[0] = C.STRING_RESULT
    (*args.arg_type)[1] = C.STRING_RESULT

    initid.maybe_null = 1

    return 0
}

有了这个构建错误

./main.go:24: 无效操作: (*args.arg_type)[0] (类型 uint32 不支持索引)

我不完全确定这意味着什么。这不应该是某种切片,而不是uint32?

这就是以某种方式将结构转储到某个地方(甚至在 Go 语法中作为超级加号)的某种方式非常有用的args地方,这样我就可以知道我正在使用什么。


好吧,我使用 spew 将变量内容转储到 init 函数内的 tmp 文件中(注释掉使其无法编译的行),我得到了这个

(string) (len=3) "%#v"
(*main._Ctype_struct_st_udf_args)(0x7ff318006af8)({
 arg_count: (main._Ctype_uint) 2,
 _: ([4]uint8) (len=4 cap=4) {
  00000000  00 00 00 00                                       |....|
 },
 arg_type: (*uint32)(0x7ff318006d18)(0),
 args: (**main._Ctype_char)(0x7ff318006d20->0x7ff3180251b0)(0),
 lengths: (*main._Ctype_ulong)(0x7ff318006d30)(0),
 maybe_null: (*main._Ctype_char)(0x7ff318006d40)(0),
 attributes: (**main._Ctype_char)(0x7ff318006d58->0x7ff318006b88)(39),
 attribute_lengths: (*main._Ctype_ulong)(0x7ff318006d68)(2),
 extension: (unsafe.Pointer) <nil>
})
4

1 回答 1

0

好吧,尽管我显然不太擅长 Go(尤其是 CGO),但我对 @JimB 的帮助很大,但我有一个 UDF 的工作版本,这是一个简单直接(快速)的功能从 URL 字符串中提取单个参数并正确解码它,而不是什么(例如 %20 作为空格返回,基本上是您期望它工作的方式)。

这对于纯 C UDF 来说似乎非常棘手,因为我并不真正了解 C(以及我了解其他语言),并且 URL 解析和 URL 参数解码可能会出错,而且原生 MySQL 函数很(并且也没有真正好的、干净的解码方式),所以对于这类问题,Go 似乎是比完美的候选者,因为它具有强大的性能、易于编写和各种易于使用的内置插件和第三方库。

完整的 UDF 及其安装/使用说明在这里https://github.com/StirlingMarketingGroup/mysql-get-url-param/blob/master/main.go


第一个问题是调试输出。我通过Fprintftmp 文件而不是标准输出来做到这一点,这样我就可以检查文件以查看变量转储。

t, err := ioutil.TempFile(os.TempDir(), "get-url-param")

fmt.Fprintf(t, "%#v\n", args.arg_type)

然后在我得到我的输出之后(我期望 args.arg_type 是一个数组,就像它在 C 中一样,而是一个数字)我需要转换该数字引用的数据(指向 C 数组开头的指针) 到一个 Go 数组,所以我可以设置它的值。

argsTypes := *(*[2]uint32)(unsafe.Pointer(args.arg_type))

argsTypes[0] = C.STRING_RESULT
argsTypes[1] = C.STRING_RESULT
于 2018-07-20T19:45:07.733 回答