diff --git a/errors_test.go b/errors_test.go index bb74de0f..52810782 100644 --- a/errors_test.go +++ b/errors_test.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "database/sql/driver" + "errors" "strings" "testing" @@ -304,7 +305,7 @@ func TestErrAPISetValue(t *testing.T) { func TestDuckDBErrors(t *testing.T) { db := openDB(t) defer db.Close() - createTable(db, t, `CREATE TABLE duckdberror_test(bar VARCHAR UNIQUE, baz INT32)`) + createTable(db, t, `CREATE TABLE duckdberror_test(bar VARCHAR UNIQUE, baz INT32, u_1 UNION("string" VARCHAR))`) _, err := db.Exec("INSERT INTO duckdberror_test(bar, baz) VALUES('bar', 0)") require.NoError(t, err) @@ -316,10 +317,6 @@ func TestDuckDBErrors(t *testing.T) { tpl: "SELECT * FROM not_exist WHERE baz=0", errTyp: ErrorTypeCatalog, }, - { - tpl: "COPY duckdberror_test FROM 'test.json'", - errTyp: ErrorTypeCatalog, - }, { tpl: "SELECT * FROM duckdberror_test WHERE col=?", errTyp: ErrorTypeBinder, @@ -344,14 +341,30 @@ func TestDuckDBErrors(t *testing.T) { tpl: "LOAD not_exist", errTyp: ErrorTypeIO, }, + { + tpl: "SELECT array_length(array_value(array_value(1, 2, 2), array_value(3, 4, 3)), 3)", + errTyp: ErrorTypeOutOfRange, + }, + { + tpl: "SELECT '010110'::BIT & '11000'::BIT", + errTyp: ErrorTypeInvalidInput, + }, + { + tpl: "SET external_threads=-1", + errTyp: ErrorTypeSyntax, + }, + { + tpl: "CREATE UNIQUE INDEX idx ON duckdberror_test(u_1)", + errTyp: ErrorTypeInvalidType, + }, } for _, tc := range testCases { _, err := db.Exec(tc.tpl) de, ok := err.(*Error) if !ok { - require.Fail(t, "error type is not DuckDBError", "tql: %s\ngot: %#v", tc.tpl, err) + require.Fail(t, "error type is not (*duckdb.Error)", "tql: %s\ngot: %#v", tc.tpl, err) } - require.Equal(t, de.Type, tc.errTyp, "tql: %s\nactual error msg: %s", tc.tpl, de.Msg) + require.Equal(t, de.Type, tc.errTyp, "tpl: %s\nactual error msg: %s", tc.tpl, de.Msg) } } @@ -386,3 +399,41 @@ func TestGetDuckDBError(t *testing.T) { require.Equal(t, tc, err) } } + +type wrappedDuckDBError struct { + e *Error +} + +func (w *wrappedDuckDBError) Error() string { + return w.e.Error() +} +func (w *wrappedDuckDBError) Unwrap() error { + return w.e +} + +func TestGetDuckDBErrorIs(t *testing.T) { + const errMsg = "Out of Range Error: Overflow" + outOfRangeErr1 := &Error{ + Type: ErrorTypeOutOfRange, + Msg: errMsg, + } + outOfRangeErr1Copy := &Error{ + Type: ErrorTypeOutOfRange, + Msg: errMsg, + } + outOfRangeErr2 := &Error{ + Type: ErrorTypeOutOfRange, + Msg: "Out of Range Error: array_length dimension '3' out of range (min: '1', max: '2')", + } + invalidInputErr := &Error{ + Type: ErrorTypeInvalidInput, + Msg: "Invalid Input Error: Map keys can not be NULL", + } + + require.ErrorIs(t, outOfRangeErr1, outOfRangeErr1) + require.ErrorIs(t, outOfRangeErr1Copy, outOfRangeErr1) + require.ErrorIs(t, &wrappedDuckDBError{outOfRangeErr1Copy}, outOfRangeErr1) + require.Equal(t, false, errors.Is(outOfRangeErr2, outOfRangeErr1)) + require.Equal(t, false, errors.Is(invalidInputErr, outOfRangeErr1)) + require.Equal(t, false, errors.Is(errors.New(errMsg), outOfRangeErr1)) +} diff --git a/statement_test.go b/statement_test.go index de3db830..5ebca8a1 100644 --- a/statement_test.go +++ b/statement_test.go @@ -84,7 +84,7 @@ func TestPrepareWithError(t *testing.T) { stmt, err := db.Prepare(tc.tpl) if err != nil { if _, ok := err.(*Error); !ok { - require.Fail(t, "error type is not DuckDBError") + require.Fail(t, "error type is not (*duckdb.Error)") } require.ErrorContains(t, err, tc.err) continue