mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add support for Schemas and Catalogs.
Initial patch by Murtuza Zabuawala with further hacking by Ashesh Vashi and I.
This commit is contained in:
parent
785d180451
commit
a92d4841d1
@ -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 |
@ -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'];
|
||||||
|
});
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
{# We have nothing to alter in the catalog #}
|
@ -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 %}
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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 %}
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
{# We have nothing to alter in the catalog #}
|
@ -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 %}
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
{# We have nothing to alter in the catalog #}
|
@ -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 %}
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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 %}
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
{# We have nothing to alter in the catalog #}
|
@ -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 %}
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
@ -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'];
|
||||||
|
});
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};
|
@ -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;
|
@ -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 %}
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};
|
@ -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;
|
@ -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 %}
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};
|
@ -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;
|
@ -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 %}
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -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 %}
|
@ -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 %}
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
DROP SCHEMA {{ conn|qtIdent(name) }} {% if cascade %}CASCADE{%endif%};
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.nspname FROM pg_namespace nsp WHERE nsp.oid = {{ scid|qtLiteral }};
|
@ -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;
|
@ -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;
|
@ -0,0 +1 @@
|
|||||||
|
SELECT nsp.oid FROM pg_namespace nsp WHERE nsp.nspname = {{ schema|qtLiteral }};
|
@ -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;
|
@ -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 %}
|
@ -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
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user