mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
562 lines
16 KiB
C++
562 lines
16 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// edbPackageFunction.cpp - EnterpriseDB Package member function
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
|
|
// App headers
|
|
#include "pgAdmin3.h"
|
|
#include "utils/pgfeatures.h"
|
|
#include "schema/edbPackageFunction.h"
|
|
|
|
|
|
edbPackageFunction::edbPackageFunction(edbPackage *newPackage, const wxString &newName)
|
|
: edbPackageObject(newPackage, packageFunctionFactory, newName)
|
|
{
|
|
}
|
|
|
|
edbPackageFunction::edbPackageFunction(edbPackage *newPackage, pgaFactory &factory, const wxString &newName)
|
|
: edbPackageObject(newPackage, factory, newName)
|
|
{
|
|
}
|
|
|
|
edbPackageProcedure::edbPackageProcedure(edbPackage *newPackage, const wxString &newName)
|
|
: edbPackageFunction(newPackage, packageProcedureFactory, newName)
|
|
{
|
|
}
|
|
|
|
wxString edbPackageFunction::GetTranslatedMessage(int kindOfMessage) const
|
|
{
|
|
wxString message = wxEmptyString;
|
|
|
|
switch (kindOfMessage)
|
|
{
|
|
case RETRIEVINGDETAILS:
|
|
message = _("Retrieving details on package function");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case REFRESHINGDETAILS:
|
|
message = _("Refreshing package function");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case DROPINCLUDINGDEPS:
|
|
message = wxString::Format(_("Are you sure you wish to drop package function \"%s\" including all objects that depend on it?"),
|
|
GetFullIdentifier().c_str());
|
|
break;
|
|
case DROPEXCLUDINGDEPS:
|
|
message = wxString::Format(_("Are you sure you wish to drop package function \"%s\"?"),
|
|
GetFullIdentifier().c_str());
|
|
break;
|
|
case DROPCASCADETITLE:
|
|
message = _("Drop package function cascaded?");
|
|
break;
|
|
case DROPTITLE:
|
|
message = _("Drop package function?");
|
|
break;
|
|
case PROPERTIESREPORT:
|
|
message = _("Package function properties report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case PROPERTIES:
|
|
message = _("Package function properties");
|
|
break;
|
|
case DDLREPORT:
|
|
message = _("Package function DDL report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case DDL:
|
|
message = _("Package function DDL");
|
|
break;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
|
|
wxString edbPackageFunction::GetFullName()
|
|
{
|
|
return GetName() + wxT("(") + GetArgSigList() + wxT(")");
|
|
}
|
|
|
|
wxString edbPackageProcedure::GetFullName()
|
|
{
|
|
if (GetArgSigList().IsEmpty())
|
|
return GetName();
|
|
else
|
|
return GetName() + wxT("(") + GetArgSigList() + wxT(")");
|
|
}
|
|
|
|
wxString edbPackageFunction::GetArgListWithNames()
|
|
{
|
|
wxString args;
|
|
|
|
for (unsigned int i = 0; i < argTypesArray.Count(); i++)
|
|
{
|
|
if (i > 0)
|
|
args += wxT(", ");
|
|
|
|
wxString arg;
|
|
|
|
if (GetIsProcedure())
|
|
{
|
|
if (!argNamesArray.Item(i).IsEmpty())
|
|
arg += qtIdent(argNamesArray.Item(i));
|
|
|
|
if (!argModesArray.Item(i).IsEmpty())
|
|
{
|
|
if (arg.IsEmpty())
|
|
arg += argModesArray.Item(i);
|
|
else
|
|
arg += wxT(" ") + argModesArray.Item(i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!argModesArray.Item(i).IsEmpty())
|
|
arg += argModesArray.Item(i);
|
|
|
|
if (!argNamesArray.Item(i).IsEmpty())
|
|
{
|
|
if (arg.IsEmpty())
|
|
arg += qtIdent(argNamesArray.Item(i));
|
|
else
|
|
arg += wxT(" ") + qtIdent(argNamesArray.Item(i));
|
|
}
|
|
}
|
|
|
|
if (!arg.IsEmpty())
|
|
arg += wxT(" ") + argTypesArray.Item(i);
|
|
else
|
|
arg += argTypesArray.Item(i);
|
|
|
|
// Parameter default value
|
|
if (GetConnection()->HasFeature(FEATURE_FUNCTION_DEFAULTS) &&
|
|
!argDefsArray.IsEmpty())
|
|
{
|
|
if ((argModesArray.Item(i).IsEmpty() ||
|
|
argModesArray.Item(i) == wxT("IN") ||
|
|
argModesArray.Item(i) == wxT("VARIADIC")) &&
|
|
!argDefsArray.Item(i).IsEmpty() &&
|
|
i < argDefsArray.Count())
|
|
arg += wxT(" DEFAULT ") + argDefsArray.Item(i);
|
|
}
|
|
|
|
args += arg;
|
|
}
|
|
return args;
|
|
}
|
|
|
|
wxString edbPackageFunction::GetArgSigList()
|
|
{
|
|
wxString args;
|
|
|
|
for (unsigned int i = 0; i < argTypesArray.Count(); i++)
|
|
{
|
|
// OUT parameters are not considered part of the signature
|
|
if (argModesArray.Item(i) != wxT("OUT"))
|
|
{
|
|
if (i > 0)
|
|
args += wxT(", ");
|
|
|
|
args += argTypesArray.Item(i);
|
|
}
|
|
}
|
|
return args;
|
|
}
|
|
|
|
wxString edbPackageFunction::GetSql(ctlTree *browser)
|
|
{
|
|
if (sql.IsNull())
|
|
{
|
|
sql = wxT("-- Package Function: ") + GetName() + wxT("\n\n");
|
|
sql += GetSource() + wxT("\n\n");
|
|
}
|
|
|
|
return sql;
|
|
}
|
|
|
|
wxString edbPackageProcedure::GetSql(ctlTree *browser)
|
|
{
|
|
if (sql.IsNull())
|
|
{
|
|
sql = wxT("-- Package Procedure: ") + GetName() + wxT("\n\n");
|
|
sql += GetSource() + wxT("\n\n");
|
|
}
|
|
|
|
return sql;
|
|
}
|
|
|
|
void edbPackageFunction::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
|
|
{
|
|
if (properties)
|
|
{
|
|
CreateListColumns(properties);
|
|
|
|
properties->AppendItem(_("Name"), GetName());
|
|
properties->AppendItem(_("OID"), GetOid());
|
|
properties->AppendItem(_("Argument count"), GetArgCount());
|
|
properties->AppendItem(_("Arguments"), GetArgListWithNames());
|
|
properties->AppendItem(_("Signature arguments"), GetArgSigList());
|
|
if (!GetIsProcedure())
|
|
properties->AppendItem(_("Return type"), GetReturnType());
|
|
properties->AppendItem(_("Visibility"), GetVisibility());
|
|
properties->AppendItem(_("Source"), firstLineOnly(GetSource()));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pgObject *edbPackageFunction::Refresh(ctlTree *browser, const wxTreeItemId item)
|
|
{
|
|
pgObject *packageFunction = 0;
|
|
pgCollection *coll = browser->GetParentCollection(item);
|
|
if (coll)
|
|
{
|
|
if (coll->GetConnection()->EdbMinimumVersion(8, 2))
|
|
packageFunction = packageFunctionFactory.CreateObjects(coll, 0, wxT("\n AND pronamespace=") + GetPackage()->GetOidStr() + wxT(" AND proname='") + GetName() + wxT("'"));
|
|
else
|
|
packageFunction = packageFunctionFactory.CreateObjects(coll, 0, wxT("\n AND packageoid=") + GetPackage()->GetOidStr() + wxT(" AND eltname='") + GetName() + wxT("'"));
|
|
}
|
|
|
|
return packageFunction;
|
|
}
|
|
|
|
|
|
/////////////////////////////
|
|
|
|
edbPackageFunctionCollection::edbPackageFunctionCollection(pgaFactory *factory, edbPackage *pkg)
|
|
: edbPackageObjCollection(factory, pkg)
|
|
{
|
|
}
|
|
|
|
wxString edbPackageFunctionCollection::GetTranslatedMessage(int kindOfMessage) const
|
|
{
|
|
wxString message = wxEmptyString;
|
|
|
|
switch (kindOfMessage)
|
|
{
|
|
case RETRIEVINGDETAILS:
|
|
message = _("Retrieving details on package functions");
|
|
break;
|
|
case REFRESHINGDETAILS:
|
|
message = _("Refreshing package functions");
|
|
break;
|
|
case GRANTWIZARDTITLE:
|
|
message = _("Privileges for package functions");
|
|
break;
|
|
case OBJECTSLISTREPORT:
|
|
message = _("Package functions list report");
|
|
break;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
edbPackageFunction *edbPackageFunctionFactory::AppendFunctions(pgObject *obj, edbPackage *package, ctlTree *browser, const wxString &restriction)
|
|
{
|
|
edbPackageFunction *packageFunction = 0;
|
|
pgSet *packageFunctions;
|
|
|
|
// Caches
|
|
cacheMap typeCache, exprCache;
|
|
wxString sql, argDefsCol;
|
|
|
|
if (obj->GetConnection()->HasFeature(FEATURE_FUNCTION_DEFAULTS))
|
|
{
|
|
if (obj->GetConnection()->EdbMinimumVersion(8, 4))
|
|
{
|
|
argDefsCol = wxT("pg_get_expr(proargdefaults, 'pg_catalog.pg_class'::regclass) AS argdefaults, pronargdefaults, ");
|
|
}
|
|
else
|
|
{
|
|
argDefsCol = wxT("proargdefvals AS argdefaults, COALESCE(substring(array_dims(proargdefvals), E'1:(.*)\\]')::integer, 0) AS pronargdefaults, ");
|
|
}
|
|
}
|
|
|
|
if (obj->GetConnection()->EdbMinimumVersion(8, 2))
|
|
{
|
|
sql = wxT("SELECT pg_proc.oid, proname AS eltname, prorettype AS eltdatatype, pronargs AS nargs, proaccess AS visibility,\n")
|
|
wxT(" proallargtypes AS allargtypes, proargtypes AS argtypes, proargnames AS argnames, proargmodes AS argmodes,") + argDefsCol + wxT("\n")
|
|
wxT(" CASE WHEN format_type(prorettype, NULL) = 'void' THEN 'P' ELSE 'F' END AS eltclass\n")
|
|
wxT(" FROM pg_proc, pg_namespace\n")
|
|
+ restriction + wxT("\n")
|
|
wxT(" AND pg_proc.pronamespace = pg_namespace.oid\n")
|
|
wxT(" ORDER BY eltname");
|
|
}
|
|
else
|
|
{
|
|
sql = wxT("SELECT oid, eltname, eltdatatype, eltclass, nargs, visibility,\n")
|
|
wxT(" allargtypes, argtypes, argnames, argmodes\n")
|
|
wxT(" FROM edb_pkgelements\n")
|
|
+ restriction + wxT("\n")
|
|
wxT(" ORDER BY eltname");
|
|
}
|
|
|
|
packageFunctions = obj->GetDatabase()->ExecuteSet(sql);
|
|
|
|
pgSet *types = obj->GetDatabase()->ExecuteSet(wxT(
|
|
"SELECT oid, format_type(oid, NULL) AS typname FROM pg_type"));
|
|
|
|
while(!types->Eof())
|
|
{
|
|
typeCache[types->GetVal(wxT("oid"))] = types->GetVal(wxT("typname"));
|
|
types->MoveNext();
|
|
}
|
|
|
|
if (packageFunctions)
|
|
{
|
|
while (!packageFunctions->Eof())
|
|
{
|
|
size_t inModeCnt = 0;
|
|
size_t defaultArgsCnt = 0;
|
|
if (packageFunctions->GetVal(wxT("eltclass")) == wxT("F"))
|
|
packageFunction = new edbPackageFunction(package, packageFunctions->GetVal(wxT("eltname")));
|
|
else
|
|
packageFunction = new edbPackageProcedure(package, packageFunctions->GetVal(wxT("eltname")));
|
|
|
|
// Tokenize the arguments
|
|
wxStringTokenizer argTypesTkz(wxEmptyString), argModesTkz(wxEmptyString);
|
|
queryTokenizer argNamesTkz(wxEmptyString, (wxChar)',');
|
|
wxArrayString argDefValArray;
|
|
wxString tmp;
|
|
|
|
// Types
|
|
tmp = packageFunctions->GetVal(wxT("allargtypes"));
|
|
if (!tmp.IsEmpty())
|
|
argTypesTkz.SetString(tmp.Mid(1, tmp.Length() - 2), wxT(","));
|
|
else
|
|
{
|
|
tmp = packageFunctions->GetVal(wxT("argtypes"));
|
|
if (!tmp.IsEmpty())
|
|
argTypesTkz.SetString(tmp);
|
|
}
|
|
|
|
// Names
|
|
tmp = packageFunctions->GetVal(wxT("argnames"));
|
|
if (!tmp.IsEmpty())
|
|
argNamesTkz.SetString(tmp.Mid(1, tmp.Length() - 2), wxT(","));
|
|
|
|
// Modes
|
|
tmp = packageFunctions->GetVal(wxT("argmodes"));
|
|
if (!tmp.IsEmpty())
|
|
argModesTkz.SetString(tmp.Mid(1, tmp.Length() - 2), wxT(","));
|
|
|
|
// Function defaults
|
|
if (obj->GetConnection()->HasFeature(FEATURE_FUNCTION_DEFAULTS))
|
|
{
|
|
defaultArgsCnt = packageFunctions->GetLong(wxT("pronargdefaults"));
|
|
|
|
if (defaultArgsCnt > 0)
|
|
{
|
|
tmp = packageFunctions->GetVal(wxT("argdefaults"));
|
|
|
|
if (!tmp.IsEmpty())
|
|
{
|
|
getArrayFromCommaSeparatedList(tmp.Mid(1, tmp.Length() - 2), argDefValArray);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now iterate the arguments and build the arrays
|
|
wxString type, name, mode;
|
|
|
|
while (argTypesTkz.HasMoreTokens())
|
|
{
|
|
// Add the arg type. This is a type oid, so
|
|
// look it up in the hashmap
|
|
type = argTypesTkz.GetNextToken();
|
|
packageFunction->iAddArgType(typeCache[type]);
|
|
|
|
// Now add the name, stripping the quotes if
|
|
// necessary.
|
|
name = argNamesTkz.GetNextToken();
|
|
if (!name.IsEmpty())
|
|
{
|
|
if (name[0] == '"')
|
|
name = name.Mid(1, name.Length() - 2);
|
|
packageFunction->iAddArgName(name);
|
|
}
|
|
else
|
|
packageFunction->iAddArgName(wxEmptyString);
|
|
|
|
// Now the mode
|
|
mode = argModesTkz.GetNextToken();
|
|
if (!mode.IsEmpty())
|
|
{
|
|
if (mode == wxT('o') || mode == wxT("2"))
|
|
mode = wxT("OUT");
|
|
else if (mode == wxT("b"))
|
|
if (packageFunctions->GetVal(wxT("eltclass")) == wxT("F"))
|
|
mode = wxT("IN OUT");
|
|
else
|
|
mode = wxT("INOUT");
|
|
else if (mode == wxT("3"))
|
|
mode = wxT("IN OUT");
|
|
else if (mode == wxT("v"))
|
|
{
|
|
inModeCnt++;
|
|
mode = wxT("VARIADIC");
|
|
}
|
|
else
|
|
{
|
|
inModeCnt++;
|
|
mode = wxT("IN");
|
|
}
|
|
|
|
packageFunction->iAddArgMode(mode);
|
|
}
|
|
else
|
|
packageFunction->iAddArgMode(wxEmptyString);
|
|
}
|
|
|
|
// Finally the defaults, as we got them.
|
|
if (packageFunction->GetConnection()->HasFeature(FEATURE_FUNCTION_DEFAULTS))
|
|
{
|
|
size_t currINindex = 0;
|
|
while (inModeCnt)
|
|
{
|
|
for (size_t index = 0; index < packageFunction->GetArgTypesArray().Count(); index++)
|
|
{
|
|
wxString def = wxEmptyString;
|
|
if(packageFunction->GetArgModesArray()[index].IsEmpty() ||
|
|
packageFunction->GetArgModesArray()[index] == wxT("IN") ||
|
|
packageFunction->GetArgModesArray()[index] == wxT("VARIADIC"))
|
|
{
|
|
if (!argDefValArray.IsEmpty() && inModeCnt <= argDefValArray.GetCount())
|
|
{
|
|
def = argDefValArray[currINindex++];
|
|
|
|
if (!def.IsEmpty() && def != wxT("-"))
|
|
{
|
|
// Only EDB 8.3 does not support get the
|
|
// default value using pg_get_expr directly
|
|
if (!packageFunction->GetConnection()->BackendMinimumVersion(8, 4))
|
|
{
|
|
// Check the cache first - if we don't
|
|
// have a value, get it and cache for
|
|
// next time
|
|
wxString val = exprCache[def];
|
|
|
|
if (val == wxEmptyString)
|
|
{
|
|
val = obj->GetDatabase()->ExecuteScalar(
|
|
wxT("SELECT pg_get_expr('") + def.Mid(1, def.Length() - 2) + wxT("', 'pg_catalog.pg_class'::regclass)"));
|
|
exprCache[def] = val;
|
|
}
|
|
def = val;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
def = wxEmptyString;
|
|
}
|
|
}
|
|
inModeCnt--;
|
|
}
|
|
packageFunction->iAddArgDef(def);
|
|
}
|
|
}
|
|
}
|
|
|
|
packageFunction->iSetOid(packageFunctions->GetOid(wxT("oid")));
|
|
packageFunction->iSetArgCount(packageFunctions->GetOid(wxT("nargs")));
|
|
packageFunction->iSetReturnType(typeCache[packageFunctions->GetVal(wxT("eltdatatype"))]);
|
|
|
|
if (packageFunctions->GetVal(wxT("visibility")) == wxT("+"))
|
|
packageFunction->iSetVisibility(_("Public"));
|
|
else if (packageFunctions->GetVal(wxT("visibility")) == wxT("-"))
|
|
packageFunction->iSetVisibility(_("Private"));
|
|
else
|
|
packageFunction->iSetVisibility(_("Unknown"));
|
|
|
|
packageFunction->iSetSource(package->GetBodyInner());
|
|
|
|
if (browser)
|
|
{
|
|
browser->AppendObject(obj, packageFunction);
|
|
packageFunctions->MoveNext();
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
delete packageFunctions;
|
|
delete types;
|
|
}
|
|
return packageFunction;
|
|
}
|
|
|
|
pgObject *edbPackageFunctionFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
|
|
{
|
|
wxString restr;
|
|
|
|
if (collection->GetDatabase()->GetConnection()->EdbMinimumVersion(8, 2))
|
|
restr = wxT(" WHERE format_type(prorettype, NULL) != 'void' AND pronamespace = ");
|
|
else
|
|
restr = wxT(" WHERE eltclass = 'F' AND packageoid = ");
|
|
|
|
restr += ((edbPackageObjCollection *)collection)->GetPackage()->GetOidStr();
|
|
restr += restriction;
|
|
|
|
return AppendFunctions(collection, ((edbPackageObjCollection *)collection)->GetPackage(), browser, restr);
|
|
}
|
|
|
|
pgObject *edbPackageProcedureFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
|
|
{
|
|
wxString restr;
|
|
|
|
if (collection->GetDatabase()->GetConnection()->EdbMinimumVersion(8, 2))
|
|
restr = wxT(" WHERE format_type(prorettype, NULL) = 'void' AND pronamespace = ");
|
|
else
|
|
restr = wxT(" WHERE eltclass = 'P' AND packageoid = ");
|
|
|
|
restr += ((edbPackageObjCollection *)collection)->GetPackage()->GetOidStr();
|
|
restr += restriction;
|
|
|
|
return AppendFunctions(collection, ((edbPackageObjCollection *)collection)->GetPackage(), browser, restr);
|
|
}
|
|
|
|
#include "images/function.pngc"
|
|
#include "images/functions.pngc"
|
|
|
|
edbPackageFunctionFactory::edbPackageFunctionFactory(const wxChar *tn, const wxChar *ns, const wxChar *nls, wxImage *img)
|
|
: edbPackageObjFactory(tn, ns, nls, img)
|
|
{
|
|
metaType = EDB_PACKAGEFUNCTION;
|
|
}
|
|
|
|
pgCollection *edbPackageFunctionFactory::CreateCollection(pgObject *obj)
|
|
{
|
|
return new edbPackageFunctionCollection(GetCollectionFactory(), (edbPackage *)obj);
|
|
}
|
|
|
|
edbPackageFunctionFactory packageFunctionFactory(__("Function"), __("New Function..."), __("Create a new Function."), function_png_img);
|
|
static pgaCollectionFactory cff(&packageFunctionFactory, __("Functions"), functions_png_img);
|
|
|
|
pgCollection *edbPackageObjFactory::CreateCollection(pgObject *obj)
|
|
{
|
|
return new edbPackageObjCollection(GetCollectionFactory(), (edbPackage *)obj);
|
|
}
|
|
|
|
#include "images/procedure.pngc"
|
|
#include "images/procedures.pngc"
|
|
|
|
edbPackageProcedureFactory::edbPackageProcedureFactory()
|
|
: edbPackageFunctionFactory(__("Procedure"), __("New Procedure..."), __("Create a new Procedure."), procedure_png_img)
|
|
{
|
|
}
|
|
|
|
edbPackageProcedureFactory packageProcedureFactory;
|
|
static pgaCollectionFactory cfp(&packageProcedureFactory, __("Procedures"), procedures_png_img);
|
|
|
|
|