mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
900 lines
25 KiB
C++
900 lines
25 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// dlgDatabase.cpp - PostgreSQL Database Property
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
#include <wx/spinbutt.h>
|
|
|
|
// App headers
|
|
#include "pgAdmin3.h"
|
|
#include "utils/misc.h"
|
|
#include "dlg/dlgDatabase.h"
|
|
#include "schema/pgDatabase.h"
|
|
#include "ctl/ctlDefaultSecurityPanel.h"
|
|
#include "ctl/ctlSeclabelPanel.h"
|
|
|
|
|
|
// pointer to controls
|
|
#define cbEncoding CTRL_COMBOBOX("cbEncoding")
|
|
#define cbTemplate CTRL_COMBOBOX("cbTemplate")
|
|
#define stPath CTRL_STATIC("stPath")
|
|
#define txtPath CTRL_TEXT("txtPath")
|
|
#define stTablespace CTRL_STATIC("stTablespace")
|
|
#define cbTablespace CTRL_COMBOBOX("cbTablespace")
|
|
#define txtSchemaRestr CTRL_TEXT("txtSchemaRestr")
|
|
|
|
#define lstVariables CTRL_LISTVIEW("lstVariables")
|
|
#define cbVarname CTRL_COMBOBOX2("cbVarname")
|
|
#define cbVarUsername CTRL_COMBOBOX2("cbVarUsername")
|
|
#define txtValue CTRL_TEXT("txtValue")
|
|
#define chkValue CTRL_CHECKBOX("chkValue")
|
|
#define btnAdd CTRL_BUTTON("wxID_ADD")
|
|
#define btnRemove CTRL_BUTTON("wxID_REMOVE")
|
|
#define cbCollate CTRL_COMBOBOX2("cbCollate")
|
|
#define cbCType CTRL_COMBOBOX2("cbCType")
|
|
#define txtConnLimit CTRL_TEXT("txtConnLimit")
|
|
|
|
dlgProperty *pgDatabaseFactory::CreateDialog(frmMain *frame, pgObject *node, pgObject *parent)
|
|
{
|
|
dlgDatabase *dlg = new dlgDatabase(this, frame, (pgDatabase *)node);
|
|
if (dlg && !node)
|
|
{
|
|
// use the server's connection to avoid "template1 in use"
|
|
dlg->SetConnection(parent->GetConnection());
|
|
}
|
|
return dlg;
|
|
}
|
|
|
|
|
|
BEGIN_EVENT_TABLE(dlgDatabase, dlgDefaultSecurityProperty)
|
|
EVT_TEXT(XRCID("txtPath"), dlgProperty::OnChange)
|
|
EVT_TEXT(XRCID("cbTablespace"), dlgProperty::OnChange)
|
|
EVT_COMBOBOX(XRCID("cbTablespace"), dlgProperty::OnChange)
|
|
EVT_TEXT(XRCID("cbEncoding"), dlgProperty::OnChange)
|
|
EVT_COMBOBOX(XRCID("cbEncoding"), dlgProperty::OnChange)
|
|
EVT_TEXT(XRCID("txtSchemaRestr"), dlgDatabase::OnChangeRestr)
|
|
EVT_LIST_ITEM_SELECTED(XRCID("lstVariables"), dlgDatabase::OnVarSelChange)
|
|
EVT_BUTTON(wxID_ADD, dlgDatabase::OnVarAdd)
|
|
EVT_BUTTON(wxID_REMOVE, dlgDatabase::OnVarRemove)
|
|
EVT_TEXT(XRCID("cbVarname"), dlgDatabase::OnVarnameSelChange)
|
|
EVT_TEXT(XRCID("cbVarUsername"), dlgDatabase::OnVarnameSelChange)
|
|
EVT_COMBOBOX(XRCID("cbVarname"), dlgDatabase::OnVarnameSelChange)
|
|
EVT_BUTTON(wxID_OK, dlgDatabase::OnOK)
|
|
EVT_TEXT(XRCID("cbCollate"), dlgDatabase::OnCollateSelChange)
|
|
EVT_TEXT(XRCID("cbCType"), dlgDatabase::OnCTypeSelChange)
|
|
EVT_TEXT(XRCID("txtConnLimit"), dlgDatabase::OnConnLimitChange)
|
|
#ifdef __WXMAC__
|
|
EVT_SIZE( dlgDatabase::OnChangeSize)
|
|
#endif
|
|
END_EVENT_TABLE();
|
|
|
|
|
|
dlgDatabase::dlgDatabase(pgaFactory *f, frmMain *frame, pgDatabase *node)
|
|
: dlgDefaultSecurityProperty(f, frame, node, wxT("dlgDatabase"), wxT("CREATE,TEMP,CONNECT"), "CTc", node != NULL ? true : false)
|
|
{
|
|
database = node;
|
|
schemaRestrictionOk = true;
|
|
lstVariables->CreateColumns(0, _("Username"), _("Variable"), _("Value"));
|
|
|
|
chkValue->Hide();
|
|
|
|
dirtyVars = false;
|
|
|
|
seclabelPage = new ctlSeclabelPanel(nbNotebook);
|
|
|
|
if (!node)
|
|
{
|
|
int icon = PGICON_PUBLIC;
|
|
wxString name = wxT("public");
|
|
wxString value = wxT("Tc");
|
|
securityPage->lbPrivileges->AppendItem(icon, name, value);
|
|
AppendCurrentAcl(name, value);
|
|
}
|
|
}
|
|
|
|
pgObject *dlgDatabase::GetObject()
|
|
{
|
|
return database;
|
|
}
|
|
|
|
|
|
wxString dlgDatabase::GetHelpPage() const
|
|
{
|
|
if (nbNotebook->GetSelection() == 1)
|
|
return wxT("pg/runtime-config");
|
|
return dlgDefaultSecurityProperty::GetHelpPage();
|
|
}
|
|
|
|
|
|
int dlgDatabase::Go(bool modal)
|
|
{
|
|
bool createDefPriv = false;
|
|
wxString strDefPrivsOnTables, strDefPrivsOnSeqs, strDefPrivsOnFuncs, strDefPrivsOnTypes;
|
|
|
|
if (connection->BackendMinimumVersion(9, 2))
|
|
{
|
|
seclabelPage->SetConnection(connection);
|
|
seclabelPage->SetObject(database);
|
|
this->Connect(EVT_SECLABELPANEL_CHANGE, wxCommandEventHandler(dlgDatabase::OnChange));
|
|
}
|
|
else
|
|
seclabelPage->Disable();
|
|
|
|
if (connection->BackendMinimumVersion(9, 0))
|
|
{
|
|
cbVarUsername->Append(wxT(""));
|
|
// AddUsers function of dlgDefaultSecurity has already been called.
|
|
// Hence, calling dlgProperty::AddUsers instead of that.
|
|
dlgProperty::AddUsers(cbVarUsername);
|
|
}
|
|
else
|
|
cbVarUsername->Enable(false);
|
|
|
|
if (connection->BackendMinimumVersion(8, 0))
|
|
{
|
|
stPath->Hide();
|
|
txtPath->Hide();
|
|
}
|
|
else
|
|
{
|
|
stTablespace->Hide();
|
|
cbTablespace->Hide();
|
|
}
|
|
|
|
if (!connection->BackendMinimumVersion(8, 1))
|
|
{
|
|
txtConnLimit->Disable();
|
|
}
|
|
else
|
|
txtConnLimit->SetValidator(numericValidator);
|
|
|
|
if (!connection->BackendMinimumVersion(8, 4))
|
|
{
|
|
cbCollate->Disable();
|
|
cbCType->Disable();
|
|
}
|
|
|
|
pgSet *set;
|
|
if (connection->BackendMinimumVersion(7, 4))
|
|
set = connection->ExecuteSet(wxT("SELECT name, vartype, min_val, max_val\n")
|
|
wxT(" FROM pg_settings WHERE context in ('user', 'superuser')"));
|
|
else
|
|
set = connection->ExecuteSet(wxT("SELECT name, 'string' as vartype, '' as min_val, '' as max_val FROM pg_settings"));
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
cbVarname->Append(set->GetVal(0));
|
|
varInfo.Add(set->GetVal(wxT("vartype")) + wxT(" ") +
|
|
set->GetVal(wxT("min_val")) + wxT(" ") +
|
|
set->GetVal(wxT("max_val")));
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
|
|
cbVarname->SetSelection(0);
|
|
|
|
if (connection->BackendMinimumVersion(9, 0))
|
|
{
|
|
cbVarUsername->SetSelection(0);
|
|
}
|
|
SetupVarEditor(0);
|
|
}
|
|
|
|
if (database)
|
|
{
|
|
// edit mode
|
|
|
|
if (!connection->BackendMinimumVersion(7, 4))
|
|
txtName->Disable();
|
|
|
|
if (!connection->BackendMinimumVersion(8, 0))
|
|
cbOwner->Disable();
|
|
|
|
readOnly = !database->GetServer()->GetCreatePrivilege();
|
|
|
|
|
|
if (connection->BackendMinimumVersion(9, 0))
|
|
{
|
|
createDefPriv = true;
|
|
strDefPrivsOnTables = database->GetDefPrivsOnTables();
|
|
strDefPrivsOnSeqs = database->GetDefPrivsOnSequences();
|
|
strDefPrivsOnFuncs = database->GetDefPrivsOnFunctions();
|
|
}
|
|
if (connection->BackendMinimumVersion(9, 2))
|
|
strDefPrivsOnTypes = database->GetDefPrivsOnTypes();
|
|
|
|
if (readOnly)
|
|
{
|
|
cbVarname->Disable();
|
|
cbVarUsername->Disable();
|
|
txtValue->Disable();
|
|
btnAdd->Disable();
|
|
btnRemove->Disable();
|
|
}
|
|
|
|
size_t i;
|
|
wxString username;
|
|
wxString varname;
|
|
wxString varvalue;
|
|
for (i = 0 ; i < database->GetVariables().GetCount() ; i += 3)
|
|
{
|
|
username = database->GetVariables().Item(i);
|
|
varname = database->GetVariables().Item(i + 1);
|
|
varvalue = database->GetVariables().Item(i + 2);
|
|
|
|
lstVariables->AppendItem(0, username, varname, varvalue);
|
|
}
|
|
|
|
PrepareTablespace(cbTablespace, database->GetTablespaceOid());
|
|
if (connection->BackendMinimumVersion(8, 4))
|
|
cbTablespace->Enable();
|
|
else
|
|
cbTablespace->Disable();
|
|
txtPath->SetValue(database->GetPath());
|
|
txtPath->Disable();
|
|
|
|
cbEncoding->Append(database->GetEncoding());
|
|
cbEncoding->SetSelection(0);
|
|
|
|
if (connection->BackendMinimumVersion(8, 1))
|
|
{
|
|
wxString strConnLimit;
|
|
strConnLimit.Printf(wxT("%ld"), database->GetConnectionLimit());
|
|
txtConnLimit->SetValue(strConnLimit);
|
|
}
|
|
|
|
if (connection->BackendMinimumVersion(8, 4))
|
|
{
|
|
cbCollate->Append(database->GetCollate());
|
|
cbCollate->SetSelection(0);
|
|
cbCType->Append(database->GetCType());
|
|
cbCType->SetSelection(0);
|
|
}
|
|
|
|
cbTemplate->Disable();
|
|
cbEncoding->Disable();
|
|
cbCollate->Disable();
|
|
cbCType->Disable();
|
|
|
|
txtSchemaRestr->SetValue(database->GetSchemaRestriction());
|
|
}
|
|
else
|
|
{
|
|
// create mode
|
|
if (!connection->BackendMinimumVersion(8, 2))
|
|
txtComment->Disable();
|
|
|
|
PrepareTablespace(cbTablespace);
|
|
|
|
// Add the default tablespace
|
|
cbTablespace->Insert(_("<default tablespace>"), 0, (void *)0);
|
|
cbTablespace->SetSelection(0);
|
|
|
|
cbTemplate->Append(wxEmptyString);
|
|
FillCombobox(wxT("SELECT datname FROM pg_database ORDER BY datname"), cbTemplate);
|
|
cbTemplate->SetSelection(0);
|
|
|
|
if (connection->BackendMinimumVersion(8, 4))
|
|
{
|
|
FillCombobox(wxT("select DISTINCT(datctype) from pg_database UNION SELECT DISTINCT(datcollate) from pg_database"), cbCollate, cbCType);
|
|
if (cbCollate->FindString(wxT("C")) < 0)
|
|
{
|
|
cbCollate->AppendString(wxT("C"));
|
|
cbCType->AppendString(wxT("C"));
|
|
}
|
|
if (cbCollate->FindString(wxT("POSIX")) < 0)
|
|
{
|
|
cbCollate->AppendString(wxT("POSIX"));
|
|
cbCType->AppendString(wxT("POSIX"));
|
|
}
|
|
}
|
|
if (connection->BackendMinimumVersion(8, 1))
|
|
{
|
|
txtConnLimit->SetValue(wxT("-1"));
|
|
}
|
|
|
|
|
|
long encNo = 0;
|
|
wxString encStr;
|
|
do
|
|
{
|
|
encStr = connection->ExecuteScalar(
|
|
wxT("SELECT pg_encoding_to_char(") + NumToStr(encNo) + wxT(")"));
|
|
if (pgConn::IsValidServerEncoding(encNo) && !encStr.IsEmpty())
|
|
cbEncoding->Append(encStr);
|
|
|
|
encNo++;
|
|
}
|
|
while (!encStr.IsEmpty());
|
|
|
|
encStr = connection->ExecuteScalar(wxT("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = 'template0'"));
|
|
encNo = cbEncoding->FindString(encStr);
|
|
|
|
if (encNo < 0)
|
|
{
|
|
encNo = cbEncoding->FindString(wxT("UNICODE"));
|
|
if (encNo < 0)
|
|
encNo = cbEncoding->FindString(wxT("UTF8"));
|
|
}
|
|
|
|
if (encNo >= 0)
|
|
cbEncoding->SetSelection(encNo);
|
|
|
|
}
|
|
|
|
// Find, and disable the CONNECT ACL option if we're on pre 8.2
|
|
if (!connection->BackendMinimumVersion(8, 2))
|
|
{
|
|
// Disable the checkbox
|
|
if (!DisablePrivilege(wxT("CONNECT")))
|
|
{
|
|
wxLogError(_("Failed to disable the CONNECT privilege checkbox!"));
|
|
}
|
|
}
|
|
|
|
return dlgDefaultSecurityProperty::Go(modal, createDefPriv, strDefPrivsOnTables, strDefPrivsOnSeqs, strDefPrivsOnFuncs, strDefPrivsOnTypes);
|
|
}
|
|
|
|
|
|
pgObject *dlgDatabase::CreateObject(pgCollection *collection)
|
|
{
|
|
wxString name = GetName();
|
|
|
|
pgObject *obj = databaseFactory.CreateObjects(collection, 0, wxT(" WHERE datname=") + qtDbString(name) + wxT("\n"));
|
|
return obj;
|
|
}
|
|
|
|
|
|
#ifdef __WXMAC__
|
|
void dlgDatabase::OnChangeSize(wxSizeEvent &ev)
|
|
{
|
|
lstVariables->SetSize(wxDefaultCoord, wxDefaultCoord,
|
|
ev.GetSize().GetWidth(), ev.GetSize().GetHeight() - 550);
|
|
dlgSecurityProperty::OnChangeSize(ev);
|
|
}
|
|
#endif
|
|
|
|
|
|
void dlgDatabase::OnChangeRestr(wxCommandEvent &ev)
|
|
{
|
|
if (txtSchemaRestr->GetValue().IsEmpty())
|
|
schemaRestrictionOk = true;
|
|
else
|
|
{
|
|
wxString sql = wxT("EXPLAIN SELECT 1 FROM pg_namespace\n")
|
|
wxT("WHERE nspname IN (") + txtSchemaRestr->GetValue() + wxT(")");
|
|
|
|
wxLogNull nix;
|
|
wxString result = connection->ExecuteScalar(sql);
|
|
|
|
schemaRestrictionOk = !result.IsEmpty();
|
|
}
|
|
OnChange(ev);
|
|
}
|
|
|
|
|
|
void dlgDatabase::OnOK(wxCommandEvent &ev)
|
|
{
|
|
#ifdef __WXGTK__
|
|
if (!btnOK->IsEnabled())
|
|
return;
|
|
#endif
|
|
if (database)
|
|
{
|
|
database->iSetSchemaRestriction(txtSchemaRestr->GetValue().Trim());
|
|
settings->Write(wxString::Format(wxT("Servers/%ld/Databases/%s/SchemaRestriction"), database->GetServer()->GetServerIndex(), database->GetName().c_str()), txtSchemaRestr->GetValue().Trim());
|
|
|
|
/*
|
|
* The connection from the database will get disconnected before execution of any
|
|
* sql statements for the database.
|
|
*
|
|
* Hence, we need to hack the execution of the default privileges statements(sqls)
|
|
* before getting disconnected from this database. So that, these statements will
|
|
* run against the current database connection, and not against the server connection.
|
|
*/
|
|
// defaultSecurityChanged will be true only for PostgreSQL 9.0 or later
|
|
if (defaultSecurityChanged)
|
|
{
|
|
wxString strDefPrivs = GetDefaultPrivileges();
|
|
if (!executeDDLSql(strDefPrivs))
|
|
{
|
|
EnableOK(true);
|
|
return;
|
|
}
|
|
defaultSecurityChanged = false;
|
|
}
|
|
}
|
|
dlgDefaultSecurityProperty::OnOK(ev);
|
|
}
|
|
|
|
/*
|
|
* Execute default privileges statement
|
|
*
|
|
* - Hacked to execute the default privileges statement (sql) for dlgDatabse against this database,
|
|
* because connection for this database object is getting disconnected, and replaced by the server
|
|
* connection, before execution of any statements (sqls) in dlgPropery::apply function called
|
|
* from dlgPropery::OnOK event handler.
|
|
*
|
|
* NOTE: This will work only if the database object exists.
|
|
*/
|
|
bool dlgDatabase::executeDDLSql(const wxString &strSql)
|
|
{
|
|
pgConn *myConn = connection;
|
|
|
|
if (!strSql.IsEmpty())
|
|
{
|
|
wxString tmp;
|
|
if (cbClusterSet && cbClusterSet->GetSelection() > 0)
|
|
{
|
|
replClientData *data = (replClientData *)cbClusterSet->wxItemContainer::GetClientData(cbClusterSet->GetSelection());
|
|
|
|
if (data->majorVer > 1 || (data->majorVer == 1 && data->minorVer >= 2))
|
|
{
|
|
// From slony version 2.2.0 onwards ddlscript_prepare() method is removed and
|
|
// ddlscript_complete() method arguments got changed so we have to use ddlcapture() method
|
|
// instead of ddlscript_prepare() and changed the argument of ddlscript_complete() method
|
|
if ((data->majorVer == 2 && data->minorVer >= 2) || (data->majorVer > 2))
|
|
{
|
|
tmp = wxT("SELECT ") + qtIdent(data->cluster)
|
|
+ wxT(".ddlcapture(") + qtDbString(strSql) + wxT(", ") + wxT("NULL::text") + wxT(");\n")
|
|
+ wxT("SELECT ") + qtIdent(data->cluster)
|
|
+ wxT(".ddlscript_complete(") + wxT("NULL::text") + wxT(");\n");
|
|
}
|
|
else
|
|
{
|
|
tmp = wxT("SELECT ") + qtIdent(data->cluster)
|
|
+ wxT(".ddlscript_prepare(") + NumToStr(data->setId) + wxT(", -1);\n")
|
|
+ strSql + wxT(";\n")
|
|
+ wxT("SELECT ") + qtIdent(data->cluster)
|
|
+ wxT(".ddlscript_complete(") + NumToStr(data->setId) + wxT(", ")
|
|
+ qtDbString(strSql) + wxT(", -1);\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tmp = wxT("SELECT ") + qtIdent(data->cluster)
|
|
+ wxT(".ddlscript(") + NumToStr(data->setId) + wxT(", ")
|
|
+ qtDbString(strSql) + wxT(", 0);\n");
|
|
}
|
|
}
|
|
else
|
|
tmp = strSql;
|
|
|
|
if (!myConn->ExecuteVoid(tmp))
|
|
// error message is displayed inside ExecuteVoid
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void dlgDatabase::CheckChange()
|
|
{
|
|
bool enable = true;
|
|
|
|
if (database)
|
|
{
|
|
long connLimit;
|
|
if (!txtConnLimit->GetValue().ToLong(&connLimit))
|
|
connLimit = database->GetConnectionLimit();
|
|
|
|
enable = txtSchemaRestr->GetValue() != database->GetSchemaRestriction()
|
|
|| txtComment->GetValue() != database->GetComment()
|
|
|| txtName->GetValue() != database->GetName()
|
|
|| cbOwner->GetValue() != database->GetOwner()
|
|
|| cbTablespace->GetValue() != database->GetTablespace()
|
|
|| connLimit != database->GetConnectionLimit()
|
|
|| dirtyVars;
|
|
if (seclabelPage && connection->BackendMinimumVersion(9, 2))
|
|
enable = enable || !(seclabelPage->GetSqlForSecLabels().IsEmpty());
|
|
}
|
|
|
|
CheckValid(enable, !GetName().IsEmpty(), _("Please specify name."));
|
|
CheckValid(enable, schemaRestrictionOk, _("Restriction not valid."));
|
|
|
|
// If there's a schema restriction, we need to ignore the SQL
|
|
// for the dialogue when enabling the OK button.
|
|
if (schemaRestrictionOk)
|
|
EnableOK(enable, true);
|
|
else
|
|
EnableOK(enable);
|
|
}
|
|
|
|
|
|
void dlgDatabase::OnVarnameSelChange(wxCommandEvent &ev)
|
|
{
|
|
int sel = cbVarname->GuessSelection(ev);
|
|
|
|
SetupVarEditor(sel);
|
|
}
|
|
|
|
void dlgDatabase::OnCollateSelChange(wxCommandEvent &ev)
|
|
{
|
|
cbCollate->GuessSelection(ev);
|
|
}
|
|
|
|
void dlgDatabase::OnCTypeSelChange(wxCommandEvent &ev)
|
|
{
|
|
cbCType->GuessSelection(ev);
|
|
}
|
|
|
|
void dlgDatabase::OnConnLimitChange(wxCommandEvent &ev)
|
|
{
|
|
if (ev.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED)
|
|
{
|
|
wxString strConnLimit = txtConnLimit->GetValue();
|
|
long val = 0;
|
|
if (strConnLimit.ToLong(&val))
|
|
{
|
|
CheckChange();
|
|
}
|
|
else if (strConnLimit.Contains(wxT(".")))
|
|
{
|
|
double val;
|
|
|
|
// Stop Propagation of the event to the parents
|
|
ev.StopPropagation();
|
|
if (strConnLimit.ToDouble(&val))
|
|
{
|
|
strConnLimit.Printf(wxT("%ld"), (long)val);
|
|
txtConnLimit->SetValue(strConnLimit);
|
|
txtConnLimit->SetInsertionPointEnd();
|
|
return;
|
|
}
|
|
}
|
|
else if (strConnLimit.length() > 9)
|
|
{
|
|
// Maximum value support is 2147483647
|
|
wxString newVal = strConnLimit.substr(0, 10);
|
|
if (!newVal.ToLong(&val))
|
|
{
|
|
newVal = strConnLimit.substr(0, 9);
|
|
}
|
|
ev.StopPropagation();
|
|
txtConnLimit->SetValue(newVal);
|
|
txtConnLimit->SetInsertionPointEnd();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void dlgDatabase::SetupVarEditor(int var)
|
|
{
|
|
if (var >= 0 && varInfo.Count() > 0)
|
|
{
|
|
wxStringTokenizer vals(varInfo.Item(var));
|
|
wxString typ = vals.GetNextToken();
|
|
|
|
if (typ == wxT("bool"))
|
|
{
|
|
txtValue->Hide();
|
|
chkValue->Show();
|
|
chkValue->SetMinSize(wxSize(cbVarname->GetSize().GetWidth(), cbVarname->GetSize().GetHeight()));
|
|
chkValue->GetParent()->Layout();
|
|
}
|
|
else
|
|
{
|
|
chkValue->Hide();
|
|
txtValue->Show();
|
|
if (typ == wxT("string") || typ == wxT("enum"))
|
|
txtValue->SetValidator(wxTextValidator());
|
|
else
|
|
txtValue->SetValidator(numericValidator);
|
|
txtValue->SetMinSize(wxSize(cbVarname->GetSize().GetWidth(), cbVarname->GetSize().GetHeight()));
|
|
txtValue->GetParent()->Layout();
|
|
}
|
|
}
|
|
}
|
|
|
|
void dlgDatabase::OnVarSelChange(wxListEvent &ev)
|
|
{
|
|
long pos = lstVariables->GetSelection();
|
|
if (pos >= 0)
|
|
{
|
|
cbVarUsername->SetValue(lstVariables->GetText(pos));
|
|
cbVarname->SetValue(lstVariables->GetText(pos, 1));
|
|
|
|
// We used to raise an OnVarnameSelChange() event here, but
|
|
// at this point the combo box hasn't necessarily updated.
|
|
wxString value = lstVariables->GetText(pos, 2);
|
|
int sel = cbVarname->FindString(lstVariables->GetText(pos, 1));
|
|
SetupVarEditor(sel);
|
|
|
|
txtValue->SetValue(value);
|
|
chkValue->SetValue(value == wxT("on"));
|
|
}
|
|
}
|
|
|
|
|
|
void dlgDatabase::OnVarAdd(wxCommandEvent &ev)
|
|
{
|
|
wxString username = cbVarUsername->GetValue();
|
|
wxString name = cbVarname->GetValue();
|
|
wxString value;
|
|
if (chkValue->IsShown())
|
|
value = chkValue->GetValue() ? wxT("on") : wxT("off");
|
|
else
|
|
value = txtValue->GetValue().Strip(wxString::both);
|
|
|
|
if (value.IsEmpty())
|
|
value = wxT("DEFAULT");
|
|
|
|
if (!name.IsEmpty())
|
|
{
|
|
bool found = false;
|
|
long prevpos = -1;
|
|
for (long item = 0; item < lstVariables->GetItemCount(); item++)
|
|
{
|
|
if (name == lstVariables->GetText(item, 1))
|
|
{
|
|
if (username == lstVariables->GetText(item))
|
|
{
|
|
found = true;
|
|
lstVariables->SetItem(item, 2, value);
|
|
}
|
|
else
|
|
{
|
|
prevpos = item;
|
|
}
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
if (prevpos != -1)
|
|
{
|
|
lstVariables->InsertItem(prevpos, username, 1);
|
|
lstVariables->SetItem(prevpos, 1, name);
|
|
lstVariables->SetItem(prevpos, 2, value);
|
|
}
|
|
else
|
|
{
|
|
long pos = lstVariables->GetItemCount();
|
|
lstVariables->InsertItem(pos, username, 1);
|
|
lstVariables->SetItem(pos, 1, name);
|
|
lstVariables->SetItem(pos, 2, value);
|
|
}
|
|
}
|
|
}
|
|
dirtyVars = true;
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgDatabase::OnVarRemove(wxCommandEvent &ev)
|
|
{
|
|
if (lstVariables->GetSelection() == wxNOT_FOUND)
|
|
return;
|
|
lstVariables->DeleteCurrentItem();
|
|
dirtyVars = true;
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
// Note: CREATE DATABASE cannot be part of a multi-statement query as of
|
|
// PG83, and never actually would have been transaction-safe prior
|
|
// to then. Therefore, when creating a new database, only the CREATE
|
|
// statement comes from GetSql(), subsequent ALTERs come from GetSql2()
|
|
wxString dlgDatabase::GetSql()
|
|
{
|
|
wxString sql, name;
|
|
name = GetName();
|
|
|
|
if (database)
|
|
{
|
|
// edit mode
|
|
|
|
AppendNameChange(sql);
|
|
AppendOwnerChange(sql, wxT("DATABASE ") + qtIdent(name));
|
|
|
|
AppendComment(sql, wxT("DATABASE"), 0, database);
|
|
|
|
if (seclabelPage && connection->BackendMinimumVersion(9, 2))
|
|
sql += seclabelPage->GetSqlForSecLabels(wxT("DATABASE"), qtIdent(name));
|
|
|
|
if (connection->BackendMinimumVersion(8, 4))
|
|
{
|
|
if (cbTablespace->GetCurrentSelection() > 0 && cbTablespace->GetOIDKey() > 0
|
|
&& cbTablespace->GetOIDKey() != database->GetTablespaceOid())
|
|
sql += wxT("ALTER DATABASE ") + qtIdent(name)
|
|
+ wxT("\n SET TABLESPACE ") + qtIdent(cbTablespace->GetValue())
|
|
+ wxT(";\n");
|
|
}
|
|
if (connection->BackendMinimumVersion(8, 1))
|
|
{
|
|
long connLimit;
|
|
|
|
if (txtConnLimit->GetValue().IsEmpty())
|
|
connLimit = -1;
|
|
else if (!txtConnLimit->GetValue().ToLong(&connLimit))
|
|
connLimit = database->GetConnectionLimit();
|
|
|
|
if (connLimit != database->GetConnectionLimit())
|
|
{
|
|
wxString strConnLimit;
|
|
strConnLimit << connLimit;
|
|
sql += wxT("ALTER DATABASE ") + qtIdent(name)
|
|
+ wxT("\n WITH CONNECTION LIMIT = ")
|
|
+ strConnLimit
|
|
+ wxT(";\n");
|
|
}
|
|
}
|
|
|
|
if (!connection->BackendMinimumVersion(8, 2))
|
|
sql += GetGrant(wxT("CT"), wxT("DATABASE ") + qtIdent(name));
|
|
else
|
|
sql += GetGrant(wxT("CTc"), wxT("DATABASE ") + qtIdent(name));
|
|
|
|
wxArrayString vars;
|
|
wxString username;
|
|
wxString varname;
|
|
wxString varvalue;
|
|
size_t index;
|
|
int pos;
|
|
|
|
// copy database->GetVariables() into vars
|
|
for (index = 0 ; index < database->GetVariables().GetCount() ; index++)
|
|
vars.Add(database->GetVariables().Item(index));
|
|
|
|
// check for changed or added vars
|
|
for (pos = 0 ; pos < lstVariables->GetItemCount() ; pos++)
|
|
{
|
|
wxString newUsr = lstVariables->GetText(pos);
|
|
wxString newVar = lstVariables->GetText(pos, 1);
|
|
wxString newVal = lstVariables->GetText(pos, 2);
|
|
|
|
wxString oldVal;
|
|
|
|
for (index = 0 ; index < vars.GetCount() ; index += 3)
|
|
{
|
|
username = vars.Item(index);
|
|
varname = vars.Item(index + 1);
|
|
varvalue = vars.Item(index + 2);
|
|
|
|
if (newUsr == username && newVar == varname)
|
|
{
|
|
oldVal = varvalue;
|
|
vars.RemoveAt(index);
|
|
vars.RemoveAt(index);
|
|
vars.RemoveAt(index);
|
|
break;
|
|
}
|
|
}
|
|
if (oldVal != newVal)
|
|
{
|
|
if (newUsr.Length() == 0)
|
|
sql += wxT("ALTER DATABASE ") + qtIdent(name);
|
|
else
|
|
sql += wxT("ALTER ROLE ") + newUsr + wxT(" IN DATABASE ") + qtIdent(name);
|
|
|
|
if (newVar != wxT("search_path") && newVar != wxT("temp_tablespaces"))
|
|
{
|
|
sql += wxT("\n SET ") + newVar + wxT(" = '") + newVal + wxT("';\n");
|
|
}
|
|
else
|
|
{
|
|
sql += wxT("\n SET ") + newVar + wxT(" = ") + newVal + wxT(";\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// check for removed vars
|
|
for (pos = 0 ; pos < (int)vars.GetCount() ; pos += 3)
|
|
{
|
|
username = vars.Item(pos);
|
|
varname = vars.Item(pos + 1);
|
|
varvalue = vars.Item(pos + 2);
|
|
|
|
if (username.Length() == 0)
|
|
{
|
|
sql += wxT("ALTER DATABASE ") + qtIdent(name)
|
|
+ wxT("\n RESET ") + varname
|
|
+ wxT(";\n");
|
|
}
|
|
else
|
|
{
|
|
sql += wxT("ALTER ROLE ") + username + wxT(" IN DATABASE ") + qtIdent(name)
|
|
+ wxT("\n RESET ") + varname + wxT(";\n");
|
|
}
|
|
}
|
|
|
|
if (defaultSecurityChanged)
|
|
sql += wxT("\n") + GetDefaultPrivileges();
|
|
}
|
|
else
|
|
{
|
|
// create mode
|
|
sql = wxT("CREATE DATABASE ") + qtIdent(name)
|
|
+ wxT("\n WITH ENCODING=") + qtDbString(cbEncoding->GetValue());
|
|
|
|
AppendIfFilled(sql, wxT("\n OWNER="), qtIdent(cbOwner->GetValue()));
|
|
AppendIfFilled(sql, wxT("\n TEMPLATE="), qtIdent(cbTemplate->GetValue()));
|
|
AppendIfFilled(sql, wxT("\n LOCATION="), txtPath->GetValue());
|
|
if (connection->BackendMinimumVersion(8, 4))
|
|
{
|
|
wxString strCollate = cbCollate->GetValue();
|
|
if (!strCollate.IsEmpty())
|
|
AppendIfFilled(sql, wxT("\n LC_COLLATE="), qtDbString(strCollate));
|
|
wxString strCType = cbCType->GetValue();
|
|
if (!strCType.IsEmpty())
|
|
AppendIfFilled(sql, wxT("\n LC_CTYPE="), qtDbString(strCType));
|
|
}
|
|
if (connection->BackendMinimumVersion(8, 1))
|
|
{
|
|
AppendIfFilled(sql, wxT("\n CONNECTION LIMIT="), (txtConnLimit->GetValue() == wxT("-") ? wxT("-1") : txtConnLimit->GetValue()));
|
|
}
|
|
if (cbTablespace->GetCurrentSelection() > 0 && cbTablespace->GetOIDKey() > 0)
|
|
sql += wxT("\n TABLESPACE=") + qtIdent(cbTablespace->GetValue());
|
|
|
|
sql += wxT(";\n");
|
|
}
|
|
|
|
return sql.Trim(false);
|
|
}
|
|
|
|
wxString dlgDatabase::GetSql2()
|
|
{
|
|
wxString sql, name;
|
|
name = GetName();
|
|
|
|
// We only use GetSql2() in the CREATE case
|
|
if (!database)
|
|
{
|
|
if (connection->BackendMinimumVersion(8, 2))
|
|
AppendComment(sql, wxT("DATABASE"), 0, database);
|
|
|
|
if (!connection->BackendMinimumVersion(8, 2))
|
|
sql += GetGrant(wxT("CT"), wxT("DATABASE ") + qtIdent(name));
|
|
else
|
|
sql += GetGrant(wxT("CTc"), wxT("DATABASE ") + qtIdent(name));
|
|
|
|
int cnt = lstVariables->GetItemCount();
|
|
int pos;
|
|
|
|
// check for changed or added vars
|
|
for (pos = 0 ; pos < cnt ; pos++)
|
|
{
|
|
wxString newUsr = lstVariables->GetText(pos);
|
|
wxString newVar = lstVariables->GetText(pos, 1);
|
|
wxString newVal = lstVariables->GetText(pos, 2);
|
|
|
|
if (newUsr.Length() == 0)
|
|
sql += wxT("ALTER DATABASE ") + qtIdent(name);
|
|
else
|
|
sql += wxT("ALTER ROLE ") + newUsr + wxT(" IN DATABASE ") + qtIdent(name);
|
|
|
|
if (newVar != wxT("search_path") && newVar != wxT("temp_tablespaces"))
|
|
{
|
|
sql += wxT("\n SET ") + newVar + wxT(" = '") + newVal + wxT("';\n");
|
|
}
|
|
else
|
|
{
|
|
sql += wxT("\n SET ") + newVar + wxT(" = ") + newVal + wxT(";\n");
|
|
}
|
|
}
|
|
if (seclabelPage && connection->BackendMinimumVersion(9, 2))
|
|
sql += seclabelPage->GetSqlForSecLabels(wxT("DATABASE"), qtIdent(name));
|
|
}
|
|
|
|
return sql;
|
|
}
|
|
|
|
bool dlgDatabase::GetDisconnectFirst()
|
|
{
|
|
if (database)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void dlgDatabase::OnChange(wxCommandEvent &event)
|
|
{
|
|
CheckChange();
|
|
}
|