drxkx6149 2018-07-20 15:41
浏览 84
已采纳

如何使用cgo进行调试/转储Go变量?

I'm trying to write a MySQL UDF in Go with cgo, in which I have a basic one functioning, but there's little bits and pieces that I can't figure out because I have no idea what some of the C variables are in terms of Go.

This is an example that I have written in C that forces the type of one of the MySQL parameters to an 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;
}

And that works fine, but then I try to do the same/similar thing with this other function in Go like this

//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
}

With this build error

./main.go:24: invalid operation: (*args.arg_type)[0] (type uint32 does not support indexing)

And I'm not totally sure what that means. Shouldn't this be a slice of some sort, not a uint32?

And this is where it'd be super helpful have some way of dumping the args struct somewhere somehow (maybe even in Go syntax as a super plus) so that I can tell what I'm working with.


Well I used spew to dump the variable contents to a tmp file inside the init function (commenting out the lines that made it not compile) and I got this

(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>
})
  • 写回答

1条回答 默认 最新

  • dtwkt46424 2018-07-20 19:45
    关注

    Alright so huge help with @JimB who stuck with me even though I'm clearly less adept with Go (and especially CGO) but I've got a working version of my UDF, which is an easy and straight forward (and fast) function that pulls a single parameter out of a URL string and decodes it correctly and what not (e.g. %20 gets returned as a space, basically how you would expect it to work).

    This seemed incredibly tricky with a pure C UDF because I don't really know C (as well as I know other languages), and there's a lot that can go wrong with URL parsing and URL parameter decoding, and native MySQL functions are slow (and there's not really a good, clean way to do the decoding either), so Go seemed like the better-than-perfect candidate for this kind of problem, for strong performance, ease of writing, and wide variety of easy to use built ins & third party libraries.

    The full UDF and it's installation/usage instructions are here https://github.com/StirlingMarketingGroup/mysql-get-url-param/blob/master/main.go


    First problem was debugging output. And I did that by Fprintfing to a tmp file instead of the standard output, so that I could check the file to see variable dumps.

    t, err := ioutil.TempFile(os.TempDir(), "get-url-param")
    
    fmt.Fprintf(t, "%#v
    ", args.arg_type)
    

    And then after I got my output (I was expecting args.arg_type to be an array like it is in C, but instead was a number) I needed to convert the data referenced by that number (the pointer to the start of the C array) to a Go array so I could set it's values.

    argsTypes := *(*[2]uint32)(unsafe.Pointer(args.arg_type))
    
    argsTypes[0] = C.STRING_RESULT
    argsTypes[1] = C.STRING_RESULT
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化