mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
4.3 KiB
216 lines
4.3 KiB
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package |
|
// |
|
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. |
|
// |
|
// This Source Code Form is subject to the terms of the Mozilla Public |
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
// You can obtain one at http://mozilla.org/MPL/2.0/. |
|
|
|
package mysql |
|
|
|
import ( |
|
"database/sql/driver" |
|
"io" |
|
"math" |
|
"reflect" |
|
) |
|
|
|
type resultSet struct { |
|
columns []mysqlField |
|
columnNames []string |
|
done bool |
|
} |
|
|
|
type mysqlRows struct { |
|
mc *mysqlConn |
|
rs resultSet |
|
finish func() |
|
} |
|
|
|
type binaryRows struct { |
|
mysqlRows |
|
} |
|
|
|
type textRows struct { |
|
mysqlRows |
|
} |
|
|
|
func (rows *mysqlRows) Columns() []string { |
|
if rows.rs.columnNames != nil { |
|
return rows.rs.columnNames |
|
} |
|
|
|
columns := make([]string, len(rows.rs.columns)) |
|
if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { |
|
for i := range columns { |
|
if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { |
|
columns[i] = tableName + "." + rows.rs.columns[i].name |
|
} else { |
|
columns[i] = rows.rs.columns[i].name |
|
} |
|
} |
|
} else { |
|
for i := range columns { |
|
columns[i] = rows.rs.columns[i].name |
|
} |
|
} |
|
|
|
rows.rs.columnNames = columns |
|
return columns |
|
} |
|
|
|
func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { |
|
return rows.rs.columns[i].typeDatabaseName() |
|
} |
|
|
|
// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { |
|
// return int64(rows.rs.columns[i].length), true |
|
// } |
|
|
|
func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { |
|
return rows.rs.columns[i].flags&flagNotNULL == 0, true |
|
} |
|
|
|
func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { |
|
column := rows.rs.columns[i] |
|
decimals := int64(column.decimals) |
|
|
|
switch column.fieldType { |
|
case fieldTypeDecimal, fieldTypeNewDecimal: |
|
if decimals > 0 { |
|
return int64(column.length) - 2, decimals, true |
|
} |
|
return int64(column.length) - 1, decimals, true |
|
case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: |
|
return decimals, decimals, true |
|
case fieldTypeFloat, fieldTypeDouble: |
|
if decimals == 0x1f { |
|
return math.MaxInt64, math.MaxInt64, true |
|
} |
|
return math.MaxInt64, decimals, true |
|
} |
|
|
|
return 0, 0, false |
|
} |
|
|
|
func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { |
|
return rows.rs.columns[i].scanType() |
|
} |
|
|
|
func (rows *mysqlRows) Close() (err error) { |
|
if f := rows.finish; f != nil { |
|
f() |
|
rows.finish = nil |
|
} |
|
|
|
mc := rows.mc |
|
if mc == nil { |
|
return nil |
|
} |
|
if err := mc.error(); err != nil { |
|
return err |
|
} |
|
|
|
// Remove unread packets from stream |
|
if !rows.rs.done { |
|
err = mc.readUntilEOF() |
|
} |
|
if err == nil { |
|
if err = mc.discardResults(); err != nil { |
|
return err |
|
} |
|
} |
|
|
|
rows.mc = nil |
|
return err |
|
} |
|
|
|
func (rows *mysqlRows) HasNextResultSet() (b bool) { |
|
if rows.mc == nil { |
|
return false |
|
} |
|
return rows.mc.status&statusMoreResultsExists != 0 |
|
} |
|
|
|
func (rows *mysqlRows) nextResultSet() (int, error) { |
|
if rows.mc == nil { |
|
return 0, io.EOF |
|
} |
|
if err := rows.mc.error(); err != nil { |
|
return 0, err |
|
} |
|
|
|
// Remove unread packets from stream |
|
if !rows.rs.done { |
|
if err := rows.mc.readUntilEOF(); err != nil { |
|
return 0, err |
|
} |
|
rows.rs.done = true |
|
} |
|
|
|
if !rows.HasNextResultSet() { |
|
rows.mc = nil |
|
return 0, io.EOF |
|
} |
|
rows.rs = resultSet{} |
|
return rows.mc.readResultSetHeaderPacket() |
|
} |
|
|
|
func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { |
|
for { |
|
resLen, err := rows.nextResultSet() |
|
if err != nil { |
|
return 0, err |
|
} |
|
|
|
if resLen > 0 { |
|
return resLen, nil |
|
} |
|
|
|
rows.rs.done = true |
|
} |
|
} |
|
|
|
func (rows *binaryRows) NextResultSet() error { |
|
resLen, err := rows.nextNotEmptyResultSet() |
|
if err != nil { |
|
return err |
|
} |
|
|
|
rows.rs.columns, err = rows.mc.readColumns(resLen) |
|
return err |
|
} |
|
|
|
func (rows *binaryRows) Next(dest []driver.Value) error { |
|
if mc := rows.mc; mc != nil { |
|
if err := mc.error(); err != nil { |
|
return err |
|
} |
|
|
|
// Fetch next row from stream |
|
return rows.readRow(dest) |
|
} |
|
return io.EOF |
|
} |
|
|
|
func (rows *textRows) NextResultSet() (err error) { |
|
resLen, err := rows.nextNotEmptyResultSet() |
|
if err != nil { |
|
return err |
|
} |
|
|
|
rows.rs.columns, err = rows.mc.readColumns(resLen) |
|
return err |
|
} |
|
|
|
func (rows *textRows) Next(dest []driver.Value) error { |
|
if mc := rows.mc; mc != nil { |
|
if err := mc.error(); err != nil { |
|
return err |
|
} |
|
|
|
// Fetch next row from stream |
|
return rows.readRow(dest) |
|
} |
|
return io.EOF |
|
}
|
|
|