mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
При обработке заголовка файла бекапа, не все данные обрабатывались правильно. Мелкие исправления в dlgTransformText.
943 lines
26 KiB
C++
943 lines
26 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// frmRestore.cpp - Restore database dialogue
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/process.h>
|
|
#include <wx/textbuf.h>
|
|
#include <wx/dir.h>
|
|
#include <wx/file.h>
|
|
#include <wx/filename.h>
|
|
|
|
|
|
// App headers
|
|
#include "frm/frmRestore.h"
|
|
#include "frm/frmMain.h"
|
|
#include "utils/sysLogger.h"
|
|
#include "schema/pgTable.h"
|
|
#include "schema/pgFunction.h"
|
|
#include "schema/pgLanguage.h"
|
|
#include "schema/pgConstraints.h"
|
|
#include "schema/pgForeignKey.h"
|
|
#include "ctl/ctlCheckTreeView.h"
|
|
|
|
// Icons
|
|
#include "images/restore.pngc"
|
|
|
|
|
|
#define nbNotebook CTRL_NOTEBOOK("nbNotebook")
|
|
#define txtFilename CTRL_TEXT("txtFilename")
|
|
#define btnFilename CTRL_BUTTON("btnFilename")
|
|
#define cbFormat CTRL_COMBOBOX("cbFormat")
|
|
#define cbRolename CTRL_COMBOBOX("cbRolename")
|
|
#define chkOnlyData CTRL_CHECKBOX("chkOnlyData")
|
|
#define chkOnlySchema CTRL_CHECKBOX("chkOnlySchema")
|
|
#define chkNoOwner CTRL_CHECKBOX("chkNoOwner")
|
|
#define chkNoPrivileges CTRL_CHECKBOX("chkNoPrivileges")
|
|
#define chkNoTablespaces CTRL_CHECKBOX("chkNoTablespaces")
|
|
#define chkCreateDb CTRL_CHECKBOX("chkCreateDb")
|
|
#define chkClean CTRL_CHECKBOX("chkClean")
|
|
#define chkSingleXact CTRL_CHECKBOX("chkSingleXact")
|
|
#define chkDisableTrigger CTRL_CHECKBOX("chkDisableTrigger")
|
|
#define chkNoDataForFailedTables CTRL_CHECKBOX("chkNoDataForFailedTables")
|
|
#define chkUseSetSession CTRL_CHECKBOX("chkUseSetSession")
|
|
#define chkExitOnError CTRL_CHECKBOX("chkExitOnError")
|
|
#define txtNumberOfJobs CTRL_TEXT("txtNumberOfJobs")
|
|
#define chkVerbose CTRL_CHECKBOX("chkVerbose")
|
|
#define stSingleObject CTRL_STATIC("stSingleObject")
|
|
#define chkSectionPreData CTRL_CHECKBOX("chkSectionPreData")
|
|
#define chkSectionData CTRL_CHECKBOX("chkSectionData")
|
|
#define chkSectionPostData CTRL_CHECKBOX("chkSectionPostData")
|
|
#define ctvObjects CTRL_CHECKTREEVIEW("ctvObjects")
|
|
#define btnView CTRL_BUTTON("btnView")
|
|
|
|
|
|
BEGIN_EVENT_TABLE(frmRestore, ExternProcessDialog)
|
|
EVT_TEXT(XRCID("txtFilename"), frmRestore::OnChangeName)
|
|
EVT_COMBOBOX(XRCID("cbFormat"), frmRestore::OnChangeFormat)
|
|
EVT_CHECKBOX(XRCID("chkOnlyData"), frmRestore::OnChangeData)
|
|
EVT_CHECKBOX(XRCID("chkOnlySchema"), frmRestore::OnChangeSchema)
|
|
EVT_BUTTON(XRCID("btnFilename"), frmRestore::OnSelectFilename)
|
|
EVT_BUTTON(wxID_OK, frmRestore::OnOK)
|
|
EVT_BUTTON(XRCID("btnView"), frmRestore::OnView)
|
|
EVT_END_PROCESS(-1, frmRestore::OnEndProcess)
|
|
EVT_CLOSE( ExternProcessDialog::OnClose)
|
|
EVT_CHECKBOX(XRCID("chkSectionPreData"), frmRestore::OnChangeSection)
|
|
EVT_CHECKBOX(XRCID("chkSectionData"), frmRestore::OnChangeSection)
|
|
EVT_CHECKBOX(XRCID("chkSectionPostData"), frmRestore::OnChangeSection)
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
frmRestore::frmRestore(frmMain *form, pgObject *obj) : ExternProcessDialog(form)
|
|
{
|
|
object = obj;
|
|
|
|
if (object->GetMetaType() == PGM_SERVER)
|
|
server = (pgServer *)object;
|
|
else
|
|
server = object->GetDatabase()->GetServer();
|
|
|
|
SetFont(settings->GetSystemFont());
|
|
LoadResource(form, wxT("frmRestore"));
|
|
RestorePosition();
|
|
|
|
SetTitle(object->GetTranslatedMessage(RESTORETITLE));
|
|
|
|
if (object->GetConnection()->EdbMinimumVersion(8, 0))
|
|
restoreExecutable = edbRestoreExecutable;
|
|
else if (object->GetConnection()->GetIsGreenplum())
|
|
restoreExecutable = gpRestoreExecutable;
|
|
else
|
|
restoreExecutable = pgRestoreExecutable;
|
|
|
|
if (object->GetMetaType() != PGM_DATABASE)
|
|
{
|
|
chkOnlySchema->SetValue(object->GetMetaType() == PGM_FUNCTION
|
|
|| object->GetMetaType() == PGM_INDEX
|
|
|| object->GetMetaType() == PGM_TRIGGER);
|
|
chkOnlyData->SetValue(object->GetMetaType() == PGM_TABLE
|
|
|| object->GetMetaType() == GP_PARTITION);
|
|
if (object->GetMetaType() != PGM_SCHEMA)
|
|
{
|
|
chkOnlyData->Disable();
|
|
chkOnlySchema->Disable();
|
|
}
|
|
if (object->GetMetaType() == PGM_FUNCTION)
|
|
{
|
|
chkClean->SetValue(true);
|
|
chkClean->Disable();
|
|
}
|
|
btnView->Disable();
|
|
}
|
|
|
|
wxString val;
|
|
settings->Read(wxT("frmRestore/LastFile"), &val, wxEmptyString);
|
|
txtFilename->SetValue(val);
|
|
|
|
// Icon
|
|
SetIcon(*restore_png_ico);
|
|
|
|
txtMessages = CTRL_TEXT("txtMessages");
|
|
// Note that under GTK+, SetMaxLength() function may only be used with single line text controls.
|
|
// (see http://docs.wxwidgets.org/2.8/wx_wxtextctrl.html#wxtextctrlsetmaxlength)
|
|
#ifndef __WXGTK__
|
|
txtMessages->SetMaxLength(0L);
|
|
#endif
|
|
btnOK->Disable();
|
|
filenameValid = false;
|
|
|
|
if (!server->GetPasswordIsStored())
|
|
environment.Add(wxT("PGPASSWORD=") + server->GetPassword());
|
|
|
|
// Pass the SSL mode via the environment
|
|
environment.Add(wxT("PGSSLMODE=") + server->GetConnection()->GetSslModeName());
|
|
|
|
if (server->GetSSLRootCert() != wxEmptyString)
|
|
environment.Add(wxT("PGSSLROOTCERT=") + server->GetSSLRootCert());
|
|
|
|
if (server->GetSSLCert() != wxEmptyString)
|
|
environment.Add(wxT("PGSSLCERT=") + server->GetSSLCert());
|
|
|
|
if (server->GetSSLKey() != wxEmptyString)
|
|
environment.Add(wxT("PGSSLKEY=") + server->GetSSLKey());
|
|
|
|
if (server->GetSSLCrl() != wxEmptyString)
|
|
environment.Add(wxT("PGSSLCRL=") + server->GetSSLCrl());
|
|
|
|
if (!pgAppMinimumVersion(restoreExecutable, 8, 4))
|
|
{
|
|
chkNoTablespaces->Disable();
|
|
chkSingleXact->Disable();
|
|
txtNumberOfJobs->Disable();
|
|
cbRolename->Disable();
|
|
}
|
|
else
|
|
{
|
|
// Available rolenames
|
|
if (server->GetConnection()->BackendMinimumVersion(8, 1))
|
|
{
|
|
pgSetIterator set(server->GetConnection(),
|
|
wxT("SELECT DISTINCT rolname\n")
|
|
wxT("FROM pg_roles db\n")
|
|
wxT("ORDER BY rolname"));
|
|
|
|
cbRolename->Append(wxEmptyString);
|
|
|
|
while(set.RowsLeft())
|
|
cbRolename->Append(set.GetVal(wxT("rolname")));
|
|
|
|
cbRolename->SetValue(server->GetRolename());
|
|
cbRolename->Enable(true);
|
|
}
|
|
else
|
|
cbRolename->Disable();
|
|
}
|
|
if (!pgAppMinimumVersion(restoreExecutable, 8, 2))
|
|
{
|
|
chkNoDataForFailedTables->Disable();
|
|
}
|
|
if (!pgAppMinimumVersion(restoreExecutable, 8, 0))
|
|
{
|
|
chkExitOnError->Disable();
|
|
}
|
|
|
|
cbFormat->Append(_("Custom or tar"));
|
|
if (pgAppMinimumVersion(restoreExecutable, 9, 1))
|
|
cbFormat->Append(_("Directory"));
|
|
cbFormat->SetSelection(0);
|
|
|
|
if (!pgAppMinimumVersion(restoreExecutable, 9, 2))
|
|
{
|
|
chkSectionPreData->Disable();
|
|
chkSectionData->Disable();
|
|
chkSectionPostData->Disable();
|
|
}
|
|
|
|
wxCommandEvent ev;
|
|
OnChangeName(ev);
|
|
}
|
|
|
|
|
|
frmRestore::~frmRestore()
|
|
{
|
|
SavePosition();
|
|
}
|
|
|
|
|
|
wxString frmRestore::GetHelpPage() const
|
|
{
|
|
wxString page;
|
|
page = wxT("pg/app-pgrestore");
|
|
return page;
|
|
}
|
|
|
|
|
|
void frmRestore::OnSelectFilename(wxCommandEvent &ev)
|
|
{
|
|
if (cbFormat->GetSelection() == 0) // custom or tar
|
|
{
|
|
wxString FilenameOnly;
|
|
wxFileName::SplitPath(txtFilename->GetValue(), NULL, NULL, &FilenameOnly, NULL);
|
|
|
|
#ifdef __WXMSW__
|
|
wxFileDialog file(this, _("Select backup filename"), ::wxPathOnly(txtFilename->GetValue()), FilenameOnly,
|
|
_("Backup files (*.backup)|*.backup|All files (*.*)|*.*"));
|
|
#else
|
|
wxFileDialog file(this, _("Select backup filename"), ::wxPathOnly(txtFilename->GetValue()), FilenameOnly,
|
|
_("Backup files (*.backup)|*.backup|All files (*)|*"));
|
|
#endif
|
|
|
|
if (file.ShowModal() == wxID_OK)
|
|
{
|
|
txtFilename->SetValue(file.GetPath());
|
|
OnChange(ev);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxDirDialog dir(this, _("Select the backup directory"), txtFilename->GetValue());
|
|
if (dir.ShowModal() == wxID_OK)
|
|
{
|
|
txtFilename->SetValue(dir.GetPath());
|
|
OnChange(ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void frmRestore::OnChangeFormat(wxCommandEvent &ev)
|
|
{
|
|
btnView->Enable(cbFormat->GetSelection() == 0);
|
|
}
|
|
|
|
|
|
void frmRestore::OnChangeData(wxCommandEvent &ev)
|
|
{
|
|
chkOnlySchema->Enable(!chkOnlyData->GetValue());
|
|
chkSectionPreData->Enable(!chkOnlyData->GetValue());
|
|
chkSectionData->Enable(!chkOnlyData->GetValue());
|
|
chkSectionPostData->Enable(!chkOnlyData->GetValue());
|
|
|
|
OnChange(ev);
|
|
}
|
|
|
|
|
|
void frmRestore::OnChangeSchema(wxCommandEvent &ev)
|
|
{
|
|
chkOnlyData->Enable(!chkOnlySchema->GetValue());
|
|
chkSectionPreData->Enable(!chkOnlySchema->GetValue());
|
|
chkSectionData->Enable(!chkOnlySchema->GetValue());
|
|
chkSectionPostData->Enable(!chkOnlySchema->GetValue());
|
|
|
|
OnChange(ev);
|
|
}
|
|
|
|
|
|
void frmRestore::OnChangeSection(wxCommandEvent &ev)
|
|
{
|
|
bool isSection = chkSectionPreData->GetValue() || chkSectionData->GetValue() || chkSectionPostData->GetValue();
|
|
|
|
chkOnlySchema->Enable(!isSection);
|
|
chkOnlyData->Enable(!isSection);
|
|
|
|
OnChange(ev);
|
|
}
|
|
|
|
|
|
void frmRestore::OnChangeName(wxCommandEvent &ev)
|
|
{
|
|
wxString name = txtFilename->GetValue();
|
|
if (cbFormat->GetSelection() == 0)
|
|
{
|
|
if (name.IsEmpty() || !wxFile::Exists(name))
|
|
filenameValid = false;
|
|
else
|
|
{
|
|
wxFile file(name, wxFile::read);
|
|
if (file.IsOpened())
|
|
{
|
|
char buffer[8];
|
|
off_t size = file.Read(buffer, 8);
|
|
if (size == 8)
|
|
{
|
|
if (memcmp(buffer, "PGDMP", 5) && !memcmp(buffer, "toc.dat", 8))
|
|
{
|
|
// tar format?
|
|
file.Seek(512);
|
|
size = file.Read(buffer, 8);
|
|
}
|
|
if (size == 8 && !memcmp(buffer, "PGDMP", 5))
|
|
{
|
|
// check version here?
|
|
filenameValid = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
filenameValid = wxDir::Exists(name);
|
|
}
|
|
OnChange(ev);
|
|
}
|
|
|
|
|
|
void frmRestore::OnChange(wxCommandEvent &ev)
|
|
{
|
|
btnOK->Enable(filenameValid);
|
|
btnView->Enable(filenameValid && object->GetMetaType() == PGM_DATABASE);
|
|
}
|
|
|
|
|
|
wxString frmRestore::GetCmd(int step)
|
|
{
|
|
wxString cmd = getCmdPart1();
|
|
|
|
return cmd + getCmdPart2(step);
|
|
}
|
|
|
|
|
|
wxString frmRestore::GetDisplayCmd(int step)
|
|
{
|
|
wxString cmd = getCmdPart1();
|
|
|
|
return cmd + getCmdPart2(step);
|
|
}
|
|
|
|
|
|
wxString frmRestore::getCmdPart1()
|
|
{
|
|
wxString cmd;
|
|
|
|
cmd = restoreExecutable;
|
|
|
|
if (!server->GetName().IsEmpty())
|
|
cmd += wxT(" --host ") + server->GetName();
|
|
|
|
cmd += wxT(" --port ") + NumToStr((long)server->GetPort())
|
|
+ wxT(" --username ") + commandLineCleanOption(qtIdent(server->GetUsername()))
|
|
+ wxT(" --dbname ") + commandLineCleanOption(object->GetDatabase()->GetQuotedIdentifier());
|
|
|
|
if (!cbRolename->GetValue().IsEmpty())
|
|
cmd += wxT(" --role ") + commandLineCleanOption(qtIdent(cbRolename->GetValue()));
|
|
|
|
if (pgAppMinimumVersion(restoreExecutable, 8, 4))
|
|
cmd += wxT(" --no-password ");
|
|
|
|
return cmd;
|
|
}
|
|
|
|
|
|
wxString frmRestore::getCmdPart2(int step)
|
|
{
|
|
wxString cmd;
|
|
|
|
wxString restoreExecutable;
|
|
if (object->GetConnection()->EdbMinimumVersion(8, 0))
|
|
restoreExecutable = edbBackupExecutable;
|
|
else if (object->GetConnection()->GetIsGreenplum())
|
|
restoreExecutable = gpBackupExecutable;
|
|
else
|
|
restoreExecutable = pgBackupExecutable;
|
|
|
|
if (step)
|
|
{
|
|
cmd.Append(wxT(" --list"));
|
|
}
|
|
else
|
|
{
|
|
if (cbFormat->GetSelection() == 1) // directory
|
|
{
|
|
cmd.Append(wxT(" --format directory"));
|
|
}
|
|
|
|
// Section
|
|
if (pgAppMinimumVersion(restoreExecutable, 9, 2))
|
|
{
|
|
if (chkSectionPreData->GetValue())
|
|
cmd.Append(wxT(" --section pre-data"));
|
|
if (chkSectionData->GetValue())
|
|
cmd.Append(wxT(" --section data"));
|
|
if (chkSectionPostData->GetValue())
|
|
cmd.Append(wxT(" --section post-data"));
|
|
}
|
|
|
|
if (chkOnlyData->GetValue())
|
|
{
|
|
cmd.Append(wxT(" --data-only"));
|
|
}
|
|
else
|
|
{
|
|
if (chkNoOwner->GetValue())
|
|
cmd.Append(wxT(" --no-owner"));
|
|
if (chkNoPrivileges->GetValue())
|
|
cmd.Append(wxT(" --no-privileges"));
|
|
if (chkNoTablespaces->GetValue())
|
|
cmd.Append(wxT(" --no-tablespaces"));
|
|
}
|
|
|
|
if (chkOnlySchema->GetValue())
|
|
{
|
|
cmd.Append(wxT(" --schema-only"));
|
|
}
|
|
else
|
|
{
|
|
if (chkDisableTrigger->GetValue())
|
|
cmd.Append(wxT(" --disable-triggers"));
|
|
}
|
|
if (chkCreateDb->GetValue())
|
|
cmd.Append(wxT(" --create"));
|
|
if (chkClean->GetValue())
|
|
cmd.Append(wxT(" --clean"));
|
|
if (chkSingleXact->GetValue())
|
|
cmd.Append(wxT(" --single-transaction"));
|
|
if (chkNoDataForFailedTables->GetValue())
|
|
cmd.Append(wxT(" --no-data-for-failed-tables"));
|
|
if (chkUseSetSession->GetValue())
|
|
cmd.Append(wxT(" --use-set-session-authorization"));
|
|
if (chkExitOnError->GetValue())
|
|
cmd.Append(wxT(" --exit-on-error"));
|
|
|
|
if (!txtNumberOfJobs->GetValue().IsEmpty())
|
|
cmd.Append(wxT(" --jobs ") + txtNumberOfJobs->GetValue());
|
|
|
|
// Process selected items
|
|
wxTreeItemId root, firstLevelObject, secondLevelObject;
|
|
wxTreeItemIdValue firstLevelObjectData, secondLevelObjectData;
|
|
bool partialDump = false;
|
|
|
|
// Get root object
|
|
root = ctvObjects->GetRootItem();
|
|
|
|
if (root && object->GetMetaType() == PGM_DATABASE)
|
|
{
|
|
// Prepare the array
|
|
wxArrayString restoreStrings;
|
|
restoreStrings.Add(wxEmptyString, numberOfTOCItems);
|
|
restoreTreeItemData *data;
|
|
|
|
// Loop through first level objects
|
|
firstLevelObject = ctvObjects->GetFirstChild(root, firstLevelObjectData);
|
|
while (firstLevelObject.IsOk())
|
|
{
|
|
if (ctvObjects->IsChecked(firstLevelObject))
|
|
{
|
|
// Write the file
|
|
data = (restoreTreeItemData *)ctvObjects->GetItemData(firstLevelObject);
|
|
restoreStrings[data->GetId()] = data->GetDesc();
|
|
|
|
// Loop through second level objects
|
|
secondLevelObject = ctvObjects->GetFirstChild(firstLevelObject, secondLevelObjectData);
|
|
while (secondLevelObject.IsOk())
|
|
{
|
|
if (ctvObjects->IsChecked(secondLevelObject))
|
|
{
|
|
// Write the file
|
|
data = (restoreTreeItemData *)ctvObjects->GetItemData(secondLevelObject);
|
|
restoreStrings[data->GetId()] = data->GetDesc();
|
|
}
|
|
else
|
|
partialDump = true;
|
|
secondLevelObject = ctvObjects->GetNextChild(firstLevelObject, secondLevelObjectData);
|
|
}
|
|
}
|
|
else
|
|
partialDump = true;
|
|
firstLevelObject = ctvObjects->GetNextChild(root, firstLevelObjectData);
|
|
}
|
|
|
|
// Open a temporary file to store the TOC
|
|
restoreTOCFilename = wxFileName::CreateTempFileName(wxT("restore"));
|
|
wxFile tocFile;
|
|
tocFile.Open(restoreTOCFilename.c_str(), wxFile::write);
|
|
|
|
// Write all selected items in it
|
|
for (int i = 0; i < numberOfTOCItems; i++)
|
|
{
|
|
if (restoreStrings[i] != wxEmptyString)
|
|
{
|
|
if (!tocFile.Write(restoreStrings[i] + wxT("\n")))
|
|
{
|
|
wxLogError(_("Error writing to the temporary file ") + restoreTOCFilename);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If some items were not checked and if the file still contains something, we have to use the list
|
|
if (partialDump && tocFile.Length() > 0)
|
|
cmd.Append(wxT(" --use-list \"") + restoreTOCFilename + wxT("\""));
|
|
tocFile.Close();
|
|
}
|
|
else if (object->GetMetaType() != PGM_DATABASE)
|
|
{
|
|
switch (object->GetMetaType())
|
|
{
|
|
case PGM_FUNCTION:
|
|
cmd.Append(wxT(" --function ") + commandLineCleanOption(qtIdent(object->GetFullName()), true));
|
|
break;
|
|
case PGM_INDEX:
|
|
cmd.Append(wxT(" --index ") + commandLineCleanOption(object->GetQuotedIdentifier(), true));
|
|
break;
|
|
case PGM_TABLE:
|
|
cmd.Append(wxT(" --table ") + commandLineCleanOption(object->GetQuotedIdentifier(), true));
|
|
break;
|
|
case PGM_TRIGGER:
|
|
cmd.Append(wxT(" --trigger ") + commandLineCleanOption(object->GetQuotedIdentifier(), true));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (object->GetMetaType() == PGM_SCHEMA)
|
|
cmd.Append(wxT(" --schema ") + commandLineCleanOption(object->GetQuotedIdentifier(), true));
|
|
else if (pgAppMinimumVersion(restoreExecutable, 8, 2))
|
|
cmd.Append(wxT(" --schema ") + commandLineCleanOption(object->GetSchema()->GetQuotedIdentifier(), true));
|
|
}
|
|
|
|
if (settings->GetIgnoreVersion())
|
|
cmd.Append(wxT(" --ignore-version"));
|
|
if (chkVerbose->GetValue())
|
|
cmd.Append(wxT(" --verbose"));
|
|
}
|
|
|
|
|
|
cmd.Append(wxT(" \"") + txtFilename->GetValue() + wxT("\""));
|
|
|
|
return cmd;
|
|
}
|
|
|
|
|
|
void frmRestore::OnView(wxCommandEvent &ev)
|
|
{
|
|
btnView->Disable();
|
|
btnOK->Disable();
|
|
viewRunning = true;
|
|
Execute(1, false);
|
|
btnOK->SetLabel(_("OK"));
|
|
done = 0;
|
|
}
|
|
|
|
|
|
void frmRestore::OnOK(wxCommandEvent &ev)
|
|
{
|
|
if (!done)
|
|
{
|
|
if (processedFile == txtFilename->GetValue())
|
|
{
|
|
if (wxMessageBox(_("Are you sure you wish to run a restore from this file again?"), _("Repeat restore?"), wxICON_QUESTION | wxYES_NO) != wxYES)
|
|
return;
|
|
}
|
|
|
|
processedFile = txtFilename->GetValue();
|
|
}
|
|
|
|
settings->Write(wxT("frmRestore/LastFile"), txtFilename->GetValue());
|
|
viewRunning = false;
|
|
btnView->Disable();
|
|
|
|
ExternProcessDialog::OnOK(ev);
|
|
|
|
}
|
|
|
|
|
|
void frmRestore::OnEndProcess(wxProcessEvent &ev)
|
|
{
|
|
ExternProcessDialog::OnEndProcess(ev);
|
|
|
|
if (done && viewRunning && !ev.GetExitCode())
|
|
{
|
|
done = false;
|
|
|
|
wxString str = wxTextBuffer::Translate(txtMessages->GetValue(), wxTextFileType_Unix);
|
|
|
|
wxStringTokenizer line(str, wxT("\n"));
|
|
line.GetNextToken();
|
|
|
|
wxBeginBusyCursor();
|
|
|
|
wxString i18nbackup = _("Backup");
|
|
wxTreeItemId root = ctvObjects->AddRoot(i18nbackup + wxT(" ") + txtFilename->GetValue());
|
|
wxString currentSchema = wxT("");
|
|
wxTreeItemId currentSchemaNode;
|
|
wxTreeItemId schemaNode, lastItem, extensionNode;
|
|
wxTreeItemIdValue schemaNodeData, extensionNodeData;
|
|
numberOfTOCItems = 0;
|
|
|
|
while (line.HasMoreTokens())
|
|
{
|
|
// Read the next line
|
|
str = line.GetNextToken();
|
|
|
|
// If this is the last line, it contains process information - skip it!
|
|
if (!line.HasMoreTokens())
|
|
continue;
|
|
|
|
// Skip the few lines of comments
|
|
if (str.Left(1) == wxT(";") || str.Left(1) == wxT("P"))
|
|
continue;
|
|
|
|
// Split the line according to spaces
|
|
wxStringTokenizer col(str, wxT(" "));
|
|
|
|
// Column 1 (dumpId)
|
|
col.GetNextToken();
|
|
|
|
// Column 2 (tableOid)
|
|
col.GetNextToken();
|
|
|
|
// Column 3 (oid)
|
|
col.GetNextToken();
|
|
|
|
// Column 4 (desc)
|
|
// First interesting information: object's type
|
|
wxString type = col.GetNextToken();
|
|
|
|
if (type == wxT("DATABASE"))
|
|
{
|
|
// We are restoring a database, not creating one. So ignore
|
|
// this line as there is no valid schema info and move on
|
|
// to the next object
|
|
continue;
|
|
}
|
|
else if (type == wxT("PROCEDURAL"))
|
|
{
|
|
// type for a PL is PROCEDURAL LANGUAGE
|
|
// we'll keep the next column for the object's type
|
|
type = col.GetNextToken();
|
|
}
|
|
else if (type == wxT("SHELL"))
|
|
{
|
|
// type for a SHELL is SHELL TYPE
|
|
// we'll keep both columns for the object's type
|
|
type += col.GetNextToken();
|
|
}
|
|
else if (type == wxT("OPERATOR"))
|
|
{
|
|
// type for an operator class is OPERATOR CLASS
|
|
// we'll keep the two columns for the object's type
|
|
wxString tmp = str.Mid(str.Find(type) + type.Length() + 1, 5);
|
|
if (tmp == wxT("CLASS"))
|
|
type += wxT(" ") + col.GetNextToken();
|
|
}
|
|
else if (type == wxT("SEQUENCE"))
|
|
{
|
|
// type for a sequence can be SEQUENCE, SEQUENCE OWNED BY or SEQUENCE SET
|
|
// we'll keep all these columns for the object's type
|
|
wxString tmp = str.Mid(str.Find(type) + type.Length() + 1, 3);
|
|
if (tmp == wxT("OWN") || tmp == wxT("SET"))
|
|
{
|
|
type += wxT(" ") + col.GetNextToken();
|
|
if (type == wxT("SEQUENCE OWNED"))
|
|
type += wxT(" ") + col.GetNextToken();
|
|
}
|
|
}
|
|
else if (type == wxT("FK"))
|
|
{
|
|
// type for a FK is FK CONSTRAINT
|
|
// we'll keep the next column for the object's type
|
|
type = col.GetNextToken();
|
|
}
|
|
else if (type == wxT("FOREIGN"))
|
|
{
|
|
// type for FOREIGN TABLE
|
|
//
|
|
type = type + " " + col.GetNextToken();
|
|
}
|
|
else if (type == wxT("MATERIALIZED"))
|
|
{
|
|
// type for MATERIALIZED VIEW
|
|
//
|
|
type = type + " " + col.GetNextToken();
|
|
if (str.Find("MATERIALIZED VIEW DATA") > 0) {
|
|
//MATERIALIZED VIEW DATA
|
|
type = type + " " + col.GetNextToken();
|
|
}
|
|
}
|
|
else if (type == wxT("USER"))
|
|
{
|
|
// type for USER MAPPING
|
|
//
|
|
type = type + " " + col.GetNextToken();
|
|
}
|
|
else if (type == wxT("INDEX"))
|
|
{
|
|
// type for INDEX ATTACH
|
|
//
|
|
if (str.Find("INDEX ATTACH") > 0)
|
|
type = type + " " + col.GetNextToken();
|
|
}
|
|
else if (type == wxT("PUBLICATION"))
|
|
{
|
|
// type for
|
|
//
|
|
if (str.Find("PUBLICATION TABLES IN SCHEMA") > 0)
|
|
type = type + " " + col.GetNextToken() + " " + col.GetNextToken() + " " + col.GetNextToken();
|
|
else if (str.Find("PUBLICATION TABLE") > 0)
|
|
type = type + " " + col.GetNextToken();
|
|
}
|
|
else if (type == wxT("EVENT"))
|
|
{
|
|
// type for EVENT TRIGGER
|
|
//
|
|
if (str.Find("EVENT TRIGGER") > 0)
|
|
type = type + " " + col.GetNextToken();
|
|
}
|
|
else if (type == wxT("TABLE"))
|
|
{
|
|
if (col.CountTokens() == 4)
|
|
{
|
|
// TABLE DATA detected
|
|
type += wxT(" ") + col.GetNextToken();
|
|
}
|
|
}
|
|
// In case of statements like DEFAULT ACL <schema name> DEFAULT PRIVILEGES FOR TABLES <privilege>
|
|
else if (type == wxT("DEFAULT"))
|
|
{
|
|
// We do not expect the 'DEFAULT <schema> <type> <name>' pattern here.
|
|
if (col.CountTokens() != 3)
|
|
{
|
|
if (str.Find("DEFAULT ACL") > 0)
|
|
type += wxT(" ") + col.GetNextToken();
|
|
}
|
|
}
|
|
|
|
// Column 5 (namespace)
|
|
// Second interesting information: object's schema
|
|
wxString schema = col.GetNextToken();
|
|
|
|
// Column 6 (tag)
|
|
// Third interesting information: object's qualified name
|
|
//wxString name=col.GetNextToken();
|
|
wxString name = str.Mid(str.Find(schema) + schema.Length() + 1).BeforeLast(' ');
|
|
|
|
// Column 7 (owner)
|
|
// Fourth interesting information: object's owner
|
|
wxString owner = str.Mid(str.Find(name) + name.Length() + 1);
|
|
|
|
// New method
|
|
if (type == wxT("LANGUAGE"))
|
|
{
|
|
lastItem = ctvObjects->AppendItem(root, wxT("Language ") + name + wxT(" [") + _("owner") + wxT(": ") + owner + wxT("]"), 1);
|
|
}
|
|
else if (type == wxT("ACL") && schema == wxT("-"))
|
|
{
|
|
lastItem = ctvObjects->AppendItem(root, type + wxT(" ") + name, 1);
|
|
}
|
|
else if (type == wxT("CAST"))
|
|
{
|
|
lastItem = ctvObjects->AppendItem(root, name, 1);
|
|
}
|
|
else if (type == wxT("SCHEMA"))
|
|
{
|
|
currentSchema = name;
|
|
lastItem = currentSchemaNode = ctvObjects->AppendItem(root, wxT("Schema ") + name, 1);
|
|
}
|
|
else if (type == wxT("EXTENSION") && (schema == wxT("-") || schema.IsEmpty()))
|
|
{
|
|
lastItem = ctvObjects->AppendItem(root,
|
|
owner.IsEmpty() ? wxT("Extension ") + name :
|
|
wxT("Extension ") + name + wxT("[") + _("owner") + wxT(": ") + owner + wxT("]"), 1);
|
|
}
|
|
else if (type == wxT("COMMENT") && name.StartsWith(wxT("EXTENSION ")))
|
|
{
|
|
wxString extension = name.SubString(10, name.Length());
|
|
|
|
if (ctvObjects->GetItemText(lastItem) == wxT("Extension ") + extension)
|
|
{
|
|
extensionNode = lastItem;
|
|
}
|
|
else
|
|
{
|
|
wxTreeItemId searchStartNode = root;
|
|
|
|
if (schema != wxT("-"))
|
|
{
|
|
searchStartNode = currentSchemaNode;
|
|
if (schema != currentSchema)
|
|
{
|
|
searchStartNode = ctvObjects->GetFirstChild(root, schemaNodeData);
|
|
bool found = false;
|
|
while (searchStartNode.IsOk() && !found)
|
|
{
|
|
if (ctvObjects->GetItemText(searchStartNode) == wxT("Schema ") + schema)
|
|
found = true;
|
|
else
|
|
searchStartNode = ctvObjects->GetNextChild(root, schemaNodeData);
|
|
}
|
|
|
|
// Found it?
|
|
if (!searchStartNode.IsOk())
|
|
{
|
|
searchStartNode = schemaNode;
|
|
}
|
|
else
|
|
{
|
|
searchStartNode = root;
|
|
}
|
|
}
|
|
}
|
|
|
|
extensionNode = ctvObjects->GetFirstChild(searchStartNode, extensionNodeData);
|
|
bool found = false;
|
|
|
|
while (extensionNode.IsOk() && !found)
|
|
{
|
|
if (ctvObjects->GetItemText(extensionNode) == wxT("Extension ") + extension)
|
|
found = true;
|
|
else
|
|
extensionNode = ctvObjects->GetNextChild(searchStartNode, schemaNodeData);
|
|
}
|
|
}
|
|
|
|
if (extensionNode.IsOk())
|
|
{
|
|
lastItem = ctvObjects->AppendItem(extensionNode,
|
|
owner.IsEmpty() ? type + wxT(" Extension ") + extension :
|
|
type + wxT(" Extension ") + extension + wxT(" [") + _("owner") + wxT(": ") + owner + wxT("]"), 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (schema != currentSchema)
|
|
{
|
|
// Loop through the nodes to find the schema
|
|
schemaNode = ctvObjects->GetFirstChild(root, schemaNodeData);
|
|
bool found = false;
|
|
while (schemaNode.IsOk() && !found)
|
|
{
|
|
if (ctvObjects->GetItemText(schemaNode) == wxT("Schema ") + schema)
|
|
found = true;
|
|
else
|
|
schemaNode = ctvObjects->GetNextChild(root, schemaNodeData);
|
|
}
|
|
|
|
// Found it?
|
|
if (schemaNode.IsOk())
|
|
{
|
|
currentSchema = schema;
|
|
currentSchemaNode = schemaNode;
|
|
}
|
|
else if (type == wxT("ACL") && schema != "-") {
|
|
currentSchemaNode = root;
|
|
}
|
|
else if (schema == "-"|| schema == "public") {
|
|
currentSchemaNode = root;
|
|
}
|
|
// if we are treating a comment, we use the schema of its
|
|
// object (ie, the previous line)
|
|
else if (type != wxT("COMMENT"))
|
|
{
|
|
wxLogError(_("Schema node not found for object ") + type + wxT(" ") + name + wxT(" [") + _("owner") + wxT(": ") + owner + wxT("]"));
|
|
}
|
|
}
|
|
lastItem = ctvObjects->AppendItem(currentSchemaNode,
|
|
owner.IsEmpty() ? type + wxT(" ") + name :
|
|
type + wxT(" ") + name + wxT(" [") + _("owner") + wxT(": ") + owner + wxT("]"), 1);
|
|
}
|
|
ctvObjects->SetItemData(lastItem, new restoreTreeItemData(numberOfTOCItems, str));
|
|
numberOfTOCItems++;
|
|
}
|
|
|
|
wxEndBusyCursor();
|
|
nbNotebook->SetSelection(3);
|
|
}
|
|
else
|
|
{
|
|
if (!restoreTOCFilename.IsEmpty()) wxRemoveFile(restoreTOCFilename);
|
|
}
|
|
}
|
|
|
|
|
|
void frmRestore::Go()
|
|
{
|
|
txtFilename->SetFocus();
|
|
Show(true);
|
|
}
|
|
|
|
|
|
|
|
restoreFactory::restoreFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("&Restore..."), _("Restores a backup from a local file"));
|
|
}
|
|
|
|
|
|
wxWindow *restoreFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
frmRestore *frm = new frmRestore(form, obj);
|
|
frm->Go();
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool restoreFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (!obj)
|
|
return false;
|
|
|
|
if (obj->GetConnection() && obj->GetConnection()->EdbMinimumVersion(8, 0))
|
|
return obj->CanCreate() && obj->CanRestore() && !edbRestoreExecutable.IsEmpty();
|
|
else if (obj->GetConnection() && obj->GetConnection()->GetIsGreenplum())
|
|
return obj->CanCreate() && obj->CanRestore() && !gpRestoreExecutable.IsEmpty();
|
|
else
|
|
return obj->CanCreate() && obj->CanRestore() && !pgRestoreExecutable.IsEmpty();
|
|
}
|
|
|
|
|
|
restoreTreeItemData::restoreTreeItemData(int id, const wxString &desc)
|
|
{
|
|
restoreId = id;
|
|
restoreDesc = desc;
|
|
}
|