pgadmin3/schema/pgForeignTable.cpp
lsv 8aafedc399 View grants for foreign tables.
Не отображались права для сторонних таблиц
2024-11-11 19:14:00 +05:00

505 lines
14 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// pgForeignTable.cpp - Foreign Table class
//
//////////////////////////////////////////////////////////////////////////
// wxWindows headers
#include <wx/wx.h>
// App headers
#include "pgAdmin3.h"
#include "utils/misc.h"
#include "schema/pgForeignTable.h"
#include "schema/pgDatatype.h"
pgForeignTable::pgForeignTable(pgSchema *newSchema, const wxString &newName)
: pgSchemaObject(newSchema, foreignTableFactory, newName)
{
}
pgForeignTable::~pgForeignTable()
{
}
wxString pgForeignTable::GetTranslatedMessage(int kindOfMessage) const
{
wxString message = wxEmptyString;
switch (kindOfMessage)
{
case RETRIEVINGDETAILS:
message = _("Retrieving details on foreign table");
message += wxT(" ") + GetName();
break;
case REFRESHINGDETAILS:
message = _("Refreshing foreign table");
message += wxT(" ") + GetName();
break;
case DROPINCLUDINGDEPS:
message = wxString::Format(_("Are you sure you wish to drop foreign 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 foreign table \"%s\"?"),
GetFullIdentifier().c_str());
break;
case DROPCASCADETITLE:
message = _("Drop foreign table cascaded?");
break;
case DROPTITLE:
message = _("Drop foreign table?");
break;
case PROPERTIESREPORT:
message = _("Foreign table properties report");
message += wxT(" - ") + GetName();
break;
case PROPERTIES:
message = _("Foreign table properties");
break;
case DDLREPORT:
message = _("Foreign table DDL report");
message += wxT(" - ") + GetName();
break;
case DDL:
message = _("Foreign table DDL");
break;
case DEPENDENCIESREPORT:
message = _("Foreign table dependencies report");
message += wxT(" - ") + GetName();
break;
case DEPENDENCIES:
message = _("Foreign table dependencies");
break;
case DEPENDENTSREPORT:
message = _("Foreign table dependents report");
message += wxT(" - ") + GetName();
break;
case DEPENDENTS:
message = _("Foreign table dependents");
break;
}
return message;
}
bool pgForeignTable::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
{
wxString sql = wxT("DROP FOREIGN TABLE ") + this->GetSchema()->GetQuotedIdentifier() + wxT(".") + this->GetQuotedIdentifier();
if (cascaded)
sql += wxT(" CASCADE");
return GetDatabase()->ExecuteVoid(sql);
}
wxString pgForeignTable::GetSql(ctlTree *browser)
{
if (sql.IsNull())
{
sql = wxT("-- Foreign Table: ") + GetQuotedFullIdentifier() + wxT("\n\n")
+ wxT("-- DROP FOREIGN TABLE ") + GetQuotedFullIdentifier() + wxT(";")
+ wxT("\n\nCREATE FOREIGN TABLE ") + GetQuotedFullIdentifier()
+ wxT("\n (") + GetQuotedTypesList()
+ wxT(")\n SERVER ") + GetForeignServer();
if (!GetOptionsList().IsEmpty())
sql += wxT("\n OPTIONS (") + GetOptionsList() + wxT(")");
sql += wxT(";\n")
+ GetOwnerSql(9, 1)
+ GetCommentSql();
if (GetConnection()->BackendMinimumVersion(9, 1))
sql += GetSeqLabelsSql();
if (GetConnection()->BackendMinimumVersion(8, 4))
{
wxString g = GetGrant(wxT("arwdDxt"));
g.Replace("FOREIGN ", "");
sql += g;
}
}
return sql;
}
void pgForeignTable::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
{
wxString constraint;
if (!expandedKids)
{
expandedKids = true;
pgSet *set = ExecuteSet(
wxT("SELECT attname, format_type(t.oid,NULL) AS typname, attndims, atttypmod, nspname, attnotnull,attfdwoptions,\n")
wxT(" (SELECT COUNT(1) from pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup\n")
wxT(" FROM pg_attribute att\n")
wxT(" JOIN pg_type t ON t.oid=atttypid\n")
wxT(" JOIN pg_namespace nsp ON t.typnamespace=nsp.oid\n")
wxT(" LEFT OUTER JOIN pg_type b ON t.typelem=b.oid\n")
wxT(" WHERE att.attrelid=") + GetOidStr() + wxT("\n")
wxT(" AND attnum>0\n")
wxT(" ORDER by attnum"));
if (set)
{
int anzvar = 0;
while (!set->Eof())
{
pgDatatype dt(set->GetVal(wxT("nspname")), set->GetVal(wxT("typname")),
set->GetBool(wxT("isdup")), set->GetLong(wxT("attndims")) > 0, set->GetLong(wxT("atttypmod")));
constraint = set->GetBool(wxT("attnotnull")) ? wxT("NOT NULL") : wxT("");
if (anzvar++)
{
typesList += wxT(", ");
quotedTypesList += wxT(",\n ");
}
wxString str = set->GetVal("attfdwoptions");
if (!str.IsEmpty()) str="OPTIONS("+ ParseColumnOptions(str) + ") ";
//FillArray(column->GetVariables(), str.Mid(1, str.Length() - 2));
typesList += set->GetVal(wxT("attname")) + wxT(" ")
+ dt.GetSchemaPrefix(GetDatabase()) + dt.FullName() + wxT(" ")
+ constraint;
quotedTypesList += qtIdent(set->GetVal(wxT("attname"))) + wxT(" ")
+ dt.GetQuotedSchemaPrefix(GetDatabase()) + dt.QuotedFullName() + wxT(" ")
+ str+ constraint;
typesArray.Add(set->GetVal(wxT("attname")));
typesArray.Add(dt.GetSchemaPrefix(GetDatabase()) + dt.FullName());
typesArray.Add(constraint);
set->MoveNext();
}
delete set;
}
}
if (properties)
{
CreateListColumns(properties);
properties->AppendItem(_("Name"), GetName());
properties->AppendItem(_("OID"), GetOid());
properties->AppendItem(_("Owner"), GetOwner());
properties->AppendItem(_("ACL"), GetAcl());
properties->AppendItem(_("Server"), GetForeignServer());
properties->AppendItem(_("Columns"), GetQuotedTypesList());
properties->AppendItem(_("Options"), GetOptionsList());
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));
}
}
}
}
}
wxString pgForeignTable::GetSelectSql(ctlTree *browser)
{
wxString columns = wxEmptyString;
wxArrayString elements = GetTypesArray();
size_t i;
for (i = 0 ; i < elements.GetCount() ; i += 3)
{
if (!columns.IsEmpty())
columns += wxT(", ");
columns += qtIdent(elements.Item(i));
}
wxString sql =
wxT("SELECT ") + columns + wxT("\n")
wxT(" FROM ") + GetQuotedFullIdentifier() + wxT(";\n");
return sql;
}
pgObject *pgForeignTable::Refresh(ctlTree *browser, const wxTreeItemId item)
{
pgObject *ft = 0;
pgCollection *coll = browser->GetParentCollection(item);
if (coll)
ft = foreignTableFactory.CreateObjects(coll, 0, wxT("\n AND c.oid=") + GetOidStr());
return ft;
}
void pgForeignTable::iSetOptions(const wxString &tmpoptions)
{
wxString tmp;
wxString option;
wxString value;
wxString currentChar;
bool wrappedInQuotes = false, antislash = false;
options = wxEmptyString;
if (tmpoptions == wxEmptyString)
return;
// parse the options string
// we start at 1 and stop at length-1 to get rid of the { and } of the array
for (unsigned int index = 1 ; index < tmpoptions.Length() - 1 ; index++)
{
// get current char
currentChar = tmpoptions.Mid(index, 1);
// if there is a double quote at the beginning of an option,
// the whole option=value will be wrapped in quotes
if (currentChar == wxT("\"") && tmp.IsEmpty())
wrappedInQuotes = true;
else if (currentChar == wxT("\\") && wrappedInQuotes)
antislash = true;
else
{
if ((currentChar == wxT(",") && !wrappedInQuotes && !tmp.IsEmpty())
|| (currentChar == wxT("\"") && wrappedInQuotes && !antislash && !tmp.IsEmpty()))
{
// new options
if (currentChar == wxT("\"") && wrappedInQuotes && !antislash && !tmp.IsEmpty())
{
// In this specific case, the next character is the comma,
// but we don't want to start the next option with the comma
// so we skip it right now
index++;
}
// we need to grab option and value from tmp string
option = tmp.BeforeFirst('=');
value = tmp.AfterFirst('=');
// put them in the array
optionsArray.Add(option);
optionsArray.Add(value);
// build the options string
if (options.Length() > 0)
options += wxT(", ");
options += option + wxT(" '") + value + wxT("'");
// reinit tmp
tmp = wxEmptyString;
wrappedInQuotes = false;
}
else
tmp += currentChar;
antislash = false;
}
}
// last options
if (!tmp.IsEmpty())
{
// we need to grab option and value from tmp string
option = tmp.BeforeFirst('=');
value = tmp.AfterFirst('=');
// put them in the array
optionsArray.Add(option);
optionsArray.Add(value);
// build the options string
if (options.Length() > 0)
options += wxT(", ");
options += option + wxT(" '") + value + wxT("'");
}
}
wxString pgForeignTable::ParseColumnOptions(const wxString& tmpoptions)
{
wxString tmp;
wxString option;
wxString value;
wxString currentChar;
bool wrappedInQuotes = false, antislash = false;
wxString options = wxEmptyString;
if (tmpoptions == wxEmptyString)
return "";
// parse the options string
// we start at 1 and stop at length-1 to get rid of the { and } of the array
for (unsigned int index = 1; index < tmpoptions.Length() - 1; index++)
{
// get current char
currentChar = tmpoptions.Mid(index, 1);
// if there is a double quote at the beginning of an option,
// the whole option=value will be wrapped in quotes
if (currentChar == wxT("\"") && tmp.IsEmpty())
wrappedInQuotes = true;
else if (currentChar == wxT("\\") && wrappedInQuotes)
antislash = true;
else
{
if ((currentChar == wxT(",") && !wrappedInQuotes && !tmp.IsEmpty())
|| (currentChar == wxT("\"") && wrappedInQuotes && !antislash && !tmp.IsEmpty()))
{
// new options
if (currentChar == wxT("\"") && wrappedInQuotes && !antislash && !tmp.IsEmpty())
{
// In this specific case, the next character is the comma,
// but we don't want to start the next option with the comma
// so we skip it right now
index++;
}
// we need to grab option and value from tmp string
option = tmp.BeforeFirst('=');
value = tmp.AfterFirst('=');
// put them in the array
// build the options string
if (options.Length() > 0)
options += wxT(", ");
options += option + wxT(" '") + value + wxT("'");
// reinit tmp
tmp = wxEmptyString;
wrappedInQuotes = false;
}
else
tmp += currentChar;
antislash = false;
}
}
// last options
if (!tmp.IsEmpty())
{
// we need to grab option and value from tmp string
option = tmp.BeforeFirst('=');
value = tmp.AfterFirst('=');
// build the options string
if (options.Length() > 0)
options += wxT(", ");
options += option + wxT(" '") + value + wxT("'");
}
return options;
}
/////////////////////////////////////////////////////////
pgForeignTableCollection::pgForeignTableCollection(pgaFactory *factory, pgSchema *sch)
: pgSchemaObjCollection(factory, sch)
{
}
wxString pgForeignTableCollection::GetTranslatedMessage(int kindOfMessage) const
{
wxString message = wxEmptyString;
switch (kindOfMessage)
{
case RETRIEVINGDETAILS:
message = _("Retrieving details on foreign tables");
break;
case REFRESHINGDETAILS:
message = _("Refreshing foreign tables");
break;
case OBJECTSLISTREPORT:
message = _("Foreign tables list report");
break;
}
return message;
}
/////////////////////////////////////////////////////////
pgObject *pgForeignTableFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
{
pgForeignTable *foreigntable = 0;
wxString sql = wxT("SELECT c.oid AS ftoid, c.relname AS ftrelname, pg_get_userbyid(relowner) AS ftowner,\n")
wxT(" ftoptions, srvname AS ftsrvname, description,c.relacl,\n")
wxT(" (SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=c.oid) AS labels,\n")
wxT(" (SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=c.oid) AS providers\n")
wxT(" FROM pg_class c\n")
wxT(" JOIN pg_foreign_table ft ON c.oid=ft.ftrelid\n")
wxT(" LEFT OUTER JOIN pg_foreign_server fs ON ft.ftserver=fs.oid\n")
wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid AND des.classoid='pg_class'::regclass AND des.objsubid=0)\n")
wxT(" WHERE c.relnamespace = ") + collection->GetSchema()->GetOidStr() + wxT("\n")
+ restriction +
wxT(" ORDER BY c.relname");
pgSet *foreigntables = collection->GetDatabase()->ExecuteSet(sql);
if (foreigntables)
{
while (!foreigntables->Eof())
{
foreigntable = new pgForeignTable(collection->GetSchema(), foreigntables->GetVal(wxT("ftrelname")));
foreigntable->iSetOid(foreigntables->GetOid(wxT("ftoid")));
foreigntable->iSetOwner(foreigntables->GetVal(wxT("ftowner")));
foreigntable->iSetForeignServer(foreigntables->GetVal(wxT("ftsrvname")));
foreigntable->iSetOptions(foreigntables->GetVal(wxT("ftoptions")));
foreigntable->iSetComment(foreigntables->GetVal(wxT("description")));
foreigntable->iSetProviders(foreigntables->GetVal(wxT("providers")));
foreigntable->iSetLabels(foreigntables->GetVal(wxT("labels")));
foreigntable->iSetAcl(foreigntables->GetVal(wxT("relacl")));
if (browser)
{
browser->AppendObject(collection, foreigntable);
foreigntables->MoveNext();
}
else
break;
}
delete foreigntables;
}
return foreigntable;
}
#include "images/foreigntable.pngc"
#include "images/foreigntables.pngc"
pgForeignTableFactory::pgForeignTableFactory()
: pgSchemaObjFactory(__("Foreign Table"), __("New Foreign Table..."), __("Create a new Foreign Table."), foreigntable_png_img)
{
metaType = PGM_FOREIGNTABLE;
}
pgCollection *pgForeignTableFactory::CreateCollection(pgObject *obj)
{
return new pgForeignTableCollection(GetCollectionFactory(), (pgSchema *)obj);
}
pgForeignTableFactory foreignTableFactory;
static pgaCollectionFactory cf(&foreignTableFactory, __("Foreign Tables"), foreigntables_png_img);