func normalizeRowValues(row []interface{}, types []string) ([]*command.Parameter, error) {
	values := make([]*command.Parameter, len(types))
	for i, v := range row {
		switch val := v.(type) {
		case int:
		case int64:
			values[i] = &command.Parameter{
				Value: &command.Parameter_I{
					I: val,
				},
			}
		case float64:
			values[i] = &command.Parameter{
				Value: &command.Parameter_D{
					D: val,
				},
			}
		case bool:
			values[i] = &command.Parameter{
				Value: &command.Parameter_B{
					B: val,
				},
			}
		case string:
			values[i] = &command.Parameter{
				Value: &command.Parameter_S{
					S: val,
				},
			}
		case []byte:
			if isTextType(types[i]) {
				values[i].Value = &command.Parameter_S{
					S: string(val),
				}
			} else {
				values[i] = &command.Parameter{
					Value: &command.Parameter_Y{
						Y: val,
					},
				}
			}
		case time.Time:
			rfc3339, err := val.MarshalText()
			if err != nil {
				return nil, err
			}
			values[i] = &command.Parameter{
				Value: &command.Parameter_S{
					S: string(rfc3339),
				},
			}
		case nil:
			continue
		default:
			return nil, fmt.Errorf("unhandled column type: %T %v", val, val)
		}
	}
	return values, nil
}
normalizeRowValues performs some normalization of values in the returned rows.
Text values come over (from sqlite-go) as []byte instead of strings
for some reason, so we have explicitly convert (but only when type
is "text" so we don't affect BLOB types)
package db
import (
	"context"
	"database/sql"
	"expvar"
	"fmt"
	"io"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"
	"github.com/rqlite/go-sqlite3"
	"github.com/rqlite/rqlite/command"
)
const bkDelay = 250
const (
	onDiskMaxOpenConns = 32
	onDiskMaxIdleTime  = 120 * time.Second
	numExecutions      = "executions"
	numExecutionErrors = "execution_errors"
	numQueries         = "queries"
	numQueryErrors     = "query_errors"
	numETx             = "execute_transactions"
	numQTx             = "query_transactions"
)
var DBVersion string
var stats *expvar.Map
func init() {
	DBVersion, _, _ = sqlite3.Version()
	stats = expvar.NewMap("db")
	stats.Add(numExecutions, 0)
	stats.Add(numExecutionErrors, 0)
	stats.Add(numQueries, 0)
	stats.Add(numQueryErrors, 0)
	stats.Add(numETx, 0)
	stats.Add(numQTx, 0)
}
type DB struct {
	path   string  
	memory bool    
	rwDB *sql.DB  
	roDB *sql.DB  
	rwDSN string  
	roDSN string  
}
type PoolStats struct {
	MaxOpenConnections int           `json:"max_open_connections"`
	OpenConnections    int           `json:"open_connections"`
	InUse              int           `json:"in_use"`
	Idle               int           `json:"idle"`
	WaitCount          int64         `json:"wait_count"`
	WaitDuration       time.Duration `json:"wait_duration"`
	MaxIdleClosed      int64         `json:"max_idle_closed"`
	MaxIdleTimeClosed  int64         `json:"max_idle_time_closed"`
	MaxLifetimeClosed  int64         `json:"max_lifetime_closed"`
}
func Open(dbPath string, fkEnabled bool) (*DB, error) {
	rwDSN := fmt.Sprintf("file:%s?_fk=%s", dbPath, strconv.FormatBool(fkEnabled))
	rwDB, err := sql.Open("sqlite3", rwDSN)
	if err != nil {
		return nil, err
	}
	roOpts := []string{
		"mode=ro",
		fmt.Sprintf("_fk=%s", strconv.FormatBool(fkEnabled)),
	}
	roDSN := fmt.Sprintf("file:%s?%s", dbPath, strings.Join(roOpts, "&"))
	roDB, err := sql.Open("sqlite3", roDSN)
	if err != nil {
		return nil, err
	}
	if err := rwDB.Ping(); err != nil {
		return nil, fmt.Errorf("failed to ping on-disk database: %s", err.Error())
	}
	rwDB.SetConnMaxIdleTime(30 * time.Second)
	rwDB.SetConnMaxLifetime(0)
	roDB.SetConnMaxIdleTime(30 * time.Second)
	roDB.SetConnMaxLifetime(0)
	return &DB{
		path:  dbPath,
		rwDB:  rwDB,
		roDB:  roDB,
		rwDSN: rwDSN,
		roDSN: roDSN,
	}, nil
}
func OpenInMemory(fkEnabled bool) (*DB, error) {
	inMemPath := fmt.Sprintf("file:/%s", randomString())
	rwOpts := []string{
		"mode=rw",
		"vfs=memdb",
		"_txlock=immediate",
		fmt.Sprintf("_fk=%s", strconv.FormatBool(fkEnabled)),
	}
	rwDSN := fmt.Sprintf("%s?%s", inMemPath, strings.Join(rwOpts, "&"))
	rwDB, err := sql.Open("sqlite3", rwDSN)
	if err != nil {
		return nil, err
	}
	rwDB.SetConnMaxIdleTime(0)
	rwDB.SetConnMaxLifetime(0)
	rwDB.SetMaxIdleConns(1)
	rwDB.SetMaxOpenConns(1)
	roOpts := []string{
		"mode=ro",
		"vfs=memdb",
		"_txlock=deferred",
		fmt.Sprintf("_fk=%s", strconv.FormatBool(fkEnabled)),
	}
	roDSN := fmt.Sprintf("%s?%s", inMemPath, strings.Join(roOpts, "&"))
	roDB, err := sql.Open("sqlite3", roDSN)
	if err != nil {
		return nil, err
	}
	if err := rwDB.Ping(); err != nil {
		return nil, fmt.Errorf("failed to ping in-memory database: %s", err.Error())
	}
	return &DB{
		memory: true,
		rwDB:   rwDB,
		roDB:   roDB,
		rwDSN:  rwDSN,
		roDSN:  roDSN,
	}, nil
}
func LoadIntoMemory(dbPath string, fkEnabled bool) (*DB, error) {
	dstDB, err := OpenInMemory(fkEnabled)
	if err != nil {
		return nil, err
	}
	srcDB, err := Open(dbPath, false)
	if err != nil {
		return nil, err
	}
	if err := copyDatabase(dstDB, srcDB); err != nil {
		return nil, err
	}
	if err := srcDB.Close(); err != nil {
		return nil, err
	}
	return dstDB, nil
}
func DeserializeIntoMemory(b []byte, fkEnabled bool) (retDB *DB, retErr error) {
	tmpDB, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		return nil, fmt.Errorf("DeserializeIntoMemory: %s", err.Error())
	}
	defer tmpDB.Close()
	tmpConn, err := tmpDB.Conn(context.Background())
	if err != nil {
		return nil, err
	}
	retDB, err = OpenInMemory(fkEnabled)
	if err != nil {
		return nil, fmt.Errorf("DeserializeIntoMemory: %s", err.Error())
	}
	defer func() {
		if retErr != nil {
			retDB.Close()
		}
	}()
	if err := tmpConn.Raw(func(driverConn interface{}) error {
		srcConn := driverConn.(*sqlite3.SQLiteConn)
		err2 := srcConn.Deserialize(b, "")
		if err2 != nil {
			return fmt.Errorf("DeserializeIntoMemory: %s", err.Error())
		}
		defer srcConn.Close()
		dbConn, err3 := retDB.rwDB.Conn(context.Background())
		if err3 != nil {
			return fmt.Errorf("DeserializeIntoMemory: %s", err.Error())
		}
		defer dbConn.Close()
		return dbConn.Raw(func(driverConn interface{}) error {
			dstConn := driverConn.(*sqlite3.SQLiteConn)
			return copyDatabaseConnection(dstConn, srcConn)
		})
	}); err != nil {
		return nil, err
	}
	return retDB, nil
}
func (db *DB) Close() error {
	if err := db.rwDB.Close(); err != nil {
		return err
	}
	return db.roDB.Close()
}
func (db *DB) Stats() (map[string]interface{}, error) {
	copts, err := db.CompileOptions()
	if err != nil {
		return nil, err
	}
	memStats, err := db.memStats()
	if err != nil {
		return nil, err
	}
	connPoolStats := map[string]interface{}{
		"ro": db.ConnectionPoolStats(db.roDB),
		"rw": db.ConnectionPoolStats(db.rwDB),
	}
	dbSz, err := db.Size()
	if err != nil {
		return nil, err
	}
	stats := map[string]interface{}{
		"version":         DBVersion,
		"compile_options": copts,
		"mem_stats":       memStats,
		"db_size":         dbSz,
		"rw_dsn":          string(db.rwDSN),
		"ro_dsn":          db.roDSN,
		"conn_pool_stats": connPoolStats,
	}
	if db.memory {
		stats["path"] = ":memory:"
	} else {
		stats["path"] = db.path
		if stats["size"], err = db.FileSize(); err != nil {
			return nil, err
		}
	}
	return stats, nil
}
func (db *DB) Size() (int64, error) {
	rows, err := db.QueryStringStmt(`SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()`)
	if err != nil {
		return 0, err
	}
	return rows[0].Values[0].Parameters[0].GetI(), nil
}
func (db *DB) FileSize() (int64, error) {
	if db.memory {
		return 0, nil
	}
	fi, err := os.Stat(db.path)
	if err != nil {
		return 0, err
	}
	return fi.Size(), nil
}
func (db *DB) CompileOptions() ([]string, error) {
	res, err := db.QueryStringStmt("PRAGMA compile_options")
	if err != nil {
		return nil, err
	}
	if len(res) != 1 {
		return nil, fmt.Errorf("compile options result wrong size (%d)", len(res))
	}
	copts := make([]string, len(res[0].Values))
	for i := range copts {
		if len(res[0].Values[i].Parameters) != 1 {
			return nil, fmt.Errorf("compile options values wrong size (%d)", len(res))
		}
		copts[i] = res[0].Values[i].Parameters[0].GetS()
	}
	return copts, nil
}
func (db *DB) ConnectionPoolStats(sqlDB *sql.DB) *PoolStats {
	s := sqlDB.Stats()
	return &PoolStats{
		MaxOpenConnections: s.MaxOpenConnections,
		OpenConnections:    s.OpenConnections,
		InUse:              s.InUse,
		Idle:               s.Idle,
		WaitCount:          s.WaitCount,
		WaitDuration:       s.WaitDuration,
		MaxIdleClosed:      s.MaxIdleClosed,
		MaxIdleTimeClosed:  s.MaxIdleTimeClosed,
		MaxLifetimeClosed:  s.MaxLifetimeClosed,
	}
}
func (db *DB) ExecuteStringStmt(query string) ([]*command.ExecuteResult, error) {
	r := &command.Request{
		Statements: []*command.Statement{
			{
				Sql: query,
			},
		},
	}
	return db.Execute(r, false)
}
func (db *DB) Execute(req *command.Request, xTime bool) ([]*command.ExecuteResult, error) {
	stats.Add(numExecutions, int64(len(req.Statements)))
	conn, err := db.rwDB.Conn(context.Background())
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	type Execer interface {
		ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
	}
	var execer Execer
	var tx *sql.Tx
	if req.Transaction {
		stats.Add(numETx, 1)
		tx, err = conn.BeginTx(context.Background(), nil)
		if err != nil {
			return nil, err
		}
		defer func() {
			if tx != nil {
				tx.Rollback()  
			}
		}()
		execer = tx
	} else {
		execer = conn
	}
	var allResults []*command.ExecuteResult
	handleError := func(result *command.ExecuteResult, err error) bool {
		stats.Add(numExecutionErrors, 1)
		result.Error = err.Error()
		allResults = append(allResults, result)
		if tx != nil {
			tx.Rollback()
			tx = nil
			return false
		}
		return true
	}
	for _, stmt := range req.Statements {
		ss := stmt.Sql
		if ss == "" {
			continue
		}
		result := &command.ExecuteResult{}
		start := time.Now()
		parameters, err := parametersToValues(stmt.Parameters)
		if err != nil {
			if handleError(result, err) {
				continue
			}
			break
		}
		r, err := execer.ExecContext(context.Background(), ss, parameters...)
		if err != nil {
			if handleError(result, err) {
				continue
			}
			break
		}
		if r == nil {
			continue
		}
		lid, err := r.LastInsertId()
		if err != nil {
			if handleError(result, err) {
				continue
			}
			break
		}
		result.LastInsertId = lid
		ra, err := r.RowsAffected()
		if err != nil {
			if handleError(result, err) {
				continue
			}
			break
		}
		result.RowsAffected = ra
		if xTime {
			result.Time = time.Now().Sub(start).Seconds()
		}
		allResults = append(allResults, result)
	}
	if tx != nil {
		err = tx.Commit()
	}
	return allResults, err
}
func (db *DB) QueryStringStmt(query string) ([]*command.QueryRows, error) {
	r := &command.Request{
		Statements: []*command.Statement{
			{
				Sql: query,
			},
		},
	}
	return db.Query(r, false)
}
func (db *DB) Query(req *command.Request, xTime bool) ([]*command.QueryRows, error) {
	stats.Add(numQueries, int64(len(req.Statements)))
	conn, err := db.roDB.Conn(context.Background())
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	return db.queryWithConn(req, xTime, conn)
}
func (db *DB) queryWithConn(req *command.Request, xTime bool, conn *sql.Conn) ([]*command.QueryRows, error) {
	var err error
	type Queryer interface {
		QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	}
	var queryer Queryer
	var tx *sql.Tx
	if req.Transaction {
		stats.Add(numQTx, 1)
		tx, err = conn.BeginTx(context.Background(), nil)
		if err != nil {
			return nil, err
		}
		defer tx.Rollback()  
		queryer = tx
	} else {
		queryer = conn
	}
	var allRows []*command.QueryRows
	for _, stmt := range req.Statements {
		sql := stmt.Sql
		if sql == "" {
			continue
		}
		rows := &command.QueryRows{}
		start := time.Now()
		var readOnly bool
		f := func(driverConn interface{}) error {
			c := driverConn.(*sqlite3.SQLiteConn)
			drvStmt, err := c.Prepare(sql)
			if err != nil {
				return err
			}
			defer drvStmt.Close()
			sqliteStmt := drvStmt.(*sqlite3.SQLiteStmt)
			readOnly = sqliteStmt.Readonly()
			return nil
		}
		if err := conn.Raw(f); err != nil {
			stats.Add(numQueryErrors, 1)
			rows.Error = err.Error()
			allRows = append(allRows, rows)
			continue
		}
		if !readOnly {
			stats.Add(numQueryErrors, 1)
			rows.Error = "attempt to change database via query operation"
			allRows = append(allRows, rows)
			continue
		}
		parameters, err := parametersToValues(stmt.Parameters)
		if err != nil {
			stats.Add(numQueryErrors, 1)
			rows.Error = err.Error()
			allRows = append(allRows, rows)
			continue
		}
		rs, err := queryer.QueryContext(context.Background(), sql, parameters...)
		if err != nil {
			stats.Add(numQueryErrors, 1)
			rows.Error = err.Error()
			allRows = append(allRows, rows)
			continue
		}
		defer rs.Close()
		columns, err := rs.Columns()
		if err != nil {
			return nil, err
		}
		types, err := rs.ColumnTypes()
		if err != nil {
			return nil, err
		}
		xTypes := make([]string, len(types))
		for i := range types {
			xTypes[i] = strings.ToLower(types[i].DatabaseTypeName())
		}
		for rs.Next() {
			dest := make([]interface{}, len(columns))
			ptrs := make([]interface{}, len(dest))
			for i := range ptrs {
				ptrs[i] = &dest[i]
			}
			if err := rs.Scan(ptrs...); err != nil {
				return nil, err
			}
			params, err := normalizeRowValues(dest, xTypes)
			if err != nil {
				return nil, err
			}
			rows.Values = append(rows.Values, &command.Values{
				Parameters: params,
			})
		}
		if err := rs.Err(); err != nil {
			stats.Add(numQueryErrors, 1)
			rows.Error = err.Error()
			allRows = append(allRows, rows)
			continue
		}
		if xTime {
			rows.Time = time.Now().Sub(start).Seconds()
		}
		rows.Columns = columns
		rows.Types = xTypes
		allRows = append(allRows, rows)
	}
	if tx != nil {
		err = tx.Commit()
	}
	return allRows, err
}
func (db *DB) Backup(path string) error {
	dstDB, err := Open(path, false)
	if err != nil {
		return err
	}
	if err := copyDatabase(dstDB, db); err != nil {
		return fmt.Errorf("backup database: %s", err)
	}
	return nil
}
func (db *DB) Copy(dstDB *DB) error {
	if err := copyDatabase(dstDB, db); err != nil {
		return fmt.Errorf("copy database: %s", err)
	}
	return nil
}
func (db *DB) Serialize() ([]byte, error) {
	if !db.memory {
		return os.ReadFile(db.path)
	}
	conn, err := db.roDB.Conn(context.Background())
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	var b []byte
	f := func(driverConn interface{}) error {
		c := driverConn.(*sqlite3.SQLiteConn)
		b = c.Serialize("")
		if b == nil {
			return fmt.Errorf("failed to serialize database")
		}
		return nil
	}
	if err := conn.Raw(f); err != nil {
		return nil, err
	}
	return b, nil
}
func (db *DB) Dump(w io.Writer) error {
	conn, err := db.roDB.Conn(context.Background())
	if err != nil {
		return err
	}
	defer conn.Close()
	commReq := func(query string) *command.Request {
		return &command.Request{
			Statements: []*command.Statement{
				{
					Sql: query,
				},
			},
		}
	}
	if _, err := w.Write([]byte("PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n")); err != nil {
		return err
	}
	query := `SELECT "name", "type", "sql" FROM "sqlite_master"
              WHERE "sql" NOT NULL AND "type" == 'table' ORDER BY "name"`
	rows, err := db.queryWithConn(commReq(query), false, conn)
	if err != nil {
		return err
	}
	row := rows[0]
	for _, v := range row.Values {
		table := v.Parameters[0].GetS()
		var stmt string
		if table == "sqlite_sequence" {
			stmt = `DELETE FROM "sqlite_sequence";`
		} else if table == "sqlite_stat1" {
			stmt = `ANALYZE "sqlite_master";`
		} else if strings.HasPrefix(table, "sqlite_") {
			continue
		} else {
			stmt = v.Parameters[2].GetS()
		}
		if _, err := w.Write([]byte(fmt.Sprintf("%s;\n", stmt))); err != nil {
			return err
		}
		tableIndent := strings.Replace(table, `"`, `""`, -1)
		r, err := db.queryWithConn(commReq(fmt.Sprintf(`PRAGMA table_info("%s")`, tableIndent)),
			false, conn)
		if err != nil {
			return err
		}
		var columnNames []string
		for _, w := range r[0].Values {
			columnNames = append(columnNames, fmt.Sprintf(`'||quote("%s")||'`, w.Parameters[1].GetS()))
		}
		query = fmt.Sprintf(`SELECT 'INSERT INTO "%s" VALUES(%s)' FROM "%s";`,
			tableIndent,
			strings.Join(columnNames, ","),
			tableIndent)
		r, err = db.queryWithConn(commReq(query), false, conn)
		if err != nil {
			return err
		}
		for _, x := range r[0].Values {
			y := fmt.Sprintf("%s;\n", x.Parameters[0].GetS())
			if _, err := w.Write([]byte(y)); err != nil {
				return err
			}
		}
	}
	// Do indexes, triggers, and views.
	query = `SELECT "name", "type", "sql" FROM "sqlite_master"
			  WHERE "sql" NOT NULL AND "type" IN ('index', 'trigger', 'view')`
	rows, err = db.queryWithConn(commReq(query), false, conn)
	if err != nil {
		return err
	}
	row = rows[0]
	for _, v := range row.Values {
		if _, err := w.Write([]byte(fmt.Sprintf("%s;\n", v.Parameters[2].GetS()))); err != nil {
			return err
		}
	}
	if _, err := w.Write([]byte("COMMIT;\n")); err != nil {
		return err
	}
	return nil
}
func (db *DB) memStats() (map[string]int64, error) {
	ms := make(map[string]int64)
	for _, p := range []string{
		"max_page_count",
		"page_count",
		"page_size",
		"hard_heap_limit",
		"soft_heap_limit",
		"cache_size",
		"freelist_count",
	} {
		res, err := db.QueryStringStmt(fmt.Sprintf("PRAGMA %s", p))
		if err != nil {
			return nil, err
		}
		ms[p] = res[0].Values[0].Parameters[0].GetI()
	}
	return ms, nil
}
func copyDatabase(dst *DB, src *DB) error {
	dstConn, err := dst.rwDB.Conn(context.Background())
	if err != nil {
		return err
	}
	defer dstConn.Close()
	srcConn, err := src.roDB.Conn(context.Background())
	if err != nil {
		return err
	}
	defer srcConn.Close()
	var dstSQLiteConn *sqlite3.SQLiteConn
	// Define the backup function.
	bf := func(driverConn interface{}) error {
		srcSQLiteConn := driverConn.(*sqlite3.SQLiteConn)
		return copyDatabaseConnection(dstSQLiteConn, srcSQLiteConn)
	}
	return dstConn.Raw(
		func(driverConn interface{}) error {
			dstSQLiteConn = driverConn.(*sqlite3.SQLiteConn)
			return srcConn.Raw(bf)
		})
}
func copyDatabaseConnection(dst, src *sqlite3.SQLiteConn) error {
	bk, err := dst.Backup("main", src, "main")
	if err != nil {
		return err
	}
	for {
		done, err := bk.Step(-1)
		if err != nil {
			bk.Finish()
			return err
		}
		if done {
			break
		}
		time.Sleep(bkDelay * time.Millisecond)
	}
	return bk.Finish()
}
// parametersToValues maps values in the proto params to SQL driver values.
func parametersToValues(parameters []*command.Parameter) ([]interface{}, error) {
	if parameters == nil {
		return nil, nil
	}
	values := make([]interface{}, len(parameters))
	for i := range parameters {
		switch w := parameters[i].GetValue().(type) {
		case *command.Parameter_I:
			values[i] = w.I
		case *command.Parameter_D:
			values[i] = w.D
		case *command.Parameter_B:
			values[i] = w.B
		case *command.Parameter_Y:
			values[i] = w.Y
		case *command.Parameter_S:
			values[i] = w.S
		default:
			return nil, fmt.Errorf("unsupported type: %T", w)
		}
	}
	return values, nil
}
// normalizeRowValues performs some normalization of values in the returned rows.
// Text values come over (from sqlite-go) as []byte instead of strings
// for some reason, so we have explicitly convert (but only when type
// is "text" so we don't affect BLOB types)