Add support for collations.

pull/3/head
Murtuza Zabuawala 2016-03-11 13:40:28 +00:00 committed by Dave Page
parent c0086b092f
commit b6f7202448
13 changed files with 1030 additions and 0 deletions

View File

@ -0,0 +1,664 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
""" Implements Collation Node """
import json
from flask import render_template, request, jsonify
from flask.ext.babel import gettext
from pgadmin.utils.ajax import make_json_response, \
make_response as ajax_response, internal_server_error
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.browser.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 CollationModule(SchemaChildModule):
"""
class CollationModule(CollectionNodeModule)
A module class for Collation node derived from CollectionNodeModule.
Methods:
-------
* __init__(*args, **kwargs)
- Method is used to initialize the Collation and it's base module.
* get_nodes(gid, sid, did, scid, coid)
- Method is used to generate the browser collection node.
* node_inode()
- Method is overridden from its base class to make the node as leaf node.
* script_load()
- Load the module script for schema, when any of the server node is
initialized.
"""
NODE_TYPE = 'collation'
COLLECTION_LABEL = gettext("Collations")
def __init__(self, *args, **kwargs):
"""
Method is used to initialize the CollationModule and it's base module.
Args:
*args:
**kwargs:
"""
super(CollationModule, self).__init__(*args, **kwargs)
self.min_ver = 90100
self.max_ver = None
def get_nodes(self, gid, sid, did, scid):
"""
Generate the collection 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):
return False
blueprint = CollationModule(__name__)
class CollationView(PGChildNodeView):
"""
This class is responsible for generating routes for Collation node
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the CollationView and it's base view.
* check_precondition()
- 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
* list()
- This function is used to list all the Collation nodes within that
collection.
* nodes()
- This function will used to create all the child node within that
collection, Here it will create all the Collation node.
* properties(gid, sid, did, scid, coid)
- This function will show the properties of the selected Collation node
* create(gid, sid, did, scid)
- This function will create the new Collation object
* update(gid, sid, did, scid, coid)
- This function will update the data for the selected Collation node
* delete(self, gid, sid, scid, coid):
- This function will drop the Collation object
* msql(gid, sid, did, scid, coid)
- This function is used to return modified SQL for the selected
Collation node
* get_sql(data, scid, coid)
- This function will generate sql from model data
* sql(gid, sid, did, scid):
- This function will generate sql to show it in sql pane for the
selected Collation node.
* dependency(gid, sid, did, scid):
- This function will generate dependency list show it in dependency
pane for the selected Collation node.
* dependent(gid, sid, did, scid):
- This function will generate dependent list to show it in dependent
pane for the selected Collation node.
"""
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': 'coid'}
]
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'}
],
'delete': [{'delete': 'delete'}],
'children': [{'get': 'children'}],
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
'sql': [{'get': 'sql'}],
'msql': [{'get': 'msql'}, {'get': 'msql'}],
'stats': [{'get': 'statistics'}],
'dependency': [{'get': 'dependencies'}],
'dependent': [{'get': 'dependents'}],
'module.js': [{}, {}, {'get': 'module_js'}],
'get_collations': [{'get': 'get_collation'},
{'get': 'get_collation'}]
})
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(did=kwargs['did'])
# If DB not connected then return error to browser
if not self.conn.connected():
return precondition_required(
gettext(
"Connection to the server has been lost!"
)
)
# we will set template path for sql scripts
self.template_path = 'collation/sql/9.1_plus'
return f(*args, **kwargs)
return wrap
@check_precondition
def list(self, gid, sid, did, scid):
"""
This function is used to list all the collation nodes within that collection.
Args:
gid: Server group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of available collation nodes
"""
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
def nodes(self, gid, sid, did, scid):
"""
This function will used to create all the child node within that collection.
Here it will create all the collation node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
Returns:
JSON of available collation child nodes
"""
res = []
SQL = render_template("/".join([self.template_path,
'nodes.sql']), scid=scid)
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
res.append(
self.blueprint.generate_browser_node(
row['oid'],
scid,
row['name'],
icon="icon-collation"
))
return make_json_response(
data=res,
status=200
)
@check_precondition
def properties(self, gid, sid, did, scid, coid):
"""
This function will show the properties of the selected collation node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
scid: Schema ID
coid: Collation ID
Returns:
JSON of selected collation node
"""
try:
SQL = render_template("/".join([self.template_path,
'properties.sql']),
scid=scid, coid=coid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
return ajax_response(
response=res['rows'][0],
status=200
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def get_collation(self, gid, sid, did, scid, coid=None):
"""
This function will return list of collation available
as AJAX response.
"""
res = [{ 'label': '', 'value': '' }]
try:
SQL = render_template("/".join([self.template_path,
'get_collations.sql']))
status, rset = self.conn.execute_2darray(SQL)
if not status:
return internal_server_error(errormsg=res)
for row in rset['rows']:
res.append(
{'label': row['copy_collation'],
'value': row['copy_collation']}
)
return make_json_response(
data=res,
status=200
)
except Exception as e:
return internal_server_error(errormsg=str(e))
def _check_definition(self, data):
"""
Args:
data: request data received from client
Returns:
True if defination is missing, False otherwise
"""
definition_args = [
'locale',
'copy_collation',
'lc_collate',
'lc_type'
]
# Additional server side validation to check if
# definition is sent properly from client side
missing_definition_flag = False
for arg in definition_args:
if arg == 'locale' and \
(arg not in data or data[arg] == ''):
if 'copy_collation' not in data and (
'lc_collate' not in data and 'lc_type' not in data
):
missing_definition_flag = True
if arg == 'copy_collation' and \
(arg not in data or data[arg] == ''):
if 'locale' not in data and (
'lc_collate' not in data and 'lc_type' not in data
):
missing_definition_flag = True
if (arg == 'lc_collate' or arg == 'lc_type') and \
(arg not in data or data[arg] == ''):
if 'copy_collation' not in data and 'locale' not in data:
missing_definition_flag = True
return missing_definition_flag
@check_precondition
def create(self, gid, sid, did, scid):
"""
This function will creates new the collation object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
"""
data = request.form if request.form else json.loads(
request.data.decode()
)
required_args = [
'name'
]
for arg in required_args:
if arg not in data:
return make_json_response(
status=410,
success=0,
errormsg=gettext(
"Couldn't find the required parameter (%s)." % arg
)
)
if self._check_definition(data):
return make_json_response(
status=410,
success=0,
errormsg=gettext(
"Incomplete definition, Please provide Locale \
OR Copy collation OR LC_TYPE/LC_COLLATE"
)
)
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)
# We need oid to to add object in tree at browser
SQL = render_template("/".join([self.template_path,
'get_oid.sql']), data=data)
status, coid = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=coid)
return jsonify(
node=self.blueprint.generate_browser_node(
coid,
scid,
data['name'],
icon="icon-collation"
)
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def delete(self, gid, sid, did, scid, coid):
"""
This function will delete existing the collation object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
coid: Collation ID
"""
# 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,
'get_name.sql']),
scid=scid, coid=coid)
status, name = self.conn.execute_scalar(SQL)
if not status:
return internal_server_error(errormsg=name)
SQL = render_template("/".join([self.template_path,
'delete.sql']),
name=name, 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("Collation dropped"),
data={
'id': coid,
'scid': scid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def update(self, gid, sid, did, scid, coid):
"""
This function will updates existing the collation object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
coid: Collation ID
"""
data = request.form if request.form else json.loads(
request.data.decode()
)
SQL = self.get_sql(gid, sid, data, scid, coid)
try:
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="Collation updated",
data={
'id': coid,
'scid': scid,
'did': did
}
)
else:
return make_json_response(
success=1,
info="Nothing to update",
data={
'id': coid,
'scid': scid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def msql(self, gid, sid, did, scid, coid=None):
"""
This function will generates modified sql for collation object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
coid: Collation ID
"""
data = dict()
for k, v in request.args.items():
try:
data[k] = json.loads(v)
except ValueError:
data[k] = v
try:
SQL = self.get_sql(gid, sid, data, scid, coid)
if SQL and SQL.strip('\n') and SQL.strip(' '):
return make_json_response(
data=SQL,
status=200
)
except Exception as e:
return internal_server_error(errormsg=str(e))
def get_sql(self, gid, sid, data, scid, coid=None):
"""
This function will genrate sql from model data
"""
if coid is not None:
SQL = render_template("/".join([self.template_path,
'properties.sql']),
scid=scid, coid=coid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
old_data = res['rows'][0]
SQL = render_template(
"/".join([self.template_path, 'update.sql']),
data=data, o_data=old_data, conn=self.conn
)
else:
required_args = [
'name'
]
for arg in required_args:
if arg not in data:
return "-- missing definition"
if self._check_definition(data):
return "-- missing definition"
SQL = render_template("/".join([self.template_path,
'create.sql']),
data=data, conn=self.conn)
return SQL.strip('\n')
@check_precondition
def sql(self, gid, sid, did, scid, coid):
"""
This function will generates reverse engineered sql for collation object
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
coid: Collation ID
"""
SQL = render_template("/".join([self.template_path,
'properties.sql']),
scid=scid, coid=coid)
status, res = self.conn.execute_dict(SQL)
if not status:
return internal_server_error(errormsg=res)
data = res['rows'][0]
SQL = render_template("/".join([self.template_path,
'create.sql']),
data=data, conn=self.conn)
sql_header = "-- Collation: {0};\n\n-- ".format(data['name'])
sql_header += render_template("/".join([self.template_path,
'delete.sql']),
name=data['name'])
SQL = sql_header + '\n\n' + SQL.strip('\n')
return ajax_response(response=SQL)
@check_precondition
def dependents(self, gid, sid, did, scid, coid):
"""
This function get the dependents and return ajax response
for the Collation node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
coid: Collation ID
"""
dependents_result = self.get_dependents(
self.conn, coid
)
return ajax_response(
response=dependents_result,
status=200
)
@check_precondition
def dependencies(self, gid, sid, did, scid, coid):
"""
This function get the dependencies and return ajax response
for the Collation node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
scid: Schema ID
coid: Collation ID
"""
dependencies_result = self.get_dependencies(
self.conn, coid
)
return ajax_response(
response=dependencies_result,
status=200
)
CollationView.register_node_view(blueprint)

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

View File

@ -0,0 +1,264 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, alertify) {
if (!pgBrowser.Nodes['coll-collation']) {
var databases = pgAdmin.Browser.Nodes['coll-collation'] =
pgAdmin.Browser.Collection.extend({
node: 'collation',
label: '{{ _('Collations') }}',
type: 'coll-collation',
columns: ['name', 'owner', 'description']
});
};
if (!pgBrowser.Nodes['collation']) {
pgAdmin.Browser.Nodes['collation'] = pgBrowser.Node.extend({
type: 'collation',
label: '{{ _('Collation') }}',
collection_type: 'coll-collation',
hasSQL: true,
hasDepends: true,
parent_type: ['schema', 'catalog'],
Init: function() {
/* Avoid mulitple registration of menus */
if (this.initialized)
return;
this.initialized = true;
pgBrowser.add_menus([{
name: 'create_collation_on_coll', node: 'coll-collation', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Collation...') }}',
icon: 'wcTabIcon icon-collation', data: {action: 'create', check: true},
enable: 'canCreate'
},{
name: 'create_collation', node: 'collation', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Collation...') }}',
icon: 'wcTabIcon icon-collation', data: {action: 'create', check: true},
enable: 'canCreate'
},{
name: 'create_collation', node: 'schema', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Collation...') }}',
icon: 'wcTabIcon icon-collation', data: {action: 'create', check: false},
enable: 'canCreate'
}
]);
},
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
model: pgAdmin.Browser.Node.Model.extend({
defaults: {
name: undefined,
oid: undefined,
owner: undefined,
lc_type: undefined,
lc_collate: undefined,
description: undefined
},
// 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({'owner': userInfo.name}, {silent: true});
this.set({'schema': schemaInfo.label}, {silent: true});
}
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
},
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema'
},{
id: 'oid', label:'{{ _('OID') }}', cell: 'string',
type: 'text' , mode: ['properties']
},{
id: 'owner', label:'{{ _('Owner') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema', control: 'node-list-by-name', node: 'role'
},{
id: 'schema', label:'{{ _('Schema') }}', cell: 'string',
type: 'text', mode: ['create', 'edit'], node: 'schema',
disabled: 'inSchema', 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;
},
control: Backform.NodeListByNameControl.extend({
render: function(){
// Initialize parent's render method
Backform.NodeListByNameControl.prototype.render.apply(this, arguments);
// Set schema default value to its parent Schema
if(this.model.isNew()){
this.model.set({'schema': this.model.node_info.schema.label});
}
return this;
}
})
},{
id: 'copy_collation', label:'{{ _('Copy collation') }}', cell: 'string',
control: 'node-ajax-options',
type: 'text', mode: ['create', 'edit'], group: 'Definition',
url: 'get_collations', disabled: 'inSchemaWithModelCheck',
deps: ['locale', 'lc_collate', 'lc_type']
},{
id: 'locale', label:'{{ _('Locale') }}', cell: 'string',
type: 'text', mode: ['create', 'edit'], group: 'Definition',
disabled: 'inSchemaWithModelCheck',
deps: ['lc_collate', 'lc_type', 'copy_collation']
},{
id: 'lc_collate', label:'{{ _('LC_COLLATE') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'], group: 'Definition',
deps: ['locale', 'copy_collation'], disabled: 'inSchemaWithModelCheck'
},{
id: 'lc_type', label:'{{ _('LC_TYPE') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'], group: 'Definition',
disabled: 'inSchemaWithModelCheck',
deps: ['locale', 'copy_collation']
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema'
}
],
validate: function() {
var err = {},
msg = undefined,
changedAttrs = this.changed,
locale_flag = false,
lc_type_flag = false,
lc_coll_flag = false,
copy_coll_flag = false,
msg = undefined,
data = this.toJSON();
this.errorModel.clear();
if (_.has(changedAttrs,data.name) && _.isUndefined(this.get('name'))
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Name can not be empty!') }}';
this.errorModel.set('name', msg);
}
if (_.has(changedAttrs,data.locale) && (_.isUndefined(this.get('locale'))
|| String(this.get('locale')).replace(/^\s+|\s+$/g, '') == '')) {
locale_flag = true;
}
if (_.has(changedAttrs,data.lc_collate) && (_.isUndefined(this.get('lc_collate'))
|| String(this.get('lc_collate')).replace(/^\s+|\s+$/g, '') == '')) {
lc_coll_flag = true;
}
if (_.has(changedAttrs,data.lc_type) && (_.isUndefined(this.get('lc_type'))
|| String(this.get('lc_type')).replace(/^\s+|\s+$/g, '') == '')) {
lc_type_flag = true;
}
if (_.has(changedAttrs,data.copy_collation) && (_.isUndefined(this.get('copy_collation'))
|| String(this.get('copy_collation')).replace(/^\s+|\s+$/g, '') == '')) {
copy_coll_flag = true;
}
if (locale_flag && (lc_coll_flag || lc_coll_flag) && copy_coll_flag) {
msg = '{{ _('Incomplete definition, Please provide Locale OR Copy collation OR LC_TYPE/LC_COLLATE!') }}';
err['locale'] = msg
}
return null;
},
// We will disable everything if we are under catalog node
inSchema: function() {
if(this.node_info && 'catalog' in this.node_info)
{
return true;
}
return false;
},
// We will check if we are under schema node & in 'create' mode
inSchemaWithModelCheck: function(m) {
if(this.node_info && 'schema' in this.node_info)
{
// Enable copy_collation only if locale & lc_* is not provided
if (m.isNew() && this.name == "copy_collation")
{
if(m.get('locale'))
return true;
if(m.get('lc_collate') || m.get('lc_type'))
return true
return false;
}
// Enable lc_* only if copy_collation & locale is not provided
if (m.isNew() && (this.name == 'lc_collate' || this.name == 'lc_type'))
{
if(m.get('locale'))
return true;
if(m.get('copy_collation'))
return true
return false;
}
// Enable localy only if lc_* & copy_collation is not provided
if (m.isNew() && this.name == 'locale')
{
if(m.get('lc_collate') || m.get('lc_type'))
return true;
if(m.get('copy_collation'))
return true
return false;
}
// We will disbale control if it's in 'edit' mode
if (m.isNew()) {
return false;
} else {
return true;
}
}
return true;
}
}),
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-collation' == d._type) {
//Check if we are not child of catalog
prev_i = t.hasParent(i) ? t.parent(i) : null;
prev_d = prev_i ? t.itemData(prev_i) : null;
if( prev_d._type == 'catalog') {
return false;
} else {
return true;
}
}
i = t.hasParent(i) ? t.parent(i) : null;
d = i ? t.itemData(i) : null;
}
// by default we do not want to allow create menu
return true;
}
});
}
return pgBrowser.Nodes['collation'];
});

View File

@ -0,0 +1,18 @@
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\\%'

View File

@ -0,0 +1,25 @@
{% if data %}
CREATE COLLATION {{ conn|qtIdent(data.schema, data.name) }}
{# if user has provided lc_collate & lc_type #}
{% if data.lc_collate and data.lc_type %}
(LC_COLLATE = {{ data.lc_collate|qtLiteral }}, LC_CTYPE = {{ data.lc_type|qtLiteral }});
{% endif %}
{# if user has provided locale only #}
{% if data.locale %}
(LOCALE = {{ data.locale|qtLiteral }});
{% endif %}
{# if user has choosed to copy from existing collation #}
{% if data.copy_collation %}
FROM {{ data.copy_collation }};
{% endif %}
{% if data.owner %}
ALTER COLLATION {{ conn|qtIdent(data.schema, data.name) }}
OWNER TO {{ conn|qtIdent(data.owner) }};
{% endif %}
{% if data.description %}
COMMENT ON COLLATION {{ conn|qtIdent(data.schema, data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{% endif %}

View File

@ -0,0 +1 @@
DROP COLLATION {{name}}{% if cascade%} CASCADE{% endif %};

View File

@ -0,0 +1,7 @@
SELECT --nspname, collname,
CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
concat(quote_ident(nspname), '.', quote_ident(collname))
ELSE '' END AS copy_collation
FROM pg_collation c, pg_namespace n
WHERE c.collnamespace=n.oid
ORDER BY nspname, collname;

View File

@ -0,0 +1,5 @@
SELECT concat(quote_ident(nspname), '.', quote_ident(collname)) AS name
FROM pg_collation c, pg_namespace n
WHERE c.collnamespace = n.oid AND
n.oid = {{ scid }}::oid AND
c.oid = {{ coid }}::oid;

View File

@ -0,0 +1,8 @@
{# Below will provide oid for newly created collation #}
{% if data %}
SELECT c.oid
FROM pg_collation c, pg_namespace n
WHERE c.collnamespace=n.oid AND
n.nspname = {{ data.schema|qtLiteral }} AND
c.collname = {{ data.name|qtLiteral }}
{% endif %}

View File

@ -0,0 +1,4 @@
SELECT c.oid, c.collname AS name
FROM pg_collation c
WHERE c.collnamespace = {{scid}}::oid
ORDER BY c.collname;

View File

@ -0,0 +1,8 @@
SELECT c.oid, c.collname AS name, c.collcollate AS lc_collate, c.collctype AS lc_type,
pg_get_userbyid(c.collowner) AS owner, description, n.nspname AS schema
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid AND des.classoid='pg_collation'::regclass)
WHERE c.collnamespace = {{scid}}::oid
{% if coid %} AND c.oid = {{coid}}::oid {% endif %}
ORDER BY c.collname;

View File

@ -0,0 +1,26 @@
{% if data %}
{# Change object's owner #}
{% if data.owner and data.owner != o_data.owner %}
ALTER COLLATION {{ conn|qtIdent(o_data.schema, o_data.name) }}
OWNER TO {{ conn|qtIdent(data.owner) }};
{% endif %}
{# Change object's comment #}
{% if data.description and data.description != o_data.description %}
COMMENT ON COLLATION {{ conn|qtIdent(o_data.schema, o_data.name) }}
IS {{ data.description|qtLiteral }};
{% endif %}
{# Change object name #}
{% if data.name and data.name != o_data.name %}
ALTER COLLATION {{ conn|qtIdent(o_data.schema, o_data.name) }}
RENAME TO {{ conn|qtIdent(data.name) }};
{% endif %}
{# Change object schema #}
{% if data.schema and data.schema != o_data.schema %}
ALTER COLLATION {% if data.name and data.name != o_data.name %}{{ conn|qtIdent(o_data.schema, data.name) }}{% else %}{{ conn|qtIdent(o_data.schema, o_data.name) }}{% endif %}
SET SCHEMA {{ conn|qtIdent(data.schema) }};
{% endif %}
{% endif %}