// 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 (
	
	
	
	
	
)

type mysqlStmt struct {
	mc         *mysqlConn
	id         uint32
	paramCount int
}

func ( *mysqlStmt) () error {
	if .mc == nil || .mc.closed.Load() {
		// driver.Stmt.Close can be called more than once, thus this function
		// has to be idempotent.
		// See also Issue #450 and golang/go#16019.
		//errLog.Print(ErrInvalidConn)
		return driver.ErrBadConn
	}

	 := .mc.writeCommandPacketUint32(comStmtClose, .id)
	.mc = nil
	return 
}

func ( *mysqlStmt) () int {
	return .paramCount
}

func ( *mysqlStmt) ( int) driver.ValueConverter {
	return converter{}
}

func ( *mysqlStmt) ( *driver.NamedValue) ( error) {
	.Value,  = converter{}.ConvertValue(.Value)
	return
}

func ( *mysqlStmt) ( []driver.Value) (driver.Result, error) {
	if .mc.closed.Load() {
		errLog.Print(ErrInvalidConn)
		return nil, driver.ErrBadConn
	}
	// Send command
	 := .writeExecutePacket()
	if  != nil {
		return nil, .mc.markBadConn()
	}

	 := .mc

	.affectedRows = 0
	.insertId = 0

	// Read Result
	,  := .readResultSetHeaderPacket()
	if  != nil {
		return nil, 
	}

	if  > 0 {
		// Columns
		if  = .readUntilEOF();  != nil {
			return nil, 
		}

		// Rows
		if  := .readUntilEOF();  != nil {
			return nil, 
		}
	}

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

	return &mysqlResult{
		affectedRows: int64(.affectedRows),
		insertId:     int64(.insertId),
	}, nil
}

func ( *mysqlStmt) ( []driver.Value) (driver.Rows, error) {
	return .query()
}

func ( *mysqlStmt) ( []driver.Value) (*binaryRows, error) {
	if .mc.closed.Load() {
		errLog.Print(ErrInvalidConn)
		return nil, driver.ErrBadConn
	}
	// Send command
	 := .writeExecutePacket()
	if  != nil {
		return nil, .mc.markBadConn()
	}

	 := .mc

	// Read Result
	,  := .readResultSetHeaderPacket()
	if  != nil {
		return nil, 
	}

	 := new(binaryRows)

	if  > 0 {
		.mc = 
		.rs.columns,  = .readColumns()
	} else {
		.rs.done = true

		switch  := .NextResultSet();  {
		case nil, io.EOF:
			return , nil
		default:
			return nil, 
		}
	}

	return , 
}

var jsonType = reflect.TypeOf(json.RawMessage{})

type converter struct{}

// ConvertValue mirrors the reference/default converter in database/sql/driver
// with _one_ exception.  We support uint64 with their high bit and the default
// implementation does not.  This function should be kept in sync with
// database/sql/driver defaultConverter.ConvertValue() except for that
// deliberate difference.
func ( converter) ( interface{}) (driver.Value, error) {
	if driver.IsValue() {
		return , nil
	}

	if ,  := .(driver.Valuer);  {
		,  := callValuerValue()
		if  != nil {
			return nil, 
		}
		if driver.IsValue() {
			return , nil
		}
		// A value returned from the Valuer interface can be "a type handled by
		// a database driver's NamedValueChecker interface" so we should accept
		// uint64 here as well.
		if ,  := .(uint64);  {
			return , nil
		}
		return nil, fmt.Errorf("non-Value type %T returned from Value", )
	}
	 := reflect.ValueOf()
	switch .Kind() {
	case reflect.Ptr:
		// indirect pointers
		if .IsNil() {
			return nil, nil
		} else {
			return .(.Elem().Interface())
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return .Int(), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return .Uint(), nil
	case reflect.Float32, reflect.Float64:
		return .Float(), nil
	case reflect.Bool:
		return .Bool(), nil
	case reflect.Slice:
		switch  := .Type(); {
		case  == jsonType:
			return , nil
		case .Elem().Kind() == reflect.Uint8:
			return .Bytes(), nil
		default:
			return nil, fmt.Errorf("unsupported type %T, a slice of %s", , .Elem().Kind())
		}
	case reflect.String:
		return .String(), nil
	}
	return nil, fmt.Errorf("unsupported type %T, a %s", , .Kind())
}

var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()

// callValuerValue returns vr.Value(), with one exception:
// If vr.Value is an auto-generated method on a pointer type and the
// pointer is nil, it would panic at runtime in the panicwrap
// method. Treat it like nil instead.
//
// This is so people can implement driver.Value on value types and
// still use nil pointers to those types to mean nil/NULL, just like
// string/*string.
//
// This is an exact copy of the same-named unexported function from the
// database/sql package.
func callValuerValue( driver.Valuer) ( driver.Value,  error) {
	if  := reflect.ValueOf(); .Kind() == reflect.Ptr &&
		.IsNil() &&
		.Type().Elem().Implements(valuerReflectType) {
		return nil, nil
	}
	return .Value()
}