status-go/appdatabase/database.go

110 lines
2.9 KiB
Go

package appdatabase
import (
"database/sql"
"errors"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/appdatabase/migrations"
migrationsprevnodecfg "github.com/status-im/status-go/appdatabase/migrationsprevnodecfg"
"github.com/status-im/status-go/nodecfg"
"github.com/status-im/status-go/sqlite"
)
const nodeCfgMigrationDate = 1640111208
// InitializeDB creates db file at a given path and applies migrations.
func InitializeDB(path, password string) (*sql.DB, error) {
db, err := sqlite.OpenDB(path, password)
if err != nil {
return nil, err
}
// Check if the migration table exists
row := db.QueryRow("SELECT exists(SELECT name FROM sqlite_master WHERE type='table' AND name='status_go_schema_migrations')")
migrationTableExists := false
err = row.Scan(&migrationTableExists)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
var lastMigration uint64 = 0
if migrationTableExists {
row = db.QueryRow("SELECT version FROM status_go_schema_migrations")
err = row.Scan(&lastMigration)
if err != nil && err != sql.ErrNoRows {
return nil, err
}
}
if !migrationTableExists || (lastMigration > 0 && lastMigration < nodeCfgMigrationDate) {
// If it's the first time migration's being run, or latest migration happened before migrating the nodecfg table
err = migrationsprevnodecfg.Migrate(db)
if err != nil {
return nil, err
}
// NodeConfig migration cannot be done with SQL
err = nodecfg.MigrateNodeConfig(db)
if err != nil {
return nil, err
}
}
err = migrations.Migrate(db)
if err != nil {
return nil, err
}
return db, nil
}
// DecryptDatabase creates an unencrypted copy of the database and copies it
// over to the given directory
func DecryptDatabase(oldPath, newPath, password string) error {
return sqlite.DecryptDB(oldPath, newPath, password)
}
// EncryptDatabase creates an encrypted copy of the database and copies it to the
// user path
func EncryptDatabase(oldPath, newPath, password string) error {
return sqlite.EncryptDB(oldPath, newPath, password)
}
func ChangeDatabasePassword(path, password, newPassword string) error {
return sqlite.ChangeEncryptionKey(path, password, newPassword)
}
// GetDBFilename takes an instance of sql.DB and returns the filename of the "main" database
func GetDBFilename(db *sql.DB) (string, error) {
if db == nil {
logger := log.New()
logger.Warn("GetDBFilename was passed a nil pointer sql.DB")
return "", nil
}
var i, category, filename string
rows, err := db.Query("PRAGMA database_list;")
if err != nil {
return "", err
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&i, &category, &filename)
if err != nil {
return "", err
}
// The "main" database is the one we care about
if category == "main" {
return filename, nil
}
}
if err := rows.Err(); err != nil {
return "", err
}
return "", errors.New("no main database found")
}