From 7dffb020f1c898cb8f178dbacb378cd9a658832a Mon Sep 17 00:00:00 2001 From: Akshay Joshi Date: Fri, 19 Aug 2016 10:26:02 +0100 Subject: [PATCH] Support CREATE LANGUAGE. Fixes #1252 --- .../servers/databases/languages/__init__.py | 150 +++++++++++++++++- .../templates/languages/js/languages.js | 145 ++++++++++++++--- .../languages/sql/9.1_plus/create.sql | 39 +++++ .../languages/sql/9.1_plus/delete.sql | 8 + .../languages/sql/9.1_plus/properties.sql | 6 +- .../languages/sql/9.1_plus/templates.sql | 7 + .../languages/sql/9.1_plus/update.sql | 2 +- .../languages/sql/9.3_plus/create.sql | 39 +++++ .../languages/sql/9.3_plus/delete.sql | 8 + .../languages/sql/9.3_plus/properties.sql | 6 +- .../languages/sql/9.3_plus/templates.sql | 7 + .../languages/sql/9.3_plus/update.sql | 2 +- 12 files changed, 386 insertions(+), 33 deletions(-) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/templates.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/delete.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/templates.sql diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py index 07c04e948..4f0238580 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py @@ -13,7 +13,7 @@ import simplejson as json from functools import wraps import pgadmin.browser.server_groups.servers.databases as databases -from flask import render_template, make_response, request +from flask import render_template, make_response, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ @@ -133,6 +133,12 @@ class LanguageView(PGChildNodeView): * update(gid, sid, did, lid) - This function will update the data for the selected language node + * create(gid, sid, did) + - This function will create the new language node + + * delete(gid, sid, did, lid) + - This function will delete the selected language node + * msql(gid, sid, did, lid) - This function is used to return modified SQL for the selected language node @@ -142,6 +148,9 @@ class LanguageView(PGChildNodeView): * get_functions(gid, sid, did) - This function returns the handler and inline functions for the selected language node + * get_templates(gid, sid, did) + - This function returns language templates. + * sql(gid, sid, did, lid): - This function will generate sql to show it in sql pane for the selected language node. @@ -165,8 +174,8 @@ class LanguageView(PGChildNodeView): operations = dict({ 'obj': [ - {'get': 'properties', 'put': 'update'}, - {'get': 'list'} + {'get': 'properties', 'delete': 'delete', 'put': 'update'}, + {'get': 'list', 'post': 'create'} ], 'nodes': [{'get': 'node'}, {'get': 'nodes'}], 'sql': [{'get': 'sql'}], @@ -175,7 +184,9 @@ class LanguageView(PGChildNodeView): 'dependency': [{'get': 'dependencies'}], 'dependent': [{'get': 'dependents'}], 'module.js': [{}, {}, {'get': 'module_js'}], - 'get_functions': [{}, {'get': 'get_functions'}] + 'get_functions': [{}, {'get': 'get_functions'}], + 'get_templates': [{}, {'get': 'get_templates'}], + 'delete': [{'delete': 'delete'}] }) def _init_(self, **kwargs): @@ -337,7 +348,6 @@ class LanguageView(PGChildNodeView): res['rows'][0]['seclabels'] = seclabels - return ajax_response( response=res['rows'][0], status=200 @@ -390,6 +400,110 @@ class LanguageView(PGChildNodeView): except Exception as e: return internal_server_error(errormsg=str(e)) + @check_precondition + def create(self, gid, sid, did): + """ + This function will create the language object + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + """ + required_args = [ + 'name' + ] + + data = request.form if request.form else json.loads( + request.data, encoding='utf-8' + ) + for arg in required_args: + if arg not in data: + return make_json_response( + status=410, + success=0, + errormsg=gettext( + "Could not find the required parameter (%s)." % arg + ) + ) + + try: + if 'lanacl' in data: + data['lanacl'] = parse_priv_to_db(data['lanacl'], ['U']) + + sql = render_template("/".join([self.template_path, 'create.sql']), + data=data, conn=self.conn) + status, res = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=res) + + sql = render_template("/".join([self.template_path, 'properties.sql']), + lanname=data['name'], conn=self.conn) + + status, r_set = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=r_set) + + for row in r_set['rows']: + return jsonify( + node=self.blueprint.generate_browser_node( + row['oid'], + did, + row['name'], + icon='icon-language' + ) + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + + @check_precondition + def delete(self, gid, sid, did, lid): + """ + This function will drop the language object + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + lid: Language ID + """ + if self.cmd == 'delete': + # This is a cascade operation + cascade = True + else: + cascade = False + + try: + # Get name for language from lid + sql = render_template("/".join([self.template_path, 'delete.sql']), lid=lid, conn=self.conn) + status, lname = self.conn.execute_scalar(sql) + + if not status: + return internal_server_error(errormsg=lname) + + # drop language + sql = render_template("/".join([self.template_path, 'delete.sql']), lname=lname, + cascade=cascade, 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("Language dropped"), + data={ + 'id': lid, + 'did': did, + 'sid': sid, + 'gid': gid, + } + ) + + except Exception as e: + return internal_server_error(errormsg=str(e)) + @check_precondition def msql(self, gid, sid, did, lid=None): """ @@ -454,6 +568,13 @@ class LanguageView(PGChildNodeView): data[arg] = old_data[arg] sql = render_template("/".join([self.template_path, 'update.sql']), data=data, o_data=old_data, conn=self.conn) + else: + + if 'lanacl' in data: + data['lanacl'] = parse_priv_to_db(data['lanacl'], 'LANGUAGE') + + sql = render_template("/".join([self.template_path, 'create.sql']), + data=data, conn=self.conn) return sql.strip('\n') except Exception as e: return internal_server_error(errormsg=str(e)) @@ -477,6 +598,25 @@ class LanguageView(PGChildNodeView): status=200 ) + @check_precondition + def get_templates(self, gid, sid, did): + """ + This function returns the language template. + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + """ + sql = render_template("/".join([self.template_path, 'templates.sql'])) + status, result = self.conn.execute_dict(sql) + if not status: + return internal_server_error(errormsg=result) + return make_json_response( + data=result['rows'], + status=200 + ) + @check_precondition def sql(self, gid, sid, did, lid): """ diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/js/languages.js b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/js/languages.js index a83b7deed..470ae4f43 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/js/languages.js +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/js/languages.js @@ -23,6 +23,8 @@ define( sqlCreateHelp: 'sql-createlanguage.html', label: '{{ _('Language') }}', hasSQL: true, + canDrop: true, + canDropCascade: true, hasDepends: true, Init: function() { @@ -31,6 +33,25 @@ define( return; this.initialized = true; + + + // Add context menus for language + pgBrowser.add_menus([{ + name: 'create_language_on_database', node: 'database', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Language...') }}', + icon: 'wcTabIcon icon-language', data: {action: 'create'} + },{ + name: 'create_language_on_coll', node: 'coll-language', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Language...') }}', + icon: 'wcTabIcon icon-language', data: {action: 'create'} + },{ + name: 'create_language', node: 'language', module: this, + applies: ['object', 'context'], callback: 'show_obj_properties', + category: 'create', priority: 4, label: '{{ _('Language...') }}', + icon: 'wcTabIcon icon-language', data: {action: 'create'} + }]); }, // Define the model for language node @@ -40,20 +61,59 @@ define( lanowner: undefined, comment: undefined, lanacl: [], - seclabels:[] + seclabels:[], + trusted: true, + lanproc: undefined, + laninl: undefined, + lanval: undefined, + is_template: false, + template_list: [] + }, + + // Default values! + initialize: function(attrs, args) { + var isNew = (_.size(attrs) === 0); + if (isNew) { + var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user; + + this.set({'lanowner': userInfo.name}, {silent: true}); + } + pgBrowser.Node.Model.prototype.initialize.apply(this, arguments); }, // Define the schema for the language node schema: [{ - id: 'name', label: '{{ _('Name') }}', cell: 'string', - type: 'text', + id: 'name', label: '{{ _('Name') }}', type: 'text', + control: 'node-ajax-options', mode: ['properties', 'create', 'edit'], + url:'get_templates', select2: { allowClear: false, tags: true, multiple: false }, + transform: function(data, cell) { + var res = [], + control = cell || this, + label = control.model.get('name'); + + if (!control.model.isNew()) { + res.push({label: label, value: label}); + } + else { + var tmp_list = []; + if (data && _.isArray(data)) { + _.each(data, function(d) { + res.push({label: d.tmplname, value: d.tmplname}); + tmp_list.push(d.tmplname); + }) + } + this.model.set({'template_list': tmp_list}); + } + + return res; + } },{ id: 'oid', label:'{{ _('OID') }}', cell: 'string', mode: ['properties'], type: 'text', disabled: true },{ id: 'lanowner', label:'{{ _('Owner') }}', type: 'text', control: Backform.NodeListByNameControl, node: 'role', - mode: ['edit', 'properties'], select2: { allowClear: false } + mode: ['edit', 'properties', 'create'], select2: { allowClear: false } },{ id: 'acl', label: '{{ _('Privileges') }}', type: 'text', group: '{{ _('Security') }}', mode: ['properties'], disabled: true @@ -67,13 +127,22 @@ define( 'onColor': 'success', 'offColor': 'primary', 'size': 'small' }, - group: 'Definition', mode: ['edit', 'properties'], + group: 'Definition', mode: ['edit', 'properties', 'create'], deps: ['name'], disabled: function(m) { - return !(m.isNew()); + if (m.isNew()) { + if (m.get('template_list').indexOf(m.get('name')) == -1) { + m.set({'is_template': false}); + return false; + } + else + m.set({'is_template': true}); + } + return true; } },{ id: 'lanproc', label:'{{ _('Handler Function') }}', type: 'text', control: 'node-ajax-options', - group: 'Definition', mode: ['edit', 'properties'], url:'get_functions', + group: 'Definition', mode: ['edit', 'properties', 'create'], url:'get_functions', + deps: ['name'], first_empty: false, /* This function is used to populate the handler function * for the selected language node. It will check if the property * type is 'handler' then push the data into the result array. @@ -81,19 +150,24 @@ define( transform: function(data) { var res = []; if (data && _.isArray(data)) { - _.each(data, function(d) { - if (d.prop_type == 'handler') { - res.push({label: d.label, value: d.label}); - } - }) + _.each(data, function(d) { + if (d.prop_type == 'handler') { + res.push({label: d.label, value: d.label}); + } + }) } return res; }, disabled: function(m) { - return !(m.isNew()); + if (m.isNew()) { + if (m.get('template_list').indexOf(m.get('name')) == -1) + return false; + } + return true; } },{ id: 'laninl', label:'{{ _('Inline Function') }}', type: 'text', control: 'node-ajax-options', - group: 'Definition', mode: ['edit', 'properties'], url:'get_functions', + group: 'Definition', mode: ['edit', 'properties', 'create'], url:'get_functions', + deps: ['name'], first_empty: false, /* This function is used to populate the inline function * for the selected language node. It will check if the property * type is 'inline' then push the data into the result array. @@ -101,19 +175,24 @@ define( transform: function(data) { var res = []; if (data && _.isArray(data)) { - _.each(data, function(d) { - if (d.prop_type == 'inline') { - res.push({label: d.label, value: d.label}); - } - }) + _.each(data, function(d) { + if (d.prop_type == 'inline') { + res.push({label: d.label, value: d.label}); + } + }) } return res; }, disabled: function(m) { - return !(m.isNew()); + if (m.isNew()) { + if (m.get('template_list').indexOf(m.get('name')) == -1) + return false; + } + return true; } },{ id: 'lanval', label:'{{ _('Validator Function') }}', type: 'text', control: 'node-ajax-options', - group: 'Definition', mode: ['edit', 'properties'], url:'get_functions', + group: 'Definition', mode: ['edit', 'properties', 'create'], url:'get_functions', + deps: ['name'], /* This function is used to populate the validator function * for the selected language node. It will check if the property * type is 'validator' then push the data into the result array. @@ -129,16 +208,20 @@ define( } return res; }, disabled: function(m) { - return !(m.isNew()); + if (m.isNew()) { + if (m.get('template_list').indexOf(m.get('name')) == -1) + return false; + } + return true; } }, pgBrowser.SecurityGroupUnderSchema, { id: 'lanacl', label: '{{ _('Privileges') }}', type: 'collection', - group: 'security', control: 'unique-col-collection', mode: ['edit'], + group: 'security', control: 'unique-col-collection', mode: ['edit', 'create'], model: pgBrowser.Node.PrivilegeRoleModel.extend({ privileges: ['U'] }), canAdd: true, canDelete: true, uniqueCol : ['grantee'] },{ - id: 'seclabels', label: '{{ _('Security Labels') }}', mode: ['edit'], + id: 'seclabels', label: '{{ _('Security Labels') }}', mode: ['edit', 'create'], model: pgBrowser.SecLabelModel, editable: false, type: 'collection', group: 'security', min_version: 90200, canAdd: true, canEdit: false, canDelete: true, @@ -160,6 +243,20 @@ define( } else { this.errorModel.unset('name'); } + + // If predefined template is selected then no need to validate it. + if (!this.get('is_template')) { + var handler_func = this.get('lanproc'); + if (_.isUndefined(handler_func) || _.isNull(handler_func) || + String(handler_func).replace(/^\s+|\s+$/g, '') == '') { + var msg = '{{ _('Handler Function cannot be empty') }}'; + this.errorModel.set('lanproc', msg); + return msg; + } else { + this.errorModel.unset('lanproc'); + } + } + return null; } }) diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/create.sql new file mode 100644 index 000000000..b85760d1d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/create.sql @@ -0,0 +1,39 @@ +{# ============= CREATE LANGUAGE Query ============= #} +{% import 'macros/privilege.macros' as PRIVILEGE %} +{% import 'macros/security.macros' as SECLABEL %} +{% if data.is_template %} +CREATE LANGUAGE {{ conn|qtIdent(data.name) }}; +{% else %} +CREATE{% if data.trusted %} TRUSTED{% endif %} PROCEDURAL LANGUAGE {{ conn|qtIdent(data.name) }} +{% if data.lanproc %} + HANDLER {{ conn|qtIdent(data.lanproc) }} +{% endif %} +{% if data.laninl %} + INLINE {{ conn|qtIdent(data.laninl) }} +{% endif %} +{% if data.lanval %} + VALIDATOR {{ conn|qtIdent(data.lanval) }} +{% endif %}; +{% endif %} +{# ============= Set the owner for language ============= #} +{% if data.lanowner %} +ALTER LANGUAGE {{ conn|qtIdent(data.name) }} + OWNER TO {{ conn|qtIdent(data.lanowner) }}; +{% endif %} +{# ============= Comment on of language object ============= #} +{% if data.description %} +COMMENT ON LANGUAGE {{ conn|qtIdent(data.name) }} + IS {{ data.description|qtLiteral }}; +{% endif %} +{# ============= Create ACL for language ============= #} +{% if data.lanacl %} +{% for priv in data.lanacl %} +{{ PRIVILEGE.APPLY(conn, 'LANGUAGE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} +{# ========= Change the security labels ========== #} +{% if data.seclabels %} +{% for r in data.seclabels %} +{{ SECLABEL.APPLY(conn, 'LANGUAGE', data.name, r.provider, r.label) }} +{% endfor %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/delete.sql new file mode 100644 index 000000000..c213263fe --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/delete.sql @@ -0,0 +1,8 @@ +{# ============= Get the language name using oid ============= #} +{% if lid %} + SELECT lanname FROM pg_language WHERE oid = {{lid}}::int; +{% endif %} +{# ============= Drop the language ============= #} +{% if lname %} + DROP LANGUAGE {{ conn|qtIdent(lname) }} {% if cascade %}CASCADE{% endif%}; +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/properties.sql index 530664272..bb4cf93f6 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/properties.sql @@ -16,4 +16,8 @@ FROM WHERE lanispl IS TRUE {% if lid %} AND lan.oid={{lid}}::int -{% endif %} ORDER BY lanname +{% endif %} +{% if lanname %} AND + lanname={{ lanname|qtLiteral }}::text +{% endif %} +ORDER BY lanname diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/templates.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/templates.sql new file mode 100644 index 000000000..f67184af5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/templates.sql @@ -0,0 +1,7 @@ +{# ============= SELECT Language templates ============= #} +SELECT + tmplname +FROM pg_pltemplate +LEFT JOIN pg_language ON tmplname=lanname +WHERE lanname IS NULL +ORDER BY tmplname; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/update.sql index 526cd9d54..99d89bda0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.1_plus/update.sql @@ -12,7 +12,7 @@ ALTER LANGUAGE {{ conn|qtIdent(data.name) }} OWNER TO {{ conn|qtIdent(data.lanowner) }}; {% endif %} {# ============= Update language comments ============= #} -{% if data.description and data.description != o_data.description %} +{% if data.description is defined and data.description != o_data.description %} COMMENT ON LANGUAGE {{ conn|qtIdent(data.name) }} IS '{{ data.description }}'; {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/create.sql new file mode 100644 index 000000000..b85760d1d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/create.sql @@ -0,0 +1,39 @@ +{# ============= CREATE LANGUAGE Query ============= #} +{% import 'macros/privilege.macros' as PRIVILEGE %} +{% import 'macros/security.macros' as SECLABEL %} +{% if data.is_template %} +CREATE LANGUAGE {{ conn|qtIdent(data.name) }}; +{% else %} +CREATE{% if data.trusted %} TRUSTED{% endif %} PROCEDURAL LANGUAGE {{ conn|qtIdent(data.name) }} +{% if data.lanproc %} + HANDLER {{ conn|qtIdent(data.lanproc) }} +{% endif %} +{% if data.laninl %} + INLINE {{ conn|qtIdent(data.laninl) }} +{% endif %} +{% if data.lanval %} + VALIDATOR {{ conn|qtIdent(data.lanval) }} +{% endif %}; +{% endif %} +{# ============= Set the owner for language ============= #} +{% if data.lanowner %} +ALTER LANGUAGE {{ conn|qtIdent(data.name) }} + OWNER TO {{ conn|qtIdent(data.lanowner) }}; +{% endif %} +{# ============= Comment on of language object ============= #} +{% if data.description %} +COMMENT ON LANGUAGE {{ conn|qtIdent(data.name) }} + IS {{ data.description|qtLiteral }}; +{% endif %} +{# ============= Create ACL for language ============= #} +{% if data.lanacl %} +{% for priv in data.lanacl %} +{{ PRIVILEGE.APPLY(conn, 'LANGUAGE', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} +{# ========= Change the security labels ========== #} +{% if data.seclabels %} +{% for r in data.seclabels %} +{{ SECLABEL.APPLY(conn, 'LANGUAGE', data.name, r.provider, r.label) }} +{% endfor %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/delete.sql new file mode 100644 index 000000000..c213263fe --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/delete.sql @@ -0,0 +1,8 @@ +{# ============= Get the language name using oid ============= #} +{% if lid %} + SELECT lanname FROM pg_language WHERE oid = {{lid}}::int; +{% endif %} +{# ============= Drop the language ============= #} +{% if lname %} + DROP LANGUAGE {{ conn|qtIdent(lname) }} {% if cascade %}CASCADE{% endif%}; +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/properties.sql index 530664272..bb4cf93f6 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/properties.sql @@ -16,4 +16,8 @@ FROM WHERE lanispl IS TRUE {% if lid %} AND lan.oid={{lid}}::int -{% endif %} ORDER BY lanname +{% endif %} +{% if lanname %} AND + lanname={{ lanname|qtLiteral }}::text +{% endif %} +ORDER BY lanname diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/templates.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/templates.sql new file mode 100644 index 000000000..f67184af5 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/templates.sql @@ -0,0 +1,7 @@ +{# ============= SELECT Language templates ============= #} +SELECT + tmplname +FROM pg_pltemplate +LEFT JOIN pg_language ON tmplname=lanname +WHERE lanname IS NULL +ORDER BY tmplname; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/update.sql index 526cd9d54..99d89bda0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/templates/languages/sql/9.3_plus/update.sql @@ -12,7 +12,7 @@ ALTER LANGUAGE {{ conn|qtIdent(data.name) }} OWNER TO {{ conn|qtIdent(data.lanowner) }}; {% endif %} {# ============= Update language comments ============= #} -{% if data.description and data.description != o_data.description %} +{% if data.description is defined and data.description != o_data.description %} COMMENT ON LANGUAGE {{ conn|qtIdent(data.name) }} IS '{{ data.description }}'; {% endif %}