mirror of
https://github.com/DBD-SQLite/DBD-SQLite
synced 2025-06-07 22:28:47 -04:00
DBD-SQLite: applied the online backup patch from Toby Corkindale (with a little modification)
This commit is contained in:
parent
b30d014286
commit
87baa98f67
7 changed files with 218 additions and 4 deletions
1
Changes
1
Changes
|
@ -3,6 +3,7 @@ Changes for Perl extension DBD-SQLite
|
||||||
1.26_02 to be released
|
1.26_02 to be released
|
||||||
- Started using install_method() suggested by TIMB (#44882)
|
- Started using install_method() suggested by TIMB (#44882)
|
||||||
Ported last_insert_rowid as the first attempt (ISHIGAKI)
|
Ported last_insert_rowid as the first attempt (ISHIGAKI)
|
||||||
|
- Added access to Online Backup functionality. (TJC)
|
||||||
|
|
||||||
1.26_01 Tue 5 May 2009
|
1.26_01 Tue 5 May 2009
|
||||||
- Added ORDINAL_POSITION support for $dbh->column_info (ADAMK)
|
- Added ORDINAL_POSITION support for $dbh->column_info (ADAMK)
|
||||||
|
|
23
SQLite.xs
23
SQLite.xs
|
@ -94,6 +94,29 @@ busy_timeout(dbh, timeout=0)
|
||||||
OUTPUT:
|
OUTPUT:
|
||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
|
static int
|
||||||
|
backup_from_file(dbh, filename)
|
||||||
|
SV *dbh
|
||||||
|
char *filename
|
||||||
|
ALIAS:
|
||||||
|
DBD::SQLite::db::sqlite_backup_from_file = 1
|
||||||
|
CODE:
|
||||||
|
RETVAL = sqlite_db_backup_from_file(aTHX_ dbh, filename);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
static int
|
||||||
|
backup_to_file(dbh, filename)
|
||||||
|
SV *dbh
|
||||||
|
char *filename
|
||||||
|
ALIAS:
|
||||||
|
DBD::SQLite::db::sqlite_backup_to_file = 1
|
||||||
|
CODE:
|
||||||
|
RETVAL = sqlite_db_backup_to_file(aTHX_ dbh, filename);
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
|
||||||
MODULE = DBD::SQLite PACKAGE = DBD::SQLite::st
|
MODULE = DBD::SQLite PACKAGE = DBD::SQLite::st
|
||||||
|
|
||||||
PROTOTYPES: DISABLE
|
PROTOTYPES: DISABLE
|
||||||
|
|
60
dbdimp.c
60
dbdimp.c
|
@ -1254,7 +1254,6 @@ sqlite_db_collation_dispatcher_utf8(
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sqlite3_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func )
|
sqlite3_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func )
|
||||||
{
|
{
|
||||||
|
@ -1293,7 +1292,6 @@ sqlite3_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sqlite_db_progress_handler_dispatcher( void *handler )
|
sqlite_db_progress_handler_dispatcher( void *handler )
|
||||||
{
|
{
|
||||||
|
@ -1318,8 +1316,6 @@ sqlite_db_progress_handler_dispatcher( void *handler )
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sqlite3_db_progress_handler(pTHX_ SV *dbh, int n_opcodes, SV *handler )
|
sqlite3_db_progress_handler(pTHX_ SV *dbh, int n_opcodes, SV *handler )
|
||||||
{
|
{
|
||||||
|
@ -1342,4 +1338,60 @@ sqlite3_db_progress_handler(pTHX_ SV *dbh, int n_opcodes, SV *handler )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Accesses the SQLite Online Backup API, and fills the currently loaded
|
||||||
|
* database from the passed filename.
|
||||||
|
* Usual usage of this would be when you're operating on the :memory:
|
||||||
|
* special database connection and want to copy it in from a real db.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sqlite_db_backup_from_file(pTHX_ SV *dbh, char *filename)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
sqlite3 *pFrom;
|
||||||
|
sqlite3_backup *pBackup;
|
||||||
|
|
||||||
|
D_imp_dbh(dbh);
|
||||||
|
|
||||||
|
rc = sqlite3_open(filename, &pFrom);
|
||||||
|
if (rc==SQLITE_OK) {
|
||||||
|
|
||||||
|
pBackup = sqlite3_backup_init(imp_dbh->db, "main", pFrom, "main");
|
||||||
|
if (pBackup) {
|
||||||
|
(void)sqlite3_backup_step(pBackup, -1);
|
||||||
|
(void)sqlite3_backup_finish(pBackup);
|
||||||
|
}
|
||||||
|
rc = sqlite3_errcode(imp_dbh->db);
|
||||||
|
(void)sqlite3_close(pFrom);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accesses the SQLite Online Backup API, and copies the currently loaded
|
||||||
|
* database into the passed filename.
|
||||||
|
* Usual usage of this would be when you're operating on the :memory:
|
||||||
|
* special database connection, and want to back it up to an on-disk file.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sqlite_db_backup_to_file(pTHX_ SV *dbh, char *filename)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
sqlite3 *pTo;
|
||||||
|
sqlite3_backup *pBackup;
|
||||||
|
|
||||||
|
D_imp_dbh(dbh);
|
||||||
|
|
||||||
|
rc = sqlite3_open(filename, &pTo);
|
||||||
|
if (rc==SQLITE_OK) {
|
||||||
|
|
||||||
|
pBackup = sqlite3_backup_init(pTo, "main", imp_dbh->db, "main");
|
||||||
|
if (pBackup) {
|
||||||
|
(void)sqlite3_backup_step(pBackup, -1);
|
||||||
|
(void)sqlite3_backup_finish(pBackup);
|
||||||
|
}
|
||||||
|
rc = sqlite3_errcode(pTo);
|
||||||
|
(void)sqlite3_close(pTo);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* end */
|
/* end */
|
||||||
|
|
2
dbdimp.h
2
dbdimp.h
|
@ -79,6 +79,8 @@ void sqlite3_db_progress_handler(pTHX_ SV *dbh, int n_opcodes, SV *handler);
|
||||||
void sqlite_st_reset(pTHX_ SV *sth );
|
void sqlite_st_reset(pTHX_ SV *sth );
|
||||||
int sqlite_bind_col( SV *sth, imp_sth_t *imp_sth, SV *col, SV *ref, IV sql_type, SV *attribs );
|
int sqlite_bind_col( SV *sth, imp_sth_t *imp_sth, SV *col, SV *ref, IV sql_type, SV *attribs );
|
||||||
int dbd_set_sqlite3_busy_timeout (pTHX_ SV *dbh, int timeout );
|
int dbd_set_sqlite3_busy_timeout (pTHX_ SV *dbh, int timeout );
|
||||||
|
int sqlite_db_backup_from_file(pTHX_ SV *dbh, char *filename);
|
||||||
|
int sqlite_db_backup_to_file(pTHX_ SV *dbh, char *filename);
|
||||||
|
|
||||||
#ifdef SvUTF8_on
|
#ifdef SvUTF8_on
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ sub driver {
|
||||||
if (!$methods_are_installed && $DBI::VERSION >= 1.608) {
|
if (!$methods_are_installed && $DBI::VERSION >= 1.608) {
|
||||||
DBI->setup_driver('DBD::SQLite');
|
DBI->setup_driver('DBD::SQLite');
|
||||||
DBD::SQLite::db->install_method('sqlite_last_insert_rowid');
|
DBD::SQLite::db->install_method('sqlite_last_insert_rowid');
|
||||||
|
DBD::SQLite::db->install_method('sqlite_backup_from_file');
|
||||||
|
DBD::SQLite::db->install_method('sqlite_backup_to_file');
|
||||||
$methods_are_installed++;
|
$methods_are_installed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,6 +736,18 @@ progress handler.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
=head2 $dbh->sqlite_backup_from_file( $filename )
|
||||||
|
|
||||||
|
This method accesses the SQLite Online Backup API, and will take a backup of
|
||||||
|
the named database file, copying it to, and overwriting, your current database
|
||||||
|
connection. This can be particularly handy if your current connection is to the
|
||||||
|
special :memory: database, and you wish to populate it from an existing DB.
|
||||||
|
|
||||||
|
=head2 $dbh->sqlite_backup_to_file( $filename )
|
||||||
|
|
||||||
|
This method accesses the SQLite Online Backup API, and will take a backup of
|
||||||
|
the currently connected database, and write it out to the named file.
|
||||||
|
|
||||||
=head1 BLOBS
|
=head1 BLOBS
|
||||||
|
|
||||||
As of version 1.11, blobs should "just work" in SQLite as text columns.
|
As of version 1.11, blobs should "just work" in SQLite as text columns.
|
||||||
|
|
64
t/34_online_backup.t
Normal file
64
t/34_online_backup.t
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Test::More;
|
||||||
|
use t::lib::Test;
|
||||||
|
use DBI;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
plan skip_all => 'requires DBI v1.608' if $DBI::VERSION < 1.608;
|
||||||
|
}
|
||||||
|
|
||||||
|
plan tests => 4;
|
||||||
|
|
||||||
|
# Connect to the test db and add some stuff:
|
||||||
|
my $foo = connect_ok( RaiseError => 1 );
|
||||||
|
$foo->do(
|
||||||
|
'CREATE TABLE online_backup_test( id INTEGER PRIMARY KEY, foo INTEGER )'
|
||||||
|
);
|
||||||
|
$foo->do("INSERT INTO online_backup_test (foo) VALUES ($$)");
|
||||||
|
|
||||||
|
# That should be in the "foo" database on disk now, so disconnect and try to
|
||||||
|
# back it up:
|
||||||
|
|
||||||
|
$foo->disconnect;
|
||||||
|
|
||||||
|
my $dbh = DBI->connect(
|
||||||
|
'dbi:SQLite:dbname=:memory:',
|
||||||
|
undef, undef,
|
||||||
|
{ RaiseError => 1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
$dbh->sqlite_backup_from_file('foo');
|
||||||
|
|
||||||
|
{
|
||||||
|
my ($count) = $dbh->selectrow_array(
|
||||||
|
"SELECT count(foo) FROM online_backup_test WHERE foo=$$"
|
||||||
|
);
|
||||||
|
is($count, 1, "Found our process ID in backed-up table");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add more data then attempt to copy it back to file:
|
||||||
|
$dbh->do(
|
||||||
|
'CREATE TABLE online_backup_test2 ( id INTEGER PRIMARY KEY, foo INTEGER )'
|
||||||
|
);
|
||||||
|
$dbh->do("INSERT INTO online_backup_test2 (foo) VALUES ($$)");
|
||||||
|
|
||||||
|
# backup to file (foo):
|
||||||
|
$dbh->sqlite_backup_to_file('foo');
|
||||||
|
|
||||||
|
$dbh->disconnect;
|
||||||
|
|
||||||
|
# Reconnect to foo db and check data made it over:
|
||||||
|
{
|
||||||
|
my $foo = connect_ok( RaiseError => 1 );
|
||||||
|
|
||||||
|
my ($count) = $foo->selectrow_array(
|
||||||
|
"SELECT count(foo) FROM online_backup_test2 WHERE foo=$$"
|
||||||
|
);
|
||||||
|
is($count, 1, "Found our process ID in table back on disk");
|
||||||
|
|
||||||
|
$foo->disconnect;
|
||||||
|
}
|
58
t/34_online_backup_func.t
Normal file
58
t/34_online_backup_func.t
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Test::More tests => 4;
|
||||||
|
use t::lib::Test;
|
||||||
|
use DBI;
|
||||||
|
|
||||||
|
# Connect to the test db and add some stuff:
|
||||||
|
my $foo = connect_ok( RaiseError => 1 );
|
||||||
|
$foo->do(
|
||||||
|
'CREATE TABLE online_backup_test( id INTEGER PRIMARY KEY, foo INTEGER )'
|
||||||
|
);
|
||||||
|
$foo->do("INSERT INTO online_backup_test (foo) VALUES ($$)");
|
||||||
|
|
||||||
|
# That should be in the "foo" database on disk now, so disconnect and try to
|
||||||
|
# back it up:
|
||||||
|
|
||||||
|
$foo->disconnect;
|
||||||
|
|
||||||
|
my $dbh = DBI->connect(
|
||||||
|
'dbi:SQLite:dbname=:memory:',
|
||||||
|
undef, undef,
|
||||||
|
{ RaiseError => 1 }
|
||||||
|
);
|
||||||
|
|
||||||
|
$dbh->func('foo', 'backup_from_file');
|
||||||
|
|
||||||
|
{
|
||||||
|
my ($count) = $dbh->selectrow_array(
|
||||||
|
"SELECT count(foo) FROM online_backup_test WHERE foo=$$"
|
||||||
|
);
|
||||||
|
is($count, 1, "Found our process ID in backed-up table");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add more data then attempt to copy it back to file:
|
||||||
|
$dbh->do(
|
||||||
|
'CREATE TABLE online_backup_test2 ( id INTEGER PRIMARY KEY, foo INTEGER )'
|
||||||
|
);
|
||||||
|
$dbh->do("INSERT INTO online_backup_test2 (foo) VALUES ($$)");
|
||||||
|
|
||||||
|
# backup to file (foo):
|
||||||
|
$dbh->func('foo', 'backup_to_file');
|
||||||
|
|
||||||
|
$dbh->disconnect;
|
||||||
|
|
||||||
|
# Reconnect to foo db and check data made it over:
|
||||||
|
{
|
||||||
|
my $foo = connect_ok( RaiseError => 1 );
|
||||||
|
|
||||||
|
my ($count) = $foo->selectrow_array(
|
||||||
|
"SELECT count(foo) FROM online_backup_test2 WHERE foo=$$"
|
||||||
|
);
|
||||||
|
is($count, 1, "Found our process ID in table back on disk");
|
||||||
|
|
||||||
|
$foo->disconnect;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue