Golang 在 C 和 Go 之间传递 sql.DB

问题描述 投票:0回答:1

我正在编写 sql.DB 连接的加密,但在 C 和 Go 之间转换指针时遇到一些问题。看来sql.DB不是Go中的简单结构体,并且有GoPointer,任何机会都可以将函数返回*sql.DB导出到C,并由另一个Go调用它?

//test.go
package main

/*
#cgo CFLAGS: -I.
#include <stdlib.h>
*/
import "C"
import (
    "database/sql"
    "fmt"
    _ "github.com/denisenkom/go-mssqldb"
    "unsafe"
)

//export GetDBPointer
func GetDBPointer(engine *C.char, connStr *C.char) uintptr {
    connStrGo := C.GoString(connStr)
    engineStrGo := C.GoString(engine)
    // Do something to decrypt connStrGo
    db, err := sql.Open(engineStrGo, connStrGo)
    if err != nil {
        fmt.Println("Failed to open database")
        return 0
    }
    return uintptr(unsafe.Pointer(db))
}

func main() {}

// demo.go
package main

/*
#cgo LDFLAGS: -L. -ltest
#include "test.h"
#include <stdlib.h>
*/
import "C"
import (
    "fmt"
    "database/sql"
    "unsafe"
)

func main() {
    // an encrypted connStr, but for easy to understand right now
    connStr := "server=;user id=;password=;database="
    engine := "sqlserver"
    // Convert Go string to C string
    connStrC := C.CString(connStr)
    engineC := C.CString(engine)
    defer C.free(unsafe.Pointer(connStrC))
    defer C.free(unsafe.Pointer(engineC))

    // Call GetDBPointer to connect to the database
    dbPtr := C.GetDBPointer(engineC, connStrC)
    if dbPtr == 0 {
        fmt.Println("Failed to connect to database")
        return
    }

    dbConn := (*sql.DB)(unsafe.Pointer(dbPtr))
    err := dbConn.Ping()
    if err != nil {
        fmt.Println("Failed to ping.")
    }
}

go build -buildmode=c-shared -o test.dll test.go
go build -o demo.exe demo.go

我尝试直接使用指针,一个结构体包含unsafe.Pointer,以及我从书上读到的类似内容:

type ObjectId int32
var refs struct {
    sync.Mutex
    objs map[ObjectId] interface{}
    next ObjectId
}

func init(){
    refs.Lock()
    defer refs.Unlock()
    refs.objs = make(map[ObjectId] interface{})
    refs.next = 1000
}

func NewObjectId(obj interface{}) ObjectId {
    refs.Lock()
    defer refs.Unlock()
    id := refs.next
    refs.next++
    refs.objs[id] = obj
    return id
}
func (id ObjectId) IsNil() bool {
    return id == 0
}
func (id ObjectId) Get() interface{} {
    refs.Lock()
    defer refs.Unlock()
    return refs.objs[id]
}
func (id *ObjectId) Free() interface{} {
    refs.Lock()
    defer refs.Unlock()
    obj := refs.objs[*id]
    delete(refs.objs, *id)
    *id = 0
    return obj
}
func GetObject(id ObjectId) (interface{}, bool) {
    refs.Lock()
    defer refs.Unlock()
    obj, exists := refs.objs[id]
    return obj, exists
}

func FreeObject(id ObjectId) {
    refs.Lock()
    defer refs.Unlock()
    delete(refs.objs, id)
}

这看起来像是在 Go 中固定内存的反映

c go cgo
1个回答
0
投票

后来,我从github下载了一个ODBC驱动程序,并在连接函数中做了一些更改:我编写了一个cpp dll,extern连接函数来替换原生的,现在对我来说效果很好。

© www.soinside.com 2019 - 2024. All rights reserved.