代码之家  ›  专栏  ›  技术社区  ›  Brian Leishman

如何在使用cgo构建时调试/转储Go变量?

  •  1
  • Brian Leishman  · 技术社区  · 6 年前

    我试图在Go和cgo中编写一个MySQL UDF,其中我有一个基本的函数,但是有一些细节我无法理解,因为我不知道一些C变量在Go中是什么。

    这是我用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 是吗?

    这是最好的办法 args 不知怎的,在某个地方构造(甚至在Go语法中作为super plus),这样我就可以知道我在用什么。


    我用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>
    })
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   Brian Leishman    6 年前

    好吧,@jimb帮了我大忙,虽然我显然不太擅长go(尤其是cgo),但我有一个工作版本的udf,它是一个简单而直接(快速)的函数,可以从url字符串中提取一个参数并正确解码,不正确的部分(例如%20作为空格返回,基本上就是你希望它能起作用的方式)。

    对于纯C UDF来说,这似乎非常棘手,因为我并不真正了解C(我也知道其他语言),而且URL解析和URL参数解码可能会出现很多问题,而本地MySQL函数是 缓慢的 (实际上也没有一种好的、干净的解码方法),因此Go似乎是解决此类问题的最佳候选方案,因为它具有强大的性能、易写性以及各种易于使用的内置第三方库。

    完整的udf及其安装/使用说明如下 https://github.com/StirlingMarketingGroup/mysql-get-url-param/blob/master/main.go


    第一个问题是调试输出我是通过 Fprintf 转换为tmp文件而不是标准输出,以便我可以检查该文件以查看变量转储。

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

    然后在我得到输出(我希望arg s.arg_类型是一个类似于c中的数组,而不是一个数字)之后,我需要将该数字引用的数据(指向c数组开头的指针)转换为go数组,以便设置它的值。

    argsTypes := *(*[2]uint32)(unsafe.Pointer(args.arg_type))
    
    argsTypes[0] = C.STRING_RESULT
    argsTypes[1] = C.STRING_RESULT