diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py new file mode 100644 index 000000000..6437f6ae7 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py @@ -0,0 +1,300 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +""" Implements Catalog objects Node.""" + +from flask import render_template +from flask.ext.babel import gettext +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.server_groups.servers.databases.schemas.utils \ + import SchemaChildModule +import pgadmin.browser.server_groups.servers.databases as database +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +from functools import wraps + + +class CatalogObjectModule(SchemaChildModule): + """ + class CatalogObjectModule(SchemaChildModule) + + A module class for Catalog objects node derived from SchemaChildModule. + + Methods: + ------- + * __init__(*args, **kwargs) + - Method is used to initialize the Catalog objects and it's base module. + + * get_nodes(gid, sid, did, scid, coid) + - Method is used to generate the browser collection node. + + * script_load() + - Load the module script for Catalog objects, when any of the server node + is initialized. + """ + NODE_TYPE = 'catalog_object' + COLLECTION_LABEL = gettext("Catalog Objects") + + # Flag for not to show node under Schema/Catalog node + # By default its set to True to display node in schema/catalog + # We do not want to display 'Catalog Objects' under Schema/Catalog + # but only in information_schema/sys/dbo + CATALOG_DB_SUPPORTED = False + SUPPORTED_SCHEMAS = ['information_schema', 'sys', 'dbo'] + + def __init__(self, *args, **kwargs): + """ + Method is used to initialize the CatalogObjectModule and it's base module. + + Args: + *args: + **kwargs: + """ + super(CatalogObjectModule, self).__init__(*args, **kwargs) + self.min_ver = None + self.max_ver = None + + def get_nodes(self, gid, sid, did, scid): + """ + Generate the collection node + """ + yield self.generate_browser_collection_node(scid) + + @property + def script_load(self): + """ + Load the module script for server, when any of the database node is + initialized. + """ + return database.DatabaseModule.NODE_TYPE + +blueprint = CatalogObjectModule(__name__) + + +class CatalogObjectView(PGChildNodeView): + """ + This class is responsible for generating routes for Catalog objects node. + + Methods: + ------- + * check_precondition() + - This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + + * list() + - Lists all the Catalog objects nodes within that collection. + + * nodes() + - Creates all the nodes of type Catalog objects. + + * properties(gid, sid, did, scid, coid) + - Shows the properties of the selected Catalog objects node. + + * dependency(gid, sid, did, scid): + - Returns the dependencies list for the given catalog object node. + + * dependent(gid, sid, did, scid): + - Returns the dependents list for the given Catalog objects node. + """ + node_type = blueprint.node_type + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'}, + {'type': 'int', 'id': 'did'}, + {'type': 'int', 'id': 'scid'} + ] + ids = [ + {'type': 'int', 'id': 'coid'} + ] + + operations = dict({ + 'obj': [{'get': 'properties'}, {'get': 'list'}], + 'children': [{'get': 'children'}], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'sql': [{'get': 'sql'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'module.js': [{}, {}, {'get': 'module_js'}] + }) + + def check_precondition(f): + """ + This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + """ + @wraps(f) + def wrap(*args, **kwargs): + # Here args[0] will hold self & kwargs will hold gid,sid,did + self = args[0] + self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( + kwargs['sid'] + ) + self.conn = self.manager.connection(did=kwargs['did']) + # If DB not connected then return error to browser + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + self.template_path = 'catalog_object/sql/{0}/9.1_plus'.format( + 'ppas' if self.manager.server_type == 'ppas' else 'pg' + ) + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid): + """ + This function is used to list all the catalog objects + nodes within that collection. + + Args: + gid: Server group ID + sid: Server ID + did: Database ID + scid: Schema ID + + Returns: + JSON of available catalog objects nodes + """ + + SQL = render_template("/".join([ + self.template_path, 'properties.sql' + ]), scid=scid + ) + + status, res = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + return ajax_response( + response=res['rows'], + status=200 + ) + + @check_precondition + def nodes(self, gid, sid, did, scid): + """ + This function will used to create all the child node within that collection. + Here it will create all the catalog objects node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + + Returns: + JSON of available catalog objects child nodes + """ + res = [] + SQL = render_template( + "/".join([self.template_path, 'nodes.sql']), scid=scid + ) + + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=rset) + + for row in rset['rows']: + res.append( + self.blueprint.generate_browser_node( + row['oid'], + scid, + row['name'], + icon="icon-catalog_object" + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, coid): + """ + This function will show the properties of the selected + catalog objects node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + scid: Schema ID + coid: Catalog object ID + + Returns: + JSON of selected catalog objects node + """ + SQL = render_template( + "/".join([self.template_path, 'properties.sql']), + scid=scid, coid=coid + ) + status, res = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + + return ajax_response( + response=res['rows'][0], + status=200 + ) + + @check_precondition + def dependents(self, gid, sid, did, scid, coid): + """ + This function get the dependents and return ajax response + for the catalog objects node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + coid: catalog objects ID + """ + dependents_result = self.get_dependents(self.conn, coid) + + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, coid): + """ + This function get the dependencies and return ajax response + for the catalog objects node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + coid: catalog objects ID + """ + dependencies_result = self.get_dependencies(self.conn, coid) + + return ajax_response( + response=dependencies_result, + status=200 + ) + +CatalogObjectView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py new file mode 100644 index 000000000..8f5a734d2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py @@ -0,0 +1,343 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +""" Implements Columns Node (For Catalog objects) """ + +from flask import render_template +from flask.ext.babel import gettext +from pgadmin.utils.ajax import make_json_response, \ + make_response as ajax_response, internal_server_error +from pgadmin.browser.utils import PGChildNodeView +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers.databases as database +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +from functools import wraps + + +class CatalogObjectColumnsModule(CollectionNodeModule): + """ + class ColumnModule(CollectionNodeModule) + + A module class for column node derived from CollectionNodeModule. + + Methods: + ------- + * __init__(*args, **kwargs) + - Method is used to initialize the column and it's base module. + + * get_nodes(gid, sid, did, scid, coid) + - Method is used to generate the browser collection node. + + * node_inode() + - Method is overridden from its base class to make the node as leaf node. + + * script_load() + - Load the module script for column, when any of the server node is + initialized. + """ + + NODE_TYPE = 'catalog_object_column' + COLLECTION_LABEL = gettext("Columns") + + def __init__(self, *args, **kwargs): + """ + Method is used to initialize the ColumnModule and it's base module. + + Args: + *args: + **kwargs: + """ + super(CatalogObjectColumnsModule, self).__init__(*args, **kwargs) + self.min_ver = None + self.max_ver = None + + def get_nodes(self, gid, sid, did, scid, coid): + """ + Generate the collection node + """ + yield self.generate_browser_collection_node(coid) + + @property + def script_load(self): + """ + Load the module script for server, when any of the database node is + initialized. + """ + return database.DatabaseModule.NODE_TYPE + + @property + def node_inode(self): + """ + Load the module node as a leaf node + """ + return False + +blueprint = CatalogObjectColumnsModule(__name__) + + +class CatalogObjectColumnsView(PGChildNodeView): + """ + This class is responsible for generating routes for column node + + Methods: + ------- + * __init__(**kwargs) + - Method is used to initialize the ColumnView and it's base view. + + * check_precondition() + - This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + + * list() + - Returns the properties of all the columns for the catalog object. + + * nodes() + - Creates and returns all the children nodes of type - catalog object + column. + + * properties(gid, sid, did, scid, coid, clid) + - Returns the properties of the given catalog-object column node. + + * dependency(gid, sid, did, scid, coid, clid): + - Returns the dependencies list of the given node. + + * dependent(gid, sid, did, scid, coid, clid): + - Returns the dependents list of the given node. + """ + + node_type = blueprint.node_type + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'}, + {'type': 'int', 'id': 'did'}, + {'type': 'int', 'id': 'scid'}, + {'type': 'int', 'id': 'coid'} + ] + ids = [ + {'type': 'int', 'id': 'clid'} + ] + + operations = dict({ + 'obj': [{'get': 'properties'}, {'get': 'list'}], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'sql': [{'get': 'sql'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'module.js': [{}, {}, {'get': 'module_js'}] + }) + + def check_precondition(f): + """ + This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + """ + @wraps(f) + def wrap(*args, **kwargs): + # Here args[0] will hold self & kwargs will hold gid,sid,did + self = args[0] + self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( + kwargs['sid'] + ) + self.conn = self.manager.connection(did=kwargs['did']) + # If DB not connected then return error to browser + if not self.conn.connected(): + return precondition_required( + gettext( + "Connection to the server has been lost!" + ) + ) + + self.template_path = 'catalog_object_column/sql/9.1_plus' + + return f(*args, **kwargs) + + return wrap + + @check_precondition + def list(self, gid, sid, did, scid, coid): + """ + This function is used to list all the column + nodes within that collection. + + Args: + gid: Server group ID + sid: Server ID + did: Database ID + scid: Schema ID + coid: Catalog objects ID + + Returns: + JSON of available column nodes + """ + SQL = render_template("/".join([self.template_path, + 'properties.sql']), coid=coid) + status, res = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + return ajax_response( + response=res['rows'], + status=200 + ) + + @check_precondition + def nodes(self, gid, sid, did, scid, coid): + """ + This function will used to create all the child node within that collection. + Here it will create all the column node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + coid: Catalog objects ID + + Returns: + JSON of available column child nodes + """ + res = [] + SQL = render_template("/".join([self.template_path, + 'nodes.sql']), coid=coid) + status, rset = self.conn.execute_2darray(SQL) + if not status: + return internal_server_error(errormsg=rset) + + for row in rset['rows']: + res.append( + self.blueprint.generate_browser_node( + row['atttypid'], + coid, + row['attname'], + icon="icon-catalog_object_column" + )) + + return make_json_response( + data=res, + status=200 + ) + + @check_precondition + def properties(self, gid, sid, did, scid, coid, clid): + """ + This function will show the properties of the selected + column node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + scid: Schema ID + coid: Catalog object ID + clid: Column ID + + Returns: + JSON of selected column node + """ + SQL = render_template("/".join([self.template_path, + 'properties.sql']),coid=coid, clid=clid) + status, res = self.conn.execute_dict(SQL) + + if not status: + return internal_server_error(errormsg=res) + + return ajax_response( + response=res['rows'][0], + status=200 + ) + + @check_precondition + def dependents(self, gid, sid, did, scid, coid, clid): + """ + This function get the dependents and return ajax response + for the column node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + coid: Catalog object ID + clid: Column ID + """ + # Specific condition for column which we need to append + where = "WHERE dep.refobjid={0}::OID AND dep.refobjsubid={1}".format( + coid, clid + ) + + dependents_result = self.get_dependents( + self.conn, clid, where=where + ) + + # Specific sql to run againt column to fetch dependents + SQL = render_template("/".join([self.template_path, + 'depend.sql']), where=where) + + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + for row in res['rows']: + ref_name = row['refname'] + if ref_name is None: + continue + + dep_type = '' + dep_str = row['deptype'] + if dep_str == 'a': + dep_type = 'auto' + elif dep_str == 'n': + dep_type = 'normal' + elif dep_str == 'i': + dep_type = 'internal' + + dependents_result.append({'type': 'sequence', 'name': ref_name, 'field': dep_type}) + + return ajax_response( + response=dependents_result, + status=200 + ) + + @check_precondition + def dependencies(self, gid, sid, did, scid, coid, clid): + """ + This function get the dependencies and return ajax response + for the column node. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + coid: Catalog objects ID + clid: Column ID + + """ + # Specific condition for column which we need to append + where = "WHERE dep.objid={0}::OID AND dep.objsubid={1}".format( + coid, clid + ) + + dependencies_result = self.get_dependencies( + self.conn, clid, where=where + ) + + return ajax_response( + response=dependencies_result, + status=200 + ) + + +CatalogObjectColumnsView.register_node_view(blueprint) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/static/img/catalog_object_column.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/static/img/catalog_object_column.png new file mode 100644 index 000000000..bd9f81df9 Binary files /dev/null and b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/static/img/catalog_object_column.png differ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/static/img/coll-catalog_object_column.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/static/img/coll-catalog_object_column.png new file mode 100644 index 000000000..89d758834 Binary files /dev/null and b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/static/img/coll-catalog_object_column.png differ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/js/catalog_object_column.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/js/catalog_object_column.js new file mode 100644 index 000000000..3c6a9ffd7 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/js/catalog_object_column.js @@ -0,0 +1,73 @@ +define( + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-catalog_object_column']) { + var databases = pgAdmin.Browser.Nodes['coll-catalog_object_column'] = + pgAdmin.Browser.Collection.extend({ + node: 'catalog_object_column', + label: '{{ _('catalog_object_column') }}', + type: 'coll-catalog_object_column' + }); + }; + + if (!pgBrowser.Nodes['catalog_object_column']) { + pgAdmin.Browser.Nodes['catalog_object_column'] = + pgAdmin.Browser.Node.extend({ + parent_type: 'catalog_object', + type: 'catalog_object_column', + label: '{{ _('catalog_object_column') }}', + hasSQL: false, + hasDepends: true, + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + }, + model: pgAdmin.Browser.Node.Model.extend({ + defaults: { + attname: undefined, + attowner: undefined, + atttypid: undefined, + attnum: undefined, + cltype: undefined, + collspcname: undefined, + attacl: undefined, + description: undefined + }, + schema: [{ + id: 'attname', label: '{{ _('Column') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'atttypid', label: '{{ _('Oid') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'attowner', label: '{{ _('Owner') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'attnum', label:'{{ _('Position') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'cltype', label:'{{ _('Data type') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'collspcname', label:'{{ _('Collation') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'attacl', label:'{{ _('ACL') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'description', label:'{{ _('Comment') }}', cell: 'string', + type: 'multiline', disabled: true + } + ] + }) + }); + + } + + return pgBrowser.Nodes['catalog_object_column']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/depend.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/depend.sql new file mode 100644 index 000000000..024103f09 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/depend.sql @@ -0,0 +1,10 @@ +SELECT + ref.relname AS refname, d2.refclassid, dep.deptype AS deptype +FROM pg_depend dep + LEFT JOIN pg_depend d2 ON dep.objid=d2.objid AND dep.refobjid != d2.refobjid + LEFT JOIN pg_class ref ON ref.oid=d2.refobjid + LEFT JOIN pg_attribute att ON d2.refclassid=att.attrelid AND d2.refobjsubid=att.attnum +{{ where }} AND + dep.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef') AND + dep.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d2.refobjid) +ORDER BY refname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/nodes.sql new file mode 100644 index 000000000..66c25bf0a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/nodes.sql @@ -0,0 +1,7 @@ +SELECT + atttypid, attname +FROM pg_attribute att +WHERE att.attrelid = {{coid}}::oid + AND att.attnum > 0 + AND att.attisdropped IS FALSE +ORDER BY att.attnum diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/properties.sql new file mode 100644 index 000000000..5a6c0d8c1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/templates/catalog_object_column/sql/9.1_plus/properties.sql @@ -0,0 +1,41 @@ +SELECT + att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval, + CASE WHEN att.attndims > 0 THEN 1 ELSE 0 END AS isarray, + format_type(ty.oid,NULL) AS typname, + format_type(ty.oid,att.atttypmod) AS displaytypname, + tn.nspname as typnspname, et.typname as elemtypname, + ty.typstorage AS defaultstorage, cl.relname, na.nspname, + att.attstattarget, description, cs.relname AS sername, + ns.nspname AS serschema, + (SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup, + indkey, coll.collname, nspc.nspname as collnspname , attoptions, + -- Start pgAdmin4, added to save time on client side parsing + CASE WHEN length(coll.collname) > 0 AND length(nspc.nspname) > 0 THEN + concat(coll.collname,'."',nspc.nspname,'"') + ELSE '' END AS collspcname, + CASE WHEN strpos(format_type(ty.oid,att.atttypmod), '.') > 0 THEN + split_part(format_type(ty.oid,att.atttypmod), '.', 2) + ELSE format_type(ty.oid,att.atttypmod) END AS cltype, + -- End pgAdmin4 + EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f' AND att.attnum=ANY(conkey)) As isfk, + (SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=att.attrelid AND sl1.objsubid=att.attnum) AS labels, + (SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=att.attrelid AND sl2.objsubid=att.attnum) AS providers +FROM pg_attribute att + JOIN pg_type ty ON ty.oid=atttypid + JOIN pg_namespace tn ON tn.oid=ty.typnamespace + JOIN pg_class cl ON cl.oid=att.attrelid + JOIN pg_namespace na ON na.oid=cl.relnamespace + LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem + LEFT OUTER JOIN pg_attrdef def ON adrelid=att.attrelid AND adnum=att.attnum + LEFT OUTER JOIN pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass) + LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=att.attrelid AND refobjsubid=att.attnum + LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace + LEFT OUTER JOIN pg_index pi ON pi.indrelid=att.attrelid AND indisprimary + LEFT OUTER JOIN pg_collation coll ON att.attcollation=coll.oid + LEFT OUTER JOIN pg_namespace nspc ON coll.collnamespace=nspc.oid +WHERE att.attrelid = {{coid}}::oid{% if clid %} + AND att.atttypid = {{clid}}::oid +{% endif %} + AND att.attnum > 0 + AND att.attisdropped IS FALSE +ORDER BY att.attnum diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/static/img/catalog_object.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/static/img/catalog_object.png new file mode 100644 index 000000000..54ed7389c Binary files /dev/null and b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/static/img/catalog_object.png differ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/static/img/coll-catalog_object.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/static/img/coll-catalog_object.png new file mode 100644 index 000000000..85b89f1e7 Binary files /dev/null and b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/static/img/coll-catalog_object.png differ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/js/catalog_object.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/js/catalog_object.js new file mode 100644 index 000000000..fa5198be6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/js/catalog_object.js @@ -0,0 +1,56 @@ +define( + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'], +function($, _, S, pgAdmin, pgBrowser, alertify) { + + if (!pgBrowser.Nodes['coll-catalog_object']) { + var databases = pgAdmin.Browser.Nodes['coll-catalog_object'] = + pgAdmin.Browser.Collection.extend({ + node: 'catalog_object', + label: '{{ _('Catalog Objects') }}', + type: 'coll-catalog_object' + }); + }; + + if (!pgBrowser.Nodes['catalog_object']) { + pgAdmin.Browser.Nodes['catalog_object'] = pgAdmin.Browser.Node.extend({ + parent_type: 'catalog', + type: 'catalog_object', + label: '{{ _('Catalog Object') }}', + hasSQL: false, + hasDepends: true, + Init: function() { + /* Avoid mulitple registration of menus */ + if (this.initialized) + return; + + this.initialized = true; + + }, + model: pgAdmin.Browser.Node.Model.extend({ + defaults: { + name: undefined, + namespaceowner: undefined, + nspacl: undefined, + description: undefined, + }, + schema: [{ + id: 'name', label: '{{ _('Name') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'oid', label:'{{ _('Oid') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'owner', label:'{{ _('Owner') }}', cell: 'string', + type: 'text', disabled: true + },{ + id: 'description', label:'{{ _('Comment') }}', cell: 'string', + type: 'multiline' , disabled: true + } + ] + }) + }); + + } + + return pgBrowser.Nodes['catalog_object']; +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/pg/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/pg/9.1_plus/nodes.sql new file mode 100644 index 000000000..8a8dad08e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/pg/9.1_plus/nodes.sql @@ -0,0 +1,6 @@ +SELECT + c.oid, c.relname as name +FROM + pg_class c +WHERE relnamespace = {{scid}}::int +ORDER BY relname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/pg/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/pg/9.1_plus/properties.sql new file mode 100644 index 000000000..dc5a64c72 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/pg/9.1_plus/properties.sql @@ -0,0 +1,12 @@ +SELECT + c.oid, c.relname as name, r.rolname AS owner, description +FROM + pg_class c + LEFT OUTER JOIN pg_description d + ON d.objoid=c.oid AND d.classoid='pg_class'::regclass + LEFT JOIN pg_roles r ON c.relowner = r.oid +WHERE + relnamespace = {{scid}}::int +{% if coid %} AND + c.oid = {{coid}}::int +{% endif %} ORDER BY relname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/ppas/9.1_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/ppas/9.1_plus/nodes.sql new file mode 100644 index 000000000..f510f49ef --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/ppas/9.1_plus/nodes.sql @@ -0,0 +1,11 @@ +SELECT + c.oid, c.relname as name +FROM pg_class c +WHERE relnamespace = {{scid}}::int +OR ( + -- On EnterpriseDB we need to ignore some objects in the catalog, namely, _*, dual and type_object_source. + select 'sys' ~ (SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{scid}}::int) + AND + (c.relname NOT LIKE '\\_%' AND c.relname = 'dual' AND c.relname = 'type_object_source') + ) +ORDER BY relname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/ppas/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/ppas/9.1_plus/properties.sql new file mode 100644 index 000000000..2e9ba91db --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/templates/catalog_object/sql/ppas/9.1_plus/properties.sql @@ -0,0 +1,23 @@ +SELECT + c.oid, c.relname as name, r.rolname AS owner, description +FROM + pg_class c + LEFT OUTER JOIN pg_description d + ON d.objoid=c.oid AND d.classoid='pg_class'::regclass + LEFT JOIN pg_roles r ON c.relowner = r.oid +WHERE + relnamespace = {{scid}}::int +{% if coid %} AND + c.oid = {{coid}}::int +{% endif %} OR ( + -- On EnterpriseDB - ignore some objects in the catalog, whose name starts + -- with _*, dual and type_object_source. + SELECT 'sys' ~ ( + SELECT nsp.nspname FROM pg_namespace nsp + WHERE nsp.oid = {{scid}}::int + ) AND ( + c.relname NOT LIKE '\\_%' AND c.relname = 'dual' AND + c.relname = 'type_object_source' + ) +) +ORDER BY relname;