Makoto1972
@Makoto1972 (makoto 1972)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

duckdbとGoの接続に失敗します

解決したいこと

Goとduckdbの接続を試したいです。
Goのバージョンはgo1.22.4です。
GoとSqlite3の連携やpostgresqlの連携については、
modファイルの作成から実行&コンパイルまで行えましたが
Go + duckDbはうまくいきません。
どなたか解決方法を教えて下さい。
Goコードは、公式サイトに公開されているものです。

発生している問題・エラー

C:\Program Files\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\m_yan\AppData\Local\Temp\go-link-2319555771\000002.o: in function `_cgo_f9e122a25730_Cfunc_duckdb_append_data_chunk':
/tmp/go-build/cgo-gcc-prolog:56: undefined reference to `__imp_duckdb_append_data_chunk'
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\m_yan\AppData\Local\Temp\go-link-2319555771\000002.o: in function `_cgo_f9e122a25730_Cfunc_duckdb_appender_column_count':
/tmp/go-build/cgo-gcc-prolog:74: undefined reference to `__imp_duckdb_appender_column_count'
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\m_yan\AppData\Local\Temp\go-link-2319555771\000002.o: in function `_cgo_f9e122a25730_Cfunc_duckdb_appender_column_type':
/tmp/go-build/cgo-gcc-prolog:93: undefined reference to `__imp_duckdb_appender_column_type'
C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\m_yan\AppData\Local\Temp\go-link-2319555771\000002.o: in function `_cgo_f9e122a25730_Cfunc_duckdb_appender_create':
(略)

該当するソースコード

package main

import (
	"context"
	"database/sql"
	"log"
	"time"

	_ "github.com/marcboeker/go-duckdb"
)

var db *sql.DB

type user struct {
	name    string
	age     int
	height  float32
	awesome bool
	bday    time.Time
}

func main() {
	var err error
        db, err := sql.Open("duckdb", "./bmi.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	check(db.Ping())

	setting := db.QueryRowContext(context.Background(), "SELECT current_setting('access_mode')")
	var am string
	check(setting.Scan(&am))
	log.Printf("DB opened with access mode %s", am)

	check(db.ExecContext(context.Background(), "CREATE TABLE users(name VARCHAR, age INTEGER, height FLOAT, awesome BOOLEAN, bday DATE)"))
	check(db.ExecContext(context.Background(), "INSERT INTO users VALUES('marc', 99, 1.91, true, '1970-01-01')"))
	check(db.ExecContext(context.Background(), "INSERT INTO users VALUES('macgyver', 70, 1.85, true, '1951-01-23')"))

	rows, err := db.QueryContext(
		context.Background(), `
		SELECT name, age, height, awesome, bday
		FROM users
		WHERE (name = ? OR name = ?) AND age > ? AND awesome = ?`,
		"macgyver", "marc", 30, true,
	)
	check(err)
	defer rows.Close()

	for rows.Next() {
		u := new(user)
		err := rows.Scan(&u.name, &u.age, &u.height, &u.awesome, &u.bday)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf(
			"%s is %d years old, %.2f tall, bday on %s and has awesomeness: %t\n",
			u.name, u.age, u.height, u.bday.Format(time.RFC3339), u.awesome,
		)
	}
	check(rows.Err())

	res, err := db.ExecContext(context.Background(), "DELETE FROM users")
	check(err)

	ra, _ := res.RowsAffected()
	log.Printf("Deleted %d rows\n", ra)

	runTransaction()
	testPreparedStmt()
}

func check(args ...interface{}) {
	err := args[len(args)-1]
	if err != nil {
		panic(err)
	}
}

func runTransaction() {
	log.Println("Starting transaction...")
	tx, err := db.Begin()
	check(err)

	check(
		tx.ExecContext(
			context.Background(),
			"INSERT INTO users VALUES('gru', 25, 1.35, false, '1996-04-03')",
		),
	)
	row := tx.QueryRowContext(context.Background(), "SELECT COUNT(*) FROM users WHERE name = ?", "gru")
	var count int64
	check(row.Scan(&count))
	if count > 0 {
		log.Println("User Gru was inserted")
	}

	log.Println("Rolling back transaction...")
	check(tx.Rollback())

	row = db.QueryRowContext(context.Background(), "SELECT COUNT(*) FROM users WHERE name = ?", "gru")
	check(row.Scan(&count))
	if count > 0 {
		log.Println("Found user Gru")
	} else {
		log.Println("Couldn't find user Gru")
	}
}

func testPreparedStmt() {
	stmt, err := db.PrepareContext(context.Background(), "INSERT INTO users VALUES(?, ?, ?, ?, ?)")
	check(err)
	defer stmt.Close()

	check(stmt.ExecContext(context.Background(), "Kevin", 11, 0.55, true, "2013-07-06"))
	check(stmt.ExecContext(context.Background(), "Bob", 12, 0.73, true, "2012-11-04"))
	check(stmt.ExecContext(context.Background(), "Stuart", 13, 0.66, true, "2014-02-12"))

	stmt, err = db.PrepareContext(context.Background(), "SELECT * FROM users WHERE age > ?")
	check(err)

	rows, err := stmt.QueryContext(context.Background(), 1)
	check(err)
	defer rows.Close()

	for rows.Next() {
		u := new(user)
		err := rows.Scan(&u.name, &u.age, &u.height, &u.awesome, &u.bday)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf(
			"%s is %d years old, %.2f tall, bday on %s and has awesomeness: %t\n",
			u.name, u.age, u.height, u.bday.Format(time.RFC3339), u.awesome,
		)
	}
}

自分で試したこと

gccコンパイラでgcc --versionの動作とC言語のコンパイルの確認
sqlite3・postgresqlでの手順の確認と動作検証
gccコンパイラをTDM-GCC-64とMinGWで動作検証するもダメ
気になっているのがmodファイルに記載された下記をブラウザで入力するとNot foundと表示されることです。

module duckdb

go 1.22.4

require (
github.com/apache/arrow/go/v14 v14.0.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/flatbuffers v23.5.26+incompatible // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/marcboeker/go-duckdb v1.7.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/tools v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
)

0

1Answer

時間が経っているので、すでに解決済みかもしれませんが、
Windows環境のCGOに関する問題ではないでしょうか?

のコメントでどうでしょう。

私はWindows環境では試していませんがMac OS環境では、このソースコードをビルドできました。
MacOSとLinux版はスタティクリンクのライブラリがgo-duckdbのパッケージにバンドルされているようです。

0Like

Comments

  1. @Makoto1972

    Questioner

    @twsnmp様、お忙しいところご回答ありがとうございました。
    すごい方にご回答いただきまして恐縮です。

    教えていただいた記事を参考に、go runで無事実行できました。

    exeファイルを作成し実行するとduckdb.dllが見つかりませんとエラーになりますが
    一旦exeファイルと同じ階層に配置すると実行できました。

    しばらくGoをさわっていなかったので色々忘れているのですが
    行き詰まりすぎて放置していました。解決方法のご紹介ありがとうございました。

  2. 実行できて良かったです。
    GO言語を嫌いにならなないことを願っています。

  3. @Makoto1972

    Questioner

    @twsnmp様、今回は過去レスにも関わらずご回答ありがとうございました。
    Python、Nim、Julia、javaでduckdbを実行できたのになぜにGoは無理なのか・・。
    モヤモヤしていました。sqlite3、postgresqlでうまくいっても
    duckdbに注目していましたので・・・。

    GO言語を嫌いにならなないことを願っています。
    ということでしたが、またGo言語の学習を進められればと思います。
    また、この記事も誰かの参考になればと思います。
    今回は、ありがとうございました。

Your answer might help someone💌