Drizzled Public API Documentation

systab_backup_ms.cc

00001 /* Copyright (C) 2009 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Barry Leslie
00020  *
00021  * 2009-10-27
00022  *
00023  * System backup info table for repository backups.
00024  */
00025 #ifdef DRIZZLED
00026 #include <config.h>
00027 #include <drizzled/common.h>
00028 #include <drizzled/session.h>
00029 #endif
00030 
00031 #include "cslib/CSConfig.h"
00032 #include <inttypes.h>
00033 
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <stdlib.h>
00037 #include <time.h>
00038 
00039 //#include "mysql_priv.h"
00040 #include "cslib/CSGlobal.h"
00041 #include "cslib/CSStrUtil.h"
00042 #include "cslib/CSLog.h"
00043 #include "cslib/CSPath.h"
00044 #include "cslib/CSDirectory.h"
00045 
00046 #include "ha_pbms.h"
00047 //#include <plugin.h>
00048 
00049 #include "mysql_ms.h"
00050 #include "database_ms.h"
00051 #include "open_table_ms.h"
00052 #include "discover_ms.h"
00053 #include "systab_util_ms.h"
00054 #include "backup_ms.h"
00055 
00056 #include "systab_backup_ms.h"
00057 
00058 
00059 DT_FIELD_INFO pbms_backup_info[]=
00060 {
00061   {"Id",        NOVAL,  NULL, MYSQL_TYPE_LONG,    NULL,     NOT_NULL_FLAG,  "The backup reference ID"},
00062   {"Database_Name", 64,   NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET,  NOT_NULL_FLAG,  "The database name"},
00063   {"Database_Id",   NOVAL,  NULL, MYSQL_TYPE_LONG,    NULL,     0,  "The database ID"},
00064   {"Started",     32,   NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET,  0,  "The start time"},
00065   {"Completed",   32,   NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET,  0,  "The completion time"},
00066   {"IsRunning",   3,    NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET,  0,  "Is the backup still running"},
00067   {"IsDump",      3,    NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET,  0,  "Is the backup the result of a dump"},
00068   {"Location",    1024, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET,  0,  "The backup location"},
00069   {"Cloud_Ref",   NOVAL,  NULL, MYSQL_TYPE_LONG,    NULL,     0,  "The S3 cloud reference number refering to the pbms.pbms_cloud table."},
00070   {"Cloud_Backup_No", NOVAL,  NULL, MYSQL_TYPE_LONG,    NULL,     0,  "The cloud backup number"},
00071   {NULL,NOVAL, NULL, MYSQL_TYPE_STRING,NULL, 0, NULL}
00072 };
00073 
00074 DT_KEY_INFO pbms_backup_keys[]=
00075 {
00076   {"pbms_backup_pk", PRI_KEY_FLAG, {"Id", NULL}},
00077   {NULL, 0, {NULL}}
00078 };
00079 
00080 #define MIN_BACKUP_TABLE_FILE_SIZE 4
00081 
00082 
00083 //----------------------------
00084 void MSBackupTable::startUp()
00085 {
00086   MSBackupInfo::startUp();
00087 }
00088 
00089 //----------------------------
00090 void MSBackupTable::shutDown()
00091 {
00092   MSBackupInfo::shutDown();
00093 }
00094 
00095 //----------------------------
00096 void MSBackupTable::loadTable(MSDatabase *db)
00097 {
00098 
00099   enter_();
00100   
00101   push_(db);
00102   lock_(MSBackupInfo::gBackupInfo);
00103   
00104   if (MSBackupInfo::gMaxInfoRef == 0) {
00105     CSPath  *path;
00106     path = getSysFile(getPBMSPath(RETAIN(db->myDatabasePath)), BACKUP_TABLE_NAME, MIN_BACKUP_TABLE_FILE_SIZE);
00107     push_(path);
00108 
00109     if (path->exists()) {
00110       CSFile    *file;
00111       SysTabRec *backupData;
00112       const char  *name, *location;
00113       uint32_t    info_id, db_id, start, end, cloud_ref, cloud_backup_no;
00114       bool    isDump;
00115       MSBackupInfo  *info;
00116       size_t    size;
00117       
00118       new_(backupData, SysTabRec("pbms", BACKUP_TABLE_NAME".dat", BACKUP_TABLE_NAME));
00119       push_(backupData);
00120 
00121       file = path->openFile(CSFile::READONLY);
00122       push_(file);
00123       size = file->getEOF();
00124       backupData->setLength(size);
00125       file->read(backupData->getBuffer(0), 0, size, size);
00126       release_(file);
00127       
00128       backupData->firstRecord();
00129       MSBackupInfo::gMaxInfoRef = backupData->getInt4Field();
00130       
00131       if (! backupData->isValidRecord()) 
00132         MSBackupInfo::gMaxInfoRef = 1;
00133       
00134       while (backupData->nextRecord()) {
00135         info_id = backupData->getInt4Field();
00136         name = backupData->getStringField();
00137         db_id = backupData->getInt4Field();
00138         start = backupData->getInt4Field();
00139         end = backupData->getInt4Field();
00140         isDump = backupData->getInt1Field();
00141         location = backupData->getStringField();
00142         cloud_ref = backupData->getInt4Field();
00143         cloud_backup_no = backupData->getInt4Field();
00144         
00145         if (backupData->isValidRecord()) {
00146           if (info_id > MSBackupInfo::gMaxInfoRef) {
00147             char msg[80];
00148             snprintf(msg, 80, "backup info id (%"PRIu32") larger than expected (%"PRIu32")\n", info_id, MSBackupInfo::gMaxInfoRef);
00149             CSL.log(self, CSLog::Warning, "pbms "BACKUP_TABLE_NAME".dat :possible damaged file or record. ");
00150             CSL.log(self, CSLog::Warning, msg);
00151             MSBackupInfo::gMaxInfoRef = info_id +1;
00152           }
00153           if ( MSBackupInfo::gBackupInfo->get(info_id)) {
00154             char msg[80];
00155             snprintf(msg, 80, "Duplicate Backup info id (%"PRIu32") being ignored\n", info_id);
00156             CSL.log(self, CSLog::Warning, "pbms "BACKUP_TABLE_NAME".dat :possible damaged file or record. ");
00157             CSL.log(self, CSLog::Warning, msg);
00158           } else {
00159             new_(info, MSBackupInfo(info_id, name, db_id, start, end, isDump, location, cloud_ref, cloud_backup_no));
00160             MSBackupInfo::gBackupInfo->set(info_id, info);
00161           }
00162         }
00163       }
00164       release_(backupData); backupData = NULL;
00165       
00166     } else
00167       MSBackupInfo::gMaxInfoRef = 1;
00168     
00169     release_(path);
00170     
00171   }
00172   unlock_(MSBackupInfo::gBackupInfo);
00173 
00174   release_(db);
00175 
00176   exit_();
00177 }
00178 
00179 void MSBackupTable::saveTable(MSDatabase *db)
00180 {
00181   SysTabRec   *backupData;
00182   MSBackupInfo    *info;
00183   enter_();
00184   
00185   push_(db);
00186   
00187   new_(backupData, SysTabRec("pbms", BACKUP_TABLE_NAME".dat", BACKUP_TABLE_NAME));
00188   push_(backupData);
00189   
00190   // Build the table records
00191   backupData->clear();
00192   lock_(MSBackupInfo::gBackupInfo);
00193   
00194   backupData->beginRecord();  
00195   backupData->setInt4Field(MSBackupInfo::gMaxInfoRef);
00196   backupData->endRecord();  
00197   for  (int i = 0;(info = (MSBackupInfo*) MSBackupInfo::gBackupInfo->itemAt(i)); i++) { // info is not referenced.
00198     
00199     backupData->beginRecord();  
00200     backupData->setInt4Field(info->getBackupRefId());
00201     
00202     backupData->setStringField(info->getName());
00203     backupData->setInt4Field(info->getDatabaseId());
00204     backupData->setInt4Field(info->getStart());
00205     backupData->setInt4Field(info->getEnd());
00206     backupData->setInt1Field(info->isDump());
00207     backupData->setStringField(info->getLocation());
00208     backupData->setInt4Field(info->getcloudRef());
00209     backupData->setInt4Field(info->getcloudBackupNo());
00210     backupData->endRecord();      
00211   }
00212   unlock_(MSBackupInfo::gBackupInfo);
00213 
00214   restoreTable(RETAIN(db), backupData->getBuffer(0), backupData->length(), false);
00215   
00216   release_(backupData);
00217   release_(db);
00218   exit_();
00219 }
00220 
00221 
00222 MSBackupTable::MSBackupTable(MSSystemTableShare *share, TABLE *table):
00223 MSOpenSystemTable(share, table),
00224 iBackupIndex(0)
00225 {
00226 }
00227 
00228 MSBackupTable::~MSBackupTable()
00229 {
00230   //unuse();
00231 }
00232 
00233 void MSBackupTable::use()
00234 {
00235   MSBackupInfo::gBackupInfo->lock();
00236 }
00237 
00238 void MSBackupTable::unuse()
00239 {
00240   MSBackupInfo::gBackupInfo->unlock();
00241   
00242 }
00243 
00244 
00245 void MSBackupTable::seqScanInit()
00246 {
00247   iBackupIndex = 0;
00248 }
00249 
00250 bool MSBackupTable::seqScanNext(char *buf)
00251 {
00252   TABLE   *table = mySQLTable;
00253   Field   *curr_field;
00254   byte    *save;
00255   MY_BITMAP *save_write_set;
00256   MSBackupInfo  *info;
00257   CSTime    *timeVal;
00258   const char  *val;
00259   
00260   enter_();
00261   
00262   info = (MSBackupInfo  *) MSBackupInfo::gBackupInfo->itemAt(iBackupIndex++); // Object is not referenced.
00263   if (!info)
00264     return_(false);
00265   
00266   save_write_set = table->write_set;
00267   table->write_set = NULL;
00268 
00269   new_(timeVal, CSTime());
00270   push_(timeVal);
00271 #ifdef DRIZZLED
00272   memset(buf, 0xFF, table->getNullBytes());
00273 #else
00274   memset(buf, 0xFF, table->s->null_bytes);
00275 #endif
00276   for (Field **field=GET_TABLE_FIELDS(table) ; *field ; field++) {
00277     curr_field = *field;
00278     save = curr_field->ptr;
00279 #if MYSQL_VERSION_ID < 50114
00280     curr_field->ptr = (byte *) buf + curr_field->offset();
00281 #else
00282 #ifdef DRIZZLED
00283     curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->getTable()->getInsertRecord());
00284 #else
00285     curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
00286 #endif
00287 #endif
00288     switch (curr_field->field_name[0]) {
00289       case 'I':
00290         if (curr_field->field_name[1] == 'd') {
00291           ASSERT(strcmp(curr_field->field_name, "Id") == 0);
00292           curr_field->store(info->getBackupRefId(), true);
00293           setNotNullInRecord(curr_field, buf);
00294         } else if (curr_field->field_name[2] == 'D') {
00295           ASSERT(strcmp(curr_field->field_name, "IsDump") == 0);
00296           val = (info->isDump())? "Yes": "No";
00297           curr_field->store(val, strlen(val), &UTF8_CHARSET);
00298           setNotNullInRecord(curr_field, buf);
00299         } else {
00300           ASSERT(strcmp(curr_field->field_name, "IsRunning") == 0);
00301           val = (info->isBackupRunning())? "Yes": "No";
00302           curr_field->store(val, strlen(val), &UTF8_CHARSET);
00303           setNotNullInRecord(curr_field, buf);
00304         } 
00305         break;
00306 
00307       case 'D':
00308         if (curr_field->field_name[9] == 'I') {
00309           ASSERT(strcmp(curr_field->field_name, "Database_Id") == 0);
00310           curr_field->store(info->getDatabaseId(), true);
00311           setNotNullInRecord(curr_field, buf);
00312         } else {
00313           ASSERT(strcmp(curr_field->field_name, "Database_Name") == 0);
00314           val = info->getName();
00315           curr_field->store(val, strlen(val), &UTF8_CHARSET);
00316           setNotNullInRecord(curr_field, buf);
00317         }
00318         
00319         break;
00320 
00321       case 'S': 
00322         ASSERT(strcmp(curr_field->field_name, "Started") == 0);
00323         if (info->getStart()) {
00324           timeVal->setUTC1970(info->getStart(), 0);
00325           val = timeVal->getCString();
00326           curr_field->store(val, strlen(val), &UTF8_CHARSET);
00327           setNotNullInRecord(curr_field, buf);
00328         }
00329         break;
00330 
00331       case 'L':
00332         ASSERT(strcmp(curr_field->field_name, "Location") == 0);
00333         val = info->getLocation();
00334         if (val) {
00335           curr_field->store(val, strlen(val), &UTF8_CHARSET);
00336           setNotNullInRecord(curr_field, buf);
00337         }
00338         break;
00339 
00340       case 'C': 
00341         if (curr_field->field_name[1] == 'o') {
00342           ASSERT(strcmp(curr_field->field_name, "Completed") == 0);
00343           if (info->getEnd()) {
00344             timeVal->setUTC1970(info->getEnd(), 0);
00345             val = timeVal->getCString();
00346             curr_field->store(val, strlen(val), &UTF8_CHARSET);
00347             setNotNullInRecord(curr_field, buf);
00348           }
00349         } else if (curr_field->field_name[6] == 'R') {
00350           ASSERT(strcmp(curr_field->field_name, "Cloud_Ref") == 0);
00351           curr_field->store(info->getcloudRef(), true);
00352           setNotNullInRecord(curr_field, buf);
00353         } else if (curr_field->field_name[6] == 'B') {
00354           ASSERT(strcmp(curr_field->field_name, "Cloud_Backup_No") == 0);
00355           curr_field->store(info->getcloudBackupNo(), true);
00356           setNotNullInRecord(curr_field, buf);
00357         } else {
00358           ASSERT(false);
00359           break;
00360         }
00361         break;
00362         
00363       default:
00364         ASSERT(false);
00365     }
00366     curr_field->ptr = save;
00367   }
00368 
00369   release_(timeVal);
00370   table->write_set = save_write_set;
00371   
00372   return_(true);
00373 }
00374 
00375 void MSBackupTable::seqScanPos(unsigned char *pos)
00376 {
00377   int32_t index = iBackupIndex -1;
00378   if (index < 0)
00379     index = 0; // This is probably an error condition.
00380     
00381   mi_int4store(pos, index);
00382 }
00383 
00384 void MSBackupTable::seqScanRead(unsigned char *pos, char *buf)
00385 {
00386   iBackupIndex = mi_uint4korr(pos);
00387   seqScanNext(buf);
00388 }
00389 
00390 void MSBackupTable::updateRow(char *old_data, char *new_data) 
00391 {
00392   uint32_t n_id, db_id, cloud_ref, cloud_backup_no, n_indx;
00393   uint32_t o_id, o_db_id, o_cloud_ref, o_cloud_backup_no, o_indx;
00394   String name, start, end, isRunning, isDump, location;
00395   String o_name, o_start, o_end, o_isRunning, o_isDump, o_location;
00396   MSBackupInfo *info, *old_info;
00397 
00398   enter_();
00399   
00400   getFieldValue(new_data, 0, &n_id);
00401   getFieldValue(new_data, 1, &name);
00402   getFieldValue(new_data, 2, &db_id);
00403   getFieldValue(new_data, 3, &start);
00404   getFieldValue(new_data, 4, &end);
00405   getFieldValue(new_data, 5, &isRunning);
00406   getFieldValue(new_data, 6, &isDump);
00407   getFieldValue(new_data, 7, &location);
00408   getFieldValue(new_data, 8, &cloud_ref);
00409   getFieldValue(new_data, 9, &cloud_backup_no);
00410 
00411   getFieldValue(old_data, 0, &o_id);
00412   getFieldValue(old_data, 1, &o_name);
00413   getFieldValue(old_data, 2, &o_db_id);
00414   getFieldValue(old_data, 3, &o_start);
00415   getFieldValue(old_data, 4, &o_end);
00416   getFieldValue(old_data, 5, &o_isRunning);
00417   getFieldValue(old_data, 6, &o_isDump);
00418   getFieldValue(old_data, 7, &o_location);
00419   getFieldValue(old_data, 8, &o_cloud_ref);
00420   getFieldValue(old_data, 9, &o_cloud_backup_no);
00421 
00422   // The only fields that are allowed to be updated are 'Location' and 'Cloud_Ref'.
00423   // It makes no scence to update any of the other fields.
00424   if (n_id != o_id )
00425     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (Id) in the "BACKUP_TABLE_NAME" table.");
00426   
00427   if (strcmp(name.c_ptr(), o_name.c_ptr()) == 0 )
00428     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (Database_Name) in the "BACKUP_TABLE_NAME" table.");
00429   
00430   if (db_id != o_db_id )
00431     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (Database_Id) in the "BACKUP_TABLE_NAME" table.");
00432   
00433   if (strcmp(start.c_ptr(), o_start.c_ptr()) == 0 )
00434     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (Started) in the "BACKUP_TABLE_NAME" table.");
00435   
00436   if (strcmp(end.c_ptr(), o_end.c_ptr()) == 0 )
00437     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (Completed) in the "BACKUP_TABLE_NAME" table.");
00438   
00439   if (strcmp(isRunning.c_ptr(), o_isRunning.c_ptr()) == 0 )
00440     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (isRunning) in the "BACKUP_TABLE_NAME" table.");
00441   
00442   if (strcmp(isDump.c_ptr(), o_isDump.c_ptr()) == 0 )
00443     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (IsDump) in the "BACKUP_TABLE_NAME" table.");
00444   
00445   if (cloud_backup_no != o_cloud_backup_no )
00446     CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only field (Cloud_Backup_No) in the "BACKUP_TABLE_NAME" table.");
00447 
00448   old_info = (MSBackupInfo*)  MSBackupInfo::gBackupInfo->get(o_id); // A non referenced object.
00449   
00450   new_(info, MSBackupInfo(n_id, old_info->getName(), db_id, old_info->getStart(), old_info->getEnd(), old_info->isDump(), location.c_ptr(), cloud_ref, cloud_backup_no));
00451   push_(info);
00452   
00453   o_indx = MSBackupInfo::gBackupInfo->getIndex(o_id);
00454 
00455   MSBackupInfo::gBackupInfo->remove(o_id);
00456   pop_(info);
00457   MSBackupInfo::gBackupInfo->set(n_id, info);
00458   
00459   // Adjust the current position in the array if required.
00460   n_indx = MSBackupInfo::gBackupInfo->getIndex(n_id);
00461   if (o_indx < n_indx )
00462     iBackupIndex--;
00463 
00464   saveTable(RETAIN(myShare->mySysDatabase));
00465 
00466   exit_();
00467 }
00468 
00469 class InsertRowCleanUp : public CSRefObject {
00470   bool do_cleanup;
00471   CSThread *myself;
00472   
00473   uint32_t ref_id;
00474 
00475   public:
00476   
00477   InsertRowCleanUp(CSThread *self): CSRefObject(),
00478     do_cleanup(true), myself(self){}
00479     
00480   ~InsertRowCleanUp() 
00481   {
00482     if (do_cleanup) {
00483       myself->logException();
00484       if (ref_id)
00485         MSBackupInfo::gBackupInfo->remove(ref_id);
00486 
00487     }
00488   }
00489   
00490   void setCleanUp(uint32_t id)
00491   {
00492     ref_id = id;
00493   }
00494   
00495   void cancelCleanUp()
00496   {
00497     do_cleanup = false;
00498   }
00499   
00500 };
00501 
00502 void MSBackupTable::insertRow(char *data) 
00503 {
00504   uint32_t ref_id = 0, db_id, cloud_ref, cloud_backup_no;
00505   String name, start, end, isRunning, isDump, location;
00506   MSBackupInfo *info = NULL;
00507   const char *db_name;
00508   InsertRowCleanUp *cleanup;
00509 
00510   enter_();
00511 
00512   new_(cleanup, InsertRowCleanUp(self));
00513   push_(cleanup);
00514   
00515   getFieldValue(data, 0, &ref_id);
00516     
00517   // The id must be unique.
00518   if (ref_id && MSBackupInfo::gBackupInfo->get(ref_id)) {
00519     CSException::throwException(CS_CONTEXT, MS_ERR_DUPLICATE, "Attempt to insert a row with a duplicate key in the "BACKUP_TABLE_NAME" table.");
00520   }
00521   
00522   // The 'Database_Id', 'Start', 'Completion' and "IsDump" fields are ignored.
00523   // I still need to get the fields though to advance the field position pointer.
00524   getFieldValue(data, 1, &name);
00525   getFieldValue(data, 2, &db_id);
00526   getFieldValue(data, 3, &start);
00527   getFieldValue(data, 4, &end);
00528   getFieldValue(data, 5, &isRunning);
00529   getFieldValue(data, 6, &isDump);
00530   getFieldValue(data, 7, &location);
00531   getFieldValue(data, 8, &cloud_ref);
00532   getFieldValue(data, 9, &cloud_backup_no);
00533   
00534   if (ref_id == 0)
00535     ref_id = MSBackupInfo::gMaxInfoRef++;
00536   else if (ref_id >= MSBackupInfo::gMaxInfoRef)
00537     MSBackupInfo::gMaxInfoRef = ref_id +1;
00538   
00539   db_name = name.c_ptr();
00540   db_id = MSDatabase::getDatabaseID(db_name, false);
00541   
00542   cleanup->setCleanUp(ref_id);
00543   new_(info, MSBackupInfo(ref_id, db_name, db_id, 0, 0, false, location.c_ptr(), cloud_ref, cloud_backup_no));
00544   MSBackupInfo::gBackupInfo->set(ref_id, info);
00545   
00546   // There is no need to call this now, startBackup() will call it
00547   // after the backup is started.
00548   // saveTable(RETAIN(myShare->mySysDatabase)); 
00549   info->startBackup(RETAIN(myShare->mySysDatabase));
00550 
00551   cleanup->cancelCleanUp();
00552   release_(cleanup);
00553   
00554   exit_();
00555 }
00556 
00557 void MSBackupTable::deleteRow(char *data) 
00558 {
00559   uint32_t ref_id, indx;
00560 
00561   enter_();
00562   
00563   getFieldValue(data, 0, &ref_id);
00564   
00565   // Adjust the current position in the array if required.
00566   indx = MSBackupInfo::gBackupInfo->getIndex(ref_id);
00567   if (indx <= iBackupIndex)
00568     iBackupIndex--;
00569   
00570   MSBackupInfo::gBackupInfo->remove(ref_id);
00571   saveTable(RETAIN(myShare->mySysDatabase));
00572   exit_();
00573 }
00574 
00575 void MSBackupTable::transferTable(MSDatabase *to_db, MSDatabase *from_db)
00576 {
00577   CSPath  *path;
00578   enter_();
00579   
00580   push_(from_db);
00581   push_(to_db);
00582   
00583   path = CSPath::newPath(getPBMSPath(RETAIN(from_db->myDatabasePath)), BACKUP_TABLE_NAME".dat");
00584   push_(path);
00585   if (path->exists()) {
00586     CSPath  *bu_path;
00587     bu_path = CSPath::newPath(getPBMSPath(RETAIN(to_db->myDatabasePath)), BACKUP_TABLE_NAME".dat");
00588     path->copyTo(bu_path, true);
00589   }
00590   
00591   release_(path);
00592   release_(to_db);
00593   release_(from_db);
00594   
00595   exit_();
00596 }
00597 
00598 CSStringBuffer *MSBackupTable::dumpTable(MSDatabase *db)
00599 {
00600 
00601   CSPath      *path;
00602   CSStringBuffer  *dump;
00603 
00604   enter_();
00605   
00606   push_(db);
00607   path = getSysFile(getPBMSPath(RETAIN(db->myDatabasePath)), BACKUP_TABLE_NAME, MIN_BACKUP_TABLE_FILE_SIZE);
00608   release_(db);
00609   
00610   push_(path);
00611   new_(dump, CSStringBuffer(20));
00612   push_(dump);
00613 
00614   if (path->exists()) {
00615     CSFile  *file;
00616     size_t  size;
00617     
00618     file = path->openFile(CSFile::READONLY);
00619     push_(file);
00620     
00621     size = file->getEOF();
00622     dump->setLength(size);
00623     file->read(dump->getBuffer(0), 0, size, size);
00624     release_(file);
00625   }
00626   
00627   pop_(dump);
00628   release_(path);
00629   return_(dump);
00630 }
00631 
00632 void MSBackupTable::restoreTable(MSDatabase *db, const char *data, size_t size, bool reload)
00633 {
00634   CSPath  *path;
00635   CSFile  *file;
00636 
00637   enter_();
00638   
00639   push_(db);
00640   path = getSysFile(getPBMSPath(RETAIN(db->myDatabasePath)), BACKUP_TABLE_NAME, MIN_BACKUP_TABLE_FILE_SIZE);
00641   push_(path);
00642   
00643   file = path->openFile(CSFile::CREATE | CSFile::TRUNCATE);
00644   push_(file);
00645   
00646   file->write(data, 0, size);
00647   file->close();
00648   release_(file);
00649   
00650   release_(path);
00651   
00652   pop_(db);
00653   if (reload)
00654     loadTable(db);
00655   else
00656     db->release();
00657     
00658   exit_();
00659 }
00660 
00661 // The cloud info table is only removed from the pbms database
00662 // if there are no more databases.
00663 void MSBackupTable::removeTable(CSString *db_path)
00664 {
00665   CSPath  *path;
00666   char pbms_path[PATH_MAX];
00667   
00668   enter_();
00669   
00670   push_(db_path); 
00671   cs_strcpy(PATH_MAX, pbms_path, db_path->getCString());
00672   release_(db_path);
00673   
00674   if (strcmp(cs_last_name_of_path(pbms_path), "pbms")  != 0)
00675     exit_();
00676     
00677   cs_remove_last_name_of_path(pbms_path);
00678 
00679   path = getSysFile(CSString::newString(pbms_path), BACKUP_TABLE_NAME, MIN_BACKUP_TABLE_FILE_SIZE);
00680   push_(path);
00681   
00682   if (path->exists())
00683     path->removeFile();
00684   release_(path);
00685   
00686   exit_();
00687 }
00688