| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- // Copyright 2023 Ross Light
- // SPDX-License-Identifier: ISC
- package sqlite
- import (
- "fmt"
- "modernc.org/libc"
- lib "modernc.org/sqlite/lib"
- )
- // A Backup represents a copy operation between two database connections.
- // See https://www.sqlite.org/backup.html for more details.
- type Backup struct {
- tls *libc.TLS
- ptr uintptr
- }
- // NewBackup creates a [Backup] that copies from one connection to another.
- // The database name is "main" or "" for the main database,
- // "temp" for the temporary database,
- // or the name specified after the AS keyword in an ATTACH statement for an attached database.
- // If src and dst are the same connection, NewBackup will return an error.
- // It is the caller's responsibility to call [Backup.Close] on the returned Backup object.
- func NewBackup(dst *Conn, dstName string, src *Conn, srcName string) (*Backup, error) {
- cDstName, freeCDstName, err := cDBName(dstName)
- if err != nil {
- return nil, fmt.Errorf("sqlite: new backup: %w", err)
- }
- defer freeCDstName()
- cSrcName, freeCSrcName, err := cDBName(srcName)
- if err != nil {
- return nil, fmt.Errorf("sqlite: new backup: %w", err)
- }
- defer freeCSrcName()
- backupPtr := lib.Xsqlite3_backup_init(dst.tls, dst.conn, cDstName, src.conn, cSrcName)
- if backupPtr == 0 {
- res := ResultCode(lib.Xsqlite3_errcode(dst.tls, dst.conn))
- return nil, fmt.Errorf("sqlite: new backup: %w", dst.extreserr(res))
- }
- return &Backup{dst.tls, backupPtr}, nil
- }
- // Step copies up to n pages from the source database to the destination database.
- // If n is negative, all remaining source pages are copied.
- // more will be true if there are pages still remaining to be copied.
- // Step may return both an error and that more pages are still remaining:
- // this indicates the error is temporary and that Step can be retried.
- func (b *Backup) Step(n int) (more bool, err error) {
- res := ResultCode(lib.Xsqlite3_backup_step(b.tls, b.ptr, int32(n)))
- switch res {
- case ResultOK:
- return true, nil
- case ResultDone:
- return false, nil
- case ResultBusy, ResultLocked:
- // SQLITE_BUSY and SQLITE_LOCKED are retriable errors.
- return true, fmt.Errorf("sqlite: backup step: %w", res.ToError())
- default:
- return false, fmt.Errorf("sqlite: backup step: %w", res.ToError())
- }
- }
- // Remaining returns the number of pages still to be backed up
- // at the conclusion of the most recent call to [Backup.Step].
- // The return value of Remaining before calling [Backup.Step] is undefined.
- // If the source database is modified in a way that changes the number of pages remaining,
- // that change is not reflected in the output until after the next call to [Backup.Step].
- func (b *Backup) Remaining() int {
- return int(lib.Xsqlite3_backup_remaining(b.tls, b.ptr))
- }
- // PageCount returns the total number of pages in the source database
- // at the conclusion of the most recent call to [Backup.Step].
- // The return value of PageCount before calling [Backup.Step] is undefined.
- // If the source database is modified in a way that changes the size of the source database,
- // that change is not reflected in the output until after the next call to [Backup.Step].
- func (b *Backup) PageCount() int {
- return int(lib.Xsqlite3_backup_pagecount(b.tls, b.ptr))
- }
- // Close releases all resources associated with the backup.
- // If [Backup.Step] has not yet returned (false, nil),
- // then any active write transaction on the destination database is rolled back.
- func (b *Backup) Close() error {
- // The error from sqlite3_backup_finish indicates whether
- // a previous call to sqlite3_backup_step returned an error.
- // Since we're assuming that the caller will handle errors as they arise,
- // we always return nil from Close.
- // However, I'm not fully confident that Close will always be infallible,
- // so I'm not documenting this as part of the API.
- lib.Xsqlite3_backup_finish(b.tls, b.ptr)
- return nil
- }
|