Skip to content

Commit ce22ccc

Browse files
BohwaZcmb69
BohwaZ
authored andcommitted
Implement SQLite3 backup API
1 parent d924b42 commit ce22ccc

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ PHP NEWS
1111
. Fixed bug #78106 (Path resolution fails if opcache disabled during request).
1212
(Nikita)
1313

14+
- SQLite3:
15+
. Implement FR ##70950 (Make SQLite3 Online Backup API available). (BohwaZ)
16+
1417
13 Jun 2019, PHP 7.4.0alpha1
1518

1619
- Core:

UPGRADING

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ PHP 7.4 UPGRADE NOTES
370370
. Added SQLite3Stmt::getSQL() to retrieve the SQL of the statement. If TRUE is
371371
passed as parameter, query parameters will be replaced in the return value
372372
by their currently bound value, if libsqlite ≥ 3.14 is used.
373+
. Added SQLite3::backup() to create database backups via the SQLite3 online
374+
backup API.
373375

374376
- Standard
375377
. bool sapi_windows_set_ctrl_handler(callable handler, [, bool add = true]) -

ext/sqlite3/sqlite3.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,63 @@ PHP_METHOD(sqlite3, enableExceptions)
12941294
}
12951295
/* }}} */
12961296

1297+
#if SQLITE_VERSION_NUMBER >= 3006011
1298+
/* {{{ proto bool SQLite3::backup(SQLite3 destination_db[, string source_dbname = "main"[, string destination_dbname = "main"]])
1299+
Backups the current database to another one. */
1300+
PHP_METHOD(sqlite3, backup)
1301+
{
1302+
php_sqlite3_db_object *source_obj;
1303+
php_sqlite3_db_object *destination_obj;
1304+
char *source_dbname = "main", *destination_dbname = "main";
1305+
size_t source_dbname_length, destination_dbname_length;
1306+
zval *source_zval = ZEND_THIS;
1307+
zval *destination_zval;
1308+
sqlite3_backup *dbBackup;
1309+
int rc; // Return code
1310+
1311+
source_obj = Z_SQLITE3_DB_P(source_zval);
1312+
SQLITE3_CHECK_INITIALIZED(source_obj, source_obj->initialised, SQLite3)
1313+
1314+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|ss", &destination_zval, php_sqlite3_sc_entry, &source_dbname, &source_dbname_length, &destination_dbname, &destination_dbname_length) == FAILURE) {
1315+
return;
1316+
}
1317+
1318+
destination_obj = Z_SQLITE3_DB_P(destination_zval);
1319+
1320+
SQLITE3_CHECK_INITIALIZED(destination_obj, destination_obj->initialised, SQLite3)
1321+
1322+
dbBackup = sqlite3_backup_init(destination_obj->db, destination_dbname, source_obj->db, source_dbname);
1323+
1324+
if (dbBackup) {
1325+
do {
1326+
rc = sqlite3_backup_step(dbBackup, -1);
1327+
} while (rc == SQLITE_OK);
1328+
1329+
/* Release resources allocated by backup_init(). */
1330+
rc = sqlite3_backup_finish(dbBackup);
1331+
}
1332+
else {
1333+
rc = sqlite3_errcode(source_obj->db);
1334+
}
1335+
1336+
if (rc != SQLITE_OK) {
1337+
if (rc == SQLITE_BUSY) {
1338+
php_sqlite3_error(source_obj, "Backup failed: source database is busy");
1339+
}
1340+
else if (rc == SQLITE_LOCKED) {
1341+
php_sqlite3_error(source_obj, "Backup failed: source database is locked");
1342+
}
1343+
else {
1344+
php_sqlite3_error(source_obj, "Backup failed: %d, %s", rc, sqlite3_errmsg(source_obj->db));
1345+
}
1346+
RETURN_FALSE;
1347+
}
1348+
1349+
RETURN_TRUE;
1350+
}
1351+
/* }}} */
1352+
#endif
1353+
12971354
/* {{{ proto int SQLite3Stmt::paramCount()
12981355
Returns the number of parameters within the prepared statement. */
12991356
PHP_METHOD(sqlite3stmt, paramCount)
@@ -2058,6 +2115,14 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_enableexceptions, 0, 0, 0)
20582115
ZEND_ARG_INFO(0, enableExceptions)
20592116
ZEND_END_ARG_INFO()
20602117

2118+
#if SQLITE_VERSION_NUMBER >= 3006011
2119+
ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_backup, 0, 0, 1)
2120+
ZEND_ARG_INFO(0, destination_db)
2121+
ZEND_ARG_INFO(0, source_dbname)
2122+
ZEND_ARG_INFO(0, destination_dbname)
2123+
ZEND_END_ARG_INFO()
2124+
#endif
2125+
20612126
ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3stmt_bindparam, 0, 0, 2)
20622127
ZEND_ARG_INFO(0, param_number)
20632128
ZEND_ARG_INFO(1, param)
@@ -2117,6 +2182,9 @@ static const zend_function_entry php_sqlite3_class_methods[] = {
21172182
PHP_ME(sqlite3, createCollation, arginfo_sqlite3_createcollation, ZEND_ACC_PUBLIC)
21182183
PHP_ME(sqlite3, openBlob, arginfo_sqlite3_openblob, ZEND_ACC_PUBLIC)
21192184
PHP_ME(sqlite3, enableExceptions, arginfo_sqlite3_enableexceptions, ZEND_ACC_PUBLIC)
2185+
#if SQLITE_VERSION_NUMBER >= 3006011
2186+
PHP_ME(sqlite3, backup, arginfo_sqlite3_backup, ZEND_ACC_PUBLIC)
2187+
#endif
21202188
/* Aliases */
21212189
PHP_MALIAS(sqlite3, __construct, open, arginfo_sqlite3_open, ZEND_ACC_PUBLIC)
21222190
PHP_FE_END
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
SQLite3::backup test
3+
--SKIPIF--
4+
<?php require_once(__DIR__ . '/skipif.inc'); ?>
5+
--FILE--
6+
<?php
7+
8+
require_once(__DIR__ . '/new_db.inc');
9+
10+
echo "Creating table\n";
11+
$db->exec('CREATE TABLE test (a, b);');
12+
$db->exec('INSERT INTO test VALUES (42, \'php\');');
13+
14+
echo "Checking if table has been created\n";
15+
var_dump($db->querySingle('SELECT COUNT(*) FROM sqlite_master;'));
16+
17+
$db2 = new SQLite3(':memory:');
18+
19+
echo "Backup to DB2\n";
20+
var_dump($db->backup($db2));
21+
22+
echo "Checking if table has been copied\n";
23+
var_dump($db2->querySingle('SELECT COUNT(*) FROM sqlite_master;'));
24+
25+
echo "Checking backup contents\n";
26+
var_dump($db2->querySingle('SELECT a FROM test;'));
27+
var_dump($db2->querySingle('SELECT b FROM test;'));
28+
29+
echo "Resetting DB2\n";
30+
31+
$db2->close();
32+
$db2 = new SQLite3(':memory:');
33+
34+
echo "Locking DB1\n";
35+
var_dump($db->exec('BEGIN EXCLUSIVE;'));
36+
37+
echo "Backup to DB2 (should fail)\n";
38+
var_dump($db->backup($db2));
39+
40+
?>
41+
--EXPECTF--
42+
Creating table
43+
Checking if table has been created
44+
int(1)
45+
Backup to DB2
46+
bool(true)
47+
Checking if table has been copied
48+
int(1)
49+
Checking backup contents
50+
int(42)
51+
string(3) "php"
52+
Resetting DB2
53+
Locking DB1
54+
bool(true)
55+
Backup to DB2 (should fail)
56+
57+
Warning: SQLite3::backup(): Backup failed: source database is busy in %s on line %d
58+
bool(false)

0 commit comments

Comments
 (0)