mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 19:23:03 +01:00
Fixed CORE-1124.
This commit is contained in:
parent
19df9afe07
commit
367a315eec
@ -185,7 +185,7 @@ private:
|
|||||||
ISC_STATUS_ARRAY status; /* status vector */
|
ISC_STATUS_ARRAY status; /* status vector */
|
||||||
isc_db_handle newdb; /* database handle */
|
isc_db_handle newdb; /* database handle */
|
||||||
isc_tr_handle trans; /* transaction handle */
|
isc_tr_handle trans; /* transaction handle */
|
||||||
|
|
||||||
Firebird::PathName database;
|
Firebird::PathName database;
|
||||||
Firebird::string username;
|
Firebird::string username;
|
||||||
Firebird::string password;
|
Firebird::string password;
|
||||||
@ -194,25 +194,25 @@ private:
|
|||||||
Firebird::PathName bakname;
|
Firebird::PathName bakname;
|
||||||
FILE_HANDLE dbase;
|
FILE_HANDLE dbase;
|
||||||
FILE_HANDLE backup;
|
FILE_HANDLE backup;
|
||||||
|
|
||||||
// IO functions
|
// IO functions
|
||||||
size_t read_file(FILE_HANDLE &file, void *buffer, size_t bufsize);
|
size_t read_file(FILE_HANDLE &file, void *buffer, size_t bufsize);
|
||||||
void write_file(FILE_HANDLE &file, void *buffer, size_t bufsize);
|
void write_file(FILE_HANDLE &file, void *buffer, size_t bufsize);
|
||||||
void seek_file(FILE_HANDLE &file, SINT64 pos);
|
void seek_file(FILE_HANDLE &file, SINT64 pos);
|
||||||
|
|
||||||
static void pr_error(const ISC_STATUS* status, const char* operation);
|
static void pr_error(const ISC_STATUS* status, const char* operation);
|
||||||
|
|
||||||
void internal_lock_database();
|
void internal_lock_database();
|
||||||
void internal_unlock_database();
|
void internal_unlock_database();
|
||||||
void attach_database();
|
void attach_database();
|
||||||
void detach_database();
|
void detach_database();
|
||||||
|
|
||||||
// Create/open database and backup
|
// Create/open database and backup
|
||||||
void open_database_write();
|
void open_database_write();
|
||||||
void open_database_scan();
|
void open_database_scan();
|
||||||
void create_database();
|
void create_database();
|
||||||
void close_database();
|
void close_database();
|
||||||
|
|
||||||
void open_backup_scan();
|
void open_backup_scan();
|
||||||
void create_backup();
|
void create_backup();
|
||||||
void close_backup();
|
void close_backup();
|
||||||
@ -433,7 +433,7 @@ void nbackup::attach_database()
|
|||||||
b_error::raise("Username or password is too long");
|
b_error::raise("Username or password is too long");
|
||||||
|
|
||||||
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
|
Firebird::ClumpletWriter dpb(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
|
||||||
|
|
||||||
if (!username.isEmpty()) {
|
if (!username.isEmpty()) {
|
||||||
dpb.insertString(isc_dpb_user_name, username);
|
dpb.insertString(isc_dpb_user_name, username);
|
||||||
}
|
}
|
||||||
@ -525,7 +525,7 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
XSQLDA *out_sqlda = (XSQLDA*)out_sqlda_data;
|
XSQLDA *out_sqlda = (XSQLDA*)out_sqlda_data;
|
||||||
out_sqlda->version = SQLDA_VERSION1;
|
out_sqlda->version = SQLDA_VERSION1;
|
||||||
out_sqlda->sqln = 2;
|
out_sqlda->sqln = 2;
|
||||||
|
|
||||||
isc_stmt_handle stmt = 0;
|
isc_stmt_handle stmt = 0;
|
||||||
if (isc_dsql_allocate_statement(status, &newdb, &stmt))
|
if (isc_dsql_allocate_statement(status, &newdb, &stmt))
|
||||||
pr_error(status, "allocate statement");
|
pr_error(status, "allocate statement");
|
||||||
@ -545,7 +545,7 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
out_sqlda->sqlvar[1].sqldata = (char*)&prev_scn;
|
out_sqlda->sqlvar[1].sqldata = (char*)&prev_scn;
|
||||||
if (isc_dsql_execute(status, &trans, &stmt, 1, NULL))
|
if (isc_dsql_execute(status, &trans, &stmt, 1, NULL))
|
||||||
pr_error(status, "execute history query");
|
pr_error(status, "execute history query");
|
||||||
|
|
||||||
switch (isc_dsql_fetch(status, &stmt, 1, out_sqlda)) {
|
switch (isc_dsql_fetch(status, &stmt, 1, out_sqlda)) {
|
||||||
case 100: /* No more records available */
|
case 100: /* No more records available */
|
||||||
b_error::raise("Cannot find record for database \"%s\" backup level %d "
|
b_error::raise("Cannot find record for database \"%s\" backup level %d "
|
||||||
@ -562,14 +562,14 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
if (isc_commit_transaction(status, &trans))
|
if (isc_commit_transaction(status, &trans))
|
||||||
pr_error(status, "commit history query");
|
pr_error(status, "commit history query");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock database for backup
|
// Lock database for backup
|
||||||
internal_lock_database();
|
internal_lock_database();
|
||||||
database_locked = true;
|
database_locked = true;
|
||||||
|
|
||||||
time_t _time = time(NULL);
|
time_t _time = time(NULL);
|
||||||
const struct tm *today = localtime(&_time);
|
const struct tm *today = localtime(&_time);
|
||||||
|
|
||||||
if (fname)
|
if (fname)
|
||||||
bakname = fname;
|
bakname = fname;
|
||||||
else {
|
else {
|
||||||
@ -589,20 +589,20 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
// used directly after fixup. Incremenal backups of other levels are
|
// used directly after fixup. Incremenal backups of other levels are
|
||||||
// consisted of header followed by page data. Each page is preceded
|
// consisted of header followed by page data. Each page is preceded
|
||||||
// by 4-byte integer page number
|
// by 4-byte integer page number
|
||||||
|
|
||||||
// Actual IO is optimized to get maximum performance
|
// Actual IO is optimized to get maximum performance
|
||||||
// from the IO subsystem while taking as little CPU time as possible
|
// from the IO subsystem while taking as little CPU time as possible
|
||||||
|
|
||||||
// NOTE: this is still possible to improve performance by implementing
|
// NOTE: this is still possible to improve performance by implementing
|
||||||
// version using asynchronous unbuffered IO on NT series of OS.
|
// version using asynchronous unbuffered IO on NT series of OS.
|
||||||
// But this task is for another day. 02 Aug 2003, Nickolay Samofatov.
|
// But this task is for another day. 02 Aug 2003, Nickolay Samofatov.
|
||||||
|
|
||||||
// Create backup file and open database file
|
// Create backup file and open database file
|
||||||
create_backup();
|
create_backup();
|
||||||
delete_backup = true;
|
delete_backup = true;
|
||||||
|
|
||||||
open_database_scan();
|
open_database_scan();
|
||||||
|
|
||||||
// Read database header
|
// Read database header
|
||||||
char unaligned_header_buffer[SECTOR_ALIGNMENT * 2];
|
char unaligned_header_buffer[SECTOR_ALIGNMENT * 2];
|
||||||
|
|
||||||
@ -616,7 +616,7 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
b_error::raise("Internal error. Database file is not locked. Flags are %d",
|
b_error::raise("Internal error. Database file is not locked. Flags are %d",
|
||||||
header->hdr_flags);
|
header->hdr_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Firebird::Array<UCHAR> unaligned_page_buffer;
|
Firebird::Array<UCHAR> unaligned_page_buffer;
|
||||||
page_buff = reinterpret_cast<Ods::pag*>(
|
page_buff = reinterpret_cast<Ods::pag*>(
|
||||||
FB_ALIGN(
|
FB_ALIGN(
|
||||||
@ -625,12 +625,12 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
SECTOR_ALIGNMENT
|
SECTOR_ALIGNMENT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
seek_file(dbase, 0);
|
seek_file(dbase, 0);
|
||||||
|
|
||||||
if (read_file(dbase, page_buff, header->hdr_page_size) != header->hdr_page_size)
|
if (read_file(dbase, page_buff, header->hdr_page_size) != header->hdr_page_size)
|
||||||
b_error::raise("Unexpected end of file when reading header of database file (stage 2)");
|
b_error::raise("Unexpected end of file when reading header of database file (stage 2)");
|
||||||
|
|
||||||
FB_GUID backup_guid;
|
FB_GUID backup_guid;
|
||||||
bool guid_found = false;
|
bool guid_found = false;
|
||||||
const UCHAR* p = reinterpret_cast<Ods::header_page*>(page_buff)->hdr_data;
|
const UCHAR* p = reinterpret_cast<Ods::header_page*>(page_buff)->hdr_data;
|
||||||
@ -648,11 +648,10 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!guid_found)
|
if (!guid_found)
|
||||||
b_error::raise("Internal error. Cannot get backup guid clumplet");
|
b_error::raise("Internal error. Cannot get backup guid clumplet");
|
||||||
|
|
||||||
|
|
||||||
// Write data to backup file
|
// Write data to backup file
|
||||||
ULONG backup_scn = header->hdr_header.pag_scn - 1;
|
ULONG backup_scn = header->hdr_header.pag_scn - 1;
|
||||||
if (level) {
|
if (level) {
|
||||||
@ -667,7 +666,7 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
bh.prev_scn = prev_scn;
|
bh.prev_scn = prev_scn;
|
||||||
write_file(backup, &bh, sizeof(bh));
|
write_file(backup, &bh, sizeof(bh));
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG curPage = 0;
|
ULONG curPage = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (curPage && page_buff->pag_scn > backup_scn)
|
if (curPage && page_buff->pag_scn > backup_scn)
|
||||||
@ -691,9 +690,9 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
}
|
}
|
||||||
close_database();
|
close_database();
|
||||||
close_backup();
|
close_backup();
|
||||||
|
|
||||||
delete_backup = false; // Backup file is consistent. No need to delete it
|
delete_backup = false; // Backup file is consistent. No need to delete it
|
||||||
|
|
||||||
// Write about successful backup to backup history table
|
// Write about successful backup to backup history table
|
||||||
if (isc_start_transaction(status, &trans, 1, &newdb, 0, NULL))
|
if (isc_start_transaction(status, &trans, 1, &newdb, 0, NULL))
|
||||||
pr_error(status, "start transaction");
|
pr_error(status, "start transaction");
|
||||||
@ -736,7 +735,7 @@ void nbackup::backup_database(int level, const char* fname)
|
|||||||
pr_error(status, "execute history insert");
|
pr_error(status, "execute history insert");
|
||||||
if (isc_commit_transaction(status, &trans))
|
if (isc_commit_transaction(status, &trans))
|
||||||
pr_error(status, "commit history insert");
|
pr_error(status, "commit history insert");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const Firebird::Exception&) {
|
catch (const Firebird::Exception&) {
|
||||||
if (delete_backup)
|
if (delete_backup)
|
||||||
@ -786,16 +785,15 @@ void nbackup::restore_database(int filecount, const char* const* files)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
open_backup_scan();
|
#ifdef WIN_NT
|
||||||
|
if (curLevel)
|
||||||
|
#endif
|
||||||
|
open_backup_scan();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (const Firebird::Exception& e) {
|
catch (const Firebird::Exception& e) {
|
||||||
printf("%s\n", e.what());
|
printf("%s\n", e.what());
|
||||||
}
|
}
|
||||||
#ifdef WIN_NT
|
|
||||||
if (curLevel)
|
|
||||||
close_backup();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -813,7 +811,7 @@ void nbackup::restore_database(int filecount, const char* const* files)
|
|||||||
open_backup_scan();
|
open_backup_scan();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curLevel) {
|
if (curLevel) {
|
||||||
inc_header bakheader;
|
inc_header bakheader;
|
||||||
if (read_file(backup, &bakheader, sizeof(bakheader)) != sizeof(bakheader))
|
if (read_file(backup, &bakheader, sizeof(bakheader)) != sizeof(bakheader))
|
||||||
@ -873,12 +871,12 @@ void nbackup::restore_database(int filecount, const char* const* files)
|
|||||||
if (read_file(dbase, &header, sizeof(header)) != sizeof(header))
|
if (read_file(dbase, &header, sizeof(header)) != sizeof(header))
|
||||||
b_error::raise("Unexpected end of file when reading restored database header");
|
b_error::raise("Unexpected end of file when reading restored database header");
|
||||||
page_buffer = FB_NEW(*getDefaultMemoryPool()) UCHAR[header.hdr_page_size];
|
page_buffer = FB_NEW(*getDefaultMemoryPool()) UCHAR[header.hdr_page_size];
|
||||||
|
|
||||||
seek_file(dbase, 0);
|
seek_file(dbase, 0);
|
||||||
|
|
||||||
if (read_file(dbase, page_buffer, header.hdr_page_size) != header.hdr_page_size)
|
if (read_file(dbase, page_buffer, header.hdr_page_size) != header.hdr_page_size)
|
||||||
b_error::raise("Unexpected end of file when reading header of restored database file (stage 2)");
|
b_error::raise("Unexpected end of file when reading header of restored database file (stage 2)");
|
||||||
|
|
||||||
bool guid_found = false;
|
bool guid_found = false;
|
||||||
const UCHAR* p = reinterpret_cast<Ods::header_page*>(page_buffer)->hdr_data;
|
const UCHAR* p = reinterpret_cast<Ods::header_page*>(page_buffer)->hdr_data;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -900,7 +898,10 @@ void nbackup::restore_database(int filecount, const char* const* files)
|
|||||||
// We are likely to have normal database here
|
// We are likely to have normal database here
|
||||||
delete_database = false;
|
delete_database = false;
|
||||||
}
|
}
|
||||||
close_backup();
|
#ifdef WIN_NT
|
||||||
|
if (curLevel)
|
||||||
|
#endif
|
||||||
|
close_backup();
|
||||||
curLevel++;
|
curLevel++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -928,7 +929,7 @@ int main( int argc, char *argv[] )
|
|||||||
const char* const* backup_files = NULL;
|
const char* const* backup_files = NULL;
|
||||||
int level;
|
int level;
|
||||||
int filecount;
|
int filecount;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Read global command line parameters
|
// Read global command line parameters
|
||||||
for (char** argp = argv + 1; argp < end; argp++) {
|
for (char** argp = argv + 1; argp < end; argp++) {
|
||||||
@ -1028,7 +1029,7 @@ int main( int argc, char *argv[] )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case nbNone:
|
case nbNone:
|
||||||
usage();
|
usage();
|
||||||
@ -1059,7 +1060,6 @@ int main( int argc, char *argv[] )
|
|||||||
// It must have been printed out. No need to repeat the task
|
// It must have been printed out. No need to repeat the task
|
||||||
return EXIT_ERROR;
|
return EXIT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_OK;
|
return EXIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user