mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add support for casts.
This commit is contained in:
parent
0b1cf1ad2c
commit
f466e0169a
@ -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 |
@ -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'];
|
||||||
|
});
|
@ -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 %}
|
@ -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 %}
|
@ -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
|
@ -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
|
@ -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 %}
|
@ -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;
|
@ -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 %}
|
Loading…
Reference in New Issue
Block a user