Hello, all.


Ok, I ask Dmitry Starodubov to create a patch for FB3.0 and publish it
for review.

Nikolay


Patch against FB HEAD in attach.

Dmitry
Index: lang_helpers/gds_codes.ftn
===================================================================
--- lang_helpers/gds_codes.ftn  (revision 58043)
+++ lang_helpers/gds_codes.ftn  (working copy)
@@ -2392,6 +2392,8 @@
       PARAMETER (GDS__nbackup_switchd_parameter        = 337117255)
       INTEGER*4 GDS__nbackup_user_stop               
       PARAMETER (GDS__nbackup_user_stop                = 337117257)
+      INTEGER*4 GDS__nbackup_lostrec_guid_db         
+      PARAMETER (GDS__nbackup_lostrec_guid_db          = 337117258)
       INTEGER*4 GDS__trace_conflict_acts             
       PARAMETER (GDS__trace_conflict_acts              = 337182750)
       INTEGER*4 GDS__trace_act_notfound              
Index: lang_helpers/gds_codes.pas
===================================================================
--- lang_helpers/gds_codes.pas  (revision 58043)
+++ lang_helpers/gds_codes.pas  (working copy)
@@ -1203,6 +1203,7 @@
        gds_nbackup_lostguid_l0bk            = 337117251;
        gds_nbackup_switchd_parameter        = 337117255;
        gds_nbackup_user_stop                = 337117257;
+       gds_nbackup_lostrec_guid_db          = 337117258;
        gds_trace_conflict_acts              = 337182750;
        gds_trace_act_notfound               = 337182751;
        gds_trace_switch_once                = 337182752;
Index: src/common/classes/ClumpletReader.cpp
===================================================================
--- src/common/classes/ClumpletReader.cpp       (revision 58043)
+++ src/common/classes/ClumpletReader.cpp       (working copy)
@@ -432,6 +432,7 @@
                        case isc_spb_nbk_file:
                        case isc_spb_nbk_direct:
                        case isc_spb_dbname:
+                       case isc_spb_nbk_guid:
                                return StringSpb;
                        case isc_spb_nbk_level:
                        case isc_spb_options:
Index: src/include/consts_pub.h
===================================================================
--- src/include/consts_pub.h    (revision 58043)
+++ src/include/consts_pub.h    (working copy)
@@ -530,7 +530,9 @@
 #define isc_spb_nbk_level                      5
 #define isc_spb_nbk_file                       6
 #define isc_spb_nbk_direct                     7
+#define isc_spb_nbk_guid                       8
 #define isc_spb_nbk_no_triggers                0x01
+#define isc_spb_nbk_inplace                    0x02
 
 /***************************************
  * Parameters for isc_action_svc_trace *
Index: src/include/gen/codetext.h
===================================================================
--- src/include/gen/codetext.h  (revision 58043)
+++ src/include/gen/codetext.h  (working copy)
@@ -1192,6 +1192,7 @@
        {"nbackup_lostguid_l0bk", 337117251},
        {"nbackup_switchd_parameter", 337117255},
        {"nbackup_user_stop", 337117257},
+       {"nbackup_lostrec_guid_db", 337117258},
        {"trace_conflict_acts", 337182750},
        {"trace_act_notfound", 337182751},
        {"trace_switch_once", 337182752},
Index: src/include/gen/iberror.h
===================================================================
--- src/include/gen/iberror.h   (revision 58043)
+++ src/include/gen/iberror.h   (working copy)
@@ -1226,6 +1226,7 @@
 const ISC_STATUS isc_nbackup_lostguid_l0bk            = 337117251L;
 const ISC_STATUS isc_nbackup_switchd_parameter        = 337117255L;
 const ISC_STATUS isc_nbackup_user_stop                = 337117257L;
+const ISC_STATUS isc_nbackup_lostrec_guid_db          = 337117258L;
 const ISC_STATUS isc_trace_conflict_acts              = 337182750L;
 const ISC_STATUS isc_trace_act_notfound               = 337182751L;
 const ISC_STATUS isc_trace_switch_once                = 337182752L;
@@ -1237,7 +1238,7 @@
 const ISC_STATUS isc_trace_switch_param_miss          = 337182758L;
 const ISC_STATUS isc_trace_param_act_notcompat        = 337182759L;
 const ISC_STATUS isc_trace_mandatory_switch_miss      = 337182760L;
-const ISC_STATUS isc_err_max                          = 1181;
+const ISC_STATUS isc_err_max                          = 1182;
 
 #else /* c definitions */
 
