mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add support for Sequences.
This commit is contained in:
committed by
Dave Page
parent
986375d60e
commit
def1a30251
@@ -0,0 +1,692 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
"""Implements Sequence Node"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from flask import render_template, make_response, request, jsonify
|
||||||
|
from flask.ext.babel import gettext as _
|
||||||
|
from pgadmin.utils.ajax import make_json_response, \
|
||||||
|
make_response as ajax_response, internal_server_error
|
||||||
|
from pgadmin.browser.utils import PGChildNodeView
|
||||||
|
from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
|
||||||
|
parse_priv_to_db
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
|
||||||
|
import SchemaChildModule
|
||||||
|
import pgadmin.browser.server_groups.servers.databases as database
|
||||||
|
from pgadmin.utils.ajax import precondition_required
|
||||||
|
from pgadmin.utils.driver import get_driver
|
||||||
|
from config import PG_DEFAULT_DRIVER
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
class SequenceModule(SchemaChildModule):
|
||||||
|
"""
|
||||||
|
class SequenceModule(CollectionNodeModule)
|
||||||
|
|
||||||
|
A module class for Sequence node derived from CollectionNodeModule.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
-------
|
||||||
|
* __init__(*args, **kwargs)
|
||||||
|
- Method is used to initialize the SequenceModule and it's base module.
|
||||||
|
|
||||||
|
* get_nodes(gid, sid, did)
|
||||||
|
- Method is used to generate the browser collection node.
|
||||||
|
|
||||||
|
* script_load()
|
||||||
|
- Load the module script for sequence, when any of the database node is
|
||||||
|
initialized.
|
||||||
|
|
||||||
|
* node_inode()
|
||||||
|
- Method is overridden from its base class to make the node as leaf node.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
NODE_TYPE = 'sequence'
|
||||||
|
COLLECTION_LABEL = _("Sequences")
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(SequenceModule, self).__init__(*args, **kwargs)
|
||||||
|
self.min_ver = None
|
||||||
|
self.max_ver = None
|
||||||
|
|
||||||
|
def get_nodes(self, gid, sid, did, scid):
|
||||||
|
"""
|
||||||
|
Generate the sequence node
|
||||||
|
"""
|
||||||
|
yield self.generate_browser_collection_node(scid)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def script_load(self):
|
||||||
|
"""
|
||||||
|
Load the module script for database, when any of the database node is
|
||||||
|
initialized.
|
||||||
|
"""
|
||||||
|
return database.DatabaseModule.NODE_TYPE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_inode(self):
|
||||||
|
"""
|
||||||
|
Override this property to make the node a leaf node.
|
||||||
|
|
||||||
|
Returns: False as this is the leaf node
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
blueprint = SequenceModule(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SequenceView(PGChildNodeView):
|
||||||
|
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': 'seid'}
|
||||||
|
]
|
||||||
|
|
||||||
|
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 module_js(self):
|
||||||
|
"""
|
||||||
|
This property defines whether javascript exists for this node.
|
||||||
|
"""
|
||||||
|
return make_response(
|
||||||
|
render_template(
|
||||||
|
"sequence/js/sequence.js",
|
||||||
|
_=_
|
||||||
|
),
|
||||||
|
200, {'Content-Type': 'application/x-javascript'}
|
||||||
|
)
|
||||||
|
|
||||||
|
def check_precondition(action=None):
|
||||||
|
"""
|
||||||
|
This function will behave as a decorator which will checks
|
||||||
|
database connection before running view, it will also attaches
|
||||||
|
manager,conn & template_path properties to self
|
||||||
|
"""
|
||||||
|
def wrap(f):
|
||||||
|
@wraps(f)
|
||||||
|
def wrapped(self, *args, **kwargs):
|
||||||
|
|
||||||
|
self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
|
||||||
|
if action and action in ["drop"]:
|
||||||
|
self.conn = self.manager.connection()
|
||||||
|
elif 'did' in kwargs:
|
||||||
|
self.conn = self.manager.connection(did=kwargs['did'])
|
||||||
|
else:
|
||||||
|
self.conn = self.manager.connection()
|
||||||
|
# If DB not connected then return error to browser
|
||||||
|
if not self.conn.connected():
|
||||||
|
return precondition_required(
|
||||||
|
_(
|
||||||
|
"Connection to the server has been lost!"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.template_path = 'sequence/sql/9.1_plus'
|
||||||
|
|
||||||
|
return f(self, *args, **kwargs)
|
||||||
|
return wrapped
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
@check_precondition(action='list')
|
||||||
|
def list(self, gid, sid, did, scid):
|
||||||
|
"""
|
||||||
|
This function is used to list all the sequence nodes within the collection.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
SQL = render_template("/".join([self.template_path, 'properties.sql']), scid=scid)
|
||||||
|
status, res = self.conn.execute_dict(SQL)
|
||||||
|
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
return ajax_response(
|
||||||
|
response=res['rows'],
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition(action='nodes')
|
||||||
|
def nodes(self, gid, sid, did, scid):
|
||||||
|
"""
|
||||||
|
This function is used to create all the child nodes within the collection.
|
||||||
|
Here it will create all the sequence nodes.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
SQL = render_template("/".join([self.template_path, 'nodes.sql']), scid=scid)
|
||||||
|
status, rset = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset)
|
||||||
|
|
||||||
|
for row in rset['rows']:
|
||||||
|
res.append(
|
||||||
|
self.blueprint.generate_browser_node(
|
||||||
|
row['oid'],
|
||||||
|
sid,
|
||||||
|
row['name'],
|
||||||
|
icon="icon-%s" % self.node_type
|
||||||
|
))
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
data=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition(action='properties')
|
||||||
|
def properties(self, gid, sid, did, scid, seid):
|
||||||
|
"""
|
||||||
|
This function will show the properties of the selected sequence node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
SQL = render_template("/".join([self.template_path, 'properties.sql']), scid=scid, seid=seid)
|
||||||
|
status, res = self.conn.execute_dict(SQL)
|
||||||
|
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
sec_lbls = []
|
||||||
|
if 'securities' in res and res['securities'] is not None:
|
||||||
|
for sec in res['seclabels']:
|
||||||
|
sec = re.search(r'([^=]+)=(.*$)', sec)
|
||||||
|
sec_lbls.append({
|
||||||
|
'provider': sec.group(1),
|
||||||
|
'security_label': sec.group(2)
|
||||||
|
})
|
||||||
|
res['securities'] = sec_lbls
|
||||||
|
|
||||||
|
for row in res['rows']:
|
||||||
|
SQL = render_template("/".join([self.template_path, 'get_def.sql']), data=row)
|
||||||
|
status, rset1 = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset1)
|
||||||
|
|
||||||
|
row['current_value'] = rset1['rows'][0]['last_value']
|
||||||
|
row['minimum'] = rset1['rows'][0]['min_value']
|
||||||
|
row['maximum'] = rset1['rows'][0]['max_value']
|
||||||
|
row['increment'] = rset1['rows'][0]['increment_by']
|
||||||
|
row['cache'] = rset1['rows'][0]['cache_value']
|
||||||
|
row['cycled'] = rset1['rows'][0]['is_cycled']
|
||||||
|
|
||||||
|
SQL = render_template("/".join([self.template_path, 'acl.sql']), scid=scid, seid=seid)
|
||||||
|
status, dataclres = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
for row in dataclres['rows']:
|
||||||
|
priv = parse_priv_from_db(row)
|
||||||
|
if row['deftype'] in res['rows'][0]:
|
||||||
|
res['rows'][0][row['deftype']].append(priv)
|
||||||
|
else:
|
||||||
|
res['rows'][0][row['deftype']] = [priv]
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=res['rows'][0],
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition(action="create")
|
||||||
|
def create(self, gid, sid, did, scid):
|
||||||
|
"""
|
||||||
|
Create the sequence.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
required_args = [
|
||||||
|
u'name',
|
||||||
|
u'schema',
|
||||||
|
u'seqowner',
|
||||||
|
]
|
||||||
|
|
||||||
|
data = request.form if request.form else json.loads(request.data.decode())
|
||||||
|
|
||||||
|
for arg in required_args:
|
||||||
|
if arg not in data:
|
||||||
|
return make_json_response(
|
||||||
|
status=400,
|
||||||
|
success=0,
|
||||||
|
errormsg=_(
|
||||||
|
"Couldn't find the required parameter (%s)." % arg
|
||||||
|
)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
# The SQL below will execute CREATE DDL only
|
||||||
|
SQL = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
|
||||||
|
status, msg = self.conn.execute_scalar(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=msg)
|
||||||
|
|
||||||
|
if 'relacl' in data:
|
||||||
|
data['relacl'] = parse_priv_to_db(data['relacl'], 'DATABASE')
|
||||||
|
|
||||||
|
# The SQL below will execute rest DMLs because we can not execute CREATE with any other
|
||||||
|
SQL = render_template("/".join([self.template_path, 'grant.sql']), data=data, conn=self.conn)
|
||||||
|
SQL = SQL.strip('\n').strip(' ')
|
||||||
|
if SQL and SQL != "":
|
||||||
|
status, msg = self.conn.execute_scalar(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=msg)
|
||||||
|
|
||||||
|
# We need oid of newly created sequence.
|
||||||
|
SQL = render_template("/".join([self.template_path, 'get_oid.sql']), name=data['name'], scid=scid)
|
||||||
|
SQL = SQL.strip('\n').strip(' ')
|
||||||
|
if SQL and SQL != "":
|
||||||
|
status, seid = self.conn.execute_scalar(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
node=self.blueprint.generate_browser_node(
|
||||||
|
seid,
|
||||||
|
scid,
|
||||||
|
data['name'],
|
||||||
|
icon="icon-%s" % self.node_type
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return make_json_response(
|
||||||
|
status=500,
|
||||||
|
success=0,
|
||||||
|
errormsg=str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition(action='delete')
|
||||||
|
def delete(self, gid, sid, did, scid, seid):
|
||||||
|
"""
|
||||||
|
This function will drop the object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Below will decide if it's simple drop or drop with cascade call
|
||||||
|
if self.cmd == 'delete':
|
||||||
|
# This is a cascade operation
|
||||||
|
cascade = True
|
||||||
|
else:
|
||||||
|
cascade = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
SQL = render_template("/".join([self.template_path, 'properties.sql']), scid=scid, seid=seid)
|
||||||
|
status, res = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
SQL = render_template("/".join([self.template_path, 'delete.sql']), data=res['rows'][0], 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=_("Sequence dropped"),
|
||||||
|
data={
|
||||||
|
'id': seid,
|
||||||
|
'scid': scid,
|
||||||
|
'sid': sid,
|
||||||
|
'gid': gid,
|
||||||
|
'did': did
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
@check_precondition(action='update')
|
||||||
|
def update(self, gid, sid, did, scid, seid):
|
||||||
|
"""
|
||||||
|
This function will update the object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = request.form if request.form else json.loads(request.data.decode())
|
||||||
|
try:
|
||||||
|
SQL = self.getSQL(gid, sid, did, data, scid, seid)
|
||||||
|
SQL = SQL.strip('\n').strip(' ')
|
||||||
|
if SQL != "":
|
||||||
|
status, res = self.conn.execute_scalar(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
success=1,
|
||||||
|
info="Sequence updated",
|
||||||
|
data={
|
||||||
|
'id': seid,
|
||||||
|
'scid': scid,
|
||||||
|
'sid': sid,
|
||||||
|
'gid': gid,
|
||||||
|
'did': did
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return make_json_response(
|
||||||
|
success=1,
|
||||||
|
info="Nothing to update",
|
||||||
|
data={
|
||||||
|
'id': seid,
|
||||||
|
'scid': scid,
|
||||||
|
'sid': sid,
|
||||||
|
'gid': gid,
|
||||||
|
'did': did
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
@check_precondition(action='msql')
|
||||||
|
def msql(self, gid, sid, did, scid, seid=None):
|
||||||
|
"""
|
||||||
|
This function to return modified SQL.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
for k, v in request.args.items():
|
||||||
|
try:
|
||||||
|
data[k] = json.loads(v)
|
||||||
|
except ValueError:
|
||||||
|
data[k] = v
|
||||||
|
|
||||||
|
if seid is None:
|
||||||
|
required_args = [
|
||||||
|
'name',
|
||||||
|
'schema'
|
||||||
|
]
|
||||||
|
|
||||||
|
for arg in required_args:
|
||||||
|
if arg not in data:
|
||||||
|
return make_json_response(
|
||||||
|
status=400,
|
||||||
|
success=0,
|
||||||
|
errormsg=_(
|
||||||
|
"Couldn't find the required parameter (%s)." % arg
|
||||||
|
)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
SQL = self.getSQL(gid, sid, did, data, scid, seid)
|
||||||
|
SQL = SQL.strip('\n').strip(' ')
|
||||||
|
return make_json_response(
|
||||||
|
data=SQL,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return make_json_response(
|
||||||
|
data="-- modified SQL",
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
def getSQL(self, gid, sid, did, data, scid, seid=None):
|
||||||
|
"""
|
||||||
|
This function will generate sql from model data.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
"""
|
||||||
|
|
||||||
|
required_args = [
|
||||||
|
u'name'
|
||||||
|
]
|
||||||
|
|
||||||
|
if seid is not None:
|
||||||
|
SQL = render_template("/".join([self.template_path, 'properties.sql']), scid=scid, seid=seid)
|
||||||
|
status, res = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
# Making copy of output for further processing
|
||||||
|
old_data = dict(res['rows'][0])
|
||||||
|
old_data = self._formatter(old_data, scid, seid)
|
||||||
|
|
||||||
|
# To format privileges data coming from client
|
||||||
|
for key in ['relacl']:
|
||||||
|
if key in data and data[key] is not None:
|
||||||
|
if 'added' in data[key]:
|
||||||
|
data[key]['added'] = parse_priv_to_db(data[key]['added'], 'SEQUENCE')
|
||||||
|
if 'changed' in data[key]:
|
||||||
|
data[key]['changed'] = parse_priv_to_db(data[key]['changed'], 'SEQUENCE')
|
||||||
|
if 'deleted' in data[key]:
|
||||||
|
data[key]['deleted'] = parse_priv_to_db(data[key]['deleted'], 'SEQUENCE')
|
||||||
|
|
||||||
|
# If name is not present with in update data then copy it
|
||||||
|
# from old data
|
||||||
|
for arg in required_args:
|
||||||
|
if arg not in data:
|
||||||
|
data[arg] = old_data[arg]
|
||||||
|
SQL = render_template("/".join([self.template_path, 'update.sql']),
|
||||||
|
data=data, o_data=old_data, conn=self.conn)
|
||||||
|
else:
|
||||||
|
# To format privileges coming from client
|
||||||
|
if 'relacl' in data:
|
||||||
|
data['relacl'] = parse_priv_to_db(data['relacl'], 'SEQUENCE')
|
||||||
|
|
||||||
|
SQL = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
|
||||||
|
SQL += render_template("/".join([self.template_path, 'grant.sql']), data=data, conn=self.conn)
|
||||||
|
return SQL
|
||||||
|
|
||||||
|
@check_precondition(action="sql")
|
||||||
|
def sql(self, gid, sid, did, scid, seid):
|
||||||
|
"""
|
||||||
|
This function will generate sql for sql panel
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL = render_template("/".join([self.template_path, 'properties.sql']), scid=scid, seid=seid)
|
||||||
|
status, res = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
for row in res['rows']:
|
||||||
|
SQL = render_template("/".join([self.template_path, 'get_def.sql']), data=row)
|
||||||
|
status, rset1 = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset1)
|
||||||
|
|
||||||
|
row['current_value'] = rset1['rows'][0]['last_value']
|
||||||
|
row['minimum'] = rset1['rows'][0]['min_value']
|
||||||
|
row['maximum'] = rset1['rows'][0]['max_value']
|
||||||
|
row['increment'] = rset1['rows'][0]['increment_by']
|
||||||
|
row['cache'] = rset1['rows'][0]['cache_value']
|
||||||
|
row['cycled'] = rset1['rows'][0]['is_cycled']
|
||||||
|
|
||||||
|
result = res['rows'][0]
|
||||||
|
result = self._formatter(result, scid, seid)
|
||||||
|
SQL = self.getSQL(gid, sid, did, result, scid)
|
||||||
|
SQL = SQL.strip('\n').strip(' ')
|
||||||
|
return ajax_response(response=SQL)
|
||||||
|
|
||||||
|
def _formatter(self, data, scid, seid):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
data: dict of query result
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
It will return formatted output of sequence
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Need to format security labels according to client js collection
|
||||||
|
if 'securities' in data and data['securities'] is not None:
|
||||||
|
seclabels = []
|
||||||
|
for seclbls in data['securities']:
|
||||||
|
k, v = seclbls.split('=')
|
||||||
|
seclabels.append({'provider': k, 'security_label': v})
|
||||||
|
|
||||||
|
data['securities'] = seclabels
|
||||||
|
|
||||||
|
# We need to parse & convert ACL coming from database to json format
|
||||||
|
SQL = render_template("/".join([self.template_path, 'acl.sql']),
|
||||||
|
scid=scid, seid=seid)
|
||||||
|
status, acl = self.conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=acl)
|
||||||
|
|
||||||
|
# We will set get privileges from acl sql so we don't need
|
||||||
|
# it from properties sql
|
||||||
|
data['relacl'] = []
|
||||||
|
|
||||||
|
for row in acl['rows']:
|
||||||
|
priv = parse_priv_from_db(row)
|
||||||
|
data.setdefault(row['deftype'], []).append(priv)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@check_precondition(action="dependents")
|
||||||
|
def dependents(self, gid, sid, did, scid, seid):
|
||||||
|
"""
|
||||||
|
This function gets the dependents and returns an ajax response
|
||||||
|
for the sequence node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
"""
|
||||||
|
dependents_result = self.get_dependents(self.conn, seid)
|
||||||
|
return ajax_response(
|
||||||
|
response=dependents_result,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition(action="dependencies")
|
||||||
|
def dependencies(self, gid, sid, did, scid, seid):
|
||||||
|
"""
|
||||||
|
This function gets the dependencies and returns an ajax response
|
||||||
|
for the sequence node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
scid: Schema ID
|
||||||
|
seid: Sequence ID
|
||||||
|
"""
|
||||||
|
dependencies_result = self.get_dependencies(self.conn, seid)
|
||||||
|
|
||||||
|
# Get missing dependencies.
|
||||||
|
# A Corner case, reported by Guillaume Lelarge, could be found at:
|
||||||
|
# http://archives.postgresql.org/pgadmin-hackers/2009-03/msg00026.php
|
||||||
|
|
||||||
|
sql = render_template("/".join([self.template_path,
|
||||||
|
'get_dependencies.sql']), seid=seid)
|
||||||
|
|
||||||
|
status, result = self.conn.execute_dict(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=result)
|
||||||
|
|
||||||
|
for row in result['rows']:
|
||||||
|
ref_name = row['refname']
|
||||||
|
if ref_name is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
dep_type = ''
|
||||||
|
dep_str = row['deptype']
|
||||||
|
if dep_str == 'a':
|
||||||
|
dep_type = 'auto'
|
||||||
|
elif dep_str == 'n':
|
||||||
|
dep_type = 'normal'
|
||||||
|
elif dep_str == 'i':
|
||||||
|
dep_type = 'internal'
|
||||||
|
|
||||||
|
dependencies_result.append({'type': 'column',
|
||||||
|
'name': ref_name,
|
||||||
|
'field': dep_type})
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=dependencies_result,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SequenceView.register_node_view(blueprint)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 359 B |
Binary file not shown.
|
After Width: | Height: | Size: 405 B |
@@ -0,0 +1,249 @@
|
|||||||
|
define(
|
||||||
|
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
|
||||||
|
function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||||
|
|
||||||
|
// Extend the browser's node model class to create a security model
|
||||||
|
var SecurityModel = pgAdmin.Browser.Node.Model.extend({
|
||||||
|
defaults: {
|
||||||
|
provider: undefined,
|
||||||
|
securitylabel: undefined
|
||||||
|
},
|
||||||
|
// Define the schema for the Security Label
|
||||||
|
schema: [{
|
||||||
|
id: 'provider', label: '{{ _('Provider') }}',
|
||||||
|
type: 'text', editable: true
|
||||||
|
},{
|
||||||
|
id: 'security_label', label: '{{ _('Security Label') }}',
|
||||||
|
type: 'text', editable: true
|
||||||
|
}],
|
||||||
|
/* validate function is used to validate the input given by
|
||||||
|
* the user. In case of error, message will be displayed on
|
||||||
|
* the GUI for the respective control.
|
||||||
|
*/
|
||||||
|
validate: function() {
|
||||||
|
var err = {},
|
||||||
|
errmsg = null,
|
||||||
|
data = this.toJSON();
|
||||||
|
|
||||||
|
if (_.isUndefined(data.label) ||
|
||||||
|
_.isNull(data.label) ||
|
||||||
|
String(data.label).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
|
return _("Please specify the value for all the security providers.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extend the browser's collection class for sequence collection
|
||||||
|
if (!pgBrowser.Nodes['coll-sequence']) {
|
||||||
|
var databases = pgAdmin.Browser.Nodes['coll-sequence'] =
|
||||||
|
pgAdmin.Browser.Collection.extend({
|
||||||
|
node: 'sequence',
|
||||||
|
label: '{{ _('Sequences') }}',
|
||||||
|
type: 'coll-sequence',
|
||||||
|
columns: ['oid', 'name', 'seqowner', 'comment']
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extend the browser's node class for sequence node
|
||||||
|
if (!pgBrowser.Nodes['sequence']) {
|
||||||
|
pgAdmin.Browser.Nodes['sequence'] = pgBrowser.Node.extend({
|
||||||
|
type: 'sequence',
|
||||||
|
label: '{{ _('Sequence') }}',
|
||||||
|
collection_type: 'coll-sequence',
|
||||||
|
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_sequence_on_coll', node: 'coll-sequence', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
|
category: 'create', priority: 4, label: '{{ _('Sequence...') }}',
|
||||||
|
icon: 'wcTabIcon icon-sequence', data: {action: 'create', check: true},
|
||||||
|
enable: 'canCreate'
|
||||||
|
},{
|
||||||
|
name: 'create_sequence', node: 'sequence', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
|
category: 'create', priority: 4, label: '{{ _('Sequence...') }}',
|
||||||
|
icon: 'wcTabIcon icon-sequence', data: {action: 'create', check: true},
|
||||||
|
enable: 'canCreate'
|
||||||
|
},{
|
||||||
|
name: 'create_sequence', node: 'schema', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
|
category: 'create', priority: 4, label: '{{ _('Sequence...') }}',
|
||||||
|
icon: 'wcTabIcon icon-sequence', data: {action: 'create', check: false},
|
||||||
|
enable: 'canCreate'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
},
|
||||||
|
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||||
|
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||||
|
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 collation
|
||||||
|
if (_.indexOf(['schema'], d._type) > -1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ('coll-sequence' == 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 want to allow create menu
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
// Define the model for sequence node.
|
||||||
|
model: pgAdmin.Browser.Node.Model.extend({
|
||||||
|
defaults: {
|
||||||
|
name: undefined,
|
||||||
|
oid: undefined,
|
||||||
|
seqowner: undefined,
|
||||||
|
schema: undefined,
|
||||||
|
comment: undefined,
|
||||||
|
increment: undefined,
|
||||||
|
start: undefined,
|
||||||
|
current_value: undefined,
|
||||||
|
minimum: undefined,
|
||||||
|
maximum: undefined,
|
||||||
|
cache: undefined,
|
||||||
|
cycled: undefined,
|
||||||
|
relacl: [],
|
||||||
|
securities: []
|
||||||
|
},
|
||||||
|
|
||||||
|
// Default values!
|
||||||
|
initialize: function(attrs, args) {
|
||||||
|
var isNew = (_.size(attrs) === 0);
|
||||||
|
|
||||||
|
if (isNew) {
|
||||||
|
var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
|
||||||
|
var schemaInfo = args.node_info.schema;
|
||||||
|
|
||||||
|
this.set({'seqowner': userInfo.name}, {silent: true});
|
||||||
|
this.set({'schema': schemaInfo.label}, {silent: true});
|
||||||
|
}
|
||||||
|
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Define the schema for sequence node.
|
||||||
|
schema: [{
|
||||||
|
id: 'name', label: '{{ _('Name') }}', cell: 'string',
|
||||||
|
type: 'text', mode: ['properties', 'create', 'edit']
|
||||||
|
},{
|
||||||
|
id: 'oid', label:'{{ _('Oid') }}', cell: 'string',
|
||||||
|
type: 'text' , mode: ['properties']
|
||||||
|
},{
|
||||||
|
id: 'seqowner', label:'{{ _('Owner') }}', cell: 'string',
|
||||||
|
type: 'text', mode: ['properties', 'create', 'edit'], node: 'role',
|
||||||
|
control: Backform.NodeListByNameControl
|
||||||
|
},{
|
||||||
|
id: 'schema', label:'{{ _('Schema') }}', cell: 'string',
|
||||||
|
control: 'node-list-by-name', node: 'schema',
|
||||||
|
type: 'text', mode: ['create', 'edit'], filter: function(d) {
|
||||||
|
// If schema name start with pg_* then we need to exclude them
|
||||||
|
if(d && d.label.match(/^pg_/))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
id: 'comment', label:'{{ _('Comment') }}', type: 'multiline',
|
||||||
|
mode: ['properties', 'create', 'edit']
|
||||||
|
},{
|
||||||
|
id: 'increment', label: '{{ _('Increment') }}', type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'start', label: '{{ _('Start') }}', type: 'int',
|
||||||
|
mode: ['create'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'current_value', label: '{{ _('Current value') }}', type: 'int',
|
||||||
|
mode: ['properties', 'edit'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'minimum', label: '{{ _('Minimum') }}', type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'maximum', label: '{{ _('Maximum') }}', type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'cache', label: '{{ _('Cache') }}', type: 'int',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'cycled', label: '{{ _('Cycled') }}', type: 'switch',
|
||||||
|
mode: ['properties', 'create', 'edit'], group: '{{ _('Definition') }}'
|
||||||
|
},{
|
||||||
|
id: 'acl', label: '{{ _('Privileges') }}', type: 'text',
|
||||||
|
mode: ['properties'], disabled: true
|
||||||
|
},{
|
||||||
|
id: 'relacl', label: '{{ _('Privileges') }}', model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
|
||||||
|
{privileges: ['r', 'w', 'U']}), uniqueCol : ['grantee', 'grantor'],
|
||||||
|
editable: false, type: 'collection', group: '{{ _('Security') }}', mode: ['edit', 'create'],
|
||||||
|
canAdd: true, canDelete: true, control: 'unique-col-collection',
|
||||||
|
},{
|
||||||
|
id: 'securities', label: '{{ _('Securitiy Labels') }}', model: SecurityModel,
|
||||||
|
editable: false, type: 'collection', canEdit: false,
|
||||||
|
group: '{{ _('Security') }}', canDelete: true,
|
||||||
|
mode: ['edit', 'create'], canAdd: true,
|
||||||
|
control: 'unique-col-collection', uniqueCol : ['provider'],
|
||||||
|
min_version: 90200
|
||||||
|
}],
|
||||||
|
/* validate function is used to validate the input given by
|
||||||
|
* the user. In case of error, message will be displayed on
|
||||||
|
* the GUI for the respective control.
|
||||||
|
*/
|
||||||
|
validate: function() {
|
||||||
|
var msg = undefined;
|
||||||
|
// Clear any existing error msg.
|
||||||
|
this.errorModel.unset('name');
|
||||||
|
this.errorModel.unset('seqowner');
|
||||||
|
this.errorModel.unset('schema');
|
||||||
|
|
||||||
|
if (_.isUndefined(this.get('name'))
|
||||||
|
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
|
msg = '{{ _('Sequence name can not be empty!') }}';
|
||||||
|
this.errorModel.set('name', msg);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isUndefined(this.get('seqowner'))
|
||||||
|
|| String(this.get('seqowner')).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
|
msg = '{{ _('Sequence owner can not be empty!') }}';
|
||||||
|
this.errorModel.set('seqowner', msg);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isUndefined(this.get('schema'))
|
||||||
|
|| String(this.get('schema')).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
|
msg = '{{ _('Sequence schema can not be empty!') }}';
|
||||||
|
this.errorModel.set('schema', msg);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pgBrowser.Nodes['sequence'];
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
SELECT 'relacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
|
||||||
|
FROM
|
||||||
|
(SELECT
|
||||||
|
d.grantee, d.grantor, d.is_grantable,
|
||||||
|
CASE d.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
|
||||||
|
FROM
|
||||||
|
(SELECT relacl
|
||||||
|
FROM pg_class cl
|
||||||
|
LEFT OUTER JOIN pg_description des ON (des.objoid=cl.oid AND des.classoid='pg_class'::regclass)
|
||||||
|
WHERE relkind = 'S' AND relnamespace = {{scid}}::oid
|
||||||
|
AND cl.oid = {{seid}}::oid ) acl,
|
||||||
|
aclexplode(relacl) d
|
||||||
|
) d
|
||||||
|
LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
|
||||||
|
LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
|
||||||
|
GROUP BY g.rolname, gt.rolname
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
SELECT
|
||||||
|
CASE WHEN nsp.nspname IN ('sys', 'dbo', 'information_schema') THEN true ELSE false END AS dbSupport
|
||||||
|
FROM pg_namespace nsp
|
||||||
|
WHERE nsp.oid={{scid}}::int AND (
|
||||||
|
(nspname = 'pg_catalog' AND EXISTS
|
||||||
|
(SELECT 1 FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid LIMIT 1))
|
||||||
|
OR (nspname = 'pgagent' AND EXISTS
|
||||||
|
(SELECT 1 FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid LIMIT 1))
|
||||||
|
OR (nspname = 'information_schema' AND EXISTS
|
||||||
|
(SELECT 1 FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid LIMIT 1))
|
||||||
|
OR (nspname LIKE '_%' AND EXISTS
|
||||||
|
(SELECT 1 FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid LIMIT 1))
|
||||||
|
) AND
|
||||||
|
nspname NOT LIKE E'pg\\temp\\%' AND
|
||||||
|
nspname NOT LIKE E'pg\\toast_temp\\%'
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{% if data %}
|
||||||
|
CREATE SEQUENCE {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.name) }}
|
||||||
|
{% if data.cycled and data.cycled == True %}
|
||||||
|
CYCLE
|
||||||
|
{% endif %}
|
||||||
|
{% if data.increment %}
|
||||||
|
INCREMENT {{data.increment}}
|
||||||
|
{% endif %}{% if data.start %}
|
||||||
|
START {{data.start}}
|
||||||
|
{% endif %}{% if data.minimum %}
|
||||||
|
MINVALUE {{data.minimum}}
|
||||||
|
{% endif %}{% if data.maximum %}
|
||||||
|
MAXVALUE {{data.maximum}}
|
||||||
|
{% endif %}{% if data.cache %}
|
||||||
|
CACHE {{data.cache}}{% endif %};
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP SEQUENCE {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.name) }}{% if cascade%} CASCADE{% endif %};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
SELECT
|
||||||
|
last_value,
|
||||||
|
min_value,
|
||||||
|
max_value,
|
||||||
|
cache_value,
|
||||||
|
is_cycled,
|
||||||
|
increment_by,
|
||||||
|
is_called
|
||||||
|
FROM {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.name) }}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
SELECT
|
||||||
|
CASE WHEN att.attname IS NOT NULL AND ref.relname IS NOT NULL THEN ref.relname || '.' || att.attname
|
||||||
|
ELSE ref.relname
|
||||||
|
END AS refname,
|
||||||
|
d2.refclassid, d1.deptype AS deptype
|
||||||
|
FROM pg_depend d1
|
||||||
|
LEFT JOIN pg_depend d2 ON d1.objid=d2.objid AND d1.refobjid != d2.refobjid
|
||||||
|
LEFT JOIN pg_class ref ON ref.oid = d2.refobjid
|
||||||
|
LEFT JOIN pg_attribute att ON d2.refobjid=att.attrelid AND d2.refobjsubid=att.attnum
|
||||||
|
WHERE d1.classid=(SELECT oid FROM pg_class WHERE relname='pg_attrdef')
|
||||||
|
AND d2.refobjid NOT IN (SELECT d3.refobjid FROM pg_depend d3 WHERE d3.objid=d1.refobjid)
|
||||||
|
AND d1.refobjid={{seid}}::oid
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
SELECT cl.oid as oid
|
||||||
|
FROM pg_class cl
|
||||||
|
LEFT OUTER JOIN pg_description des ON (des.objoid=cl.oid AND des.classoid='pg_class'::regclass)
|
||||||
|
WHERE relkind = 'S' AND relnamespace = {{scid}}::oid
|
||||||
|
AND relname = {{ name|qtLiteral }}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||||
|
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
|
||||||
|
{# Construct sequence name from name and schema #}
|
||||||
|
{% set seqname=conn|qtIdent(data.schema, data.name) %}
|
||||||
|
{% if data.seqowner %}
|
||||||
|
|
||||||
|
ALTER SEQUENCE {{ seqname }}
|
||||||
|
OWNER TO {{ conn|qtIdent(data.seqowner) }};
|
||||||
|
{% endif %}
|
||||||
|
{% if data.comment %}
|
||||||
|
|
||||||
|
COMMENT ON SEQUENCE {{ seqname }}
|
||||||
|
IS {{ data.comment|qtLiteral }};
|
||||||
|
{% endif %}
|
||||||
|
{% if data.securities %}
|
||||||
|
|
||||||
|
{% for r in data.securities %}
|
||||||
|
{{ SECLABLE.SET(conn, 'SEQUENCE', data.name, r.provider, r.security_label, data.schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.relacl %}
|
||||||
|
|
||||||
|
{% for priv in data.relacl %}
|
||||||
|
{{ PRIVILEGE.SET(conn, 'SEQUENCE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
SELECT cl.oid as oid, relname as name
|
||||||
|
FROM pg_class cl
|
||||||
|
WHERE relkind = 'S' AND relnamespace = {{scid}}::oid
|
||||||
|
ORDER BY relname
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{% if scid %}
|
||||||
|
SELECT
|
||||||
|
cl.oid as oid,
|
||||||
|
relname as name,
|
||||||
|
nsp.nspname as schema,
|
||||||
|
pg_get_userbyid(relowner) AS seqowner,
|
||||||
|
description as comment,
|
||||||
|
array_to_string(relacl::text[], ', ') as acl,
|
||||||
|
(SELECT array_agg(provider || '=' || label) FROM pg_shseclabel sl1 WHERE sl1.objoid=cl.oid) AS securities
|
||||||
|
FROM pg_class cl
|
||||||
|
LEFT OUTER JOIN pg_namespace nsp ON cl.relnamespace = nsp.oid
|
||||||
|
LEFT OUTER JOIN pg_description des ON (des.objoid=cl.oid
|
||||||
|
AND des.classoid='pg_class'::regclass)
|
||||||
|
WHERE relkind = 'S' AND relnamespace = {{scid}}::oid
|
||||||
|
{% if seid %}AND cl.oid = {{seid}}::oid {% endif %}
|
||||||
|
ORDER BY relname
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
{% import 'macros/schemas/security.macros' as SECLABLE %}
|
||||||
|
{% import 'macros/schemas/privilege.macros' as PRIVILEGE %}
|
||||||
|
{% if data %}
|
||||||
|
{% if data.name != o_data.name %}
|
||||||
|
ALTER SEQUENCE {{ conn|qtIdent(o_data.schema, o_data.name) }}
|
||||||
|
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if data.seqowner and data.seqowner != o_data.seqowner %}
|
||||||
|
ALTER SEQUENCE {{ conn|qtIdent(o_data.schema, data.name) }}
|
||||||
|
OWNER TO {{ conn|qtIdent(data.seqowner) }};
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if data.current_value %}
|
||||||
|
{% set seqname = conn|qtIdent(o_data.schema, data.name) %}
|
||||||
|
SELECT setval({{ seqname|qtLiteral }}, {{ data.current_value }}, true);
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% set defquery = '' %}
|
||||||
|
{% if data.increment %}
|
||||||
|
{% set defquery = defquery+'\n INCREMENT '+data.increment|string %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.minimum %}
|
||||||
|
{% set defquery = defquery+'\n MINVALUE '+data.minimum|string %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.maximum %}
|
||||||
|
{% set defquery = defquery+'\n MAXVALUE '+data.maximum|string %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.cache %}
|
||||||
|
{% set defquery = defquery+'\n CACHE '+data.cache|string %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.cycled == True %}
|
||||||
|
{% set defquery = defquery+'\n CYCLE' %}
|
||||||
|
{% elif data.cycled == False %}
|
||||||
|
{% set defquery = defquery+'\n NO CYCLE' %}
|
||||||
|
{% endif %}
|
||||||
|
{% if defquery and defquery != '' %}
|
||||||
|
ALTER SEQUENCE {{ conn|qtIdent(o_data.schema, data.name) }} {{ defquery }};
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if data.schema and data.schema != o_data.schema %}
|
||||||
|
ALTER SEQUENCE {{ conn|qtIdent(o_data.schema, data.name) }}
|
||||||
|
SET SCHEMA {{ conn|qtIdent(data.schema) }};
|
||||||
|
|
||||||
|
{% set seqname = conn|qtIdent(data.schema, data.name) %}
|
||||||
|
{% set schema = data.schema %}
|
||||||
|
{% else %}
|
||||||
|
{% set seqname = conn|qtIdent(o_data.schema, data.name) %}
|
||||||
|
{% set schema = o_data.schema %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.comment and data.comment != o_data.comment %}
|
||||||
|
COMMENT ON SEQUENCE {{ seqname }}
|
||||||
|
IS {{ data.comment|qtLiteral }};
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if data.securities and data.securities|length > 0 %}
|
||||||
|
|
||||||
|
{% set seclabels = data.securities %}
|
||||||
|
{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %}
|
||||||
|
{% for r in seclabels.deleted %}
|
||||||
|
{{ SECLABLE.UNSET(conn, 'SEQUENCE', data.name, r.provider, schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'added' in seclabels and seclabels.added|length > 0 %}
|
||||||
|
{% for r in seclabels.added %}
|
||||||
|
{{ SECLABLE.SET(conn, 'SEQUENCE', data.name, r.provider, r.security_label, schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'changed' in seclabels and seclabels.changed|length > 0 %}
|
||||||
|
{% for r in seclabels.changed %}
|
||||||
|
{{ SECLABLE.SET(conn, 'SEQUENCE', data.name, r.provider, r.security_label, schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.relacl %}
|
||||||
|
|
||||||
|
{% if 'deleted' in data.relacl %}
|
||||||
|
{% for priv in data.relacl.deleted %}
|
||||||
|
{{ PRIVILEGE.UNSETALL(conn, 'SEQUENCE', priv.grantee, data.name, schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'changed' in data.relacl %}
|
||||||
|
{% for priv in data.relacl.changed %}
|
||||||
|
{{ PRIVILEGE.UNSETALL(conn, 'SEQUENCE', priv.grantee, data.name, schema) }}
|
||||||
|
{{ PRIVILEGE.SET(conn, 'SEQUENCE', priv.grantee, data.name, priv.without_grant, priv.with_grant, schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'added' in data.relacl %}
|
||||||
|
{% for priv in data.relacl.added %}
|
||||||
|
{{ PRIVILEGE.SET(conn, 'SEQUENCE', priv.grantee, data.name, priv.without_grant, priv.with_grant, schema) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
Reference in New Issue
Block a user