mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 03:18:24 +00:00 
			
		
		
		
	Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
		
			
				
	
	
		
			224 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // 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
 | |
| 	}
 | |
| 
 | |
| 	// flip the buffer for this connection if we need to drain it.
 | |
| 	// note that for a successful query (i.e. one where rows.next()
 | |
| 	// has been called until it returns false), `rows.mc` will be nil
 | |
| 	// by the time the user calls `(*Rows).Close`, so we won't reach this
 | |
| 	// see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47
 | |
| 	mc.buf.flip()
 | |
| 
 | |
| 	// 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
 | |
| }
 |