Add support for Schemas and Catalogs.

Initial patch by Murtuza Zabuawala with further hacking by Ashesh Vashi and I.
This commit is contained in:
Dave Page 2016-03-08 15:48:11 +00:00
parent 785d180451
commit a92d4841d1
94 changed files with 3304 additions and 0 deletions

View File

@ -0,0 +1,987 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
import re
from flask import render_template, request, jsonify, current_app
from flask.ext.babel import gettext
from pgadmin.utils.ajax import make_json_response, \
make_response as ajax_response, internal_server_error, gone, \
bad_request
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.browser.collection import CollectionNodeModule, PGChildModule
import pgadmin.browser.server_groups.servers as servers
from pgadmin.utils.ajax import precondition_required
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
parse_priv_to_db
from functools import wraps
"""
This module is responsible for generating two nodes
1) Schema
2) Catalog
We have created single file because catalog & schema has same
functionality, the only difference is we can not perform DDL/DML operations
on catalog, also - it allows us to share the same submodules for both
catalog, and schema modules.
This modules uses separate template paths for each respective node
- templates/catalog for Catalog node
- templates/schema for Schema node
[Each path contains node specific js files as well as sql template files.]
"""
class SchemaModule(CollectionNodeModule):
"""
class SchemaModule(CollectionNodeModule)
A module class for Schema node derived from CollectionNodeModule.
Methods:
-------
* __init__(*args, **kwargs)
- Method is used to initialize the Schema and it's base module.
* get_nodes(gid, sid, did)
- 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 schema, when any of the server node is
initialized.
"""
NODE_TYPE = 'schema'
COLLECTION_LABEL = gettext("Schemas")
def __init__(self, *args, **kwargs):
"""
Method is used to initialize the SchemaModule and it's base module.
Args:
*args:
**kwargs:
"""
self.min_ver = None
self.max_ver = None
super(SchemaModule, self).__init__(*args, **kwargs)
def get_nodes(self, gid, sid, did):
"""
Generate the collection node
"""
yield self.generate_browser_collection_node(did)
@property
def script_load(self):
"""
Load the module script for server, when any of the server-group node is
initialized.
"""
return servers.ServerModule.NODE_TYPE
class CatalogModule(SchemaModule):
"""
class CatalogModule(SchemaModule)
A module class for the catalog schema node derived from SchemaModule.
"""
NODE_TYPE = 'catalog'
COLLECTION_LABEL = gettext("Catalogs")
schema_blueprint = SchemaModule(__name__)
catalog_blueprint = CatalogModule(__name__)
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 instance of the method.
Assumptions:
This function will always be used as decorator of a class method.
"""
@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!")
)
# Set template path for sql scripts
self.template_path = self.template_initial + '/' + (
self.ppas_template_path(self.manager.version)
if self.manager.server_type == 'ppas' else
self.pg_template_path(self.manager.version)
)
return f(*args, **kwargs)
return wrap
class SchemaView(PGChildNodeView):
"""
This class is responsible for generating routes for schema node.
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the SchemaView and it's base view.
* module_js()
- Request handler for module.js routes for the schema node module
javascript, which returns javscript for this module.
* list()
- This function is used to list all the schema nodes within the
collection.
* nodes()
- This function will used to create all the child node within the
collection, Here it will create all the schema node.
* properties(gid, sid, did, scid)
- This function will show the properties of the selected schema node.
* create(gid, sid, did, scid)
- This function will create the new schema object.
* update(gid, sid, did, scid)
- This function will update the data for the selected schema node.
* delete(self, gid, sid, scid):
- This function will drop the schema object
* msql(gid, sid, did, scid)
- This function is used to return modified SQL for the selected schema
node.
* get_sql(data, scid)
- This function will generate sql from model data
* sql(gid, sid, did, scid):
- This function will generate sql to show it in sql pane for the schema
node.
* dependency(gid, sid, did, scid):
- This function will generate dependency list show it in dependency
pane for the selected schema node.
* dependent(gid, sid, did, scid):
- This function will generate dependent list to show it in dependent
pane for the selected schema node.
"""
node_type = schema_blueprint.node_type
parent_ids = [
{'type': 'int', 'id': 'gid'},
{'type': 'int', 'id': 'sid'},
{'type': 'int', 'id': 'did'}
]
ids = [
{'type': 'int', 'id': 'scid'}
]
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'}
],
'children': [{ 'get': 'children'}],
'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}],
'stats': [{'get': 'statistics'}],
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'delete': [{'delete': 'delete'}]
})
def __init__(self, *args, **kwargs):
"""
Initialize the variables used by methods of SchemaView.
"""
super(SchemaView, self).__init__(*args, **kwargs)
self.manager = None
self.conn = None
self.template_path = None
self.template_initial = 'schema'
@staticmethod
def ppas_template_path(ver):
"""
Returns the template path for PPAS servers.
"""
if ver >= 90200:
return 'ppas/9.2_plus'
return 'ppas/9.1_plus'
@staticmethod
def pg_template_path(ver):
"""
Returns the template path for PostgreSQL servers.
"""
if ver >= 90200:
return 'pg/9.2_plus'
return 'pg/9.1_plus'
def format_request_acls(self, data, modified=False, specific=None):
acls = {}
try:
acls = render_template(
"/".join([self.template_path, 'allowed_privs.json'])
)
acls = json.loads(acls)
except Exception as e:
current_app.logger.exception(e)
# Privileges
for aclcol in acls:
if specific is not None:
if aclcol not in specific:
continue
if aclcol in data:
allowedacl = acls[aclcol]
if modified:
for modifier in ['added', 'changed', 'deleted']:
if modifier in data[aclcol]:
data[aclcol][modifier] = parse_priv_to_db(
data[aclcol][modifier], allowedacl['acl']
)
else:
data[aclcol] = parse_priv_to_db(data[aclcol], allowedacl['acl'])
return acls
@staticmethod
def formatdbacl(acl):
"""
Args:
acl: Privileges from ACL query
Returns:
Formatted output required for client side parsing
"""
# Reset any data for that acl if its already present in result set
data = dict()
for row in acl['rows']:
priv = parse_priv_from_db(row)
if row['deftype'] in data:
data[row['deftype']].append(priv)
else:
data[row['deftype']] = [priv]
return data
def _formatter_no_defacl(self, data, scid=None):
"""
Args:
data: Result of properties query
scid: Schema OID
Returns:
It will return formatted output of collections like
security lables, privileges
"""
# Need to format security labels according to client js collection
seclabels = []
if 'seclabels' in data and data['seclabels'] is not None:
for sec in data['seclabels']:
sec = re.search(r'([^=]+)=(.*$)', sec)
seclabels.append({
'provider': sec.group(1),
'security_label': sec.group(2)
})
data['seclabels'] = seclabels
# We need to parse & convert ACL coming from database to json format
SQL = render_template(
"/".join([self.template_path, 'sql/acl.sql']),
_=gettext,
scid=scid
)
status, acl = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=acl)
data.update(self.formatdbacl(acl))
return data
def _formatter(self, data, scid=None):
self._formatter_no_defacl(data, scid)
# We need to parse & convert DEFAULT ACL coming from
# database to json format
SQL = render_template(
"/".join([self.template_path, 'sql/defacl.sql']),
_=gettext,
scid=scid
)
status, defacl = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=defacl)
data.update(self.formatdbacl(defacl))
return data
@check_precondition
def list(self, gid, sid, did):
"""
This function is used to list all the schema nodes within the collection.
Args:
gid: Server group ID
sid: Server ID
did: Database ID
Returns:
JSON of available schema nodes
"""
SQL = render_template(
"/".join([self.template_path, 'sql/properties.sql']),
_=gettext,
show_sysobj=self.blueprint.show_system_objects
)
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=None):
"""
This function will create all the child nodes within the collection
Here it will create all the schema node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
Returns:
JSON of available schema child nodes
"""
res = []
SQL = render_template(
"/".join([self.template_path, 'sql/nodes.sql']),
show_sysobj=self.blueprint.show_system_objects,
_=gettext,
scid=scid
)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
if scid is not None:
if len(rset['rows']) == 0:
return gone(gettext("""
Could not find the schema in the database.
It may have been removed by another user.
"""))
icon = 'icon-{0}'.format(self.node_type)
for row in rset['rows']:
res.append(
self.blueprint.generate_browser_node(
row['oid'],
did,
row['name'],
icon=icon,
can_create=row['can_create'],
has_usage=row['has_usage']
)
)
return make_json_response(
data=res,
status=200
)
@check_precondition
def properties(self, gid, sid, did, scid):
"""
This function will show the properties of the selected schema node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of selected schema node
"""
SQL = render_template(
"/".join([self.template_path, 'sql/properties.sql']),
scid=scid,
_=gettext,
show_sysobj=self.blueprint.show_system_objects
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(gettext("""
Could not find the schema in the database.
It may have been removed by another user.
"""))
# Making copy of output for future use
copy_data = dict(res['rows'][0])
copy_data = self._formatter(copy_data, scid)
return ajax_response(
response=copy_data,
status=200
)
@check_precondition
def create(self, gid, sid, did):
"""
This function will create a schema object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
"""
data = request.form if request.form else \
json.loads(request.data.decode())
required_args = {
'name': 'Name'
}
for arg in required_args:
if arg not in data:
return make_json_response(
status=410,
success=0,
errormsg=gettext(
"Couldn't find the required parameter (%s)." %
required_args[arg]
)
)
try:
SQL = render_template(
"/".join([self.template_path, 'sql/create.sql']),
data=data, conn=self.conn, _=gettext
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return make_json_response(
status=410,
success=0,
errormsg=res + '\n' +
'Operation failed while running create statement'
)
self.format_request_acls(data, specific=['nspacl'])
SQL = render_template(
"/".join([self.template_path, 'sql/alter.sql']),
data=data, conn=self.conn, _=gettext
)
# Checking if we are not executing empty query
if SQL and SQL.strip('\n') and SQL.strip(' '):
status, res = self.conn.execute_scalar(SQL)
if not status:
return make_json_response(
status=410,
success=0,
errormsg=res + '\n' +
'Operation failed while running alter statement'
)
# we need oid to to add object in tree at browser,
# below sql will gives the same
SQL = render_template(
"/".join([self.template_path, 'sql/oid.sql']),
schema=data['name'], _=gettext
)
status, scid = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=scid)
icon = 'icon-{0}'.format(self.node_type)
return jsonify(
node=self.blueprint.generate_browser_node(
scid,
did,
data['name'],
icon=icon
)
)
except Exception as e:
current_app.logger.exception(e)
return internal_server_error(errormsg=str(e))
@check_precondition
def update(self, gid, sid, did, scid):
"""
This function will update an existing schema object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
data = request.form if request.form else json.loads(
request.data.decode()
)
try:
SQL = self.get_sql(gid, sid, data, scid)
if SQL and SQL.strip('\n') and SQL.strip(' '):
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info="Updated",
data={
'id': scid,
'sid': sid,
'gid': gid,
'did': did
}
)
else:
return make_json_response(
success=1,
info="Nothing to update",
data={
'id': scid,
'sid': sid,
'gid': gid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def delete(self, gid, sid, did, scid):
"""
This function will delete an existing schema object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
try:
# Get name for schema from did
SQL = render_template(
"/".join([self.template_path, 'sql/get_name.sql']),
_=gettext,
scid=scid
)
status, name = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=name)
# drop schema
SQL = render_template(
"/".join([self.template_path, 'sql/delete.sql']),
_=gettext, name=name, conn=self.conn,
cascade=True if self.cmd == 'delete' else False
)
status, res = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info=gettext("Schema dropped"),
data={
'id': scid,
'sid': sid,
'gid': gid,
'did': did
}
)
except Exception as e:
current_app.logger.exception(e)
return internal_server_error(errormsg=str(e))
@check_precondition
def msql(self, gid, sid, did, scid=None):
"""
This function will generate modified sql for schema object based on
the input from the user. This route is used by the SQL tab in the
edit/create dialog.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID (When working with existing schema node)
"""
data = dict()
for k, v in request.args.items():
try:
data[k] = json.loads(v)
except ValueError:
data[k] = v
try:
SQL = self.get_sql(gid, sid, data, scid)
if SQL and SQL.strip('\n') and SQL.strip(' '):
return make_json_response(
data=SQL,
status=200
)
except Exception as e:
return internal_server_error(errormsg=str(e))
def get_sql(self, gid, sid, data, scid=None):
"""
This function will generate sql from model data received from client
"""
if scid is not None:
SQL = render_template(
"/".join([self.template_path, 'sql/properties.sql']),
_=gettext, scid=scid,
show_sysobj=self.blueprint.show_system_objects
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
old_data = res['rows'][0]
# old_data contains all the existing data for requested schema
old_data = self._formatter(old_data, scid)
# if name is not present in request data then use old name
if 'name' not in data:
data['name'] = old_data['name']
# Privileges and Default privileges
self.format_request_acls(data, True)
SQL = render_template(
"/".join([self.template_path, 'sql/update.sql']),
_=gettext, data=data, o_data=old_data, conn=self.conn
)
else:
required_args = ['name']
for arg in required_args:
if arg not in data:
return " -- " + gettext("definition incomplete")
# Privileges
self.format_request_acls(data, specific=['nspacl'])
SQL = render_template(
"/".join([self.template_path, 'sql/create.sql']),
data=data, conn=self.conn, _=gettext
)
SQL += "\n"
SQL += render_template(
"/".join([self.template_path, 'sql/alter.sql']),
_=gettext, data=data, conn=self.conn
)
return SQL
@check_precondition
def sql(self, gid, sid, did, scid):
"""
This function will generate reverse engineered sql for the schema
object.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
SQL = render_template(
"/".join([self.template_path, 'sql/properties.sql']),
scid=scid, _=gettext
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(gettext("""
Could not find the schema in the database.
It may have been removed by another user.
"""))
data = res['rows'][0]
data = self._formatter(data, scid)
# Privileges and Default privileges
self.format_request_acls(data)
# Render sql from create & alter sql using properties & acl data
SQL = ''
SQL = render_template(
"/".join([self.template_path, 'sql/create.sql']),
_=gettext, data=data, conn=self.conn
)
SQL += "\n"
SQL += render_template(
"/".join([self.template_path, 'sql/alter.sql']),
_=gettext, data=data, conn=self.conn
)
sql_header = """
-- SCHEMA: {0}
-- DROP SCHEMA {0};
""".format(data['name'])
SQL = sql_header + SQL
return ajax_response(response=SQL.strip("\n"))
@check_precondition
def dependents(self, gid, sid, did, scid):
"""
This function gets the dependencies and returns an ajax response.
for the schema node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
dependents_result = self.get_dependents(self.conn, scid)
return ajax_response(
response=dependents_result,
status=200
)
@check_precondition
def dependencies(self, gid, sid, did, scid):
"""
This function get the dependencies and return ajax response
for the schema node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
dependencies_result = self.get_dependencies(self.conn, scid)
return ajax_response(
response=dependencies_result,
status=200
)
@check_precondition
def children(self, **kwargs):
"""Build a list of treeview nodes from the child nodes."""
SQL = render_template(
"/".join([self.template_path, 'sql/is_catalog.sql']),
scid=kwargs['scid'], _=gettext
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(gettext("""
Could not find the schema in the database.
It may have been removed by another user.
"""))
data = res['rows'][0]
backend_support_keywords = kwargs.copy()
backend_support_keywords['is_catalog'] = data['is_catalog']
backend_support_keywords['db_support'] = data['db_support']
backend_support_keywords['schema_name'] = data['schema_name']
nodes = []
for module in self.blueprint.submodules:
if isinstance(module, PGChildModule):
if self.manager is not None and \
module.BackendSupported(
self.manager, **backend_support_keywords
):
nodes.extend(module.get_nodes(**kwargs))
else:
nodes.extend(module.get_nodes(**kwargs))
return make_json_response(data=nodes)
class CatalogView(SchemaView):
"""
This class is responsible for generating routes for catalog schema node.
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the CatalogView and it's base view.
* module_js()
- This property defines (if javascript) exists for this node.
Override this property for your own logic
* create(gid, sid, did, scid)
- Raise an error - we can not create a catalog.
* update(gid, sid, did, scid)
- This function will update the data for the selected catalog node
* delete(self, gid, sid, scid):
- Raise an error - we can not delete a catalog.
* get_sql(data, scid)
- This function will generate sql from model data
"""
node_type = catalog_blueprint.node_type
def __init__(self, *args, **kwargs):
"""
Initialize the variables used by methods of SchemaView.
"""
super(CatalogView, self).__init__(*args, **kwargs)
self.template_initial = 'catalog'
def _formatter(self, data, scid=None):
"""
Overriding _formatter, because - we won't show the Default
privileges with the catalog schema.
"""
self._formatter_no_defacl(data, scid)
return data
def get_sql(self, gid, sid, data, scid=None):
"""
This function will generate sql from model data
"""
if scid is None:
return bad_request('Cannot create a catalog schema!')
return super(CatalogView, self).get_sql(gid, sid, data, scid)
@check_precondition
def sql(self, gid, sid, did, scid):
"""
This function will generate reverse engineered sql for schema object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
SQL = render_template(
"/".join([self.template_path, 'sql/properties.sql']),
scid=scid, _=gettext
)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(gettext("""
Could not find the schema in the database.
It may have been removed by another user.
"""))
old_data = res['rows'][0]
old_data = self._formatter(old_data, scid)
# Privileges
self.format_request_acls(old_data, specific=['nspacl'])
# Render sql from create & alter sql using properties & acl data
SQL = ''
SQL = render_template(
"/".join([self.template_path, 'sql/create.sql']),
_=gettext, data=old_data, conn=self.conn
)
SQL += "\n"
SQL += render_template(
"/".join([self.template_path, 'sql/alter.sql']),
_=gettext, data=old_data, conn=self.conn
)
sql_header = """
-- CATALOG: {0}
-- DROP SCHEMA {0};
""".format(old_data['name'])
SQL = sql_header + SQL
return ajax_response(response=SQL.strip("\n"))
SchemaView.register_node_view(schema_blueprint)
CatalogView.register_node_view(catalog_blueprint)

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

View File

@ -0,0 +1,111 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin',
'pgadmin.browser', 'backform', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
// Extend the browser's collection class for SecurityLabel control
var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
defaults: {
provider: null,
security_label: null
},
schema: [{
id: 'provider', label: '{{ _('Provider') }}',
type: 'text', disabled: false
},{
id: 'security_label', label: '{{ _('Security Label') }}',
type: 'text', disabled: false
}],
validate: function() {
var err = {},
errmsg = null;
if (_.isUndefined(this.get('security_label')) ||
_.isNull(this.get('security_label')) ||
String(this.get('security_label')).replace(/^\s+|\s+$/g, '') == '') {
errmsg = '{{ _('Please specify the value for all the security providers.')}}';
this.errorModel.set('security_label', errmsg);
return errmsg;
} else {
this.errorModel.unset('security_label');
}
return null;
}
});
// Extend the browser's collection class for catalog collection
if (!pgBrowser.Nodes['coll-catalog']) {
var databases = pgAdmin.Browser.Nodes['coll-catalog'] =
pgAdmin.Browser.Collection.extend({
node: 'catalog',
label: '{{ _('Catalogs') }}',
type: 'coll-catalog',
columns: ['name', 'oid', 'description']
});
};
// Extend the browser's node class for catalog node
if (!pgBrowser.Nodes['catalog']) {
pgAdmin.Browser.Nodes['catalog'] = pgAdmin.Browser.Node.extend({
parent_type: 'database',
type: 'catalog',
label: '{{ _('Catalog') }}',
hasSQL: true,
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,
securitylabel: []
},
initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0);
if (isNew) {
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
this.set({'namespaceowner': userInfo.name}, {silent: true});
}
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
},
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
type: 'text', disabled: true
},{
id: 'oid', label:'{{ _('Oid') }}', cell: 'string',
type: 'text', disabled: true
},{
id: 'namespaceowner', label:'{{ _('Owner') }}', cell: 'string',
type: 'text', disabled: true
},{
id: 'acl', label: '{{ _('Privileges') }}', type: 'text',
mode: ['properties'], disabled: true
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline'
},{
id: 'seclabels', label: '{{ _('Security Labels') }}',
model: SecurityModel, editable: false, type: 'collection',
group: '{{ _('Security') }}', mode: ['edit', 'create'],
min_version: 90200, canAdd: true,
canEdit: false, canDelete: true, control: 'unique-col-collection'
}
],
validate: function() {
return null;
}
})
});
}
return pgBrowser.Nodes['catalog'];
});

View File

@ -0,0 +1,26 @@
{# List of allowed privileges for PostgreSQL 9.1 #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "DATABASE",
"acl": ["c", "C", "T"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1 @@
{# We have nothing to alter in the catalog #}

View File

@ -0,0 +1,17 @@
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% if data %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}
{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,16 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
{{ CATALOGS.LABELS('nsp', _) }},
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,27 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
2 AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,30 @@
{% import 'macros/security.macros' as SECLABLE %}
{% if data %}
{# ==== To update catalog comments ==== #}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(o_data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ==== To update catalog securitylabel ==== #}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'SCHEMA', o_data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,30 @@
{# List of allowed privileges for PostgreSQL 9.2 or later #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "DATABASE",
"acl": ["c", "C", "T"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
},
"deftypeacl": {
"type": "TYPE",
"acl": ["U"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1 @@
{# We have nothing to alter in the catalog #}

View File

@ -0,0 +1,17 @@
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% if data %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}
{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,16 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
{{ CATALOGS.LABELS('nsp', _) }},
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,28 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
2 AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftypeacl' AND defaclnamespace = nsp.oid) AS typeacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,30 @@
{% import 'macros/security.macros' as SECLABLE %}
{% if data %}
{# ==== To update catalog comments ==== #}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(o_data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ==== To update catalog securitylabel ==== #}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'SCHEMA', o_data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,25 @@
{% macro LIST(tbl) -%}
({{ tbl }}.nspname = 'pg_catalog' AND EXISTS
(SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND
relnamespace = {{ tbl }}.oid LIMIT 1)) OR
({{ tbl }}.nspname = 'pgagent' AND EXISTS
(SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND
relnamespace = {{ tbl }}.oid LIMIT 1)) OR
({{ tbl }}.nspname = 'information_schema' AND EXISTS
(SELECT 1 FROM pg_class WHERE relname = 'tables' AND
relnamespace = {{ tbl }}.oid LIMIT 1))
{%- endmacro %}
{% macro LABELS(tbl, _) -%}
CASE {{ tbl }}.nspname
WHEN 'pg_catalog' THEN '{{ _( 'PostgreSQL Catalog' ) }} (pg_catalog)'
WHEN 'pgagent' THEN '{{ _( 'pgAgent Job Scheduler' ) }} (pgagent)'
WHEN 'information_schema' THEN '{{ _( 'ANSI' ) }} (information_schema)'
ELSE {{ tbl }}.nspname
END AS name
{%- endmacro %}
{% macro DB_SUPPORT(tbl) -%}
CASE
WHEN {{ tbl }}.nspname = ANY('{information_schema}')
THEN false
ELSE true END
{%- endmacro %}

View File

@ -0,0 +1,26 @@
{# List of allowed privileges for PPAS 9.1 #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "DATABASE",
"acl": ["c", "C", "T"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1 @@
{# We have nothing to alter in the catalog #}

View File

@ -0,0 +1,17 @@
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% if data %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}
{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,17 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
{{ CATALOGS.LABELS('nsp', _) }},
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
nsp.nspparent = 0 AND
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,31 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
CASE
WHEN (nspname LIKE E'pg\\_temp\\_%') THEN 1
WHEN (nspname LIKE E'pg\\_%') THEN 0
ELSE 3 END AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
nsp.nspparent = 0 AND
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,30 @@
{% import 'macros/security.macros' as SECLABLE %}
{% if data %}
{# ==== To update catalog comments ==== #}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(o_data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ==== To update catalog securitylabel ==== #}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'SCHEMA', o_data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,30 @@
{# List of allowed privileges for PPAS 9.2 or later #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "DATABASE",
"acl": ["c", "C", "T"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
},
"deftypeacl": {
"type": "TYPE",
"acl": ["U"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1 @@
{# We have nothing to alter in the catalog #}

View File

@ -0,0 +1,17 @@
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% if data %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}
{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,17 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
{{ CATALOGS.LABELS('nsp', _) }},
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
nsp.nspparent = 0 AND
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,29 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
2 END AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftypeacl' AND defaclnamespace = nsp.oid) AS typeacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% endif %}
nsp.nspparent = 0 AND
(
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,30 @@
{% import 'macros/security.macros' as SECLABLE %}
{% if data %}
{# ==== To update catalog comments ==== #}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(o_data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ==== To update catalog securitylabel ==== #}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'SCHEMA', o_data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', o_data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,29 @@
{% macro LIST(tbl) -%}
({{ tbl }}.nspname = 'pg_catalog' AND EXISTS
(SELECT 1 FROM pg_class
WHERE relname = 'pg_class' AND relnamespace = {{ tbl }}.oid LIMIT 1)) OR
({{ tbl }}.nspname = 'pgagent' AND EXISTS
(SELECT 1 FROM pg_class
WHERE relname = 'pga_job' AND relnamespace = {{ tbl }}.oid LIMIT 1)) OR
({{ tbl }}.nspname = 'information_schema' AND EXISTS
(SELECT 1 FROM pg_class
WHERE relname = 'tables' AND relnamespace = {{ tbl }}.oid LIMIT 1)) OR
({{ tbl }}.nspname = 'dbo' OR {{ tbl }}.nspname = 'sys') OR
{{ tbl }}.nspname = 'dbms_job_procedure' AND EXISTS
(SELECT 1 FROM pg_proc
WHERE pronamespace = {{ tbl }}.oid and proname = 'run_job' LIMIT 1))
{%- endmacro %}
{% macro LABELS(tbl, _) -%}
CASE {{ tbl }}.nspname
WHEN 'pg_catalog' THEN '{{ _( 'PostgreSQL Catalog' ) }} (pg_catalog)'
WHEN 'pgagent' THEN '{{ _( 'pgAgent Job Scheduler' ) }} (pgagent)'
WHEN 'information_schema' THEN '{{ _( 'ANSI' ) }} (information_schema)'
ELSE {{ tbl }}.nspname
END AS name
{%- endmacro %}
{% macro DB_SUPPORT(tbl) -%}
CASE
WHEN {{ tbl }}.nspname = ANY('{information_schema,sys,dbo}')
THEN false
ELSE true END
{%- endmacro %}

View File

@ -0,0 +1,234 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin',
'pgadmin.browser', 'backform', 'alertify',
'pgadmin.browser.collection',
'pgadmin.browser.server.privilege'],
function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
// Extend the browser's collection class for SecurityLabel control
var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
defaults: {
provider: null,
security_label: null
},
schema: [{
id: 'provider', label: '{{ _('Provider') }}',
type: 'text', disabled: false
},{
id: 'security_label', label: '{{ _('Security Label') }}',
type: 'text', disabled: false
}],
validate: function() {
var err = {},
errmsg = null;
if (_.isUndefined(this.get('security_label')) ||
_.isNull(this.get('security_label')) ||
String(this.get('security_label')).replace(/^\s+|\s+$/g, '') == '') {
errmsg = '{{ _('Please specify the value for all the security providers.')}}';
this.errorModel.set('security_label', errmsg);
return errmsg;
} else {
this.errorModel.unset('security_label');
}
return null;
}
});
// Extend the browser's collection class for schema collection
if (!pgBrowser.Nodes['coll-schema']) {
var databases = pgAdmin.Browser.Nodes['coll-schema'] =
pgAdmin.Browser.Collection.extend({
node: 'schema',
label: '{{ _('Schemas') }}',
type: 'coll-schema',
columns: ['name', 'oid', 'description']
});
};
// Extend the browser's node class for schema node
if (!pgBrowser.Nodes['schema']) {
pgAdmin.Browser.Nodes['schema'] = pgAdmin.Browser.Node.extend({
parent_type: 'database',
type: 'schema',
label: '{{ _('Schema') }}',
hasSQL: true,
canDrop: true,
canDropCascade: true,
hasDepends: true,
Init: function() {
/* Avoid mulitple registration of menus */
if (this.initialized)
return;
this.initialized = true;
pgBrowser.add_menus([{
name: 'create_schema_on_coll', node: 'coll-schema', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Schema...') }}',
icon: 'wcTabIcon icon-schema', data: {action: 'create'}
},{
name: 'create_schema', node: 'schema', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Schema...') }}',
icon: 'wcTabIcon icon-schema', data: {action: 'create'}
},{
name: 'create_schema', node: 'database', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Schema...') }}',
icon: 'wcTabIcon icon-schema', data: {action: 'create'}
}
]);
},
model: pgAdmin.Browser.Node.Model.extend({
defaults: {
name: undefined,
namespaceowner: undefined,
description: undefined,
is_system_obj: undefined,
},
initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0);
if (isNew) {
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
this.set({'namespaceowner': userInfo.name}, {silent: true});
}
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
},
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
type: 'text'
},{
id: 'oid', label:'{{ _('Oid') }}', cell: 'string',
type: 'text', disabled: true, mode: ['edit', 'properties']
},{
id: 'namespaceowner', label:'{{ _('Owner') }}', cell: 'string',
type: 'text', control: 'node-list-by-name', node: 'role',
select2: { allowClear: false }
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline'
},{
id: 'is_sys_object', label:'{{ _('System schema?') }}',
cell: 'switch', type: 'switch', mode: ['properties'], disabled: true,
options: {
'onText': 'Yes', 'offText': 'No',
'onColor': 'success', 'offColor': 'primary',
'size': 'small'
}
},{
id: 'acl', label: '{{ _('Privileges') }}', type: 'text',
mode: ['properties'], disabled: true
},{
id: 'tblacl', label: '{{ _('Default TABLE Privileges') }}', type: 'text',
mode: ['properties'], disabled: true
},{
id: 'seqacl', label: '{{ _('Default SEQUENCE Privileges') }}', type: 'text',
mode: ['properties'], disabled: true
},{
id: 'funcacl', label: '{{ _('Default FUNCTION Privileges') }}',
type: 'text', mode: ['properties'], disabled: true
},{
id: 'typeacl', label: '{{ _('Default TYPE Privileges') }}', type: 'text',
mode: ['properties'], disabled: true, min_version: 90200,
visible: function() {
return this.version_compatible;
}
},{
id: 'nspacl', label: '{{ _('Privileges') }}',
model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['C', 'U']}), uniqueCol : ['grantee', 'grantor'],
editable: false, type: 'collection', group: '{{ _('Security') }}',
mode: ['edit', 'create'],
canAdd: true, canDelete: true, control: 'unique-col-collection',
},{
id: 'seclabels', label: '{{ _('Security Labels') }}',
model: SecurityModel, editable: false, type: 'collection',
group: '{{ _('Security') }}', mode: ['edit', 'create'],
min_version: 90200, canAdd: true,
canEdit: false, canDelete: true, control: 'unique-col-collection'
},{
type: 'nested', control: 'tab', group: '{{ _('Default Privileges') }}',
mode: ['edit'],
schema:[{
id: 'deftblacl', model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}),
label: '{{ _('Default Privileges: Tables') }}',
editable: false, type: 'collection', group: '{{ _('Tables') }}',
mode: ['edit', 'create'], control: 'unique-col-collection',
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor']
},{
id: 'defseqacl', model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['r', 'w', 'U']}),
label: '{{ _('Default Privileges: Sequences') }}',
editable: false, type: 'collection', group: '{{ _('Sequences') }}',
mode: ['edit', 'create'], control: 'unique-col-collection',
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor']
},{
id: 'deffuncacl', model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['X']}),
label: '{{ _('Default Privileges: Functions') }}',
editable: false, type: 'collection', group: '{{ _('Functions') }}',
mode: ['edit', 'create'], control: 'unique-col-collection',
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor']
},{
id: 'deftypeacl', model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['U']}),
label: '{{ _('Default Privileges: Types') }}',
editable: false, type: 'collection', group: '{{ _('Types') }}',
mode: ['edit', 'create'], control: 'unique-col-collection',
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
min_version: 90200
}]
}
],
validate: function() {
var err = {},
errmsg = null;
// Validation of mandatory fields
this.errorModel.clear();
if (_.isUndefined(this.get('name')) ||
_.isNull(this.get('name')) ||
String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
errmsg = '{{ _('Name can not be empty.')}}';
this.errorModel.set('name', errmsg);
return errmsg;
} else if (_.isUndefined(this.get('namespaceowner')) ||
_.isNull(this.get('namespaceowner')) ||
String(this.get('namespaceowner')).replace(/^\s+|\s+$/g, '') == '') {
errmsg = '{{ _('Owner can not be empty.')}}';
this.errorModel.set('namespaceowner', errmsg);
return errmsg;
}
return null;
}
}),
// This function will checks whether we can allow user to
// drop object or not based on location within schema & catalog
canChildDrop: function(itemData, item) {
var t = pgBrowser.tree, i = item, d = itemData;
// To iterate over tree to check parent node
while (i) {
// If it is schema then allow user to create collation
if (_.indexOf(['schema'], d._type) > -1)
return true;
//Check if we are not child of catalog
prev_i = t.hasParent(i) ? t.parent(i) : null;
prev_d = prev_i ? t.itemData(prev_i) : null;
if( prev_d._type == 'catalog') {
return false;
}
i = t.hasParent(i) ? t.parent(i) : null;
d = i ? t.itemData(i) : null;
}
// by default we do not want to allow create menu
return true;
}
});
}
return pgBrowser.Nodes['schema'];
});

View File

@ -0,0 +1,26 @@
{# List of allowed privileges for PostgreSQL 9.1 #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "SCHEMA",
"acl": ["C", "U"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1,35 @@
{% import 'macros/security.macros' as SECLABLE %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{# Alter the comment/description #}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ACL for the schema #}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{# Default privileges on tables #}
{% for defacl, type in [
('deftblacl', 'TABLES'), ('defseqacl', 'SEQUENCES'),
('deffuncacl', 'FUNCTIONS')]
%}
{% if data[defacl] %}{% set acl = data[defacl] %}
{% for priv in data.deftblacl %}
{{ DEFAULT_PRIVILEGE.SET(
conn, 'SCHEMA', data.name, type, priv.grantee,
priv.without_grant, priv.with_grant
) }}{% endfor %}
{% endif %}
{% endfor %}
{# Security Labels on schema #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% for r in data.seclabels %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,7 @@
{% if data.name %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }}{% endif %};
{% else %}
{{ -- _('Incomplete definition') }}
{% endif %}

View File

@ -0,0 +1,39 @@
SELECT
CASE (a.deftype)
WHEN 'r' THEN 'deftblacl'
WHEN 'S' THEN 'defseqacl'
WHEN 'f' THEN 'deffuncacl'
ELSE 'UNKNOWN - ' || a.deftype
END AS deftype,
COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(a.privilege_type) as privileges, array_agg(a.is_grantable) as grantable
FROM
(SELECT
(acl).grantee as grantee, (acl).grantor AS grantor, (acl).is_grantable AS is_grantable,
CASE (acl).privilege_type
WHEN 'CONNECT' THEN 'c'
WHEN 'CREATE' THEN 'C'
WHEN 'DELETE' THEN 'd'
WHEN 'EXECUTE' THEN 'X'
WHEN 'INSERT' THEN 'a'
WHEN 'REFERENCES' THEN 'x'
WHEN 'SELECT' THEN 'r'
WHEN 'TEMPORARY' THEN 'T'
WHEN 'TRIGGER' THEN 't'
WHEN 'TRUNCATE' THEN 'D'
WHEN 'UPDATE' THEN 'w'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN'
END AS privilege_type,
defaclobjtype as deftype
FROM
(SELECT defaclobjtype, aclexplode(defaclacl) as acl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_catalog.pg_default_acl dacl ON (dacl.defaclnamespace = nsp.oid)
WHERE
nsp.oid={{scid}}::int
) d) a
LEFT JOIN pg_catalog.pg_roles g ON (a.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (a.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname, a.deftype
ORDER BY a.deftype;

View File

@ -0,0 +1 @@
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,21 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
nsp.nspname as name,
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1 @@
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};

View File

@ -0,0 +1,35 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
CASE
WHEN (nspname LIKE E'pg\\_temp\\_%') THEN 1
WHEN (nspname LIKE E'pg\\_%') THEN 0
ELSE 3 END AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,83 @@
{% import 'macros/security.macros' as SECLABEL %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{# Rename the schema #}
{% if data.name and data.name != o_data.name %}
ALTER SCHEMA {{ conn|qtIdent(o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{# Change the owner #}
{% if data.namespaceowner and data.namespaceowner != o_data.namespaceowner %}
ALTER SCHEMA {{ conn|qtIdent(data.name) }}
OWNER TO {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{# Update the comments/description #}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# Change the privileges #}
{% if data.nspacl %}
{% if 'deleted' in data.nspacl %}
{% for priv in data.nspacl.deleted %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.nspacl %}
{% for priv in data.nspacl.changed %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.nspacl %}
{% for priv in data.nspacl.added %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{# Change the default privileges #}
{% for defacl, type in [
('deftblacl', 'TABLES'), ('defseqacl', 'SEQUENCES'),
('deffuncacl', 'FUNCTIONS')]
%}
{% if data[defacl] %}{% set acl = data[defacl] %}
{% if 'deleted' in acl %}
{% for priv in acl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, type, priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in acl %}
{% for priv in acl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, type, priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, type, priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in acl %}
{% for priv in acl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, type, priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{# Change the security labels #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.DROP(conn, 'SCHEMA', data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,30 @@
{# List of allowed privileges for PostgreSQL 9.2 or later #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "SCHEMA",
"acl": ["C", "U"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
},
"deftypeacl": {
"type": "TYPE",
"acl": ["U"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1,35 @@
{% import 'macros/security.macros' as SECLABEL %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{# Alter the comment/description #}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ACL for the schema #}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{# Default privileges on tables #}
{% for defacl, type in [
('deftblacl', 'TABLES'), ('defseqacl', 'SEQUENCES'),
('deffuncacl', 'FUNCTIONS'), ('deftypeacl', 'TYPES')]
%}
{% if data[defacl] %}{% set acl = data[defacl] %}
{% for priv in data.deftblacl %}
{{ DEFAULT_PRIVILEGE.SET(
conn, 'SCHEMA', data.name, type, priv.grantee,
priv.without_grant, priv.with_grant
) }}{% endfor %}
{% endif %}
{% endfor %}
{# Security Labels on schema #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% for r in data.seclabels %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,7 @@
{% if data.name %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }}{% endif %};
{% else %}
{{ -- _('Incomplete definition') }}
{% endif %}

View File

@ -0,0 +1,40 @@
SELECT
CASE (a.deftype)
WHEN 'r' THEN 'deftblacl'
WHEN 'S' THEN 'defseqacl'
WHEN 'f' THEN 'deffuncacl'
WHEN 'T' THEN 'deftypeacl'
ELSE 'UNKNOWN - ' || a.deftype
END AS deftype,
COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(a.privilege_type) as privileges, array_agg(a.is_grantable) as grantable
FROM
(SELECT
(acl).grantee as grantee, (acl).grantor AS grantor, (acl).is_grantable AS is_grantable,
CASE (acl).privilege_type
WHEN 'CONNECT' THEN 'c'
WHEN 'CREATE' THEN 'C'
WHEN 'DELETE' THEN 'd'
WHEN 'EXECUTE' THEN 'X'
WHEN 'INSERT' THEN 'a'
WHEN 'REFERENCES' THEN 'x'
WHEN 'SELECT' THEN 'r'
WHEN 'TEMPORARY' THEN 'T'
WHEN 'TRIGGER' THEN 't'
WHEN 'TRUNCATE' THEN 'D'
WHEN 'UPDATE' THEN 'w'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (acl).privilege_type
END AS privilege_type,
defaclobjtype as deftype
FROM
(SELECT defaclobjtype, aclexplode(defaclacl) as acl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_catalog.pg_default_acl dacl ON (dacl.defaclnamespace = nsp.oid)
WHERE
nsp.oid={{scid}}::int
) d) a
LEFT JOIN pg_catalog.pg_roles g ON (a.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (a.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname, a.deftype
ORDER BY a.deftype;

View File

@ -0,0 +1 @@
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,21 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
nsp.nspname as name,
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1 @@
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};

View File

@ -0,0 +1,36 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
SELECT
CASE
WHEN (nspname LIKE E'pg\\_temp\\_%') THEN 1
WHEN (nspname LIKE E'pg\\_%') THEN 0
ELSE 3 END AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftypeacl' AND defaclnamespace = nsp.oid) AS typeacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,83 @@
{% import 'macros/security.macros' as SECLABEL %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{# Rename the schema #}
{% if data.name and data.name != o_data.name %}
ALTER SCHEMA {{ conn|qtIdent(o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{# Change the owner #}
{% if data.namespaceowner and data.namespaceowner != o_data.namespaceowner %}
ALTER SCHEMA {{ conn|qtIdent(data.name) }}
OWNER TO {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{# Update the comments/description #}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# Change the privileges #}
{% if data.nspacl %}
{% if 'deleted' in data.nspacl %}
{% for priv in data.nspacl.deleted %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.nspacl %}
{% for priv in data.nspacl.changed %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.nspacl %}
{% for priv in data.nspacl.added %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{# Change the default privileges #}
{% for defacl, type in [
('deftblacl', 'TABLES'), ('defseqacl', 'SEQUENCES'),
('deffuncacl', 'FUNCTIONS'), ('deftypeacl', 'TYPES')]
%}
{% if data[defacl] %}{% set acl = data[defacl] %}
{% if 'deleted' in acl %}
{% for priv in acl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, type, priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in acl %}
{% for priv in acl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, type, priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, type, priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in acl %}
{% for priv in acl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, type, priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{# Change the security labels #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABEL.DROP(conn, 'SCHEMA', data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,26 @@
{# List of allowed privileges for PPAS 9.1 #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "SCHEMA",
"acl": ["C", "U"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1,35 @@
{% import 'macros/security.macros' as SECLABEL %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{# Alter the comment/description #}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ACL for the schema #}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{# Default privileges on tables #}
{% for defacl, type in [
('deftblacl', 'TABLES'), ('defseqacl', 'SEQUENCES'),
('deffuncacl', 'FUNCTIONS')]
%}
{% if data[defacl] %}{% set acl = data[defacl] %}
{% for priv in data.deftblacl %}
{{ DEFAULT_PRIVILEGE.SET(
conn, 'SCHEMA', data.name, type, priv.grantee,
priv.without_grant, priv.with_grant
) }}{% endfor %}
{% endif %}
{% endfor %}
{# Security Labels on schema #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% for r in data.seclabels %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,7 @@
{% if data.name %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }}{% endif %};
{% else %}
{{ -- _('Incomplete definition') }}
{% endif %}

View File

@ -0,0 +1,39 @@
SELECT
CASE (a.deftype)
WHEN 'r' THEN 'deftblacl'
WHEN 'S' THEN 'defseqacl'
WHEN 'f' THEN 'deffuncacl'
ELSE 'UNKNOWN - ' || a.deftype
END AS deftype,
COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(a.privilege_type) as privileges, array_agg(a.is_grantable) as grantable
FROM
(SELECT
(acl).grantee as grantee, (acl).grantor AS grantor, (acl).is_grantable AS is_grantable,
CASE (acl).privilege_type
WHEN 'CONNECT' THEN 'c'
WHEN 'CREATE' THEN 'C'
WHEN 'DELETE' THEN 'd'
WHEN 'EXECUTE' THEN 'X'
WHEN 'INSERT' THEN 'a'
WHEN 'REFERENCES' THEN 'x'
WHEN 'SELECT' THEN 'r'
WHEN 'TEMPORARY' THEN 'T'
WHEN 'TRIGGER' THEN 't'
WHEN 'TRUNCATE' THEN 'D'
WHEN 'UPDATE' THEN 'w'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (acl).privilege_type
END AS privilege_type,
defaclobjtype as deftype
FROM
(SELECT defaclobjtype, aclexplode(defaclacl) as acl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_catalog.pg_default_acl dacl ON (dacl.defaclnamespace = nsp.oid)
WHERE
nsp.oid={{scid}}::int
) d) a
LEFT JOIN pg_catalog.pg_roles g ON (a.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (a.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname, a.deftype
ORDER BY a.deftype;

View File

@ -0,0 +1 @@
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,21 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
nsp.nspname as name,
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1 @@
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};

View File

@ -0,0 +1,36 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
CASE
WHEN (nspname LIKE E'pg\\_temp\\_%') THEN 1
WHEN (nspname LIKE E'pg\\_%') THEN 0
ELSE 3 END AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
nsp.nspparent = 0 AND
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,125 @@
{% import 'macros/security.macros' as SECLABLE %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{% if data %}
{### To update SCHEMA name ###}
{% if data.name and data.name != o_data.name %}
ALTER SCHEMA {{ conn|qtIdent(o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{### To update SCHEMA owner ###}
{% if data.namespaceowner and data.namespaceowner != o_data.namespaceowner %}
ALTER SCHEMA {{ conn|qtIdent(data.name) }}
OWNER TO {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{### To update SCHEMA comments ###}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{### Change the security labels ###}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'SCHEMA', data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}
{### Change the privileges ###}
{% if data.nspacl %}
{% if 'deleted' in data.nspacl %}
{% for priv in data.nspacl.deleted %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.nspacl %}
{% for priv in data.nspacl.changed %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.nspacl %}
{% for priv in data.nspacl.added %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for tables ###}
{% if data.deftblacl %}
{% if 'deleted' in data.deftblacl %}
{% for priv in data.deftblacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, 'TABLES', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.deftblacl %}
{% for priv in data.deftblacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, 'TABLES', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'TABLES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.deftblacl %}
{% for priv in data.deftblacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'TABLES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for sequences ###}
{% if data.defseqacl %}
{% if 'deleted' in data.defseqacl %}
{% for priv in data.defseqacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.defseqacl %}
{% for priv in data.defseqacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.defseqacl %}
{% for priv in data.defseqacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for functions ###}
{% if data.deffuncacl %}
{% if 'deleted' in data.deffuncacl %}
{% for priv in data.deffuncacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.deffuncacl %}
{% for priv in data.deffuncacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.deffuncacl %}
{% for priv in data.deffuncacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### End main if data ###}
{% endif %}

View File

@ -0,0 +1,30 @@
{# List of allowed privileges for PPAS 9.2 or later #}
{#
Format for allowed privileges is:
"acl_col": {
"type": "name",
"acl": [...]
}
#}
{
"nspacl": {
"type": "SCHEMA",
"acl": ["C", "U"]
},
"deftblacl": {
"type": "TABLE",
"acl": ["r", "a", "w", "d", "D", "x", "t"]
},
"defseqacl": {
"type": "SEQUENCE",
"acl": ["U", "r", "a"]
},
"deffuncacl": {
"type": "FUNCTION",
"acl": ["X"]
},
"deftypeacl": {
"type": "TYPE",
"acl": ["U"]
}
}

View File

@ -0,0 +1,23 @@
{# Fetch privileges for schema #}
SELECT
'nspacl' as deftype, COALESCE(gt.rolname, 'public') AS grantee,
g.rolname AS grantor, array_agg(b.privilege_type) AS privileges,
array_agg(b.is_grantable) AS grantable
FROM
(SELECT
(d).grantee AS grantee, (d).grantor AS grantor,
(d).is_grantable AS is_grantable,
CASE (d).privilege_type
WHEN 'CREATE' THEN 'C'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (d).privilege_type
END AS privilege_type
FROM
(SELECT aclexplode(nsp.nspacl) as d
FROM pg_namespace nsp
WHERE nsp.oid = {{ scid|qtLiteral }}::OID
) a
) b
LEFT JOIN pg_catalog.pg_roles g ON (b.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (b.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname;

View File

@ -0,0 +1,35 @@
{% import 'macros/security.macros' as SECLABEL %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{# Alter the comment/description #}
{% if data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# ACL for the schema #}
{% if data.nspacl %}
{% for priv in data.nspacl %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
{% endif %}
{# Default privileges on tables #}
{% for defacl, type in [
('deftblacl', 'TABLES'), ('defseqacl', 'SEQUENCES'),
('deffuncacl', 'FUNCTIONS'), ('deftypeacl', 'TYPES')]
%}
{% if data[defacl] %}{% set acl = data[defacl] %}
{% for priv in data.deftblacl %}
{{ DEFAULT_PRIVILEGE.SET(
conn, 'SCHEMA', data.name, type, priv.grantee,
priv.without_grant, priv.with_grant
) }}{% endfor %}
{% endif %}
{% endfor %}
{# Security Labels on schema #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% for r in data.seclabels %}
{{ SECLABEL.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,7 @@
{% if data.name %}
CREATE SCHEMA {{ conn|qtIdent(data.name) }}{% if data.namespaceowner %}
AUTHORIZATION {{ conn|qtIdent(data.namespaceowner) }}{% endif %};
{% else %}
{{ -- _('Incomplete definition') }}
{% endif %}

View File

@ -0,0 +1,40 @@
SELECT
CASE (a.deftype)
WHEN 'r' THEN 'deftblacl'
WHEN 'S' THEN 'defseqacl'
WHEN 'f' THEN 'deffuncacl'
WHEN 'T' THEN 'deftypeacl'
ELSE 'UNKNOWN - ' || a.deftype
END AS deftype,
COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(a.privilege_type) as privileges, array_agg(a.is_grantable) as grantable
FROM
(SELECT
(acl).grantee as grantee, (acl).grantor AS grantor, (acl).is_grantable AS is_grantable,
CASE (acl).privilege_type
WHEN 'CONNECT' THEN 'c'
WHEN 'CREATE' THEN 'C'
WHEN 'DELETE' THEN 'd'
WHEN 'EXECUTE' THEN 'X'
WHEN 'INSERT' THEN 'a'
WHEN 'REFERENCES' THEN 'x'
WHEN 'SELECT' THEN 'r'
WHEN 'TEMPORARY' THEN 'T'
WHEN 'TRIGGER' THEN 't'
WHEN 'TRUNCATE' THEN 'D'
WHEN 'UPDATE' THEN 'w'
WHEN 'USAGE' THEN 'U'
ELSE 'UNKNOWN - ' || (acl).privilege_type
END AS privilege_type,
defaclobjtype as deftype
FROM
(SELECT defaclobjtype, aclexplode(defaclacl) as acl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_catalog.pg_default_acl dacl ON (dacl.defaclnamespace = nsp.oid)
WHERE
nsp.oid={{scid}}::int
) d) a
LEFT JOIN pg_catalog.pg_roles g ON (a.grantor = g.oid)
LEFT JOIN pg_catalog.pg_roles gt ON (a.grantee = gt.oid)
GROUP BY g.rolname, gt.rolname, a.deftype
ORDER BY a.deftype;

View File

@ -0,0 +1 @@
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};

View File

@ -0,0 +1 @@
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};

View File

@ -0,0 +1,9 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.nspname as schema_name,
{{ CATALOGS.LIST('nsp') }} AS is_catalog,
{{ CATALOGS.DB_SUPPORT('nsp') }} AS db_support
FROM
pg_catalog.pg_namespace nsp
WHERE
nsp.oid = {{ scid|qtLiteral }}::OID;

View File

@ -0,0 +1,21 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
nsp.oid,
nsp.nspname as name,
has_schema_privilege(nsp.oid, 'CREATE') as can_create,
has_schema_privilege(nsp.oid, 'USAGE') as has_usage
FROM
pg_namespace nsp
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1 @@
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};

View File

@ -0,0 +1,37 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
SELECT
CASE
WHEN (nspname LIKE E'pg\\_temp\\_%') THEN 1
WHEN (nspname LIKE E'pg\\_%') THEN 0
ELSE 3 END AS nsptyp,
nsp.nspname AS name,
nsp.oid,
array_to_string(nsp.nspacl::text[], ', ') as acl,
r.rolname AS namespaceowner, description,
has_schema_privilege(nsp.oid, 'CREATE') AS can_create,
CASE
WHEN nspname LIKE E'pg\\_%' THEN true
ELSE false END AS is_sys_object,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftblacl' AND defaclnamespace = nsp.oid) AS tblacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'defseqacl' AND defaclnamespace = nsp.oid) AS seqacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deffuncacl' AND defaclnamespace = nsp.oid) AS funcacl,
(SELECT array_to_string(defaclacl::text[], ', ') FROM pg_default_acl WHERE defaclobjtype = 'deftypeacl' AND defaclnamespace = nsp.oid) AS typeacl
FROM
pg_namespace nsp
LEFT OUTER JOIN pg_description des ON
(des.objoid=nsp.oid AND des.classoid='pg_namespace'::regclass)
LEFT JOIN pg_roles r ON (r.oid = nsp.nspowner)
WHERE
{% if scid %}
nsp.oid={{scid}}::int AND
{% else %}
{% if show_sysobj %}
nspname NOT LIKE E'pg\\_temp\\_%' AND
nspname NOT LIKE E'pg\\_toast\\_temp\\_%' AND
{% endif %}
{% endif %}
nsp.nspparent = 0 AND
NOT (
{{ CATALOGS.LIST('nsp') }}
)
ORDER BY 1, nspname;

View File

@ -0,0 +1,145 @@
{% import 'macros/security.macros' as SECLABLE %}
{% import 'macros/privilege.macros' as PRIVILEGE %}
{% import 'macros/default_privilege.macros' as DEFAULT_PRIVILEGE %}
{% if data %}
{### To update SCHEMA name ###}
{% if data.name and data.name != o_data.name %}
ALTER SCHEMA {{ conn|qtIdent(o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{### To update SCHEMA owner ###}
{% if data.namespaceowner and data.namespaceowner != o_data.namespaceowner %}
ALTER SCHEMA {{ conn|qtIdent(data.name) }}
OWNER TO {{ conn|qtIdent(data.namespaceowner) }};
{% endif %}
{### To update SCHEMA comments ###}
{% if data.description and data.description != o_data.description %}
COMMENT ON SCHEMA {{ conn|qtIdent(data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{### Change the security labels ###}
{# The SQL generated below will change Security Label #}
{% if data.seclabels and data.seclabels|length > 0 %}
{% set seclabels = data.seclabels %}
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
{% for r in seclabels.deleted %}
{{ SECLABLE.DROP(conn, 'SCHEMA', data.name, r.provider) }}
{% endfor %}
{% endif %}
{% if 'added' in seclabels and seclabels.added|length > 0 %}
{% for r in seclabels.added %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
{% for r in seclabels.changed %}
{{ SECLABLE.APPLY(conn, 'SCHEMA', data.name, r.provider, r.security_label) }}
{% endfor %}
{% endif %}
{% endif %}
{### Change the privileges ###}
{% if data.nspacl %}
{% if 'deleted' in data.nspacl %}
{% for priv in data.nspacl.deleted %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.nspacl %}
{% for priv in data.nspacl.changed %}
{{ PRIVILEGE.RESETALL(conn, 'SCHEMA', priv.grantee, data.name) }}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.nspacl %}
{% for priv in data.nspacl.added %}
{{ PRIVILEGE.APPLY(conn, 'SCHEMA', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for tables ###}
{% if data.deftblacl %}
{% if 'deleted' in data.deftblacl %}
{% for priv in data.deftblacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, 'TABLES', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.deftblacl %}
{% for priv in data.deftblacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn, 'SCHEMA', data.name, 'TABLES', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'TABLES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.deftblacl %}
{% for priv in data.deftblacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'TABLES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for sequences ###}
{% if data.defseqacl %}
{% if 'deleted' in data.defseqacl %}
{% for priv in data.defseqacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.defseqacl %}
{% for priv in data.defseqacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.defseqacl %}
{% for priv in data.defseqacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'SEQUENCES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for functions ###}
{% if data.deffuncacl %}
{% if 'deleted' in data.deffuncacl %}
{% for priv in data.deffuncacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.deffuncacl %}
{% for priv in data.deffuncacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.deffuncacl %}
{% for priv in data.deffuncacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'FUNCTIONS', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### To change default privileges for types ###}
{% if data.deftypeacl %}
{% if 'deleted' in data.deftypeacl %}
{% for priv in data.deftypeacl.deleted %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'TYPES', priv.grantee) }}
{% endfor %}
{% endif %}
{% if 'changed' in data.deftypeacl %}
{% for priv in data.deftypeacl.changed %}
{{ DEFAULT_PRIVILEGE.UNSET(conn,'SCHEMA', data.name, 'TYPES', priv.grantee) }}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'TYPES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% if 'added' in data.deftypeacl %}
{% for priv in data.deftypeacl.added %}
{{ DEFAULT_PRIVILEGE.SET(conn,'SCHEMA', data.name, 'TYPES', priv.grantee, priv.without_grant, priv.with_grant) }}
{% endfor %}
{% endif %}
{% endif %}
{### End main if data ###}
{% endif %}

View File

@ -0,0 +1,59 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""Schema collection node helper class"""
from pgadmin.browser.collection import CollectionNodeModule
class SchemaChildModule(CollectionNodeModule):
"""
Base class for the schema child node.
Some of the node may be/may not be allowed in certain catalog nodes.
i.e.
Do not show the schema objects under pg_catalog, pgAgent, etc.
Looks at two parameters CATALOG_DB_SUPPORTED, SUPPORTED_SCHEMAS.
Schema child objects like catalog_objects are only supported for
'pg_catalog', and objects like 'jobs' & 'schedules' are only supported for
the 'pgagent' schema.
For catalog_objects, we should set:
CATALOG_DB_SUPPORTED = False
SUPPORTED_SCHEMAS = ['pg_catalog']
For jobs & schedules, we should set:
CATALOG_DB_SUPPORTED = False
SUPPORTED_SCHEMAS = ['pgagent']
"""
CATALOG_DB_SUPPORTED = True
SUPPORTED_SCHEMAS = None
def BackendSupported(self, manager, **kwargs):
return (
(
kwargs['is_catalog'] and ((
self.CATALOG_DB_SUPPORTED and kwargs['db_support']
) or (
not self.CATALOG_DB_SUPPORTED and
not kwargs['db_support'] and
(
self.SUPPORTED_SCHEMAS is None or (
kwargs['schema_name'] in self.SUPPORTED_SCHEMAS
)
)
))
) or (
not kwargs['is_catalog'] and self.CATALOG_DB_SUPPORTED
)
) and CollectionNodeModule.BackendSupported(
self, manager, **kwargs
)