mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
826 lines
26 KiB
C++
826 lines
26 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// pgColumn.cpp - Column class
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
|
|
// App headers
|
|
#include "pgAdmin3.h"
|
|
#include "utils/misc.h"
|
|
#include "utils/pgDefs.h"
|
|
#include "schema/pgDatatype.h"
|
|
#include "schema/pgColumn.h"
|
|
|
|
|
|
pgColumn::pgColumn(pgTable *newTable, const wxString &newName)
|
|
: pgTableObject(newTable, columnFactory, newName)
|
|
{
|
|
isFK = false;
|
|
isPK = false;
|
|
isReferenced = -1;
|
|
}
|
|
|
|
pgColumn::~pgColumn()
|
|
{
|
|
}
|
|
|
|
|
|
wxString pgColumn::GetTranslatedMessage(int kindOfMessage) const
|
|
{
|
|
wxString message = wxEmptyString;
|
|
|
|
switch (kindOfMessage)
|
|
{
|
|
case RETRIEVINGDETAILS:
|
|
message = _("Retrieving details on column");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case REFRESHINGDETAILS:
|
|
message = _("Refreshing column");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case GRANTWIZARDTITLE:
|
|
message = _("Privileges for column");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case DROPINCLUDINGDEPS:
|
|
message = wxString::Format(_("Are you sure you wish to drop column \"%s\" including all objects that depend on it?"),
|
|
GetFullIdentifier().c_str());
|
|
break;
|
|
case DROPEXCLUDINGDEPS:
|
|
message = wxString::Format(_("Are you sure you wish to drop column \"%s\"?"),
|
|
GetFullIdentifier().c_str());
|
|
break;
|
|
case DROPCASCADETITLE:
|
|
message = _("Drop column cascaded?");
|
|
break;
|
|
case DROPTITLE:
|
|
message = _("Drop column?");
|
|
break;
|
|
case PROPERTIESREPORT:
|
|
message = _("Column properties report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case PROPERTIES:
|
|
message = _("Column properties");
|
|
break;
|
|
case DDLREPORT:
|
|
message = _("Column DDL report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case DDL:
|
|
message = _("Column DDL");
|
|
break;
|
|
case STATISTICSREPORT:
|
|
message = _("Column statistics report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case OBJSTATISTICS:
|
|
message = _("Column statistics");
|
|
break;
|
|
case DEPENDENCIESREPORT:
|
|
message = _("Column dependencies report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case DEPENDENCIES:
|
|
message = _("Column dependencies");
|
|
break;
|
|
case DEPENDENTSREPORT:
|
|
message = _("Column dependents report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case DEPENDENTS:
|
|
message = _("Column dependents");
|
|
break;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
|
|
bool pgColumn::IsReferenced()
|
|
{
|
|
if (isReferenced < 0)
|
|
{
|
|
isReferenced = (int)StrToLong(GetConnection()->ExecuteScalar(
|
|
wxT("SELECT COUNT(1) FROM pg_depend dep\n")
|
|
wxT(" JOIN pg_class cl ON dep.classid=cl.oid AND relname='pg_rewrite'\n")
|
|
wxT(" WHERE refobjid=") + GetTableOidStr()
|
|
+ wxT(" AND refobjsubid=") + NumToStr(GetColNumber())));
|
|
}
|
|
|
|
return (isReferenced != 0);
|
|
}
|
|
|
|
|
|
bool pgColumn::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
|
|
{
|
|
wxString sql = wxT("ALTER TABLE ") + GetQuotedFullTable();
|
|
sql += wxT(" DROP COLUMN ") + GetQuotedIdentifier();
|
|
|
|
return GetDatabase()->ExecuteVoid(sql);
|
|
}
|
|
|
|
|
|
void pgColumn::ShowDependencies(frmMain *form, ctlListView *Dependencies, const wxString &where)
|
|
{
|
|
pgObject::ShowDependencies(form, Dependencies,
|
|
wxT("\n WHERE dep.objid=") + table->GetOidStr() +
|
|
wxT(" AND dep.objsubid=") + NumToStr(colNumber));
|
|
}
|
|
|
|
|
|
void pgColumn::ShowDependents(frmMain *form, ctlListView *referencedBy, const wxString &where)
|
|
{
|
|
pgObject::ShowDependents(form, referencedBy,
|
|
wxT("\n WHERE dep.refobjid=") + table->GetOidStr() +
|
|
wxT(" AND dep.refobjsubid=") + NumToStr(colNumber));
|
|
}
|
|
|
|
wxString pgColumn::GetSql(ctlTree *browser)
|
|
{
|
|
if (sql.IsNull() && !GetSystemObject())
|
|
{
|
|
if (GetTable()->GetMetaType() == PGM_VIEW)
|
|
{
|
|
sql = wxT("-- Column: ") + GetQuotedIdentifier() + wxT("\n\n");
|
|
|
|
if (!GetDefault().IsEmpty())
|
|
sql += wxT("ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
|
|
+ wxT(" SET DEFAULT ") + GetDefault() + wxT(";\n");
|
|
|
|
sql += GetCommentSql();
|
|
}
|
|
else if (GetTable()->GetMetaType() == PGM_CATALOGOBJECT || GetTable()->GetMetaType() == GP_EXTTABLE)
|
|
{
|
|
sql = wxT("-- Column: ") + GetQuotedIdentifier() + wxT("\n\n");
|
|
}
|
|
else
|
|
{
|
|
if (GetInheritedCount())
|
|
sql = wxT("-- Column inherited; cannot be changed");
|
|
else
|
|
{
|
|
sql = wxT("-- Column: ") + GetQuotedIdentifier() + wxT("\n\n")
|
|
+ wxT("-- ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" DROP COLUMN ") + GetQuotedIdentifier() + wxT(";")
|
|
|
|
+ wxT("\n\nALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ADD COLUMN ") + GetQuotedIdentifier() + wxT(" ")
|
|
+ GetQuotedTypename();
|
|
if (!GetCollation().IsEmpty() && GetCollation() != wxT("pg_catalog.\"default\""))
|
|
sql += wxT(" COLLATE ") + GetCollation();
|
|
sql += wxT(";\n");
|
|
|
|
sql += GetStorageSql();
|
|
|
|
if (GetNotNull())
|
|
sql += wxT("ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
|
|
+ wxT(" SET NOT NULL;\n");
|
|
if (!GetDefault().IsEmpty())
|
|
sql += wxT("ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
|
|
+ wxT(" SET DEFAULT ") + GetDefault() + wxT(";\n");
|
|
sql += GetAttstattargetSql();
|
|
|
|
sql += GetVariablesSql();
|
|
|
|
sql += GetCommentSql();
|
|
|
|
if (GetDatabase()->BackendMinimumVersion(8, 4))
|
|
sql += GetPrivileges();
|
|
|
|
if (GetConnection()->BackendMinimumVersion(9, 1))
|
|
sql += GetSeqLabelsSql();
|
|
}
|
|
}
|
|
}
|
|
|
|
return sql;
|
|
}
|
|
|
|
wxString pgColumn::GetCommentSql()
|
|
{
|
|
wxString commentSql;
|
|
|
|
if (!GetComment().IsEmpty())
|
|
commentSql = wxT("COMMENT ON COLUMN ") + GetQuotedFullTable() + wxT(".") + GetQuotedIdentifier()
|
|
+ wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
|
|
|
|
return commentSql;
|
|
}
|
|
|
|
wxString pgColumn::GetStorageSql()
|
|
{
|
|
wxString storageSql;
|
|
|
|
if (GetStorage() != GetDefaultStorage())
|
|
storageSql = wxT("ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
|
|
+ wxT(" SET STORAGE ") + GetStorage() + wxT(";\n");
|
|
|
|
return storageSql;
|
|
}
|
|
|
|
wxString pgColumn::GetAttstattargetSql()
|
|
{
|
|
wxString attstattargetSql;
|
|
|
|
if (GetAttstattarget() >= 0)
|
|
attstattargetSql = wxT("ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
|
|
+ wxT(" SET STATISTICS ") + NumToStr(GetAttstattarget()) + wxT(";\n");
|
|
|
|
return attstattargetSql;
|
|
}
|
|
|
|
wxString pgColumn::GetVariablesSql()
|
|
{
|
|
wxString variablesSql;
|
|
|
|
size_t i;
|
|
for (i = 0 ; i < variables.GetCount() ; i++)
|
|
variablesSql += wxT("ALTER TABLE ") + GetQuotedFullTable()
|
|
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
|
|
+ wxT(" SET (") + variables.Item(i) + wxT(");\n");
|
|
|
|
return variablesSql;
|
|
}
|
|
|
|
wxString pgColumn::GetPrivileges()
|
|
{
|
|
wxString privileges;
|
|
wxString strAcl = GetAcl();
|
|
if (!strAcl.IsEmpty())
|
|
{
|
|
wxArrayString aclArray;
|
|
strAcl = strAcl.Mid(1, strAcl.Length() - 2);
|
|
getArrayFromCommaSeparatedList(strAcl, aclArray);
|
|
wxString role;
|
|
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)'"')
|
|
role = strCurrAcl + wxT(",");
|
|
continue;
|
|
}
|
|
else
|
|
strCurrAcl = role + strCurrAcl;
|
|
|
|
if (strCurrAcl[0U] == (wxChar)'"')
|
|
strCurrAcl = strCurrAcl.Mid(1, strCurrAcl.Length() - 1);
|
|
role = strCurrAcl.BeforeLast('=');
|
|
wxString value = strCurrAcl.Mid(role.Length() + 1).BeforeLast('/');
|
|
|
|
if (role.Left(6).IsSameAs(wxT("group "), false))
|
|
{
|
|
role = wxT("group ") + qtIdent(qtStrip(role.Mid(6)));
|
|
}
|
|
else if (role.IsEmpty())
|
|
{
|
|
role = wxT("public");
|
|
}
|
|
else
|
|
role = qtIdent(qtStrip(role));
|
|
|
|
privileges += pgObject::GetPrivileges(wxT("awrx"), value, GetQuotedFullTable(), role, GetQuotedIdentifier());
|
|
role.Clear();
|
|
}
|
|
}
|
|
return privileges;
|
|
}
|
|
wxString pgColumn::GetDefinition()
|
|
{
|
|
wxString sql = wxEmptyString;
|
|
wxString seqDefault1, seqDefault2;
|
|
|
|
if (table->GetOfTypeOid() == 0)
|
|
sql += GetQuotedTypename();
|
|
|
|
if (GetDatabase()->BackendMinimumVersion(16, 0))
|
|
{
|
|
if (GetStorage() != GetDefaultStorage())
|
|
sql += " STORAGE " + GetStorage();
|
|
}
|
|
if (GetDatabase()->BackendMinimumVersion(14, 0))
|
|
{
|
|
wxString cmp = GetCompression();
|
|
if (!cmp.IsEmpty())
|
|
sql += " COMPRESSION " + GetCompression();
|
|
}
|
|
|
|
if (!GetCollation().IsEmpty() && GetCollation() != wxT("pg_catalog.\"default\""))
|
|
sql += wxT(" COLLATE ") + GetCollation();
|
|
|
|
wxString full_tabname = wxEmptyString;
|
|
if (GetDatabase()->BackendMinimumVersion(8, 1))
|
|
{
|
|
wxString schpref;
|
|
|
|
schpref = schema->GetQuotedPrefix();
|
|
full_tabname = GetTableName() + wxT("_") + GetName() + wxT("_seq");
|
|
|
|
// If the generated sequence name is longer than 64 characters, then
|
|
// - If both table & column name exceed 29 chars, truncate both to 29
|
|
// - If one of table or column name exceeds 29 chars, truncate it to
|
|
// 29 chars plus however much less than 29 chars the other name is.
|
|
if (full_tabname.Length() > 64)
|
|
{
|
|
int tlen = GetTableName().Length();
|
|
int clen = GetName().Length();
|
|
|
|
if (tlen > 29 && clen > 29)
|
|
full_tabname = GetTableName().Left(29) + wxT("_") + GetName().Left(29) + wxT("_seq");
|
|
else if (tlen > 29)
|
|
full_tabname = GetTableName().Left(29 + (29 - clen)) + wxT("_") + GetName() + wxT("_seq");
|
|
else if (clen > 29)
|
|
full_tabname = GetTableName() + wxT("_") + GetName().Left(29 + (29 - tlen)) + wxT("_seq");
|
|
}
|
|
|
|
full_tabname = qtIdent(full_tabname);
|
|
|
|
if (schpref != wxEmptyString)
|
|
full_tabname = schpref + full_tabname;
|
|
|
|
seqDefault1 = wxT("nextval('") + full_tabname + wxT("'::regclass)");
|
|
seqDefault2 = seqDefault1;
|
|
}
|
|
else
|
|
{
|
|
seqDefault1 = wxT("nextval('")
|
|
+ schema->GetName() + wxT(".") + GetTableName()
|
|
+ wxT("_") + GetName() + wxT("_seq'::text)");
|
|
seqDefault2 = wxT("nextval('\"")
|
|
+ schema->GetName() + wxT(".") + GetTableName()
|
|
+ wxT("_") + GetName() + wxT("_seq\"'::text)");
|
|
}
|
|
|
|
if ((sql == wxT("integer") || sql == wxT("bigint") || sql == wxT("smallint") ||
|
|
sql == wxT("pg_catalog.integer") || sql == wxT("pg_catalog.bigint") || sql == wxT("pg_catalog.smallint"))
|
|
&& (GetDefault() == seqDefault1 || GetDefault() == seqDefault2))
|
|
{
|
|
if (GetDatabase()->BackendMinimumVersion(8, 1))
|
|
{
|
|
pgSet *set = ExecuteSet(
|
|
wxT("SELECT classid\n")
|
|
wxT(" FROM pg_depend\n")
|
|
wxT(" WHERE refobjid=") + table->GetOidStr() +
|
|
wxT(" AND refobjsubid = ") + NumToStr(GetColNumber()) +
|
|
wxT(" AND objid = '") + full_tabname + wxT("'::regclass") +
|
|
wxT(" AND deptype='a'"));
|
|
|
|
if (set && set->NumRows())
|
|
{
|
|
if (sql.Right(6) == wxT("bigint"))
|
|
sql = wxT("bigserial");
|
|
else if (sql.Right(8) == wxT("smallint"))
|
|
sql = wxT("smallserial");
|
|
else
|
|
sql = wxT("serial");
|
|
}
|
|
|
|
if (GetNotNull())
|
|
sql += wxT(" NOT NULL");
|
|
|
|
if (!set || !(set->NumRows()))
|
|
AppendIfFilled(sql, wxT(" DEFAULT "), GetDefault());
|
|
|
|
if (set)
|
|
delete set;
|
|
}
|
|
else
|
|
{
|
|
if (sql.Right(6) == wxT("bigint"))
|
|
sql = wxT("bigserial");
|
|
else if (sql.Right(8) == wxT("smallint"))
|
|
sql = wxT("smallserial");
|
|
else
|
|
sql = wxT("serial");
|
|
|
|
if (GetNotNull())
|
|
sql += wxT(" NOT NULL");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetNotNull())
|
|
sql += wxT(" NOT NULL");
|
|
if (!GetGenerated().IsEmpty()) {
|
|
if (GetGenerated()=="s") sql+= " GENERATED ALWAYS AS " + GetDefault() + " STORED";
|
|
if (GetGenerated()=="v") sql+= " GENERATED ALWAYS AS " + GetDefault() + " VIRTUAL";
|
|
} else if (!GetIdentity().IsEmpty()) {
|
|
if (GetIdentity()=="a") sql+= " GENERATED ALWAYS AS IDENTITY";
|
|
if (GetIdentity()=="d") sql+= " GENERATED BY DEFAULT AS IDENTITY" ;
|
|
}
|
|
else
|
|
AppendIfFilled(sql, wxT(" DEFAULT "), GetDefault());
|
|
}
|
|
return sql;
|
|
}
|
|
|
|
|
|
void pgColumn::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
|
|
{
|
|
if (!expandedKids)
|
|
{
|
|
expandedKids = true;
|
|
|
|
wxStringTokenizer indkey(pkCols);
|
|
while (indkey.HasMoreTokens())
|
|
{
|
|
wxString str = indkey.GetNextToken();
|
|
if (StrToLong(str) == GetColNumber())
|
|
{
|
|
isPK = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!GetDatabase()->BackendMinimumVersion(7, 4))
|
|
{
|
|
// 7.3 misses the ANY(array) comparison
|
|
pgSet *set = ExecuteSet(
|
|
wxT("SELECT conkey\n")
|
|
wxT(" FROM pg_constraint ct\n")
|
|
wxT(" JOIN pg_class cl on cl.oid=confrelid\n")
|
|
wxT(" WHERE contype='f' AND conrelid = ") + GetTableOidStr() + wxT("\n")
|
|
wxT(" ORDER BY conname"));
|
|
if (set)
|
|
{
|
|
wxString str;
|
|
while (!isFK && !set->Eof())
|
|
{
|
|
wxStringTokenizer conkey(set->GetVal(0));
|
|
|
|
while (conkey.HasMoreTokens())
|
|
{
|
|
str = conkey.GetNextToken();
|
|
if (StrToLong(str.Mid(1)) == GetColNumber())
|
|
{
|
|
isFK = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
set->MoveNext();
|
|
}
|
|
delete set;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (properties)
|
|
{
|
|
CreateListColumns(properties);
|
|
|
|
properties->AppendItem(_("Name"), GetName());
|
|
properties->AppendItem(_("Position"), GetColNumber());
|
|
properties->AppendItem(_("Data type"), GetVarTypename());
|
|
if (GetDatabase()->BackendMinimumVersion(9, 1))
|
|
{
|
|
properties->AppendItem(_("Collation"), GetCollation());
|
|
}
|
|
if (GetTable()->GetMetaType() != PGM_CATALOGOBJECT)
|
|
{
|
|
properties->AppendItem(_("Default"), GetDefault());
|
|
if (GetTable()->GetMetaType() != PGM_VIEW && GetTable()->GetMetaType() != GP_EXTTABLE)
|
|
{
|
|
properties->AppendItem(_("Sequence"), database->GetSchemaPrefix(GetSerialSchema()) + GetSerialSequence());
|
|
|
|
properties->AppendYesNoItem(_("Not NULL?"), GetNotNull());
|
|
properties->AppendYesNoItem(_("Primary key?"), GetIsPK());
|
|
properties->AppendYesNoItem(_("Foreign key?"), GetIsFK());
|
|
properties->AppendItem(_("Storage"), GetStorage());
|
|
if (GetInheritedCount() != 0)
|
|
{
|
|
properties->AppendItem(_("Inherited"),
|
|
wxT("Yes (from table ") + GetInheritedTableName() + wxT(")"));
|
|
}
|
|
else
|
|
{
|
|
properties->AppendYesNoItem(_("Inherited"), false);
|
|
}
|
|
properties->AppendItem(_("Statistics"), GetAttstattarget());
|
|
size_t i;
|
|
for (i = 0 ; i < variables.GetCount() ; i++)
|
|
{
|
|
wxString item = variables.Item(i);
|
|
properties->AppendItem(item.BeforeFirst('='), item.AfterFirst('='));
|
|
}
|
|
properties->AppendYesNoItem(_("System column?"), GetSystemObject());
|
|
}
|
|
}
|
|
if (GetDatabase()->BackendMinimumVersion(8, 4))
|
|
{
|
|
properties->AppendItem(_("ACL"), GetAcl());
|
|
}
|
|
|
|
properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
|
|
|
|
if (!GetLabels().IsEmpty())
|
|
{
|
|
wxArrayString seclabels = GetProviderLabelArray();
|
|
if (seclabels.GetCount() > 0)
|
|
{
|
|
for (unsigned int index = 0 ; index < seclabels.GetCount() - 1 ; index += 2)
|
|
{
|
|
properties->AppendItem(seclabels.Item(index), seclabels.Item(index + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void pgColumn::ShowStatistics(frmMain *form, ctlListView *statistics)
|
|
{
|
|
DisplayStatistics(statistics,
|
|
wxT("SELECT null_frac AS ") + qtIdent(_("Null Fraction")) +
|
|
wxT(", avg_width AS ") + qtIdent(_("Average Width")) +
|
|
wxT(", n_distinct AS ") + qtIdent(_("Distinct Values")) +
|
|
wxT(", most_common_vals AS ") + qtIdent(_("Most Common Values")) +
|
|
wxT(", most_common_freqs AS ") + qtIdent(_("Most Common Frequencies")) +
|
|
wxT(", histogram_bounds AS ") + qtIdent(_("Histogram Bounds")) +
|
|
wxT(", correlation AS ") + qtIdent(_("Correlation")) + wxT("\n")
|
|
wxT(" FROM pg_stats\n")
|
|
wxT(" WHERE schemaname = ") + qtDbString(schema->GetName()) + wxT("\n")
|
|
wxT(" AND tablename = ") + qtDbString(GetTableName()) + wxT("\n")
|
|
wxT(" AND attname = ") + qtDbString(GetName()));
|
|
}
|
|
|
|
|
|
pgObject *pgColumn::Refresh(ctlTree *browser, const wxTreeItemId item)
|
|
{
|
|
pgObject *column = 0;
|
|
pgCollection *coll = browser->GetParentCollection(item);
|
|
if (coll)
|
|
column = columnFactory.CreateObjects(coll, 0, wxT("\n AND att.attnum=") + NumToStr(GetColNumber()));
|
|
|
|
return column;
|
|
}
|
|
|
|
|
|
|
|
pgObject *pgColumnFactory::CreateObjects(pgCollection *coll, ctlTree *browser, const wxString &restriction)
|
|
{
|
|
pgTableObjCollection *collection = (pgTableObjCollection *)coll;
|
|
pgColumn *column = 0;
|
|
pgDatabase *database = collection->GetDatabase();
|
|
inheritHashMap inhMap;
|
|
|
|
// grab inherited tables with attibute names
|
|
pgSet *inhtables = database->ExecuteSet(
|
|
wxT("SELECT\n")
|
|
wxT(" array_to_string(array_agg(inhrelname), ', ') inhrelname,\n")
|
|
wxT(" attrname\n")
|
|
wxT("FROM\n")
|
|
wxT(" (SELECT\n")
|
|
wxT(" inhparent::regclass AS inhrelname,\n")
|
|
wxT(" a.attname AS attrname\n")
|
|
wxT(" FROM\n")
|
|
wxT(" pg_inherits i\n")
|
|
wxT(" LEFT JOIN pg_attribute a ON\n")
|
|
wxT(" (attrelid = inhparent AND attnum > 0)\n")
|
|
wxT(" WHERE inhrelid = ") + collection->GetOidStr() + wxT("::oid\n")
|
|
wxT(" ORDER BY inhseqno) a\n")
|
|
wxT("GROUP BY attrname"));
|
|
|
|
if (inhtables)
|
|
{
|
|
while (!inhtables->Eof())
|
|
{
|
|
wxString attrName = inhtables->GetVal(wxT("attrname"));
|
|
wxString inhrelName = inhtables->GetVal(wxT("inhrelname"));
|
|
inhMap[attrName] = inhrelName;
|
|
inhtables->MoveNext();
|
|
}
|
|
|
|
delete inhtables;
|
|
}
|
|
|
|
wxString systemRestriction;
|
|
if (!settings->GetShowSystemObjects())
|
|
systemRestriction = wxT("\n AND att.attnum > 0");
|
|
|
|
wxString sql =
|
|
wxT("SELECT att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval, CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray, format_type(ty.oid,NULL) AS typname, format_type(ty.oid,att.atttypmod) AS displaytypname, tn.nspname as typnspname, et.typname as elemtypname,\n")
|
|
wxT(" ty.typstorage AS defaultstorage, cl.relname, na.nspname, coalesce(att.attstattarget,-1) attstattarget2, description, cs.relname AS sername, ns.nspname AS serschema,\n")
|
|
wxT(" (SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup, indkey");
|
|
|
|
if (database->BackendMinimumVersion(9, 1))
|
|
sql += wxT(",\n coll.collname, nspc.nspname as collnspname");
|
|
if (database->BackendMinimumVersion(8, 5))
|
|
sql += wxT(",\n attoptions");
|
|
if (database->BackendMinimumVersion(7, 4))
|
|
sql +=
|
|
wxT(",\n")
|
|
wxT(" EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f'")
|
|
wxT(" AND att.attnum=ANY(conkey)) As isfk");
|
|
if (database->BackendMinimumVersion(9, 1))
|
|
{
|
|
sql += wxT(",\n(SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS labels");
|
|
sql += wxT(",\n(SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=att.attrelid AND sl2.objsubid=att.attnum) AS providers");
|
|
}
|
|
|
|
sql += wxT("\n")
|
|
wxT(" FROM pg_attribute att\n")
|
|
wxT(" JOIN pg_type ty ON ty.oid=atttypid\n")
|
|
wxT(" JOIN pg_namespace tn ON tn.oid=ty.typnamespace\n")
|
|
wxT(" JOIN pg_class cl ON cl.oid=att.attrelid\n")
|
|
wxT(" JOIN pg_namespace na ON na.oid=cl.relnamespace\n")
|
|
wxT(" LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem\n")
|
|
wxT(" LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum\n")
|
|
wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)\n")
|
|
wxT(" LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON classid='pg_class'::regclass AND objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum\n")
|
|
wxT(" LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace\n")
|
|
wxT(" LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary\n");
|
|
if (database->BackendMinimumVersion(9, 1))
|
|
sql += wxT(" LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid\n")
|
|
wxT(" LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid\n");
|
|
sql += wxT(" WHERE att.attrelid = ") + collection->GetOidStr()
|
|
+ restriction + systemRestriction + wxT("\n")
|
|
wxT(" AND att.attisdropped IS FALSE\n")
|
|
wxT(" ORDER BY att.attnum");
|
|
|
|
pgSet *columns = database->ExecuteSet(sql);
|
|
if (columns)
|
|
{
|
|
while (!columns->Eof())
|
|
{
|
|
wxString attrName = columns->GetVal(wxT("attname"));
|
|
column = new pgColumn(collection->GetTable(), attrName);
|
|
|
|
column->iSetAttTypId(columns->GetOid(wxT("atttypid")));
|
|
column->iSetColNumber(columns->GetLong(wxT("attnum")));
|
|
column->iSetIsArray(columns->GetBool(wxT("isarray")));
|
|
column->iSetComment(columns->GetVal(wxT("description")));
|
|
column->iSetSerialSequence(columns->GetVal(wxT("sername")));
|
|
column->iSetSerialSchema(columns->GetVal(wxT("serschema")));
|
|
if (database->BackendMinimumVersion(10, 0))
|
|
{
|
|
column->iSetIdentity(columns->GetVal(wxT("attidentity")));
|
|
};
|
|
if (database->BackendMinimumVersion(12, 0))
|
|
{
|
|
column->iSetGenerated(columns->GetVal(wxT("attgenerated")));
|
|
};
|
|
if (database->BackendMinimumVersion(14, 0))
|
|
{
|
|
wxString compres = columns->GetVal(wxT("attcompression"));
|
|
column->iSetCompression(compres);
|
|
}
|
|
|
|
|
|
|
|
column->iSetPkCols(columns->GetVal(wxT("indkey")));
|
|
if (database->BackendMinimumVersion(7, 4))
|
|
column->iSetIsFK(columns->GetBool(wxT("isfk")));
|
|
|
|
if (columns->GetBool(wxT("atthasdef")))
|
|
column->iSetDefault(columns->GetVal(wxT("defval")));
|
|
|
|
wxString storage = columns->GetVal(wxT("attstorage"));
|
|
column->iSetStorage(
|
|
storage == wxT("p") ? wxT("PLAIN") :
|
|
storage == wxT("e") ? wxT("EXTERNAL") :
|
|
storage == wxT("m") ? wxT("MAIN") :
|
|
storage == wxT("x") ? wxT("EXTENDED") : wxT("Unknown"));
|
|
wxString defaultStorage = columns->GetVal(wxT("defaultstorage"));
|
|
column->iSetDefaultStorage(
|
|
defaultStorage == wxT("p") ? wxT("PLAIN") :
|
|
defaultStorage == wxT("e") ? wxT("EXTERNAL") :
|
|
defaultStorage == wxT("m") ? wxT("MAIN") :
|
|
defaultStorage == wxT("x") ? wxT("EXTENDED") : wxT("Unknown"));
|
|
|
|
column->iSetTyplen(columns->GetLong(wxT("attlen")));
|
|
|
|
long typmod = columns->GetLong(wxT("atttypmod"));
|
|
pgDatatype dt(columns->GetVal(wxT("typnspname")), columns->GetVal(wxT("typname")),
|
|
columns->GetBool(wxT("isdup")),
|
|
columns->GetLong(wxT("attndims")), typmod);
|
|
|
|
|
|
column->iSetTypmod(typmod);
|
|
column->iSetLength(dt.Length());
|
|
column->iSetPrecision(dt.Precision());
|
|
column->iSetRawTypename(dt.Name());
|
|
|
|
column->iSetVarTypename(dt.FullName());
|
|
column->iSetQuotedTypename(columns->GetVal(wxT("displaytypname")));
|
|
|
|
column->iSetNotNull(columns->GetBool(wxT("attnotnull")));
|
|
column->iSetQuotedFullTable(database->GetQuotedSchemaPrefix(columns->GetVal(wxT("nspname")))
|
|
+ qtIdent(columns->GetVal(wxT("relname"))));
|
|
column->iSetTableName(columns->GetVal(wxT("relname")));
|
|
column->iSetInheritedCount(columns->GetLong(wxT("attinhcount")));
|
|
|
|
// Check whether the attribute is inherited
|
|
inheritHashMap::iterator it = inhMap.find(attrName);
|
|
if (it != inhMap.end())
|
|
column->iSetInheritedTableName(it->second);
|
|
|
|
column->iSetIsLocal(columns->GetBool(wxT("attislocal")));
|
|
column->iSetAttstattarget(columns->GetLong(wxT("attstattarget2")));
|
|
if (database->BackendMinimumVersion(8, 5))
|
|
{
|
|
wxString str = columns->GetVal(wxT("attoptions"));
|
|
if (!str.IsEmpty())
|
|
FillArray(column->GetVariables(), str.Mid(1, str.Length() - 2));
|
|
}
|
|
if (database->BackendMinimumVersion(8, 4))
|
|
column->iSetAcl(columns->GetVal(wxT("attacl")));
|
|
if (database->BackendMinimumVersion(9, 1))
|
|
{
|
|
wxString coll = wxEmptyString;
|
|
if (!columns->GetVal(wxT("collname")).IsEmpty())
|
|
coll = qtIdent(columns->GetVal(wxT("collnspname"))) + wxT(".") + qtIdent(columns->GetVal(wxT("collname")));
|
|
column->iSetCollation(coll);
|
|
}
|
|
|
|
if (database->BackendMinimumVersion(9, 1))
|
|
{
|
|
column->iSetProviders(columns->GetVal(wxT("providers")));
|
|
column->iSetLabels(columns->GetVal(wxT("labels")));
|
|
}
|
|
|
|
if (browser)
|
|
{
|
|
browser->AppendObject(collection, column);
|
|
columns->MoveNext();
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
delete columns;
|
|
}
|
|
|
|
inhMap.clear();
|
|
return column;
|
|
}
|
|
|
|
/////////////////////////////
|
|
|
|
pgColumnCollection::pgColumnCollection(pgaFactory *factory, pgTable *tbl)
|
|
: pgTableObjCollection(factory, tbl)
|
|
{
|
|
}
|
|
|
|
|
|
wxString pgColumnCollection::GetTranslatedMessage(int kindOfMessage) const
|
|
{
|
|
wxString message = wxEmptyString;
|
|
|
|
switch (kindOfMessage)
|
|
{
|
|
case RETRIEVINGDETAILS:
|
|
message = _("Retrieving details on columns");
|
|
break;
|
|
case REFRESHINGDETAILS:
|
|
message = _("Refreshing columns");
|
|
break;
|
|
case OBJECTSLISTREPORT:
|
|
message = _("Columns list report");
|
|
break;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
/////////////////////////////
|
|
|
|
#include "images/column.pngc"
|
|
#include "images/column-sm.pngc"
|
|
#include "images/columns.pngc"
|
|
|
|
pgColumnFactory::pgColumnFactory()
|
|
: pgTableObjFactory(__("Column"), __("New Column..."), __("Create a new Column."), column_png_img, column_sm_png_img)
|
|
{
|
|
metaType = PGM_COLUMN;
|
|
}
|
|
|
|
|
|
pgCollection *pgColumnFactory::CreateCollection(pgObject *obj)
|
|
{
|
|
return new pgColumnCollection(GetCollectionFactory(), (pgTable *)obj);
|
|
}
|
|
|
|
pgColumnFactory columnFactory;
|
|
static pgaCollectionFactory cf(&columnFactory, __("Columns"), columns_png_img);
|