Skip to content
This repository was archived by the owner on Oct 20, 2025. It is now read-only.

Conversation

@fanyang01
Copy link
Contributor

Hi @taniabogatsch,

This PR exposes conn and stmt, enabling access according to Go’s visibility rules. Additionally, it makes more information about stmt accessible.

The motivation for this comes from the MyDuck Server project, which I’m actively developing. MyDuck Server allows users to run DuckDB as a server that supports MySQL and Postgres wire protocols, leveraging go-duckdb extensively—and it’s been working well so far. Thanks for your continued maintenance!

Currently, I'm implementing prepared statement support for the Postgres protocol, which requires access to parameter and return types for prepared statements (the client sends Describe messages to the server to retrieve this info). With the changes in this PR, I would be able to retrieve parameter types using the Conn.Raw method.

However, the C API still lacks access to the return types of a prepared statement (though it is available in the C++ API). I’m considering a workaround, like executing the query with LIMIT 0 to infer return types.

Thanks for considering this PR!

@taniabogatsch
Copy link
Collaborator

Hi @fanyang01, thanks for your PR :) I don't quite follow how you call your new functions by exposing the raw driver connection. How do you retrieve the prepared Stmt? I.e., could you provide some tests for:

  • func (s *Stmt) ParamName(n int) string
  • func (s *Stmt) ParamType(n int) Type
  • func (s *Stmt) StatementType() StmtType

That would help me better understand why you want to expose both Conn and Stmt.

However, the C API still lacks access to the return types of a prepared statement (though it is available in the C++ API). I’m considering a workaround, like executing the query with LIMIT 0 to infer return types.

PRs against duckdb main are always welcome - you could tag me on it.

@taniabogatsch
Copy link
Collaborator

In general, I am not opposed to exposing the connection and the statement.
Other database drivers (I checked go-sqlite3) seem to do the same.

@fanyang01
Copy link
Contributor Author

Tests added :) In short, this PR allows me to do something like:

c, _ := db.Conn(context.Background())
c.Raw(func (driverConn any) error {
    conn := driverConn.(*duckdb.Conn)
    s, _ := conn.Prepare("SELECT ... WHERE a = $1")
    stmt := s.(*duckdb.Stmt)
    stmt.StatementType()
    stmt.ParamName(1)
    stmt.ParamType(1)
})

PRs against duckdb main are always welcome - you could tag me on it.

Sure, stay tuned!

Copy link
Collaborator

@taniabogatsch taniabogatsch left a comment

Choose a reason for hiding this comment

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

Hi, @fanyang01, thanks for adding the tests. I've had another more detailed pass over your changes. Thanks also for adding more comments to the existing functions!

One thing I was wondering: this PR is becoming quite involved and touches a lot of critical-ish code paths. Would it be possible to split it into a few smaller PRs? E.g.,

  1. Expose Conn and Stmt and the comments.
  2. ParamName, ParamType, and StatementType and their tests.
  3. New exposed low-level API calls for binding and their tests.

That would make it easier for me to review and know what's happening - no worries if it is too much work. Then, we'll work with this PR. :smiling:

Comment on lines +119 to +121
if s.closed {
return errors.Join(errCouldNotBind, errClosedCon)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing test.

Comment on lines -198 to +311
func (s *stmt) QueryContext(ctx context.Context, nargs []driver.NamedValue) (driver.Rows, error) {
res, err := s.execute(ctx, nargs)
if err != nil {
// QueryContext executes a query that may return rows, such as a SELECT.
// It implements the driver.StmtQueryContext interface.
func (s *Stmt) QueryContext(ctx context.Context, nargs []driver.NamedValue) (driver.Rows, error) {
if err := s.Bind(nargs); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Am I missing something here? It looks like we changed the behavior of QueryContext: Instead of execute, it now performs Bind and QueryBound.

@fanyang01
Copy link
Contributor Author

Hi @taniabogatsch, thank you very much for the detailed review! I will split this PR into several smaller ones, as you suggested, later this week.

@fanyang01
Copy link
Contributor Author

Splitted into #319, #324, and #333

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants