Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
__init__.py1167 linesDownload Raw Back to schemas
1##########################################################################2#3# pgAdmin 4 - PostgreSQL Tools4#5# Copyright (C) 2013 - 2024, The pgAdmin Development Team6# This software is released under the PostgreSQL Licence7#8##########################################################################9 10import re11from functools import wraps12 13import json14from flask import render_template, request, jsonify, current_app15from flask_babel import gettext16 17from pgadmin.browser.server_groups import servers18from config import PG_DEFAULT_DRIVER19from pgadmin.browser.collection import CollectionNodeModule, PGChildModule20from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \21    parse_priv_to_db22from pgadmin.browser.utils import PGChildNodeView23from pgadmin.utils.ajax import make_json_response, internal_server_error, \24    make_response as ajax_response, gone, bad_request25from pgadmin.utils.driver import get_driver26from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry27from pgadmin.model import Database28 29"""30    This module is responsible for generating two nodes31    1) Schema32    2) Catalog33 34    We have created single file because catalog & schema has same35    functionality, the only difference is we cannot perform DDL/DML operations36    on catalog, also - it allows us to share the same submodules for both37    catalog, and schema modules.38 39    This modules uses separate template paths for each respective node40    - templates/catalog for Catalog node41    - templates/schema for Schema node42 43    [Each path contains node specific js files as well as sql template files.]44"""45 46 47class SchemaModule(CollectionNodeModule):48    """49     class SchemaModule(CollectionNodeModule)50 51        A module class for Schema node derived from CollectionNodeModule.52 53    Methods:54    -------55    * __init__(*args, **kwargs)56      - Method is used to initialize the Schema and it's base module.57 58    * get_nodes(gid, sid, did)59      - Method is used to generate the browser collection node.60 61    * node_inode()62      - Method is overridden from its base class to make the node as leaf node.63 64    * script_load()65      - Load the module script for schema, when any of the server node is66        initialized.67    """68    _NODE_TYPE = 'schema'69    _COLLECTION_LABEL = gettext("Schemas")70 71    def __init__(self, *args, **kwargs):72        """73        Method is used to initialize the SchemaModule and it's base module.74 75        Args:76            *args:77            **kwargs:78        """79        self.min_ver = None80        self.max_ver = None81 82        super().__init__(*args, **kwargs)83 84    def get_nodes(self, gid, sid, did):85        """86        Generate the collection node87        """88        if self.has_nodes(89            sid, did,90            base_template_path=SchemaView.BASE_TEMPLATE_PATH +91                '/' + SchemaView._SQL_PREFIX):92            yield self.generate_browser_collection_node(did)93 94    @property95    def script_load(self):96        """97        Load the module script for schema, when any of the server node is98        initialized.99        """100        return servers.ServerModule.node_type101 102    @property103    def module_use_template_javascript(self):104        """105        Returns whether Jinja2 template is used for generating the javascript106        module.107        """108        return False109 110    def register(self, app, options):111        """112        Override the default register function to automagically register113        sub-modules at once.114        """115        from .aggregates import blueprint as module116        self.submodules.append(module)117 118        from .catalog_objects import blueprint as module119        self.submodules.append(module)120 121        from .collations import blueprint as module122        self.submodules.append(module)123 124        from .domains import blueprint as module125        self.submodules.append(module)126 127        from .foreign_tables import blueprint as module128        self.submodules.append(module)129 130        from .fts_configurations import blueprint as module131        self.submodules.append(module)132 133        from .fts_dictionaries import blueprint as module134        self.submodules.append(module)135 136        from .fts_parsers import blueprint as module137        self.submodules.append(module)138 139        from .fts_templates import blueprint as module140        self.submodules.append(module)141 142        from .functions import blueprint as module143        self.submodules.append(module)144 145        from .functions import trigger_function_blueprint as module146        self.submodules.append(module)147 148        from .functions import procedure_blueprint as module149        self.submodules.append(module)150 151        from .operators import blueprint as module152        self.submodules.append(module)153 154        from .packages import blueprint as module155        self.submodules.append(module)156 157        from .sequences import blueprint as module158        self.submodules.append(module)159 160        from .synonyms import blueprint as module161        self.submodules.append(module)162 163        from .tables import blueprint as module164        self.submodules.append(module)165 166        from .types import blueprint as module167        self.submodules.append(module)168 169        from .views import view_blueprint as module170        self.submodules.append(module)171 172        from .views import mview_blueprint as module173        self.submodules.append(module)174 175        super().register(app, options)176 177 178class CatalogModule(SchemaModule):179    """180     class CatalogModule(SchemaModule)181 182        A module class for the catalog schema node derived from SchemaModule.183    """184 185    _NODE_TYPE = 'catalog'186    _COLLECTION_LABEL = gettext("Catalogs")187 188    def register(self, app, options):189        """190        Override the default register function to automagically register191        sub-modules at once.192        """193        super().register(app, options)194 195    def get_nodes(self, gid, sid, did):196        """197        Generate the collection node198        """199        yield self.generate_browser_collection_node(did)200 201 202schema_blueprint = SchemaModule(__name__)203catalog_blueprint = CatalogModule(__name__)204 205 206def check_precondition(f):207    """208    This function will behave as a decorator which will checks209    database connection before running view, it will also attaches210    manager,conn & template_path properties to instance of the method.211 212    Assumptions:213        This function will always be used as decorator of a class method.214    """215 216    @wraps(f)217    def wrap(*args, **kwargs):218        # Here args[0] will hold self & kwargs will hold gid,sid,did219        self = args[0]220        self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(221            kwargs['sid']222        )223        if not self.manager:224            return gone(errormsg=gettext("Could not find the server."))225 226        self.conn = self.manager.connection(did=kwargs['did'])227        self.datistemplate = False228        if (229            self.manager.db_info is not None and230            kwargs['did'] in self.manager.db_info and231            'datistemplate' in self.manager.db_info[kwargs['did']]232        ):233            self.datistemplate = self.manager.db_info[234                kwargs['did']]['datistemplate']235 236        # Set the template path for the SQL scripts237        self.template_path = self.BASE_TEMPLATE_PATH.format(238            self.manager.server_type, self.manager.version)239 240        return f(*args, **kwargs)241 242    return wrap243 244 245class SchemaView(PGChildNodeView):246    """247    This class is responsible for generating routes for schema node.248 249    Methods:250    -------251    * __init__(**kwargs)252      - Method is used to initialize the SchemaView and it's base view.253 254    * list()255      - This function is used to list all the schema nodes within the256      collection.257 258    * nodes()259      - This function will used to create all the child node within the260        collection, Here it will create all the schema node.261 262    * properties(gid, sid, did, scid)263      - This function will show the properties of the selected schema node.264 265    * create(gid, sid, did, scid)266      - This function will create the new schema object.267 268    * update(gid, sid, did, scid)269      - This function will update the data for the selected schema node.270 271    * delete(self, gid, sid, scid):272      - This function will drop the schema object273 274    * msql(gid, sid, did, scid)275      - This function is used to return modified SQL for the selected schema276        node.277 278    * get_sql(data, scid)279      - This function will generate sql from model data280 281    * sql(gid, sid, did, scid):282      - This function will generate sql to show it in sql pane for the schema283        node.284 285    * dependency(gid, sid, did, scid):286      - This function will generate dependency list show it in dependency287        pane for the selected schema node.288 289    * dependent(gid, sid, did, scid):290      - This function will generate dependent list to show it in dependent291        pane for the selected schema node.292    """293    node_type = schema_blueprint.node_type294    _SQL_PREFIX = 'sql/'295    node_icon = 'icon-%s' % node_type296    BASE_TEMPLATE_PATH = 'schemas/{0}/#{1}#'297 298    parent_ids = [299        {'type': 'int', 'id': 'gid'},300        {'type': 'int', 'id': 'sid'},301        {'type': 'int', 'id': 'did'}302    ]303    ids = [304        {'type': 'int', 'id': 'scid'}305    ]306 307    operations = dict({308        'obj': [309            {'get': 'properties', 'delete': 'delete', 'put': 'update'},310            {'get': 'list', 'post': 'create', 'delete': 'delete'}311        ],312        'children': [{'get': 'children'}],313        'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],314        'sql': [{'get': 'sql'}],315        'msql': [{'get': 'msql'}, {'get': 'msql'}],316        'stats': [{'get': 'statistics'}],317        'dependency': [{'get': 'dependencies'}],318        'dependent': [{'get': 'dependents'}],319        'delete': [{'delete': 'delete'},320                   {'delete': 'delete'}]321    })322 323    def __init__(self, *args, **kwargs):324        """325        Initialize the variables used by methods of SchemaView.326        """327 328        super().__init__(*args, **kwargs)329 330        self.manager = None331        self.conn = None332        self.template_path = None333 334    @staticmethod335    def ppas_template_path(ver):336        """337        Returns the template path for PPAS servers.338        """339        return 'ppas/#{0}#'.format(ver)340 341    @staticmethod342    def pg_template_path(ver):343        """344        Returns the template path for PostgreSQL servers.345        """346        return 'pg/#{0}#'.format(ver)347 348    def format_request_acls(self, data, modified=False, specific=None):349        acls = {}350        try:351            acls = render_template(352                "/".join([self.template_path, 'allowed_privs.json'])353            )354            acls = json.loads(acls)355        except Exception as e:356            current_app.logger.exception(e)357 358        # Privileges359        for aclcol in acls:360            if specific is not None and aclcol not in specific:361                continue362            if aclcol in data:363                allowedacl = acls[aclcol]364                if modified:365                    for modifier in ['added', 'changed', 'deleted']:366                        if modifier in data[aclcol]:367                            data[aclcol][modifier] = parse_priv_to_db(368                                data[aclcol][modifier], allowedacl['acl']369                            )370                else:371                    data[aclcol] = parse_priv_to_db(data[aclcol],372                                                    allowedacl['acl'])373 374        return acls375 376    @staticmethod377    def formatdbacl(acl):378        """379        Args:380            acl: Privileges from ACL query381 382        Returns:383            Formatted output required for client side parsing384        """385        # Reset any data for that acl if its already present in result set386        data = dict()387        for row in acl['rows']:388            priv = parse_priv_from_db(row)389 390            if row['deftype'] in data:391                data[row['deftype']].append(priv)392            else:393                data[row['deftype']] = [priv]394        return data395 396    def _formatter_no_defacl(self, data, scid=None):397        """398        Args:399            data: Result of properties query400            scid: Schema OID401 402        Returns:403            It will return formatted output of collections like404            security lables, privileges405        """406        # Need to format security labels according to client js collection407        seclabels = []408        if 'seclabels' in data and data['seclabels'] is not None:409            for sec in data['seclabels']:410                sec = re.search(r'([^=]+)=(.*$)', sec)411                seclabels.append({412                    'provider': sec.group(1),413                    'label': sec.group(2)414                })415 416        data['seclabels'] = seclabels417 418        # We need to parse & convert ACL coming from database to json format419        SQL = render_template(420            "/".join([self.template_path, 'sql/acl.sql']),421            _=gettext,422            scid=scid,423            conn=self.conn424        )425        status, acl = self.conn.execute_dict(SQL)426        if not status:427            return internal_server_error(errormsg=acl)428 429        data.update(self.formatdbacl(acl))430 431        return data432 433    def _formatter(self, data, scid=None):434 435        self._formatter_no_defacl(data, scid)436 437        # We need to parse & convert DEFAULT ACL coming from438        # database to json format439        SQL = render_template(440            "/".join([self.template_path, 'sql/defacl.sql']),441            _=gettext,442            scid=scid443        )444 445        status, defacl = self.conn.execute_dict(SQL)446        if not status:447            return internal_server_error(errormsg=defacl)448 449        data.update(self.formatdbacl(defacl))450 451        return data452 453    @check_precondition454    def list(self, gid, sid, did):455        """456        This function is used to list all the schema nodes within the457        collection.458 459        Args:460            gid: Server group ID461            sid: Server ID462            did: Database ID463 464        Returns:465            JSON of available schema nodes466        """467        database = Database.query.filter_by(id=did, server=sid).first()468        param = None469        if database:470            schema_restrictions = database.schema_res471 472            if schema_restrictions:473                schema_res = ",".join(474                    ["'%s'"] * len(schema_restrictions.split(',')))475                param = schema_res % (tuple(schema_restrictions.split(',')))476 477        SQL = render_template(478            "/".join([self.template_path,479                      self._SQL_PREFIX + self._PROPERTIES_SQL]),480            _=gettext,481            show_sysobj=self.blueprint.show_system_objects,482            schema_restrictions=param483        )484        status, res = self.conn.execute_dict(SQL)485 486        if not status:487            return internal_server_error(errormsg=res)488        return ajax_response(489            response=res['rows'],490            status=200491        )492 493    @check_precondition494    def nodes(self, gid, sid, did, scid=None, is_schema_diff=False):495        """496        This function will create all the child nodes within the collection497        Here it will create all the schema node.498 499        Args:500            gid: Server Group ID501            sid: Server ID502            did: Database ID503            scid: Schema ID504            is_schema_diff: True if called by schema diff tool505 506        Returns:507            JSON of available schema child nodes508        """509        res = []510        database = Database.query.filter_by(id=did, server=sid).first()511        param = None512        if database:513            schema_restrictions = database.schema_res514 515            if schema_restrictions:516                schema_res = ",".join(517                    ["'%s'"] * len(schema_restrictions.split(',')))518                param = schema_res % (tuple(schema_restrictions.split(',')))519 520        show_system_objects = self.blueprint.show_system_objects521        if is_schema_diff:522            show_system_objects = False523 524        SQL = render_template(525            "/".join([self.template_path, self._SQL_PREFIX + self._NODES_SQL]),526            show_sysobj=show_system_objects,527            _=gettext,528            scid=scid,529            schema_restrictions=param,530            conn=self.conn531        )532 533        status, rset = self.conn.execute_2darray(SQL)534        if not status:535            return internal_server_error(errormsg=rset)536 537        if scid is not None:538            if len(rset['rows']) == 0:539                return gone(gettext(540                    """Could not find the schema in the database.541                    It may have been removed by another user."""))542            row = rset['rows'][0]543            return make_json_response(544                data=self.blueprint.generate_browser_node(545                    row['oid'],546                    did,547                    row['name'],548                    icon=self.node_icon,549                    can_create=row['can_create'],550                    has_usage=row['has_usage'],551                    description=row['description']552                ),553                status=200554            )555 556        for row in rset['rows']:557            res.append(558                self.blueprint.generate_browser_node(559                    row['oid'],560                    did,561                    row['name'],562                    icon=self.node_icon,563                    can_create=row['can_create'],564                    has_usage=row['has_usage'],565                    description=row['description']566                )567            )568 569        return make_json_response(570            data=res,571            status=200572        )573 574    @check_precondition575    def node(self, gid, sid, did, scid):576        """577        This function will fetch the properties of the schema node.578 579        Args:580            gid: Server Group ID581            sid: Server ID582            did: Database ID583            scid: Schema ID584 585        Returns:586            JSON of given schema child node587        """588        SQL = render_template(589            "/".join([self.template_path, self._SQL_PREFIX + self._NODES_SQL]),590            show_sysobj=self.blueprint.show_system_objects,591            _=gettext,592            scid=scid,593            conn=self.conn594        )595 596        status, rset = self.conn.execute_2darray(SQL)597        if not status:598            return internal_server_error(errormsg=rset)599 600        if scid is not None and len(rset['rows']) == 0:601            return gone(gettext("""602Could not find the schema in the database.603It may have been removed by another user.604"""))605 606        for row in rset['rows']:607            return make_json_response(608                data=self.blueprint.generate_browser_node(609                    row['oid'],610                    did,611                    row['name'],612                    icon=self.node_icon,613                    can_create=row['can_create'],614                    has_usage=row['has_usage']615                ),616                status=200617            )618 619    @check_precondition620    def properties(self, gid, sid, did, scid):621        """622        This function will show the properties of the selected schema node.623 624        Args:625            gid: Server Group ID626            sid: Server ID627            did:  Database ID628            scid: Schema ID629 630        Returns:631            JSON of selected schema node632        """633        SQL = render_template(634            "/".join([self.template_path,635                      self._SQL_PREFIX + self._PROPERTIES_SQL]),636            scid=scid,637            _=gettext,638            show_sysobj=self.blueprint.show_system_objects639        )640 641        status, res = self.conn.execute_dict(SQL)642 643        if not status:644            return internal_server_error(errormsg=res)645 646        if len(res['rows']) == 0:647            return gone(gettext(648                "Could not find the schema in the database. "649                "It may have been removed by another user."650            ))651 652        # Making copy of output for future use653        copy_data = dict(res['rows'][0])654        copy_data['is_sys_obj'] = (655            copy_data['oid'] <= self._DATABASE_LAST_SYSTEM_OID or656            self.datistemplate)657        copy_data = self._formatter(copy_data, scid)658 659        return ajax_response(660            response=copy_data,661            status=200662        )663 664    @check_precondition665    def create(self, gid, sid, did):666        """667        This function will create a schema object668 669         Args:670           gid: Server Group ID671           sid: Server ID672           did: Database ID673        """674        data = request.form if request.form else json.loads(675            request.data676        )677 678        for k, v in data.items():679            try:680                # comments should be taken as is because if user enters a681                # json comment it is parsed by loads which should not happen682                if k in ('comment',):683                    data[k] = v684                else:685                    data[k] = json.loads(v)686            except (ValueError, TypeError, KeyError):687                data[k] = v688 689        required_args = {690            'name': 'Name'691        }692 693        for arg in required_args:694            if arg not in data:695                return make_json_response(696                    status=410,697                    success=0,698                    errormsg=gettext(699                        "Could not find the required parameter ({})."700                    ).format(arg)701                )702        try:703            self.format_request_acls(data)704            SQL = render_template(705                "/".join([self.template_path,706                          self._SQL_PREFIX + self._CREATE_SQL]),707                data=data, conn=self.conn, _=gettext708            )709            status, res = self.conn.execute_scalar(SQL)710            if not status:711                return make_json_response(712                    status=410,713                    success=0,714                    errormsg=res715                )716 717            # we need oid to add object in tree at browser,718            # below sql will gives the same719            SQL = render_template(720                "/".join([self.template_path, 'sql/oid.sql']),721                schema=data['name'], _=gettext, conn=self.conn722            )723 724            status, scid = self.conn.execute_scalar(SQL)725            if not status:726                return internal_server_error(errormsg=scid)727 728            return jsonify(729                node=self.blueprint.generate_browser_node(730                    scid,731                    did,732                    data['name'],733                    icon=self.node_icon734                )735            )736        except Exception as e:737            current_app.logger.exception(e)738            return internal_server_error(errormsg=str(e))739 740    @check_precondition741    def update(self, gid, sid, did, scid):742        """743        This function will update an existing schema object744 745         Args:746           gid: Server Group ID747           sid: Server ID748           did: Database ID749           scid: Schema ID750        """751        data = request.form if request.form else json.loads(752            request.data753        )754        try:755            SQL, name = self.get_sql(gid, sid, data, scid)756 757            SQL = SQL.strip('\n').strip(' ')758            status, res = self.conn.execute_scalar(SQL)759            if not status:760                return internal_server_error(errormsg=res)761 762            other_node_info = {}763            if 'description' in data:764                other_node_info['description'] = data['description']765 766            return jsonify(767                node=self.blueprint.generate_browser_node(768                    scid,769                    did,770                    name,771                    icon=self.node_icon,772                    **other_node_info773                )774            )775        except Exception as e:776            return internal_server_error(errormsg=str(e))777 778    @check_precondition779    def delete(self, gid, sid, did, scid=None):780        """781        This function will delete an existing schema object782 783         Args:784           gid: Server Group ID785           sid: Server ID786           did: Database ID787           scid: Schema ID788        """789 790        if scid is None:791            data = request.form if request.form else json.loads(792                request.data793            )794        else:795            data = {'ids': [scid]}796 797        for scid in data['ids']:798            try:799                # Get name for schema from did800                SQL = render_template(801                    "/".join([self.template_path, 'sql/get_name.sql']),802                    _=gettext,803                    scid=scid804                )805 806                status, name = self.conn.execute_scalar(SQL)807                if not status:808                    return internal_server_error(errormsg=name)809 810                if name is None:811                    return make_json_response(812                        status=410,813                        success=0,814                        errormsg=gettext(815                            'Error: Object not found.'816                        ),817                        info=gettext(818                            'The specified schema could not be found.\n'819                        )820                    )821 822                # drop schema823                SQL = render_template(824                    "/".join([self.template_path,825                              self._SQL_PREFIX + self._DELETE_SQL]),826                    _=gettext, name=name, conn=self.conn,827                    cascade=self._check_cascade_operation()828                )829                status, res = self.conn.execute_scalar(SQL)830                if not status:831                    return internal_server_error(errormsg=res)832 833            except Exception as e:834                current_app.logger.exception(e)835                return internal_server_error(errormsg=str(e))836 837        return make_json_response(838            success=1,839            info=gettext("Schema dropped")840        )841 842    @check_precondition843    def msql(self, gid, sid, did, scid=None):844        """845        This function will generate modified sql for schema object based on846        the input from the user. This route is used by the SQL tab in the847        edit/create dialog.848 849         Args:850           gid: Server Group ID851           sid: Server ID852           did: Database ID853           scid: Schema ID (When working with existing schema node)854        """855        data = dict()856        for k, v in request.args.items():857            try:858                # comments should be taken as is because if user enters a859                # json comment it is parsed by loads which should not happen860                if k in ('description',):861                    data[k] = v862                else:863                    data[k] = json.loads(v)864            except ValueError:865                data[k] = v866 867        try:868            SQL, _ = self.get_sql(gid, sid, data, scid)869            if SQL and SQL.strip('\n') and SQL.strip(' '):870                return make_json_response(871                    data=SQL.strip('\n'),872                    status=200873                )874        except Exception as e:875            return internal_server_error(errormsg=str(e))876 877    def get_sql(self, gid, sid, data, scid=None):878        """879        This function will generate sql from model data received from client880        """881        if scid is not None:882            SQL = render_template(883                "/".join([self.template_path,884                          self._SQL_PREFIX + self._PROPERTIES_SQL]),885                _=gettext, scid=scid,886                show_sysobj=self.blueprint.show_system_objects887            )888 889            status, res = self.conn.execute_dict(SQL)890            if not status:891                return internal_server_error(errormsg=res)892            old_data = res['rows'][0]893            # old_data contains all the existing data for requested schema894            old_data = self._formatter(old_data, scid)895 896            # if name is not present in request data then use old name897            if 'name' not in data:898                data['name'] = old_data['name']899 900            # Privileges and Default privileges901            self.format_request_acls(data, True)902 903            SQL = render_template(904                "/".join([self.template_path,905                          self._SQL_PREFIX + self._UPDATE_SQL]),906                _=gettext, data=data, o_data=old_data, conn=self.conn907            )908            return SQL, data['name'] if 'name' in data else old_data['nam']909        else:910            required_args = ['name']911 912            for arg in required_args:913                if arg not in data:914                    return " -- " + gettext("Definition incomplete.")915 916            # Privileges917            self.format_request_acls(data)918 919            SQL = render_template(920                "/".join([self.template_path,921                          self._SQL_PREFIX + self._CREATE_SQL]),922                data=data, conn=self.conn, _=gettext923            )924 925            return SQL, data['name']926 927    @check_precondition928    def sql(self, gid, sid, did, scid):929        """930        This function will generate reverse engineered sql for the schema931        object.932 933         Args:934           gid: Server Group ID935           sid: Server ID936           did: Database ID937           scid: Schema ID938        """939        SQL = render_template(940            "/".join([self.template_path,941                      self._SQL_PREFIX + self._PROPERTIES_SQL]),942            scid=scid, _=gettext943        )944 945        status, res = self.conn.execute_dict(SQL)946        if not status:947            return internal_server_error(errormsg=res)948 949        if len(res['rows']) == 0:950            return gone(gettext(951                'Could not find the schema in the database.'952                ' It may have been removed by another user.'))953 954        data = res['rows'][0]955        data = self._formatter(data, scid)956 957        # Privileges and Default privileges958        self.format_request_acls(data)959 960        # Render sql from create & alter sql using properties & acl data961        SQL = ''962        SQL = render_template(963            "/".join([self.template_path,964                      self._SQL_PREFIX + self._CREATE_SQL]),965            _=gettext, data=data, conn=self.conn, add_not_exists_clause=True966        )967 968        sql_header = "-- SCHEMA: {0}\n\n-- ".format(data['name'])969 970        # drop schema971        sql_header += render_template(972            "/".join([self.template_path,973                      self._SQL_PREFIX + self._DELETE_SQL]),974            _=gettext, name=data['name'], conn=self.conn, cascade=False)975 976        SQL = sql_header + '\n\n' + SQL977 978        return ajax_response(response=SQL.strip("\n"))979 980    @check_precondition981    def dependents(self, gid, sid, did, scid):982        """983        This function gets the dependencies and returns an ajax response.984        for the schema node.985 986        Args:987            gid: Server Group ID988            sid: Server ID989            did: Database ID990            scid: Schema ID991        """992        dependents_result = self.get_dependents(self.conn, scid)993        return ajax_response(994            response=dependents_result,995            status=200996        )997 998    @check_precondition999    def dependencies(self, gid, sid, did, scid):1000        """1001        This function get the dependencies and return ajax response1002        for the schema node.1003 1004        Args:1005            gid: Server Group ID1006            sid: Server ID1007            did: Database ID1008            scid: Schema ID1009        """1010        dependencies_result = self.get_dependencies(self.conn, scid)1011        return ajax_response(1012            response=dependencies_result,1013            status=2001014        )1015 1016    @check_precondition1017    def children(self, **kwargs):1018        """Build a list of treeview nodes from the child nodes."""1019 1020        SQL = render_template(1021            "/".join([self.template_path, 'sql/is_catalog.sql']),1022            scid=kwargs['scid'], _=gettext, conn=self.conn1023        )1024 1025        status, res = self.conn.execute_dict(SQL)1026 1027        if not status:1028            return internal_server_error(errormsg=res)1029 1030        if len(res['rows']) == 0:1031            return gone(gettext(1032                """Could not find the schema in the database.1033                It may have been removed by another user."""))1034 1035        data = res['rows'][0]1036        backend_support_keywords = kwargs.copy()1037        backend_support_keywords['is_catalog'] = data['is_catalog']1038        backend_support_keywords['db_support'] = data['db_support']1039        backend_support_keywords['schema_name'] = data['schema_name']1040 1041        nodes = []1042        for module in self.blueprint.submodules:1043            if isinstance(module, PGChildModule):1044                if (1045                    self.manager is not None and1046                    module.backend_supported(1047                        self.manager, **backend_support_keywords1048                    )1049                ):1050                    nodes.extend(module.get_nodes(**kwargs))1051            else:1052                nodes.extend(module.get_nodes(**kwargs))1053 1054        return make_json_response(data=nodes)1055 1056 1057class CatalogView(SchemaView):1058    """1059    This class is responsible for generating routes for catalog schema node.1060 1061    Methods:1062    -------1063    * __init__(**kwargs)1064      - Method is used to initialize the CatalogView and it's base view.1065 1066    * create(gid, sid, did, scid)1067      - Raise an error - we cannot create a catalog.1068 1069    * update(gid, sid, did, scid)1070      - This function will update the data for the selected catalog node1071 1072    * delete(self, gid, sid, scid):1073      - Raise an error - we cannot delete a catalog.1074 1075    * get_sql(data, scid)1076      - This function will generate sql from model data1077 1078    """1079 1080    node_type = catalog_blueprint.node_type1081    BASE_TEMPLATE_PATH = 'catalog/{0}/#{1}#'1082 1083    def __init__(self, *args, **kwargs):1084        """1085        Initialize the variables used by methods of SchemaView.1086        """1087 1088        super().__init__(*args, **kwargs)1089 1090    def _formatter(self, data, scid=None):1091 1092        """1093        Overriding _formatter, because - we won't show the Default1094        privileges with the catalog schema.1095        """1096 1097        self._formatter_no_defacl(data, scid)1098 1099        return data1100 1101    def get_sql(self, gid, sid, data, scid=None):1102        """1103        This function will generate sql from model data1104        """1105        if scid is None:1106            return bad_request('Cannot create a catalog schema!')1107 1108        return super().get_sql(gid, sid, data, scid)1109 1110    @check_precondition1111    def sql(self, gid, sid, did, scid):1112        """1113        This function will generate reverse engineered sql for schema object1114 1115         Args:1116           gid: Server Group ID1117           sid: Server ID1118           did: Database ID1119           scid: Schema ID1120        """1121        SQL = render_template(1122            "/".join([self.template_path,1123                      self._SQL_PREFIX + self._PROPERTIES_SQL]),1124            scid=scid, _=gettext1125        )1126 1127        status, res = self.conn.execute_dict(SQL)1128        if not status:1129            return internal_server_error(errormsg=res)1130 1131        if len(res['rows']) == 0:1132            return gone(gettext("""1133Could not find the schema in the database.1134It may have been removed by another user.1135"""))1136 1137        old_data = res['rows'][0]1138        old_data = self._formatter(old_data, scid)1139 1140        # Privileges1141        self.format_request_acls(old_data, specific=['nspacl'])1142 1143        # Render sql from create & alter sql using properties & acl data1144        SQL = ''1145        SQL = render_template(1146            "/".join([self.template_path,1147                      self._SQL_PREFIX + self._CREATE_SQL]),1148            _=gettext, data=old_data, conn=self.conn,1149            add_not_exists_clause=True1150        )1151 1152        sql_header = """1153-- CATALOG: {0}1154 1155-- DROP SCHEMA IF EXISTS {0};1156 1157""".format(old_data['name'])1158 1159        SQL = sql_header + SQL1160 1161        return ajax_response(response=SQL.strip("\n"))1162 1163 1164SchemaDiffRegistry(schema_blueprint.node_type, SchemaView)1165SchemaView.register_node_view(schema_blueprint)1166CatalogView.register_node_view(catalog_blueprint)1167 
codekingpro/portable-devtools · Team Ai