package pgdriver

import (
	
	
	
	
	
	
	
	
	
	
	
	
	
)

func () {
	sql.Register("pg", NewDriver())
}

type logging interface {
	Printf(ctx context.Context, format string, v ...interface{})
}

type logger struct {
	log *log.Logger
}

func ( *logger) ( context.Context,  string,  ...interface{}) {
	_ = .log.Output(2, fmt.Sprintf(, ...))
}

var Logger logging = &logger{
	log: log.New(os.Stderr, "pgdriver: ", log.LstdFlags|log.Lshortfile),
}

//------------------------------------------------------------------------------

type Driver struct {
	connector *Connector
}

var _ driver.DriverContext = (*Driver)(nil)

func () Driver {
	return Driver{}
}

func ( Driver) ( string) (driver.Connector, error) {
	,  := parseDSN()
	if  != nil {
		return nil, 
	}
	return NewConnector(...), nil
}

func ( Driver) ( string) (driver.Conn, error) {
	,  := .OpenConnector()
	if  != nil {
		return nil, 
	}
	return .Connect(context.TODO())
}

//------------------------------------------------------------------------------

type DriverStats struct {
	Queries uint64
	Errors  uint64
}

type Connector struct {
	cfg *Config

	stats DriverStats
}

func ( ...DriverOption) *Connector {
	 := &Connector{cfg: newDefaultConfig()}
	for ,  := range  {
		()
	}
	return 
}

var _ driver.Connector = (*Connector)(nil)

func ( *Connector) ( context.Context) (driver.Conn, error) {
	if  := .cfg.verify();  != nil {
		return nil, 
	}

	return newConn(, )
}

func ( *Connector) () driver.Driver {
	return Driver{connector: }
}

func ( *Connector) () *Config {
	return .cfg
}

func ( *Connector) () DriverStats {
	return DriverStats{
		Queries: atomic.LoadUint64(&.stats.Queries),
		Errors:  atomic.LoadUint64(&.stats.Errors),
	}
}

//------------------------------------------------------------------------------

type Conn struct {
	driver *Connector

	netConn net.Conn
	rd      *reader

	processID int32
	secretKey int32

	stmtCount int

	closed int32
}

func ( context.Context,  *Connector) (*Conn, error) {
	,  := .cfg.Dialer(, .cfg.Network, .cfg.Addr)
	if  != nil {
		return nil, 
	}

	 := &Conn{
		driver:  ,
		netConn: ,
		rd:      newReader(),
	}

	if .driver.cfg.TLSConfig != nil {
		if  := enableSSL(, , .driver.cfg.TLSConfig);  != nil {
			return nil, 
		}
	}

	if  := startup(, );  != nil {
		return nil, 
	}

	return , nil
}

func ( *Conn) ( context.Context,  time.Duration) *reader {
	.setReadDeadline(, )
	return .rd
}

func ( *Conn) ( context.Context,  *writeBuffer) error {
	.setWriteDeadline(, -1)

	,  := .netConn.Write(.Bytes)
	if  != nil {
		if  == 0 {
			return driver.ErrBadConn
		}
		return 
	}
	return nil
}

var _ driver.Conn = (*Conn)(nil)

func ( *Conn) ( string) (driver.Stmt, error) {
	if .isClosed() {
		return nil, driver.ErrBadConn
	}

	 := context.TODO()

	 := fmt.Sprintf("pgdriver-%d", .stmtCount)
	.stmtCount++

	if  := writeParseDescribeSync(, , , );  != nil {
		return nil, 
	}

	,  := readParseDescribeSync(, )
	if  != nil {
		return nil, 
	}

	return newStmt(, , ), nil
}

func ( *Conn) () error {
	if !atomic.CompareAndSwapInt32(&.closed, 0, 1) {
		return nil
	}
	return .netConn.Close()
}

func ( *Conn) () bool {
	return atomic.LoadInt32(&.closed) == 1
}

func ( *Conn) () (driver.Tx, error) {
	return .BeginTx(context.Background(), driver.TxOptions{})
}

var _ driver.ConnBeginTx = (*Conn)(nil)

