diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py b/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py new file mode 100644 index 0000000..f1a4f65 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/__init__.py @@ -0,0 +1,521 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## +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 NodeView, parse_privileges +from pgadmin.browser.collection import CollectionNodeModule +import pgadmin.browser.server_groups.servers as servers +from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.driver import get_driver +from config import PG_DEFAULT_DRIVER +from functools import wraps + + +class TablespaceModule(CollectionNodeModule): + NODE_TYPE = 'tablespace' + COLLECTION_LABEL = gettext("Tablespaces") + + def __init__(self, *args, **kwargs): + self.min_ver = None + self.max_ver = None + + super(TablespaceModule, self).__init__(*args, **kwargs) + + def get_nodes(self, gid, sid): + """ + Generate the collection node + """ + yield self.generate_browser_collection_node(sid) + + @property + def script_load(self): + """ + Load the module script for server, when any of the server-group node is + initialized. + """ + return servers.ServerModule.NODE_TYPE + + +blueprint = TablespaceModule(__name__) + + +class TablespaceView(NodeView): + node_type = blueprint.node_type + + parent_ids = [ + {'type': 'int', 'id': 'gid'}, + {'type': 'int', 'id': 'sid'} + ] + ids = [ + {'type': 'int', 'id': 'did'} + ] + + operations = dict({ + 'obj': [ + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} + ], + 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'children': [{'get': 'children'}], + 'sql': [{'get': 'sql'}], + 'msql': [{'get': 'msql'}, {'get': 'msql'}], + 'stats': [{'get': 'statistics'}], + 'dependency': [{'get': 'dependencies'}], + 'dependent': [{'get': 'dependents'}], + 'module.js': [{}, {}, {'get': 'module_js'}], + 'vopts': [{}, {'get': 'variable_options'}] + }) + + def module_js(self): + """ + This property defines (if javascript) exists for this node. + Override this property for your own logic. + """ + return make_response( + render_template( + "tablespaces/js/tablespaces.js", + _=gettext + ), + 200, {'Content-Type': 'application/x-javascript'} + ) + + def check_precondition(f): + """ + This function will behave as a decorator which will checks + database connection before running view, it will also attaches + manager,conn & template_path properties to self + """ + @wraps(f) + def wrap(*args, **kwargs): + # Here args[0] will hold self & kwargs will hold gid,sid,did + self = args[0] + self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) + self.conn = self.manager.connection() + + # 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 + if ver >= 90200: + self.template_path = 'tablespaces/sql/9.1_plus' + else: + self.template_path = 'tablespaces/sql/pre_9.1' + + return f(*args, **kwargs) + return wrap + + @staticmethod + def _parse_privileges(str_privileges): + """Parse Privileges.""" + tblspc_privileges = { + 'C': 'CREATE' + } + + privileges = [] + + for priv in str_privileges: + priv_with_grant = [] + priv_without_grant = [] + for privilege in priv['privileges']: + if privilege['with_grant']: + priv_with_grant.append(tblspc_privileges[privilege['privilege_type']]) + elif privilege['privilege']: + priv_without_grant.append(tblspc_privileges[privilege['privilege_type']]) + + priv_with_grant = ", ".join(priv_with_grant) + priv_without_grant = ", ".join(priv_without_grant) + + privileges.append({'grantee': priv['grantee'], + 'with_grant': priv_with_grant, + 'without_grant': priv_without_grant}) + return privileges + + + @check_precondition + def list(self, gid, sid): + SQL = render_template("/".join([self.template_path, 'properties.sql'])) + 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): + res = [] + SQL = render_template("/".join([self.template_path, 'properties.sql'])) + 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'], + row['name'], + icon="icon-tablespace" + )) + + return make_json_response( + data=res, + status=200 + ) + + def _formatter(self, data, did=None): + """ + Args: + data: dict of query result + did: tablespace oid + + Returns: + It will return formatted output of collections + """ + # We need to format variables according to client js collection + if data['spcoptions'] is not None: + spcoptions = [] + for spcoption in data['spcoptions']: + k, v = spcoption.split('=') + spcoptions.append({'name': k, 'value': v}) + + data['spcoptions'] = spcoptions + + # Need to format security labels according to client js collection + if data['seclabels'] is not None: + seclabels = [] + for seclbls in data['seclabels']: + k, v = seclbls.split('=') + seclabels.append({'provider': k, 'security_label': v}) + + data['seclabels'] = seclabels + + # We need to parse & convert ACL coming from database to json format + SQL = render_template("/".join([self.template_path, 'acl.sql']), + did=did) + 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['spcacl'] = [] + + for row in acl['rows']: + priv = parse_privileges(row) + if row['deftype'] in data: + data[row['deftype']].append(priv) + else: + data[row['deftype']] = [priv] + + return data + + @check_precondition + def properties(self, gid, sid, did): + SQL = render_template("/".join([self.template_path, 'properties.sql']), + did=did, conn=self.conn) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Making copy of output for future use + copy_data = dict(res['rows'][0]) + copy_data = self._formatter(copy_data, did) + + return ajax_response( + response=copy_data, + status=200 + ) + + @check_precondition + def create(self, gid, sid): + """ + This function will creates new the tablespace object + """ + + required_args = { + 'name': 'Name', + 'spclocation': 'Location' + } + + 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=410, + success=0, + errormsg=gettext( + "Couldn't find the required parameter (%s)." % + required_args[arg] + ) + ) + + # To format privileges coming from client + if 'spcacl' in data: + data['spcacl'] = self._parse_privileges(data['spcacl']) + + try: + SQL = render_template("/".join([self.template_path, 'create.sql']), + data=data, conn=self.conn) + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + SQL = render_template("/".join([self.template_path, 'alter.sql']), + data=data, conn=self.conn) + # Checking if we are not executing empty query + if SQL and SQL.strip('\n') and SQL.strip(' '): + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + # To fetch the oid of newly created tablespace + SQL = render_template("/".join([self.template_path, 'alter.sql']), + tablespace=data['name'], conn=self.conn) + status, did = self.conn.execute_scalar(SQL) + if not status: + + return internal_server_error(errormsg=did) + + return jsonify( + node=self.blueprint.generate_browser_node( + did, + data['name'], + icon="icon-tablespace" + ) + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def update(self, gid, sid, did): + """ + This function will update tablespace object + """ + data = request.form if request.form else json.loads(request.data.decode()) + + try: + SQL = self.getSQL(gid, sid, data, did) + if SQL and SQL.strip('\n') and SQL.strip(' '): + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info="Tablespace updated", + data={ + 'id': did, + 'sid': sid, + 'gid': gid + } + ) + else: + return make_json_response( + success=1, + info="Nothing to update", + data={ + 'id': did, + 'sid': sid, + 'gid': gid + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did): + """ + This function will drop the tablespace object + """ + try: + # Get name for tablespace from did + SQL = render_template("/".join([self.template_path, 'delete.sql']), + did=did, conn=self.conn) + status, tsname = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=tsname) + # drop tablespace + SQL = render_template("/".join([self.template_path, 'delete.sql']), + tsname=tsname, conn=self.conn) + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + return make_json_response( + success=1, + info=gettext("Tablespace dropped"), + data={ + 'id': did, + 'sid': sid, + 'gid': gid, + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def msql(self, gid, sid, did=None): + """ + This function to return modified SQL + """ + data = dict() + for k, v in request.args.items(): + try: + data[k] = json.loads(v) + except ValueError: + data[k] = v + try: + SQL = self.getSQL(gid, sid, data, did) + + if SQL and SQL.strip('\n') and SQL.strip(' '): + return make_json_response( + data=SQL, + status=200 + ) + except Exception as e: + return internal_server_error(errormsg=str(e)) + + def getSQL(self, gid, sid, data, did=None): + """ + This function will genrate sql from model/properties data + """ + required_args = [ + 'name' + ] + + if did is not None: + SQL = render_template("/".join([self.template_path, 'properties.sql']), + did=did, conn=self.conn) + 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, did) + + # To format privileges data coming from client + for key in ['spcacl']: + if key in data and data[key] is not None: + if 'added' in data[key]: + data[key]['added'] = self._parse_privileges(data[key]['added']) + if 'changed' in data[key]: + data[key]['changed'] = self._parse_privileges(data[key]['changed']) + if 'deleted' in data[key]: + data[key]['deleted'] = self._parse_privileges(data[key]['deleted']) + + # 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) + else: + # To format privileges coming from client + if 'spcacl' in data: + data['spcacl'] = self._parse_privileges(data['spcacl']) + # If the request for new object which do not have did + SQL = render_template("/".join([self.template_path, 'create.sql']), + data=data) + SQL += "\n" + SQL += render_template("/".join([self.template_path, 'alter.sql']), + data=data) + + return SQL + + @check_precondition + def sql(self, gid, sid, did): + """ + This function will generate sql for sql panel + """ + SQL = render_template("/".join([self.template_path, 'properties.sql']), + did=did, conn=self.conn) + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) + + # Making copy of output for future use + old_data = dict(res['rows'][0]) + + old_data = self._formatter(old_data, did) + + SQL = '' + # We are not showing create sql for system tablespace + if not old_data['name'].startswith('pg_'): + SQL = render_template("/".join([self.template_path, 'create.sql']), + data=old_data) + SQL += "\n" + SQL += render_template("/".join([self.template_path, 'alter.sql']), + data=old_data) + + sql_header = """ +-- Tablespace: {0} + +-- DROP TABLESPACE {0} + +""".format(old_data['name']) + + SQL = sql_header + SQL + + return ajax_response(response=SQL) + + + @check_precondition + def variable_options(self, gid, sid): + """ + Args: + gid: + sid: + + Returns: + This function will return list of variables available for + table spaces. + """ + res = [] + SQL = render_template("/".join([self.template_path, 'variables.sql'])) + status, rset = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=rset) + + return make_json_response( + data=rset['rows'], + status=200 + ) + + @check_precondition + def stats(self, gid, sid, did): + """ + This function will return data for statistics panel + """ + SQL = render_template("/".join([self.template_path, 'stats.sql']), + did=did) + status, res = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) + + # TODO:// Format & return output of stats call accordingly + # TODO:// for now it's hardcoded as below + result = 'Tablespace Size: {0}'.format(res) + return ajax_response(response=result) + + +TablespaceView.register_node_view(blueprint) \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/static/img/coll-tablespace.png b/web/pgadmin/browser/server_groups/servers/tablespaces/static/img/coll-tablespace.png new file mode 100644 index 0000000000000000000000000000000000000000..9b090e419671c8179d99fa534b5bd91037da1036 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa3-AeX1=6RMsysMV_v`ztpWh~b z|Jr%?nBUhgb)P;LfBclm?tKNMjj<%iFPOpM*^M+HhqJ&VvKUBvfU(=jY&#$$)6>N< zgyVX0LIb0lqaug%jT-`oL<)g`#n9z23#+gr&qt@^WJgCG23o0rrD-}<$boTZ2xd}KIJv%c~Sn(Sd7uSJUMus_J z!b;bB{wxAos#@Y2QIe8al4_M)lnSI6j0_A7bqx%4jf_JKjIDsk&{*5R%*w#vz!jhFYcy%{ZjYy+vFE_5g`_t#* zC%1iX9kKuTDf96y_sd&6&#aNV&zS!hXeeVzkY6x^!?PP{Kn`btM`SUO_5fqIli7Aa zMuMk{V~E7%-t+E44GKK00Y9|F0(2ri{9_lL6ftdI?7t;GQ+_!r|76n;da+&4Gw-p$ z)n@iYA6`e@jHp|aN~Rn*)OqizBF~4UFCso0lD3KHa3t}TuuGSfDSUc(Tk`*&D#j~c zS(dBwMXLerQY~?fC`m~yNwrEYN(E93Mh1okx`sx&28JO<2397 0 %} +{% for r in data.seclabels %} +{{ SECLABLE.APPLY(conn, 'TABLESPACE', data.name, r.provider, r.security_label) }} +{% endfor %} + +{% endif %} +{### Variables on tablespace ###} +{% if data.spcoptions %} +{{ VARIABLE.SET(conn, 'TABLESPACE', data.name, data.spcoptions) }} + +{% endif %} +{### ACL on tablespace ###} +{% if data.spcacl %} +{% for priv in data.spcacl %} +{{ PRIVILEGE.APPLY(conn, 'TABLESPACE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} + +{% endif %} +{% endif %} +{# ======== The SQl Below will fetch id for given dataspace ======== #} +{% if tablespace %} +SELECT ts.oid FROM pg_tablespace ts WHERE spcname = {{tablespace|qtLiteral}} +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/create.sql new file mode 100644 index 0000000..193f03f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/create.sql @@ -0,0 +1,9 @@ +{### SQL to create tablespace object ###} +{% if data %} +CREATE TABLESPACE {{ conn|qtIdent(data.name) }} +{% if data.spcuser %} + OWNER {{ data.spcuser }} +{% endif %} + LOCATION {{ data.spclocation|qtLiteral }}; + +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/delete.sql new file mode 100644 index 0000000..68e925f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/delete.sql @@ -0,0 +1,9 @@ +{### SQL to delete tablespace object ###} +{% if did %} +SELECT spcname + FROM pg_tablespace ts + WHERE ts.oid = {{did}} +{% endif %} +{% if tsname %} +DROP TABLESPACE {{ conn|qtIdent(tsname) }}; +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/properties.sql new file mode 100755 index 0000000..4a1f2ed --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/properties.sql @@ -0,0 +1,10 @@ +{### SQL to fetch tablespace object properties ###} +SELECT ts.oid, spcname AS name, pg_catalog.pg_tablespace_location(ts.oid) AS spclocation, spcoptions, +pg_get_userbyid(spcowner) as spcuser, spcacl::text[], +pg_catalog.shobj_description(oid, 'pg_tablespace') AS description +,(SELECT array_agg(provider || '=' || label) FROM pg_shseclabel sl1 WHERE sl1.objoid=ts.oid) AS seclabels +FROM pg_tablespace ts +{% if did %} +WHERE ts.oid={{did}}::int +{% endif %} +ORDER BY name \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/stats.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/stats.sql new file mode 100644 index 0000000..ecc5b07 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/stats.sql @@ -0,0 +1,2 @@ +{### SQL to fetch tablespace object stats ###} +SELECT pg_size_pretty(pg_tablespace_size({{did}})) AS tablespace_size \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/update.sql new file mode 100644 index 0000000..5860295 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/update.sql @@ -0,0 +1,80 @@ +{### SQL to update tablespace object ###} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/variable.macros' as VARIABLE %} +{% import 'macros/privilege.macros' as PRIVILEGE %} +{% if data %} +{# ==== To update tablespace name ==== #} +{% if data.name != o_data.name %} +ALTER TABLESPACE {{ o_data.name }} + RENAME TO {{ conn|qtIdent(data.name) }}; + +{% endif %} +{# ==== To update tablespace user ==== #} +{% if data.spcuser and data.spcuser != o_data.spcuser %} +ALTER TABLESPACE {{ conn|qtIdent(data.name) }} + OWNER TO {{ data.spcuser }}; + +{% endif %} +{# ==== To update tablespace comments ==== #} +{% if data.description and data.description != o_data.description %} +COMMENT ON TABLESPACE {{ data.name }} + IS {{ data.description|qtLiteral }}; + +{% endif %} +{# ==== To update tablespace variables ==== #} +{% if 'spcoptions' in data and data.spcoptions|length > 0 %} +{% set variables = data.spcoptions %} +{% if 'deleted' in variables and variables.deleted|length > 0 %} +{{ VARIABLE.UNSET(conn, 'TABLESPACE', data.name, variables.deleted) }} +{% endif %} +{% if 'added' in variables and variables.added|length > 0 %} +{{ VARIABLE.SET(conn, 'TABLESPACE', data.name, variables.added) }} +{% endif %} +{% if 'changed' in variables and variables.changed|length > 0 %} +{{ VARIABLE.SET(conn, 'TABLESPACE', data.name, variables.changed) }} +{% endif %} + +{% endif %} +{# ==== To update tablespace securitylabel ==== #} +{# The SQL generated below will change Security Label #} +{% if data.seclabels and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABLE.DROP(conn, 'TABLESPACE', data.name, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABLE.APPLY(conn, 'TABLESPACE', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABLE.APPLY(conn, 'TABLESPACE', data.name, r.provider, r.security_label) }} +{% endfor %} +{% endif %} + +{% endif %} +{# ==== To update tablespace privileges ==== #} +{# Change the privileges #} +{% if data.spcacl %} +{% if 'deleted' in data.spcacl %} +{% for priv in data.spcacl.deleted %} +{{ PRIVILEGE.RESETALL(conn, 'TABLESPACE', priv.grantee, data.name) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.spcacl %} +{% for priv in data.spcacl.changed %} +{{ PRIVILEGE.RESETALL(conn, 'TABLESPACE', priv.grantee, data.name) }} +{{ PRIVILEGE.APPLY(conn, 'TABLESPACE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} +{% if 'added' in data.spcacl %} +{% for priv in data.spcacl.added %} +{{ PRIVILEGE.APPLY(conn, 'TABLESPACE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} + +{% endif %} +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/variables.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/variables.sql new file mode 100644 index 0000000..d476a05 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/9.1_plus/variables.sql @@ -0,0 +1,4 @@ +{### SQL to fetch tablespace object options ###} +SELECT name, vartype, min_val, max_val, enumvals +FROM pg_settings +WHERE name IN ('seq_page_cost', 'random_page_cost'); \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/acl.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/acl.sql new file mode 100644 index 0000000..76fb033 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/acl.sql @@ -0,0 +1,28 @@ +{### SQL to fetch privileges for tablespace ###} +SELECT 'spcacl' 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 'CREATE' THEN 'C' + ELSE 'UNKNOWN' + END AS privilege_type + FROM + (SELECT ts.spcacl + FROM pg_tablespace ts + {% if did %} + WHERE ts.oid={{did}}::int + {% endif %} + ) acl, + (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable + AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT + aclexplode(ts.spcacl) as d FROM pg_tablespace ts + {% if did %} + WHERE ts.oid={{did}}::int + {% endif %} + ) a) 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 \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/alter.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/alter.sql new file mode 100755 index 0000000..6558387 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/alter.sql @@ -0,0 +1,41 @@ +{### SQL to alter tablespace ###} +{% import 'macros/security.macros' as SECLABLE %} +{% import 'macros/variable.macros' as VARIABLE %} +{% import 'macros/privilege.macros' as PRIVILEGE %} +{% if data %} +{### Owner on tablespace ###} +{% if data.spcuser %} +ALTER TABLESPACE {{ conn|qtIdent(data.name) }} + OWNER TO {{ data.spcuser }}; + +{% endif %} +{### Comments on tablespace ###} +{% if data.description %} +COMMENT ON TABLESPACE {{ conn|qtIdent(data.name) }} + IS {{ data.description|qtLiteral }}; + +{% endif %} +{### Security Labels on tablespace ###} +{% if data.seclabels and data.seclabels|length > 0 %} +{% for r in data.seclabels %} +{{ SECLABLE.APPLY(conn, 'TABLESPACE', data.name, r.provider, r.security_label) }} +{% endfor %} + +{% endif %} +{### Variables on tablespace ###} +{% if data.spcoptions %} +{{ VARIABLE.SET(conn, 'TABLESPACE', data.name, data.spcoptions) }} + +{% endif %} +{### ACL on tablespace ###} +{% if data.spcacl %} +{% for priv in data.spcacl %} +{{ PRIVILEGE.APPLY(conn, 'TABLESPACE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} + +{% endif %} +{% endif %} +{# ======== The SQl Below will fetch id for given dataspace ======== #} +{% if tablespace %} +SELECT ts.oid FROM pg_tablespace ts WHERE spcname = {{tablespace|qtLiteral}} +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/create.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/create.sql new file mode 100644 index 0000000..193f03f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/create.sql @@ -0,0 +1,9 @@ +{### SQL to create tablespace object ###} +{% if data %} +CREATE TABLESPACE {{ conn|qtIdent(data.name) }} +{% if data.spcuser %} + OWNER {{ data.spcuser }} +{% endif %} + LOCATION {{ data.spclocation|qtLiteral }}; + +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/delete.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/delete.sql new file mode 100644 index 0000000..68e925f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/delete.sql @@ -0,0 +1,9 @@ +{### SQL to delete tablespace object ###} +{% if did %} +SELECT spcname + FROM pg_tablespace ts + WHERE ts.oid = {{did}} +{% endif %} +{% if tsname %} +DROP TABLESPACE {{ conn|qtIdent(tsname) }}; +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/properties.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/properties.sql new file mode 100755 index 0000000..6a62afc --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/properties.sql @@ -0,0 +1,9 @@ +{### SQL to fetch tablespace object properties ###} +SELECT ts.oid, spcname AS name, pg_catalog.pg_tablespace_location(ts.oid) AS spclocation, spcoptions, +pg_get_userbyid(spcowner) as spcuser, spcacl::text[], +pg_catalog.shobj_description(oid, 'pg_tablespace') AS description +FROM pg_tablespace ts +{% if did %} +WHERE ts.oid={{did}}::int +{% endif %} +ORDER BY name \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/stats.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/stats.sql new file mode 100644 index 0000000..ecc5b07 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/stats.sql @@ -0,0 +1,2 @@ +{### SQL to fetch tablespace object stats ###} +SELECT pg_size_pretty(pg_tablespace_size({{did}})) AS tablespace_size \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/update.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/update.sql new file mode 100644 index 0000000..7520ded --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/update.sql @@ -0,0 +1,58 @@ +{### SQL to update tablespace object ###} +{% import 'macros/variable.macros' as VARIABLE %} +{% import 'macros/privilege.macros' as PRIVILEGE %} +{% if data %} +{# ==== To update tablespace name ==== #} +{% if data.name != o_data.name %} +ALTER TABLESPACE {{ o_data.name }} + RENAME TO {{ conn|qtIdent(data.name) }}; + +{% endif %} +{# ==== To update tablespace user ==== #} +{% if data.spcuser and data.spcuser != o_data.spcuser %} +ALTER TABLESPACE {{ conn|qtIdent(data.name) }} + OWNER TO {{ data.spcuser }}; + +{% endif %} +{# ==== To update tablespace comments ==== #} +{% if data.description and data.description != o_data.description %} +COMMENT ON TABLESPACE {{ data.name }} + IS {{ data.description|qtLiteral }}; + +{% endif %} +{# ==== To update tablespace variables ==== #} +{% if 'spcoptions' in data and data.spcoptions|length > 0 %} +{% set variables = data.spcoptions %} +{% if 'deleted' in variables and variables.deleted|length > 0 %} +{{ VARIABLE.UNSET(conn, 'TABLESPACE', data.name, variables.deleted) }} +{% endif %} +{% if 'added' in variables and variables.added|length > 0 %} +{{ VARIABLE.SET(conn, 'TABLESPACE', data.name, variables.added) }} +{% endif %} +{% if 'changed' in variables and variables.changed|length > 0 %} +{{ VARIABLE.SET(conn, 'TABLESPACE', data.name, variables.changed) }} +{% endif %} + +{% endif %} +{# ==== To update tablespace privileges ==== #} +{# Change the privileges #} +{% if data.spcacl %} +{% if 'deleted' in data.spcacl %} +{% for priv in data.spcacl.deleted %} +{{ PRIVILEGE.RESETALL(conn, 'TABLESPACE', priv.grantee, data.name) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.spcacl %} +{% for priv in data.spcacl.changed %} +{{ PRIVILEGE.RESETALL(conn, 'TABLESPACE', priv.grantee, data.name) }} +{{ PRIVILEGE.APPLY(conn, 'TABLESPACE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} +{% if 'added' in data.spcacl %} +{% for priv in data.spcacl.added %} +{{ PRIVILEGE.APPLY(conn, 'TABLESPACE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} + +{% endif %} +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/variables.sql b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/variables.sql new file mode 100644 index 0000000..d476a05 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/tablespaces/templates/tablespaces/sql/pre_9.1/variables.sql @@ -0,0 +1,4 @@ +{### SQL to fetch tablespace object options ###} +SELECT name, vartype, min_val, max_val, enumvals +FROM pg_settings +WHERE name IN ('seq_page_cost', 'random_page_cost'); \ No newline at end of file