Add support for casts.

This commit is contained in:
Sanket Mehta 2016-02-24 16:44:37 +00:00 committed by Dave Page
parent 0b1cf1ad2c
commit f466e0169a
11 changed files with 1153 additions and 0 deletions

View File

@ -0,0 +1,643 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2016, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""Implements Cast Node"""
import json
from flask import render_template, make_response, current_app, 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
from pgadmin.browser.collection import CollectionNodeModule
import pgadmin.browser.server_groups.servers.databases as databases
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 CastModule(CollectionNodeModule):
"""
class CastModule(CollectionNodeModule)
A module class for Cast node derived from CollectionNodeModule.
Methods:
-------
* __init__(*args, **kwargs)
- Method is used to initialize the CastModule and it's base module.
* get_nodes(gid, sid, did)
- 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 cast, when any of the database node is
initialized.
"""
NODE_TYPE = 'cast'
COLLECTION_LABEL = 'Casts'
def __init__(self, *args, **kwargs):
super(CastModule, self).__init__(*args, **kwargs)
def get_nodes(self, gid, sid, did):
"""
Generate the collection node
:param gid: group id
:param sid: server id
:param did: database id
"""
yield self.generate_browser_collection_node(did)
@property
def node_inode(self):
"""
Override the property to make the node as leaf node
"""
return False
@property
def script_load(self):
"""
Load the module script for cast, when any of the database node is
initialized.
"""
return databases.DatabaseModule.NODE_TYPE
blueprint = CastModule(__name__)
class CastView(NodeView):
"""
class CastView(NodeView)
A view class for cast node derived from NodeView. This class is
responsible for all the stuff related to view like create/update/delete cast,
showing properties of cast node, showing sql in sql pane.
Methods:
-------
* __init__(**kwargs)
- Method is used to initialize the CastView and it's base view.
* module_js()
- This property defines (if javascript) exists for this node.
Override this property for your own logic
* 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 cast nodes within that collection.
* nodes()
- This function will used to create all the child node within that collection.
Here it will create all the cast nodes.
* properties(gid, sid, did, rg_id)
- This function will show the properties of the selected cast node
* create(gid, sid, did, rg_id)
- This function will create the new cast object
* update(gid, sid, did, rg_id)
- This function will update the data for the selected cast node
* delete(self, gid, sid, rg_id):
- This function will drop the cast object
* msql(gid, sid, did, rg_id)
- This function is used to return modified SQL for the selected cast node
* get_sql(data, rg_id)
- This function will generate sql from model data
* sql(gid, sid, did, rg_id):
- This function will generate sql to show in sql pane for the selected cast node.
* get_type():
- This function will fetch all the types for source and target types select control.
* get_functions():
- This function will fetch associated functions list depending on selected source
and target types while creating a new cast node.
"""
node_type = blueprint.node_type
parent_ids = [
{'type': 'int', 'id': 'gid'},
{'type': 'int', 'id': 'sid'},
{'type': 'int', 'id': 'did'}
]
ids = [
{'type': 'int', 'id': 'cid'}
]
operations = dict({
'obj': [
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
{'get': 'list', 'post': 'create'}
],
'children': [{
'get': 'children'
}],
'delete': [{'delete': 'delete'}],
'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_type': [{'get': 'get_src_and_trg_type'}, {'get': 'get_src_and_trg_type'}],
'get_functions': [{'post': 'get_functions'}, {'post': 'get_functions'}]
})
def _init_(self, **kwargs):
self.conn = None
self.template_path = None
self.manager = None
super(CastView, self).__init__(**kwargs)
def module_js(self):
"""
This property defines whether javascript exists for this node.
"""
return make_response(
render_template(
"cast/js/casts.js",
_=gettext
),
200, {'Content-Type': 'application/x-javascript'}
)
def check_precondition(f):
"""
This function will behave as a decorator which will check the
database connection before running view. It will also attach
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!"
)
)
ver = self.manager.version
# we will set template path for sql scripts
if ver >= 90100:
self.template_path = 'cast/sql/9.1_plus'
return f(*args, **kwargs)
return wrap
@check_precondition
def list(self, gid, sid, did):
"""
This function is used to list all the cast nodes within the collection.
:param gid: group id
:param sid: server id
:param did: database id
:return:
"""
sql = render_template(
"/".join([self.template_path, 'properties.sql']),
datlastsysoid=self.manager.db_info[did]['datlastsysoid']
)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
for row in res['rows']:
row['castcontext'] = True if row['castcontext'] == 'IMPLICIT' else False
return ajax_response(
response=res['rows'],
status=200
)
@check_precondition
def nodes(self, gid, sid, did):
"""
This function will used to create all the child nodes within the collection.
Here it will create all the cast nodes.
:param gid: group id
:param sid: server id
:param did: database id
:return:
"""
res = []
sql = render_template(
"/".join([self.template_path, 'properties.sql']),
datlastsysoid=self.manager.db_info[did]['datlastsysoid']
)
status, rset = self.conn.execute_2darray(sql)
if not status:
return internal_server_error(errormsg=rset)
for row in rset['rows']:
row['castcontext'] = True if row['castcontext'] == 'IMPLICIT' else False
res.append(
self.blueprint.generate_browser_node(
row['oid'],
did,
row['name'],
icon="icon-cast"
))
return make_json_response(
data=res,
status=200
)
@check_precondition
def properties(self, gid, sid, did, cid):
"""
This function will show the properties of the selected cast node
:param gid: group id
:param sid: server id
:param did: database id
:param cid: cast id
:return:
"""
sql = render_template(
"/".join([self.template_path, 'properties.sql']),
cid=cid,
datlastsysoid=self.manager.db_info[did]['datlastsysoid']
)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
result = res['rows'][0]
return ajax_response(
response=res['rows'][0],
status=200
)
@check_precondition
def create(self, gid, sid, did):
"""
This function will creates new the cast object
:param did: database id
:param sid: server id
:param gid: group id
:return:
"""
required_args = [
'srctyp',
'trgtyp'
]
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)." % arg
)
)
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, below sql will gives the same
sql = render_template("/".join([self.template_path, 'properties.sql']),
srctyp=data['srctyp'],
trgtyp=data['trgtyp'],
datlastsysoid=self.manager.db_info[did]['datlastsysoid']
)
status, cid = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=cid)
return jsonify(
node=self.blueprint.generate_browser_node(
cid,
did,
data['name'],
icon="icon-cast"
)
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def update(self, gid, sid, did, cid):
"""
This function will update cast object
:param cid: cast id
:param did: database id
:param sid: server id
:param gid: group id
:return:
"""
data = request.form if request.form else json.loads(request.data.decode())
sql = self.get_sql(gid, sid, did, data, cid)
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="Cast updated",
data={
'id': cid,
'sid': sid,
'gid': gid,
'did': did
}
)
else:
return make_json_response(
success=1,
info="Nothing to update",
data={
'id': cid,
'sid': sid,
'gid': gid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def delete(self, gid, sid, did, cid):
"""
This function will drop the cast object
:param cid: cast id
:param did: database id
:param sid: server id
:param gid: group id
:return:
"""
# 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:
# Get name for cast from cid
sql = render_template("/".join([self.template_path, 'delete.sql']),
cid=cid)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
# drop cast
result = res['rows'][0]
sql = render_template("/".join([self.template_path, 'delete.sql']),
castsource=result['castsource'],
casttarget=result['casttarget'],
cascade=cascade
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(
success=1,
info=gettext("Cast dropped"),
data={
'id': cid,
'sid': sid,
'gid': gid,
'did': did
}
)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def msql(self, gid, sid, did, cid=None):
"""
This function returns modified SQL
:param cid: cast id
:param did: database id
:param sid: server id
:param gid: group id
:return:
"""
data = request.args
sql = self.get_sql(gid, sid, did, data, cid)
if isinstance(sql, str) and sql and sql.strip('\n') and sql.strip(' '):
return make_json_response(
data=sql,
status=200
)
else:
return make_json_response(
data="--modified SQL",
status=200
)
def get_sql(self, gid, sid, did, data, cid=None):
"""
This function will return sql for model data
:param gid: group id
:param sid: server id
:param did: database id
:param cid: cast id
:param data: model data
:return:
"""
try:
if cid is not None:
sql = render_template("/".join([self.template_path, 'properties.sql']),
cid=cid,
datlastsysoid=self.manager.db_info[did]['datlastsysoid'])
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
)
else:
if 'srctyp' in data and 'trgtyp' in data:
sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
else:
sql = "-- incomplete definition"
return str(sql)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def get_functions(self, gid, sid, did, cid=None):
"""
This function will return functions list associated with a cast
:param gid: group id
:param sid: server id
:param did: database id
:param cid: cast id
:return:
"""
res = []
data = request.form if request.form else json.loads(request.data.decode())
sql = render_template("/".join([self.template_path, 'functions.sql']),
srctyp=data['srctyp'],
trgtyp=data['trgtyp'])
status, rset = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=rset)
res.append({'label': '',
'value': ''})
for row in rset['rows']:
res.append({'label': row['proname'],
'value': row['proname']})
return make_json_response(
data=res,
status=200
)
@check_precondition
def get_src_and_trg_type(self, gid, sid, did, cid=None):
"""
This function will return type list
:param gid: group id
:param sid: server id
:param did: database id
:param cid: cast id
:return:
"""
res = []
sql = render_template(
"/".join([self.template_path, 'getsrcandtrgttype.sql']),
cid=cid
)
status, rset = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=rset)
res = [{'label': '', 'value': ''}]
for row in rset['rows']:
res.append({
'label': row['typname'],
'value': row['typname']
})
return make_json_response(
data=res,
status=200
)
@check_precondition
def sql(self, gid, sid, did, cid):
"""
This function will generate sql for sql panel
:param gid: group id
:param sid: server id
:param did: database id
:param cid: cast id
:return:
"""
try:
sql = render_template(
"/".join([self.template_path, 'sql.sql']),
cid=cid,
conn=self.conn
)
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(
_("ERROR: Couldn't generate reversed engineered SQL for the cast!\n{0}").format(
res
)
)
if res is None:
return gone(
_("ERROR: Couldn't generate reversed engineered SQL for the cast node!")
)
return ajax_response(response=res)
except Exception as e:
return internal_server_error(errormsg=str(e))
@check_precondition
def dependents(self, gid, sid, did, cid):
"""
This function gets the dependents and returns an ajax response
for the cast node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
cid: Cast ID
"""
dependents_result = get_dependents(self.conn, cid, 'language')
return ajax_response(
response=dependents_result,
status=200
)
@check_precondition
def dependencies(self, gid, sid, did, cid):
"""
This function gets the dependencies and returns an ajax response
for the cast node.
Args:
gid: Server Group ID
sid: Server ID
did: Database ID
cid: Cast ID
"""
dependencies_result = get_dependencies(self.conn, cid, 'language')
return ajax_response(
response=dependencies_result,
status=200
)
CastView.register_node_view(blueprint)

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

