diff --git a/.gitignore b/.gitignore index 4edda059..fcff0a3c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ run.sh duckdb/ .idea +./duckdb +duckdb diff --git a/duckdb_test.go b/duckdb_test.go index 690ad5df..3ebd07c8 100644 --- a/duckdb_test.go +++ b/duckdb_test.go @@ -5,6 +5,8 @@ import ( "database/sql" "database/sql/driver" "encoding/json" + "fmt" + "log" "math/big" "os" "reflect" @@ -88,6 +90,38 @@ func TestConnector_Close(t *testing.T) { require.NoError(t, connector.Close()) } +func ExampleNewConnector() { + c, err := NewConnector("duckdb?access_mode=READ_WRITE", func(execer driver.ExecerContext) error { + initQueries := []string{ + `SET memory_limit = '10GB';`, + `SET threads TO 1;`, + } + + ctx := context.Background() + for _, query := range initQueries { + _, err := execer.ExecContext(ctx, query, nil) + if err != nil { + return err + } + } + return nil + }) + checkErr(err, "failed to create new duckdb connector: %s") + defer c.Close() + + db := sql.OpenDB(c) + defer db.Close() + + var value string + row := db.QueryRow(`SELECT value FROM duckdb_settings() WHERE name = 'memory_limit';`) + if row.Scan(&value) != nil { + log.Fatalf("failed to scan row: %s", err) + } + + fmt.Printf("Setting memory_limit is %s", value) + // Output: Setting memory_limit is 9.3 GiB +} + func TestConnPool(t *testing.T) { db := openDB(t) db.SetMaxOpenConns(2) // set connection pool size greater than 1 @@ -629,6 +663,28 @@ func TestQueryTimeout(t *testing.T) { require.NoError(t, db.Close()) } +func Example_simpleConnection() { + // Connect to DuckDB using '[database/sql.Open]'. + db, err := sql.Open("duckdb", "?access_mode=READ_WRITE") + checkErr(err, "failed to open connection to duckdb: %s") + defer db.Close() + + ctx := context.Background() + + createStmt := `CREATE table users(name VARCHAR, age INTEGER)` + _, err = db.ExecContext(ctx, createStmt) + checkErr(err, "failed to create table: %s") + + insertStmt := `INSERT INTO users(name, age) VALUES (?, ?);` + res, err := db.ExecContext(ctx, insertStmt, "Marc", 30) + checkErr(err, "failed to insert users: %s") + + rowsAffected, err := res.RowsAffected() + checkErr(err, "failed to get number of rows affected") + fmt.Printf("Inserted %d row(s) into users table", rowsAffected) + // Output: Inserted 1 row(s) into users table +} + func openDB(t *testing.T) *sql.DB { db, err := sql.Open("duckdb", "") require.NoError(t, err) @@ -645,3 +701,9 @@ func createTable(db *sql.DB, t *testing.T, sql string) *sql.Result { func createFooTable(db *sql.DB, t *testing.T) *sql.Result { return createTable(db, t, `CREATE TABLE foo(bar VARCHAR, baz INTEGER)`) } + +func checkErr(err error, msg string) { + if err != nil { + log.Fatalf(msg, err) + } +} diff --git a/errors.go b/errors.go index 9131d0ab..efad36cf 100644 --- a/errors.go +++ b/errors.go @@ -91,7 +91,7 @@ var ( errUnsupportedMapKeyType = errors.New("MAP key type not supported") errEmptyName = errors.New("empty name") - errInvalidDecimalWidth = fmt.Errorf("the DECIMAL with must be between 1 and %d", MAX_DECIMAL_WIDTH) + errInvalidDecimalWidth = fmt.Errorf("the DECIMAL with must be between 1 and %d", max_decimal_width) errInvalidDecimalScale = errors.New("the DECIMAL scale must be less than or equal to the width") errSetSQLNULLValue = errors.New("cannot write to a NULL column") diff --git a/type_info.go b/type_info.go index 6abfa7ca..1a12bbe1 100644 --- a/type_info.go +++ b/type_info.go @@ -114,7 +114,7 @@ func NewTypeInfo(t Type) (TypeInfo, error) { // NewDecimalInfo returns DECIMAL type information. // Its input parameters are the width and scale of the DECIMAL type. func NewDecimalInfo(width uint8, scale uint8) (TypeInfo, error) { - if width < 1 || width > MAX_DECIMAL_WIDTH { + if width < 1 || width > max_decimal_width { return nil, getError(errAPI, errInvalidDecimalWidth) } if scale > width { diff --git a/types.go b/types.go index 95617da5..5b9751f2 100644 --- a/types.go +++ b/types.go @@ -21,12 +21,12 @@ func convertNumericType[srcT numericType, destT numericType](val srcT) destT { return destT(val) } -const UUIDLength = 16 +const uuid_length = 16 -type UUID [UUIDLength]byte +type UUID [uuid_length]byte func (u *UUID) Scan(v any) error { - if n := copy(u[:], v.([]byte)); n != UUIDLength { + if n := copy(u[:], v.([]byte)); n != uuid_length { return fmt.Errorf("invalid UUID length: %d", n) } return nil @@ -36,7 +36,7 @@ func (u *UUID) Scan(v any) error { // The value is computed as: upper * 2^64 + lower func hugeIntToUUID(hi C.duckdb_hugeint) []byte { - var uuid [UUIDLength]byte + var uuid [uuid_length]byte // We need to flip the sign bit of the signed hugeint to transform it to UUID bytes binary.BigEndian.PutUint64(uuid[:8], uint64(hi.upper)^1<<63) binary.BigEndian.PutUint64(uuid[8:], uint64(hi.lower)) @@ -117,7 +117,7 @@ func (s *Composite[T]) Scan(v any) error { return mapstructure.Decode(v, &s.t) } -const MAX_DECIMAL_WIDTH = 38 +const max_decimal_width = 38 type Decimal struct { Width uint8 diff --git a/vector_setters.go b/vector_setters.go index 271679c7..448c7093 100644 --- a/vector_setters.go +++ b/vector_setters.go @@ -395,10 +395,10 @@ func setUUID[S any](vec *vector, rowIdx C.idx_t, val S) error { case UUID: uuid = v case []uint8: - if len(v) != UUIDLength { + if len(v) != uuid_length { return castError(reflect.TypeOf(val).String(), reflect.TypeOf(uuid).String()) } - for i := 0; i < UUIDLength; i++ { + for i := 0; i < uuid_length; i++ { uuid[i] = v[i] } default: