mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 14:15:49 -06:00
1432 lines
40 KiB
C++
1432 lines
40 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// dlgType.cpp - PostgreSQL TYPE Property
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
|
|
|
|
// App headers
|
|
#include "utils/misc.h"
|
|
#include "dlg/dlgType.h"
|
|
#include "schema/pgSchema.h"
|
|
#include "schema/pgType.h"
|
|
#include "schema/pgDatatype.h"
|
|
#include "ctl/ctlSeclabelPanel.h"
|
|
#include "frm/frmMain.h"
|
|
#include "schema/pgUser.h"
|
|
#include "schema/pgGroup.h"
|
|
|
|
|
|
// pointer to controls
|
|
#define rdbType CTRL_RADIOBOX("rdbType")
|
|
|
|
#define cbInput CTRL_COMBOBOX("cbInput")
|
|
#define cbOutput CTRL_COMBOBOX("cbOutput")
|
|
#define cbReceive CTRL_COMBOBOX("cbReceive")
|
|
#define cbSend CTRL_COMBOBOX("cbSend")
|
|
#define cbTypmodin CTRL_COMBOBOX("cbTypmodin")
|
|
#define cbTypmodout CTRL_COMBOBOX("cbTypmodout")
|
|
#define cbAnalyze CTRL_COMBOBOX("cbAnalyze")
|
|
#define cbCategory CTRL_COMBOBOX("cbCategory")
|
|
#define chkPrefered CTRL_CHECKBOX("chkPrefered")
|
|
#define chkVariable CTRL_CHECKBOX("chkVariable")
|
|
#define txtIntLength CTRL_TEXT("txtIntLength")
|
|
#define txtDefault CTRL_TEXT("txtDefault")
|
|
#define cbElement CTRL_COMBOBOX2("cbElement")
|
|
#define txtDelimiter CTRL_TEXT("txtDelimiter")
|
|
#define chkByValue CTRL_CHECKBOX("chkByValue")
|
|
#define cbAlignment CTRL_COMBOBOX("cbAlignment")
|
|
#define cbStorage CTRL_COMBOBOX("cbStorage")
|
|
#define lstMembers CTRL_LISTVIEW("lstMembers")
|
|
#define txtMembername CTRL_TEXT("txtMembername")
|
|
#define lstLabels CTRL_LISTVIEW("lstLabels")
|
|
#define txtLabel CTRL_TEXT("txtLabel")
|
|
#define btnAddMember CTRL_BUTTON("btnAddMember")
|
|
#define btnChangeMember CTRL_BUTTON("btnChangeMember")
|
|
#define btnRemoveMember CTRL_BUTTON("btnRemoveMember")
|
|
#define btnAddAfterLabel CTRL_BUTTON("btnAddAfterLabel")
|
|
#define btnAddBeforeLabel CTRL_BUTTON("btnAddBeforeLabel")
|
|
#define btnRemoveLabel CTRL_BUTTON("btnRemoveLabel")
|
|
#define pnlDefinition CTRL_PANEL("pnlDefinition")
|
|
#define pnlDefinitionExtern CTRL_PANEL("pnlDefinitionExtern")
|
|
#define pnlDefinitionComposite CTRL_PANEL("pnlDefinitionComposite")
|
|
#define pnlDefinitionEnum CTRL_PANEL("pnlDefinitionEnum")
|
|
#define pnlDefinitionRange CTRL_PANEL("pnlDefinitionRange")
|
|
#define chkCollatable CTRL_CHECKBOX("chkCollatable")
|
|
#define cbCollation CTRL_COMBOBOX("cbCollation")
|
|
#define cbSubtype CTRL_COMBOBOX("cbSubtype")
|
|
#define cbSubtypeOpclass CTRL_COMBOBOX("cbSubtypeOpclass")
|
|
#define cbRngCollation CTRL_COMBOBOX("cbRngCollation")
|
|
#define cbCanonical CTRL_COMBOBOX("cbCanonical")
|
|
#define cbSubtypeDiff CTRL_COMBOBOX("cbSubtypeDiff")
|
|
|
|
|
|
BEGIN_EVENT_TABLE(dlgType, dlgTypeProperty)
|
|
EVT_RADIOBOX(XRCID("rdbType"), dlgType::OnTypeChange)
|
|
|
|
EVT_TEXT(XRCID("cbInput"), dlgProperty::OnChange)
|
|
EVT_COMBOBOX(XRCID("cbInput"), dlgProperty::OnChange)
|
|
EVT_TEXT(XRCID("cbOutput"), dlgProperty::OnChange)
|
|
EVT_COMBOBOX(XRCID("cbOutput"), dlgProperty::OnChange)
|
|
EVT_TEXT(XRCID("txtIntLength"), dlgProperty::OnChange)
|
|
EVT_CHECKBOX(XRCID("chkVariable"), dlgProperty::OnChange)
|
|
|
|
EVT_BUTTON(XRCID("btnAddMember"), dlgType::OnMemberAdd)
|
|
EVT_BUTTON(XRCID("btnChangeMember"), dlgType::OnMemberChange)
|
|
EVT_BUTTON(XRCID("btnRemoveMember"), dlgType::OnMemberRemove)
|
|
EVT_BUTTON(XRCID("btnAddBeforeLabel"), dlgType::OnLabelAddBefore)
|
|
EVT_BUTTON(XRCID("btnAddAfterLabel"), dlgType::OnLabelAddAfter)
|
|
EVT_BUTTON(XRCID("btnRemoveLabel"), dlgType::OnLabelRemove)
|
|
EVT_LIST_ITEM_SELECTED(XRCID("lstMembers"), dlgType::OnMemberSelChange)
|
|
EVT_LIST_ITEM_SELECTED(XRCID("lstLabels"), dlgType::OnLabelSelChange)
|
|
EVT_TEXT(XRCID("cbDatatype"), dlgType::OnSelChangeTyp)
|
|
EVT_COMBOBOX(XRCID("cbDatatype"), dlgType::OnSelChangeTyp)
|
|
EVT_TEXT(XRCID("txtMembername"), dlgType::OnChangeMember)
|
|
EVT_TEXT(XRCID("txtLength"), dlgType::OnSelChangeTypOrLen)
|
|
EVT_TEXT(XRCID("txtPrecision"), dlgType::OnSelChangeTypOrLen)
|
|
EVT_BUTTON(CTL_ADDPRIV, dlgType::OnAddPriv)
|
|
EVT_BUTTON(CTL_DELPRIV, dlgType::OnDelPriv)
|
|
EVT_TEXT(XRCID("cbSubtype"), dlgType::OnSubtypeChange)
|
|
EVT_COMBOBOX(XRCID("cbSubtype"), dlgType::OnSubtypeChange)
|
|
EVT_TEXT(XRCID("txtName"), dlgType::OnNameChange)
|
|
#ifdef __WXMAC__
|
|
EVT_SIZE( dlgType::OnChangeSize)
|
|
#endif
|
|
END_EVENT_TABLE();
|
|
|
|
|
|
dlgProperty *pgTypeFactory::CreateDialog(frmMain *frame, pgObject *node, pgObject *parent)
|
|
{
|
|
return new dlgType(this, frame, (pgType *)node, (pgSchema *)parent);
|
|
}
|
|
|
|
|
|
dlgType::dlgType(pgaFactory *f, frmMain *frame, pgType *node, pgSchema *sch)
|
|
: dlgTypeProperty(f, frame, wxT("dlgType"))
|
|
{
|
|
type = node;
|
|
schema = sch;
|
|
|
|
seclabelPage = new ctlSeclabelPanel(nbNotebook);
|
|
|
|
lstMembers->CreateColumns(0, _("Member"), _("Data type"), _("Collation"), -1);
|
|
lstLabels->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, GetClientSize().GetWidth());
|
|
|
|
cbStorage->Append(wxT("PLAIN"));
|
|
cbStorage->Append(wxT("MAIN"));
|
|
cbStorage->Append(wxT("EXTERNAL"));
|
|
cbStorage->Append(wxT("EXTENDED"));
|
|
|
|
queriesToBeSplitted = false;
|
|
|
|
/* Type Privileges */
|
|
securityChanged = false;
|
|
if (node)
|
|
connection = node->GetConnection();
|
|
securityPage = new ctlSecurityPanel(nbNotebook, wxT("USAGE"), "U", frame->GetImageList());
|
|
if (connection && connection->BackendMinimumVersion(9, 2) && (!node || node->CanCreate()))
|
|
{
|
|
// Fetch Groups Information
|
|
pgSet *setGrp = connection->ExecuteSet(wxT("SELECT groname FROM pg_group ORDER BY groname"));
|
|
|
|
if (setGrp)
|
|
{
|
|
while (!setGrp->Eof())
|
|
{
|
|
groups.Add(setGrp->GetVal(0));
|
|
setGrp->MoveNext();
|
|
}
|
|
delete setGrp;
|
|
}
|
|
|
|
if (node)
|
|
{
|
|
wxString strAcl = node->GetAcl();
|
|
if (!strAcl.IsEmpty())
|
|
{
|
|
wxArrayString aclArray;
|
|
strAcl = strAcl.Mid(1, strAcl.Length() - 2);
|
|
getArrayFromCommaSeparatedList(strAcl, aclArray);
|
|
wxString roleName;
|
|
for (unsigned int index = 0; index < aclArray.Count(); index++)
|
|
{
|
|
wxString strCurrAcl = aclArray[index];
|
|
|
|
/*
|
|
* In rare case, we can have ',' (comma) in the user name.
|
|
* But, we need to handle them also
|
|
*/
|
|
if (strCurrAcl.Find(wxChar('=')) == wxNOT_FOUND)
|
|
{
|
|
// Check it is start of the ACL
|
|
if (strCurrAcl[0U] == (wxChar)'"')
|
|
roleName = strCurrAcl + wxT(",");
|
|
continue;
|
|
}
|
|
else
|
|
strCurrAcl = roleName + strCurrAcl;
|
|
|
|
if (strCurrAcl[0U] == (wxChar)'"')
|
|
strCurrAcl = strCurrAcl.Mid(1, strCurrAcl.Length() - 1);
|
|
roleName = strCurrAcl.BeforeLast('=');
|
|
|
|
wxString value = strCurrAcl.Mid(roleName.Length() + 1).BeforeLast('/');
|
|
|
|
int icon = userFactory.GetIconId();
|
|
|
|
if (roleName.Left(6).IsSameAs(wxT("group "), false))
|
|
{
|
|
icon = groupFactory.GetIconId();
|
|
roleName = wxT("group ") + qtStrip(roleName.Mid(6));
|
|
}
|
|
else if (roleName.IsEmpty())
|
|
{
|
|
icon = PGICON_PUBLIC;
|
|
roleName = wxT("public");
|
|
}
|
|
else
|
|
{
|
|
roleName = qtStrip(roleName);
|
|
for (unsigned int index = 0; index < groups.Count(); index++)
|
|
if (roleName == groups[index])
|
|
{
|
|
roleName = wxT("group ") + roleName;
|
|
icon = groupFactory.GetIconId();
|
|
break;
|
|
}
|
|
}
|
|
|
|
securityPage->lbPrivileges->AppendItem(icon, roleName, value);
|
|
currentAcl.Add(roleName + wxT("=") + value);
|
|
|
|
// Reset roleName
|
|
roleName.Empty();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
securityPage->Disable();
|
|
|
|
}
|
|
|
|
|
|
#ifdef __WXMAC__
|
|
void dlgType::OnChangeSize(wxSizeEvent &ev)
|
|
{
|
|
securityPage->lbPrivileges->SetSize(wxDefaultCoord, wxDefaultCoord,
|
|
ev.GetSize().GetWidth(), ev.GetSize().GetHeight() - 550);
|
|
if (GetAutoLayout())
|
|
{
|
|
Layout();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
void dlgType::OnChangeMember(wxCommandEvent &ev)
|
|
{
|
|
wxString name = txtMembername->GetValue().Strip(wxString::both);
|
|
|
|
btnAddMember->Enable(
|
|
((type && connection->BackendMinimumVersion(9, 1)) || !type)
|
|
&& !name.IsEmpty()
|
|
&& lstMembers->FindItem(-1, name, false) == -1
|
|
&& cbDatatype->GetGuessedSelection() >= 0);
|
|
btnChangeMember->Enable(
|
|
lstMembers->FindItem(-1, name, false) == lstMembers->GetFirstSelected()
|
|
|| lstMembers->FindItem(-1, name, false) == -1);
|
|
}
|
|
|
|
void dlgType::showDefinition(int panel)
|
|
{
|
|
pnlDefinitionExtern->Show(false);
|
|
pnlDefinitionComposite->Show(false);
|
|
pnlDefinitionEnum->Show(false);
|
|
pnlDefinitionRange->Show(false);
|
|
|
|
switch (panel)
|
|
{
|
|
case 0:
|
|
pnlDefinitionComposite->Show(true);
|
|
break;
|
|
case 1:
|
|
pnlDefinitionEnum->Show(true);
|
|
break;
|
|
case 2:
|
|
pnlDefinitionExtern->Show(true);
|
|
break;
|
|
case 3:
|
|
pnlDefinitionRange->Show(true);
|
|
break;
|
|
}
|
|
|
|
pnlDefinitionComposite->GetParent()->Layout();
|
|
// we don't need to call GetParent()->Layout() for all four panels
|
|
// because they all share the same parent
|
|
}
|
|
|
|
|
|
void dlgType::OnTypeChange(wxCommandEvent &ev)
|
|
{
|
|
showDefinition(rdbType->GetSelection());
|
|
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
pgObject *dlgType::GetObject()
|
|
{
|
|
return type;
|
|
}
|
|
|
|
|
|
int dlgType::Go(bool modal)
|
|
{
|
|
pgSet *set;
|
|
|
|
cbRngCollation->Enable(false);
|
|
if (connection->BackendMinimumVersion(9, 2))
|
|
{
|
|
securityPage->SetConnection(connection);
|
|
|
|
if (securityPage->cbGroups)
|
|
{
|
|
// Fetch Groups Information
|
|
for ( unsigned int index = 0; index < groups.Count();)
|
|
securityPage->cbGroups->Append(wxT("group ") + groups[index++]);
|
|
|
|
// Fetch Users Information
|
|
if (settings->GetShowUsersForPrivileges())
|
|
{
|
|
securityPage->stGroup->SetLabel(_("Group/User"));
|
|
dlgProperty::AddUsers(securityPage->cbGroups);
|
|
}
|
|
}
|
|
securityPage->lbPrivileges->GetParent()->Layout();
|
|
|
|
// Load the range combox (the 403 opcmethod is btree)
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT DISTINCT typ.typname\n")
|
|
wxT(" FROM pg_opclass opc\n")
|
|
wxT(" JOIN pg_type typ ON opc.opcintype=typ.oid\n")
|
|
wxT(" WHERE opc.opcmethod=403\n")
|
|
wxT(" ORDER BY typname"));
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString name = qtTypeIdent(set->GetVal(wxT("typname")));
|
|
cbSubtype->Append(name);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
cbSubtype->SetSelection(0);
|
|
}
|
|
else
|
|
{
|
|
rdbType->Enable(3, false);
|
|
}
|
|
|
|
if (connection->BackendMinimumVersion(9, 1))
|
|
{
|
|
seclabelPage->SetConnection(connection);
|
|
seclabelPage->SetObject(type);
|
|
this->Connect(EVT_SECLABELPANEL_CHANGE, wxCommandEventHandler(dlgType::OnChange));
|
|
}
|
|
else
|
|
seclabelPage->Disable();
|
|
|
|
FillDatatype(cbDatatype, cbElement);
|
|
|
|
if (connection->BackendMinimumVersion(9, 1))
|
|
{
|
|
// fill collation combobox
|
|
cbCollation->Append(wxEmptyString);
|
|
cbRngCollation->Append(wxEmptyString);
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT nspname, collname\n")
|
|
wxT(" FROM pg_collation c, pg_namespace n\n")
|
|
wxT(" WHERE c.collnamespace=n.oid\n")
|
|
wxT(" ORDER BY nspname, collname"));
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString name = qtIdent(set->GetVal(wxT("nspname"))) + wxT(".") + qtIdent(set->GetVal(wxT("collname")));
|
|
cbCollation->Append(name);
|
|
cbRngCollation->Append(name);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
cbCollation->SetSelection(0);
|
|
cbRngCollation->SetSelection(0);
|
|
}
|
|
|
|
if (type)
|
|
{
|
|
// Edit Mode
|
|
cbSchema->Enable(connection->BackendMinimumVersion(8, 1));
|
|
txtName->Enable(connection->BackendMinimumVersion(8, 4));
|
|
rdbType->SetSelection(type->GetTypeClass());
|
|
rdbType->Disable();
|
|
|
|
showDefinition(type->GetTypeClass());
|
|
|
|
cbInput->Append(type->GetInputFunction());
|
|
cbInput->SetSelection(0);
|
|
cbInput->Disable();
|
|
cbOutput->Append(type->GetOutputFunction());
|
|
cbOutput->SetSelection(0);
|
|
cbOutput->Disable();
|
|
cbReceive->Append(type->GetReceiveFunction());
|
|
cbReceive->SetSelection(0);
|
|
cbReceive->Disable();
|
|
cbSend->Append(type->GetSendFunction());
|
|
cbSend->SetSelection(0);
|
|
cbSend->Disable();
|
|
cbTypmodin->Append(type->GetTypmodinFunction());
|
|
cbTypmodin->SetSelection(0);
|
|
cbTypmodin->Disable();
|
|
cbTypmodout->Append(type->GetTypmodoutFunction());
|
|
cbTypmodout->SetSelection(0);
|
|
cbTypmodout->Disable();
|
|
cbAnalyze->Append(type->GetAnalyzeFunction());
|
|
cbAnalyze->SetSelection(0);
|
|
cbAnalyze->Disable();
|
|
cbCategory->Append(catGetText(type->GetCategory()));
|
|
cbCategory->SetSelection(0);
|
|
cbCategory->Disable();
|
|
chkPrefered->SetValue(type->GetPrefered());
|
|
chkPrefered->Disable();
|
|
|
|
chkVariable->SetValue(type->GetInternalLength() < 0);
|
|
chkVariable->Disable();
|
|
if (type->GetInternalLength() > 0)
|
|
txtIntLength->SetValue(NumToStr(type->GetInternalLength()));
|
|
txtIntLength->Disable();
|
|
txtDefault->SetValue(type->GetDefault());
|
|
txtDefault->Disable();
|
|
cbElement->Append(type->GetElement());
|
|
cbElement->SetSelection(0);
|
|
cbElement->Disable();
|
|
txtDelimiter->SetValue(type->GetDelimiter());
|
|
txtDelimiter->Disable();
|
|
chkByValue->SetValue(type->GetPassedByValue());
|
|
chkByValue->Disable();
|
|
cbAlignment->SetValue(type->GetAlignment());
|
|
cbAlignment->Disable();
|
|
cbStorage->SetValue(type->GetStorage());
|
|
cbStorage->Disable();
|
|
chkCollatable->SetValue(type->GetCollatable());
|
|
chkCollatable->Disable();
|
|
|
|
bool changeok = connection->BackendMinimumVersion(9, 1);
|
|
txtMembername->Enable(changeok);
|
|
cbCollation->Enable(changeok);
|
|
btnAddMember->Enable(false);
|
|
btnChangeMember->Enable(false);
|
|
btnRemoveMember->Enable(false);
|
|
|
|
txtLabel->Enable(connection->BackendMinimumVersion(9, 1));
|
|
btnAddBeforeLabel->Enable(connection->BackendMinimumVersion(9, 1));
|
|
btnAddAfterLabel->Enable(connection->BackendMinimumVersion(9, 1));
|
|
btnRemoveLabel->Disable();
|
|
|
|
wxArrayString elements = type->GetTypesArray();
|
|
wxString fullType, typeName, typeLength, typePrecision;
|
|
size_t pos;
|
|
size_t i;
|
|
for (i = 0 ; i < elements.GetCount() ; i += 3)
|
|
{
|
|
lstMembers->AppendItem(0, elements.Item(i), elements.Item(i + 1), elements.Item(i + 2));
|
|
|
|
fullType = elements.Item(i + 1);
|
|
typeName = fullType;
|
|
typeLength = wxEmptyString;
|
|
typePrecision = wxEmptyString;
|
|
|
|
if (fullType.Find(wxT("(")) > 0)
|
|
{
|
|
// there is at least a length
|
|
typeName = fullType.BeforeFirst('(');
|
|
if (fullType.Find(wxT(",")) > 0)
|
|
{
|
|
// there is also a precision
|
|
typeLength = fullType.AfterFirst('(').BeforeFirst(',');
|
|
typePrecision = fullType.AfterFirst(',').BeforeFirst(')');
|
|
}
|
|
else
|
|
typeLength = fullType.AfterFirst('(').BeforeFirst(')');
|
|
}
|
|
|
|
for (pos = 0; pos < cbDatatype->GetCount() - 1; pos++)
|
|
{
|
|
if (cbDatatype->GetString(pos) == typeName)
|
|
{
|
|
memberTypes.Add(GetTypeInfo(pos));
|
|
break;
|
|
}
|
|
}
|
|
memberLengths.Add(typeLength);
|
|
memberPrecisions.Add(typePrecision);
|
|
memberCollations.Add(elements.Item(i + 2));
|
|
memberOriginalNames.Add(elements.Item(i));
|
|
}
|
|
|
|
cbDatatype->Enable(changeok);
|
|
txtLength->Enable(changeok);
|
|
|
|
// Load the enum labels
|
|
elements = type->GetLabelArray();
|
|
for (i = 0 ; i < elements.GetCount() ; i++)
|
|
lstLabels->AppendItem(0, elements.Item(i));
|
|
|
|
// Load the RANGE informations
|
|
cbSubtype->SetValue(type->GetSubtypeFunctionStr());
|
|
cbSubtype->Disable();
|
|
cbSubtypeOpclass->Append(type->GetSubtypeOpClassFunctionStr());
|
|
cbSubtypeOpclass->SetSelection(0);
|
|
cbSubtypeOpclass->Disable();
|
|
cbRngCollation->Append(type->GetCollationFunctionStr());
|
|
cbRngCollation->SetSelection(0);
|
|
cbRngCollation->Disable();
|
|
cbCanonical->Append(type->GetCanonical());
|
|
cbCanonical->SetSelection(0);
|
|
cbCanonical->Disable();
|
|
cbSubtypeDiff->Append(type->GetSubtypeDiff());
|
|
cbSubtypeDiff->SetSelection(0);
|
|
cbSubtypeDiff->Disable();
|
|
|
|
if (!connection->BackendMinimumVersion(7, 5))
|
|
cbOwner->Disable();
|
|
}
|
|
else
|
|
{
|
|
// Create mode
|
|
cbOwner->Disable();
|
|
|
|
bool hasSendRcv = connection->BackendMinimumVersion(7, 4);
|
|
bool hasTypmod = connection->BackendMinimumVersion(8, 3);
|
|
|
|
cbCategory->Enable(connection->BackendMinimumVersion(8, 4));
|
|
chkPrefered->Enable(connection->BackendMinimumVersion(8, 4));
|
|
|
|
if (hasSendRcv)
|
|
{
|
|
cbReceive->Append(wxEmptyString);
|
|
cbSend->Append(wxEmptyString);
|
|
cbAnalyze->Append(wxEmptyString);
|
|
}
|
|
else
|
|
{
|
|
cbReceive->Disable();
|
|
cbSend->Disable();
|
|
cbAnalyze->Disable();
|
|
}
|
|
|
|
if (hasTypmod)
|
|
{
|
|
cbTypmodin->Append(wxEmptyString);
|
|
cbTypmodout->Append(wxEmptyString);
|
|
}
|
|
else
|
|
{
|
|
cbTypmodin->Disable();
|
|
cbTypmodout->Disable();
|
|
}
|
|
|
|
if (!connection->BackendMinimumVersion(8, 3))
|
|
rdbType->Enable(TYPE_ENUM, false);
|
|
|
|
chkCollatable->Enable(connection->BackendMinimumVersion(9, 1));
|
|
cbCollation->Enable(connection->BackendMinimumVersion(9, 1));
|
|
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT proname, nspname\n")
|
|
wxT(" FROM (\n")
|
|
wxT(" SELECT proname, nspname, max(proargtypes[0]) AS arg0, max(proargtypes[1]) AS arg1\n")
|
|
wxT(" FROM pg_proc p\n")
|
|
wxT(" JOIN pg_namespace n ON n.oid=pronamespace\n")
|
|
wxT(" GROUP BY proname, nspname\n")
|
|
wxT(" HAVING count(proname) = 1 ) AS uniquefunc\n")
|
|
wxT(" WHERE arg0 <> 0 AND arg1 = 0"));
|
|
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString pn = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
|
|
|
|
cbInput->Append(pn);
|
|
cbOutput->Append(pn);
|
|
if (hasSendRcv)
|
|
{
|
|
cbReceive->Append(pn);
|
|
cbSend->Append(pn);
|
|
cbAnalyze->Append(pn);
|
|
}
|
|
if (hasTypmod)
|
|
{
|
|
cbTypmodin->Append(pn);
|
|
cbTypmodout->Append(pn);
|
|
}
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
|
|
if (hasTypmod)
|
|
{
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT proname, nspname\n")
|
|
wxT(" FROM pg_proc p\n")
|
|
wxT(" JOIN pg_namespace n ON n.oid=pronamespace\n")
|
|
wxT(" WHERE prorettype=(SELECT oid FROM pg_type WHERE typname='int4')")
|
|
wxT(" AND proargtypes[0]=(SELECT oid FROM pg_type WHERE typname='_cstring')")
|
|
wxT(" AND proargtypes[1] IS NULL")
|
|
wxT(" ORDER BY nspname, proname"));
|
|
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString pn = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
|
|
|
|
cbTypmodin->Append(pn);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT proname, nspname\n")
|
|
wxT(" FROM pg_proc p\n")
|
|
wxT(" JOIN pg_namespace n ON n.oid=pronamespace\n")
|
|
wxT(" WHERE prorettype=(SELECT oid FROM pg_type WHERE typname='cstring')")
|
|
wxT(" AND proargtypes[0]=(SELECT oid FROM pg_type WHERE typname='int4')")
|
|
wxT(" AND proargtypes[1] IS NULL")
|
|
wxT(" ORDER BY nspname, proname"));
|
|
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString pn = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
|
|
|
|
cbTypmodout->Append(pn);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
}
|
|
}
|
|
|
|
txtLength->SetValidator(numericValidator);
|
|
|
|
return dlgTypeProperty::Go(modal);
|
|
}
|
|
|
|
|
|
void dlgType::OnSelChangeTyp(wxCommandEvent &ev)
|
|
{
|
|
txtLength->SetValue(wxEmptyString);
|
|
txtPrecision->SetValue(wxEmptyString);
|
|
cbDatatype->GuessSelection(ev);
|
|
cbCollation->SetValue(wxEmptyString);
|
|
OnSelChangeTypOrLen(ev);
|
|
}
|
|
|
|
|
|
|
|
void dlgType::OnNameChange(wxCommandEvent &ev)
|
|
{
|
|
wxString qry;
|
|
wxString shelltype;
|
|
pgSet *set;
|
|
|
|
cbCanonical->Clear();
|
|
if (!txtName->GetValue().IsEmpty())
|
|
{
|
|
// Grab the shelltype
|
|
qry = wxT("SELECT oid FROM pg_type WHERE typname='") + qtIdent(txtName->GetValue()) + wxT("'");
|
|
set = connection->ExecuteSet(qry);
|
|
if (set)
|
|
{
|
|
if (!set->Eof())
|
|
{
|
|
shelltype = set->GetVal(wxT("oid"));
|
|
}
|
|
delete set;
|
|
}
|
|
|
|
if (!shelltype.IsEmpty())
|
|
{
|
|
// Load the canonical functions
|
|
qry = wxT("SELECT proname, nspname\n")
|
|
wxT(" FROM pg_proc\n")
|
|
wxT(" JOIN pg_namespace n ON n.oid=pronamespace\n")
|
|
wxT(" WHERE prorettype=") + shelltype +
|
|
wxT(" AND proargtypes='") + shelltype + wxT("'\n")
|
|
wxT(" ORDER BY proname\n");
|
|
|
|
cbCanonical->Append(wxEmptyString);
|
|
set = connection->ExecuteSet(qry);
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString procname = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
|
|
cbCanonical->Append(procname);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
cbCanonical->SetSelection(0);
|
|
}
|
|
}
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnSubtypeChange(wxCommandEvent &ev)
|
|
{
|
|
wxString subtypeoid;
|
|
cbSubtypeOpclass->Clear();
|
|
cbSubtypeDiff->Clear();
|
|
|
|
if (!cbSubtype->GetValue().IsEmpty())
|
|
{
|
|
cbSubtypeOpclass->Append(wxEmptyString);
|
|
pgSet *set = connection->ExecuteSet(
|
|
wxT("SELECT opc.opcname, opc.opcintype\n")
|
|
wxT(" FROM pg_opclass opc\n")
|
|
wxT(" JOIN pg_type typ ON opc.opcintype=typ.oid ")
|
|
wxT(" AND typ.typname='") + cbSubtype->GetValue() + wxT("'\n")
|
|
wxT(" WHERE opc.opcmethod=403\n")
|
|
wxT(" ORDER BY opcname"));
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString name = qtIdent(set->GetVal(wxT("opcname")));
|
|
subtypeoid = set->GetVal(wxT("opcintype"));
|
|
cbSubtypeOpclass->Append(name);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
cbSubtypeOpclass->SetSelection(0);
|
|
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT typcollation FROM pg_type WHERE typname='") + cbSubtype->GetValue() + wxT("'\n"));
|
|
if (set)
|
|
{
|
|
if (!set->Eof())
|
|
{
|
|
cbRngCollation->Enable(set->GetLong(wxT("typcollation")) > 0);
|
|
}
|
|
delete set;
|
|
}
|
|
else
|
|
{
|
|
cbRngCollation->Enable(false);
|
|
}
|
|
|
|
// Load the subtypediff functions (701 is double precision type)
|
|
|
|
set = connection->ExecuteSet(
|
|
wxT("SELECT proname, nspname\n")
|
|
wxT(" FROM pg_proc\n")
|
|
wxT(" JOIN pg_namespace n ON n.oid=pronamespace\n")
|
|
wxT(" WHERE prorettype=701 ")
|
|
wxT(" AND proargtypes='") + subtypeoid + wxT(" ") + subtypeoid + wxT("'\n")
|
|
wxT(" ORDER BY proname\n"));
|
|
if (set)
|
|
{
|
|
while (!set->Eof())
|
|
{
|
|
wxString procname = database->GetSchemaPrefix(set->GetVal(wxT("nspname"))) + set->GetVal(wxT("proname"));
|
|
cbSubtypeDiff->Append(procname);
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void dlgType::OnSelChangeTypOrLen(wxCommandEvent &ev)
|
|
{
|
|
if ((type && connection->BackendMinimumVersion(9, 1)) || !type)
|
|
{
|
|
CheckLenEnable();
|
|
txtLength->Enable(isVarLen);
|
|
txtPrecision->Enable(isVarPrec);
|
|
cbCollation->Enable(connection->BackendMinimumVersion(9, 1));
|
|
CheckChange();
|
|
OnChangeMember(ev);
|
|
}
|
|
}
|
|
|
|
|
|
void dlgType::CheckChange()
|
|
{
|
|
bool enable = true;
|
|
|
|
if (rdbType->GetSelection() == TYPE_COMPOSITE)
|
|
{
|
|
CheckValid(enable, lstMembers->GetItemCount() > 1, _("Please specify at least two members."));
|
|
}
|
|
else if (rdbType->GetSelection() == TYPE_ENUM)
|
|
{
|
|
CheckValid(enable, lstLabels->GetItemCount() >= 1, _("Please specify at least one label."));
|
|
}
|
|
else if (rdbType->GetSelection() == TYPE_EXTERNAL)
|
|
{
|
|
txtLength->Enable(!chkVariable->GetValue());
|
|
CheckValid(enable, cbInput->GetCurrentSelection() >= 0, _("Please specify input conversion function."));
|
|
CheckValid(enable, cbOutput->GetCurrentSelection() >= 0, _("Please specify output conversion function."));
|
|
CheckValid(enable, chkVariable->GetValue() || StrToLong(txtLength->GetValue()) > 0, _("Please specify internal storage length."));
|
|
}
|
|
else
|
|
{
|
|
CheckValid(enable, cbSubtype->GetCurrentSelection() >= 0, _("Please specify subtype function."));
|
|
}
|
|
|
|
if (type)
|
|
{
|
|
enable = enable && (GetName() != type->GetName()
|
|
|| txtComment->GetValue() != type->GetComment()
|
|
|| cbSchema->GetValue() != type->GetSchema()->GetName()
|
|
|| cbOwner->GetValue() != type->GetOwner()
|
|
|| (rdbType->GetSelection() == TYPE_COMPOSITE && GetSqlForTypes() != wxEmptyString)
|
|
|| (GetSql().Length() > 0 && connection->BackendMinimumVersion(9, 1)));
|
|
if (seclabelPage && connection->BackendMinimumVersion(9, 1))
|
|
enable = enable || !(seclabelPage->GetSqlForSecLabels().IsEmpty());
|
|
}
|
|
else
|
|
{
|
|
wxString name = GetName();
|
|
|
|
CheckValid(enable, !name.IsEmpty(), _("Please specify name."));
|
|
CheckValid(enable, !name.StartsWith(wxT("_")), _("Name may not start with '_'."));
|
|
}
|
|
|
|
EnableOK(enable || securityChanged);
|
|
}
|
|
|
|
|
|
void dlgType::OnMemberSelChange(wxListEvent &ev)
|
|
{
|
|
long pos = lstMembers->GetSelection();
|
|
if (pos >= 0)
|
|
{
|
|
txtMembername->SetValue(lstMembers->GetText(pos));
|
|
cbDatatype->SetValue(memberTypes.Item(pos).AfterFirst(':'));
|
|
txtLength->SetValue(memberLengths.Item(pos));
|
|
txtLength->Enable(((type && connection->BackendMinimumVersion(9, 1)) || !type) && !txtLength->GetValue().IsEmpty());
|
|
txtPrecision->SetValue(memberPrecisions.Item(pos));
|
|
txtPrecision->Enable(((type && connection->BackendMinimumVersion(9, 1)) || !type) && !txtPrecision->GetValue().IsEmpty());
|
|
cbCollation->SetValue(memberCollations.Item(pos));
|
|
cbCollation->Enable(connection->BackendMinimumVersion(9, 1));
|
|
btnChangeMember->Enable((type && connection->BackendMinimumVersion(9, 1)) || !type);
|
|
btnRemoveMember->Enable((type && connection->BackendMinimumVersion(9, 1)) || !type);
|
|
}
|
|
}
|
|
|
|
|
|
void dlgType::OnMemberAdd(wxCommandEvent &ev)
|
|
{
|
|
wxString name = txtMembername->GetValue().Strip(wxString::both);
|
|
wxString type = cbDatatype->GetValue();
|
|
wxString length = wxEmptyString;
|
|
wxString precision = wxEmptyString;
|
|
wxString collation = wxEmptyString;
|
|
|
|
if (txtLength->GetValue() != wxT("") && txtLength->IsEnabled())
|
|
length = txtLength->GetValue();
|
|
if (txtPrecision->GetValue() != wxT("") && txtPrecision->IsEnabled())
|
|
precision = txtPrecision->GetValue();
|
|
if (cbCollation->GetValue() != wxT("") && cbCollation->IsEnabled())
|
|
collation = cbCollation->GetValue();
|
|
|
|
if (!length.IsEmpty())
|
|
{
|
|
type += wxT("(") + length;
|
|
if (!precision.IsEmpty())
|
|
type += wxT(",") + precision;
|
|
type += wxT(")");
|
|
}
|
|
|
|
if (!name.IsEmpty())
|
|
{
|
|
size_t pos = lstMembers->GetItemCount();
|
|
lstMembers->InsertItem(pos, name, 0);
|
|
lstMembers->SetItem(pos, 1, type);
|
|
lstMembers->SetItem(pos, 2, collation);
|
|
memberTypes.Add(GetTypeInfo(cbDatatype->GetGuessedSelection()));
|
|
memberLengths.Add(length);
|
|
memberPrecisions.Add(precision);
|
|
memberCollations.Add(collation);
|
|
memberOriginalNames.Add(wxEmptyString);
|
|
}
|
|
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnMemberChange(wxCommandEvent &ev)
|
|
{
|
|
wxString name = txtMembername->GetValue().Strip(wxString::both);
|
|
wxString type = cbDatatype->GetValue();
|
|
wxString length = wxEmptyString;
|
|
wxString precision = wxEmptyString;
|
|
wxString collation = wxEmptyString;
|
|
|
|
if (txtLength->GetValue() != wxT("") && txtLength->IsEnabled())
|
|
length = txtLength->GetValue();
|
|
if (txtPrecision->GetValue() != wxT("") && txtPrecision->IsEnabled())
|
|
precision = txtPrecision->GetValue();
|
|
if (cbCollation->GetValue() != wxT("") && cbCollation->IsEnabled())
|
|
collation = cbCollation->GetValue();
|
|
|
|
if (!length.IsEmpty())
|
|
{
|
|
type += wxT("(") + length;
|
|
if (!precision.IsEmpty())
|
|
type += wxT(",") + precision;
|
|
type += wxT(")");
|
|
}
|
|
|
|
if (!name.IsEmpty())
|
|
{
|
|
long pos = lstMembers->GetFirstSelected();
|
|
if (pos >= 0)
|
|
{
|
|
lstMembers->SetItem(pos, 0, name);
|
|
lstMembers->SetItem(pos, 1, type);
|
|
lstMembers->SetItem(pos, 2, collation);
|
|
memberTypes.Insert(GetTypeInfo(cbDatatype->GetGuessedSelection()), pos);
|
|
memberLengths.Insert(length, pos);
|
|
memberPrecisions.Insert(precision, pos);
|
|
memberCollations.Insert(collation, pos);
|
|
memberTypes.RemoveAt(pos + 1);
|
|
memberLengths.RemoveAt(pos + 1);
|
|
memberPrecisions.RemoveAt(pos + 1);
|
|
memberCollations.RemoveAt(pos + 1);
|
|
}
|
|
}
|
|
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnMemberRemove(wxCommandEvent &ev)
|
|
{
|
|
long pos = lstMembers->GetSelection();
|
|
|
|
if (pos >= 0)
|
|
{
|
|
lstMembers->DeleteItem(pos);
|
|
memberTypes.RemoveAt(pos);
|
|
memberLengths.RemoveAt(pos);
|
|
memberPrecisions.RemoveAt(pos);
|
|
memberCollations.RemoveAt(pos);
|
|
memberOriginalNames.RemoveAt(pos);
|
|
}
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnLabelSelChange(wxListEvent &ev)
|
|
{
|
|
long pos = lstLabels->GetSelection();
|
|
if (pos >= 0)
|
|
{
|
|
txtLabel->SetValue(lstLabels->GetText(pos));
|
|
}
|
|
}
|
|
|
|
|
|
void dlgType::OnLabelAddBefore(wxCommandEvent &ev)
|
|
{
|
|
wxString label = txtLabel->GetValue().Strip(wxString::both);
|
|
|
|
if (!label.IsEmpty())
|
|
{
|
|
long pos = lstLabels->FindItem(-1, label);
|
|
if (pos < 0)
|
|
{
|
|
if (lstLabels->GetFirstSelected() >= 0)
|
|
pos = lstLabels->GetFirstSelected();
|
|
else
|
|
pos = 0;
|
|
lstLabels->InsertItem(pos, label, 0);
|
|
}
|
|
}
|
|
txtLabel->SetValue(wxEmptyString);
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnLabelAddAfter(wxCommandEvent &ev)
|
|
{
|
|
wxString label = txtLabel->GetValue().Strip(wxString::both);
|
|
|
|
if (!label.IsEmpty())
|
|
{
|
|
long pos = lstLabels->FindItem(-1, label);
|
|
if (pos < 0)
|
|
{
|
|
if (lstLabels->GetFirstSelected() >= 0)
|
|
pos = lstLabels->GetFirstSelected() + 1;
|
|
else
|
|
pos = lstLabels->GetItemCount();
|
|
lstLabels->InsertItem(pos, label, 0);
|
|
}
|
|
}
|
|
txtLabel->SetValue(wxEmptyString);
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnLabelRemove(wxCommandEvent &ev)
|
|
{
|
|
long pos = lstLabels->GetSelection();
|
|
|
|
if (pos >= 0)
|
|
lstLabels->DeleteItem(pos);
|
|
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
pgObject *dlgType::CreateObject(pgCollection *collection)
|
|
{
|
|
pgObject *obj = 0; //pgType::ReadObjects(collection, 0, wxT("\n WHERE usename=") + qtDbString(name));
|
|
return obj;
|
|
}
|
|
|
|
|
|
wxString dlgType::GetSql()
|
|
{
|
|
wxString sql, direction, objname;
|
|
size_t existingitems_index, listitems_index, offset;
|
|
|
|
if (type)
|
|
{
|
|
// Edit Mode
|
|
objname = schema->GetQuotedPrefix() + qtIdent(GetName());
|
|
AppendNameChange(sql, wxT("TYPE ") + type->GetQuotedFullIdentifier());
|
|
AppendOwnerChange(sql, wxT("TYPE ") + objname);
|
|
|
|
sql += GetSqlForTypes();
|
|
if (rdbType->GetSelection() == TYPE_ENUM && connection->BackendMinimumVersion(9, 1))
|
|
{
|
|
wxArrayString elements = type->GetLabelArray();
|
|
existingitems_index = 0;
|
|
for (listitems_index = 0 ; listitems_index < (size_t)lstLabels->GetItemCount() ; listitems_index++)
|
|
{
|
|
if (existingitems_index >= elements.GetCount() || lstLabels->GetItemText(listitems_index) != elements.Item(existingitems_index))
|
|
{
|
|
queriesToBeSplitted = true;
|
|
if (listitems_index == 0)
|
|
{
|
|
direction = wxT("BEFORE");
|
|
offset = 0;
|
|
}
|
|
else
|
|
{
|
|
direction = wxT("AFTER");
|
|
offset = -1;
|
|
}
|
|
|
|
sql += wxT("ALTER TYPE ") + objname
|
|
+ wxT("\n ADD VALUE ") + connection->qtDbString(lstLabels->GetItemText(listitems_index))
|
|
+ wxT(" ") + direction + wxT(" ")
|
|
+ connection->qtDbString(elements.Item(existingitems_index + offset))
|
|
+ wxT(";\n");
|
|
}
|
|
else
|
|
existingitems_index++;
|
|
}
|
|
}
|
|
AppendSchemaChange(sql, wxT("TYPE ") + objname);
|
|
}
|
|
else
|
|
{
|
|
// Create Mode
|
|
sql = wxT("CREATE TYPE ") + schema->GetQuotedPrefix() + qtIdent(GetName());
|
|
|
|
if (rdbType->GetSelection() == TYPE_COMPOSITE)
|
|
{
|
|
sql += wxT(" AS\n (");
|
|
|
|
int i;
|
|
for (i = 0 ; i < lstMembers->GetItemCount() ; i++)
|
|
{
|
|
if (i)
|
|
sql += wxT(",\n ");
|
|
sql += qtIdent(lstMembers->GetItemText(i)) + wxT(" ")
|
|
+ GetFullTypeName(i);
|
|
}
|
|
}
|
|
else if (rdbType->GetSelection() == TYPE_ENUM)
|
|
{
|
|
sql += wxT(" AS ENUM\n (");
|
|
|
|
int i;
|
|
for (i = 0 ; i < lstLabels->GetItemCount() ; i++)
|
|
{
|
|
if (i)
|
|
sql += wxT(",\n ");
|
|
sql += connection->qtDbString(lstLabels->GetItemText(i));
|
|
}
|
|
}
|
|
else if (rdbType->GetSelection() == TYPE_EXTERNAL)
|
|
{
|
|
sql += wxT("\n (INPUT=");
|
|
AppendQuoted(sql, cbInput->GetValue());
|
|
sql += wxT(", OUTPUT=");
|
|
AppendQuoted(sql, cbOutput->GetValue());
|
|
|
|
if (connection->BackendMinimumVersion(7, 4))
|
|
{
|
|
if (cbReceive->GetCurrentSelection() > 0 || cbSend->GetCurrentSelection() > 0)
|
|
{
|
|
if (cbReceive->GetCurrentSelection() > 0)
|
|
{
|
|
sql += wxT(",\n RECEIVE=");
|
|
AppendQuoted(sql, cbReceive->GetValue());
|
|
if (cbSend->GetCurrentSelection() > 0)
|
|
{
|
|
sql += wxT(", SEND=");
|
|
AppendQuoted(sql, cbSend->GetValue());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sql += wxT(",\n SEND=");
|
|
AppendQuoted(sql, cbSend->GetValue());
|
|
}
|
|
}
|
|
if (cbAnalyze->GetCurrentSelection() > 0)
|
|
{
|
|
sql += wxT(",\n ANALYZE=");
|
|
AppendQuoted(sql, cbAnalyze->GetValue());
|
|
}
|
|
|
|
}
|
|
if (connection->BackendMinimumVersion(8, 3))
|
|
{
|
|
if (cbTypmodin->GetCurrentSelection() > 0 || cbTypmodout->GetCurrentSelection() > 0)
|
|
{
|
|
if (cbTypmodin->GetCurrentSelection() > 0)
|
|
{
|
|
sql += wxT(",\n TYPMOD_IN=");
|
|
AppendQuoted(sql, cbTypmodin->GetValue());
|
|
if (cbTypmodout->GetCurrentSelection() > 0)
|
|
{
|
|
sql += wxT(", TYPMOD_OUT=");
|
|
AppendQuoted(sql, cbTypmodout->GetValue());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sql += wxT(",\n TYPMOD_OUT=");
|
|
AppendQuoted(sql, cbTypmodout->GetValue());
|
|
}
|
|
}
|
|
|
|
}
|
|
if (connection->BackendMinimumVersion(8, 4))
|
|
{
|
|
sql += wxT(",\n CATEGORY=") + qtDbString(cbCategory->GetValue());
|
|
if (chkPrefered->GetValue())
|
|
sql += wxT(",\n PREFERRED=true");
|
|
}
|
|
sql += wxT(",\n INTERNALLENGTH=");
|
|
if (chkVariable->GetValue())
|
|
sql += wxT("VARIABLE");
|
|
else
|
|
sql += txtLength->GetValue();
|
|
AppendIfFilled(sql, wxT(",\n DEFAULT="), txtDefault->GetValue());
|
|
if (!cbElement->GetValue().IsEmpty())
|
|
{
|
|
sql += wxT(",\n ELEMENT=");
|
|
AppendQuoted(sql, cbElement->GetValue());
|
|
AppendIfFilled(sql, wxT(", DELIMITER="), qtDbString(txtDelimiter->GetValue().Strip(wxString::both)));
|
|
}
|
|
if (chkByValue->GetValue())
|
|
sql += wxT(",\n PASSEDBYVALUE");
|
|
AppendIfFilled(sql, wxT(",\n ALIGNMENT="), cbAlignment->GetValue());
|
|
AppendIfFilled(sql, wxT(",\n STORAGE="), cbStorage->GetValue());
|
|
if (connection->BackendMinimumVersion(9, 1) && chkCollatable->GetValue())
|
|
sql += wxT(",\n COLLATABLE=true");
|
|
}
|
|
else
|
|
{
|
|
sql += wxT(" AS RANGE\n (SUBTYPE=");
|
|
AppendQuoted(sql, cbSubtype->GetValue());
|
|
if (!cbSubtypeOpclass->GetValue().IsEmpty())
|
|
{
|
|
sql += wxT(", SUBTYPE_OPCLASS=");
|
|
AppendQuoted(sql, cbSubtypeOpclass->GetValue());
|
|
}
|
|
if (!cbRngCollation->GetValue().IsEmpty())
|
|
{
|
|
sql += wxT(", COLLATION=") + cbRngCollation->GetValue();
|
|
}
|
|
if (!cbCanonical->GetValue().IsEmpty())
|
|
{
|
|
sql += wxT(", CANONICAL=");
|
|
AppendQuoted(sql, cbCanonical->GetValue());
|
|
}
|
|
if (!cbSubtypeDiff->GetValue().IsEmpty())
|
|
{
|
|
sql += wxT(", SUBTYPE_DIFF=");
|
|
AppendQuoted(sql, cbSubtypeDiff->GetValue());
|
|
}
|
|
}
|
|
|
|
sql += wxT(");\n");
|
|
}
|
|
AppendComment(sql, wxT("TYPE ") + qtIdent(cbSchema->GetValue()) + wxT(".") + qtIdent(GetName()), type);
|
|
|
|
if (seclabelPage && connection->BackendMinimumVersion(9, 1))
|
|
sql += seclabelPage->GetSqlForSecLabels(wxT("TYPE"), qtIdent(cbSchema->GetValue()) + wxT(".") + qtIdent(GetName()));
|
|
|
|
// securityPage will exists only for PG 9.2 and later
|
|
if (connection->BackendMinimumVersion(9, 2))
|
|
sql += securityPage->GetGrant(wxT("U"), wxT("TYPE ") + qtIdent(cbSchema->GetValue()) + wxT(".") + qtIdent(GetName()), ¤tAcl);
|
|
return sql;
|
|
}
|
|
|
|
wxString dlgType::GetFullTypeName(int type)
|
|
{
|
|
wxString typname = memberTypes.Item(type).AfterFirst(':');
|
|
|
|
if (!memberLengths.Item(type).IsEmpty())
|
|
{
|
|
typname += wxT("(") + memberLengths.Item(type);
|
|
if (!memberPrecisions.Item(type).IsEmpty())
|
|
typname += wxT(",") + memberPrecisions.Item(type);
|
|
typname += wxT(")");
|
|
}
|
|
if (!memberCollations.Item(type).IsEmpty() && memberCollations.Item(type) != wxT("pg_catalog.\"default\""))
|
|
typname += wxT(" COLLATE ") + memberCollations.Item(type);
|
|
|
|
return typname;
|
|
}
|
|
|
|
wxString dlgType::GetSqlForTypes()
|
|
{
|
|
wxString sql = wxEmptyString;
|
|
wxString objname, old_name, old_type, old_collation, new_name, new_type, new_full_type, new_collation, original_name;
|
|
wxArrayString elements = type->GetTypesArray();
|
|
int newindex;
|
|
unsigned int oldindex = 0;
|
|
int hold = 0;
|
|
objname = schema->GetQuotedPrefix() + qtIdent(GetName());
|
|
|
|
for (newindex = 0 ; newindex < lstMembers->GetItemCount() ; newindex = newindex + 1 - hold)
|
|
{
|
|
// this will decide whether we progress to the next new item,
|
|
// or whether we need to continue checking the old list first
|
|
hold = 0;
|
|
|
|
// these are a copy of the list before any changes
|
|
if (elements.GetCount() >= (oldindex * 3) + 3)
|
|
{
|
|
old_name = elements.Item(oldindex * 3);
|
|
old_type = elements.Item(oldindex * 3 + 1);
|
|
old_collation = elements.Item(oldindex * 3 + 2);
|
|
}
|
|
else
|
|
{
|
|
// we've now used up all the old attributes
|
|
old_name = wxEmptyString;
|
|
old_type = wxEmptyString;
|
|
old_collation = wxEmptyString;
|
|
}
|
|
|
|
// this is the original name of the type before editing
|
|
original_name = memberOriginalNames.Item(newindex);
|
|
|
|
new_name = lstMembers->GetItemText(newindex);
|
|
new_type = memberTypes.Item(newindex).AfterFirst(':');
|
|
new_full_type = GetFullTypeName(newindex);
|
|
new_collation = memberCollations.Item(newindex);
|
|
|
|
if (!original_name.IsEmpty() && original_name == old_name && (new_name != old_name
|
|
|| new_type != old_type || new_collation != old_collation))
|
|
{
|
|
// if this was originally in the list and the name has changed then rename it
|
|
|
|
if (new_name != old_name)
|
|
{
|
|
sql += wxT("ALTER TYPE ") + objname + wxT("\n RENAME ATTRIBUTE ")
|
|
+ qtIdent(original_name) + wxT(" TO ") + qtIdent(new_name) + wxT(";\n");
|
|
}
|
|
|
|
if (new_type != old_type || new_collation != old_collation)
|
|
{
|
|
sql += wxT("ALTER TYPE ") + objname + wxT("\n ALTER ATTRIBUTE ")
|
|
+ qtIdent(new_name);
|
|
|
|
// the syntax for alter attribute requires that we always specify the type
|
|
sql += wxT(" SET DATA TYPE ") + new_type;
|
|
|
|
if (new_collation != old_collation)
|
|
sql += wxT(" COLLATE ") + new_collation;
|
|
|
|
sql += wxT(";\n");
|
|
}
|
|
}
|
|
else if (!original_name.IsEmpty() && original_name != old_name)
|
|
{
|
|
// the old attribute isn't in the new list so drop it
|
|
|
|
// don't move through new list yet
|
|
hold = 1;
|
|
|
|
sql += wxT("ALTER TYPE ") + objname + wxT("\n DROP ATTRIBUTE ")
|
|
+ qtIdent(old_name) + wxT(";\n");
|
|
}
|
|
else if (original_name.IsEmpty())
|
|
{
|
|
if (!old_name.IsEmpty())
|
|
{
|
|
sql += wxT("ALTER TYPE ") + objname + wxT("\n DROP ATTRIBUTE ")
|
|
+ qtIdent(old_name) + wxT(";\n");
|
|
}
|
|
|
|
sql += wxT("ALTER TYPE ") + objname + wxT("\n ADD ATTRIBUTE ")
|
|
+ qtIdent(new_name) + wxT(" ") + new_full_type + wxT(";\n");
|
|
}
|
|
else
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
oldindex++;
|
|
|
|
if (newindex + 1 - hold == lstMembers->GetItemCount() && elements.GetCount() >= (oldindex * 3) + 3)
|
|
{
|
|
// remove remaining old attributes
|
|
for (; elements.GetCount() >= (oldindex * 3) + 3; oldindex++)
|
|
{
|
|
old_name = elements.Item(oldindex * 3);
|
|
old_type = elements.Item(oldindex * 3 + 1);
|
|
old_collation = elements.Item(oldindex * 3 + 2);
|
|
|
|
sql += wxT("ALTER TYPE ") + objname + wxT("\n DROP ATTRIBUTE ")
|
|
+ qtIdent(old_name) + wxT(";\n");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sql;
|
|
}
|
|
|
|
|
|
void dlgType::OnChange(wxCommandEvent &event)
|
|
{
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnAddPriv(wxCommandEvent &ev)
|
|
{
|
|
securityChanged = true;
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
void dlgType::OnDelPriv(wxCommandEvent &ev)
|
|
{
|
|
securityChanged = true;
|
|
CheckChange();
|
|
}
|
|
|
|
|
|
wxString dlgType::catGetText(wxString c)
|
|
{
|
|
if (c == wxT("A"))
|
|
return wxT("Array types");
|
|
if (c == wxT("B"))
|
|
return wxT("Boolean types");
|
|
if (c == wxT("C"))
|
|
return wxT("Composite types");
|
|
if (c == wxT("D"))
|
|
return wxT("Date/time types");
|
|
if (c == wxT("E"))
|
|
return wxT("Enum types");
|
|
if (c == wxT("G"))
|
|
return wxT("Geometric types");
|
|
if (c == wxT("I"))
|
|
return wxT("Network address types");
|
|
if (c == wxT("N"))
|
|
return wxT("Numeric types");
|
|
if (c == wxT("P"))
|
|
return wxT("Pseudo-types");
|
|
if (c == wxT("S"))
|
|
return wxT("String types");
|
|
if (c == wxT("T"))
|
|
return wxT("Timespan types");
|
|
if (c == wxT("U"))
|
|
return wxT("User-defined types");
|
|
if (c == wxT("V"))
|
|
return wxT("Bit-string types");
|
|
if (c == wxT("X"))
|
|
return wxT("unknown type");
|
|
return wxEmptyString;
|
|
}
|
|
|
|
|
|
wxString dlgType::catGetChar(wxString t)
|
|
{
|
|
if (t == wxT("Array types"))
|
|
return wxT("A");
|
|
if (t == wxT("Boolean types"))
|
|
return wxT("B");
|
|
if (t == wxT("Composite types"))
|
|
return wxT("C");
|
|
if (t == wxT("Date/time types"))
|
|
return wxT("D");
|
|
if (t == wxT("Enum types"))
|
|
return wxT("E");
|
|
if (t == wxT("Geometric types"))
|
|
return wxT("G");
|
|
if (t == wxT("Network address types"))
|
|
return wxT("I");
|
|
if (t == wxT("Numeric types"))
|
|
return wxT("N");
|
|
if (t == wxT("Pseudo-types"))
|
|
return wxT("P");
|
|
if (t == wxT("String types"))
|
|
return wxT("S");
|
|
if (t == wxT("Timespan types"))
|
|
return wxT("T");
|
|
if (t == wxT("User-defined types"))
|
|
return wxT("U");
|
|
if (t == wxT("Bit-string types"))
|
|
return wxT("V");
|
|
if (t == wxT("unknown type"))
|
|
return wxT("X");
|
|
return wxEmptyString;
|
|
}
|