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