mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add support for domains.
This commit is contained in:
parent
d1eb3fd9d5
commit
2add0155a3
@ -0,0 +1,824 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Implements the Domain Node."""
|
||||
|
||||
import json
|
||||
from flask import render_template, make_response, request, jsonify
|
||||
from flask.ext.babel import gettext
|
||||
from pgadmin.utils.ajax import make_json_response, \
|
||||
make_response as ajax_response, internal_server_error, gone
|
||||
from pgadmin.browser.utils import PGChildNodeView
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
import pgadmin.browser.server_groups.servers.databases.schemas as schemas
|
||||
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.databases.schemas.utils import \
|
||||
SchemaChildModule, DataTypeReader
|
||||
from pgadmin.browser.server_groups.servers.databases.utils import \
|
||||
parse_sec_labels_from_db
|
||||
from functools import wraps
|
||||
|
||||
|
||||
class DomainModule(SchemaChildModule):
|
||||
"""
|
||||
class DomainModule(SchemaChildModule):
|
||||
|
||||
This class represents The Domain Module.
|
||||
|
||||
Methods:
|
||||
-------
|
||||
* __init__(*args, **kwargs)
|
||||
- Initialize the Domain Module.
|
||||
|
||||
* get_nodes(gid, sid, did, scid)
|
||||
- Generate the domain collection node.
|
||||
|
||||
* script_load()
|
||||
- Load the module script for domain, when schema node is
|
||||
initialized.
|
||||
"""
|
||||
|
||||
NODE_TYPE = 'domain'
|
||||
COLLECTION_LABEL = gettext("Domains")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DomainModule, self).__init__(*args, **kwargs)
|
||||
self.min_ver = None
|
||||
self.max_ver = None
|
||||
|
||||
def get_nodes(self, gid, sid, did, scid):
|
||||
"""
|
||||
Generate the domain collection node.
|
||||
"""
|
||||
yield self.generate_browser_collection_node(scid)
|
||||
|
||||
@property
|
||||
def script_load(self):
|
||||
"""
|
||||
Load the module script for domain, when schema node is
|
||||
initialized.
|
||||
"""
|
||||
return schemas.SchemaModule.NODE_TYPE
|
||||
|
||||
|
||||
blueprint = DomainModule(__name__)
|
||||
|
||||
|
||||
class DomainView(PGChildNodeView, DataTypeReader):
|
||||
"""
|
||||
class DomainView
|
||||
|
||||
This class inherits PGChildNodeView to get the different routes for
|
||||
the module. Also, inherits DataTypeReader to get data types.
|
||||
|
||||
The class is responsible to Create, Read, Update and Delete operations for
|
||||
the Domain.
|
||||
|
||||
Methods:
|
||||
-------
|
||||
* validate_request(f):
|
||||
- Works as a decorator.
|
||||
Validating request on the request of create, update and modified SQL.
|
||||
|
||||
* module_js():
|
||||
- Load JS file (domains.js) for this module.
|
||||
|
||||
* check_precondition(f):
|
||||
- Works as a decorator.
|
||||
- Checks database connection status.
|
||||
- Attach connection object and template path.
|
||||
|
||||
* list(gid, sid, did, scid, doid):
|
||||
- List the Domains.
|
||||
|
||||
* nodes(gid, sid, did, scid):
|
||||
- Returns all the Domains to generate Nodes in the browser.
|
||||
|
||||
* properties(gid, sid, did, scid, doid):
|
||||
- Returns the Domain properties.
|
||||
|
||||
* get_collations(gid, sid, did, scid, doid=None):
|
||||
- Returns Collations.
|
||||
|
||||
* create(gid, sid, did, scid):
|
||||
- Creates a new Domain object.
|
||||
|
||||
* update(gid, sid, did, scid, doid):
|
||||
- Updates the Domain object.
|
||||
|
||||
* delete(gid, sid, did, scid, doid):
|
||||
- Drops the Domain object.
|
||||
|
||||
* sql(gid, sid, did, scid, doid=None):
|
||||
- Returns the SQL for the Domain object.
|
||||
|
||||
* msql(gid, sid, did, scid, doid=None):
|
||||
- Returns the modified SQL.
|
||||
|
||||
* get_sql(gid, sid, data, scid, doid=None):
|
||||
- Generates the SQL statements to create/update the Domain object.
|
||||
|
||||
* dependents(gid, sid, did, scid, doid):
|
||||
- Returns the dependents for the Domain object.
|
||||
|
||||
* dependencies(gid, sid, did, scid, doid):
|
||||
- Returns the dependencies for the Domain object.
|
||||
|
||||
* types(gid, sid, did, scid, fnid=None):
|
||||
- Returns Data Types.
|
||||
"""
|
||||
|
||||
node_type = blueprint.node_type
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
{'type': 'int', 'id': 'sid'},
|
||||
{'type': 'int', 'id': 'did'},
|
||||
{'type': 'int', 'id': 'scid'}
|
||||
]
|
||||
ids = [
|
||||
{'type': 'int', 'id': 'doid'}
|
||||
]
|
||||
|
||||
operations = dict({
|
||||
'obj': [
|
||||
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
|
||||
{'get': 'list', 'post': 'create'}
|
||||
],
|
||||
'delete': [{'delete': 'delete'}],
|
||||
'children': [{'get': 'children'}],
|
||||
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
|
||||
'sql': [{'get': 'sql'}],
|
||||
'msql': [{'get': 'msql'}, {'get': 'msql'}],
|
||||
'stats': [{'get': 'statistics'}],
|
||||
'dependency': [{'get': 'dependencies'}],
|
||||
'dependent': [{'get': 'dependents'}],
|
||||
'module.js': [{}, {}, {'get': 'module_js'}],
|
||||
'get_types': [{'get': 'types'}, {'get': 'types'}],
|
||||
'get_collations': [
|
||||
{'get': 'get_collations'},
|
||||
{'get': 'get_collations'}
|
||||
]
|
||||
})
|
||||
|
||||
def validate_request(f):
|
||||
"""
|
||||
Works as a decorator.
|
||||
Validating request on the request of create, update and modified SQL.
|
||||
|
||||
Required Args:
|
||||
name: Name of the Domain
|
||||
owner: Domain Owner
|
||||
basensp: Schema Name
|
||||
basetype: Data Type of the Domain
|
||||
|
||||
Above both the arguments will not be validated in the update action.
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def wrap(self, **kwargs):
|
||||
|
||||
data = {}
|
||||
if request.data:
|
||||
req = json.loads(request.data.decode())
|
||||
else:
|
||||
req = request.args or request.form
|
||||
|
||||
if 'doid' not in kwargs:
|
||||
required_args = [
|
||||
'name',
|
||||
'basetype'
|
||||
]
|
||||
|
||||
for arg in required_args:
|
||||
if arg not in req or req[arg] == '':
|
||||
return make_json_response(
|
||||
status=410,
|
||||
success=0,
|
||||
errormsg=gettext(
|
||||
"Couldn't find the required parameter \
|
||||
(%s)." % arg
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
list_params = []
|
||||
if request.method == 'GET':
|
||||
list_params = ['constraints', 'seclabels']
|
||||
|
||||
for key in req:
|
||||
if key in list_params and req[key] != '' \
|
||||
and req[key] is not None:
|
||||
# Coverts string into python list as expected.
|
||||
data[key] = json.loads(req[key])
|
||||
elif key == 'typnotnull':
|
||||
data[key] = True if req[key] == 'true' or req[key] is\
|
||||
True else\
|
||||
(False if req[key] == 'false' or req[key] is
|
||||
False else '')
|
||||
else:
|
||||
data[key] = req[key]
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
self.request = data
|
||||
return f(self, **kwargs)
|
||||
|
||||
return wrap
|
||||
|
||||
def module_js(self):
|
||||
"""
|
||||
Load JS file (domains.js) for this module.
|
||||
"""
|
||||
return make_response(
|
||||
render_template(
|
||||
"domains/js/domains.js",
|
||||
_=gettext
|
||||
),
|
||||
200, {'Content-Type': 'application/x-javascript'}
|
||||
)
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
Works as a decorator.
|
||||
Checks database connection status.
|
||||
Attach connection object and template path.
|
||||
"""
|
||||
@wraps(f)
|
||||
def wrap(*args, **kwargs):
|
||||
self = args[0]
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
self.manager = driver.connection_manager(kwargs['sid'])
|
||||
# Get database connection
|
||||
self.conn = self.manager.connection(did=kwargs['did'])
|
||||
self.qtIdent = driver.qtIdent
|
||||
|
||||
if not self.conn.connected():
|
||||
return precondition_required(
|
||||
gettext("Connection to the server has been lost!")
|
||||
)
|
||||
|
||||
ver = self.manager.version
|
||||
server_type = self.manager.server_type
|
||||
|
||||
# we will set template path for sql scripts
|
||||
if ver >= 90200:
|
||||
self.template_path = 'domains/sql/9.2_plus'
|
||||
elif ver >= 90100:
|
||||
self.template_path = 'domains/sql/9.1_plus'
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return wrap
|
||||
|
||||
@check_precondition
|
||||
def list(self, gid, sid, did, scid):
|
||||
"""
|
||||
List the Domains.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
"""
|
||||
|
||||
SQL = render_template("/".join([self.template_path, 'node.sql']),
|
||||
scid=scid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
return ajax_response(
|
||||
response=res['rows'],
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def nodes(self, gid, sid, did, scid):
|
||||
"""
|
||||
Returns all the Domains to generate Nodes in the browser.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
"""
|
||||
|
||||
res = []
|
||||
SQL = render_template("/".join([self.template_path, 'node.sql']),
|
||||
scid=scid)
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
res.append(
|
||||
self.blueprint.generate_browser_node(
|
||||
row['oid'],
|
||||
scid,
|
||||
row['name'],
|
||||
icon="icon-domain"
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
data=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def properties(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
Returns the Domain properties.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
|
||||
SQL = render_template("/".join([self.template_path, 'properties.sql']),
|
||||
scid=scid, doid=doid)
|
||||
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 domain in the database.
|
||||
It may have been removed by another user or
|
||||
shifted to the another schema.
|
||||
"""))
|
||||
|
||||
data = res['rows'][0]
|
||||
|
||||
# Get Type Length and Precision
|
||||
data.update(self._parse_type(data['fulltype']))
|
||||
|
||||
# Get Domain Constraints
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_constraints.sql']),
|
||||
doid=doid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
data['constraints'] = res['rows']
|
||||
|
||||
# Get formatted Security Labels
|
||||
if 'seclabels' in data:
|
||||
data.update(parse_sec_labels_from_db(data['seclabels']))
|
||||
|
||||
# Set System Domain Status
|
||||
data['sysdomain'] = False
|
||||
if doid <= self.manager.db_info[did]['datlastsysoid']:
|
||||
data['sysdomain'] = True
|
||||
|
||||
return ajax_response(
|
||||
response=data,
|
||||
status=200
|
||||
)
|
||||
|
||||
def _parse_type(self, basetype):
|
||||
"""
|
||||
Returns Type and Data Type from the basetype.
|
||||
"""
|
||||
typ_len = ''
|
||||
typ_precision = ''
|
||||
|
||||
# The Length and the precision of the Datatype should be separate.
|
||||
# The Format we getting from database is: numeric(1,1)
|
||||
# So, we need to separate Length: 1, Precision: 1
|
||||
|
||||
if basetype != '' and basetype.find("(") > 0:
|
||||
substr = basetype[basetype.find("(") + 1:len(
|
||||
basetype) - 1]
|
||||
typlen = substr.split(",")
|
||||
if len(typlen) > 1:
|
||||
typ_len = typlen[0]
|
||||
typ_precision = typlen[1]
|
||||
else:
|
||||
typ_len = typlen
|
||||
typ_precision = ''
|
||||
|
||||
return {'typlen': typ_len, 'precision': typ_precision}
|
||||
|
||||
@check_precondition
|
||||
def get_collations(self, gid, sid, did, scid, doid=None):
|
||||
"""
|
||||
Returns Collations.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
|
||||
res = [{'label': '', 'value': ''}]
|
||||
try:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_collations.sql']))
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
for row in rset['rows']:
|
||||
res.append({'label': row['copy_collation'],
|
||||
'value': row['copy_collation']}
|
||||
)
|
||||
|
||||
return make_json_response(
|
||||
data=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
def types(self, gid, sid, did, scid, doid=None):
|
||||
"""
|
||||
Returns the Data Types.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
fnid: Function Id
|
||||
"""
|
||||
|
||||
condition = """typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r')
|
||||
AND NOT EXISTS (SELECT 1 FROM pg_class WHERE relnamespace=typnamespace
|
||||
AND relname = typname AND relkind != 'c') AND
|
||||
(typname NOT LIKE '_%' OR NOT EXISTS (SELECT 1 FROM pg_class WHERE
|
||||
relnamespace=typnamespace AND relname = substring(typname FROM 2)::name
|
||||
AND relkind != 'c'))"""
|
||||
|
||||
if self.blueprint.show_system_objects:
|
||||
condition += " AND nsp.nspname != 'information_schema'"
|
||||
|
||||
# Get Types
|
||||
status, types = self.get_types(self.conn, condition)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=types)
|
||||
|
||||
return make_json_response(
|
||||
data=types,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
@validate_request
|
||||
def create(self, gid, sid, did, scid):
|
||||
"""
|
||||
Creates a new Domain object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
|
||||
Required Args:
|
||||
name: Domain Name
|
||||
owner: Owner Name
|
||||
basensp: Schema Name
|
||||
basetype: Domain Base Type
|
||||
|
||||
Returns:
|
||||
Domain object in json format.
|
||||
"""
|
||||
|
||||
data = self.request
|
||||
try:
|
||||
status, SQL = self.get_sql(gid, sid, data, scid)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=SQL)
|
||||
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
# We need oid to to add object in tree at browser, below sql will
|
||||
# gives the same
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_oid.sql']),
|
||||
basensp=data['basensp'],
|
||||
name=data['name'])
|
||||
status, res = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
doid, scid = res['rows'][0]
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
doid,
|
||||
scid,
|
||||
data['name'],
|
||||
icon="icon-domain"
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
Drops the Domain object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
|
||||
if self.cmd == 'delete':
|
||||
# This is a cascade operation
|
||||
cascade = True
|
||||
else:
|
||||
cascade = False
|
||||
|
||||
try:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'delete.sql']),
|
||||
scid=scid, doid=doid)
|
||||
status, res = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
name, basensp = res['rows'][0]
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'delete.sql']),
|
||||
name=name, basensp=basensp, cascade=cascade)
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext("Domain dropped"),
|
||||
data={
|
||||
'id': doid,
|
||||
'scid': scid,
|
||||
'sid': sid,
|
||||
'gid': gid,
|
||||
'did': did
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
@validate_request
|
||||
def update(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
Updates the Domain object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
|
||||
status, SQL = self.get_sql(gid, sid, self.request, scid, doid)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=SQL)
|
||||
|
||||
try:
|
||||
if SQL:
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
# Get Schema Id
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_oid.sql']),
|
||||
doid=doid)
|
||||
status, res = self.conn.execute_2darray(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
scid = res['rows'][0]['scid']
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info="Domain updated",
|
||||
data={
|
||||
'id': doid,
|
||||
'scid': scid,
|
||||
'sid': sid,
|
||||
'gid': gid,
|
||||
'did': did
|
||||
}
|
||||
)
|
||||
else:
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info="Nothing to update",
|
||||
data={
|
||||
'id': doid,
|
||||
'scid': scid,
|
||||
'sid': sid,
|
||||
'gid': gid,
|
||||
'did': did
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, doid=None):
|
||||
"""
|
||||
Returns the SQL for the Domain object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
scid=scid, doid=doid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return False, internal_server_error(errormsg=res)
|
||||
data = res['rows'][0]
|
||||
|
||||
# Get Type Length and Precision
|
||||
data.update(self._parse_type(data['fulltype']))
|
||||
|
||||
# Get Domain Constraints
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_constraints.sql']),
|
||||
doid=doid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
data['constraints'] = res['rows']
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'create.sql']), data=data)
|
||||
|
||||
sql_header = """-- DOMAIN: {0}
|
||||
|
||||
-- DROP DOMAIN {0};
|
||||
|
||||
""".format(data['basensp'] + '.' + data['name'])
|
||||
|
||||
SQL = sql_header + SQL
|
||||
|
||||
return ajax_response(response=SQL.strip('\n'))
|
||||
|
||||
@check_precondition
|
||||
@validate_request
|
||||
def msql(self, gid, sid, did, scid, doid=None):
|
||||
"""
|
||||
Returns the modified SQL.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
|
||||
Required Args:
|
||||
name: Domain Name
|
||||
owner: Owner Name
|
||||
basensp: Schema Name
|
||||
basetype: Domain Base Type
|
||||
|
||||
Returns:
|
||||
SQL statements to create/update the Domain.
|
||||
"""
|
||||
|
||||
status, SQL = self.get_sql(gid, sid, self.request, scid, doid)
|
||||
|
||||
if SQL:
|
||||
return make_json_response(
|
||||
data=SQL,
|
||||
status=200
|
||||
)
|
||||
else:
|
||||
return SQL
|
||||
|
||||
def get_sql(self, gid, sid, data, scid, doid=None):
|
||||
"""
|
||||
Generates the SQL statements to create/update the Domain.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
|
||||
try:
|
||||
if doid is not None:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
scid=scid, doid=doid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
|
||||
if not status:
|
||||
return False, internal_server_error(errormsg=res)
|
||||
|
||||
old_data = res['rows'][0]
|
||||
|
||||
# Get Domain Constraints
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_constraints.sql']),
|
||||
doid=doid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
con_data = {}
|
||||
for c in res['rows']:
|
||||
con_data[c['conoid']] = c
|
||||
|
||||
old_data['constraints'] = con_data
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
data=data, o_data=old_data)
|
||||
else:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'create.sql']),
|
||||
data=data)
|
||||
return True, SQL.strip('\n')
|
||||
|
||||
except Exception as e:
|
||||
return False, e
|
||||
|
||||
@check_precondition
|
||||
def dependents(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
This function get the dependents and return ajax response
|
||||
for the Domain node.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
dependents_result = self.get_dependents(self.conn, doid)
|
||||
return ajax_response(
|
||||
response=dependents_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def dependencies(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
This function get the dependencies and return ajax response
|
||||
for the Domain node.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
dependencies_result = self.get_dependencies(self.conn, doid)
|
||||
return ajax_response(
|
||||
response=dependencies_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
DomainView.register_node_view(blueprint)
|
@ -0,0 +1,691 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Implements the Domain Constraint Module."""
|
||||
|
||||
import json
|
||||
from flask import render_template, make_response, request, jsonify
|
||||
from flask.ext.babel import gettext
|
||||
from pgadmin.utils.ajax import make_json_response, \
|
||||
make_response as ajax_response, internal_server_error
|
||||
from pgadmin.browser.utils import PGChildNodeView
|
||||
from pgadmin.browser.collection import CollectionNodeModule
|
||||
import pgadmin.browser.server_groups.servers.databases.schemas.domains \
|
||||
as domains
|
||||
from pgadmin.utils.ajax import precondition_required
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from functools import wraps
|
||||
|
||||
|
||||
class DomainConstraintModule(CollectionNodeModule):
|
||||
"""
|
||||
class DomainConstraintModule(CollectionNodeModule):
|
||||
|
||||
This class represents The Domain Constraint Module.
|
||||
|
||||
Methods:
|
||||
-------
|
||||
* __init__(*args, **kwargs)
|
||||
- Initialize the Domain Constraint Module.
|
||||
|
||||
* get_nodes(gid, sid, did, scid)
|
||||
- Generate the Domain Constraint collection node.
|
||||
|
||||
* node_inode(gid, sid, did, scid)
|
||||
- Returns Domain Constraint node as leaf node.
|
||||
|
||||
* script_load()
|
||||
- Load the module script for the Domain Constraint, when any of the
|
||||
Domain node is initialized.
|
||||
"""
|
||||
NODE_TYPE = 'domain-constraints'
|
||||
COLLECTION_LABEL = gettext("Domain Constraints")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DomainConstraintModule, self).__init__(*args, **kwargs)
|
||||
self.min_ver = None
|
||||
self.max_ver = None
|
||||
|
||||
def get_nodes(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
Generate the Domain Constraint collection node.
|
||||
"""
|
||||
yield self.generate_browser_collection_node(doid)
|
||||
|
||||
@property
|
||||
def node_inode(self):
|
||||
"""
|
||||
Returns Domain Constraint node as leaf node.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def script_load(self):
|
||||
"""
|
||||
Load the module script for the Domain Constraint, when any of the
|
||||
Domain node is initialized.
|
||||
"""
|
||||
return domains.DomainModule.NODE_TYPE
|
||||
|
||||
@property
|
||||
def csssnippets(self):
|
||||
"""
|
||||
Returns a snippet of css to include in the page
|
||||
"""
|
||||
return [
|
||||
render_template(
|
||||
"domain-constraints/css/domain-constraints.css",
|
||||
node_type=self.node_type
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
||||
blueprint = DomainConstraintModule(__name__)
|
||||
|
||||
|
||||
class DomainConstraintView(PGChildNodeView):
|
||||
"""
|
||||
class DomainConstraintView(PGChildNodeView):
|
||||
|
||||
This class inherits PGChildNodeView to get the different routes for
|
||||
the module.
|
||||
|
||||
The class is responsible to Create, Read, Update and Delete operations for
|
||||
the Domain Constraint.
|
||||
|
||||
Methods:
|
||||
-------
|
||||
|
||||
* module_js():
|
||||
- Load JS file (domain-constraints.js) for this module.
|
||||
|
||||
* check_precondition(f):
|
||||
- Works as a decorator.
|
||||
- Checks database connection status.
|
||||
- Attach connection object and template path.
|
||||
|
||||
* list(gid, sid, did, scid, doid):
|
||||
- List the Domain Constraints.
|
||||
|
||||
* nodes(gid, sid, did, scid):
|
||||
- Returns all the Domain Constraints to generate Nodes in the browser.
|
||||
|
||||
* properties(gid, sid, did, scid, doid):
|
||||
- Returns the Domain Constraint properties.
|
||||
|
||||
* create(gid, sid, did, scid):
|
||||
- Creates a new Domain Constraint object.
|
||||
|
||||
* update(gid, sid, did, scid, doid):
|
||||
- Updates the Domain Constraint object.
|
||||
|
||||
* delete(gid, sid, did, scid, doid):
|
||||
- Drops the Domain Constraint object.
|
||||
|
||||
* sql(gid, sid, did, scid, doid=None):
|
||||
- Returns the SQL for the Domain Constraint object.
|
||||
|
||||
* msql(gid, sid, did, scid, doid=None):
|
||||
- Returns the modified SQL.
|
||||
|
||||
* get_sql(gid, sid, data, scid, doid=None):
|
||||
- Generates the SQL statements to create/update the Domain Constraint.
|
||||
object.
|
||||
|
||||
* dependents(gid, sid, did, scid, doid, coid):
|
||||
- Returns the dependents for the Domain Constraint object.
|
||||
|
||||
* dependencies(gid, sid, did, scid, doid, coid):
|
||||
- Returns the dependencies for the Domain Constraint object.
|
||||
"""
|
||||
node_type = blueprint.node_type
|
||||
|
||||
parent_ids = [
|
||||
{'type': 'int', 'id': 'gid'},
|
||||
{'type': 'int', 'id': 'sid'},
|
||||
{'type': 'int', 'id': 'did'},
|
||||
{'type': 'int', 'id': 'scid'},
|
||||
{'type': 'int', 'id': 'doid'}
|
||||
]
|
||||
ids = [
|
||||
{'type': 'int', 'id': 'coid'}
|
||||
]
|
||||
|
||||
operations = dict({
|
||||
'obj': [
|
||||
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
|
||||
{'get': 'list', 'post': 'create'}
|
||||
],
|
||||
'delete': [{'delete': 'delete'}],
|
||||
'children': [{'get': 'children'}],
|
||||
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
|
||||
'sql': [{'get': 'sql'}],
|
||||
'msql': [{'get': 'msql'}, {'get': 'msql'}],
|
||||
'stats': [{'get': 'statistics'}],
|
||||
'dependency': [{'get': 'dependencies'}],
|
||||
'dependent': [{'get': 'dependents'}],
|
||||
'module.js': [{}, {}, {'get': 'module_js'}]
|
||||
})
|
||||
|
||||
def validate_request(f):
|
||||
"""
|
||||
Works as a decorator.
|
||||
Validating request on the request of create, update and modified SQL.
|
||||
|
||||
Required Args:
|
||||
name: Name of the Domain Constraint
|
||||
consrc: Check Constraint Definition
|
||||
|
||||
Above both the arguments will not be validated in the update action.
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def wrap(self, **kwargs):
|
||||
|
||||
data = {}
|
||||
if request.data:
|
||||
req = json.loads(request.data.decode())
|
||||
else:
|
||||
req = request.args or request.form
|
||||
|
||||
if 'coid' not in kwargs:
|
||||
required_args = [
|
||||
'name',
|
||||
'consrc'
|
||||
]
|
||||
|
||||
for arg in required_args:
|
||||
if arg not in req or req[arg] == '':
|
||||
return make_json_response(
|
||||
status=410,
|
||||
success=0,
|
||||
errormsg=gettext(
|
||||
"Couldn't find the required parameter \
|
||||
(%s)." % arg
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
for key in req:
|
||||
if key == 'convalidated':
|
||||
data[key] = True if (req[key] == 'true' or req[key] is
|
||||
True) else False
|
||||
else:
|
||||
data[key] = req[key]
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
self.request = data
|
||||
return f(self, **kwargs)
|
||||
|
||||
return wrap
|
||||
|
||||
def module_js(self):
|
||||
"""
|
||||
Load JS file (domain-constraints.js) for this module.
|
||||
"""
|
||||
return make_response(
|
||||
render_template(
|
||||
"domain-constraints/js/domain-constraints.js",
|
||||
_=gettext
|
||||
),
|
||||
200, {'Content-Type': 'application/x-javascript'}
|
||||
)
|
||||
|
||||
def check_precondition(f):
|
||||
"""
|
||||
Works as a decorator.
|
||||
Checks database connection status.
|
||||
Attach connection object and template path.
|
||||
"""
|
||||
@wraps(f)
|
||||
def wrap(*args, **kwargs):
|
||||
self = args[0]
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
self.manager = driver.connection_manager(kwargs['sid'])
|
||||
self.conn = self.manager.connection(did=kwargs['did'])
|
||||
self.qtIdent = driver.qtIdent
|
||||
|
||||
# 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!")
|
||||
)
|
||||
|
||||
ver = self.manager.version
|
||||
|
||||
# we will set template path for sql scripts
|
||||
if ver >= 90200:
|
||||
self.template_path = 'domain-constraints/sql/9.2_plus'
|
||||
elif ver >= 90100:
|
||||
self.template_path = 'domain-constraints/sql/9.1_plus'
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return wrap
|
||||
|
||||
@check_precondition
|
||||
def list(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
List the Domain Constraints.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
doid=doid)
|
||||
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, doid):
|
||||
"""
|
||||
Returns all the Domain Constraints.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
"""
|
||||
res = []
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
doid=doid)
|
||||
status, rset = self.conn.execute_2darray(SQL)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=rset)
|
||||
|
||||
for row in rset['rows']:
|
||||
if 'convalidated' not in row:
|
||||
icon = 'icon-domain-constraints'
|
||||
elif row['convalidated']:
|
||||
icon = 'icon-domain-constraints'
|
||||
else:
|
||||
icon = 'icon-domain-constraints-bad'
|
||||
res.append(
|
||||
self.blueprint.generate_browser_node(
|
||||
row['oid'],
|
||||
doid,
|
||||
row['name'],
|
||||
icon=icon
|
||||
))
|
||||
|
||||
return make_json_response(
|
||||
data=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def properties(self, gid, sid, did, scid, doid, coid):
|
||||
"""
|
||||
Returns the Domain Constraints property.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
doid=doid, coid=coid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
data = res['rows'][0]
|
||||
return ajax_response(
|
||||
response=data,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
@validate_request
|
||||
def create(self, gid, sid, did, scid, doid):
|
||||
"""
|
||||
Creates a new Domain Constraint object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
|
||||
Returns:
|
||||
Domain Constraint object in json format.
|
||||
"""
|
||||
data = self.request
|
||||
try:
|
||||
status, SQL = self.get_sql(gid, sid, data, scid, doid)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=SQL)
|
||||
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
# Get the recently added constraints oid
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_oid.sql']),
|
||||
doid=doid, name=data['name'])
|
||||
status, coid = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=coid)
|
||||
|
||||
if 'convalidated' not in data:
|
||||
icon = 'icon-domain-constraints'
|
||||
elif 'convalidated' in data and data['convalidated']:
|
||||
icon = 'icon-domain-constraints'
|
||||
else:
|
||||
icon = 'icon-domain-constraints-bad'
|
||||
|
||||
return jsonify(
|
||||
node=self.blueprint.generate_browser_node(
|
||||
coid,
|
||||
doid,
|
||||
data['name'],
|
||||
icon=icon
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
def delete(self, gid, sid, did, scid, doid, coid):
|
||||
"""
|
||||
Drops the Domain Constraint object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
try:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
doid=doid, coid=coid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
data = res['rows'][0]
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'delete.sql']),
|
||||
data=data)
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info=gettext("Domain Constraint dropped"),
|
||||
data={
|
||||
'id': doid,
|
||||
'scid': scid,
|
||||
'sid': sid,
|
||||
'gid': gid,
|
||||
'did': did
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
@validate_request
|
||||
def update(self, gid, sid, did, scid, doid, coid):
|
||||
"""
|
||||
Updates the Domain Constraint object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
data = self.request
|
||||
status, SQL = self.get_sql(gid, sid, data, scid, doid, coid)
|
||||
|
||||
try:
|
||||
if SQL and status:
|
||||
status, res = self.conn.execute_scalar(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
if 'convalidated' in data and data['convalidated']:
|
||||
icon = 'icon-domain-constraints'
|
||||
elif 'convalidated' in data and not data['convalidated']:
|
||||
icon = 'icon-domain-constraints-bad'
|
||||
else:
|
||||
icon = ''
|
||||
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info="Domain Constraint updated",
|
||||
data={
|
||||
'id': coid,
|
||||
'doid': doid,
|
||||
'scid': scid,
|
||||
'sid': sid,
|
||||
'gid': gid,
|
||||
'did': did,
|
||||
'icon': icon
|
||||
}
|
||||
)
|
||||
else:
|
||||
return make_json_response(
|
||||
success=1,
|
||||
info="Nothing to update",
|
||||
data={
|
||||
'id': coid,
|
||||
'doid': doid,
|
||||
'scid': scid,
|
||||
'sid': sid,
|
||||
'gid': gid,
|
||||
'did': did
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
@check_precondition
|
||||
def sql(self, gid, sid, did, scid, doid, coid=None):
|
||||
"""
|
||||
Returns the SQL for the Domain Constraint object.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
|
||||
# Get Schema and Domain.
|
||||
domain, schema = self._get_domain(doid)
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
doid=doid, coid=coid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
data = res['rows'][0]
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'create.sql']),
|
||||
data=data, domain=domain, schema=schema)
|
||||
|
||||
sql_header = """-- CHECK: {1}.{0}
|
||||
|
||||
-- ALTER DOMAIN {1} DROP CONSTRAINT {0};
|
||||
|
||||
""".format(data['name'], schema + '.' + domain)
|
||||
|
||||
SQL = sql_header + SQL
|
||||
|
||||
return ajax_response(response=SQL)
|
||||
|
||||
@check_precondition
|
||||
@validate_request
|
||||
def msql(self, gid, sid, did, scid, doid, coid=None):
|
||||
"""
|
||||
Returns the modified SQL.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
|
||||
Returns:
|
||||
Domain Constraint object in json format.
|
||||
"""
|
||||
data = self.request
|
||||
|
||||
status, SQL = self.get_sql(gid, sid, data, scid, doid, coid)
|
||||
if status and SQL:
|
||||
return make_json_response(
|
||||
data=SQL,
|
||||
status=200
|
||||
)
|
||||
else:
|
||||
return SQL
|
||||
|
||||
def get_sql(self, gid, sid, data, scid, doid, coid=None):
|
||||
"""
|
||||
Generates the SQL statements to create/update the Domain Constraint.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
try:
|
||||
if coid is not None:
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'properties.sql']),
|
||||
doid=doid, coid=coid)
|
||||
status, res = self.conn.execute_dict(SQL)
|
||||
|
||||
if not status:
|
||||
return False, internal_server_error(errormsg=res)
|
||||
|
||||
old_data = res['rows'][0]
|
||||
|
||||
SQL = render_template(
|
||||
"/".join([self.template_path, 'update.sql']),
|
||||
data=data, o_data=old_data, conn=self.conn
|
||||
)
|
||||
else:
|
||||
domain, schema = self._get_domain(doid)
|
||||
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'create.sql']),
|
||||
data=data, domain=domain, schema=schema)
|
||||
return True, SQL.strip('\n')
|
||||
except Exception as e:
|
||||
return False, internal_server_error(errormsg=str(e))
|
||||
|
||||
def _get_domain(self, doid):
|
||||
"""
|
||||
Returns Domain and Schema name.
|
||||
|
||||
Args:
|
||||
doid: Domain Id
|
||||
|
||||
"""
|
||||
SQL = render_template("/".join([self.template_path,
|
||||
'get_domain.sql']),
|
||||
doid=doid)
|
||||
status, res = self.conn.execute_2darray(SQL)
|
||||
|
||||
if not status:
|
||||
return False, internal_server_error(errormsg=res)
|
||||
|
||||
return res['rows'][0]
|
||||
|
||||
@check_precondition
|
||||
def dependents(self, gid, sid, did, scid, doid, coid):
|
||||
"""
|
||||
This function get the dependents and return ajax response
|
||||
for the Domain Constraint node.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
dependents_result = self.get_dependents(self.conn, coid)
|
||||
return ajax_response(
|
||||
response=dependents_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
@check_precondition
|
||||
def dependencies(self, gid, sid, did, scid, doid, coid):
|
||||
"""
|
||||
This function get the dependencies and return ajax response
|
||||
for the Domain Constraint node.
|
||||
|
||||
Args:
|
||||
gid: Server Group Id
|
||||
sid: Server Id
|
||||
did: Database Id
|
||||
scid: Schema Id
|
||||
doid: Domain Id
|
||||
coid: Domain Constraint Id
|
||||
"""
|
||||
dependencies_result = self.get_dependencies(self.conn, coid)
|
||||
return ajax_response(
|
||||
response=dependencies_result,
|
||||
status=200
|
||||
)
|
||||
|
||||
DomainConstraintView.register_node_view(blueprint)
|
Binary file not shown.
After Width: | Height: | Size: 314 B |
Binary file not shown.
After Width: | Height: | Size: 579 B |
Binary file not shown.
After Width: | Height: | Size: 406 B |
@ -0,0 +1,23 @@
|
||||
.icon-coll-domain-constraints {
|
||||
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/coll-domain-constraints.png' )}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-check-bad, .icon-domain-constraints-bad {
|
||||
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/domain-constraints-bad.png' )}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.icon-check, .icon-domain-constraints {
|
||||
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/domain-constraints.png' )}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
// Domain Constraint Module: Collection and Node
|
||||
define(
|
||||
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
|
||||
function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
|
||||
// Define Domain Constraint Collection Node
|
||||
if (!pgBrowser.Nodes['coll-domain-constraints']) {
|
||||
var domain_constraints = pgAdmin.Browser.Nodes['coll-domain-constraints'] =
|
||||
pgAdmin.Browser.Collection.extend({
|
||||
node: 'domain-constraints',
|
||||
label: '{{ _('Domain Constraints') }}',
|
||||
type: 'coll-domain-constraints',
|
||||
columns: ['name', 'description']
|
||||
});
|
||||
};
|
||||
|
||||
// Domain Constraint Node
|
||||
if (!pgBrowser.Nodes['domain-constraints']) {
|
||||
pgAdmin.Browser.Nodes['domain-constraints'] = pgBrowser.Node.extend({
|
||||
type: 'domain-constraints',
|
||||
label: '{{ _('Domain Constraints') }}',
|
||||
collection_type: 'coll-domain-constraints',
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
parent_type: ['domain'],
|
||||
Init: function() {
|
||||
// Avoid mulitple registration of menus
|
||||
if (this.initialized)
|
||||
return;
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
pgBrowser.add_menus([{
|
||||
name: 'create_domain_on_coll', node: 'coll-domain-constraints', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 5, label: '{{ _('Domain Constraint...') }}',
|
||||
icon: 'wcTabIcon icon-domain-constraints', data: {action: 'create', check: true},
|
||||
enable: 'canCreate'
|
||||
},{
|
||||
name: 'create_domain-constraints', node: 'domain-constraints', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 5, label: '{{ _('Domain Constraint...') }}',
|
||||
icon: 'wcTabIcon icon-domain-constraints', data: {action: 'create', check: true},
|
||||
enable: 'canCreate'
|
||||
},{
|
||||
name: 'create_domain-constraints', node: 'domain', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 5, label: '{{ _('Domain Constraint...') }}',
|
||||
icon: 'wcTabIcon icon-domain-constraints', data: {action: 'create', check: false},
|
||||
enable: 'canCreate'
|
||||
}
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
name: undefined,
|
||||
oid: undefined,
|
||||
description: undefined,
|
||||
consrc: undefined,
|
||||
connoinherit: undefined,
|
||||
convalidated: true
|
||||
},
|
||||
// Domain Constraint Schema
|
||||
schema: [{
|
||||
id: 'name', label: '{{ _('Name') }}', type:'text', cell:'string',
|
||||
disabled: 'isDisabled'
|
||||
},{
|
||||
id: 'oid', label:'{{ _('OID') }}', cell: 'string',
|
||||
type: 'text' , mode: ['properties']
|
||||
},{
|
||||
id: 'description', label: '{{ _('Comment') }}', type: 'multiline', cell:
|
||||
'string', mode: ['properties', 'create', 'edit'], min_version: 90500,
|
||||
},{
|
||||
id: 'consrc', label: '{{ _('Check') }}', type: 'multiline', cel:
|
||||
'string', group: '{{ _('Definition') }}', mode: ['properties',
|
||||
'create', 'edit'], disabled: function(m) { return !m.isNew(); }
|
||||
},{
|
||||
id: 'connoinherit', label: '{{ _('No Inherit') }}', type:
|
||||
'switch', cell: 'boolean', group: '{{ _('Definition') }}', mode:
|
||||
['properties', 'create', 'edit'], disabled: 'isDisabled',
|
||||
visible: false
|
||||
},{
|
||||
id: 'convalidated', label: "{{ _("Validate?") }}", type: 'switch', cell:
|
||||
'boolean', group: '{{ _('Definition') }}', min_version: 90200,
|
||||
disabled: function(m) {
|
||||
if (!m.isNew()) {
|
||||
var server = this.node_info.server;
|
||||
if (server.version < 90200) { return true;
|
||||
}
|
||||
else if(m.get('convalidated')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
mode: ['properties', 'create', 'edit']
|
||||
}],
|
||||
// Client Side Validation
|
||||
validate: function() {
|
||||
var err = {},
|
||||
errmsg;
|
||||
|
||||
if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['name'] = '{{ _('Name can not be empty!') }}';
|
||||
errmsg = errmsg || err['name'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('consrc')) || String(this.get('consrc')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['consrc'] = '{{ _('Check can not be empty!') }}';
|
||||
errmsg = errmsg || err['consrc'];
|
||||
}
|
||||
|
||||
this.errorModel.clear().set(err);
|
||||
|
||||
if (_.size(err)) {
|
||||
this.trigger('on-status', {msg: errmsg});
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
},
|
||||
isDisabled: function(m){
|
||||
if (!m.isNew()) {
|
||||
var server = this.node_info.server;
|
||||
if (server.version < 90200)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return pgBrowser.Nodes['domain'];
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
{% if data and schema and domain %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(schema, domain) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(data.name) }} CHECK ({{ data.consrc }});{% endif -%}
|
@ -0,0 +1,4 @@
|
||||
{% if data %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(data.nspname, data.relname) }}
|
||||
DROP CONSTRAINT {{ conn|qtIdent(data.name) }};
|
||||
{% endif %}
|
@ -0,0 +1,8 @@
|
||||
SELECT
|
||||
d.typname as domain, bn.nspname as schema
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
d.oid = {{doid}};
|
@ -0,0 +1,7 @@
|
||||
SELECT
|
||||
oid, conname as name
|
||||
FROM
|
||||
pg_constraint
|
||||
WHERE
|
||||
contypid = {{doid}}::oid
|
||||
AND conname={{ name|qtLiteral }};
|
@ -0,0 +1,14 @@
|
||||
SELECT
|
||||
c.oid, conname AS name, typname AS relname, nspname,
|
||||
regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') AS consrc
|
||||
FROM
|
||||
pg_constraint c
|
||||
JOIN
|
||||
pg_type t ON t.oid=contypid
|
||||
JOIN
|
||||
pg_namespace nl ON nl.oid=typnamespace
|
||||
WHERE
|
||||
contype = 'c' AND contypid = {{doid}}::oid
|
||||
{% if coid %}
|
||||
AND c.oid = {{ coid }}
|
||||
{% endif %}
|
@ -0,0 +1,3 @@
|
||||
{% if data.name %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};{% endif %}
|
@ -0,0 +1,10 @@
|
||||
{% if data and schema and domain %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(schema, domain) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(data.name) }} CHECK ({{ data.consrc }}){% if not data.convalidated %}
|
||||
|
||||
NOT VALID{% endif %};{% if data.description %}
|
||||
|
||||
|
||||
COMMENT ON CONSTRAINT {{ conn|qtIdent(data.name) }} ON DOMAIN {{ conn|qtIdent(schema, domain) }}
|
||||
IS '{{ data.description }}';{% endif %}
|
||||
{% endif %}
|
@ -0,0 +1,4 @@
|
||||
{% if data %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(data.nspname, data.relname) }}
|
||||
DROP CONSTRAINT {{ conn|qtIdent(data.name) }};
|
||||
{% endif %}
|
@ -0,0 +1,8 @@
|
||||
SELECT
|
||||
d.typname as domain, bn.nspname as schema
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
d.oid = {{doid}};
|
@ -0,0 +1,7 @@
|
||||
SELECT
|
||||
oid, conname as name
|
||||
FROM
|
||||
pg_constraint
|
||||
WHERE
|
||||
contypid = {{doid}}::oid
|
||||
AND conname={{ name|qtLiteral }};
|
@ -0,0 +1,5 @@
|
||||
SELECT
|
||||
typcategory
|
||||
FROM
|
||||
pg_type
|
||||
WHERE typname = {{datatype}};
|
@ -0,0 +1,17 @@
|
||||
SELECT
|
||||
c.oid, conname AS name, typname AS relname, nspname, description,
|
||||
regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') AS consrc,
|
||||
connoinherit, convalidated, convalidated AS convalidated_p
|
||||
FROM
|
||||
pg_constraint c
|
||||
JOIN
|
||||
pg_type t ON t.oid=contypid
|
||||
JOIN
|
||||
pg_namespace nl ON nl.oid=typnamespace
|
||||
LEFT OUTER JOIN
|
||||
pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass)
|
||||
WHERE
|
||||
contype = 'c' AND contypid = {{doid}}::oid
|
||||
{% if coid %}
|
||||
AND c.oid = {{ coid }}
|
||||
{% endif %}
|
@ -0,0 +1,13 @@
|
||||
{% set name = o_data.name %}
|
||||
{% if data.name %}
|
||||
{% set name = data.name %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
RENAME CONSTRAINT {{ conn|qtIdent(o_data.name) }} TO {{ conn|qtIdent(data.name) }};{% endif -%}{% if data.convalidated %}
|
||||
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
VALIDATE CONSTRAINT {{ conn|qtIdent(name) }};{% endif -%}{% if data.description %}
|
||||
|
||||
|
||||
COMMENT ON CONSTRAINT {{ conn|qtIdent(name) }} ON DOMAIN {{ conn|qtIdent(o_data.nspname, o_data.relname) }}
|
||||
IS '{{ data.description }}';{% endif %}
|
Binary file not shown.
After Width: | Height: | Size: 462 B |
Binary file not shown.
After Width: | Height: | Size: 401 B |
Binary file not shown.
After Width: | Height: | Size: 424 B |
@ -0,0 +1,362 @@
|
||||
// Domain Module: Collection and Node.
|
||||
define(
|
||||
['jquery', 'underscore', 'underscore.string', 'pgadmin',
|
||||
'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
|
||||
function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
|
||||
// Define Domain Collection Node
|
||||
if (!pgBrowser.Nodes['coll-domain']) {
|
||||
var domains = pgAdmin.Browser.Nodes['coll-domain'] =
|
||||
pgAdmin.Browser.Collection.extend({
|
||||
node: 'domain',
|
||||
label: '{{ _('Domains') }}',
|
||||
type: 'coll-domain',
|
||||
columns: ['name', 'owner', 'description']
|
||||
});
|
||||
};
|
||||
|
||||
// Security Model
|
||||
var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
provider: null,
|
||||
security_label: null
|
||||
},
|
||||
schema: [{
|
||||
id: 'provider', label: '{{ _('Provider') }}',
|
||||
type: 'text', editable: true, cellHeaderClasses:'width_percent_50'
|
||||
},{
|
||||
id: 'security_label', label: '{{ _('Security Label') }}',
|
||||
type: 'text', editable: true, cellHeaderClasses:'width_percent_50'
|
||||
}],
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
// Constraint Model
|
||||
var ConstraintModel = pgAdmin.Browser.Node.Model.extend({
|
||||
idAttribute: 'conoid',
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
if (!isNew) {
|
||||
this.convalidated_default = this.get('convalidated')
|
||||
}
|
||||
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
defaults: {
|
||||
conoid: undefined,
|
||||
conname: undefined,
|
||||
consrc: undefined,
|
||||
convalidated: true
|
||||
},
|
||||
convalidated_default: true,
|
||||
schema: [{
|
||||
id: 'conoid', type: 'text', cell: 'string', visible: false
|
||||
},{
|
||||
id: 'conname', label: '{{ _('Name') }}', type: 'text', cell: 'string',
|
||||
cellHeaderClasses: 'width_percent_40',
|
||||
editable: function(m) {
|
||||
if (_.isUndefined(m.isNew)) { return true; }
|
||||
if (!m.isNew()) {
|
||||
var server = this.get('node_info').server;
|
||||
if (server.version < 90200) { return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},{
|
||||
id: 'consrc', label: '{{ _('Check') }}', type: 'multiline',
|
||||
cell: Backgrid.Extension.TextareaCell, group: '{{ _('Definition') }}',
|
||||
cellHeaderClasses: 'width_percent_60', editable: function(m) {
|
||||
return _.isUndefined(m.isNew) ? true : m.isNew();
|
||||
}
|
||||
},{
|
||||
id: 'convalidated', label: '{{ _('Validate?') }}', type: 'switch', cell:
|
||||
'boolean', group: '{{ _('Definition') }}',
|
||||
editable: function(m) {
|
||||
var server = this.get('node_info').server;
|
||||
if (server.version < 90200) { return false;
|
||||
}
|
||||
if (_.isUndefined(m.isNew)) { return true; }
|
||||
if (!m.isNew()) {
|
||||
if(m.get('convalidated') && m.convalidated_default) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}],
|
||||
toJSON: Backbone.Model.prototype.toJSON,
|
||||
validate: function() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Domain Node
|
||||
if (!pgBrowser.Nodes['domain']) {
|
||||
pgAdmin.Browser.Nodes['domain'] = pgBrowser.Node.extend({
|
||||
type: 'domain',
|
||||
label: '{{ _('Domain') }}',
|
||||
collection_type: 'coll-domain',
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
parent_type: ['schema'],
|
||||
Init: function() {
|
||||
// Avoid mulitple registration of menus
|
||||
if (this.initialized)
|
||||
return;
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
pgBrowser.add_menus([{
|
||||
name: 'create_domain_on_coll', node: 'coll-domain', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: '{{ _('Domain...') }}',
|
||||
icon: 'wcTabIcon icon-domain', data: {action: 'create', check: true},
|
||||
enable: 'canCreate'
|
||||
},{
|
||||
name: 'create_domain', node: 'domain', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: '{{ _('Domain...') }}',
|
||||
icon: 'wcTabIcon icon-domain', data: {action: 'create', check: true},
|
||||
enable: 'canCreate'
|
||||
},{
|
||||
name: 'create_domain', node: 'schema', module: this,
|
||||
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||
category: 'create', priority: 4, label: '{{ _('Domain...') }}',
|
||||
icon: 'wcTabIcon icon-domain', data: {action: 'create', check: false},
|
||||
enable: 'canCreate'
|
||||
}
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
// Domain Node Model
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
if (isNew) {
|
||||
// Set Selected Schema
|
||||
schema = args.node_info.schema.label
|
||||
this.set({'basensp': schema}, {silent: true});
|
||||
|
||||
// Set Current User
|
||||
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
|
||||
this.set({'owner': userInfo.name}, {silent: true});
|
||||
}
|
||||
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
defaults: {
|
||||
name: undefined,
|
||||
oid: undefined,
|
||||
owner: undefined,
|
||||
basensp: undefined,
|
||||
description: undefined,
|
||||
basetype: undefined,
|
||||
typlen: undefined,
|
||||
precision: undefined,
|
||||
typdefault: undefined,
|
||||
typnotnull: undefined,
|
||||
sysdomain: undefined,
|
||||
collname: undefined,
|
||||
constraints: [],
|
||||
seclabels: []
|
||||
},
|
||||
type_options: undefined,
|
||||
// Domain Schema
|
||||
schema: [{
|
||||
id: 'name', label: '{{ _('Name') }}', cell: 'string',
|
||||
type: 'text', mode: ['properties', 'create', 'edit']
|
||||
},{
|
||||
id: 'oid', label:'{{ _('OID') }}', cell: 'string',
|
||||
type: 'text' , mode: ['properties']
|
||||
},{
|
||||
id: 'owner', label:'{{ _('Owner') }}', cell: 'string', control: Backform.NodeListByNameControl,
|
||||
node: 'role', type: 'text', mode: ['edit', 'create', 'properties']
|
||||
},{
|
||||
id: 'basensp', label:'{{ _('Schema') }}', cell: 'node-list-by-name',
|
||||
control: 'node-list-by-name', cache_level: 'database', type: 'text',
|
||||
node: 'schema', mode: ['create', 'edit']
|
||||
},{
|
||||
id: 'sysdomain', label:'{{ _('System domain?') }}', cell: 'boolean',
|
||||
type: 'switch', mode: ['properties'],
|
||||
options: {
|
||||
'onText': 'Yes', 'offText': 'No',
|
||||
'onColor': 'success', 'offColor': 'primary',
|
||||
'size': 'small'
|
||||
}
|
||||
},{
|
||||
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
|
||||
type: 'multiline'
|
||||
},{
|
||||
id: 'basetype', label:'{{ _('Base type') }}', cell: 'string', control: 'node-ajax-options',
|
||||
type: 'text', mode:['properties', 'create', 'edit'], group: '{{ _('Definition') }}', url: 'get_types',
|
||||
disabled: function(m) { return !m.isNew(); }, first_empty: true,
|
||||
transform: function(d){
|
||||
this.model.type_options = d;
|
||||
return d;
|
||||
}
|
||||
},{
|
||||
id: 'typlen', label:'{{ _('Length') }}', cell: 'string',
|
||||
type: 'text', group: '{{ _('Definition') }}', deps: ['basetype'],
|
||||
disabled: function(m) {
|
||||
// We will store type from selected from combobox
|
||||
if (!m.isNew()) {
|
||||
return true;
|
||||
}
|
||||
var of_type = m.get('basetype');
|
||||
if(m.type_options) {
|
||||
// iterating over all the types
|
||||
_.each(m.type_options, function(o) {
|
||||
// if type from selected from combobox matches in options
|
||||
if ( of_type == o.value ) {
|
||||
// if length is allowed for selected type
|
||||
if(o.length)
|
||||
{
|
||||
// set the values in model
|
||||
m.set('is_tlength', true, {silent: true});
|
||||
m.set('min_val', o.min_val, {silent: true});
|
||||
m.set('max_val', o.max_val, {silent: true});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return !m.get('is_tlength');
|
||||
}
|
||||
},{
|
||||
id: 'precision', label:'{{ _('Precision') }}', cell: 'string',
|
||||
type: 'text', group: '{{ _('Definition') }}', deps: ['basetype'],
|
||||
disabled: function(m) {
|
||||
// We will store type from selected from combobox
|
||||
if (!m.isNew()) {
|
||||
return true;
|
||||
}
|
||||
var of_type = m.get('basetype');
|
||||
if(m.type_options) {
|
||||
// iterating over all the types
|
||||
_.each(m.type_options, function(o) {
|
||||
// if type from selected from combobox matches in options
|
||||
if ( of_type == o.value ) {
|
||||
// if precession is allowed for selected type
|
||||
if(o.precision)
|
||||
{
|
||||
// set the values in model
|
||||
m.set('is_precision', true, {silent: true});
|
||||
m.set('min_val', o.min_val, {silent: true});
|
||||
m.set('max_val', o.max_val, {silent: true});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return !m.get('is_precision');
|
||||
}
|
||||
},{
|
||||
id: 'typdefault', label:'{{ _('Default') }}', cell: 'string',
|
||||
type: 'text', group: '{{ _('Definition') }}',
|
||||
placeholder: "Enter an expression or a value."
|
||||
},{
|
||||
id: 'typnotnull', label:'{{ _('Not Null?') }}', cell: 'boolean',
|
||||
type: 'switch', group: '{{ _('Definition') }}',
|
||||
options: {
|
||||
'onText': 'Yes', 'offText': 'No',
|
||||
'onColor': 'success', 'offColor': 'primary',
|
||||
'size': 'small'
|
||||
}
|
||||
},{
|
||||
id: 'collname', label:'{{ _('Collation') }}', cell: 'string', control: 'node-ajax-options',
|
||||
type: 'text', group: '{{ _('Definition') }}', url: 'get_collations', disabled: function(m) {
|
||||
return !m.isNew();
|
||||
}
|
||||
},{
|
||||
id: 'constraints', label:'{{ _('Constraints') }}', cell: 'string',
|
||||
type: 'collection', group: '{{ _('Constraints') }}', mode: ['edit', 'create'],
|
||||
model: ConstraintModel, canAdd: true, canDelete: true,
|
||||
canEdit: false, columns: ['conname','consrc', 'convalidated']
|
||||
},{
|
||||
id: 'seclabels', label: '{{ _('Security Labels') }}',
|
||||
model: SecurityModel, type: 'collection',
|
||||
group: '{{ _('Security') }}', mode: ['edit', 'create'],
|
||||
min_version: 90100, canAdd: true,
|
||||
canEdit: false, canDelete: true,
|
||||
control: 'unique-col-collection', uniqueCol : ['provider']
|
||||
}
|
||||
],
|
||||
validate: function() // Client Side Validation
|
||||
{
|
||||
var err = {},
|
||||
errmsg,
|
||||
seclabels = this.get('seclabels');
|
||||
|
||||
if (_.isUndefined(this.get('name')) || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['name'] = '{{ _('Name can not be empty!') }}';
|
||||
errmsg = errmsg || err['name'];
|
||||
}
|
||||
|
||||
if (_.isUndefined(this.get('basetype')) || String(this.get('basetype')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
err['basetype'] = '{{ _('Base Type can not be empty!') }}';
|
||||
errmsg = errmsg || err['basetype'];
|
||||
}
|
||||
|
||||
this.errorModel.clear().set(err);
|
||||
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
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 domain
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-domain' == d._type) {
|
||||
//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;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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;
|
||||
},
|
||||
isDisabled: function(m){
|
||||
if (!m.isNew()) {
|
||||
var server = this.node_info.server;
|
||||
if (server.version < 90200)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return pgBrowser.Nodes['domain'];
|
||||
});
|
@ -0,0 +1,30 @@
|
||||
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||
{% if data %}
|
||||
CREATE DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
AS {{ conn|qtTypeIdent(data.basetype) }}{% if data.typlen %}({{data.typlen}}{% if data.precision %},{{data.precision}}{% endif %}){% endif %}{% if data.collname %}
|
||||
|
||||
COLLATE {{ data.collname }}{% endif %}{% if data.typdefault %}
|
||||
|
||||
DEFAULT {{ data.typdefault }}{% endif %}{% if data.typnotnull %}
|
||||
|
||||
NOT NULL{% endif %}{% if data.constraints %}{% for c in data.constraints %}{% if c.conname and c.consrc %}
|
||||
|
||||
CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% endif -%}
|
||||
{% endfor -%}
|
||||
{% endif -%};
|
||||
|
||||
{% if data.owner %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }};{% endif %}{% if data.description %}
|
||||
|
||||
|
||||
COMMENT ON DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
IS '{{ data.description }}';{% endif -%}{% if data.seclabels %}
|
||||
{% for r in data.seclabels %}
|
||||
{% if r.security_label and r.provider %}
|
||||
|
||||
|
||||
{{ SECLABLE.SET(conn, 'DOMAIN', data.name, r.provider, r.security_label, data.basensp) }}{% endif -%}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% endif -%}
|
@ -0,0 +1,16 @@
|
||||
{% if scid and doid %}
|
||||
SELECT
|
||||
d.typname as name, bn.nspname as basensp
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
AND
|
||||
d.oid={{doid}}::int;
|
||||
{% endif %}
|
||||
|
||||
{% if name %}
|
||||
DROP DOMAIN {{ conn|qtIdent(basensp, name) }}{% if cascade %} CASCADE{% endif %};
|
||||
{% endif %}
|
@ -0,0 +1,10 @@
|
||||
SELECT --nspname, collname,
|
||||
CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
|
||||
concat(nspname, '."', collname,'"')
|
||||
ELSE '' END AS copy_collation
|
||||
FROM
|
||||
pg_collation c, pg_namespace n
|
||||
WHERE
|
||||
c.collnamespace=n.oid
|
||||
ORDER BY
|
||||
nspname, collname;
|
@ -0,0 +1,15 @@
|
||||
SELECT
|
||||
'DOMAIN' AS objectkind, c.oid as conoid, conname, typname as relname, nspname, description,
|
||||
regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') as cons
|
||||
FROM
|
||||
pg_constraint c
|
||||
JOIN
|
||||
pg_type t ON t.oid=contypid
|
||||
JOIN
|
||||
pg_namespace nl ON nl.oid=typnamespace
|
||||
LEFT OUTER JOIN
|
||||
pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)
|
||||
WHERE
|
||||
contype = 'c'
|
||||
AND contypid = {{doid}}::oid
|
||||
ORDER BY conname;
|
@ -0,0 +1,18 @@
|
||||
{% if doid %}
|
||||
SELECT
|
||||
d.typnamespace as scid
|
||||
FROM
|
||||
pg_type d
|
||||
WHERE
|
||||
d.oid={{ doid }}::oid;
|
||||
{% else %}
|
||||
SELECT
|
||||
d.oid, d.typnamespace
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
bn.nspname = {{ basensp|qtLiteral }}
|
||||
AND d.typname={{ name|qtLiteral }};
|
||||
{% endif %}
|
@ -0,0 +1,13 @@
|
||||
SELECT
|
||||
d.oid, d.typname as name, pg_get_userbyid(d.typowner) as owner,
|
||||
bn.nspname as basensp
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_type b ON b.oid = d.typbasetype
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
ORDER BY
|
||||
d.typname;
|
@ -0,0 +1,35 @@
|
||||
SELECT
|
||||
d.oid, d.typname as name, d.typbasetype, format_type(b.oid,NULL) as basetype,
|
||||
pg_get_userbyid(d.typowner) as owner,
|
||||
c.oid AS colloid, format_type(b.oid, d.typtypmod) AS fulltype,
|
||||
CASE WHEN length(cn.nspname) > 0 AND length(c.collname) > 0 THEN
|
||||
concat(cn.nspname, '."', c.collname,'"')
|
||||
ELSE '' END AS collname,
|
||||
d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,
|
||||
description, (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname=d.typname) > 1 AS domisdup,
|
||||
(SELECT COUNT(1) FROM pg_type t3 WHERE t3.typname=b.typname) > 1 AS baseisdup,
|
||||
(SELECT
|
||||
array_agg(provider || '=' || label)
|
||||
FROM
|
||||
pg_seclabel sl1
|
||||
WHERE
|
||||
sl1.objoid=d.oid) AS seclabels
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_type b ON b.oid = d.typbasetype
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
LEFT OUTER JOIN
|
||||
pg_description des ON (des.objoid=d.oid AND des.classoid='pg_type'::regclass)
|
||||
LEFT OUTER JOIN
|
||||
pg_collation c ON d.typcollation=c.oid
|
||||
LEFT OUTER JOIN
|
||||
pg_namespace cn ON c.collnamespace=cn.oid
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
{% if doid %}
|
||||
AND d.oid={{doid}}::int
|
||||
{% endif %}
|
||||
ORDER BY
|
||||
d.typname;
|
@ -0,0 +1,69 @@
|
||||
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||
{% if data %}
|
||||
{% set name = o_data.name %}
|
||||
{% if data.name %}
|
||||
{% if data.name != o_data.name %}
|
||||
ALTER TYPE {{ conn|qtIdent(o_data.basensp, o_data.name) }}
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
{% set name = data.name %}
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
{% if data.typnotnull and not o_data.typnotnull %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET NOT NULL;
|
||||
{% elif 'typnotnull' in data and not data.typnotnull and o_data.typnotnull%}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP NOT NULL;
|
||||
{% endif -%}{% if data.typdefault %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET DEFAULT {{ data.typdefault }};
|
||||
{% elif data.typdefault == '' and o_data.typdefault %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP DEFAULT;
|
||||
{% endif -%}{% if data.owner %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
OWNER TO {{ conn|qtIdent(data.owner) }};
|
||||
{% endif -%}{% if data.constraints %}
|
||||
{% for c in data.constraints.deleted %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP CONSTRAINT {{ conn|qtIdent(c.conname) }};
|
||||
{% endfor -%}
|
||||
{% for c in data.constraints.added %}
|
||||
{% if c.conname and c.consrc %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }} );{% endif -%}
|
||||
{% endfor -%}{% endif -%}
|
||||
{% set seclabels = data.seclabels %}
|
||||
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
|
||||
{% for r in seclabels.deleted %}
|
||||
{{ SECLABLE.UNSET(conn, 'DOMAIN', name, r.provider, o_data.basensp) }}
|
||||
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
{% if 'added' in seclabels and seclabels.added|length > 0 %}
|
||||
{% for r in seclabels.added %}
|
||||
{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
|
||||
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
|
||||
{% for r in seclabels.changed %}
|
||||
{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
|
||||
|
||||
{% endfor -%}
|
||||
{% endif -%}{% if data.description %}
|
||||
|
||||
COMMENT ON DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
IS {{ data.description|qtLiteral }};
|
||||
{% endif -%}{% if data.basensp %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET SCHEMA {{ conn|qtIdent(data.basensp) }};{% endif -%}
|
||||
{% endif -%}
|
@ -0,0 +1,36 @@
|
||||
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||
{% if data %}
|
||||
CREATE DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
AS {{ conn|qtTypeIdent(data.basetype) }}{% if data.typlen %}({{data.typlen}}{% if data.precision %},{{data.precision}}{% endif %}){% endif %}{% if data.collname and data.collname != "pg_catalog.\"default\"" %}
|
||||
|
||||
COLLATE {{ data.collname }}{% endif %}{% if data.typdefault %}
|
||||
|
||||
DEFAULT {{ data.typdefault }}{% endif %}{% if data.typnotnull %}
|
||||
|
||||
NOT NULL{% endif %};
|
||||
|
||||
{% if data.owner %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }} OWNER TO {{ conn|qtIdent(data.owner) }};{% endif %}
|
||||
|
||||
{% if data.constraints %}
|
||||
{% for c in data.constraints %}{% if c.conname and c.consrc %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if not c.convalidated %} NOT VALID{% endif %}{% endif -%};
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
{% if data.description %}
|
||||
COMMENT ON DOMAIN {{ conn|qtIdent(data.basensp, data.name) }}
|
||||
IS '{{ data.description }}';{% endif -%}
|
||||
|
||||
{% if data.seclabels %}
|
||||
{% for r in data.seclabels %}
|
||||
{% if r.security_label and r.provider %}
|
||||
|
||||
|
||||
{{ SECLABLE.SET(conn, 'DOMAIN', data.name, r.provider, r.security_label, data.basensp) }}{% endif -%}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% endif -%}
|
@ -0,0 +1,16 @@
|
||||
{% if scid and doid %}
|
||||
SELECT
|
||||
d.typname as name, bn.nspname as basensp
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
AND
|
||||
d.oid={{doid}}::int;
|
||||
{% endif %}
|
||||
|
||||
{% if name %}
|
||||
DROP DOMAIN {{ conn|qtIdent(basensp, name) }}{% if cascade %} CASCADE{% endif %};
|
||||
{% endif %}
|
@ -0,0 +1,10 @@
|
||||
SELECT --nspname, collname,
|
||||
CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
|
||||
concat(nspname, '."', collname,'"')
|
||||
ELSE '' END AS copy_collation
|
||||
FROM
|
||||
pg_collation c, pg_namespace n
|
||||
WHERE
|
||||
c.collnamespace=n.oid
|
||||
ORDER BY
|
||||
nspname, collname;
|
@ -0,0 +1,15 @@
|
||||
SELECT
|
||||
'DOMAIN' AS objectkind, c.oid as conoid, conname, typname as relname, nspname, description,
|
||||
regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\((.*)\\).*', E'\\1') as consrc, connoinherit, convalidated
|
||||
FROM
|
||||
pg_constraint c
|
||||
JOIN
|
||||
pg_type t ON t.oid=contypid
|
||||
JOIN
|
||||
pg_namespace nl ON nl.oid=typnamespace
|
||||
LEFT OUTER JOIN
|
||||
pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)
|
||||
WHERE
|
||||
contype = 'c' AND contypid = {{doid}}::oid
|
||||
ORDER BY
|
||||
conname;
|
@ -0,0 +1,18 @@
|
||||
{% if doid %}
|
||||
SELECT
|
||||
d.typnamespace as scid
|
||||
FROM
|
||||
pg_type d
|
||||
WHERE
|
||||
d.oid={{ doid }}::oid;
|
||||
{% else %}
|
||||
SELECT
|
||||
d.oid, d.typnamespace
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
bn.nspname = {{ basensp|qtLiteral }}
|
||||
AND d.typname={{ name|qtLiteral }};
|
||||
{% endif %}
|
@ -0,0 +1,13 @@
|
||||
SELECT
|
||||
d.oid, d.typname as name, pg_get_userbyid(d.typowner) as owner,
|
||||
bn.nspname as basensp
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_type b ON b.oid = d.typbasetype
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
ORDER BY
|
||||
d.typname;
|
@ -0,0 +1,34 @@
|
||||
SELECT
|
||||
d.oid, d.typname as name, d.typbasetype, format_type(b.oid,NULL) as basetype, pg_get_userbyid(d.typowner) as owner,
|
||||
c.oid AS colloid, format_type(b.oid, d.typtypmod) AS fulltype,
|
||||
CASE WHEN length(cn.nspname) > 0 AND length(c.collname) > 0 THEN
|
||||
concat(cn.nspname, '."', c.collname,'"')
|
||||
ELSE '' END AS collname,
|
||||
d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,
|
||||
description, (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname=d.typname) > 1 AS domisdup,
|
||||
(SELECT COUNT(1) FROM pg_type t3 WHERE t3.typname=b.typname) > 1 AS baseisdup,
|
||||
(SELECT
|
||||
array_agg(provider || '=' || label)
|
||||
FROM
|
||||
pg_shseclabel sl1
|
||||
WHERE
|
||||
sl1.objoid=d.oid) AS seclabels
|
||||
FROM
|
||||
pg_type d
|
||||
JOIN
|
||||
pg_type b ON b.oid = d.typbasetype
|
||||
JOIN
|
||||
pg_namespace bn ON bn.oid=d.typnamespace
|
||||
LEFT OUTER JOIN
|
||||
pg_description des ON (des.objoid=d.oid AND des.classoid='pg_type'::regclass)
|
||||
LEFT OUTER JOIN
|
||||
pg_collation c ON d.typcollation=c.oid
|
||||
LEFT OUTER JOIN
|
||||
pg_namespace cn ON c.collnamespace=cn.oid
|
||||
WHERE
|
||||
d.typnamespace = {{scid}}::oid
|
||||
{% if doid %}
|
||||
AND d.oid={{doid}}::int
|
||||
{% endif %}
|
||||
ORDER BY
|
||||
d.typname;
|
@ -0,0 +1,80 @@
|
||||
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||
{% if data %}
|
||||
{% set name = o_data.name %}
|
||||
{% if data.name %}
|
||||
{% if data.name != o_data.name %}
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, o_data.name) }}
|
||||
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||
{% set name = data.name %}
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
{% if data.typnotnull and not o_data.typnotnull %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET NOT NULL;
|
||||
{% elif 'typnotnull' in data and not data.typnotnull and o_data.typnotnull%}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP NOT NULL;
|
||||
{% endif -%}{% if data.typdefault %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET DEFAULT {{ data.typdefault }};
|
||||
{% elif data.typdefault == '' and o_data.typdefault %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP DEFAULT;
|
||||
{% endif -%}{% if data.owner %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
OWNER TO {{ conn|qtIdent(data.owner) }};
|
||||
{% endif -%}{% if data.constraints %}
|
||||
{% for c in data.constraints.deleted %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
DROP CONSTRAINT {{ conn|qtIdent(o_data['constraints'][c.conoid]['conname']) }};
|
||||
{% endfor -%}
|
||||
{% for c in data.constraints.changed %}
|
||||
{% if c.conname and c.conname !=o_data['constraints'][c.conoid]['conname'] %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
RENAME CONSTRAINT {{ conn|qtIdent(o_data['constraints'][c.conoid]['conname']) }} TO {{ conn|qtIdent(c.conname) }};
|
||||
{% endif %}
|
||||
{% if c.convalidated and not o_data['constraints'][c.conoid]['convalidated'] %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
VALIDATE CONSTRAINT {{ conn|qtIdent(c.conname) }};
|
||||
{% endif %}
|
||||
{% endfor -%}
|
||||
{% for c in data.constraints.added %}
|
||||
{% if c.conname and c.consrc %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
ADD CONSTRAINT {{ conn|qtIdent(c.conname) }} CHECK ({{ c.consrc }}){% if not c.convalidated %} NOT VALID{% endif %}{% if c.connoinherit %} NO INHERIT{% endif -%};{% endif -%}
|
||||
{% endfor -%}{% endif -%}
|
||||
{% set seclabels = data.seclabels %}
|
||||
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
|
||||
{% for r in seclabels.deleted %}
|
||||
{{ SECLABLE.UNSET(conn, 'DOMAIN', name, r.provider, o_data.basensp) }}
|
||||
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
{% if 'added' in seclabels and seclabels.added|length > 0 %}
|
||||
{% for r in seclabels.added %}
|
||||
|
||||
{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
|
||||
{% endfor %}
|
||||
{% endif -%}{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
|
||||
{% for r in seclabels.changed %}
|
||||
|
||||
{{ SECLABLE.SET(conn, 'DOMAIN', name, r.provider, r.security_label, o_data.basensp) }}
|
||||
{% endfor %}
|
||||
{% endif -%}{% if data.description %}
|
||||
|
||||
COMMENT ON DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
IS {{ data.description|qtLiteral }};
|
||||
{% endif -%}{% if data.basensp %}
|
||||
|
||||
ALTER DOMAIN {{ conn|qtIdent(o_data.basensp, name) }}
|
||||
SET SCHEMA {{ conn|qtIdent(data.basensp) }};{% endif -%}
|
||||
{% endif -%}
|
Loading…
Reference in New Issue
Block a user