@@ -2433,6 +2434,7 @@
 #define isc_nbackup_lostguid_l0bk            337117251L
 #define isc_nbackup_switchd_parameter        337117255L
 #define isc_nbackup_user_stop                337117257L
+#define isc_nbackup_lostrec_guid_db          337117258L
 #define isc_trace_conflict_acts              337182750L
 #define isc_trace_act_notfound               337182751L
 #define isc_trace_switch_once                337182752L
@@ -2444,7 +2446,7 @@
 #define isc_trace_switch_param_miss          337182758L
 #define isc_trace_param_act_notcompat        337182759L
 #define isc_trace_mandatory_switch_miss      337182760L
-#define isc_err_max                          1181
+#define isc_err_max                          1182
 
 #endif
 
Index: src/include/gen/msgs.h
===================================================================
--- src/include/gen/msgs.h      (revision 58043)
+++ src/include/gen/msgs.h      (working copy)
@@ -1195,6 +1195,7 @@
        {337117251, "Cannot get backup guid clumplet from L0 backup"},          
/* nbackup_lostguid_l0bk */
        {337117255, "Wrong parameter @1 for switch -D, need ON or OFF"},        
        /* nbackup_switchd_parameter */
        {337117257, "Terminated due to user request"},          /* 
nbackup_user_stop */
+       {337117258, "Cannot find record for database \"@1\" backup GUID @2 in 
the backup history"},             /* nbackup_lostrec_guid_db */
        {337182750, "conflicting actions \"@1\" and \"@2\" found"},             
/* trace_conflict_acts */
        {337182751, "action switch not found"},         /* trace_act_notfound */
        {337182752, "switch \"@1\" must be set only once"},             /* 
trace_switch_once */
Index: src/include/gen/sql_code.h
===================================================================
--- src/include/gen/sql_code.h  (revision 58043)
+++ src/include/gen/sql_code.h  (working copy)
@@ -1191,6 +1191,7 @@
        {337117251, -901}, /*  67 nbackup_lostguid_l0bk */
        {337117255, -901}, /*  71 nbackup_switchd_parameter */
        {337117257, -901}, /*  73 nbackup_user_stop */
+       {337117258, -901}, /*  74 nbackup_lostrec_guid_db */
        {337182750, -901}, /*  30 trace_conflict_acts */
        {337182751, -901}, /*  31 trace_act_notfound */
        {337182752, -901}, /*  32 trace_switch_once */
Index: src/include/gen/sql_state.h
===================================================================
--- src/include/gen/sql_state.h (revision 58043)
+++ src/include/gen/sql_state.h (working copy)
@@ -1191,6 +1191,7 @@
        {337117251, "00000"}, //  67 nbackup_lostguid_l0bk
        {337117255, "00000"}, //  71 nbackup_switchd_parameter
        {337117257, "08006"}, //  73 nbackup_user_stop
+       {337117258, "00000"}, //  74 nbackup_lostrec_guid_db
        {337182750, "00000"}, //  30 trace_conflict_acts
        {337182751, "00000"}, //  31 trace_act_notfound
        {337182752, "00000"}, //  32 trace_switch_once
Index: src/jrd/svc.cpp
===================================================================
--- src/jrd/svc.cpp     (revision 58043)
+++ src/jrd/svc.cpp     (working copy)
@@ -2571,6 +2571,7 @@
 
        string nbk_database, nbk_file;
        int nbk_level = -1;
+       string nbk_guid;
 
        bool found = false;
 
@@ -2593,13 +2594,23 @@
                                break;
 
                        case isc_spb_nbk_level:
-                               if (nbk_level >= 0)
+                               if (nbk_level >= 0 || nbk_guid.hasData())
                                {
-                                       (Arg::Gds(isc_unexp_spb_form) << 
Arg::Str("only one isc_spb_nbk_level")).raise();
+                                       (Arg::Gds(isc_unexp_spb_form) <<
+                                               Arg::Str("only one 
isc_spb_nbk_level or isc_spb_nbk_guid")).raise();
                                }
                                nbk_level = spb.getInt();
                                break;
 
+                       case isc_spb_nbk_guid:
+                               if (nbk_level >= 0 || nbk_guid.hasData())
+                               {
+                                       (Arg::Gds(isc_unexp_spb_form) <<
+                                               Arg::Str("only one 
isc_spb_nbk_level or isc_spb_nbk_guid")).raise();
+                               }
+                               get_action_svc_string(spb, nbk_guid);
+                               break;
+
                        case isc_spb_nbk_file:
                                if (nbk_file.hasData() && svc_action != 
isc_action_svc_nrest)
                                {
@@ -2987,13 +2998,19 @@
                }
                if (svc_action == isc_action_svc_nbak)
                {
-                       if (nbk_level < 0)
+                       if (nbk_level < 0 && nbk_guid.isEmpty())
                        {
-                               (Arg::Gds(isc_missing_required_spb) << 
Arg::Str("isc_spb_nbk_level")).raise();
+                               (Arg::Gds(isc_missing_required_spb) <<
+                                       Arg::Str("isc_spb_nbk_level or 
isc_spb_nbk_guid")).raise();
                        }
-                       string temp;
-                       temp.printf("%d ", nbk_level);
-                       switches += temp;
+                       if (nbk_level >= 0)
+                       {
+                               string temp;
+                               temp.printf("%d ", nbk_level);
+                               switches += temp;
+                       }
+                       else
+                               switches += nbk_guid;
                }
                switches += nbk_database;
                switches += nbk_file;
Index: src/msgs/facilities2.sql
===================================================================
--- src/msgs/facilities2.sql    (revision 58043)
+++ src/msgs/facilities2.sql    (working copy)
@@ -18,7 +18,7 @@
 ('2012-05-25 19:59:42', 'GSTAT', 21, 56)
 ('2009-12-18 19:33:34', 'FBSVCMGR', 22, 57)
 ('2009-07-18 12:12:12', 'UTL', 23, 2)
-('2011-05-25 16:17:34', 'NBACKUP', 24, 74)
+('2011-05-25 16:17:34', 'NBACKUP', 24, 77)
 ('2009-07-20 07:55:48', 'FBTRACEMGR', 25, 41)
 stop
 
Index: src/msgs/messages2.sql
===================================================================
--- src/msgs/messages2.sql      (revision 58043)
+++ src/msgs/messages2.sql      (working copy)
@@ -3153,7 +3153,7 @@
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 8, NULL, '  -L(OCK) <database>        
             Lock database for filesystem copy', NULL, NULL)
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 9, NULL, '  -UN(LOCK) <database>      
             Unlock previously locked database', NULL, NULL)
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 10, NULL, '  -F(IXUP) <database>      
              Fixup database after filesystem copy', NULL, NULL)
-(NULL, 'usage', 'nbackup.cpp', NULL, 24, 11, NULL, '  -B(ACKUP) <level> <db> 
[<file>]        Create incremental backup', NULL, NULL)
+(NULL, 'usage', 'nbackup.cpp', NULL, 24, 11, NULL, '  -B(ACKUP) <level>|<GUID> 
<db> [<file>] Create incremental backup', NULL, NULL)
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 12, NULL, '  -R(ESTORE) <db> [<file0> 
[<file1>...]] Restore incremental backup', NULL, NULL)
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 13, NULL, '  -U(SER) <user>           
              User name', NULL, NULL)
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 14, NULL, '  -P(ASSWORD) <password>   
              Password', NULL, NULL)
@@ -3216,6 +3216,9 @@
 ('nbackup_switchd_parameter', 'main', 'nbackup.cpp', NULL, 24, 71, NULL, 
'Wrong parameter @1 for switch -D, need ON or OFF', NULL, NULL)
 (NULL, 'usage', 'nbackup.cpp', NULL, 24, 72, NULL, 'special options are:', 
NULL, NULL)
 ('nbackup_user_stop', 'checkCtrlC()', 'nbackup.cpp', NULL, 24, 73, NULL, 
'Terminated due to user request', NULL, NULL)
+('nbackup_lostrec_guid_db', 'NBackup::backup_database', 'nbackup.cpp', NULL, 
24, 74, NULL, 'Cannot find record for database "@1" backup GUID @2 in the 
backup history', NULL, NULL)
+(NULL, 'usage', 'nbackup.cpp', NULL, 24, 75, NULL, '  -I                       
              Restore incremental backup(s) to existing database', NULL, NULL)
+(NULL, 'usage', 'nbackup.cpp', NULL, 24, 76, NULL, '  -I option could corrupt 
the database that has changed since previous restore', NULL, NULL)
 -- FBTRACEMGR
 -- All messages use the new format.
 (NULL, 'usage', 'TraceCmdLine.cpp', NULL, 25, 1, NULL, 'Firebird Trace Manager 
version @1', NULL, NULL)
Index: src/msgs/system_errors2.sql
===================================================================
--- src/msgs/system_errors2.sql (revision 58043)
+++ src/msgs/system_errors2.sql (working copy)
@@ -1190,6 +1190,7 @@
 (-901, '00', '000', 24, 67, 'nbackup_lostguid_l0bk', NULL, NULL)
 (-901, '00', '000', 24, 71, 'nbackup_switchd_parameter', NULL, NULL)
 (-901, '08', '006', 24, 73, 'nbackup_user_stop', NULL, NULL)
+(-901, '00', '000', 24, 74, 'nbackup_lostrec_guid_db', NULL, NULL)
 -- FBTRACEMGR
 (-901, '00', '000', 25, 30, 'trace_conflict_acts', NULL, NULL)
 (-901, '00', '000', 25, 31, 'trace_act_notfound', NULL, NULL)
Index: src/utilities/fbsvcmgr/fbsvcmgr.cpp
===================================================================
--- src/utilities/fbsvcmgr/fbsvcmgr.cpp (revision 58043)
+++ src/utilities/fbsvcmgr/fbsvcmgr.cpp (working copy)
@@ -456,6 +456,7 @@
        {"dbname", putStringArgument, 0, isc_spb_dbname, 0},
        {"nbk_file", putStringArgument, 0, isc_spb_nbk_file, 0},
        {"nbk_level", putNumericArgument, 0, isc_spb_nbk_level, 0},
+       {"nbk_guid", putStringArgument, 0, isc_spb_nbk_guid, 0},
        {"nbk_no_triggers", putOption, 0, isc_spb_nbk_no_triggers, 0},
        {"nbk_direct", putStringArgument, 0, isc_spb_nbk_direct, 0},
        {0, 0, 0, 0, 0}
@@ -465,6 +466,7 @@
 {
        {"dbname", putStringArgument, 0, isc_spb_dbname, 0},
        {"nbk_file", putStringArgument, 0, isc_spb_nbk_file, 0},
+       {"nbk_inplace", putOption, 0, isc_spb_nbk_inplace, 0},
        {0, 0, 0, 0, 0}
 };
 
Index: src/utilities/nbackup/nbackup.cpp
===================================================================
--- src/utilities/nbackup/nbackup.cpp   (revision 58043)
+++ src/utilities/nbackup/nbackup.cpp   (working copy)
@@ -135,7 +135,7 @@
                }
 
                const int mainUsage[] = { 2, 3, 4, 5, 6, 0 };
-               const int notes[] = { 19, 20, 21, 22, 26, 27, 28, 0 };
+               const int notes[] = { 19, 20, 21, 22, 26, 27, 28, 76, 0 };
                const Switches::in_sw_tab_t* const base = 
nbackup_action_in_sw_table;
 
                for (int i = 0; mainUsage[i]; ++i)
@@ -293,11 +293,11 @@
        typedef ObjectsArray<PathName> BackupFiles;
 
        // External calls must clean up resources after themselves
-       void fixup_database();
+       void fixup_database(bool set_readonly = false);
        void lock_database(bool get_size);
        void unlock_database();
-       void backup_database(int level, const PathName& fname);
-       void restore_database(const BackupFiles& files);
+       void backup_database(int level, Guid& guid, const PathName& fname);
+       void restore_database(const BackupFiles& files, bool inc_rest = false);
 
        bool printed()
        {
@@ -337,7 +337,7 @@
        void detach_database();
 
        // Create/open database and backup
-       void open_database_write();
+       void open_database_write(bool exclusive = false);
        void open_database_scan();
        void create_database();
        void close_database();
@@ -407,16 +407,19 @@
                Arg::OsError());
 }
 
-void NBackup::open_database_write()
+void NBackup::open_database_write(bool exclusive)
 {
 #ifdef WIN_NT
+       const DWORD shareFlags = exclusive ? FILE_SHARE_READ : 
+               FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
        dbase = CreateFile(dbname.c_str(), GENERIC_READ | GENERIC_WRITE,
-               FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-               NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+               shareFlags,     NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 
NULL);
        if (dbase != INVALID_HANDLE_VALUE)
                return;
 #else
-       dbase = open(dbname.c_str(), O_RDWR | O_LARGEFILE);
+       const int flags = exclusive ? O_EXCL | O_RDWR | O_LARGEFILE :
+               O_RDWR | O_LARGEFILE;
+       dbase = open(dbname.c_str(), flags);
        if (dbase >= 0)
                return;
 #endif
@@ -570,7 +573,7 @@
 #endif
 }
 
-void NBackup::fixup_database()
+void NBackup::fixup_database(bool set_readonly)
 {
        open_database_write();
        Ods::header_page header;
@@ -584,6 +587,8 @@
                        Arg::Num(Jrd::nbak_state_stalled));
        }
        header.hdr_flags = (header.hdr_flags & ~Ods::hdr_backup_mask) | 
Jrd::nbak_state_normal;
+       if (set_readonly)
+               header.hdr_flags |= Ods::hdr_read_only;
        seek_file(dbase, 0);
        write_file(dbase, &header, sizeof(header));
        close_database();
@@ -771,13 +776,14 @@
        detach_database();
 }
 
-void NBackup::backup_database(int level, const PathName& fname)
+void NBackup::backup_database(int level, Guid& guid, const PathName& fname)
 {
        bool database_locked = false;
        // We set this flag when backup file is in inconsistent state
        bool delete_backup = false;
        ULONG prev_scn = 0;
        char prev_guid[GUID_BUFF_SIZE] = "";
+       char str_guid[GUID_BUFF_SIZE] = "";
        Ods::pag* page_buff = NULL;
        attach_database();
        ULONG page_writes = 0, page_reads = 0;
@@ -804,6 +810,9 @@
                // Look for SCN and GUID of previous-level backup in history 
table
                if (level)
                {
+                       if (level < 0)
+                               GuidToString(str_guid, &guid);
+
                        if (isc_start_transaction(status, &trans, 1, &newdb, 0, 
NULL))
                                pr_error(status, "start transaction");
                        char out_sqlda_data[XSQLDA_LENGTH(2)];
@@ -815,10 +824,18 @@
                        if (isc_dsql_allocate_statement(status, &newdb, &stmt))
                                pr_error(status, "allocate statement");
                        char str[200];
-                       sprintf(str, "select rdb$guid, rdb$scn from 
rdb$backup_history "
-                               "where rdb$backup_id = "
-                                 "(select max(rdb$backup_id) from 
rdb$backup_history "
-                                  "where rdb$backup_level = %d)", level - 1);
+                       if (level > 0)
+                       {
+                               sprintf(str, "select rdb$guid, rdb$scn from 
rdb$backup_history "
+                                       "where rdb$backup_id = "
+                                         "(select max(rdb$backup_id) from 
rdb$backup_history "
+                                          "where rdb$backup_level = %d)", 
level - 1);
+                       }
+                       else
+                       {
+                               sprintf(str, "select first 1 rdb$guid, rdb$scn 
from rdb$backup_history "
+                                       "where rdb$guid = '%s'", str_guid);
+                       }
                        if (isc_dsql_prepare(status, &trans, &stmt, 0, str, 1, 
NULL))
                                pr_error(status, "prepare history query");
                        if (isc_dsql_describe(status, &stmt, 1, out_sqlda))
@@ -834,8 +851,12 @@
                        switch (isc_dsql_fetch(status, &stmt, 1, out_sqlda))
                        {
                        case 100: // No more records available
-                               
status_exception::raise(Arg::Gds(isc_nbackup_lostrec_db) << database.c_str() <<
-                                                                               
Arg::Num(level - 1));
+                               if (level > 0)
+                                       
status_exception::raise(Arg::Gds(isc_nbackup_lostrec_db) << database.c_str() <<
+                                                                               
        Arg::Num(level - 1));
+                               else
+                                       
status_exception::raise(Arg::Gds(isc_nbackup_lostrec_guid_db) << 
database.c_str() <<
+                                                                               
        Arg::Str(str_guid));
                        case 0:
                                if (guid_null || scn_null)
                                        
status_exception::raise(Arg::Gds(isc_nbackup_lostguid_db));
@@ -862,9 +883,18 @@
                        // Let's generate nice new filename
                        PathName begin, fil;
                        PathUtils::splitLastComponent(begin, fil, database);
-                       bakname.printf("%s-%d-%04d%02d%02d-%02d%02d.nbk", 
fil.c_str(), level,
-                               today.tm_year + 1900, today.tm_mon + 1, 
today.tm_mday,
-                               today.tm_hour, today.tm_min);
+                       if (level >= 0)
+                       {
+                               
bakname.printf("%s-%d-%04d%02d%02d-%02d%02d.nbk", fil.c_str(), level,
+                                       today.tm_year + 1900, today.tm_mon + 1, 
today.tm_mday,
+                                       today.tm_hour, today.tm_min);
+                       }
+                       else
+                       {
+                               
bakname.printf("%s-%s-%04d%02d%02d-%02d%02d.nbk", fil.c_str(), str_guid,
+                                       today.tm_year + 1900, today.tm_mon + 1, 
today.tm_mday,
+                                       today.tm_hour, today.tm_min);
+                       }
                        if (!uSvc->isService())
                                printf("%s", bakname.c_str()); // Print out 
generated filename for script processing
                }
@@ -953,7 +983,7 @@
                        inc_header bh;
                        memcpy(bh.signature, backup_signature, 
sizeof(backup_signature));
                        bh.version = 1;
-                       bh.level = level;
+                       bh.level = level > 0 ? level : 0;
                        bh.backup_guid = backup_guid;
                        StringToGuid(&bh.prev_guid, prev_guid);
                        bh.page_size = header->hdr_page_size;
@@ -1110,8 +1140,17 @@
                if (isc_dsql_describe_bind(status, &stmt, 1, in_sqlda))
                        pr_error(status, "bind history insert");
                short null_flag = 0;
-               in_sqlda->sqlvar[0].sqldata = (char*) &level;
-               in_sqlda->sqlvar[0].sqlind = &null_flag;
+               if (level >= 0)
+               {
+                       in_sqlda->sqlvar[0].sqldata = (char*) &level;
+                       in_sqlda->sqlvar[0].sqlind = &null_flag;
+               }
+               else
+               {
+                       short null_ind = -1;
+                       in_sqlda->sqlvar[0].sqldata = NULL;
+                       in_sqlda->sqlvar[0].sqlind = &null_ind;
+               }
                char temp[GUID_BUFF_SIZE];
                GuidToString(temp, &backup_guid);
                in_sqlda->sqlvar[1].sqldata = temp;
@@ -1170,14 +1209,17 @@
                elapsed, page_reads, page_writes);
 }
 
-void NBackup::restore_database(const BackupFiles& files)
+void NBackup::restore_database(const BackupFiles& files, bool inc_rest)
 {
        // We set this flag when database file is in inconsistent state
        bool delete_database = false;
        const int filecount = files.getCount();
 #ifndef WIN_NT
-       create_database();
-       delete_database = true;
+       if (!inc_rest)
+       {
+               create_database();
+               delete_database = true;
+       }
 #endif
        UCHAR *page_buffer = NULL;
        try {
@@ -1232,16 +1274,19 @@
                        }
                        else
                        {
-                               if (curLevel >= filecount)
+                               if (curLevel >= filecount + (inc_rest ? 1 : 0))
                                {
                                        close_database();
-                                       fixup_database();
+                                       fixup_database(inc_rest);
                                        delete[] page_buffer;
                                        return;
                                }
-                               bakname = files[curLevel];
+                               if (!inc_rest || curLevel)
+                                       bakname = files[curLevel - (inc_rest ? 
1 : 0)];
 #ifdef WIN_NT
                                if (curLevel)
+#else
+                               if (!inc_rest || curLevel)
 #endif
                                        open_backup_scan();
                        }
@@ -1258,7 +1303,7 @@
                                        
status_exception::raise(Arg::Gds(isc_nbackup_unsupvers_incbk) <<
                                                                                
Arg::Num(bakheader.version) << bakname.c_str());
                                }
-                               if (bakheader.level != curLevel)
+                               if (bakheader.level && bakheader.level != 
curLevel)
                                {
                                        
status_exception::raise(Arg::Gds(isc_nbackup_invlevel_incbk) <<
                                                Arg::Num(bakheader.level) << 
bakname.c_str() << Arg::Num(curLevel));
@@ -1267,7 +1312,8 @@
                                if (memcmp(&bakheader.prev_guid, &prev_guid, 
sizeof(Guid)) != 0)
                                        
status_exception::raise(Arg::Gds(isc_nbackup_wrong_orderbk) << bakname.c_str());
 
-                               delete_database = true;
+                               if (!inc_rest)
+                                       delete_database = true;
                                prev_guid = bakheader.backup_guid;
                                while (true)
                                {
@@ -1288,28 +1334,34 @@
                        }
                        else
                        {
+                               if (!inc_rest)
+                               {
 #ifdef WIN_NT
-                               if (!CopyFile(bakname.c_str(), dbname.c_str(), 
TRUE))
-                               {
-                                       
status_exception::raise(Arg::Gds(isc_nbackup_err_copy) <<
-                                               dbname.c_str() << 
bakname.c_str() << Arg::OsError());
-                               }
-                               checkCtrlC(uSvc);
-                               delete_database = true; // database is possibly 
broken
-                               open_database_write();
+                                       if (!CopyFile(bakname.c_str(), 
dbname.c_str(), TRUE))
+                                       {
+                                               
status_exception::raise(Arg::Gds(isc_nbackup_err_copy) <<
+                                                       dbname.c_str() << 
bakname.c_str() << Arg::OsError());
+                                       }
+                                       checkCtrlC(uSvc);
+                                       delete_database = true; // database is 
possibly broken
+                                       open_database_write();
 #else
-                               // Use relatively small buffer to make use of 
prefetch and lazy flush
-                               char buffer[65536];
-                               while (true)
-                               {
-                                       const size_t bytesRead = 
read_file(backup, buffer, sizeof(buffer));
-                                       if (bytesRead == 0)
-                                               break;
-                                       write_file(dbase, buffer, bytesRead);
-                                       checkCtrlC(uSvc);
+                                       // Use relatively small buffer to make 
use of prefetch and lazy flush
+                                       char buffer[65536];
+                                       while (true)
+                                       {
+                                               const size_t bytesRead = 
read_file(backup, buffer, sizeof(buffer));
+                                               if (bytesRead == 0)
+                                                       break;
+                                               write_file(dbase, buffer, 
bytesRead);
+                                               checkCtrlC(uSvc);
+                                       }
+                                       seek_file(dbase, 0);
+#endif
                                }
-                               seek_file(dbase, 0);
-#endif
+                               else
+                                       open_database_write(true);
+
                                // Read database header
                                Ods::header_page header;
                                if (read_file(dbase, &header, sizeof(header)) 
!= sizeof(header))
@@ -1417,8 +1469,9 @@
                false;
 #endif
        NBackup::BackupFiles backup_files;
-       int level;
-       bool print_size = false, version = false;
+       int level = -1;
+       Guid guid;
+       bool print_size = false, version = false, inc_rest = false;
        string trustedUser;
        bool trustedRole = false;
        string onOff;
@@ -1548,7 +1601,10 @@
                        if (++itr >= argc)
                                missingParameterForSwitch(uSvc, argv[itr - 1]);
 
-                       level = atoi(argv[itr]);
+                       if (argv[itr][0] == '{')
+                               StringToGuid(&guid, argv[itr]);
+                       else
+                               level = atoi(argv[itr]);
 
                        if (++itr >= argc)
                                missingParameterForSwitch(uSvc, argv[itr - 2]);
@@ -1593,6 +1649,10 @@
                                version = true;
                        break;
 
+               case IN_SW_NBK_INPLACE:
+                       inc_rest = true;
+                       break;
+
                default:
                        usage(uSvc, isc_nbackup_unknown_switch, argv[itr]);
                        break;
@@ -1636,11 +1696,11 @@
                                break;
 
                        case nbBackup:
-                               nbk.backup_database(level, filename);
+                               nbk.backup_database(level, guid, filename);
                                break;
 
                        case nbRestore:
-                               nbk.restore_database(backup_files);
+                               nbk.restore_database(backup_files, inc_rest);
                                break;
                }
        }
Index: src/utilities/nbackup/nbkswi.h
===================================================================
--- src/utilities/nbackup/nbkswi.h      (revision 58043)
+++ src/utilities/nbackup/nbkswi.h      (working copy)
@@ -48,12 +48,14 @@
 const int IN_SW_NBK_TRUSTED_ROLE       = 13;
 const int IN_SW_NBK_HELP                       = 14;
 const int IN_SW_NBK_DIRECT                     = 15;
+const int IN_SW_NBK_INPLACE                    = 16;
 
 
 static const struct Switches::in_sw_tab_t nbackup_in_sw_table [] =
 {
        {IN_SW_NBK_NODBTRIG,    isc_spb_nbk_no_triggers,        "T",            
0, 0, 0, false, 0,      1, NULL},
        {IN_SW_NBK_DIRECT,              isc_spb_nbk_direct,                     
"DIRECT",       0, 0, 0, false, 0,  1, NULL},
+       {IN_SW_NBK_INPLACE,             isc_spb_nbk_inplace,            "I",    
        0, 0, 0, false, 0,  1, NULL},
        {IN_SW_NBK_0,                   0,                                      
                NULL,           0, 0, 0, false, 0,      0, NULL}        // End 
of List
 };
 
@@ -68,6 +70,7 @@
        {IN_SW_NBK_BACKUP,              isc_action_svc_nbak,    "BACKUP",       
                0, 0, 0, false, 11,     1,      NULL, nboExclusive},
        {IN_SW_NBK_RESTORE,             isc_action_svc_nrest,   "RESTORE",      
                0, 0, 0, false, 12,     1,      NULL, nboExclusive},
        {IN_SW_NBK_DIRECT,              0,                                      
        "DIRECT",                       0, 0, 0, false, 70,     1,      NULL, 
nboSpecial},
+       {IN_SW_NBK_INPLACE,             0,                                      
        "I",                            0, 0, 0, false, 75,     1,      NULL, 
nboSpecial},
        {IN_SW_NBK_SIZE,                0,                                      
        "SIZE",                         0, 0, 0, false, 17,     1,      NULL, 
nboSpecial},
        {IN_SW_NBK_NODBTRIG,    0,                                              
"T",                            0, 0, 0, false, 0,      1,      NULL, 
nboGeneral},
        {IN_SW_NBK_NODBTRIG,    0,                                              
"NODBTRIGGERS",         0, 0, 0, false, 16,     3,      NULL, nboGeneral},
------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and 
their applications. This 200-page book is written by three acclaimed 
leaders in the field. The early access version is available now. 
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel

Reply via email to