pgadmin3/schema/pgTable.cpp
lsv 38f4510342 Add view MAINTAIN privilege
Добавлена поддержка отображения новой привелегии MAINTAIN.
2025-01-21 10:16:11 +05:00

2047 lines
71 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// pgTable.cpp - Table class
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
#include "utils/misc.h"
#include "frm/frmHint.h"
#include "frm/frmMain.h"
#include "frm/frmMaintenance.h"
#include "schema/pgTable.h"
#include "schema/pgColumn.h"
#include "schema/pgIndexConstraint.h"
#include "schema/pgForeignKey.h"
#include "schema/pgCheck.h"
#include "utils/sysSettings.h"
#include "utils/pgfeatures.h"
#include "schema/pgRule.h"
#include "schema/pgTrigger.h"
#include "schema/pgConstraints.h"
#include "schema/gpPartition.h"
#include "schema/pgPartition.h"
#include <wx/regex.h>
// App headers
pgTable::pgTable(pgSchema *newSchema, const wxString &newName)
: pgSchemaObject(newSchema, tableFactory, newName)
{
Init();
}
pgTable::pgTable(pgSchema *newSchema, pgaFactory &newFactory, const wxString &newName)
: pgSchemaObject(newSchema, newFactory, newName)
{
Init();
}
pgTable::~pgTable()
{
}
void pgTable::Init()
{
rows = 0;
estimatedRows = 0.0;
hasToastTable = false;
autovacuum_enabled = 0;
toast_autovacuum_enabled = 0;
isPartitioned = false;
hasOids = false;
unlogged = false;
hasSubclass = false;
rowsCounted = false;
isReplicated = false;
showExtendedStatistics = false;
distributionIsRandom = false;
inheritedTableCount = 0;
triggerCount = 0;
tablespaceOid = 0;
ofTypeOid = 0;
}
wxString pgTable::GetTranslatedMessage(int kindOfMessage) const
{
wxString message = wxEmptyString;
switch (kindOfMessage)
{
case RETRIEVINGDETAILS:
message = _("Retrieving details on table");
message += wxT(" ") + GetName();
break;
case REFRESHINGDETAILS:
message = _("Refreshing table");
message += wxT(" ") + GetName();
break;
case DROPINCLUDINGDEPS:
message = wxString::Format(_("Are you sure you wish to drop table \"%s\" including all objects that depend on it?"),
GetFullIdentifier().c_str());
break;
case DROPEXCLUDINGDEPS:
message = wxString::Format(_("Are you sure you wish to drop table \"%s\"?"),
GetFullIdentifier().c_str());
break;
case DROPCASCADETITLE:
message = _("Drop table cascaded?");
break;
case DROPTITLE:
message = _("Drop table?");
break;
case PROPERTIESREPORT:
message = _("Table properties report");
message += wxT(" - ") + GetName();
break;
case PROPERTIES:
message = _("Table properties");
break;
case DDLREPORT:
message = _("Table DDL report");
message += wxT(" - ") + GetName();
break;
case DDL:
message = _("Table DDL");
break;
case DATADICTIONNARYREPORT:
message = _("Table Data dictionary report");
message += wxT(" - ") + GetName();
break;
case STATISTICSREPORT:
message = _("Table statistics report");
message += wxT(" - ") + GetName();
break;
case OBJSTATISTICS:
message = _("Table statistics");
break;
case DEPENDENCIESREPORT:
message = _("Table dependencies report");
message += wxT(" - ") + GetName();
break;
case DEPENDENCIES:
message = _("Table dependencies");
break;
case DEPENDENTSREPORT:
message = _("Table dependents report");
message += wxT(" - ") + GetName();
break;
case DEPENDENTS:
message = _("Table dependents");
break;
case BACKUPTITLE:
message = wxString::Format(_("Backup table \"%s\""),
GetFullIdentifier().c_str());
break;
case RESTORETITLE:
message = wxString::Format(_("Restore table \"%s\""),
GetFullIdentifier().c_str());
break;
}
return message;
}
int pgTable::GetIconId()
{
if (isReplicated)
return tableFactory.GetReplicatedIconId();
else
if (!GetPartKeyDef().IsEmpty()||GetIsPartitioned()) return tableFactory.GetPartitionsIconId();
else
return tableFactory.GetIconId();
}
wxMenu *pgTable::GetNewMenu()
{
wxMenu *menu = pgObject::GetNewMenu();
if (schema->GetCreatePrivilege())
{
columnFactory.AppendMenu(menu);
if (GetPrimaryKey().IsEmpty()) // Will not notice if pk has been added after last refresh
primaryKeyFactory.AppendMenu(menu);
foreignKeyFactory.AppendMenu(menu);
excludeFactory.AppendMenu(menu);
uniqueFactory.AppendMenu(menu);
checkFactory.AppendMenu(menu);
indexFactory.AppendMenu(menu);
ruleFactory.AppendMenu(menu);
triggerFactory.AppendMenu(menu);
/*
* TEMPORARY: Disable adding new partitions until that code is working right.
*
if (GetConnection() != 0 && GetConnection()->GetIsGreenplum() && GetIsPartitioned())
partitionFactory.AppendMenu(menu);
*/
}
return menu;
}
int pgTable::GetReplicationStatus(ctlTree *browser, wxString *clusterName, long *setId)
{
wxArrayString clusters = GetDatabase()->GetSlonyClusters(browser);
bool isSubscribed = false;
size_t i;
for (i = 0 ; i < clusters.GetCount() ; i++)
{
wxString nsp = qtIdent(wxT("_") + clusters.Item(i));
pgSetIterator sets(GetConnection(),
wxT("SELECT tab_set, sub_provider, ") + nsp + wxT(".getlocalnodeid(") + qtDbString(wxT("_") + clusters.Item(i)) + wxT(") AS localnode\n")
wxT(" FROM ") + nsp + wxT(".sl_table\n")
wxT(" LEFT JOIN ") + nsp + wxT(".sl_subscribe ON sub_set=tab_set\n")
wxT(" WHERE tab_reloid = ") + GetOidStr());
if (sets.RowsLeft())
{
if (clusterName)
*clusterName = clusters.Item(i);
if (setId)
*setId = sets.GetLong(wxT("tab_set"));
if (isSubscribed)
return REPLICATIONSTATUS_MULTIPLY_PUBLISHED;
long provider = sets.GetLong(wxT("sub_provider"));
if (provider)
{
if (provider != sets.GetLong(wxT("localnode")))
return REPLICATIONSTATUS_REPLICATED;
isSubscribed = true;
}
}
}
if (isSubscribed)
return REPLICATIONSTATUS_SUBSCRIBED;
return REPLICATIONSTATUS_NONE;
}
wxString pgTable::GetHelpPage(bool forCreate) const
{
if (forCreate)
return wxT("pg/sql-createtable");
else
return wxT("pg/sql-altertable");
}
bool pgTable::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
{
wxString sql = wxT("DROP TABLE ") + this->GetSchema()->GetQuotedIdentifier() + wxT(".") + this->GetQuotedIdentifier();
if (cascaded)
sql += wxT(" CASCADE");
return GetDatabase()->ExecuteVoid(sql);
}
bool pgTable::Truncate(bool cascaded)
{
wxString sql = wxT("TRUNCATE TABLE ") + this->GetSchema()->GetQuotedIdentifier() + wxT(".") + this->GetQuotedIdentifier();
if (cascaded)
sql += wxT(" CASCADE");
return GetDatabase()->ExecuteVoid(sql);
}
bool pgTable::ResetStats()
{
wxString sql = wxT("SELECT pg_stat_reset_single_table_counters(")
+ NumToStr(this->GetOid())
+ wxT(")");
return GetDatabase()->ExecuteVoid(sql);
}
void pgTable::AppendStuff(wxString &sql, ctlTree *browser, pgaFactory &factory)
{
wxString tmp;
pgCollection *collection = browser->FindCollection(factory, GetId());
if (collection)
{
tmp += wxT("\n");
collection->ShowTreeDetail(browser);
treeObjectIterator idxIt(browser, collection);
pgObject *obj;
while ((obj = idxIt.GetNextObject()) != 0)
{
obj->ShowTreeDetail(browser);
tmp += obj->GetSql(browser) + wxT("\n");
}
}
if (!tmp.IsEmpty() && tmp != wxT("\n"))
sql += tmp;
}
void pgTable::AppendStuffNoSql(wxString &sql, ctlTree *browser, pgaFactory &factory)
{
pgCollection *collection = browser->FindCollection(factory, GetId());
if (collection)
{
collection->ShowTreeDetail(browser);
treeObjectIterator idxIt(browser, collection);
pgObject *obj;
while ((obj = idxIt.GetNextObject()) != 0)
{
obj->ShowTreeDetail(browser);
}
}
}
wxString pgTable::GetSql(ctlTree *browser)
{
wxString colDetails, conDetails;
wxString prevComment;
wxString cols_sql = wxEmptyString;
wxString cols_type = wxEmptyString;
wxString columnPrivileges;
if (sql.IsNull())
{
// make sure all kids are appended
ShowTreeDetail(browser);
sql = wxT("-- Table: ") + GetQuotedFullIdentifier() + wxT("\n\n")
+ wxT("-- DROP TABLE ") + GetQuotedFullIdentifier() + wxT(";")
+ wxT("\n\nCREATE ");
if (GetUnlogged())
sql += wxT("UNLOGGED ");
sql += wxT("TABLE ") + GetQuotedFullIdentifier();
// of type (9.0 material)
if (ofTypeOid > 0)
sql += wxT("\nOF ") + qtIdent(ofType);
// Get a count of the constraints.
int consCount = 0;
pgCollection *constraints = browser->FindCollection(primaryKeyFactory, GetId());
if (constraints)
consCount = browser->GetChildrenCount(constraints->GetId());
// Get the columns
pgCollection *columns = browser->FindCollection(columnFactory, GetId());
if (columns)
{
columns->ShowTreeDetail(browser);
treeObjectIterator colIt1(browser, columns);
treeObjectIterator colIt2(browser, columns);
int lastRealCol = 0;
int currentCol = 0;
pgColumn *column;
// Iterate the columns to find the last 'real' one
while ((column = (pgColumn *)colIt1.GetNextObject()) != 0)
{
if (currentCol==0) {cols_type+=column->GetDisplayName()+wxT(" ")+column->GetQuotedTypename();
} else cols_type+=wxT(", ")+column->GetDisplayName()+wxT(" ")+column->GetQuotedTypename();
currentCol++;
//AppendIfFilled(cols_type,wxT(","),cols_type);
if (column->GetInheritedCount() == 0)
lastRealCol = currentCol;
}
cols_type=wxT("-- (")+cols_type+wxT(")");
// Now build the actual column list
int colCount = 0;
while ((column = (pgColumn *)colIt2.GetNextObject()) != 0)
{
column->ShowTreeDetail(browser);
if (column->GetColNumber() > 0)
{
if (colCount)
{
// Only add a comma if this isn't the last 'real' column, or if there are constraints
if (colCount != lastRealCol || consCount)
cols_sql += wxT(",");
if (!prevComment.IsEmpty())
cols_sql += wxT(" -- ") + firstLineOnly(prevComment);
cols_sql += wxT("\n");
}
if (column->GetInheritedCount() > 0)
{
if (!column->GetIsLocal())
{
cols_sql += wxString::Format(wxT("-- %s "), _("Inherited"))
+ wxT("from table ") + column->GetInheritedTableName() + wxT(":");
}
}
if (ofTypeOid > 0)
{
if (column->GetDefinition().Length() == 0)
{
cols_sql += wxString::Format(wxT("-- %s "), _("Inherited"))
+ wxT("from type ") + ofType + wxT(": ")
+ column->GetQuotedIdentifier();
}
else
{
cols_sql += wxT(" ") + column->GetQuotedIdentifier() + wxT(" WITH OPTIONS ")
+ column->GetDefinition();
}
}
else
{
cols_sql += wxT(" ") + column->GetQuotedIdentifier() + wxT(" ")
+ column->GetDefinition();
}
prevComment = column->GetComment();
// Whilst we are looping round the columns, grab their comments as well.
colDetails += column->GetCommentSql();
if (colDetails.Length() > 0)
if (colDetails.Last() != '\n')
colDetails += wxT("\n");
if (!GetDatabase()->BackendMinimumVersion(16, 0))
colDetails += column->GetStorageSql();
if (colDetails.Length() > 0)
if (colDetails.Last() != '\n')
colDetails += wxT("\n");
colDetails += column->GetAttstattargetSql();
if (colDetails.Length() > 0)
if (colDetails.Last() != '\n')
colDetails += wxT("\n");
colDetails += column->GetVariablesSql();
if (colDetails.Length() > 0)
if (colDetails.Last() != '\n')
colDetails += wxT("\n");
colCount++;
columnPrivileges += column->GetPrivileges();
}
}
}
// Now iterate the constraints
if (constraints)
{
constraints->ShowTreeDetail(browser);
treeObjectIterator consIt(browser, constraints);
pgObject *data;
while ((data = consIt.GetNextObject()) != 0)
{
data->ShowTreeDetail(browser);
cols_sql += wxT(",");
if (!prevComment.IsEmpty())
cols_sql += wxT(" -- ") + firstLineOnly(prevComment);
cols_sql += wxT("\n CONSTRAINT ") + data->GetQuotedIdentifier()
+ wxT(" ") + data->GetTypeName().Upper()
+ wxT(" ") ;
prevComment = data->GetComment();
if (!data->GetComment().IsEmpty())
conDetails += wxT("COMMENT ON CONSTRAINT ") + data->GetQuotedIdentifier() +
wxT(" ON ") + GetQuotedFullIdentifier() +
wxT(" IS ") + qtDbString(data->GetComment()) + wxT(";\n");
switch (data->GetMetaType())
{
case PGM_PRIMARYKEY:
case PGM_UNIQUE:
case PGM_EXCLUDE:
cols_sql += ((pgIndexConstraint *)data)->GetDefinition();
break;
case PGM_FOREIGNKEY:
cols_sql += ((pgForeignKey *)data)->GetDefinition();
break;
case PGM_CHECK:
cols_sql += wxT("(") + ((pgCheck *)data)->GetDefinition() + wxT(")");
if (GetDatabase()->BackendMinimumVersion(9, 2) && ((pgCheck *)data)->GetNoInherit())
cols_sql += wxT(" NO INHERIT");
if (GetDatabase()->BackendMinimumVersion(9, 2) && !((pgCheck *)data)->GetValid())
cols_sql += wxT(" NOT VALID");
break;
}
}
}
if (!prevComment.IsEmpty())
cols_sql += wxT(" -- ") + firstLineOnly(prevComment);
if (GetConnection()->BackendMinimumVersion(10, 0)&&!GetPartExp().IsEmpty())
{
sql += wxT("\n PARTITION OF ") + GetQuotedInheritedTables() + wxT("(\n") + cols_sql + wxT("\n)");
sql += wxT(" ") + GetPartExp() + wxT(" ");
} else
{
sql += wxT("\n(\n") + cols_sql + wxT("\n)");
}
if (GetInheritedTableCount())
{
if (GetConnection()->BackendMinimumVersion(10, 0)&&!GetPartExp().IsEmpty()) {
} else
{
sql += wxT("\nINHERITS (") + GetQuotedInheritedTables() + wxT(")");
}
}
if (GetConnection()->BackendMinimumVersion(10, 0)&&!GetPartKeyDef().IsEmpty())
{
sql += wxT("\nPARTITION BY ") + GetPartKeyDef() + wxT(" ");
}
if (GetConnection()->BackendMinimumVersion(8, 2))
{
wxString sqlopt=wxEmptyString;
if (GetFillFactor().Length() > 0)
sqlopt += wxT("\n FILLFACTOR=") + GetFillFactor() + wxT(", ");
if (GetAppendOnly().Length() > 0)
sqlopt += wxT("APPENDONLY=") + GetAppendOnly() + wxT(", ");
if (GetCompressLevel().Length() > 0)
sqlopt += wxT("COMPRESSLEVEL=") + GetCompressLevel() + wxT(", ");
if (GetOrientation().Length() > 0)
sqlopt += wxT("ORIENTATION=") + GetOrientation() + wxT(", ");
if (GetCompressType().Length() > 0)
sqlopt += wxT("COMPRESSTYPE=") + GetCompressType() + wxT(", ");
if (GetBlocksize().Length() > 0)
sqlopt += wxT("BLOCKSIZE=") + GetBlocksize() + wxT(", ");
if (GetChecksum().Length() > 0)
sqlopt += wxT("CHECKSUM=") + GetChecksum() + wxT(", ");
if (GetConnection()->BackendMinimumVersion(12, 0)) {
if (!sqlopt.IsEmpty()) sqlopt=sqlopt.BeforeLast(',');
} else {
if (GetHasOids())
sqlopt += wxT("\n OIDS=TRUE");
else
sqlopt += wxT("\n OIDS=FALSE");
}
if(GetConnection()->BackendMinimumVersion(8, 4))
{
if (GetCustomAutoVacuumEnabled())
{
if (GetAutoVacuumEnabled() == 1)
sqlopt += wxT(",\n autovacuum_enabled=true");
else if (GetCustomAutoVacuumEnabled() == 0)
sqlopt += wxT(",\n autovacuum_enabled=false");
if (!GetAutoVacuumVacuumThreshold().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_vacuum_threshold=") + GetAutoVacuumVacuumThreshold();
}
if (!GetAutoVacuumVacuumScaleFactor().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_vacuum_scale_factor=") + GetAutoVacuumVacuumScaleFactor();
}
if (!GetAutoVacuumAnalyzeThreshold().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_analyze_threshold=") + GetAutoVacuumAnalyzeThreshold();
}
if (!GetAutoVacuumAnalyzeScaleFactor().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_analyze_scale_factor=") + GetAutoVacuumAnalyzeScaleFactor();
}
if (!GetAutoVacuumVacuumCostDelay().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_vacuum_cost_delay=") + GetAutoVacuumVacuumCostDelay();
}
if (!GetAutoVacuumVacuumCostLimit().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_vacuum_cost_limit=") + GetAutoVacuumVacuumCostLimit();
}
if (!GetAutoVacuumFreezeMinAge().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_freeze_min_age=") + GetAutoVacuumFreezeMinAge();
}
if (!GetAutoVacuumFreezeMaxAge().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_freeze_max_age=") + GetAutoVacuumFreezeMaxAge();
}
if (!GetAutoVacuumFreezeTableAge().IsEmpty())
{
sqlopt += wxT(",\n autovacuum_freeze_table_age=") + GetAutoVacuumFreezeTableAge();
}
}
if (GetHasToastTable() && GetToastCustomAutoVacuumEnabled())
{
if (GetToastAutoVacuumEnabled() == 1)
sqlopt += wxT(",\n toast.autovacuum_enabled=true");
else if (GetToastAutoVacuumEnabled() == 0)
sqlopt += wxT(",\n toast.autovacuum_enabled=false");
if (!GetToastAutoVacuumVacuumThreshold().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_vacuum_threshold=") + GetToastAutoVacuumVacuumThreshold();
}
if (!GetToastAutoVacuumVacuumScaleFactor().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_vacuum_scale_factor=") + GetToastAutoVacuumVacuumScaleFactor();
}
if (!GetToastAutoVacuumVacuumCostDelay().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_vacuum_cost_delay=") + GetToastAutoVacuumVacuumCostDelay();
}
if (!GetToastAutoVacuumVacuumCostLimit().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_vacuum_cost_limit=") + GetToastAutoVacuumVacuumCostLimit();
}
if (!GetToastAutoVacuumFreezeMinAge().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_freeze_min_age=") + GetToastAutoVacuumFreezeMinAge();
}
if (!GetToastAutoVacuumFreezeMaxAge().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_freeze_max_age=") + GetToastAutoVacuumFreezeMaxAge();
}
if (!GetToastAutoVacuumFreezeTableAge().IsEmpty())
{
sqlopt += wxT(",\n toast.autovacuum_freeze_table_age=") + GetToastAutoVacuumFreezeTableAge();
}
}
}
wxRegEx reg("autovacuum_vacuum_insert_scale_factor=[0-9.]+|autovacuum_vacuum_insert_threshold=[0-9]+|vacuum_index_cleanup=[a-z]+|vacuum_truncate=[a-z]+|parallel_workers=[0-9]+|toast_tuple_target=[0-9]+|log_autovacuum_min_duration=[0-9]+|user_catalog_table=[a-z]+");
wxString relopt=GetRelOptions();
wxString o;
size_t start, len;
while ( reg.Matches(relopt) )
{
reg.GetMatch(&start, &len, 0);
o=reg.GetMatch(relopt, 0);
AppendIfFilled(sqlopt, ",\n ", o);
relopt = relopt.Mid (start + len);
}
relopt=GetToastRelOptions();
while ( reg.Matches(relopt) )
{
reg.GetMatch(&start, &len, 0);
o="toast." + reg.GetMatch(relopt, 0);
AppendIfFilled(sqlopt, ",\n ", o);
relopt = relopt.Mid (start + len);
}
if (!sqlopt.IsEmpty()) {
sql += wxT("\nWITH (");
if (sqlopt.Index(',')==0) sqlopt=sqlopt.Mid(1);
sql += sqlopt;
sql += wxT("\n)");
}
}
else
{
if (GetHasOids())
sql += wxT("\nWITH OIDS");
else
sql += wxT("\nWITHOUT OIDS");
}
if (GetConnection()->BackendMinimumVersion(8, 0) && tablespace != GetDatabase()->GetDefaultTablespace())
sql += wxT("\nTABLESPACE ") + qtIdent(tablespace);
if (GetConnection()->GetIsGreenplum())
{
// Add Greenplum DISTRIBUTED BY
if (distributionIsRandom)
{
sql += wxT("\nDISTRIBUTED RANDOMLY");
}
else if (GetDistributionColNumbers().Length() == 0)
{
// catalog table or other non-distributed table
}
else
{
// convert list of columns numbers to column names
wxStringTokenizer collist(GetDistributionColNumbers(), wxT(","));
wxString cn;
wxString distributionColumns;
while (collist.HasMoreTokens())
{
cn = collist.GetNextToken();
pgSet *set = ExecuteSet(
wxT("SELECT attname\n")
wxT(" FROM pg_attribute\n")
wxT(" WHERE attrelid=") + GetOidStr() + wxT(" AND attnum IN (") + cn + wxT(")"));
if (set)
{
if (!distributionColumns.IsNull())
{
distributionColumns += wxT(", ");
}
distributionColumns += qtIdent(set->GetVal(0));
delete set;
}
}
sql += wxT("\nDISTRIBUTED BY (");
sql += distributionColumns;
sql += wxT(")");
}
if (GetIsPartitioned())
if (GetConnection()->BackendMinimumVersion(8, 2, 9) && GetConnection()->GetIsGreenplum())
if (GetPartitionDef().Length() == 0)
{
wxString query = wxT("SELECT pg_get_partition_def(");
query += GetOidStr();
query += wxT(", true) ");
wxString partition_def = GetDatabase()->ExecuteScalar(query);
iSetPartitionDef(partition_def);
// pg_get_partition_def() doesn't work on partitions
if (GetPartitionDef().Length() == 0)
iSetPartitionDef(wxT("-- This partition has subpartitions"));
}
if (partitionDef.Length() > 0)
sql += wxT("\n") + partitionDef + wxT("\n");
}
sql += wxT(";\n")
+ GetOwnerSql(7, 3);
if (GetConnection()->BackendMinimumVersion(17, 0))
sql += GetGrant(wxT("arwdDxtm"));
else if (GetConnection()->BackendMinimumVersion(8, 4))
sql += GetGrant(wxT("arwdDxt"));
else if (GetConnection()->BackendMinimumVersion(8, 2))
sql += GetGrant(wxT("arwdxt"));
else
sql += GetGrant(wxT("arwdRxt"));
wxString st=GetStatExt();
if (!st.IsEmpty()) sql += st + wxT("\n");
sql += GetCommentSql();
if (GetConnection()->BackendMinimumVersion(9, 1))
sql += GetSeqLabelsSql();
// Column/constraint comments
if (!colDetails.IsEmpty())
sql += colDetails + wxT("\n");
if (!conDetails.IsEmpty())
sql += conDetails + wxT("\n");
if (!columnPrivileges.IsEmpty())
{
sql += columnPrivileges + wxT("\n");
}
AppendStuff(sql, browser, indexFactory);
AppendStuff(sql, browser, ruleFactory);
AppendStuff(sql, browser, triggerFactory);
/*
* Disable adding partitions until that code works.
*
if (partitionDef.Length() > 0)
{
AppendStuffNoSql(sql, browser, partitionFactory);
}
*/
sql+=cols_type;
}
return sql;
}
wxString pgTable::GetCoveringIndex(ctlTree *browser, const wxString &collist)
{
// delivers the name of the index which covers the named columns
wxCookieType cookie;
wxTreeItemId collItem = browser->GetFirstChild(GetId(), cookie);
while (collItem)
{
pgObject *data = browser->GetObject(collItem);
if (data && data->IsCollection() && (data->GetMetaType() == PGM_CONSTRAINT || data->GetMetaType() == PGM_INDEX))
{
wxCookieType cookie2;
wxTreeItemId item = browser->GetFirstChild(collItem, cookie2);
while (item)
{
pgIndex *index = (pgIndex *)browser->GetObject(item);
if (index && (index->GetMetaType() == PGM_INDEX || index->GetMetaType() == PGM_PRIMARYKEY
|| index->GetMetaType() == PGM_UNIQUE || index->GetMetaType() == PGM_EXCLUDE))
{
index->ShowTreeDetail(browser);
if (collist == index->GetColumns() ||
collist + wxT(",") == index->GetColumns().Left(collist.Length() + 1))
return index->GetName();
}
item = browser->GetNextChild(collItem, cookie2);
}
}
collItem = browser->GetNextChild(GetId(), cookie);
}
return wxEmptyString;
}
wxString pgTable::GetCols(ctlTree *browser, size_t indent, wxString &QMs, bool withQM)
{
wxString sql;
wxString line;
int colcount = 0;
pgCollection *columns = browser->FindCollection(columnFactory, GetId());
if (columns)
{
columns->ShowTreeDetail(browser);
treeObjectIterator colIt(browser, columns);
pgColumn *column;
while ((column = (pgColumn *)colIt.GetNextObject()) != 0)
{
column->ShowTreeDetail(browser);
if (column->GetColNumber() > 0)
{
if (colcount++)
{
line += wxT(", ");
QMs += wxT(", ");
}
if (line.Length() > 60)
{
if (!sql.IsEmpty())
{
sql += wxT("\n") + wxString(' ', indent);
}
sql += line;
line = wxEmptyString;
QMs += wxT("\n") + wxString(' ', indent);
}
line += column->GetQuotedIdentifier();
if (withQM)
line += wxT("=?");
QMs += wxT("?");
}
}
}
if (!line.IsEmpty())
{
if (!sql.IsEmpty())
sql += wxT("\n") + wxString(' ', indent);
sql += line;
}
return sql;
}
pgCollection *pgTable::GetColumnCollection(ctlTree *browser)
{
pgCollection *columns = browser->FindCollection(columnFactory, GetId());
return columns;
}
pgCollection *pgTable::GetConstraintCollection(ctlTree *browser)
{
pgCollection *constraints = browser->FindCollection(constraintFactory, GetId());
return constraints;
}
wxString pgTable::GetSelectSql(ctlTree *browser)
{
wxString qms;
wxString sql =
wxT("SELECT ") + GetCols(browser, 7, qms, false) + wxT("\n")
wxT(" FROM ") + GetQuotedFullIdentifier() + wxT(";\n");
return sql;
}
wxString pgTable::GetInsertSql(ctlTree *browser)
{
wxString qms;
wxString sql =
wxT("INSERT INTO ") + GetQuotedFullIdentifier() + wxT("(\n")
wxT(" ") + GetCols(browser, 12, qms, false) + wxT(")\n")
wxT(" VALUES (") + qms + wxT(");\n");
return sql;
}
wxString pgTable::GetUpdateSql(ctlTree *browser)
{
wxString qms;
wxString sql =
wxT("UPDATE ") + GetQuotedFullIdentifier() + wxT("\n")
wxT(" SET ") + GetCols(browser, 7, qms, true) + wxT("\n")
wxT(" WHERE <condition>;\n");
return sql;
}
wxString pgTable::GetDeleteSql(ctlTree *browser)
{
wxString sql =
wxT("DELETE FROM ") + GetQuotedFullIdentifier() + wxT("\n")
wxT(" WHERE <condition>;\n");
return sql;
}
bool pgTable::EnableTriggers(const bool b)
{
wxString sql = wxT("ALTER TABLE ") + GetQuotedFullIdentifier() + wxT(" ");
if (!b)
sql += wxT("DISABLE");
else
sql += wxT("ENABLE");
sql += wxT(" TRIGGER ALL");
return GetDatabase()->ExecuteVoid(sql);
}
void pgTable::UpdateRows()
{
pgSet *props = ExecuteSet(wxT("SELECT count(*) AS rows FROM ONLY ") + GetQuotedFullIdentifier());
if (props)
{
rows = props->GetLongLong(0);
delete props;
rowsCounted = true;
}
}
void pgTable::UpdateInheritance()
{
// not checked so far
pgSet *props = ExecuteSet(
wxT("SELECT c.oid, c.relname , nspname\n")
wxT(" FROM pg_inherits i\n")
wxT(" JOIN pg_class c ON c.oid = i.inhparent\n")
wxT(" JOIN pg_namespace n ON n.oid=c.relnamespace\n")
wxT(" WHERE i.inhrelid = ") + GetOidStr() + wxT("\n")
wxT(" ORDER BY inhseqno"));
if (props)
{
inheritedTableCount = 0;
inheritedTables = wxT("");
while (!props->Eof())
{
if (inheritedTableCount)
{
inheritedTables += wxT(", ");
quotedInheritedTables += wxT(", ");
}
inheritedTables += props->GetVal(wxT("relname"));
quotedInheritedTables += GetQuotedSchemaPrefix(props->GetVal(wxT("nspname")))
+ qtIdent(props->GetVal(wxT("relname")));
quotedInheritedTablesList.Add(GetQuotedSchemaPrefix(props->GetVal(wxT("nspname")))
+ qtIdent(props->GetVal(wxT("relname"))));
inheritedTablesOidList.Add(props->GetVal(wxT("oid")));
props->MoveNext();
inheritedTableCount++;
}
delete props;
}
}
void pgTable::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
{
if (!expandedKids)
{
expandedKids = true;
browser->RemoveDummyChild(this);
// Log
wxLogInfo(wxT("Adding child object to table %s"), GetIdentifier().c_str());
browser->AppendCollection(this, columnFactory);
browser->AppendCollection(this, constraintFactory);
browser->AppendCollection(this, indexFactory);
browser->AppendCollection(this, ruleFactory);
browser->AppendCollection(this, triggerFactory);
if (GetConnection() != 0 && GetConnection()->GetIsGreenplum() && GetIsPartitioned())
browser->AppendCollection(this, partitionFactory);
if (GetConnection() != 0 && (!GetPartKeyDef().IsEmpty()||GetIsPartitioned()))
browser->AppendCollection(this, pg_partitionFactory);
// convert list of columns numbers to column names
wxStringTokenizer collist(GetPrimaryKeyColNumbers(), wxT(","));
wxString cn;
while (collist.HasMoreTokens())
{
cn = collist.GetNextToken();
pgSet *set = ExecuteSet(
wxT("SELECT attname\n")
wxT(" FROM pg_attribute\n")
wxT(" WHERE attrelid=") + GetOidStr() + wxT(" AND attnum IN (") + cn + wxT(")"));
if (set)
{
if (!primaryKey.IsNull())
{
quotedPrimaryKey += wxT(", ");
primaryKey += wxT(", ");
}
primaryKey += set->GetVal(0);
quotedPrimaryKey += qtIdent(set->GetVal(0));
delete set;
}
}
if (settings->GetAutoRowCountThreshold() >= GetEstimatedRows())
UpdateRows();
UpdateInheritance();
}
if (properties)
{
CreateListColumns(properties);
properties->AppendItem(_("Name"), GetName());
if (GetConnection() != 0 && GetConnection()->GetIsGreenplum())
{
gpPartition *p = dynamic_cast<gpPartition *>(this);
if (p != 0)
properties->AppendItem(_("Partition Name"), p->GetPartitionName());
}
properties->AppendItem(_("OID"), GetOid());
properties->AppendItem(_("Owner"), GetOwner());
if (GetConnection()->BackendMinimumVersion(8, 0))
properties->AppendItem(_("Tablespace"), tablespace);
properties->AppendItem(_("ACL"), GetAcl());
if (GetConnection()->BackendMinimumVersion(9, 0))
properties->AppendItem(_("Of type"), ofType);
if (GetPrimaryKey().IsNull())
properties->AppendItem(_("Primary key"), _("<no primary key>"));
else
properties->AppendItem(_("Primary key"), GetPrimaryKey());
properties->AppendItem(_("Rows (estimated)"), GetEstimatedRows());
if (GetConnection()->BackendMinimumVersion(8, 2))
properties->AppendItem(_("Fill factor"), GetFillFactor());
if (rowsCounted)
properties->AppendItem(_("Rows (counted)"), rows);
else
properties->AppendItem(_("Rows (counted)"), _("not counted"));
long setId;
wxString clusterName;
long repStat = GetReplicationStatus(browser, &clusterName, &setId);
wxString clusterInfo;
clusterInfo.Printf(_("Cluster \"%s\", set %ld"), clusterName.c_str(), setId);
wxString repString;
switch (repStat)
{
case REPLICATIONSTATUS_SUBSCRIBED:
repString = _("Published");
break;
case REPLICATIONSTATUS_REPLICATED:
repString = _("Replicated");
break;
case REPLICATIONSTATUS_MULTIPLY_PUBLISHED:
repString = _("Replicated");
clusterName = _("Multiple clusters");
break;
default:
break;
}
if (!repString.IsEmpty())
properties->AppendItem(repString, clusterInfo);
properties->AppendYesNoItem(_("Inherits tables"), GetHasSubclass());
properties->AppendItem(_("Inherited tables count"), GetInheritedTableCount());
if (GetInheritedTableCount())
properties->AppendItem(_("Inherited tables"), GetInheritedTables());
if (GetConnection()->BackendMinimumVersion(9, 1))
properties->AppendYesNoItem(_("Unlogged?"), GetUnlogged());
if (!GetConnection()->BackendMinimumVersion(12, 0))
properties->AppendYesNoItem(_("Has OIDs?"), GetHasOids());
if (!GetConnection()->BackendMinimumVersion(12, 0))
properties->AppendYesNoItem(_("System table?"), GetSystemObject());
if (GetConnection()->GetIsPgProEnt() && GetRatio().Len()>0)
properties->AppendItem(_("CFS fragmentation"), GetRatio());
if (GetConnection()->HasFeature(FEATURE_TRACK_COMMIT_TS) && GetCreateTableTS().Len()>0)
properties->AppendItem(_("Create table timestamp"), GetCreateTableTS());
/* Custom AutoVacuum Settings */
if (GetConnection()->BackendMinimumVersion(8, 4) && GetCustomAutoVacuumEnabled())
{
if (GetAutoVacuumEnabled() != 2)
{
properties->AppendItem(_("Table auto-vacuum enabled?"), GetAutoVacuumEnabled() == 1 ? _("Yes") : _("No"));
}
if (!GetAutoVacuumVacuumThreshold().IsEmpty())
properties->AppendItem(_("Table auto-vacuum VACUUM base threshold"), GetAutoVacuumVacuumThreshold());
if (!GetAutoVacuumVacuumScaleFactor().IsEmpty())
properties->AppendItem(_("Table auto-vacuum VACUUM scale factor"), GetAutoVacuumVacuumScaleFactor());
if (!GetAutoVacuumAnalyzeThreshold().IsEmpty())
properties->AppendItem(_("Table auto-vacuum ANALYZE base threshold"), GetAutoVacuumAnalyzeThreshold());
if (!GetAutoVacuumAnalyzeScaleFactor().IsEmpty())
properties->AppendItem(_("Table auto-vacuum ANALYZE scale factor"), GetAutoVacuumAnalyzeScaleFactor());
if (!GetAutoVacuumVacuumCostDelay().IsEmpty())
properties->AppendItem(_("Table auto-vacuum VACUUM cost delay"), GetAutoVacuumVacuumCostDelay());
if (!GetAutoVacuumVacuumCostLimit().IsEmpty())
properties->AppendItem(_("Table auto-vacuum VACUUM cost limit"), GetAutoVacuumVacuumCostLimit());
if (!GetAutoVacuumFreezeMinAge().IsEmpty())
properties->AppendItem(_("Table auto-vacuum FREEZE minimum age"), GetAutoVacuumFreezeMinAge());
if (!GetAutoVacuumFreezeMaxAge().IsEmpty())
properties->AppendItem(_("Table auto-vacuum FREEZE maximum age"), GetAutoVacuumFreezeMaxAge());
if (!GetAutoVacuumFreezeTableAge().IsEmpty())
properties->AppendItem(_("Table auto-vacuum FREEZE table age"), GetAutoVacuumFreezeTableAge());
}
/* Custom TOAST-TABLE AutoVacuum Settings */
if (GetConnection()->BackendMinimumVersion(8, 4) &&
GetHasToastTable() &&
GetToastCustomAutoVacuumEnabled())
{
if (GetToastAutoVacuumEnabled() != 2)
{
properties->AppendItem(_("Toast auto-vacuum enabled?"), GetToastAutoVacuumEnabled() == 1 ? _("Yes") : _("No"));
}
if (!GetToastAutoVacuumVacuumThreshold().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum VACUUM base threshold"), GetToastAutoVacuumVacuumThreshold());
if (!GetToastAutoVacuumVacuumScaleFactor().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum VACUUM scale factor"), GetToastAutoVacuumVacuumScaleFactor());
if (!GetToastAutoVacuumVacuumCostDelay().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum VACUUM cost delay"), GetToastAutoVacuumVacuumCostDelay());
if (!GetToastAutoVacuumVacuumCostLimit().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum VACUUM cost limit"), GetToastAutoVacuumVacuumCostLimit());
if (!GetToastAutoVacuumFreezeMinAge().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum FREEZE minimum age"), GetToastAutoVacuumFreezeMinAge());
if (!GetToastAutoVacuumFreezeMaxAge().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum FREEZE maximum age"), GetToastAutoVacuumFreezeMaxAge());
if (!GetToastAutoVacuumFreezeTableAge().IsEmpty())
properties->AppendItem(_("Toast auto-vacuum FREEZE table age"), GetToastAutoVacuumFreezeTableAge());
}
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));
}
}
}
}
if (form && GetVacuumHint() && !hintShown)
{
ShowHint(form, false);
}
}
bool pgTable::GetCanHint()
{
return (GetVacuumHint() || primaryKey.IsEmpty());
}
bool pgTable::GetVacuumHint()
{
bool canHint = false;
if (rowsCounted)
{
if (!estimatedRows || (estimatedRows == 1000 && rows.GetValue() != 1000))
canHint = (rows >= 20);
else
{
double rowsDbl = (wxLongLong_t)rows.GetValue();
double quot = rowsDbl * 10. / estimatedRows;
canHint = ((quot > 12 || quot < 8) && (rowsDbl < estimatedRows - 20. || rowsDbl > estimatedRows + 20.));
}
}
else if (estimatedRows == 1000)
{
canHint = true;
}
return canHint;
}
void pgTable::ShowHint(frmMain *form, bool force)
{
hintShown = true;
int rc;
if (force)
{
wxArrayString hints;
if (GetVacuumHint())
hints.Add(HINT_VACUUM);
if (primaryKey.IsEmpty())
hints.Add(HINT_PRIMARYKEY);
rc = frmHint::ShowHint(form, hints, GetFullIdentifier(), force);
}
else
rc = frmHint::ShowHint(form, HINT_VACUUM, GetFullIdentifier(), force);
if (rc == HINT_RC_FIX)
{
frmMaintenance *frm = new frmMaintenance(form, this);
frm->Go();
}
}
pgObject *pgTable::Refresh(ctlTree *browser, const wxTreeItemId item)
{
pgTable *table = 0;
pgCollection *coll = browser->GetParentCollection(item);
if (coll)
table = (pgTable *)tableFactory.CreateObjects(coll, 0, wxT("\n AND rel.oid=") + GetOidStr());
return table;
}
bool pgTable::HasPgstattuple()
{
return GetConnection()->HasFeature(FEATURE_PGSTATTUPLE);
}
void pgTable::iSetTriggersEnabled(ctlTree *browser, bool enable)
{
pgCollection *triggers = browser->FindCollection(triggerFactory, GetId());
if (triggers)
{
triggers->ShowTreeDetail(browser);
treeObjectIterator trgIt(browser, triggers);
pgTrigger *trigger;
while ((trigger = (pgTrigger *)trgIt.GetNextObject()) != 0)
{
trigger->SetEnabled(browser, enable);
}
}
}
///////////////////////////////////////////////////////////
pgTableCollection::pgTableCollection(pgaFactory *factory, pgSchema *sch)
: pgSchemaObjCollection(factory, sch)
{
}
wxString pgTableCollection::GetTranslatedMessage(int kindOfMessage) const
{
wxString message = wxEmptyString;
switch (kindOfMessage)
{
case RETRIEVINGDETAILS:
message = _("Retrieving details on tables");
break;
case REFRESHINGDETAILS:
message = _("Refreshing tables");
break;
case GRANTWIZARDTITLE:
message = _("Privileges for tables");
break;
case STATISTICSREPORT:
message = _("Tables statistics report");
break;
case OBJSTATISTICS:
message = _("Tables statistics");
break;
case OBJECTSLISTREPORT:
message = _("Tables list report");
break;
}
return message;
}
void pgTableCollection::ShowStatistics(frmMain *form, ctlListView *statistics)
{
ShowStatisticsTables(form, statistics, this);
return;
wxLogInfo(wxT("Displaying statistics for tables on %s"), GetSchema()->GetIdentifier().c_str());
bool hasSize = GetConnection()->HasFeature(FEATURE_SIZE);
// Add the statistics view columns
statistics->ClearAll();
statistics->AddColumn(_("Table Name"));
if (hasSize)
statistics->AddColumn(_("Size"), 50);
if (GetConnection()->GetIsPgProEnt()) statistics->AddColumn(_("CFS %"));
statistics->AddColumn(_("Live tuples"));
statistics->AddColumn(_("Tuples inserted"));
statistics->AddColumn(_("Tuples updated"));
statistics->AddColumn(_("Tuples deleted"));
if (GetConnection()->BackendMinimumVersion(8, 3))
{
statistics->AddColumn(_("Tuples HOT updated"));
statistics->AddColumn(_("Dead tuples"));
}
if (GetConnection()->BackendMinimumVersion(8, 2))
{
statistics->AddColumn(_("Last vacuum"));
statistics->AddColumn(_("Last autovacuum"));
statistics->AddColumn(_("Last analyze"));
statistics->AddColumn(_("Last autoanalyze"));
}
if (GetConnection()->BackendMinimumVersion(9, 1))
{
statistics->AddColumn(_("Vacuum counter"));
statistics->AddColumn(_("Autovacuum counter"));
statistics->AddColumn(_("Analyze counter"));
statistics->AddColumn(_("Autoanalyze counter"));
}
wxString sql = wxT("SELECT st.relname, n_tup_ins, n_tup_upd, n_tup_del");
if (GetConnection()->BackendMinimumVersion(8, 3))
sql += wxT(", n_tup_hot_upd, n_live_tup, n_dead_tup");
if (GetConnection()->BackendMinimumVersion(8, 2))
sql += wxT(", last_vacuum, last_autovacuum, last_analyze, last_autoanalyze");
if (GetConnection()->BackendMinimumVersion(9, 1))
sql += wxT(", vacuum_count, autovacuum_count, analyze_count, autoanalyze_count");
if (hasSize)
sql += wxT(", pg_size_pretty(pg_relation_size(st.relid)")
wxT(" + CASE WHEN cl.reltoastrelid = 0 THEN 0 ELSE pg_relation_size(cl.reltoastrelid) + COALESCE((SELECT SUM(pg_relation_size(indexrelid)) FROM pg_index WHERE indrelid=cl.reltoastrelid)::int8, 0) END")
wxT(" + COALESCE((SELECT SUM(pg_relation_size(indexrelid)) FROM pg_index WHERE indrelid=st.relid)::int8, 0)) AS size");
if (GetConnection()->GetIsPgProEnt()) sql += wxT(",left((cfs_fragmentation(cl.oid)*100)::text,5)::text AS cfs_ratio");
sql += wxT("\n FROM pg_stat_all_tables st")
wxT(" JOIN pg_class cl on cl.oid=st.relid\n")
wxT(" WHERE schemaname = ") + qtDbString(GetSchema()->GetName())
+ wxT("\n ORDER BY relname");
pgSet *stats = GetDatabase()->ExecuteSet(sql);
if (stats)
{
long pos = 0;
int i;
while (!stats->Eof())
{
i = 1;
statistics->InsertItem(pos, stats->GetVal(wxT("relname")), PGICON_STATISTICS);
if (hasSize)
statistics->SetItem(pos, i++, stats->GetVal(wxT("size")));
if (GetConnection()->GetIsPgProEnt()) statistics->SetItem(pos, i++, stats->GetVal(wxT("cfs_ratio")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("n_tup_ins")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("n_tup_upd")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("n_tup_del")));
if (GetConnection()->BackendMinimumVersion(8, 3))
{
statistics->SetItem(pos, i++, stats->GetVal(wxT("n_tup_hot_upd")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("n_live_tup")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("n_dead_tup")));
}
if (GetConnection()->BackendMinimumVersion(8, 2))
{
statistics->SetItem(pos, i++, stats->GetVal(wxT("last_vacuum")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("last_autovacuum")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("last_analyze")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("last_autoanalyze")));
if (stats->GetVal(wxT("last_analyze")).IsEmpty()&& stats->GetVal(wxT("last_autoanalyze")).IsEmpty())
statistics->SetItemBackgroundColour(pos, wxColour(wxT("#FF8028")));
}
if (GetConnection()->BackendMinimumVersion(9, 1))
{
statistics->SetItem(pos, i++, stats->GetVal(wxT("vacuum_count")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("autovacuum_count")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("analyze_count")));
statistics->SetItem(pos, i++, stats->GetVal(wxT("autoanalyze_count")));
}
stats->MoveNext();
pos++;
}
delete stats;
}
statistics->SetColumnWidth(0,wxLIST_AUTOSIZE);
}
///////////////////////////////////////////////////////////
void pgTable::ShowStatistics(frmMain *form, ctlListView *statistics)
{
if (GetIsPartitioned()) {
ShowStatisticsTables(form,statistics,this);
return;
}
wxString sql =
wxT("SELECT seq_scan AS ") + qtIdent(_("Sequential Scans")) +
wxT(", seq_tup_read AS ") + qtIdent(_("Sequential Tuples Read")) +
wxT(", idx_scan AS ") + qtIdent(_("Index Scans")) +
wxT(", idx_tup_fetch AS ") + qtIdent(_("Index Tuples Fetched")) +
wxT(", n_tup_ins AS ") + qtIdent(_("Tuples Inserted")) +
wxT(", n_tup_upd AS ") + qtIdent(_("Tuples Updated")) +
wxT(", n_tup_del AS ") + qtIdent(_("Tuples Deleted"));
if (GetConnection()->BackendMinimumVersion(8, 3))
{
sql +=
wxT(", n_tup_hot_upd AS ") + qtIdent(_("Tuples HOT Updated")) +
wxT(", n_live_tup AS ") + qtIdent(_("Live Tuples")) +
wxT(", n_dead_tup AS ") + qtIdent(_("Dead Tuples"));
}
sql += wxT(", heap_blks_read AS ") + qtIdent(_("Heap Blocks Read")) +
wxT(", heap_blks_hit AS ") + qtIdent(_("Heap Blocks Hit")) +
wxT(", idx_blks_read AS ") + qtIdent(_("Index Blocks Read")) +
wxT(", idx_blks_hit AS ") + qtIdent(_("Index Blocks Hit")) +
wxT(", toast_blks_read AS ") + qtIdent(_("Toast Blocks Read")) +
wxT(", toast_blks_hit AS ") + qtIdent(_("Toast Blocks Hit")) +
wxT(", tidx_blks_read AS ") + qtIdent(_("Toast Index Blocks Read")) +
wxT(", tidx_blks_hit AS ") + qtIdent(_("Toast Index Blocks Hit"));
if (GetConnection()->BackendMinimumVersion(8, 2))
{
sql +=
wxT(", last_vacuum AS ") + qtIdent(_("Last Vacuum")) +
wxT(", last_autovacuum AS ") + qtIdent(_("Last Autovacuum")) +
wxT(", last_analyze AS ") + qtIdent(_("Last Analyze")) +
wxT(", last_autoanalyze AS ") + qtIdent(_("Last Autoanalyze"));
}
if (GetConnection()->BackendMinimumVersion(9, 1))
{
sql +=
wxT(", vacuum_count AS ") + qtIdent(_("Vacuum counter")) +
wxT(", autovacuum_count AS ") + qtIdent(_("Autovacuum counter")) +
wxT(", analyze_count AS ") + qtIdent(_("Analyze counter")) +
wxT(", autoanalyze_count AS ") + qtIdent(_("Autoanalyze counter"));
}
if (GetConnection()->HasFeature(FEATURE_SIZE))
{
sql += wxT(", pg_size_pretty(pg_relation_size(stat.relid)) AS ") + qtIdent(_("Table Size"))
+ wxT(", CASE WHEN cl.reltoastrelid = 0 THEN ") + qtDbString(_("none")) + wxT(" ELSE pg_size_pretty(pg_relation_size(cl.reltoastrelid)+ COALESCE((SELECT SUM(pg_relation_size(indexrelid)) FROM pg_index WHERE indrelid=cl.reltoastrelid)::int8, 0)) END AS ") + qtIdent(_("Toast Table Size"))
+ wxT(", pg_size_pretty(COALESCE((SELECT SUM(pg_relation_size(indexrelid)) FROM pg_index WHERE indrelid=stat.relid)::int8, 0)) AS ") + qtIdent(_("Indexes Size"));
}
if (showExtendedStatistics)
{
sql += wxT("\n")
wxT(", tuple_count AS ") + qtIdent(_("Tuple Count")) + wxT(",\n")
wxT(" pg_size_pretty(tuple_len) AS ") + qtIdent(_("Tuple Length")) + wxT(",\n")
wxT(" tuple_percent AS ") + qtIdent(_("Tuple Percent")) + wxT(",\n")
wxT(" dead_tuple_count AS ") + qtIdent(_("Dead Tuple Count")) + wxT(",\n")
wxT(" pg_size_pretty(dead_tuple_len) AS ") + qtIdent(_("Dead Tuple Length")) + wxT(",\n")
wxT(" dead_tuple_percent AS ") + qtIdent(_("Dead Tuple Percent")) + wxT(",\n")
wxT(" pg_size_pretty(free_space) AS ") + qtIdent(_("Free Space")) + wxT(",\n")
wxT(" free_percent AS ") + qtIdent(_("Free Percent")) + wxT("\n")
wxT(" FROM pgstattuple('") + GetQuotedFullIdentifier() + wxT("'), pg_stat_all_tables stat");
}
else
{
sql += wxT("\n")
wxT(" FROM pg_stat_all_tables stat");
}
sql += wxT("\n")
wxT(" JOIN pg_statio_all_tables statio ON stat.relid = statio.relid\n")
wxT(" JOIN pg_class cl ON cl.oid=stat.relid\n")
wxT(" WHERE stat.relid = ") + GetOidStr();
DisplayStatistics(statistics, sql);
}
pgObject *pgTableFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
{
wxString query;
pgTable *table = 0;
// Greenplum returns reltuples and relpages as tuples per segmentDB and pages per segmentDB,
// so we need to multiply them by the number of segmentDBs to get reasonable values.
long gp_segments = 1;
if (collection->GetConnection()->GetIsGreenplum())
{
query = wxT("SELECT count(*) AS gp_segments from pg_catalog.gp_configuration where definedprimary = 't' and content >= 0");
gp_segments = StrToLong(collection->GetDatabase()->ExecuteScalar(query));
if (gp_segments <= 1)
gp_segments = 1;
}
pgSet *tables;
if (collection->GetConnection()->BackendMinimumVersion(8, 0))
{
query = wxT("SELECT rel.oid, rel.relname, rel.reltablespace AS spcoid, spc.spcname, pg_get_userbyid(rel.relowner) AS relowner, rel.relacl, ")
wxT("rel.relhassubclass, rel.reltuples, des.description, con.conname, con.conkey,\n")
wxT(" EXISTS(select 1 FROM pg_trigger\n")
wxT(" JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'\n")
wxT(" JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'\n")
wxT(" WHERE tgrelid=rel.oid) AS isrepl,\n");
if (collection->GetConnection()->BackendMinimumVersion(9, 0))
{
query += wxT(" (select count(*) FROM pg_trigger\n")
wxT(" WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount\n");
}
else
{
query += wxT(" (select count(*) FROM pg_trigger\n")
wxT(" WHERE tgrelid=rel.oid AND tgisconstraint = FALSE) AS triggercount\n");
}
if (collection->GetConnection()->BackendMinimumVersion(9, 1))
query += wxT(", rel.relpersistence \n");
if (collection->GetConnection()->BackendMinimumVersion(8, 2))
query += wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor \n");
if (collection->GetConnection()->GetIsGreenplum())
{
query += wxT(", gpd.localoid, gpd.attrnums \n");
query += wxT(", substring(array_to_string(rel.reloptions, ',') from 'appendonly=([a-z]*)') AS appendonly \n");
query += wxT(", substring(array_to_string(rel.reloptions, ',') from 'compresslevel=([0-9]*)') AS compresslevel \n");
query += wxT(", substring(array_to_string(rel.reloptions, ',') from 'orientation=([a-z]*)') AS orientation \n");
query += wxT(", substring(array_to_string(rel.reloptions, ',') from 'compresstype=([a-z0-9]*)') AS compresstype \n");
query += wxT(", substring(array_to_string(rel.reloptions, ',') from 'blocksize=([0-9]*)') AS blocksize \n");
query += wxT(", substring(array_to_string(rel.reloptions, ',') from 'checksum=([a-z]*)') AS checksum \n");
if (collection->GetConnection()->GetIsGreenplum() && collection->GetConnection()->BackendMinimumVersion(8, 2, 9))
query += wxT(", rel.oid in (select parrelid from pg_partition) as ispartitioned\n");
}
else if (collection->GetConnection()->BackendMinimumVersion(8, 4))
{
query += wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') AS autovacuum_enabled \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age \n")
wxT(", substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') AS toast_autovacuum_enabled \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age \n")
wxT(", substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age \n")
wxT(", rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions \n")
wxT(", (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable\n");
}
if (collection->GetConnection()->BackendMinimumVersion(9, 0))
query += wxT(", rel.reloftype, typ.typname\n");
if (collection->GetConnection()->HasFeature(FEATURE_TRACK_COMMIT_TS))
query += wxT(", pg_xact_commit_timestamp(typ2.xmin) create_ts\n");
if (collection->GetDatabase()->BackendMinimumVersion(9, 1))
{
query += wxT(",\n(SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS labels");
query += wxT(",\n(SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=rel.oid AND sl2.objsubid=0) AS providers");
}
wxString pg10=wxEmptyString;
if (collection->GetDatabase()->BackendMinimumVersion(10, 0))
{
query += wxT(",case when lk.relation=rel.oid then null else pg_get_partkeydef(rel.oid) end \n AS partkeydef");
query += wxT(",case when lk.relation=rel.oid then null else pg_get_expr(rel.relpartbound, rel.oid) end \n AS partexp");
query += wxT(",(select count(*)from pg_inherits ii where ii.inhparent=rel.oid) >0 AS ispartitioned");
//pg10=wxT("pg_get_expr(rel.relpartbound, rel.oid) is null and");
pg10=wxT("(rel.relpartbound is null and i.inhrelid is null) and");
//query += wxT(",\n(SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=rel.oid AND sl2.objsubid=0) AS providers");
}
// 'ALTER STATISTICS '||substring('CREATE STATISTICS public.tab_a (dependencies) ON c1, c3 FROM a' from 'ICS (.+?)\s\(')||' OWNER TO '||
//select relation from pg_locks where locktype='relation' and granted=true and mode='AccessExclusiveLock'
if (collection->GetDatabase()->connection()->GetIsPgProEnt()) query += wxT(",left((cfs_fragmentation(rel.oid)*100)::text,5)::text AS cfs_ratio");
else query += wxT(",null::text AS cfs_ratio");
if (collection->GetDatabase()->BackendMinimumVersion(10, 0))
{
//query += wxT(",\n pg_get_statisticsobjdef(stat_ext.oid) AS stat_stmt");
//query += wxT(",\nCASE WHEN stat_ext.stxowner<>rel.relowner then 'ALTER STATISTICS '||substring(pg_get_statisticsobjdef(stat_ext.oid) from 'ICS (.+?)\\s\\(')||' OWNER TO '||stat_ext.stxowner::regrole else null end AS alter_stmt");
query += ",(select string_agg(pg_get_statisticsobjdef(stat_ext.oid)||CASE WHEN stat_ext.stxowner<>rl.relowner then E';\\nALTER STATISTICS '||substring(pg_get_statisticsobjdef(stat_ext.oid) from 'ICS (.+?)\\s')||' OWNER TO '||stat_ext.stxowner::regrole else '' end"
;
if (collection->GetDatabase()->BackendMinimumVersion(13, 0)) {
query += "||CASE WHEN stat_ext.stxstattarget<>-1 then E';\\nALTER STATISTICS '||substring(pg_get_statisticsobjdef(stat_ext.oid) from 'ICS (.+?)\\s')||' SET STATISTICS '||stat_ext.stxstattarget else '' end";
}
query += ",E';\\n' order by stat_ext.stxrelid) stat_stmt from pg_class rl join pg_statistic_ext stat_ext on rl.oid=stat_ext.stxrelid where stat_ext.stxrelid=rel.oid) stat_stmt";
}
query += wxT(" FROM pg_class rel\n")
wxT(" LEFT JOIN pg_locks lk ON locktype='relation' and granted=true and mode='AccessExclusiveLock' and relation=rel.oid\n")
wxT(" LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace\n")
wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)\n")
wxT(" LEFT OUTER JOIN pg_inherits i on i.inhrelid=rel.oid\n")
wxT(" LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'\n");
// Add the toast table for vacuum parameters.
if (collection->GetConnection()->BackendMinimumVersion(8, 4))
query += wxT(" LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid\n");
if (collection->GetConnection()->GetIsGreenplum())
query += wxT(" LEFT OUTER JOIN gp_distribution_policy gpd ON gpd.localoid=rel.oid\n");
if (collection->GetConnection()->BackendMinimumVersion(9, 0))
query += wxT("LEFT JOIN pg_type typ ON rel.reloftype=typ.oid\n");
if (collection->GetConnection()->HasFeature(FEATURE_TRACK_COMMIT_TS))
query += wxT("LEFT JOIN pg_type typ2 ON rel.oid=typ2.typrelid\n");
query += wxT(" WHERE ")+pg10+wxT(" rel.relkind IN ('r','s','t','p') AND rel.relnamespace = ") + collection->GetSchema()->GetOidStr() + wxT("\n");
// Greenplum: Eliminate (sub)partitions from the display, only show the parent partitioned table
// and eliminate external tables
if (collection->GetConnection()->GetIsGreenplum() && collection->GetConnection()->BackendMinimumVersion(8, 2, 9))
query += wxT("AND rel.relstorage <> 'x' AND rel.oid NOT IN (SELECT parchildrelid from pg_partition_rule)");
// only show the parent partitioned table
if (collection->GetConnection()->BackendMinimumVersion(10, 0)){
//addIcon(tables_png_img);
query += wxT("AND (not (rel.relkind='r' and rel.relpartbound IS NOT NULL)) ");
}
query += restriction +
wxT(" ORDER BY rel.relname");
}
else
{
query = wxT("SELECT rel.oid, rel.relname, pg_get_userbyid(rel.relowner) AS relowner, rel.relacl, ")
wxT("rel.relhassubclass, rel.reltuples, des.description, con.conname, con.conkey,\n")
wxT(" (select count(*) FROM pg_trigger\n")
wxT(" WHERE tgrelid=rel.oid AND tgisconstraint = FALSE) AS triggercount,\n")
wxT(" EXISTS(select 1 FROM pg_trigger\n")
wxT(" JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'\n")
wxT(" JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'\n")
wxT(" WHERE tgrelid=rel.oid) AS isrepl\n")
wxT(" FROM pg_class rel\n")
wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass)\n")
wxT(" LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p'\n")
wxT(" WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = ") + collection->GetSchema()->GetOidStr() + wxT("\n")
+ restriction +
wxT(" ORDER BY rel.relname");
}
tables = collection->GetDatabase()->ExecuteSet(query);
if (tables)
{
while (!tables->Eof())
{
table = new pgTable(collection->GetSchema(), tables->GetVal(wxT("relname")));
table->iSetOid(tables->GetOid(wxT("oid")));
table->iSetOwner(tables->GetVal(wxT("relowner")));
table->iSetAcl(tables->GetVal(wxT("relacl")));
table->iSetRatio(tables->GetVal(wxT("cfs_ratio")));
if (collection->GetConnection()->HasFeature(FEATURE_TRACK_COMMIT_TS)) {
table->iSetCreateTableTS(tables->GetVal(wxT("create_ts")));
}
if (collection->GetConnection()->BackendMinimumVersion(8, 0))
{
if (tables->GetOid(wxT("spcoid")) == 0)
table->iSetTablespaceOid(collection->GetDatabase()->GetTablespaceOid());
else
table->iSetTablespaceOid(tables->GetOid(wxT("spcoid")));
if (tables->GetVal(wxT("spcname")) == wxEmptyString)
table->iSetTablespace(collection->GetDatabase()->GetTablespace());
else
table->iSetTablespace(tables->GetVal(wxT("spcname")));
}
if (collection->GetConnection()->BackendMinimumVersion(9, 0))
{
table->iSetOfTypeOid(tables->GetOid(wxT("reloftype")));
table->iSetOfType(tables->GetVal(wxT("typname")));
}
else
{
table->iSetOfTypeOid(0);
table->iSetOfType(wxT(""));
}
table->iSetComment(tables->GetVal(wxT("description")));
if (collection->GetConnection()->BackendMinimumVersion(9, 1))
table->iSetUnlogged(tables->GetVal(wxT("relpersistence")) == wxT("u"));
else
table->iSetUnlogged(false);
table->iSetHasOids(false);
table->iSetEstimatedRows(tables->GetDouble(wxT("reltuples")) * gp_segments);
if (collection->GetConnection()->BackendMinimumVersion(8, 2))
{
table->iSetFillFactor(tables->GetVal(wxT("fillfactor")));
}
if (collection->GetConnection()->BackendMinimumVersion(8, 4))
{
table->iSetRelOptions(tables->GetVal(wxT("reloptions")));
if (table->GetCustomAutoVacuumEnabled())
{
if (tables->GetVal(wxT("autovacuum_enabled")).IsEmpty())
table->iSetAutoVacuumEnabled(2);
else if (tables->GetBool(wxT("autovacuum_enabled")))
table->iSetAutoVacuumEnabled(1);
else
table->iSetAutoVacuumEnabled(0);
table->iSetAutoVacuumVacuumThreshold(tables->GetVal(wxT("autovacuum_vacuum_threshold")));
table->iSetAutoVacuumVacuumScaleFactor(tables->GetVal(wxT("autovacuum_vacuum_scale_factor")));
table->iSetAutoVacuumAnalyzeThreshold(tables->GetVal(wxT("autovacuum_analyze_threshold")));
table->iSetAutoVacuumAnalyzeScaleFactor(tables->GetVal(wxT("autovacuum_analyze_scale_factor")));
table->iSetAutoVacuumVacuumCostDelay(tables->GetVal(wxT("autovacuum_vacuum_cost_delay")));
table->iSetAutoVacuumVacuumCostLimit(tables->GetVal(wxT("autovacuum_vacuum_cost_limit")));
table->iSetAutoVacuumFreezeMinAge(tables->GetVal(wxT("autovacuum_freeze_min_age")));
table->iSetAutoVacuumFreezeMaxAge(tables->GetVal(wxT("autovacuum_freeze_max_age")));
table->iSetAutoVacuumFreezeTableAge(tables->GetVal(wxT("autovacuum_freeze_table_age")));
}
table->iSetHasToastTable(tables->GetBool(wxT("hastoasttable")));
if (table->GetHasToastTable())
{
table->iSetToastRelOptions(tables->GetVal(wxT("toast_reloptions")));
if (table->GetToastCustomAutoVacuumEnabled())
{
if (tables->GetVal(wxT("toast_autovacuum_enabled")).IsEmpty())
table->iSetToastAutoVacuumEnabled(2);
else if (tables->GetBool(wxT("toast_autovacuum_enabled")))
table->iSetToastAutoVacuumEnabled(1);
else
table->iSetToastAutoVacuumEnabled(0);
table->iSetToastAutoVacuumVacuumThreshold(tables->GetVal(wxT("toast_autovacuum_vacuum_threshold")));
table->iSetToastAutoVacuumVacuumScaleFactor(tables->GetVal(wxT("toast_autovacuum_vacuum_scale_factor")));
table->iSetToastAutoVacuumVacuumCostDelay(tables->GetVal(wxT("toast_autovacuum_vacuum_cost_delay")));
table->iSetToastAutoVacuumVacuumCostLimit(tables->GetVal(wxT("toast_autovacuum_vacuum_cost_limit")));
table->iSetToastAutoVacuumFreezeMinAge(tables->GetVal(wxT("toast_autovacuum_freeze_min_age")));
table->iSetToastAutoVacuumFreezeMaxAge(tables->GetVal(wxT("toast_autovacuum_freeze_max_age")));
table->iSetToastAutoVacuumFreezeTableAge(tables->GetVal(wxT("toast_autovacuum_freeze_table_age")));
}
}
}
table->iSetHasSubclass(tables->GetBool(wxT("relhassubclass")));
table->iSetPrimaryKeyName(tables->GetVal(wxT("conname")));
table->iSetIsReplicated(tables->GetBool(wxT("isrepl")));
table->iSetTriggerCount(tables->GetLong(wxT("triggercount")));
wxString cn = tables->GetVal(wxT("conkey"));
cn = cn.Mid(1, cn.Length() - 2);
table->iSetPrimaryKeyColNumbers(cn);
table->iSetPartitionDef(wxT(""));
table->iSetIsPartitioned(false);
if (collection->GetConnection()->BackendMinimumVersion(10, 0))
{
table->iSetPartKeyDef(tables->GetVal(wxT("partkeydef")));
table->iSetPartExp(tables->GetVal(wxT("partexp")));
table->iSetIsPartitioned(tables->GetBool(wxT("ispartitioned")));
wxString st = tables->GetVal(wxT("stat_stmt"));
//wxString at = tables->GetVal(wxT("alter_stmt"));
if (!st.IsEmpty()) if ((st.Right(1) != ";") ) st=st+wxT(";\n");
table->iSetStatExt(st);
}
if (collection->GetConnection()->GetIsGreenplum())
{
Oid lo = tables->GetOid(wxT("localoid"));
wxString db = tables->GetVal(wxT("attrnums"));
db = db.Mid(1, db.Length() - 2);
table->iSetDistributionColNumbers(db);
if (lo > 0 && db.Length() == 0)
table->iSetDistributionIsRandom();
table->iSetAppendOnly(tables->GetVal(wxT("appendonly")));
table->iSetCompressLevel(tables->GetVal(wxT("compresslevel")));
table->iSetOrientation(tables->GetVal(wxT("orientation")));
table->iSetCompressType(tables->GetVal(wxT("compresstype")));
table->iSetBlocksize(tables->GetVal(wxT("blocksize")));
table->iSetChecksum(tables->GetVal(wxT("checksum")));
if (collection->GetConnection()->BackendMinimumVersion(8, 2, 9))
{
table->iSetIsPartitioned(tables->GetBool(wxT("ispartitioned")));
}
}
if (collection->GetConnection()->BackendMinimumVersion(9, 1))
{
table->iSetProviders(tables->GetVal(wxT("providers")));
table->iSetLabels(tables->GetVal(wxT("labels")));
}
if (browser)
{
browser->AppendObject(collection, table);
tables->MoveNext();
}
else
break;
}
delete tables;
}
return table;
}
bool pgTableObjCollection::CanCreate()
{
// We don't create sub-objects of Views or External tables
if (GetTable()->GetMetaType() == PGM_VIEW || GetTable()->GetMetaType() == GP_EXTTABLE)
return false;
return GetSchema()->GetCreatePrivilege();
}
#include "images/table.pngc"
#include "images/table-repl.pngc"
#include "images/table-repl-sm.pngc"
#include "images/table-sm.pngc"
#include "images/tables.pngc"
pgTableFactory::pgTableFactory()
: pgSchemaObjFactory(__("Table"), __("New Table..."), __("Create a new Table."), table_png_img, table_sm_png_img)
{
metaType = PGM_TABLE;
if (WantSmallIcon())
replicatedIconId = addIcon(table_repl_sm_png_img);
else
replicatedIconId = addIcon(table_repl_png_img);
partitionsIconId=addIcon(tables_png_img);
}
pgCollection *pgTableFactory::CreateCollection(pgObject *obj)
{
return new pgTableCollection(GetCollectionFactory(), (pgSchema *)obj);
}
pgTableFactory tableFactory;
static pgaCollectionFactory cf(&tableFactory, __("Tables"), tables_png_img);
pgCollection *pgTableObjFactory::CreateCollection(pgObject *obj)
{
return new pgTableObjCollection(GetCollectionFactory(), (pgTable *)obj);
}
countRowsFactory::countRowsFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("&Count"), _("Count rows in the selected object."));
}
wxWindow *countRowsFactory::StartDialog(frmMain *form, pgObject *obj)
{
form->StartMsg(_("Counting rows"));
((pgTable *)obj)->UpdateRows();
wxTreeItemId item = form->GetBrowser()->GetSelection();
if (obj == form->GetBrowser()->GetObject(item))
obj->ShowTreeDetail(form->GetBrowser(), 0, form->GetProperties());
form->EndMsg();
return 0;
}
bool countRowsFactory::CheckEnable(pgObject *obj)
{
return obj && ( obj->IsCreatedBy(pg_partitionFactory) ||obj->IsCreatedBy(tableFactory));
}
executePgstattupleFactory::executePgstattupleFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("&Extended table statistics"), _("Get extended statistics via pgstattuple for the selected object."), wxITEM_CHECK);
}
wxWindow *executePgstattupleFactory::StartDialog(frmMain *form, pgObject *obj)
{
if (!((pgTable *)obj)->GetShowExtendedStatistics())
{
((pgTable *)obj)->iSetShowExtendedStatistics(true);
wxTreeItemId item = form->GetBrowser()->GetSelection();
if (obj == form->GetBrowser()->GetObject(item))
form->SelectStatisticsTab();
}
else
((pgTable *)obj)->iSetShowExtendedStatistics(false);
form->GetMenuFactories()->CheckMenu(obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar());
return 0;
}
bool executePgstattupleFactory::CheckEnable(pgObject *obj)
{
return obj && ( obj->IsCreatedBy(pg_partitionFactory) ||obj->IsCreatedBy(tableFactory)) && ((pgTable *)obj)->HasPgstattuple();
}
bool executePgstattupleFactory::CheckChecked(pgObject *obj)
{
return obj && ( obj->IsCreatedBy(pg_partitionFactory) ||obj->IsCreatedBy(tableFactory)) && ((pgTable *)obj)->GetShowExtendedStatistics();
}
disableAllTriggersFactory::disableAllTriggersFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("Disable triggers"), _("Disable all triggers on the selected table."));
}
wxWindow *disableAllTriggersFactory::StartDialog(frmMain *form, pgObject *obj)
{
if (wxMessageBox(_("Are you sure you wish to disable all triggers on this table?"), _("Disable triggers"), wxYES_NO) != wxYES)
return 0;
if (!((pgTable *)obj)->EnableTriggers(false))
return 0;
((pgTable *)obj)->iSetTriggersEnabled(form->GetBrowser(), false);
return 0;
}
bool disableAllTriggersFactory::CheckEnable(pgObject *obj)
{
return obj && ( obj->IsCreatedBy(pg_partitionFactory) ||obj->IsCreatedBy(tableFactory)) && obj->CanEdit()
&& (obj->GetOwner() == obj->GetConnection()->GetUser() || obj->GetServer()->GetSuperUser())
&& ((pgTable *)obj)->GetConnection()->BackendMinimumVersion(8, 1)
&& ((pgTable *)obj)->GetTriggerCount() > 0;
}
enableAllTriggersFactory::enableAllTriggersFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("Enable triggers"), _("Enable all triggers on the selected table."));
}
wxWindow *enableAllTriggersFactory::StartDialog(frmMain *form, pgObject *obj)
{
if (wxMessageBox(_("Are you sure you wish to enable all triggers on this table?"), _("Enable triggers"), wxYES_NO) != wxYES)
return 0;
if (!((pgTable *)obj)->EnableTriggers(true))
return 0;
((pgTable *)obj)->iSetTriggersEnabled(form->GetBrowser(), true);
return 0;
}
bool enableAllTriggersFactory::CheckEnable(pgObject *obj)
{
return obj && ( obj->IsCreatedBy(pg_partitionFactory) ||obj->IsCreatedBy(tableFactory)) && obj->CanEdit()
&& (obj->GetOwner() == obj->GetConnection()->GetUser() || obj->GetServer()->GetSuperUser())
&& ((pgTable *)obj)->GetConnection()->BackendMinimumVersion(8, 1)
&& ((pgTable *)obj)->GetTriggerCount() > 0;
}
truncateFactory::truncateFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("&Truncate"), _("Truncate the selected table."));
}
wxWindow *truncateFactory::StartDialog(frmMain *form, pgObject *obj)
{
if (wxMessageBox(_("Are you sure you wish to truncate this table?\n\nWARNING: This action will delete ALL data in the table!"), _("Truncate table"), wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT) != wxYES)
return 0;
((pgTable *)obj)->Truncate(false);
((pgTable *)obj)->UpdateRows();
wxTreeItemId item = form->GetBrowser()->GetSelection();
if (obj == form->GetBrowser()->GetObject(item))
obj->ShowTreeDetail(form->GetBrowser(), 0, form->GetProperties());
return 0;
}
bool truncateFactory::CheckEnable(pgObject *obj)
{
return obj && obj->IsCreatedBy(tableFactory);
}
truncateCascadedFactory::truncateCascadedFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("Truncate Cascaded"), _("Truncate the selected table and all referencing tables."));
}
wxWindow *truncateCascadedFactory::StartDialog(frmMain *form, pgObject *obj)
{
if (wxMessageBox(_("Are you sure you wish to truncate this table and all tables that have foreign key references to this table?\n\nWARNING: This action will delete ALL data in the tables!"), _("Truncate table cascaded"), wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT) != wxYES)
return 0;
((pgTable *)obj)->Truncate(true);
((pgTable *)obj)->UpdateRows();
wxTreeItemId item = form->GetBrowser()->GetSelection();
if (obj == form->GetBrowser()->GetObject(item))
obj->ShowTreeDetail(form->GetBrowser(), 0, form->GetProperties());
return 0;
}
bool truncateCascadedFactory::CheckEnable(pgObject *obj)
{
return obj && obj->IsCreatedBy(tableFactory) && ((pgTable *)obj)->GetConnection()->BackendMinimumVersion(8, 2);
}
resetTableStatsFactory::resetTableStatsFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
{
mnu->Append(id, _("&Reset table statistics"), _("Reset statistics of the selected table."));
}
wxWindow *resetTableStatsFactory::StartDialog(frmMain *form, pgObject *obj)
{
if (wxMessageBox(_("Are you sure you wish to reset statistics of this table?"), _("Reset statistics"), wxYES_NO) != wxYES)
return 0;
((pgTable *)obj)->ResetStats();
((pgTable *)obj)->ShowStatistics(form, form->GetStatistics());
return 0;
}
bool resetTableStatsFactory::CheckEnable(pgObject *obj)
{
return obj && ( obj->IsCreatedBy(pg_partitionFactory) ||obj->IsCreatedBy(tableFactory)) && ((pgTable *)obj)->GetConnection()->BackendMinimumVersion(9, 0);
}