func ( *Conn) ( context.Context,  driver.TxOptions) (driver.Tx, error) {
	// No need to check if the conn is closed. ExecContext below handles that.

	if sql.IsolationLevel(.Isolation) != sql.LevelDefault {
		return nil, errors.New("pgdriver: custom IsolationLevel is not supported")
	}
	if .ReadOnly {
		return nil, errors.New("pgdriver: ReadOnly transactions are not supported")
	}

	if ,  := .ExecContext(, "BEGIN", nil);  != nil {
		return nil, 
	}
	return tx{cn: }, nil
}

var _ driver.ExecerContext = (*Conn)(nil)

func ( *Conn) (
	 context.Context,  string,  []driver.NamedValue,
) (driver.Result, error) {
	if .isClosed() {
		return nil, driver.ErrBadConn
	}
	,  := .exec(, , )
	if  != nil {
		return nil, .checkBadConn()
	}
	return , nil
}

func ( *Conn) (
	 context.Context,  string,  []driver.NamedValue,
) (driver.Result, error) {
	,  := formatQuery(, )
	if  != nil {
		return nil, 
	}
	if  := writeQuery(, , );  != nil {
		return nil, 
	}
	return readQuery(, )
}

var _ driver.QueryerContext = (*Conn)(nil)

func ( *Conn) (
	 context.Context,  string,  []driver.NamedValue,
) (driver.Rows, error) {
	if .isClosed() {
		return nil, driver.ErrBadConn
	}
	,  := .query(, , )
	if  != nil {
		return nil, .checkBadConn()
	}
	return , nil
}

func ( *Conn) (
	 context.Context,  string,  []driver.NamedValue,
) (driver.Rows, error) {
	,  := formatQuery(, )
	if  != nil {
		return nil, 
	}
	if  := writeQuery(, , );  != nil {
		return nil, 
	}
	return readQueryData(, )
}

var _ driver.Pinger = (*Conn)(nil)

func ( *Conn) ( context.Context) error {
	,  := .ExecContext(, "SELECT 1", nil)
	return 
}

func ( *Conn) ( context.Context,  time.Duration) {
	if  == -1 {
		 = .driver.cfg.ReadTimeout
	}
	_ = .netConn.SetReadDeadline(.deadline(, ))
}

func ( *Conn) ( context.Context,  time.Duration) {
	if  == -1 {
		 = .driver.cfg.WriteTimeout
	}
	_ = .netConn.SetWriteDeadline(.deadline(, ))
}

func ( *Conn) ( context.Context,  time.Duration) time.Time {
	,  := .Deadline()
	if ! {
		if  == 0 {
			return time.Time{}
		}
		return time.Now().Add()
	}

	if  == 0 {
		return 
	}
	if  := time.Now().Add(); .Before() {
		return 
	}
	return 
}

var _ driver.Validator = (*Conn)(nil)

func ( *Conn) () bool {
	return !.isClosed()
}

func ( *Conn) ( error) error {
	if isBadConn(, false) {
		// Close and return driver.ErrBadConn next time the conn is used.
		_ = .Close()
	}
	// Always return the original error.
	return 
}

//------------------------------------------------------------------------------

type rows struct {
	cn       *Conn
	rowDesc  *rowDescription
	reusable bool
	closed   bool
}

var _ driver.Rows = (*rows)(nil)

func ( *Conn,  *rowDescription,  bool) *rows {
	return &rows{
		cn:       ,
		rowDesc:  ,
		reusable: ,
	}
}

func ( *rows) () []string {
	if .closed || .rowDesc == nil {
		return nil
	}
	return .rowDesc.names
}

func ( *rows) () error {
	if .closed {
		return nil
	}
	defer .close()

	for {
		switch  := .Next(nil);  {
		case nil, io.EOF:
			return nil
		default: // unexpected error
			_ = .cn.Close()
			return 
		}
	}
}

func ( *rows) () {
	.closed = true

	if .rowDesc != nil {
		if .reusable {
			rowDescPool.Put(.rowDesc)
		}
		.rowDesc = nil
	}
}

