Add support for casts.
							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