View File

@ -0,0 +1,302 @@
define(
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, alertify) {
// Extend the collection class for cast
if (!pgBrowser.Nodes['coll-cast']) {
var casts = pgAdmin.Browser.Nodes['coll-cast'] =
pgAdmin.Browser.Collection.extend({
node: 'cast',
label: '{{ _('Casts') }}',
type: 'coll-cast',
columns: ['name', 'description']
});
};
// Extend the node class for cast
if (!pgBrowser.Nodes['cast']) {
pgAdmin.Browser.Nodes['cast'] = pgAdmin.Browser.Node.extend({
parent_type: 'database',
type: 'cast',
canDrop: true,
canDropCascade: true,
label: '{{ _('Cast') }}',
hasSQL: true,
hasDepends: true,
Init: function() {
// Avoid multiple registration of menus
if (this.initialized)
return;
this.initialized = true;
// Add context menus for cast
pgBrowser.add_menus([{
name: 'create_cast_on_database', node: 'database', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Cast...') }}',
icon: 'wcTabIcon icon-cast', data: {action: 'create'}
},{
name: 'create_cast_on_coll', node: 'coll-cast', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Cast...') }}',
icon: 'wcTabIcon icon-cast', data: {action: 'create'}
},{
name: 'create_cast', node: 'cast', module: this,
applies: ['object', 'context'], callback: 'show_obj_properties',
category: 'create', priority: 4, label: '{{ _('Cast...') }}',
icon: 'wcTabIcon icon-cast', data: {action: 'create'}
}]);
},
// Define the backform model for cast node
model: pgAdmin.Browser.Node.Model.extend({
defaults: {
name: undefined, // Name of the cast
encoding: 'UTF8',
srctyp: undefined, // Source type
trgtyp: undefined, // Target type
proname: undefined, // Function
castcontext: undefined, // Context (IMPLICIT/EXPLICIT/ASSIGNMENT)
syscast: undefined, // Is this cast is system object? Yes/No
description: undefined // Comment on the cast
},
// Define the schema for cast
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string', group: '{{ _('Definition') }}',
editable: false, type: 'text', disabled: true, cellHeaderClasses: 'width_percent_50'
},{
id: 'oid', label:'{{ _('Oid') }}', cell: 'string', group: '{{ _('Definition') }}',
editable: false, type: 'text', disabled: true
},{
id: 'srctyp', label:'{{ _('Source type') }}', url: 'get_type',
type: 'text', group: 'Definition', disabled: function(m) {
return !m.isNew()
}, mode: ['create'],
transform: function(rows) {
_.each(rows, function(r) {
r['image'] = 'icon-cast';
});
return rows;
},
/*
* Control is extended to create cast name from source type and destination type
* once their values are changed
*/
control: Backform.NodeAjaxOptionsControl.extend({
onChange: function() {
Backform.NodeAjaxOptionsControl.prototype.onChange.apply(
this, arguments
);
/*
* On source type change, check if both source type and
* target type are set, if yes then fetch values from both
* controls and generate cast name
*/
var srctype = this.model.get('srctyp');
var trgtype = this.model.get('trgtyp');
if(srctype != undefined && srctype != '' &&
trgtype != undefined && trgtype != '')
this.model.set("name", srctype+"->"+trgtype);
else
this.model.unset("name");
}
})
},
/*
* Text control for viewing source type in properties and
* edit mode only
*/
{
id: 'srctyp', label:'{{ _('Source type') }}', type: 'text',
group: 'Definition', disabled: true, mode:['properties','edit']
},{
id: 'trgtyp', label:'{{ _('Target type') }}', url: 'get_type',
type: 'text', group: 'Definition', disabled: function(m) {
return !m.isNew()
}, mode: ['create'],
transform: function(rows) {
_.each(rows, function(r) {
r['image'] = 'icon-cast';
});
return rows;
},
/*
* Control is extended to create cast name from source type and destination type
* once their values are changed
*/
control: Backform.NodeAjaxOptionsControl.extend({
onChange: function() {
Backform.NodeAjaxOptionsControl.prototype.onChange.apply(
this, arguments
);
/*
* on target type change, check if both source type and
* target type are set, if yes then fetch values from both
* controls and generate cast name
*/
var srcType = this.model.get('srctyp');
var trgtype = this.model.get('trgtyp');
if(srcType != undefined && srcType != '' &&
trgtype != undefined && trgtype != '')
this.model.set("name", srcType+"->"+trgtype);
else
this.model.unset("name");
}
})
},
/*
* Text control for viewing target type in properties and
* edit mode only
*/
{
id: 'trgtyp', label:'{{ _('Target type') }}', type: 'text',
group: 'Definition', disabled: true, mode:['properties','edit']
},
/*
* Proname field is dependent on source type and target type.
* On source and target type changed event,
* associated functions will be fetch using ajax call
*/
{
id: 'proname', label:'{{ _('Function') }}', deps:['srctyp', 'trgtyp'],
type: 'text', disabled: function(m) { return !m.isNew(); },
group: 'Definition', mode: ['create'],
control: 'node-ajax-options',
options: function() {
var srcTyp = this.model.get('srctyp');
var trgtyp = this.model.get('trgtyp');
var res = [];
if(srcTyp != undefined && srcTyp != '' &&
trgtyp != undefined && trgtyp != '')
{
var node = this.field.get('schema_node'),
_url = node.generate_url.apply(
node, [
null, 'get_functions', this.field.get('node_data'), false,
this.field.get('node_info')
]);
$.ajax({
type: 'POST',
timeout: 30000,
url: _url,
cache: false,
async: false,
data: {"srctyp" : srcTyp, "trgtyp" : trgtyp},
// On success return function list from server
success: function(result) {
res = result.data;
return res;
},
// On failure show error appropriate error message to user
error: function(xhr, status, error) {
try {
var err = $.parseJSON(xhr.responseText);
if (err.success == 0) {
msg = S('{{ _(' + err.errormsg + ')}}').value();
alertify.error("{{ _('" + err.errormsg + "') }}");
}
} catch (e) {}
}
});
}
return res;
}
},
/*
* Text type control for viewing function name in properties and
* edit mode only
*/
{
id: 'proname', label:'{{ _('Function') }}', type: 'text',
group: 'Definition', disabled: true, mode:['properties','edit']
},{
id: 'castcontext', label:'{{ _('Context') }}',
options:{'onText':'IMPLICIT','offText':'EXPLICIT'},
editable: false, type: 'string', group: 'Definition',
mode:['create'],
control: Backform.SwitchControl.extend({
getValueFromDOM: function() {
return this.$input.prop('checked') ? 'IMPLICIT' : 'EXPLICIT';
}
})
},
/*
* Text control for viewing context in properties and
* edit mode
*/
{
id: 'castcontext', label:'{{ _('Context') }}', disabled: true,
options:[{
label: 'IMPLICIT', value: 'IMPLICIT'
},{
label: 'EXPLICIT', value: 'EXPLICIT'
},{
label: 'ASSIGNMENT', value: 'ASSIGNMENT'
}], editable: false, type: 'select2', group: 'Definition',
mode:['properties', 'edit']
},{
id: 'syscast', label:'{{ _('System Cast?') }}', mode: ['properties'],
editable: false, type: 'text'
},{
id: 'description', label:'{{ _('Comment') }}',type: 'text', group: 'Definition',
type: 'multiline', cellHeaderClasses: 'width_percent_50'
}
],
/*
* Triggers control specific error messages for source type and
* target type if any one of them is not selected while creating
* new cast
*/
validate: function(keys){
var srctype = this.get('srctyp');
var trgtype = this.get('trgtyp');
// validate source type control
if (_.isUndefined(srctype) || _.isNull(srctype) || String(srctype).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Source type must be selected!') }}';
this.errorModel.set('srctyp', msg);
return msg;
}
else
{
this.errorModel.unset('srctyp');
}
// validate target type control
if (_.isUndefined(trgtype) || _.isNull(trgtype) || String(trgtype).replace(/^\s+|\s+$/g, '') == '') {
var msg = '{{ _('Target type must be selected!') }}';
this.errorModel.set('trgtyp', msg);
return msg;
}
else
{
this.errorModel.unset('trgtyp');
}
this.trigger('on-status-clear');
return null;
}
})
});
}
return pgBrowser.Nodes['coll-cast'];
});

