From e965728f2218402981d659dcd27c91f9c02d373a Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:42:10 +0200 Subject: [PATCH 1/8] started working on profiling --- appender.go | 4 +-- errors.go | 12 +++++---- errors_test.go | 8 +++--- profiling.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++ profiling_test.go | 46 ++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 profiling.go create mode 100644 profiling_test.go diff --git a/appender.go b/appender.go index 31396201..fa611903 100644 --- a/appender.go +++ b/appender.go @@ -34,10 +34,10 @@ type Appender struct { func NewAppenderFromConn(driverConn driver.Conn, schema, table string) (*Appender, error) { con, ok := driverConn.(*conn) if !ok { - return nil, getError(errAppenderInvalidCon, nil) + return nil, getError(errInvalidCon, nil) } if con.closed { - return nil, getError(errAppenderClosedCon, nil) + return nil, getError(errClosedCon, nil) } var cSchema *C.char diff --git a/errors.go b/errors.go index 06112b04..77ff5c1f 100644 --- a/errors.go +++ b/errors.go @@ -60,14 +60,14 @@ var ( errAPI = errors.New("API error") errVectorSize = errors.New("data chunks cannot exceed duckdb's internal vector size") - errParseDSN = errors.New("could not parse DSN for database") - errOpen = errors.New("could not open database") - errSetConfig = errors.New("could not set invalid or local option for global database config") + errParseDSN = errors.New("could not parse DSN for database") + errOpen = errors.New("could not open database") + errSetConfig = errors.New("could not set invalid or local option for global database config") + errInvalidCon = errors.New("not a DuckDB driver connection") + errClosedCon = errors.New("closed connection") errUnsupportedMapKeyType = errors.New("MAP key type not supported") - errAppenderInvalidCon = errors.New("could not create appender: not a DuckDB driver connection") - errAppenderClosedCon = errors.New("could not create appender: appender creation on a closed connection") errAppenderCreation = errors.New("could not create appender") errAppenderDoubleClose = errors.New("could not close appender: already closed") errAppenderAppendRow = errors.New("could not append row") @@ -75,6 +75,8 @@ var ( errAppenderClose = errors.New("could not close appender") errAppenderFlush = errors.New("could not flush appender") + errProfilingInfoEmpty = errors.New("no profiling information available for this connection") + // Errors not covered in tests. errConnect = errors.New("could not connect to database") errCreateConfig = errors.New("could not create config for database") diff --git a/errors_test.go b/errors_test.go index be1e8811..63467409 100644 --- a/errors_test.go +++ b/errors_test.go @@ -59,13 +59,13 @@ func TestErrNestedMap(t *testing.T) { func TestErrAppender(t *testing.T) { t.Parallel() - t.Run(errAppenderInvalidCon.Error(), func(t *testing.T) { + t.Run(errInvalidCon.Error(), func(t *testing.T) { var con driver.Conn _, err := NewAppenderFromConn(con, "", "test") - testError(t, err, errAppenderInvalidCon.Error()) + testError(t, err, errInvalidCon.Error()) }) - t.Run(errAppenderClosedCon.Error(), func(t *testing.T) { + t.Run(errClosedCon.Error(), func(t *testing.T) { c, err := NewConnector("", nil) require.NoError(t, err) @@ -74,7 +74,7 @@ func TestErrAppender(t *testing.T) { require.NoError(t, con.Close()) _, err = NewAppenderFromConn(con, "", "test") - testError(t, err, errAppenderClosedCon.Error()) + testError(t, err, errClosedCon.Error()) require.NoError(t, c.Close()) }) diff --git a/profiling.go b/profiling.go new file mode 100644 index 00000000..4292a344 --- /dev/null +++ b/profiling.go @@ -0,0 +1,67 @@ +package duckdb + +/* +#include +*/ +import "C" +import ( + "unsafe" +) + +type ProfilingInfo struct { + Metrics map[string]string + Children []ProfilingInfo +} + +func GetProfilingInfo(driverConn any) (ProfilingInfo, error) { + info := ProfilingInfo{} + + con, ok := driverConn.(*conn) + if !ok { + return info, getError(errInvalidCon, nil) + } + if con.closed { + return info, getError(errClosedCon, nil) + } + + duckdbInfo := C.duckdb_get_profiling_info(con.duckdbCon) + if duckdbInfo == nil { + return info, getError(errProfilingInfoEmpty, nil) + } + + // Recursive tree traversal. + info.getMetrics(duckdbInfo) + return info, nil +} + +func (info *ProfilingInfo) getMetrics(duckdbInfo C.duckdb_profiling_info) { + m := C.duckdb_profiling_info_get_metrics(duckdbInfo) + count := C.duckdb_get_map_size(m) + + for i := C.idx_t(0); i < count; i++ { + key := C.duckdb_get_map_key(m, i) + value := C.duckdb_get_map_value(m, i) + + cKey := C.duckdb_get_varchar(key) + cValue := C.duckdb_get_varchar(value) + + keyStr := C.GoString(cKey) + valueStr := C.GoString(cValue) + + info.Metrics[keyStr] = valueStr + + C.duckdb_destroy_value(&key) + C.duckdb_destroy_value(&value) + C.duckdb_free(unsafe.Pointer(cKey)) + C.duckdb_free(unsafe.Pointer(cValue)) + } + C.duckdb_destroy_value(&m) + + childCount := C.duckdb_profiling_info_get_child_count(duckdbInfo) + for i := C.idx_t(0); i < childCount; i++ { + duckdbChildInfo := C.duckdb_profiling_info_get_child(duckdbInfo, i) + childInfo := ProfilingInfo{} + childInfo.getMetrics(duckdbChildInfo) + info.Children = append(info.Children, childInfo) + } +} diff --git a/profiling_test.go b/profiling_test.go new file mode 100644 index 00000000..742f94df --- /dev/null +++ b/profiling_test.go @@ -0,0 +1,46 @@ +package duckdb + +import ( + "context" + "database/sql" + "fmt" + "github.com/stretchr/testify/require" + "testing" +) + +func TestProfiling(t *testing.T) { + db, err := sql.Open("duckdb", "") + require.NoError(t, err) + + con, err := db.Conn(context.Background()) + require.NoError(t, err) + + _, err = con.ExecContext(context.Background(), `PRAGMA enable_profiling = 'no_output'`) + require.NoError(t, err) + + _, err = con.ExecContext(context.Background(), `PRAGMA profiling_mode = 'detailed'`) + require.NoError(t, err) + + res, err := con.QueryContext(context.Background(), "SELECT range AS i FROM range(100) ORDER BY i") + require.NoError(t, err) + + //var info ProfilingInfo + err = con.Raw(func(driverCon any) error { + info, errGetInfo := GetProfilingInfo(driverCon) + require.NoError(t, errGetInfo) + fmt.Println(info) + return nil + }) + + //info, err := GetProfilingInfo(con) + //require.NoError(t, err) + + require.NoError(t, res.Close()) + require.NoError(t, con.Close()) + require.NoError(t, db.Close()) + + // Verify our metrics. + //require.NotEmpty(t, info.Metrics, "metrics must not be empty") + //require.NotEmpty(t, info.Children, "children must not be empty") + //fmt.Println(info) +} From bc5ba8daf0d80a1ebf0420c65032296f5f35c62b Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:52:38 +0200 Subject: [PATCH 2/8] add profiling support --- errors_test.go | 37 +++++++++++++++++++++++++++++++++++++ profiling_test.go | 20 ++++++++++---------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/errors_test.go b/errors_test.go index 63467409..ac217408 100644 --- a/errors_test.go +++ b/errors_test.go @@ -302,6 +302,43 @@ func TestErrAPISetValue(t *testing.T) { testError(t, err, errAPI.Error(), columnCountErrMsg) } +func TestErrProfiling(t *testing.T) { + t.Parallel() + + t.Run(errInvalidCon.Error(), func(t *testing.T) { + var con driver.Conn + _, err := GetProfilingInfo(con) + testError(t, err, errInvalidCon.Error()) + }) + + t.Run(errClosedCon.Error(), func(t *testing.T) { + c, err := NewConnector("", nil) + require.NoError(t, err) + + con, err := c.Connect(context.Background()) + require.NoError(t, err) + require.NoError(t, con.Close()) + + _, err = GetProfilingInfo(con) + testError(t, err, errClosedCon.Error()) + require.NoError(t, c.Close()) + }) + + t.Run(errProfilingInfoEmpty.Error(), func(t *testing.T) { + c, err := NewConnector("", nil) + require.NoError(t, err) + + con, err := c.Connect(context.Background()) + require.NoError(t, err) + + _, err = GetProfilingInfo(con) + testError(t, err, errProfilingInfoEmpty.Error()) + + require.NoError(t, con.Close()) + require.NoError(t, c.Close()) + }) +} + func TestDuckDBErrors(t *testing.T) { db := openDB(t) defer db.Close() diff --git a/profiling_test.go b/profiling_test.go index 742f94df..7e6d0e00 100644 --- a/profiling_test.go +++ b/profiling_test.go @@ -9,6 +9,8 @@ import ( ) func TestProfiling(t *testing.T) { + t.Parallel() + db, err := sql.Open("duckdb", "") require.NoError(t, err) @@ -24,23 +26,21 @@ func TestProfiling(t *testing.T) { res, err := con.QueryContext(context.Background(), "SELECT range AS i FROM range(100) ORDER BY i") require.NoError(t, err) - //var info ProfilingInfo + var info ProfilingInfo err = con.Raw(func(driverCon any) error { - info, errGetInfo := GetProfilingInfo(driverCon) - require.NoError(t, errGetInfo) - fmt.Println(info) - return nil + info, err = GetProfilingInfo(driverCon) + return err }) - - //info, err := GetProfilingInfo(con) - //require.NoError(t, err) + require.NoError(t, err) require.NoError(t, res.Close()) require.NoError(t, con.Close()) require.NoError(t, db.Close()) - // Verify our metrics. + // Verify the metrics. + // TODO: currently failing due to C API bug. + fmt.Println(info) // Dummy print to use variable. //require.NotEmpty(t, info.Metrics, "metrics must not be empty") //require.NotEmpty(t, info.Children, "children must not be empty") - //fmt.Println(info) + //require.NotEmpty(t, info.Children[0].Metrics, "child metrics must not be empty") } From 9b99a4b1dfe0131affe6d24cabcb396eb9d3cfd7 Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:53:32 +0200 Subject: [PATCH 3/8] formatter --- profiling.go | 1 + profiling_test.go | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/profiling.go b/profiling.go index 4292a344..c3eb1f00 100644 --- a/profiling.go +++ b/profiling.go @@ -4,6 +4,7 @@ package duckdb #include */ import "C" + import ( "unsafe" ) diff --git a/profiling_test.go b/profiling_test.go index 7e6d0e00..c07c467c 100644 --- a/profiling_test.go +++ b/profiling_test.go @@ -4,8 +4,9 @@ import ( "context" "database/sql" "fmt" - "github.com/stretchr/testify/require" "testing" + + "github.com/stretchr/testify/require" ) func TestProfiling(t *testing.T) { @@ -40,7 +41,7 @@ func TestProfiling(t *testing.T) { // Verify the metrics. // TODO: currently failing due to C API bug. fmt.Println(info) // Dummy print to use variable. - //require.NotEmpty(t, info.Metrics, "metrics must not be empty") - //require.NotEmpty(t, info.Children, "children must not be empty") - //require.NotEmpty(t, info.Children[0].Metrics, "child metrics must not be empty") + // require.NotEmpty(t, info.Metrics, "metrics must not be empty") + // require.NotEmpty(t, info.Children, "children must not be empty") + // require.NotEmpty(t, info.Children[0].Metrics, "child metrics must not be empty") } From 6b761fdfac1c0366cb7198d3fcae670bb4113903 Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:27:30 +0200 Subject: [PATCH 4/8] add profiling documentation --- README.md | 36 ++++++++++++++++++++++++++++++++++++ profiling.go | 10 +++++++++- profiling_test.go | 5 ++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f459a07c..53f78a69 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,42 @@ if err != nil { } ``` +## DuckDB Profiling API + +This section describes using the [DuckDB Profiling API](https://duckdb.org/docs/dev/profiling.html). +DuckDB's profiling information is connection-local. +The following example walks you through the necessary steps to obtain the `ProfilingInformation` type, which contains all available metrics. +Please refer to the [DuckDB documentation](https://duckdb.org/docs/dev/profiling.html) on configuring and collecting specific metrics. + +- First, you need to obtain a connection. +- Then, you enable profiling for the connection. +- Now, for each subsequent query on this connection, DuckDB will collect profiling information. + - Optionally, you can turn off profiling at any point. +- Next, you execute the query for which you want to obtain profiling information. +- Finally, directly after executing the query, you use the underlying DuckDB connection to retrieve any available profiling information. + +For readability, we omit error handling in this example. +```Go +db, err := sql.Open("duckdb", "") +con, err := db.Conn(context.Background()) + +_, err = con.ExecContext(context.Background(), `PRAGMA enable_profiling = 'no_output'`) +_, err = con.ExecContext(context.Background(), `PRAGMA profiling_mode = 'detailed'`) + +res, err := con.QueryContext(context.Background(), `SELECT 42`) + +var info ProfilingInfo +err = con.Raw(func(driverCon any) error { + info, err = GetProfilingInfo(driverCon) + return err +}) +err = res.Close() + +_, err = con.ExecContext(context.Background(), `PRAGMA disable_profiling`) +err = con.Close() +err = db.Close() +``` + ## DuckDB Apache Arrow Interface If you want to use the [DuckDB Arrow Interface](https://duckdb.org/docs/api/c/api#arrow-interface), you can obtain a new `Arrow` by passing a DuckDB connection to `NewArrowFromConn()`. diff --git a/profiling.go b/profiling.go index c3eb1f00..cc4ec427 100644 --- a/profiling.go +++ b/profiling.go @@ -9,11 +9,19 @@ import ( "unsafe" ) +// ProfilingInfo is a recursive type containing metrics for each node in DuckDB's query plan. +// There are two types of nodes: the QUERY_ROOT and OPERATOR nodes. +// The QUERY_ROOT refers exclusively to the top-level node; its metrics are measured over the entire query. +// The OPERATOR nodes refer to the individual operators in the query plan. type ProfilingInfo struct { - Metrics map[string]string + // Metrics contains all key-value pairs of the current node. + // The key represents the name and corresponds to the measured value. + Metrics map[string]string + // Children contains all children of the node and their respective metrics. Children []ProfilingInfo } +// GetProfilingInfo obtains all available metrics set by the current connection. func GetProfilingInfo(driverConn any) (ProfilingInfo, error) { info := ProfilingInfo{} diff --git a/profiling_test.go b/profiling_test.go index c07c467c..e345ec9d 100644 --- a/profiling_test.go +++ b/profiling_test.go @@ -24,7 +24,7 @@ func TestProfiling(t *testing.T) { _, err = con.ExecContext(context.Background(), `PRAGMA profiling_mode = 'detailed'`) require.NoError(t, err) - res, err := con.QueryContext(context.Background(), "SELECT range AS i FROM range(100) ORDER BY i") + res, err := con.QueryContext(context.Background(), `SELECT range AS i FROM range(100) ORDER BY i`) require.NoError(t, err) var info ProfilingInfo @@ -34,6 +34,9 @@ func TestProfiling(t *testing.T) { }) require.NoError(t, err) + _, err = con.ExecContext(context.Background(), `PRAGMA disable_profiling`) + require.NoError(t, err) + require.NoError(t, res.Close()) require.NoError(t, con.Close()) require.NoError(t, db.Close()) From 86c4e331902c501b093dc5d09810ef396aeb2d38 Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:44:30 +0200 Subject: [PATCH 5/8] nit --- profiling_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/profiling_test.go b/profiling_test.go index e345ec9d..92ff840a 100644 --- a/profiling_test.go +++ b/profiling_test.go @@ -28,8 +28,8 @@ func TestProfiling(t *testing.T) { require.NoError(t, err) var info ProfilingInfo - err = con.Raw(func(driverCon any) error { - info, err = GetProfilingInfo(driverCon) + err = con.Raw(func(driverConn any) error { + info, err = GetProfilingInfo(driverConn) return err }) require.NoError(t, err) From db3245d144a228f6399ca2fb58772752b56b9b22 Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:51:16 +0200 Subject: [PATCH 6/8] small fixes after moving to latest duckdb --- errors_test.go | 37 ------------------------------------- profiling.go | 31 ++++++++++++++----------------- profiling_test.go | 32 +++++++++++++++++--------------- scalar_udf_test.go | 2 +- 4 files changed, 32 insertions(+), 70 deletions(-) diff --git a/errors_test.go b/errors_test.go index 4bc347ca..00bb91ae 100644 --- a/errors_test.go +++ b/errors_test.go @@ -306,43 +306,6 @@ func TestErrAPISetValue(t *testing.T) { testError(t, err, errAPI.Error(), columnCountErrMsg) } -func TestErrProfiling(t *testing.T) { - t.Parallel() - - t.Run(errInvalidCon.Error(), func(t *testing.T) { - var con driver.Conn - _, err := GetProfilingInfo(con) - testError(t, err, errInvalidCon.Error()) - }) - - t.Run(errClosedCon.Error(), func(t *testing.T) { - c, err := NewConnector("", nil) - require.NoError(t, err) - - con, err := c.Connect(context.Background()) - require.NoError(t, err) - require.NoError(t, con.Close()) - - _, err = GetProfilingInfo(con) - testError(t, err, errClosedCon.Error()) - require.NoError(t, c.Close()) - }) - - t.Run(errProfilingInfoEmpty.Error(), func(t *testing.T) { - c, err := NewConnector("", nil) - require.NoError(t, err) - - con, err := c.Connect(context.Background()) - require.NoError(t, err) - - _, err = GetProfilingInfo(con) - testError(t, err, errProfilingInfoEmpty.Error()) - - require.NoError(t, con.Close()) - require.NoError(t, c.Close()) - }) -} - func TestDuckDBErrors(t *testing.T) { db := openDB(t) createTable(db, t, `CREATE TABLE duckdb_error_test(bar VARCHAR UNIQUE, baz INT32, u_1 UNION("string" VARCHAR))`) diff --git a/profiling.go b/profiling.go index cc4ec427..cd146a12 100644 --- a/profiling.go +++ b/profiling.go @@ -6,6 +6,7 @@ package duckdb import "C" import ( + "database/sql" "unsafe" ) @@ -22,30 +23,26 @@ type ProfilingInfo struct { } // GetProfilingInfo obtains all available metrics set by the current connection. -func GetProfilingInfo(driverConn any) (ProfilingInfo, error) { +func GetProfilingInfo(c *sql.Conn) (ProfilingInfo, error) { info := ProfilingInfo{} + err := c.Raw(func(driverConn any) error { + con := driverConn.(*conn) + duckdbInfo := C.duckdb_get_profiling_info(con.duckdbCon) + if duckdbInfo == nil { + return getError(errProfilingInfoEmpty, nil) + } - con, ok := driverConn.(*conn) - if !ok { - return info, getError(errInvalidCon, nil) - } - if con.closed { - return info, getError(errClosedCon, nil) - } - - duckdbInfo := C.duckdb_get_profiling_info(con.duckdbCon) - if duckdbInfo == nil { - return info, getError(errProfilingInfoEmpty, nil) - } - - // Recursive tree traversal. - info.getMetrics(duckdbInfo) - return info, nil + // Recursive tree traversal. + info.getMetrics(duckdbInfo) + return nil + }) + return info, err } func (info *ProfilingInfo) getMetrics(duckdbInfo C.duckdb_profiling_info) { m := C.duckdb_profiling_info_get_metrics(duckdbInfo) count := C.duckdb_get_map_size(m) + info.Metrics = make(map[string]string, count) for i := C.idx_t(0); i < count; i++ { key := C.duckdb_get_map_key(m, i) diff --git a/profiling_test.go b/profiling_test.go index 92ff840a..74f10411 100644 --- a/profiling_test.go +++ b/profiling_test.go @@ -3,7 +3,6 @@ package duckdb import ( "context" "database/sql" - "fmt" "testing" "github.com/stretchr/testify/require" @@ -14,37 +13,40 @@ func TestProfiling(t *testing.T) { db, err := sql.Open("duckdb", "") require.NoError(t, err) - con, err := db.Conn(context.Background()) require.NoError(t, err) _, err = con.ExecContext(context.Background(), `PRAGMA enable_profiling = 'no_output'`) require.NoError(t, err) - _, err = con.ExecContext(context.Background(), `PRAGMA profiling_mode = 'detailed'`) require.NoError(t, err) - res, err := con.QueryContext(context.Background(), `SELECT range AS i FROM range(100) ORDER BY i`) require.NoError(t, err) - var info ProfilingInfo - err = con.Raw(func(driverConn any) error { - info, err = GetProfilingInfo(driverConn) - return err - }) + info, err := GetProfilingInfo(con) require.NoError(t, err) _, err = con.ExecContext(context.Background(), `PRAGMA disable_profiling`) require.NoError(t, err) - require.NoError(t, res.Close()) require.NoError(t, con.Close()) require.NoError(t, db.Close()) // Verify the metrics. - // TODO: currently failing due to C API bug. - fmt.Println(info) // Dummy print to use variable. - // require.NotEmpty(t, info.Metrics, "metrics must not be empty") - // require.NotEmpty(t, info.Children, "children must not be empty") - // require.NotEmpty(t, info.Children[0].Metrics, "child metrics must not be empty") + require.NotEmpty(t, info.Metrics, "metrics must not be empty") + require.NotEmpty(t, info.Children, "children must not be empty") + require.NotEmpty(t, info.Children[0].Metrics, "child metrics must not be empty") +} + +func TestErrProfiling(t *testing.T) { + t.Parallel() + db, err := sql.Open("duckdb", "") + require.NoError(t, err) + con, err := db.Conn(context.Background()) + require.NoError(t, err) + + _, err = GetProfilingInfo(con) + testError(t, err, errProfilingInfoEmpty.Error()) + require.NoError(t, con.Close()) + require.NoError(t, db.Close()) } diff --git a/scalar_udf_test.go b/scalar_udf_test.go index feb939fb..0a59b306 100644 --- a/scalar_udf_test.go +++ b/scalar_udf_test.go @@ -368,7 +368,7 @@ func TestANYScalarUDF(t *testing.T) { require.NoError(t, db.Close()) } -func TestScalarUDFErrors(t *testing.T) { +func TestErrScalarUDF(t *testing.T) { t.Parallel() db, err := sql.Open("duckdb", "") From ddeeff7503711cbb8b96d76c747045e2215fbd29 Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:09:19 +0200 Subject: [PATCH 7/8] nit --- errors.go | 16 +++++----------- profiling.go | 1 - 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/errors.go b/errors.go index 3c84364c..054ce8ec 100644 --- a/errors.go +++ b/errors.go @@ -84,21 +84,17 @@ var ( errUnsupportedMapKeyType = errors.New("MAP key type not supported") - errAppenderCreation = errors.New("could not create appender") - errAppenderInvalidCon = fmt.Errorf("%w: not a DuckDB driver connection", errAppenderCreation) - errAppenderClosedCon = fmt.Errorf("%w: appender creation on a closed connection", errAppenderCreation) - - errAppenderClose = errors.New("could not close appender") - errAppenderDoubleClose = fmt.Errorf("%w: already closed", errAppenderClose) - + errAppenderCreation = errors.New("could not create appender") + errAppenderClose = errors.New("could not close appender") + errAppenderDoubleClose = fmt.Errorf("%w: already closed", errAppenderClose) errAppenderAppendRow = errors.New("could not append row") errAppenderAppendAfterClose = fmt.Errorf("%w: appender already closed", errAppenderAppendRow) - - errAppenderFlush = errors.New("could not flush appender") + errAppenderFlush = errors.New("could not flush appender") errEmptyName = errors.New("empty name") 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") errScalarUDFCreate = errors.New("could not create scalar UDF") errScalarUDFNoName = fmt.Errorf("%w: missing name", errScalarUDFCreate) @@ -110,8 +106,6 @@ var ( errScalarUDFCreateSet = fmt.Errorf("could not create scalar UDF set") errScalarUDFAddToSet = fmt.Errorf("%w: could not add the function to the set", errScalarUDFCreateSet) - errSetSQLNULLValue = errors.New("cannot write to a NULL column") - errProfilingInfoEmpty = errors.New("no profiling information available for this connection") // Errors not covered in tests. diff --git a/profiling.go b/profiling.go index cd146a12..6fe8960a 100644 --- a/profiling.go +++ b/profiling.go @@ -50,7 +50,6 @@ func (info *ProfilingInfo) getMetrics(duckdbInfo C.duckdb_profiling_info) { cKey := C.duckdb_get_varchar(key) cValue := C.duckdb_get_varchar(value) - keyStr := C.GoString(cKey) valueStr := C.GoString(cValue) From 9c9511e1b19ea5249cbe8aec2af2e73617b98ba9 Mon Sep 17 00:00:00 2001 From: taniabogatsch <44262898+taniabogatsch@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:11:19 +0200 Subject: [PATCH 8/8] nit --- errors.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/errors.go b/errors.go index 054ce8ec..9131d0ab 100644 --- a/errors.go +++ b/errors.go @@ -82,8 +82,6 @@ var ( errInvalidCon = errors.New("not a DuckDB driver connection") errClosedCon = errors.New("closed connection") - errUnsupportedMapKeyType = errors.New("MAP key type not supported") - errAppenderCreation = errors.New("could not create appender") errAppenderClose = errors.New("could not close appender") errAppenderDoubleClose = fmt.Errorf("%w: already closed", errAppenderClose) @@ -91,10 +89,11 @@ var ( errAppenderAppendAfterClose = fmt.Errorf("%w: appender already closed", errAppenderAppendRow) errAppenderFlush = errors.New("could not flush appender") - errEmptyName = errors.New("empty name") - 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") + 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) + errInvalidDecimalScale = errors.New("the DECIMAL scale must be less than or equal to the width") + errSetSQLNULLValue = errors.New("cannot write to a NULL column") errScalarUDFCreate = errors.New("could not create scalar UDF") errScalarUDFNoName = fmt.Errorf("%w: missing name", errScalarUDFCreate)