func ( *rows) ( []driver.Value) error {
	if .closed {
		return io.EOF
	}

	,  := .next()
	if  == io.EOF {
		return io.ErrUnexpectedEOF
	} else if  != nil {
		return 
	}
	if  {
		return io.EOF
	}
	return nil
}

func ( *rows) ( []driver.Value) ( bool,  error) {
	 := .cn.reader(context.TODO(), -1)
	var  error
	for {
		, ,  := readMessageType()
		if  != nil {
			return false, 
		}

		switch  {
		case dataRowMsg:
			return false, .readDataRow(, )
		case commandCompleteMsg:
			if  := .Discard();  != nil {
				return false, 
			}
		case readyForQueryMsg:
			.close()

			if  := .Discard();  != nil {
				return false, 
			}

			if  != nil {
				return false, 
			}
			return true, nil
		case errorResponseMsg:
			,  := readError()
			if  != nil {
				return false, 
			}
			if  == nil {
				 = 
			}
		default:
			return false, fmt.Errorf("pgdriver: Next: unexpected message %q", )
		}
	}
}

func ( *rows) ( *reader,  []driver.Value) error {
	,  := readInt16()
	if  != nil {
		return 
	}

	if len() != int() {
		return fmt.Errorf("pgdriver: query returned %d columns, but Scan dest has %d items",
			, len())
	}

	for  := int16(0);  < ; ++ {
		,  := readInt32()
		if  != nil {
			return 
		}

		,  := readColumnValue(, .rowDesc.types[], int())
		if  != nil {
			return 
		}

		if  != nil {
			[] = 
		}
	}

	return nil
}

//------------------------------------------------------------------------------

func ( []byte) (driver.RowsAffected, error) {
	 := bytes.LastIndexByte(, ' ')
	if  == -1 {
		return 0, nil
	}

	 = [+1 : len()-1]
	,  := strconv.ParseUint(bytesToString(), 10, 64)
	if  != nil {
		return 0, nil
	}

	return driver.RowsAffected(), nil
}

//------------------------------------------------------------------------------

type tx struct {
	cn *Conn
}

var _ driver.Tx = (*tx)(nil)

func ( tx) () error {
	,  := .cn.ExecContext(context.Background(), "COMMIT", nil)
	return 
}

func ( tx) () error {
	,  := .cn.ExecContext(context.Background(), "ROLLBACK", nil)
	return 
}

//------------------------------------------------------------------------------

type stmt struct {
	cn      *Conn
	name    string
	rowDesc *rowDescription
}

var (
	_ driver.Stmt             = (*stmt)(nil)
	_ driver.StmtExecContext  = (*stmt)(nil)
	_ driver.StmtQueryContext = (*stmt)(nil)
)

func ( *Conn,  string,  *rowDescription) *stmt {
	return &stmt{
		cn:      ,
		name:    ,
		rowDesc: ,
	}
}

func ( *stmt) () error {
	if .rowDesc != nil {
		rowDescPool.Put(.rowDesc)
		.rowDesc = nil
	}

	 := context.TODO()
	if  := writeCloseStmt(, .cn, .name);  != nil {
		return 
	}
	if  := readCloseStmtComplete(, .cn);  != nil {
		return 
	}
	return nil
}

func ( *stmt) () int {
	if .rowDesc == nil {
		return -1
	}
	return int(.rowDesc.numInput)
}

func ( *stmt) ( []driver.Value) (driver.Result, error) {
	panic("not implemented")
}

func ( *stmt) ( context.Context,  []driver.NamedValue) (driver.Result, error) {
	if  := writeBindExecute(, .cn, .name, );  != nil {
		return nil, 
	}
	return readExtQuery(, .cn)
}

func ( *stmt) ( []driver.Value) (driver.Rows, error) {
	panic("not implemented")
}

func ( *stmt) ( context.Context,  []driver.NamedValue) (driver.Rows, error) {
	if  := writeBindExecute(, .cn, .name, );  != nil {
		return nil, 
	}
	return readExtQueryData(, .cn, .rowDesc)
}