pgadmin3/schema/edbPackageFunction.cpp
2020-07-07 22:19:12 +05:00

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);