-
Notifications
You must be signed in to change notification settings - Fork 12
Support new prepared statement metadata functions #51
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
base: main
Are you sure you want to change the base?
Changes from all commits
101b338
290bc97
ec3b96a
a0468f0
8187ed3
69b9fdf
0853903
e5b9c41
81a60f2
ddf3368
a49e3b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,6 +54,17 @@ type Stmt struct { | |
| rows bool | ||
| } | ||
|
|
||
| // checkState checks if the statement is closed or uninitialized. | ||
| func (s *Stmt) checkState() error { | ||
| if s.closed { | ||
| return errClosedStmt | ||
| } | ||
| if s.preparedStmt == nil { | ||
| return errUninitializedStmt | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // Close the statement. | ||
| // Implements the driver.Stmt interface. | ||
| func (s *Stmt) Close() error { | ||
|
|
@@ -81,11 +92,8 @@ func (s *Stmt) NumInput() int { | |
|
|
||
| // ParamName returns the name of the parameter at the given index (1-based). | ||
| func (s *Stmt) ParamName(n int) (string, error) { | ||
| if s.closed { | ||
| return "", errClosedStmt | ||
| } | ||
| if s.preparedStmt == nil { | ||
| return "", errUninitializedStmt | ||
| if err := s.checkState(); err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| count := mapping.NParams(*s.preparedStmt) | ||
|
|
@@ -99,11 +107,8 @@ func (s *Stmt) ParamName(n int) (string, error) { | |
|
|
||
| // ParamType returns the expected type of the parameter at the given index (1-based). | ||
| func (s *Stmt) ParamType(n int) (Type, error) { | ||
| if s.closed { | ||
| return TYPE_INVALID, errClosedStmt | ||
| } | ||
| if s.preparedStmt == nil { | ||
| return TYPE_INVALID, errUninitializedStmt | ||
| if err := s.checkState(); err != nil { | ||
| return TYPE_INVALID, err | ||
| } | ||
|
|
||
| count := mapping.NParams(*s.preparedStmt) | ||
|
|
@@ -117,11 +122,8 @@ func (s *Stmt) ParamType(n int) (Type, error) { | |
|
|
||
| func (s *Stmt) paramLogicalType(n int) (mapping.LogicalType, error) { | ||
| var lt mapping.LogicalType | ||
| if s.closed { | ||
| return lt, errClosedStmt | ||
| } | ||
| if s.preparedStmt == nil { | ||
| return lt, errUninitializedStmt | ||
| if err := s.checkState(); err != nil { | ||
| return lt, err | ||
| } | ||
|
|
||
| count := mapping.NParams(*s.preparedStmt) | ||
|
|
@@ -134,11 +136,8 @@ func (s *Stmt) paramLogicalType(n int) (mapping.LogicalType, error) { | |
|
|
||
| // StatementType returns the type of the statement. | ||
| func (s *Stmt) StatementType() (StmtType, error) { | ||
| if s.closed { | ||
| return STATEMENT_TYPE_INVALID, errClosedStmt | ||
| } | ||
| if s.preparedStmt == nil { | ||
| return STATEMENT_TYPE_INVALID, errUninitializedStmt | ||
| if err := s.checkState(); err != nil { | ||
| return STATEMENT_TYPE_INVALID, err | ||
| } | ||
|
|
||
| t := mapping.PreparedStatementType(*s.preparedStmt) | ||
|
|
@@ -470,6 +469,77 @@ func (s *Stmt) ExecContext(ctx context.Context, nargs []driver.NamedValue) (driv | |
| return &result{ra}, nil | ||
| } | ||
|
|
||
| // ColumnCount returns the number of columns that will be returned by executing the prepared statement. | ||
| // If any of the column types is invalid (which can happen when the type is ambiguous), the result will be 1. | ||
| // Returns an error if the statement is closed or uninitialized. | ||
| func (s *Stmt) ColumnCount() (int, error) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add tests here? For both error paths, and the happy path?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we return |
||
| if err := s.checkState(); err != nil { | ||
| return 0, err | ||
| } | ||
|
|
||
| count := mapping.PreparedStatementColumnCount(*s.preparedStmt) | ||
| return int(count), nil | ||
| } | ||
|
|
||
| // ColumnType returns the type of the column at the given index (0-based). | ||
| // Returns TYPE_INVALID and a columnIndexError if the column is out of range. | ||
| // Returns an error if the statement is closed or uninitialized. | ||
| func (s *Stmt) ColumnType(n int) (Type, error) { | ||
| if err := s.checkState(); err != nil { | ||
| return TYPE_INVALID, err | ||
| } | ||
|
|
||
| count := mapping.PreparedStatementColumnCount(*s.preparedStmt) | ||
| if n < 0 || n >= int(count) { | ||
| return TYPE_INVALID, getError(errAPI, columnIndexError(n, uint64(count))) | ||
| } | ||
|
|
||
| t := mapping.PreparedStatementColumnType(*s.preparedStmt, mapping.IdxT(n)) | ||
| return t, nil | ||
| } | ||
|
|
||
| // ColumnTypeInfo returns the TypeInfo of the column at the given index (0-based). | ||
| // TypeInfo provides detailed type information including nested structures, DECIMAL precision, | ||
| // ENUM values, etc. | ||
| // Returns a TypeInfo with internalType TYPE_INVALID and a columnIndexError if the column is out of range. | ||
| // Returns an error if the statement is closed or uninitialized. | ||
| func (s *Stmt) ColumnTypeInfo(n int) (TypeInfo, error) { | ||
| if err := s.checkState(); err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| count := mapping.PreparedStatementColumnCount(*s.preparedStmt) | ||
| if n < 0 || n >= int(count) { | ||
| return nil, getError(errAPI, columnIndexError(n, uint64(count))) | ||
| } | ||
|
|
||
| lt := mapping.PreparedStatementColumnLogicalType(*s.preparedStmt, mapping.IdxT(n)) | ||
| defer mapping.DestroyLogicalType(<) | ||
|
|
||
| return NewTypeInfoFromLogicalType(lt) | ||
| } | ||
|
|
||
| // ColumnName returns the name of the column at the given index (0-based). | ||
| // Returns "" and a columnIndexError if the column is out of range. | ||
| // Returns an error if the statement is closed or uninitialized. | ||
| func (s *Stmt) ColumnName(n int) (string, error) { | ||
| if err := s.checkState(); err != nil { | ||
| return "", err | ||
| } | ||
|
|
||
| count := mapping.PreparedStatementColumnCount(*s.preparedStmt) | ||
| if n < 0 || n >= int(count) { | ||
| return "", getError(errAPI, columnIndexError(n, uint64(count))) | ||
| } | ||
|
|
||
| name := mapping.PreparedStatementColumnName(*s.preparedStmt, mapping.IdxT(n)) | ||
| // C API returns nullptr for out-of-range indices | ||
| if name == "" { | ||
| return "", nil | ||
| } | ||
| return name, nil | ||
|
Comment on lines
+537
to
+540
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't these paths the same? |
||
| } | ||
|
|
||
| // ExecBound executes a bound query that doesn't return rows, such as an INSERT or UPDATE. | ||
| // It can only be used after Bind has been called. | ||
| // WARNING: This is a low-level API and should be used with caution. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.