mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
database/sql: support returning query database types
Creates a ColumnType structure that can be extended in to future. Allow drivers to implement what makes sense for the database. Fixes #16652 Change-Id: Ieb1fd64eac1460107b1d3474eba5201fa300a4ec Reviewed-on: https://go-review.googlesource.com/29961 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
2ecaaf18f9
commit
2a85578b0e
4 changed files with 259 additions and 11 deletions
|
|
@ -18,6 +18,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
|
|
@ -996,8 +997,8 @@ const maxBadConnRetries = 2
|
|||
// The caller must call the statement's Close method
|
||||
// when the statement is no longer needed.
|
||||
//
|
||||
// The provided context is for the preparation of the statment, not for the execution of
|
||||
// the statement.
|
||||
// The provided context is used for the preparation of the statement, not for the
|
||||
// execution of the statement.
|
||||
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
|
||||
var stmt *Stmt
|
||||
var err error
|
||||
|
|
@ -2033,6 +2034,107 @@ func (rs *Rows) Columns() ([]string, error) {
|
|||
return rs.rowsi.Columns(), nil
|
||||
}
|
||||
|
||||
// ColumnTypes returns column information such as column type, length,
|
||||
// and nullable. Some information may not be available from some drivers.
|
||||
func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
|
||||
if rs.isClosed() {
|
||||
return nil, errors.New("sql: Rows are closed")
|
||||
}
|
||||
if rs.rowsi == nil {
|
||||
return nil, errors.New("sql: no Rows available")
|
||||
}
|
||||
return rowsColumnInfoSetup(rs.rowsi), nil
|
||||
}
|
||||
|
||||
// ColumnType contains the name and type of a column.
|
||||
type ColumnType struct {
|
||||
name string
|
||||
|
||||
hasNullable bool
|
||||
hasLength bool
|
||||
hasPrecisionScale bool
|
||||
|
||||
nullable bool
|
||||
length int64
|
||||
databaseType string
|
||||
precision int64
|
||||
scale int64
|
||||
scanType reflect.Type
|
||||
}
|
||||
|
||||
// Name returns the name or alias of the column.
|
||||
func (ci *ColumnType) Name() string {
|
||||
return ci.name
|
||||
}
|
||||
|
||||
// Length returns the column type length for variable length column types such
|
||||
// as text and binary field types. If the type length is unbounded the value will
|
||||
// be math.MaxInt64 (any database limits will still apply).
|
||||
// If the column type is not variable length, such as an int, or if not supported
|
||||
// by the driver ok is false.
|
||||
func (ci *ColumnType) Length() (length int64, ok bool) {
|
||||
return ci.length, ci.hasLength
|
||||
}
|
||||
|
||||
// DecimalSize returns the scale and precision of a decimal type.
|
||||
// If not applicable or if not supported ok is false.
|
||||
func (ci *ColumnType) DecimalSize() (precision, scale int64, ok bool) {
|
||||
return ci.precision, ci.scale, ci.hasPrecisionScale
|
||||
}
|
||||
|
||||
// ScanType returns a Go type suitable for scanning into using Rows.Scan.
|
||||
// If a driver does not support this property ScanType will return
|
||||
// the type of an empty interface.
|
||||
func (ci *ColumnType) ScanType() reflect.Type {
|
||||
return ci.scanType
|
||||
}
|
||||
|
||||
// Nullable returns whether the column may be null.
|
||||
// If a driver does not support this property ok will be false.
|
||||
func (ci *ColumnType) Nullable() (nullable, ok bool) {
|
||||
return ci.nullable, ci.hasNullable
|
||||
}
|
||||
|
||||
// DatabaseTypeName returns the database system name of the column type. If an empty
|
||||
// string is returned the driver type name is not supported.
|
||||
// Consult your driver documentation for a list of driver data types. Length specifiers
|
||||
// are not included.
|
||||
// Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
|
||||
func (ci *ColumnType) DatabaseTypeName() string {
|
||||
return ci.databaseType
|
||||
}
|
||||
|
||||
func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType {
|
||||
names := rowsi.Columns()
|
||||
|
||||
list := make([]*ColumnType, len(names))
|
||||
for i := range list {
|
||||
ci := &ColumnType{
|
||||
name: names[i],
|
||||
}
|
||||
list[i] = ci
|
||||
|
||||
if prop, ok := rowsi.(driver.RowsColumnTypeScanType); ok {
|
||||
ci.scanType = prop.ColumnTypeScanType(i)
|
||||
} else {
|
||||
ci.scanType = reflect.TypeOf(new(interface{})).Elem()
|
||||
}
|
||||
if prop, ok := rowsi.(driver.RowsColumnTypeDatabaseTypeName); ok {
|
||||
ci.databaseType = prop.ColumnTypeDatabaseTypeName(i)
|
||||
}
|
||||
if prop, ok := rowsi.(driver.RowsColumnTypeLength); ok {
|
||||
ci.length, ci.hasLength = prop.ColumnTypeLength(i)
|
||||
}
|
||||
if prop, ok := rowsi.(driver.RowsColumnTypeNullable); ok {
|
||||
ci.nullable, ci.hasNullable = prop.ColumnTypeNullable(i)
|
||||
}
|
||||
if prop, ok := rowsi.(driver.RowsColumnTypePrecisionScale); ok {
|
||||
ci.precision, ci.scale, ci.hasPrecisionScale = prop.ColumnTypePrecisionScale(i)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Scan copies the columns in the current row into the values pointed
|
||||
// at by dest. The number of values in dest must be the same as the
|
||||
// number of columns in Rows.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue