2019-02-15 16:13:00 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package sqliteutil
|
|
|
|
|
|
|
|
import (
|
2020-01-13 13:03:30 +00:00
|
|
|
"context"
|
2019-02-15 16:13:00 +00:00
|
|
|
"strconv"
|
|
|
|
|
2019-04-04 15:42:01 +01:00
|
|
|
sqlite3 "github.com/mattn/go-sqlite3"
|
2019-02-15 16:13:00 +00:00
|
|
|
"github.com/zeebo/errs"
|
|
|
|
|
2019-11-14 19:46:15 +00:00
|
|
|
"storj.io/storj/private/dbutil/dbschema"
|
2020-01-19 14:41:23 +00:00
|
|
|
"storj.io/storj/private/tagsql"
|
2019-02-15 16:13:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// LoadSchemaFromSQL inserts script into connstr and loads schema.
|
2020-01-13 13:03:30 +00:00
|
|
|
func LoadSchemaFromSQL(ctx context.Context, script string) (_ *dbschema.Schema, err error) {
|
2020-01-19 14:41:23 +00:00
|
|
|
db, err := tagsql.Open("sqlite3", ":memory:")
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, db.Close()) }()
|
|
|
|
|
2020-01-14 11:29:25 +00:00
|
|
|
_, err = db.ExecContext(ctx, script)
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 13:03:30 +00:00
|
|
|
return QuerySchema(ctx, db)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadSnapshotFromSQL inserts script into connstr and loads schema.
|
2020-01-13 13:03:30 +00:00
|
|
|
func LoadSnapshotFromSQL(ctx context.Context, script string) (_ *dbschema.Snapshot, err error) {
|
2020-01-19 14:41:23 +00:00
|
|
|
db, err := tagsql.Open("sqlite3", ":memory:")
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, db.Close()) }()
|
|
|
|
|
2020-01-14 11:29:25 +00:00
|
|
|
_, err = db.ExecContext(ctx, script)
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 13:03:30 +00:00
|
|
|
snapshot, err := QuerySnapshot(ctx, db)
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 20:31:49 +01:00
|
|
|
snapshot.Sections = dbschema.NewSections(script)
|
|
|
|
|
2019-02-15 16:13:00 +00:00
|
|
|
return snapshot, nil
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// QuerySnapshot loads snapshot from database.
|
2020-01-13 13:03:30 +00:00
|
|
|
func QuerySnapshot(ctx context.Context, db dbschema.Queryer) (*dbschema.Snapshot, error) {
|
|
|
|
schema, err := QuerySchema(ctx, db)
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 13:03:30 +00:00
|
|
|
data, err := QueryData(ctx, db, schema)
|
2019-02-15 16:13:00 +00:00
|
|
|
if err != nil {
|
2019-07-12 20:29:09 +01:00
|
|
|
return nil, errs.Wrap(err)
|
2019-02-15 16:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &dbschema.Snapshot{
|
|
|
|
Version: -1,
|
|
|
|
Schema: schema,
|
|
|
|
Data: data,
|
|
|
|
}, err
|
|
|
|
}
|
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// QueryData loads all data from tables.
|
2020-01-13 13:03:30 +00:00
|
|
|
func QueryData(ctx context.Context, db dbschema.Queryer, schema *dbschema.Schema) (*dbschema.Data, error) {
|
2020-01-17 18:08:13 +00:00
|
|
|
return dbschema.QueryData(ctx, db, schema, func(columnName string) string {
|
2019-02-15 16:13:00 +00:00
|
|
|
quoted := strconv.Quote(columnName)
|
|
|
|
return `quote(` + quoted + `) as ` + quoted
|
|
|
|
})
|
|
|
|
}
|
2019-04-04 15:42:01 +01:00
|
|
|
|
2020-07-16 15:18:02 +01:00
|
|
|
// IsConstraintError checks if given error is about constraint violation.
|
2019-04-04 15:42:01 +01:00
|
|
|
func IsConstraintError(err error) bool {
|
2019-06-26 08:38:07 +01:00
|
|
|
return errs.IsFunc(err, func(err error) bool {
|
2019-04-23 12:13:57 +01:00
|
|
|
if e, ok := err.(sqlite3.Error); ok {
|
|
|
|
if e.Code == sqlite3.ErrConstraint {
|
|
|
|
return true
|
|
|
|
}
|
2019-04-04 15:42:01 +01:00
|
|
|
}
|
2019-04-23 12:13:57 +01:00
|
|
|
return false
|
|
|
|
})
|
2019-04-04 15:42:01 +01:00
|
|
|
}
|