View File

@ -0,0 +1,20 @@
{# CREATE CAST Statement #}
{% if is_sql %}
-- Cast: {{conn|qtTypeIdent(data.srctyp)}}->{{ conn|qtTypeIdent(data.trgtyp) }};
-- DROP CAST ({{ conn|qtTypeIdent(data.srctyp) }} AS {{ conn|qtTypeIdent(data.trgtyp) }});
{% endif %}
{% if data and data.srctyp and data.trgtyp %}
CREATE CAST ({{ conn|qtTypeIdent(data.srctyp) }} AS {{ conn|qtTypeIdent(data.trgtyp) }})
{% if data.proname and data.proname != 'binary compatible'%}
WITH FUNCTION {{data.proname}}{% else %}
WITHOUT FUNCTION{% endif %}
{% if data.castcontext and data.castcontext != 'EXPLICIT' %}
AS {{data.castcontext}}{% endif %};
{# Description for CAST #}
{% if data.description %}
COMMENT ON CAST ({{ conn|qtTypeIdent(data.srctyp) }} AS {{ conn|qtTypeIdent(data.trgtyp) }})
IS {{ data.description|qtLiteral }};
{% endif %}{% endif %}

View File

@ -0,0 +1,14 @@
{# FETCH CAST SOURCE TYPE AND TARGET TYPE Statement #}
{% if cid %}
SELECT
format_type(ca.castsource, null) as castsource,
format_type(ca.casttarget, null) as casttarget
FROM
pg_cast ca
WHERE
ca.oid = {{cid}}::OID;
{% endif %}
{# DROP CAST Statement #}
{% if castsource and casttarget %}
DROP CAST ({{castsource}} AS {{casttarget}}) {% if cascade %}CASCADE{%endif%};
{% endif %}

View File

@ -0,0 +1,17 @@
{# FETCH FUNCTIONS depending upon SOURCE TYPE and TARGET TYPE IN CAST #}
SELECT
proname || '(' || pg_catalog.pg_get_function_identity_arguments(p.oid) || ')' as proname,
nspname,
proargtypes
FROM
pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace
WHERE
proargtypes[0] = (SELECT t.oid FROM pg_type t WHERE format_type(t.oid, NULL) = {{srctyp|qtLiteral}})
AND prorettype = (SELECT t.oid FROM pg_type t WHERE format_type(t.oid, NULL) = {{trgtyp|qtLiteral}})
AND CASE
WHEN array_length(proargtypes,1) = 2 THEN
proargtypes[1] = 23
WHEN array_length(proargtypes,1) >= 3 THEN
proargtypes[1] = 23 AND proargtypes[2] = 16
ELSE TRUE
END

View File

@ -0,0 +1,46 @@
SELECT
*
FROM (
SELECT
format_type(t.oid,NULL) AS typname,
CASE
WHEN typelem > 0 THEN typelem
ELSE t.oid
END as elemoid,
typlen,
typtype,
t.oid,
nspname,
(SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup
FROM
pg_type t
JOIN pg_namespace nsp ON typnamespace=nsp.oid
WHERE
(NOT (typname = 'unknown'
AND nspname = 'pg_catalog'))
AND typisdefined
AND typtype IN ('b', 'c', 'e', 'r')
AND NOT EXISTS (
SELECT
1
FROM
pg_class
WHERE
relnamespace = typnamespace
AND relname = typname
AND relkind != 'c')
AND (typname NOT LIKE '_%'
OR NOT EXISTS (
SELECT
1
FROM
pg_class
WHERE
relnamespace = typnamespace
AND relname = SUBSTRING(typname FROM 2)::name
AND relkind != 'c'
)
)
AND nsp.nspname != 'information_schema' ) AS dummy
ORDER BY
nspname <> 'pg_catalog', nspname <> 'public', nspname, 1

View File

@ -0,0 +1,61 @@
{# Get OID for CAST #}
{% if srctyp and trgtyp %}
SELECT
ca.oid
FROM pg_cast ca
WHERE ca.castsource = (SELECT t.oid FROM pg_type t WHERE format_type(t.oid, NULL) = {{srctyp|qtLiteral}})
AND ca.casttarget = (SELECT t.oid FROM pg_type t WHERE format_type(t.oid, NULL) = {{trgtyp|qtLiteral}})
{% if datlastsysoid %}
AND ca.oid > {{datlastsysoid}}::OID
{% endif %}
{# FETCH properties for CAST #}
{% else %}
SELECT
ca.oid,
CASE
WHEN {{datlastsysoid}}::OID > ca.oid then 'Yes' ELSE 'No'
END AS syscast,
CASE
WHEN ca.castcontext = 'a' THEN 'ASSIGNMENT'
WHEN ca.castcontext = 'i' THEN 'IMPLICIT'
WHEN ca.castcontext = 'e' THEN 'EXPLICIT'
END AS castcontext,
CASE
WHEN proname IS NULL THEN 'binary compatible'
ELSE proname || '(' || pg_catalog.pg_get_function_identity_arguments(pr.oid) || ')'
END AS proname,
ca.castfunc,
format_type(st.oid,NULL) AS srctyp,
format_type(tt.oid,tt.typtypmod) AS trgtyp,
ns.nspname AS srcnspname,
nt.nspname AS trgnspname,
np.nspname AS pronspname,
description,
concat(format_type(st.oid,NULL),'->',format_type(tt.oid,tt.typtypmod)) as name
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_namespace ns ON ns.oid=st.typnamespace
JOIN pg_type tt ON tt.oid=casttarget
JOIN pg_namespace nt ON nt.oid=tt.typnamespace
LEFT JOIN pg_proc pr ON pr.oid=castfunc
LEFT JOIN pg_namespace np ON np.oid=pr.pronamespace
LEFT OUTER JOIN pg_description des ON (des.objoid=ca.oid AND des.objsubid=0 AND des.classoid='pg_cast'::regclass)
{% if cid %}
WHERE ca.oid={{cid}}::int
{% endif %}
--TODO: add check for showSystemObject(). currently assumed as false
{#
{% if datlastsysoid %}
{% if cid %}
AND
{% else %}
WHERE
{% endif %}
ca.oid > {{datlastsysoid}}::OID
{% endif %}
#}
ORDER BY st.typname, tt.typname
{% endif %}

View File

@ -0,0 +1,44 @@
SELECT
array_to_string(array_agg(sql), E'\n\n') as sql
FROM
(SELECT
E'-- Cast: ' ||
format_type(st.oid, null)|| E' -> ' ||
format_type(tt.oid, tt.typtypmod) ||
E'\n\n-- DROP CAST (' || format_type(st.oid, null) ||
E' AS ' || format_type(tt.oid,tt.typtypmod) ||
E');\n\n CREATE CAST (' || format_type(st.oid, null) ||
E' AS ' || format_type(tt.oid,tt.typtypmod) || E')\n' ||
CASE WHEN ca.castfunc != 0 THEN
E'\tWITH FUNCTION ' ||
pr.proname || '(' || COALESCE(pg_catalog.pg_get_function_identity_arguments(pr.oid), '') || E')'
WHEN ca.castfunc = 0 AND ca.castmethod = 'i' THEN
E'\tWITH INOUT'
ELSE E'\tWITHOUT FUNCTION' END ||
CASE WHEN ca.castcontext = 'a' THEN E'\n\tAS ASSIGNMENT;'
WHEN ca.castcontext = 'i' THEN E'\n\tAS IMPLICIT;'
ELSE E';' END ||
CASE WHEN a.description IS NOT NULL THEN
E'\n\nCOMMENT ON CAST (' || (format_type(st.oid,NULL)) ||
E' AS ' || (format_type(tt.oid,tt.typtypmod)) ||
E') IS ' || pg_catalog.quote_literal(description) || E';'
ELSE '' END as sql
FROM
pg_cast ca
JOIN pg_type st ON st.oid=ca.castsource
JOIN pg_namespace ns ON ns.oid=st.typnamespace
JOIN pg_type tt ON tt.oid=ca.casttarget
JOIN pg_namespace nt ON nt.oid=tt.typnamespace
LEFT JOIN pg_proc pr ON pr.oid=ca.castfunc
LEFT JOIN (
SELECT
des.description as description,
des.objoid as descoid
FROM
pg_description des
WHERE
des.objoid={{cid}}::OID AND des.objsubid=0 AND des.classoid='pg_cast'::regclass
) a ON (a.descoid = ca.oid)
WHERE
ca.oid={{cid}}::OID
) c;

View File

@ -0,0 +1,6 @@
{# UPDATE Description for CAST #}
{% if data and 'description' in data and data.description != o_data.description %}
COMMENT ON CAST ({{ conn|qtTypeIdent(o_data.srctyp) }} AS {{ conn|qtTypeIdent(o_data.trgtyp) }})
IS {{ data.description|qtLiteral }};
{% endif %}