Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for DuckDB Appender API #37

Merged
merged 8 commits into from
Feb 14, 2023

Conversation

panta
Copy link
Contributor

@panta panta commented Aug 2, 2022

Besides the support for the aforementioned Appender API, this also

  • adds explicit support for various numerical types (UTINYINT, USMALLINT, ...) in particular to add column type support
  • add more fuzzing tests for the various basic types
  • switch to use duckdb_open_ext() in place of duckdb_open() to be able to return error information

@panta panta changed the title Add support for DuckDB Appender APIcccccckliludifnfbjgfrnjflunlrbkfflilvbbbjkdh Add support for DuckDB Appender API Aug 2, 2022
@marcboeker
Copy link
Owner

@panta Thank you for this PR. Please give me some days to review this, as I'm currently quite busy.

@panta
Copy link
Contributor Author

panta commented Aug 4, 2022

@panta Thank you for this PR. Please give me some days to review this, as I'm currently quite busy.

Sure, thanks. Just a thing I forgot to mention: tests for the appender use filesystem backed DBs (using temporary files), because the appender API doesn't seem to work with memory DBs.

appender.go Outdated

switch v := v.(type) {
case uint8:
if rv := C.duckdb_append_uint8(*a.appender, C.uint8_t(v)); rv == C.DuckDBError {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to define rv outside of the switch statement and just do a

rv := C.duckdb_append_uint8(*a.appender, C.uint8_t(v))

and after the switch statement check rv for an error and in case return the error? This would probably reduce some duplicate code except for string and time.Time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for the feedback, and I apologize for the delay. In the next few days I'll resume the work on this and address the issues with the PR. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed an additional commit that addresses all the points.
If you deem it ok, I could squash the appender commits into one before merging, so we have a cleaner history.
Please let me know.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the additional commits. There is currently one big PR ongoing, which should be merged shortly. I would suggest to wait for the merge and check, if your modifications still work. Would that be OK for you?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@panta The PR has been merged. Could you please check if your branch still works with the modifications. Thanks 🙂

appender_test.go Outdated
)

const (
testAppenderTableDdl = `CREATE TABLE appdata(id BIGINT, u8 UTINYINT, i8 TINYINT, u16 USMALLINT, i16 SMALLINT,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to call it DDL instead of Ddl as per the Go naming convention for acronyms.

appender.go Outdated
"unsafe"
)

type appender struct {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make sense to make the appender exported? Then it would also appear in the documentation.

appender.go Outdated
Comment on lines 36 to 39
// if state := C.duckdb_appender_flush(*a.appender); state == C.DuckDBError {
// dbErr := C.GoString(C.duckdb_appender_error(*a.appender))
// return errors.New(dbErr)
// }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this part as duckdb_appender_destroy should be sufficient?

connection.go Outdated
return &appender{c: c, schema: schema, table: table, appender: &a}, nil
}

func Appender(dbconn driver.Conn, schema string, table string) (*appender, error) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to add a NewAppenderFromConn(conn driver.Conn, schema, table string) (*Appender, error) method to the appender.go and move the code from (c *conn) Appender() there. This would keep the current DuckDB implementation close to the original database/sql design idea and all extensions, like the appender, would be more separated. What do you think about this?

appender.go Outdated
return fmt.Errorf("couldn't append parameter %d (type %T)", i, v)
}
case []byte:
if v == nil {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this already checked for in line 58?

appender_test.go Outdated

appender, err := Appender(llConn, "", "appdata")
require.NoError(t, err)
// defer appender.Close()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be more safe than a manual appender.Close() in line 183?

appender_test.go Outdated
return &res
}

func TestAppenderSimple(t *testing.T) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could only use TestRandomizedAppender instead of TestAppenderSimple as it already covers everything that the simple test case does.

@panta panta force-pushed the panta/feature/appender-support branch 2 times, most recently from 711c21f to ef45a79 Compare October 14, 2022 09:37
… return meaningful error messages in case of error.
* Reduce code duplication in appender.AppendRowArray()
* Rename testAppenderTableDdl to testAppenderTableDDL.
* Rename Appender() to NewAppenderFromConn().
* Move NewAppenderFromConn() to appender.go and remove conn.Appender().
* Remove commented unnecessary code from appender.Close()
* Export the appender type (rename it from appender to Appender).
* Add documentation comments to Appender and its methods.
* FIX: typecast the driver connection interface to the proper interface before passing to NewAppenderFromConn().
* Remove reduntant nil handling in AppendRowArray().
* Remove unnecessary TestAppenderSimple (the same test cases are covered by the more thorough TestRandomizedAppender).
* Remove commented defer and add an explanation for the explicit Close() call.
@panta panta force-pushed the panta/feature/appender-support branch from ef45a79 to e7bf1e1 Compare October 17, 2022 07:39
@marcboeker
Copy link
Owner

Thanks for all the updates and sorry for my late response. As the PR got quite big I would suggest to extract the testing part to a separate PR and start with a smaller PR just for the appender API. I've seen, that there are merge conflicts. Maybe you could merge the current master beforehand.

Regarding the tests: I don't quite see a huge difference compared to the current tests. What do you think about using real fuzzing provided by Go 1.18?

@marcboeker marcboeker mentioned this pull request Feb 9, 2023
@flarco
Copy link
Contributor

flarco commented Feb 9, 2023

Perhaps I can help get this to a merging state. @marcboeker you stated to split the tests and api changes into two different PRs. I can do that. Anything else you think needs to be done?

@marcboeker
Copy link
Owner

@flarco Sounds great. I think it would make sense to merge the current master into this branch, as there are could be some breaking changes.

The idea behind splitting the tests was, that some tests are not related to the appender feature. For now I would suggest to exclude non related tests and only keep the appender relates ones in the PR.

@flarco
Copy link
Contributor

flarco commented Feb 10, 2023

@marcboeker opened #71 and removed the non-appender related tests. master was merged into it and there are no conflicts at the moment. Please review and approve.

@marcboeker marcboeker merged commit 9916032 into marcboeker:master Feb 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants