????

Your IP : 216.73.216.72


Current Path : C:/opt/pgsql/pgAdmin 4/web/pgadmin/tools/sqleditor/
Upload File :
Current File : C:/opt/pgsql/pgAdmin 4/web/pgadmin/tools/sqleditor/__init__.py

##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2024, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################

"""A blueprint module implementing the sqleditor frame."""
import os
import pickle
import re
import secrets
from urllib.parse import unquote
from threading import Lock
import threading

import json
from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD, SHARED_STORAGE
from werkzeug.user_agent import UserAgent
from flask import Response, url_for, render_template, session, current_app
from flask import request
from flask_babel import gettext
from pgadmin.user_login_check import pga_login_required
from flask_security import current_user
from pgadmin.misc.file_manager import Filemanager
from pgadmin.tools.sqleditor.command import QueryToolCommand, ObjectRegistry, \
    SQLFilter
from pgadmin.tools.sqleditor.utils.constant_definition import ASYNC_OK, \
    ASYNC_EXECUTION_ABORTED, \
    CONNECTION_STATUS_MESSAGE_MAPPING, TX_STATUS_INERROR
from pgadmin.tools.sqleditor.utils.start_running_query import StartRunningQuery
from pgadmin.tools.sqleditor.utils.update_session_grid_transaction import \
    update_session_grid_transaction
from pgadmin.utils import PgAdminModule
from pgadmin.utils import get_storage_directory
from pgadmin.utils.ajax import make_json_response, bad_request, \
    success_return, internal_server_error, service_unavailable
from pgadmin.utils.driver import get_driver
from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost, \
    CryptKeyMissing, ObjectGone
from pgadmin.browser.utils import underscore_unescape, underscore_escape
from pgadmin.utils.menu import MenuItem
from pgadmin.utils.sqlautocomplete.autocomplete import SQLAutoComplete
from pgadmin.tools.sqleditor.utils.query_tool_preferences import \
    register_query_tool_preferences
from pgadmin.tools.sqleditor.utils.query_tool_fs_utils import \
    read_file_generator
from pgadmin.tools.sqleditor.utils.filter_dialog import FilterDialog
from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
from pgadmin.tools.sqleditor.utils.macros import get_macros,\
    get_user_macros, set_macros
from pgadmin.utils.constants import MIMETYPE_APP_JS, \
    SERVER_CONNECTION_CLOSED, ERROR_MSG_TRANS_ID_NOT_FOUND, \
    ERROR_FETCHING_DATA, MY_STORAGE, ACCESS_DENIED_MESSAGE, \
    ERROR_MSG_FAIL_TO_PROMOTE_QT
from pgadmin.model import Server, ServerGroup
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.settings import get_setting
from pgadmin.utils.preferences import Preferences
from pgadmin.tools.sqleditor.utils.apply_explain_plan_wrapper import \
    get_explain_query_length

MODULE_NAME = 'sqleditor'
TRANSACTION_STATUS_CHECK_FAILED = gettext("Transaction status check failed.")
_NODES_SQL = 'nodes.sql'
sqleditor_close_session_lock = Lock()
auto_complete_objects = dict()


class SqlEditorModule(PgAdminModule):
    """
    class SqlEditorModule(PgAdminModule)

        A module class for SQL Grid derived from PgAdminModule.
    """

    LABEL = gettext("Query Tool")

    def get_own_menuitems(self):
        return {'tools': [
            MenuItem(name='mnu_query_tool',
                     label=gettext('Query tool'),
                     priority=100,
                     callback='show_query_tool',
                     icon='fa fa-question',
                     url=url_for('help.static', filename='index.html'))
        ]}

    def get_exposed_url_endpoints(self):
        """
        Returns:
            list: URL endpoints for sqleditor module
        """
        return [
            'sqleditor.initialize_viewdata',
            'sqleditor.initialize_sqleditor',
            'sqleditor.initialize_sqleditor_with_did',
            'sqleditor.filter_validate',
            'sqleditor.filter',
            'sqleditor.panel',
            'sqleditor.close',
            'sqleditor.update_sqleditor_connection',

            'sqleditor.view_data_start',
            'sqleditor.query_tool_start',
            'sqleditor.poll',
            'sqleditor.fetch',
            'sqleditor.fetch_all',
            'sqleditor.fetch_all_from_start',
            'sqleditor.save',
            'sqleditor.inclusive_filter',
            'sqleditor.exclusive_filter',
            'sqleditor.remove_filter',
            'sqleditor.set_limit',
            'sqleditor.cancel_transaction',
            'sqleditor.get_object_name',
            'sqleditor.auto_commit',
            'sqleditor.auto_rollback',
            'sqleditor.autocomplete',
            'sqleditor.load_file',
            'sqleditor.save_file',
            'sqleditor.query_tool_download',
            'sqleditor.connection_status',
            'sqleditor.get_filter_data',
            'sqleditor.set_filter_data',
            'sqleditor.get_query_history',
            'sqleditor.add_query_history',
            'sqleditor.clear_query_history',
            'sqleditor.get_macro',
            'sqleditor.get_macros',
            'sqleditor.set_macros',
            'sqleditor.get_new_connection_data',
            'sqleditor.get_new_connection_servers',
            'sqleditor.get_new_connection_database',
            'sqleditor.get_new_connection_user',
            'sqleditor._check_server_connection_status',
            'sqleditor.get_new_connection_role',
            'sqleditor.connect_server',
        ]

    def on_logout(self):
        """
        This is a callback function when user logout from pgAdmin
        :param user:
        :return:
        """
        with sqleditor_close_session_lock:
            if 'gridData' in session:
                for trans_id in session['gridData']:
                    close_sqleditor_session(trans_id)

                # Delete all grid data from session variable
                del session['gridData']

    def register_preferences(self):
        register_query_tool_preferences(self)


blueprint = SqlEditorModule(MODULE_NAME, __name__, static_url_path='/static')


@blueprint.route('/')
@pga_login_required
def index():
    return bad_request(
        errormsg=gettext('This URL cannot be requested directly.')
    )


@blueprint.route("/filter", endpoint='filter')
@pga_login_required
def show_filter():
    return render_template(MODULE_NAME + '/filter.html')


@blueprint.route(
    '/initialize/viewdata/<int:trans_id>/<int:cmd_type>/<obj_type>/'
    '<int:sgid>/<int:sid>/<int:did>/<int:obj_id>',
    methods=["PUT", "POST"],
    endpoint="initialize_viewdata"
)
@pga_login_required
def initialize_viewdata(trans_id, cmd_type, obj_type, sgid, sid, did, obj_id):
    """
    This method is responsible for creating an asynchronous connection.
    After creating the connection it will instantiate and initialize
    the object as per the object type. It will also create a unique
    transaction id and store the information into session variable.

    Args:
        cmd_type: Contains value for which menu item is clicked.
        obj_type: Contains type of selected object for which data grid to
        be render
        sgid: Server group Id
        sid: Server Id
        did: Database Id
        obj_id: Id of currently selected object
    """

    if request.data:
        filter_sql = json.loads(request.data)
    else:
        filter_sql = request.args or request.form

    # Create asynchronous connection using random connection id.
    conn_id = str(secrets.choice(range(1, 9999999)))
    try:
        manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
        # default_conn is same connection which is created when user connect to
        # database from tree
        default_conn = manager.connection(did=did)
        conn = manager.connection(did=did, conn_id=conn_id,
                                  auto_reconnect=False,
                                  use_binary_placeholder=True,
                                  array_to_string=True)
    except (ConnectionLost, SSHTunnelConnectionLost):
        raise
    except Exception as e:
        current_app.logger.error(e)
        return internal_server_error(errormsg=str(e))

    status, msg = default_conn.connect()
    if not status:
        current_app.logger.error(msg)
        return internal_server_error(errormsg=str(msg))

    status, msg = conn.connect()
    if not status:
        current_app.logger.error(msg)
        return internal_server_error(errormsg=str(msg))
    try:
        # if object type is partition then it is nothing but a table.
        if obj_type == 'partition':
            obj_type = 'table'

        # Get the object as per the object type
        command_obj = ObjectRegistry.get_object(
            obj_type, conn_id=conn_id, sgid=sgid, sid=sid,
            did=did, obj_id=obj_id, cmd_type=cmd_type,
            sql_filter=filter_sql
        )
    except ObjectGone:
        raise
    except Exception as e:
        current_app.logger.error(e)
        return internal_server_error(errormsg=str(e))

    if 'gridData' not in session:
        sql_grid_data = dict()
    else:
        sql_grid_data = session['gridData']

    # Use pickle to store the command object which will be used later by the
    # sql grid module.
    sql_grid_data[str(trans_id)] = {
        # -1 specify the highest protocol version available
        'command_obj': pickle.dumps(command_obj, -1)
    }

    # Store the grid dictionary into the session variable
    session['gridData'] = sql_grid_data

    return make_json_response(
        data={
            'conn_id': conn_id
        }
    )


@blueprint.route(
    '/panel/<int:trans_id>',
    methods=["POST"],
    endpoint='panel'
)
def panel(trans_id):
    """
    This method calls index.html to render the data grid.

    Args:
        trans_id: unique transaction id
    """

    params = None
    if request.args:
        params = {k: v for k, v in request.args.items()}

    if request.form:
        for key, val in request.form.items():
            params[key] = val

    params['trans_id'] = trans_id

    # We need client OS information to render correct Keyboard shortcuts
    params['client_platform'] = UserAgent(request.headers.get('User-Agent'))\
        .platform

    params['is_linux'] = False
    from sys import platform as _platform
    if "linux" in _platform:
        params['is_linux'] = True

    # Fetch the server details
    params['bgcolor'] = None
    params['fgcolor'] = None

    s = Server.query.filter_by(id=int(params['sid'])).first()
    if s.shared and s.user_id != current_user.id:
        # Import here to avoid circular dependency
        from pgadmin.browser.server_groups.servers import ServerModule
        shared_server = ServerModule.get_shared_server(s, params['sgid'])
        s = ServerModule.get_shared_server_properties(s, shared_server)

    if s and s.bgcolor:
        # If background is set to white means we do not have to change
        # the title background else change it as per user specified
        # background
        if s.bgcolor != '#ffffff':
            params['bgcolor'] = s.bgcolor
        params['fgcolor'] = s.fgcolor or 'black'

    params['server_name'] = underscore_escape(s.name)
    if 'user' not in params:
        params['user'] = underscore_escape(s.username)
    if 'role' not in params and s.role:
        params['role'] = underscore_escape(s.role)
    params['layout'] = get_setting('SQLEditor/Layout')
    params['macros'] = get_user_macros()
    params['is_desktop_mode'] = current_app.PGADMIN_RUNTIME
    if 'database_name' in params:
        params['database_name'] = underscore_escape(params['database_name'])

    return render_template(
        "sqleditor/index.html",
        title=underscore_unescape(params['title']),
        params=json.dumps(params),
    )


@blueprint.route(
    '/initialize/sqleditor/<int:trans_id>/<int:sgid>/<int:sid>/'
    '<int:did>',
    methods=["POST"], endpoint='initialize_sqleditor_with_did'
)
@blueprint.route(
    '/initialize/sqleditor/<int:trans_id>/<int:sgid>/<int:sid>',
    methods=["POST"], endpoint='initialize_sqleditor'
)
@pga_login_required
def initialize_sqleditor(trans_id, sgid, sid, did=None):
    """
    This method is responsible for instantiating and initializing
    the query tool object. It will also create a unique
    transaction id and store the information into session variable.

    Args:
        sgid: Server group Id
        sid: Server Id
        did: Database Id
    """
    connect = True
    # Read the data if present. Skipping read may cause connection
    # reset error if data is sent from the client
    data = {}
    if request.data:
        data = json.loads(request.data)

    req_args = request.args
    if ('recreate' in req_args and
            req_args['recreate'] == '1'):
        connect = False

    kwargs = {
        'user': data['user'] if 'user' in data else None,
        'role': data['role'] if 'role' in data else None,
        'password': data['password'] if 'password' in data else None
    }

    is_error, errmsg, conn_id, version = _init_sqleditor(
        trans_id, connect, sgid, sid, did, data['dbname'], **kwargs)
    if is_error:
        return errmsg

    return make_json_response(
        data={
            'connId': str(conn_id),
            'serverVersion': version,
        }
    )


def _connect(conn, **kwargs):
    """
    Connect the database.
    :param conn: Connection instance.
    :param kwargs: user, role and password data from user.
    :return:
    """
    user = None
    role = None
    password = None
    is_ask_password = False
    if 'user' in kwargs and 'role' in kwargs:
        user = kwargs['user']
        role = kwargs['role'] if kwargs['role'] else None
        password = kwargs['password'] if kwargs['password'] else None
        is_ask_password = True
    if user:
        status, msg = conn.connect(user=user, role=role,
                                   password=password)
    else:
        status, msg = conn.connect(**kwargs)

    return status, msg, is_ask_password, user, role, password


def _init_sqleditor(trans_id, connect, sgid, sid, did, dbname=None, **kwargs):
    # Create asynchronous connection using random connection id.
    conn_id = kwargs['conn_id'] if 'conn_id' in kwargs else str(
        secrets.choice(range(1, 9999999)))
    if 'conn_id' in kwargs:
        kwargs.pop('conn_id')

    conn_id_ac = str(secrets.choice(range(1, 9999999)))

    manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)

    if did is None:
        did = manager.did
    try:
        command_obj = ObjectRegistry.get_object(
            'query_tool', conn_id=conn_id, sgid=sgid, sid=sid, did=did,
            conn_id_ac=conn_id_ac, **kwargs
        )
    except Exception as e:
        current_app.logger.error(e)
        return True, internal_server_error(errormsg=str(e)), '', ''

    pref = Preferences.module('sqleditor')

    if kwargs.get('auto_commit', None) is None:
        kwargs['auto_commit'] = pref.preference('auto_commit').get()
    if kwargs.get('auto_rollback', None) is None:
        kwargs['auto_rollback'] = pref.preference('auto_rollback').get()

    try:
        conn = manager.connection(conn_id=conn_id,
                                  auto_reconnect=False,
                                  use_binary_placeholder=True,
                                  array_to_string=True,
                                  **({"database": dbname} if dbname is not None
                                     else {"did": did}))

        if connect:
            status, msg, is_ask_password, user, _, _ = _connect(
                conn, **kwargs)
            if not status:
                current_app.logger.error(msg)
                if is_ask_password:
                    server = Server.query.filter_by(id=sid).first()
                    return True, make_json_response(
                        success=0,
                        status=428,
                        result={
                            "server_label": server.name,
                            "username": user or server.username,
                            "errmsg": msg,
                            "prompt_password": True,
                            "allow_save_password": True
                            if ALLOW_SAVE_PASSWORD and
                            session['allow_save_password'] else False,
                        }
                    ), '', ''
                else:
                    return True, internal_server_error(
                        errormsg=str(msg)), '', ''

            if pref.preference('autocomplete_on_key_press').get():
                conn_ac = manager.connection(conn_id=conn_id_ac,
                                             auto_reconnect=False,
                                             use_binary_placeholder=True,
                                             array_to_string=True,
                                             **({"database": dbname}
                                                if dbname is not None
                                                else {"did": did}))
                status, msg, is_ask_password, user, _, _ = _connect(
                    conn_ac, **kwargs)

    except (ConnectionLost, SSHTunnelConnectionLost) as e:
        current_app.logger.error(e)
        raise
    except Exception as e:
        current_app.logger.error(e)
        return True, internal_server_error(errormsg=str(e)), '', ''

    if 'gridData' not in session:
        sql_grid_data = dict()
    else:
        sql_grid_data = session['gridData']

    # Set the value of auto commit and auto rollback specified in Preferences
    command_obj.set_auto_commit(kwargs['auto_commit'])
    command_obj.set_auto_rollback(kwargs['auto_rollback'])

    # Set the value of database name, that will be used later
    command_obj.dbname = dbname if dbname else None
    # Use pickle to store the command object which will be used
    # later by the sql grid module.
    sql_grid_data[str(trans_id)] = {
        # -1 specify the highest protocol version available
        'command_obj': pickle.dumps(command_obj, -1)
    }

    # Store the grid dictionary into the session variable
    session['gridData'] = sql_grid_data

    return False, '', conn_id, manager.version


@blueprint.route(
    '/initialize/sqleditor/update_connection/<int:trans_id>/'
    '<int:sgid>/<int:sid>/<int:did>',
    methods=["POST"], endpoint='update_sqleditor_connection'
)
def update_sqleditor_connection(trans_id, sgid, sid, did):
    # Remove transaction Id.
    with sqleditor_close_session_lock:
        data = json.loads(request.data)

        if 'gridData' not in session:
            return make_json_response(data={'status': True})

        grid_data = session['gridData']

        # Return from the function if transaction id not found
        if str(trans_id) not in grid_data:
            return make_json_response(data={'status': True})

        connect = True

        req_args = request.args
        if ('recreate' in req_args and
                req_args['recreate'] == '1'):
            connect = False

        # Old transaction
        _, _, _, trans_obj, session_obj = \
            check_transaction_status(trans_id)

        new_trans_id = str(secrets.choice(range(1, 9999999)))
        kwargs = {
            'user': data['user'],
            'role': data['role'] if 'role' in data else None,
            'password': data['password'] if 'password' in data else None,
            'auto_commit': getattr(trans_obj, 'auto_commit', None),
            'auto_rollback': getattr(trans_obj, 'auto_rollback', None),
        }

        is_error, errmsg, conn_id, version = _init_sqleditor(
            new_trans_id, connect, sgid, sid, did, data['database_name'],
            **kwargs)

        if is_error:
            return errmsg
        else:
            try:
                _, _, _, _, new_session_obj = \
                    check_transaction_status(new_trans_id)

                new_session_obj['primary_keys'] = session_obj[
                    'primary_keys'] if 'primary_keys' in session_obj else None
                new_session_obj['columns_info'] = session_obj[
                    'columns_info'] if 'columns_info' in session_obj else None
                new_session_obj['client_primary_key'] = session_obj[
                    'client_primary_key'] if 'client_primary_key'\
                                             in session_obj else None

                close_sqleditor_session(trans_id)
                # Remove the information of unique transaction id from the
                # session variable.
                grid_data.pop(str(trans_id), None)
                session['gridData'] = grid_data
            except Exception as e:
                current_app.logger.error(e)

    return make_json_response(
        data={
            'connId': str(conn_id),
            'serverVersion': version,
            'trans_id': new_trans_id
        }
    )


@blueprint.route('/close/<int:trans_id>', methods=["DELETE"], endpoint='close')
def close(trans_id):
    """
    This method is used to close the asynchronous connection
    and remove the information of unique transaction id from
    the session variable.

    Args:
        trans_id: unique transaction id
    """
    with sqleditor_close_session_lock:
        # delete the SQLAutoComplete object
        if trans_id in auto_complete_objects:
            del auto_complete_objects[trans_id]

        if 'gridData' not in session:
            return make_json_response(data={'status': True})

        grid_data = session['gridData']
        # Return from the function if transaction id not found
        if str(trans_id) not in grid_data:
            return make_json_response(data={'status': True})

        try:
            close_sqleditor_session(trans_id)
            # Remove the information of unique transaction id from the
            # session variable.
            grid_data.pop(str(trans_id), None)
            session['gridData'] = grid_data
        except Exception as e:
            current_app.logger.error(e)
            return internal_server_error(errormsg=str(e))

    return make_json_response(data={'status': True})


@blueprint.route(
    '/filter/validate/<int:sid>/<int:did>/<int:obj_id>',
    methods=["PUT", "POST"], endpoint='filter_validate'
)
@pga_login_required
def validate_filter(sid, did, obj_id):
    """
    This method is used to validate the sql filter.

    Args:
        sid: Server Id
        did: Database Id
        obj_id: Id of currently selected object
    """
    if request.data:
        filter_data = json.loads(request.data)
    else:
        filter_data = request.args or request.form

    try:
        # Create object of SQLFilter class
        sql_filter_obj = SQLFilter(sid=sid, did=did, obj_id=obj_id)

        # Call validate_filter method to validate the SQL.
        status, res = sql_filter_obj.validate_filter(filter_data['filter_sql'])
        if not status:
            return internal_server_error(errormsg=str(res))
    except ObjectGone:
        raise
    except Exception as e:
        current_app.logger.error(e)
        return internal_server_error(errormsg=str(e))

    return make_json_response(data={'status': status, 'result': res})


def close_sqleditor_session(trans_id):
    """
    This function is used to cancel the transaction and release the connection.

    :param trans_id: Transaction id
    :return:
    """
    if 'gridData' in session and str(trans_id) in session['gridData']:
        cmd_obj_str = session['gridData'][str(trans_id)]['command_obj']
        # Use pickle.loads function to get the command object
        cmd_obj = pickle.loads(cmd_obj_str)

        # if connection id is None then no need to release the connection
        if cmd_obj.conn_id is not None:
            manager = get_driver(
                PG_DEFAULT_DRIVER).connection_manager(cmd_obj.sid)
            if manager is not None:
                conn = manager.connection(
                    did=cmd_obj.did, conn_id=cmd_obj.conn_id)

                # Release the connection
                if conn.connected():
                    conn.cancel_transaction(cmd_obj.conn_id, cmd_obj.did)
                    manager.release(did=cmd_obj.did, conn_id=cmd_obj.conn_id)

        # Close the auto complete connection
        if hasattr(cmd_obj, 'conn_id_ac') and cmd_obj.conn_id_ac is not None:
            manager = get_driver(
                PG_DEFAULT_DRIVER).connection_manager(cmd_obj.sid)
            if manager is not None:
                conn = manager.connection(
                    did=cmd_obj.did, conn_id=cmd_obj.conn_id_ac)

                # Release the connection
                if conn.connected():
                    conn.cancel_transaction(cmd_obj.conn_id_ac, cmd_obj.did)
                    manager.release(did=cmd_obj.did,
                                    conn_id=cmd_obj.conn_id_ac)


def check_transaction_status(trans_id, auto_comp=False):
    """
    This function is used to check the transaction id
    is available in the session object and connection
    status.

    Args:
        trans_id: Transaction Id
        auto_comp: Auto complete flag

    Returns: status and connection object

    """

    if 'gridData' not in session:
        return False, ERROR_MSG_TRANS_ID_NOT_FOUND, None, None, None

    grid_data = session['gridData']

    # Return from the function if transaction id not found
    if str(trans_id) not in grid_data:
        return False, ERROR_MSG_TRANS_ID_NOT_FOUND, None, None, None

    # Fetch the object for the specified transaction id.
    # Use pickle.loads function to get the command object
    session_obj = grid_data[str(trans_id)]
    trans_obj = pickle.loads(session_obj['command_obj'])

    if auto_comp:
        conn_id = trans_obj.conn_id_ac
        connect = True
    else:
        conn_id = trans_obj.conn_id
        connect = True if 'connect' in request.args and \
                          request.args['connect'] == '1' else False
    try:
        manager = get_driver(
            PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
        conn = manager.connection(
            did=trans_obj.did,
            conn_id=conn_id,
            auto_reconnect=False,
            use_binary_placeholder=True,
            array_to_string=True
        )
    except (ConnectionLost, SSHTunnelConnectionLost, CryptKeyMissing):
        raise
    except Exception as e:
        current_app.logger.error(e)
        return False, internal_server_error(errormsg=str(e)), None, None, None

    if connect and conn and not conn.connected():
        conn.connect()

    return True, None, conn, trans_obj, session_obj


@blueprint.route(
    '/view_data/start/<int:trans_id>',
    methods=["GET"], endpoint='view_data_start'
)
@pga_login_required
def start_view_data(trans_id):
    """
    This method is used to execute query using asynchronous connection.

    Args:
        trans_id: unique transaction id
    """
    limit = -1

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    # get the default connection as current connection which is attached to
    # trans id holds the cursor which has query result so we cannot use that
    # connection to execute another query otherwise we'll lose query result.

    try:
        manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
            trans_obj.sid)
        default_conn = manager.connection(did=trans_obj.did)
    except (ConnectionLost, SSHTunnelConnectionLost) as e:
        raise
    except Exception as e:
        current_app.logger.error(e)
        return internal_server_error(errormsg=str(e))

    # Connect to the Server if not connected.
    if not default_conn.connected():
        status, msg = default_conn.connect()
        if not status:
            return make_json_response(
                data={'status': status, 'result': "{}".format(msg)}
            )

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        # set fetched row count to 0 as we are executing query again.
        trans_obj.update_fetched_row_cnt(0)

        # Fetch the sql and primary_keys from the object
        sql = trans_obj.get_sql(default_conn)
        _, primary_keys = trans_obj.get_primary_keys(default_conn)

        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)

        has_oids = False
        if trans_obj.object_type == 'table':
            # Fetch OIDs status
            has_oids = trans_obj.has_oids(default_conn)

        # Fetch the applied filter.
        filter_applied = trans_obj.is_filter_applied()

        # Fetch the limit for the SQL query
        limit = trans_obj.get_limit()

        can_edit = trans_obj.can_edit()
        can_filter = trans_obj.can_filter()

        # Store the primary keys to the session object
        session_obj['primary_keys'] = primary_keys

        # Store the OIDs status into session object
        session_obj['has_oids'] = has_oids

        update_session_grid_transaction(trans_id, session_obj)

        # Execute sql asynchronously
        status, result = conn.execute_async(sql)
    else:
        status = False
        result = error_msg
        filter_applied = False
        can_edit = False
        can_filter = False
        sql = None

    return make_json_response(
        data={
            'status': status, 'result': result,
            'filter_applied': filter_applied,
            'limit': limit, 'can_edit': can_edit,
            'can_filter': can_filter, 'sql': sql,
        }
    )


@blueprint.route(
    '/query_tool/start/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='query_tool_start'
)
@pga_login_required
def start_query_tool(trans_id):
    """
    This method is used to execute query using asynchronous connection.

    Args:
        trans_id: unique transaction id
    """

    sql = extract_sql_from_network_parameters(
        request.data, request.args, request.form
    )

    connect = 'connect' in request.args and request.args['connect'] == '1'
    is_error, errmsg = check_and_upgrade_to_qt(trans_id, connect)
    if is_error:
        return make_json_response(success=0, errormsg=errmsg,
                                  info=ERROR_MSG_FAIL_TO_PROMOTE_QT,
                                  status=404)

    return StartRunningQuery(blueprint, current_app.logger).execute(
        sql, trans_id, session, connect
    )


def extract_sql_from_network_parameters(request_data, request_arguments,
                                        request_form_data):
    if request_data:
        sql_parameters = json.loads(request_data)

        if isinstance(sql_parameters, str):
            return dict(sql=str(sql_parameters), explain_plan=None)
        return sql_parameters
    else:
        return request_arguments or request_form_data


@blueprint.route('/poll/<int:trans_id>', methods=["GET"], endpoint='poll')
@pga_login_required
def poll(trans_id):
    """
    This method polls the result of the asynchronous query and returns
    the result.

    Args:
        trans_id: unique transaction id
    """
    result = None
    rows_affected = 0
    rows_fetched_from = 0
    rows_fetched_to = 0
    has_more_rows = False
    columns = dict()
    columns_info = None
    primary_keys = None
    types = {}
    client_primary_key = None
    has_oids = False
    oids = None
    additional_messages = None
    notifies = None
    data_obj = {}
    on_demand_record_count = Preferences.module(MODULE_NAME).\
        preference('on_demand_record_count').get()
    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if type(error_msg) is Response:
        return error_msg

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    is_thread_alive = False
    if trans_obj.get_thread_native_id():
        for thread in threading.enumerate():
            _native_id = thread.native_id if hasattr(thread, 'native_id'
                                                     ) else thread.ident
            if _native_id == trans_obj.get_thread_native_id() and\
                    thread.is_alive():
                is_thread_alive = True
                break

    # if transaction object is instance of QueryToolCommand
    # and transaction aborted for some reason then issue a
    # rollback to cleanup
    if isinstance(trans_obj, QueryToolCommand):
        trans_status = conn.transaction_status()
        if trans_status == TX_STATUS_INERROR and trans_obj.auto_rollback:
            conn.execute_void("ROLLBACK;")

    if is_thread_alive:
        status = 'Busy'
        messages = conn.messages()
        if messages and len(messages) > 0:
            result = ''.join(messages)
    elif status and conn is not None and session_obj is not None:
        status, result = conn.poll(
            formatted_exception_msg=True, no_result=True)
        if not status:
            if not conn.connected():
                return service_unavailable(
                    gettext("Connection to the server has been lost."),
                    info="CONNECTION_LOST",
                )

            messages = conn.messages()
            if messages and len(messages) > 0:
                additional_messages = ''.join(messages)
                result = '{0}\n{1}\n\n{2}'.format(
                    additional_messages,
                    gettext('******* Error *******'),
                    result
                )

            transaction_status = conn.transaction_status() if conn else 0
            query_len_data = {
                'transaction_status': transaction_status,
                'explain_query_length':
                    get_explain_query_length(
                        conn._Connection__async_cursor._query)
            }
            return internal_server_error(result, query_len_data)
        elif status == ASYNC_OK:
            status = 'Success'
            rows_affected = conn.rows_affected()

            st, result = conn.async_fetchmany_2darray(on_demand_record_count)

            # There may be additional messages even if result is present
            # eg: Function can provide result as well as RAISE messages
            messages = conn.messages()
            if messages:
                additional_messages = ''.join(messages)
            notifies = conn.get_notifies()

            if st:
                if 'primary_keys' in session_obj:
                    primary_keys = session_obj['primary_keys']

                # Fetch column information
                columns_info = conn.get_column_info()
                client_primary_key = generate_client_primary_key_name(
                    columns_info
                )
                session_obj['client_primary_key'] = client_primary_key

                # If trans_obj is a QueryToolCommand then check for updatable
                # resultsets and primary keys
                if isinstance(trans_obj, QueryToolCommand) and \
                        trans_obj.check_updatable_results_pkeys_oids():
                    _, primary_keys = trans_obj.get_primary_keys()
                    session_obj['has_oids'] = trans_obj.has_oids()
                    # Update command_obj in session obj
                    session_obj['command_obj'] = pickle.dumps(
                        trans_obj, -1)
                    # If primary_keys exist, add them to the session_obj to
                    # allow for saving any changes to the data
                    if primary_keys is not None:
                        session_obj['primary_keys'] = primary_keys

                if 'has_oids' in session_obj:
                    has_oids = session_obj['has_oids']
                    if has_oids:
                        oids = {'oid': 'oid'}

                if columns_info is not None:
                    # Only QueryToolCommand or TableCommand can be editable
                    if hasattr(trans_obj, 'obj_id') and trans_obj.can_edit():
                        columns = trans_obj.get_columns_types(conn)

                    else:
                        for col in columns_info:
                            col_type = dict()
                            col_type['type_code'] = col['type_code']
                            col_type['type_name'] = None
                            col_type['internal_size'] = col['internal_size']
                            col_type['display_size'] = col['display_size']
                            columns[col['name']] = col_type

                if columns:
                    st, types = fetch_pg_types(columns, trans_obj)

                    if not st:
                        return internal_server_error(types)

                    for col_name, col_info in columns.items():
                        for col_type in types:
                            if col_type['oid'] == col_info['type_code']:
                                typname = col_type['typname']
                                col_info['type_name'] = typname

                        # Using characters %, (, ) in the argument names is not
                        # supported in psycopg
                        col_info['pgadmin_alias'] = \
                            re.sub("[%()]+", "|", col_name).\
                            encode('unicode_escape').decode('utf-8')

                    session_obj['columns_info'] = columns

                # status of async_fetchmany_2darray is True and result is none
                # means nothing to fetch
                if result and rows_affected > -1:
                    res_len = len(result)
                    if res_len == on_demand_record_count:
                        has_more_rows = True

                    if res_len > 0:
                        rows_fetched_from = trans_obj.get_fetched_row_cnt()
                        trans_obj.update_fetched_row_cnt(
                            rows_fetched_from + res_len)
                        rows_fetched_from += 1
                        rows_fetched_to = trans_obj.get_fetched_row_cnt()
                        session_obj['command_obj'] = pickle.dumps(
                            trans_obj, -1)

                # As we changed the transaction object we need to
                # restore it and update the session variable.
                update_session_grid_transaction(trans_id, session_obj)

            # Procedure/Function output may comes in the form of Notices
            # from the database server, so we need to append those outputs
            # with the original result.
            if result is None:
                result = conn.status_message()
                if result is not None and additional_messages is not None:
                    result = additional_messages + result
                else:
                    result = result if result is not None \
                        else additional_messages

        elif status == ASYNC_EXECUTION_ABORTED:
            status = 'Cancel'
        else:
            status = 'Busy'
            messages = conn.messages()
            if messages and len(messages) > 0:
                result = ''.join(messages)

    else:
        status = 'NotConnected'
        result = error_msg

    transaction_status = conn.transaction_status() if conn else 0
    data_obj['db_name'] = conn.db if conn else None

    data_obj['db_id'] = trans_obj.did \
        if trans_obj is not None and hasattr(trans_obj, 'did') else 0

    return make_json_response(
        data={
            'status': status, 'result': result,
            'rows_affected': rows_affected,
            'rows_fetched_from': rows_fetched_from,
            'rows_fetched_to': rows_fetched_to,
            'additional_messages': additional_messages,
            'notifies': notifies,
            'has_more_rows': has_more_rows,
            'colinfo': columns_info,
            'primary_keys': primary_keys,
            'types': types,
            'client_primary_key': client_primary_key,
            'has_oids': has_oids,
            'oids': oids,
            'transaction_status': transaction_status,
            'data_obj': data_obj,
        }
    )


@blueprint.route(
    '/fetch/<int:trans_id>', methods=["GET"], endpoint='fetch'
)
@blueprint.route(
    '/fetch/<int:trans_id>/<int:fetch_all>', methods=["GET"],
    endpoint='fetch_all'
)
@pga_login_required
def fetch(trans_id, fetch_all=None):
    result = None
    has_more_rows = False
    rows_fetched_from = 0
    rows_fetched_to = 0
    on_demand_record_count = Preferences.module(MODULE_NAME).preference(
        'on_demand_record_count').get()
    fetch_row_cnt = -1 if fetch_all == 1 else on_demand_record_count

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and session_obj is not None:
        status, result = conn.async_fetchmany_2darray(fetch_row_cnt)
        if not status:
            status = 'Error'
        else:
            status = 'Success'
            res_len = len(result) if result else 0
            if fetch_row_cnt != -1 and res_len == on_demand_record_count:
                has_more_rows = True

            if res_len:
                rows_fetched_from = trans_obj.get_fetched_row_cnt()
                trans_obj.update_fetched_row_cnt(rows_fetched_from + res_len)
                rows_fetched_from += 1
                rows_fetched_to = trans_obj.get_fetched_row_cnt()
                session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
                update_session_grid_transaction(trans_id, session_obj)
    else:
        status = 'NotConnected'
        result = error_msg

    return make_json_response(
        data={
            'status': status,
            'result': result,
            'has_more_rows': has_more_rows,
            'rows_fetched_from': rows_fetched_from,
            'rows_fetched_to': rows_fetched_to
        }
    )


@blueprint.route(
    '/fetch_all_from_start/<int:trans_id>/<int:limit>', methods=["GET"],
    endpoint='fetch_all_from_start'
)
@pga_login_required
def fetch_all_from_start(trans_id, limit=-1):
    """
    This function is used to fetch all the records from start and reset
    the cursor back to it's previous position.
    """
    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and session_obj is not None:
        # Reset the cursor to start to fetch all the records.
        conn.reset_cursor_at(0)

        status, result = conn.async_fetchmany_2darray(limit)
        if not status:
            status = 'Error'
        else:
            status = 'Success'

        # Reset the cursor back to it's actual position
        conn.reset_cursor_at(trans_obj.get_fetched_row_cnt())
    else:
        status = 'NotConnected'
        result = error_msg

    return make_json_response(
        data={
            'status': status,
            'result': result
        }
    )


def fetch_pg_types(columns_info, trans_obj):
    """
    This method is used to fetch the pg types, which is required
    to map the data type comes as a result of the query.

    Args:
        columns_info:
    """

    # get the default connection as current connection attached to trans id
    # holds the cursor which has query result so we cannot use that connection
    # to execute another query otherwise we'll lose query result.

    manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
    default_conn = manager.connection(conn_id=trans_obj.conn_id,
                                      did=trans_obj.did)

    # Connect to the Server if not connected.
    res = []
    if not default_conn.connected():
        status, msg = default_conn.connect()
        if not status:
            return status, msg

    oids = [columns_info[col]['type_code'] for col in columns_info]

    if oids:
        status, res = default_conn.execute_dict(
            "SELECT oid, pg_catalog.format_type(oid, NULL) AS typname FROM "
            "pg_catalog.pg_type WHERE oid = ANY(%s) ORDER BY oid;", [oids]
        )

        if not status:
            return False, res

        return status, res['rows']
    else:
        return True, []


def generate_client_primary_key_name(columns_info):
    temp_key = '__temp_PK'
    if not columns_info:
        return temp_key

    initial_temp_key_len = len(temp_key)
    duplicate = False
    suffix = 1
    while True:
        for col in columns_info:
            if col['name'] == temp_key:
                duplicate = True
                break
        if duplicate:
            if initial_temp_key_len == len(temp_key):
                temp_key += str(suffix)
                suffix += 1
            else:
                temp_key = temp_key[:-1] + str(suffix)
                suffix += 1
            duplicate = False
        else:
            break
    return temp_key


def _check_and_connect(trans_obj):
    """
    Check and connect to the database for transaction.
    :param trans_obj: Transaction object.
    :return: If any error return error with error msg,
    if not then return connection object.
    """
    manager = get_driver(
        PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
    if hasattr(trans_obj, 'conn_id'):
        conn = manager.connection(did=trans_obj.did,
                                  conn_id=trans_obj.conn_id)
    else:
        conn = manager.connection(did=trans_obj.did)  # default connection

    # Connect to the Server if not connected.
    if not conn.connected():
        status, msg = conn.connect()
        if not status:
            return True, msg, conn
    return False, '', conn


@blueprint.route(
    '/save/<int:trans_id>', methods=["PUT", "POST"], endpoint='save'
)
@pga_login_required
def save(trans_id):
    """
    This method is used to save the data changes to the server

    Args:
        trans_id: unique transaction id
    """
    if request.data:
        changed_data = json.loads(request.data)
    else:
        changed_data = request.args or request.form

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        # If there is no primary key found then return from the function.
        if ('primary_keys' not in session_obj or
            len(session_obj['primary_keys']) <= 0 or
                len(changed_data) <= 0) and 'has_oids' not in session_obj:
            return make_json_response(
                data={
                    'status': False,
                    'result': gettext('No primary key found for this object, '
                                      'so unable to save records.')
                }
            )

        is_error, errmsg, conn = _check_and_connect(trans_obj)
        if is_error:
            return make_json_response(
                data={'status': status, 'result': "{}".format(errmsg)}
            )

        status, res, query_results, _rowid = trans_obj.save(
            changed_data,
            session_obj['columns_info'],
            session_obj['client_primary_key'],
            conn)
    else:
        status = False
        res = error_msg
        query_results = None
        _rowid = None

    transaction_status = conn.transaction_status()

    return make_json_response(
        data={
            'status': status,
            'result': res,
            'query_results': query_results,
            '_rowid': _rowid,
            'transaction_status': transaction_status
        }
    )


@blueprint.route(
    '/filter/inclusive/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='inclusive_filter'
)
@pga_login_required
def append_filter_inclusive(trans_id):
    """
    This method is used to append and apply the filter.

    Args:
        trans_id: unique transaction id
    """
    if request.data:
        filter_data = json.loads(request.data)
    else:
        filter_data = request.args or request.form

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        res = None
        filter_sql = ''
        driver = get_driver(PG_DEFAULT_DRIVER)

        for column_name in filter_data:
            column_value = filter_data[column_name]
            if column_value is None:
                filter_sql = driver.qtIdent(conn, column_name) + ' IS NULL '
            else:
                filter_sql = driver.qtIdent(
                    conn, column_name
                ) + ' = ' + driver.qtLiteral(column_value, conn)

        trans_obj.append_filter(filter_sql)

        # As we changed the transaction object we need to
        # restore it and update the session variable.
        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
        update_session_grid_transaction(trans_id, session_obj)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


@blueprint.route(
    '/filter/exclusive/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='exclusive_filter'
)
@pga_login_required
def append_filter_exclusive(trans_id):
    """
    This method is used to append and apply the filter.

    Args:
        trans_id: unique transaction id
    """
    if request.data:
        filter_data = json.loads(request.data)
    else:
        filter_data = request.args or request.form

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)
    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        res = None
        filter_sql = ''
        driver = get_driver(PG_DEFAULT_DRIVER)

        for column_name in filter_data:
            column_value = filter_data[column_name]
            if column_value is None:
                filter_sql = driver.qtIdent(
                    conn, column_name) + ' IS NOT NULL '
            else:
                filter_sql = driver.qtIdent(
                    conn, column_name
                ) + ' IS DISTINCT FROM ' + driver.qtLiteral(column_value, conn)

        # Call the append_filter method of transaction object
        trans_obj.append_filter(filter_sql)

        # As we changed the transaction object we need to
        # restore it and update the session variable.
        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
        update_session_grid_transaction(trans_id, session_obj)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


@blueprint.route(
    '/filter/remove/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='remove_filter'
)
@pga_login_required
def remove_filter(trans_id):
    """
    This method is used to remove the filter.

    Args:
        trans_id: unique transaction id
    """

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        res = None

        # Call the remove_filter method of transaction object
        trans_obj.remove_filter()

        # As we changed the transaction object we need to
        # restore it and update the session variable.
        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
        update_session_grid_transaction(trans_id, session_obj)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


@blueprint.route(
    '/limit/<int:trans_id>', methods=["PUT", "POST"], endpoint='set_limit'
)
@pga_login_required
def set_limit(trans_id):
    """
    This method is used to set the limit for the SQL.

    Args:
        trans_id: unique transaction id
    """
    if request.data:
        limit = json.loads(request.data)
    else:
        limit = request.args or request.form

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        res = None

        # Call the set_limit method of transaction object
        trans_obj.set_limit(limit)

        # As we changed the transaction object we need to
        # restore it and update the session variable.
        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
        update_session_grid_transaction(trans_id, session_obj)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


def _check_for_transaction_before_cancel(trans_id):
    """
    Check if transaction exists or not before cancel it.
    :param trans_id: Transaction ID for check.
    :return: return error is transaction not found, else return grid data.
    """

    if 'gridData' not in session:
        return True, ''

    grid_data = session['gridData']

    # Return from the function if transaction id not found
    if str(trans_id) not in grid_data:
        return True, ''

    return False, grid_data


def _check_and_cancel_transaction(trans_obj, delete_connection, conn, manager):
    """
    Check for connection and cancel current transaction.
    :param trans_obj: transaction object for cancel.
    :param delete_connection: Flag for remove connection.
    :param conn: Connection
    :param manager: Manager
    :return: Return status and result of transaction cancel.
    """
    if conn.connected():
        # on successful connection cancel the running transaction
        status, result = conn.cancel_transaction(
            trans_obj.conn_id, trans_obj.did)

        # Delete connection if we have created it to
        # cancel the transaction
        if delete_connection:
            manager.release(did=trans_obj.did)
    else:
        status = False
        result = SERVER_CONNECTION_CLOSED
    return status, result


@blueprint.route(
    '/cancel/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='cancel_transaction'
)
@pga_login_required
def cancel_transaction(trans_id):
    """
    This method is used to cancel the running transaction

    Args:
        trans_id: unique transaction id
    """
    is_error, grid_data = _check_for_transaction_before_cancel(trans_id)
    if is_error:
        return make_json_response(
            success=0,
            errormsg=ERROR_MSG_TRANS_ID_NOT_FOUND,
            info='DATAGRID_TRANSACTION_REQUIRED', status=404)

    # Fetch the object for the specified transaction id.
    # Use pickle.loads function to get the command object
    session_obj = grid_data[str(trans_id)]
    trans_obj = pickle.loads(session_obj['command_obj'])

    if trans_obj is not None and session_obj is not None:

        # Fetch the main connection object for the database.
        try:
            manager = get_driver(
                PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
            conn = manager.connection(**({"database": trans_obj.dbname}
                                         if trans_obj.dbname is not None
                                         else {"did": trans_obj.did}))

        except Exception as e:
            return internal_server_error(errormsg=str(e))

        delete_connection = False

        # Connect to the Server if not connected.
        if not conn.connected():
            status, msg = conn.connect()
            if not status:
                return internal_server_error(errormsg=str(msg))
            delete_connection = True

        status, result = _check_and_cancel_transaction(trans_obj,
                                                       delete_connection, conn,
                                                       manager)
    else:
        status = False
        result = gettext(
            'Either transaction object or session object not found.')

    return make_json_response(
        data={
            'status': status, 'result': result
        }
    )


@blueprint.route(
    '/object/get/<int:trans_id>',
    methods=["GET"], endpoint='get_object_name'
)
@pga_login_required
def get_object_name(trans_id):
    """
    This method is used to get the object name

    Args:
        trans_id: unique transaction id
    """

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:
        res = trans_obj.object_name
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


def check_and_upgrade_to_qt(trans_id, connect):
    is_error = False
    errmsg = None

    if 'gridData' in session and str(trans_id) in session['gridData']:
        data = pickle.loads(session['gridData'][str(trans_id)]['command_obj'])
        if data.object_type == 'table' or data.object_type == 'view' or\
                data.object_type == 'mview':
            manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
                data.sid)
            default_conn = manager.connection(conn_id=data.conn_id,
                                              did=data.did)
            kwargs = {
                'user': default_conn.manager.user,
                'role': default_conn.manager.role,
                'password': default_conn.manager.password,
                'conn_id': data.conn_id
            }
            is_error, errmsg, _, _ = _init_sqleditor(
                trans_id, connect, data.sgid, data.sid, data.did, **kwargs)

    return is_error, errmsg


@blueprint.route(
    '/auto_commit/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='auto_commit'
)
@pga_login_required
def set_auto_commit(trans_id):
    """
    This method is used to set the value for auto commit .

    Args:
        trans_id: unique transaction id
    """
    if request.data:
        auto_commit = json.loads(request.data)
    else:
        auto_commit = request.args or request.form

    connect = 'connect' in request.args and request.args['connect'] == '1'

    is_error, errmsg = check_and_upgrade_to_qt(trans_id, connect)
    if is_error:
        return make_json_response(success=0, errormsg=errmsg,
                                  info=ERROR_MSG_FAIL_TO_PROMOTE_QT,
                                  status=404)

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        res = None

        # Call the set_auto_commit method of transaction object
        trans_obj.set_auto_commit(auto_commit)

        # As we changed the transaction object we need to
        # restore it and update the session variable.
        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
        update_session_grid_transaction(trans_id, session_obj)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


@blueprint.route(
    '/auto_rollback/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='auto_rollback'
)
@pga_login_required
def set_auto_rollback(trans_id):
    """
    This method is used to set the value for auto commit .

    Args:
        trans_id: unique transaction id
    """
    if request.data:
        auto_rollback = json.loads(request.data)
    else:
        auto_rollback = request.args or request.form

    connect = 'connect' in request.args and request.args['connect'] == '1'

    is_error, errmsg = check_and_upgrade_to_qt(trans_id, connect)
    if is_error:
        return make_json_response(success=0, errormsg=errmsg,
                                  info=ERROR_MSG_FAIL_TO_PROMOTE_QT,
                                  status=404)

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        res = None

        # Call the set_auto_rollback method of transaction object
        trans_obj.set_auto_rollback(auto_rollback)

        # As we changed the transaction object we need to
        # restore it and update the session variable.
        session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
        update_session_grid_transaction(trans_id, session_obj)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


@blueprint.route(
    '/autocomplete/<int:trans_id>',
    methods=["PUT", "POST"], endpoint='autocomplete'
)
@pga_login_required
def auto_complete(trans_id):
    """
    This method implements the autocomplete feature.

    Args:
        trans_id: unique transaction id
    """
    full_sql = ''
    text_before_cursor = ''

    if request.data:
        data = json.loads(request.data)
    else:
        data = request.args or request.form

    if len(data) > 0:
        full_sql = data[0]
        text_before_cursor = data[1]

    connect = 'connect' in request.args and request.args['connect'] == '1'

    is_error, errmsg = check_and_upgrade_to_qt(trans_id, connect)
    if is_error:
        return make_json_response(success=0, errormsg=errmsg,
                                  info=ERROR_MSG_FAIL_TO_PROMOTE_QT,
                                  status=404)

    # Check the transaction and connection status
    status, error_msg, conn, trans_obj, session_obj = \
        check_transaction_status(trans_id, auto_comp=True)

    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:
        return make_json_response(success=0, errormsg=error_msg,
                                  info='DATAGRID_TRANSACTION_REQUIRED',
                                  status=404)

    if status and conn is not None and \
            trans_obj is not None and session_obj is not None:

        with sqleditor_close_session_lock:
            if trans_id not in auto_complete_objects:
                # Create object of SQLAutoComplete class and pass
                # connection object
                auto_complete_objects[trans_id] = \
                    SQLAutoComplete(sid=trans_obj.sid, did=trans_obj.did,
                                    conn=conn)

            auto_complete_obj = auto_complete_objects[trans_id]
            # # Get the auto completion suggestions.
            res = auto_complete_obj.get_completions(full_sql,
                                                    text_before_cursor)
    else:
        status = False
        res = error_msg

    return make_json_response(data={'status': status, 'result': res})


@blueprint.route("/sqleditor.js")
@pga_login_required
def script():
    """render the required javascript"""
    return Response(
        response=render_template(
            "sqleditor/js/sqleditor.js",
            tab_size=blueprint.tab_size.get(),
            use_spaces=blueprint.use_spaces.get(),
            _=gettext
        ),
        status=200,
        mimetype=MIMETYPE_APP_JS
    )


@blueprint.route('/load_file/', methods=["PUT", "POST"], endpoint='load_file')
@pga_login_required
def load_file():
    """
    This function gets name of file from request data
    reads the data and sends back in response
    """
    if request.data:
        file_data = json.loads(request.data)

    file_path = unquote(file_data['file_name'])

    # get the current storage from request if available
    # or get it from last_storage preference.
    if 'storage' in file_data:
        storage_folder = file_data['storage']
    else:
        storage_folder = Preferences.module('file_manager').preference(
            'last_storage').get()

    # retrieve storage directory path
    storage_manager_path = get_storage_directory(
        shared_storage=storage_folder)

    try:
        Filemanager.check_access_permission(storage_manager_path, file_path)
    except Exception as e:
        return internal_server_error(errormsg=str(e))

    if storage_manager_path:
        # generate full path of file
        file_path = os.path.join(
            storage_manager_path,
            file_path.lstrip('/').lstrip('\\')
        )

    (status, err_msg, is_binary,
     is_startswith_bom, enc) = Filemanager.check_file_for_bom_and_binary(
        file_path
    )

    if not status:
        return internal_server_error(
            errormsg=gettext(err_msg)
        )

    if is_binary:
        return internal_server_error(
            errormsg=gettext("File type not supported")
        )

    return Response(read_file_generator(file_path, enc), mimetype='text/plain')


@blueprint.route('/save_file/', methods=["PUT", "POST"], endpoint='save_file')
@pga_login_required
def save_file():
    """
    This function retrieves file_name and data from request.
    and then save the data to the file
    """
    if request.data:
        file_data = json.loads(request.data)

    # retrieve storage directory path
    last_storage = Preferences.module('file_manager').preference(
        'last_storage').get()
    if last_storage != MY_STORAGE:
        selected_dir_list = [sdir for sdir in SHARED_STORAGE if
                             sdir['name'] == last_storage]
        selected_dir = selected_dir_list[0] if len(
            selected_dir_list) == 1 else None

        if selected_dir and selected_dir['restricted_access'] and \
                not current_user.has_role("Administrator"):
            return make_json_response(success=0,
                                      errormsg=ACCESS_DENIED_MESSAGE,
                                      info='ACCESS_DENIED',
                                      status=403)
        storage_manager_path = get_storage_directory(
            shared_storage=last_storage)
    else:
        storage_manager_path = get_storage_directory()

    # generate full path of file
    file_path = unquote(file_data['file_name'])

    try:
        Filemanager.check_access_permission(storage_manager_path, file_path)
    except Exception as e:
        return internal_server_error(errormsg=str(e))

    if storage_manager_path is not None:
        file_path = os.path.join(
            storage_manager_path,
            file_path.lstrip('/').lstrip('\\')
        )

    # Get value for encoding if file is already loaded to SQL editor
    def get_file_encoding_of_loaded_file(file_name):
        encoding = 'utf-8'
        for ele in Filemanager.loaded_file_encoding_list:
            if file_name in ele:
                encoding = ele[file_name]
        return encoding

    enc = get_file_encoding_of_loaded_file(os.path.basename(file_path))

    file_content = file_data['file_content'].encode(enc)
    error_str = gettext("Error: {0}")

    # write to file
    try:
        with open(file_path, 'wb+') as output_file:
            output_file.write(file_content)
    except IOError as e:
        err_msg = error_str.format(e.strerror)
        return internal_server_error(errormsg=err_msg)
    except Exception as e:
        err_msg = error_str.format(e.strerror)
        return internal_server_error(errormsg=err_msg)

    return make_json_response(
        data={
            'status': True,
        }
    )


@blueprint.route(
    '/query_tool/download/<int:trans_id>',
    methods=["POST"],
    endpoint='query_tool_download'
)
@pga_login_required
def start_query_download_tool(trans_id):
    (status, error_msg, sync_conn, trans_obj,
     session_obj) = check_transaction_status(trans_id)

    if not status or sync_conn is None or trans_obj is None or \
            session_obj is None:
        return internal_server_error(
            errormsg=TRANSACTION_STATUS_CHECK_FAILED
        )

    data = request.values if request.values else request.get_json(silent=True)
    if data is None:
        return make_json_response(
            status=410,
            success=0,
            errormsg=gettext(
                "Could not find the required parameter (query)."
            )
        )

    try:

        # This returns generator of records.
        status, gen, conn_obj = \
            sync_conn.execute_on_server_as_csv(records=10)

        if not status:
            return make_json_response(
                data={
                    'status': status, 'result': gen
                }
            )

        r = Response(
            gen(conn_obj,
                trans_obj,
                quote=blueprint.csv_quoting.get(),
                quote_char=blueprint.csv_quote_char.get(),
                field_separator=blueprint.csv_field_separator.get(),
                replace_nulls_with=blueprint.replace_nulls_with.get()),
            mimetype='text/csv' if
            blueprint.csv_field_separator.get() == ','
            else 'text/plain'
        )

        import time
        extn = 'csv' if blueprint.csv_field_separator.get() == ',' else 'txt'
        filename = data['filename'] if data.get('filename', '') != "" else \
            '{0}.{1}'.format(int(time.time()), extn)

        # We will try to encode report file name with latin-1
        # If it fails then we will fallback to default ascii file name
        # werkzeug only supports latin-1 encoding supported values
        try:
            tmp_file_name = filename
            tmp_file_name.encode('latin-1', 'strict')
        except UnicodeEncodeError:
            filename = "download.csv"

        r.headers[
            "Content-Disposition"
        ] = "attachment;filename={0}".format(filename)

        return r
    except (ConnectionLost, SSHTunnelConnectionLost):
        raise
    except Exception as e:
        current_app.logger.error(e)
        err_msg = "Error: {0}".format(
            e.strerror if hasattr(e, 'strerror') else str(e))
        return internal_server_error(errormsg=err_msg)


@blueprint.route(
    '/status/<int:trans_id>',
    methods=["GET"],
    endpoint='connection_status'
)
@pga_login_required
def query_tool_status(trans_id):
    """
    The task of this function to return the status of the current connection
    used in query tool instance with given transaction ID.
    Args:
        trans_id: Transaction ID

    Returns:
        Response with the connection status

        Psycopg Status Code Mapping:
        -----------------------------
        TRANSACTION_STATUS_IDLE     = 0
        TRANSACTION_STATUS_ACTIVE   = 1
        TRANSACTION_STATUS_INTRANS  = 2
        TRANSACTION_STATUS_INERROR  = 3
        TRANSACTION_STATUS_UNKNOWN  = 4
    """
    (status, error_msg, conn, trans_obj,
     session_obj) = check_transaction_status(trans_id)

    if not status and error_msg and isinstance(error_msg, str):
        return internal_server_error(
            errormsg=error_msg
        )

    if conn and trans_obj and session_obj:
        status = conn.transaction_status()

        if status is not None:
            # Check for the asynchronous notifies statements.
            notifies = conn.get_notifies()

            return make_json_response(
                data={
                    'status': status,
                    'message': gettext(
                        CONNECTION_STATUS_MESSAGE_MAPPING.get(status),
                    ),
                    'notifies': notifies
                }
            )
        else:
            return internal_server_error(
                errormsg=TRANSACTION_STATUS_CHECK_FAILED
            )
    else:
        return internal_server_error(
            errormsg=TRANSACTION_STATUS_CHECK_FAILED
        )


@blueprint.route(
    '/filter_dialog/<int:trans_id>',
    methods=["GET"], endpoint='get_filter_data'
)
@pga_login_required
def get_filter_data(trans_id):
    """
    This method is used to get all the columns for data sorting dialog.

    Args:
        trans_id: unique transaction id
    """

    status, error_msg, conn, trans_obj, session_ob = \
        check_transaction_status(trans_id)

    return FilterDialog.get(status, error_msg, conn, trans_obj, session_ob)


@blueprint.route(
    '/get_server_connection/<int:sgid>/<int:sid>',
    methods=["GET"], endpoint='_check_server_connection_status'
)
@pga_login_required
def _check_server_connection_status(sgid, sid=None):
    """
    This function returns the server connection details
    """
    try:
        driver = get_driver(PG_DEFAULT_DRIVER)
        from pgadmin.browser.server_groups.servers import \
            server_icon_and_background
        server = Server.query.filter_by(
            id=sid).first()

        manager = driver.connection_manager(server.id)
        conn = manager.connection()
        connected = conn.connected()

        msg = "Success"
        return make_json_response(
            data={
                'status': True,
                'msg': msg,
                'result': {
                    'server': connected
                }
            }
        )

    except Exception as e:
        current_app.logger.exception(e)
        return make_json_response(
            data={
                'status': False,
                'msg': ERROR_FETCHING_DATA,
                'result': {
                    'server': False
                }
            }
        )


@blueprint.route(
    '/new_connection_dialog/<int:sgid>/<int:sid>',
    methods=["GET"], endpoint='get_new_connection_data'
)
@blueprint.route(
    '/new_connection_dialog',
    methods=["GET"], endpoint='get_new_connection_servers'
)
@pga_login_required
def get_new_connection_data(sgid=None, sid=None):
    """
    This method is used to get required data for get new connection.
    :extract_sql_from_network_parameters,
    """
    try:
        driver = get_driver(PG_DEFAULT_DRIVER)
        from pgadmin.browser.server_groups.servers import \
            server_icon_and_background
        server_groups = ServerGroup.query.all()
        server_group_data = {server_group.name: [] for server_group in
                             server_groups}
        servers = Server.query.all()

        for server in servers:
            manager = driver.connection_manager(server.id)
            conn = manager.connection()
            connected = conn.connected()
            server_group_data[server.servers.name].append({
                'label': server.name,
                "value": server.id,
                'image': server_icon_and_background(connected, manager,
                                                    server),
                'fgcolor': server.fgcolor,
                'bgcolor': server.bgcolor,
                'connected': connected})

        msg = "Success"
        return make_json_response(
            data={
                'status': True,
                'msg': msg,
                'result': {
                    'server_list': server_group_data
                }
            }
        )

    except Exception as e:
        current_app.logger.exception(e)
        return make_json_response(
            data={
                'status': False,
                'msg': ERROR_FETCHING_DATA,
                'result': {
                    'server_list': []
                }
            }
        )


@blueprint.route(
    '/new_connection_database/<int:sgid>/<int:sid>',
    methods=["GET"], endpoint='get_new_connection_database'
)
@pga_login_required
def get_new_connection_database(sgid, sid=None):
    """
    This method is used to get required data for get new connection.
    :extract_sql_from_network_parameters,
    """
    try:
        database_list = []
        from pgadmin.utils.driver import get_driver
        manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
        conn = manager.connection()
        if conn.connected():
            is_connected = True
        else:
            is_connected = False
        if is_connected:
            if sid:
                template_path = 'databases/sql/#{0}#'.format(manager.version)
                last_system_oid = 0
                server_node_res = manager

                db_disp_res = None
                params = None
                if server_node_res and server_node_res.db_res:
                    db_disp_res = ", ".join(
                        ['%s'] * len(server_node_res.db_res.split(','))
                    )
                    params = tuple(server_node_res.db_res.split(','))
                sql = render_template(
                    "/".join([template_path, _NODES_SQL]),
                    last_system_oid=last_system_oid,
                    db_restrictions=db_disp_res
                )
                status, databases = conn.execute_dict(sql, params)
                _db = manager.db
                database_list = [
                    {
                        'label': database['name'],
                        'value': database['did'],
                        'selected': True if database['name'] == _db else False
                    } for database in databases['rows']]
            else:
                status = False

            msg = "Success"
            return make_json_response(
                data={
                    'status': status,
                    'msg': msg,
                    'result': {
                        'data': database_list,
                    }
                }
            )
        else:
            return make_json_response(
                data={
                    'status': False,
                    'msg': SERVER_CONNECTION_CLOSED,
                    'result': {
                        'database_list': [],
                    }
                }
            )
    except Exception as e:
        current_app.logger.exception(e)
        return make_json_response(
            data={
                'status': False,
                'msg': ERROR_FETCHING_DATA,
                'result': {
                    'database_list': [],
                }
            }
        )


@blueprint.route(
    '/new_connection_user/<int:sgid>/<int:sid>',
    methods=["GET"], endpoint='get_new_connection_user'
)
@pga_login_required
def get_new_connection_user(sgid, sid=None):
    """
    This method is used to get required data for get new connection.
    :extract_sql_from_network_parameters,
    """
    try:
        from pgadmin.utils.driver import get_driver
        manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
        conn = manager.connection()
        user_list = []
        if conn.connected():
            is_connected = True
        else:
            is_connected = False
        if is_connected:
            if sid:
                sql_path = 'roles/sql/#{0}#'.format(manager.version)
                status, users = conn.execute_2darray(
                    render_template(sql_path + _NODES_SQL)
                )
                _user = manager.user
                user_list = [
                    {'value': user['rolname'], 'label': user['rolname'],
                     'selected': True if user['rolname'] == _user else False}
                    for user in users['rows'] if user['rolcanlogin']]
            else:
                status = False

            msg = "Success"
            return make_json_response(
                data={
                    'status': status,
                    'msg': msg,
                    'result': {
                        'data': user_list,
                    }
                }
            )
        else:
            return make_json_response(
                data={
                    'status': False,
                    'msg': SERVER_CONNECTION_CLOSED,
                    'result': {
                        'user_list': [],
                    }
                }
            )
    except Exception as e:
        current_app.logger.exception(e)
        return make_json_response(
            data={
                'status': False,
                'msg': 'Unable to fetch data.',
                'result': {
                    'user_list': [],
                }
            }
        )


@blueprint.route(
    '/new_connection_role/<int:sgid>/<int:sid>',
    methods=["GET"], endpoint='get_new_connection_role'
)
@pga_login_required
def get_new_connection_role(sgid, sid=None):
    """
    This method is used to get required data for get new connection.
    :extract_sql_from_network_parameters,
    """
    try:
        from pgadmin.utils.driver import get_driver
        manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
        conn = manager.connection()
        role_list = []
        if conn.connected():
            is_connected = True
        else:
            is_connected = False
        if is_connected:
            if sid:
                sql_path = 'roles/sql/#{0}#'.format(manager.version)
                status, roles = conn.execute_2darray(
                    render_template(sql_path + _NODES_SQL)
                )
                role_list = [
                    {'value': role['rolname'], 'label': role['rolname']} for
                    role in roles['rows']]
            else:
                status = False

            msg = "Success"
            return make_json_response(
                data={
                    'status': status,
                    'msg': msg,
                    'result': {
                        'data': role_list,
                    }
                }
            )
        else:
            return make_json_response(
                data={
                    'status': False,
                    'msg': SERVER_CONNECTION_CLOSED,
                    'result': {
                        'user_list': [],
                    }
                }
            )
    except Exception as e:
        current_app.logger.exception(e)
        return make_json_response(
            data={
                'status': False,
                'msg': 'Unable to fetch data.',
                'result': {
                    'user_list': [],
                }
            }
        )


@blueprint.route(
    '/connect_server/<int:sid>',
    methods=["POST"],
    endpoint="connect_server"
)
@pga_login_required
def connect_server(sid):
    # Check if server is already connected then no need to reconnect again.
    server = Server.query.filter_by(id=sid).first()
    driver = get_driver(PG_DEFAULT_DRIVER)
    manager = driver.connection_manager(sid)

    conn = manager.connection()
    if conn.connected():
        return make_json_response(
            success=1,
            info=gettext("Server connected."),
            data={}
        )

    view = SchemaDiffRegistry.get_node_view('server')
    return view.connect(
        server.servergroup_id, sid
    )


@blueprint.route(
    '/filter_dialog/<int:trans_id>',
    methods=["PUT"], endpoint='set_filter_data'
)
@pga_login_required
def set_filter_data(trans_id):
    """
    This method is used to update the columns for data sorting dialog.

    Args:
        trans_id: unique transaction id
    """

    status, error_msg, conn, trans_obj, session_ob = \
        check_transaction_status(trans_id)

    return FilterDialog.save(
        status, error_msg, conn, trans_obj, session_ob,
        request=request,
        trans_id=trans_id
    )


@blueprint.route(
    '/query_history/<int:trans_id>',
    methods=["POST"], endpoint='add_query_history'
)
@pga_login_required
def add_query_history(trans_id):
    """
    This method adds to query history for user/server/database

    Args:
        sid: server id
        did: database id
    """

    _, _, conn, trans_obj, _ = check_transaction_status(trans_id)

    if not trans_obj:
        return make_json_response(
            data={
                'status': False,
            }
        )
    return QueryHistory.save(current_user.id, trans_obj.sid, conn.db,
                             request=request)


@blueprint.route(
    '/query_history/<int:trans_id>',
    methods=["DELETE"], endpoint='clear_query_history'
)
@pga_login_required
def clear_query_history(trans_id):
    """
    This method returns clears history for user/server/database

    Args:
        sid: server id
        did: database id
    """

    _, _, conn, trans_obj, _ = check_transaction_status(trans_id)
    filter_json = request.get_json(silent=True)
    return QueryHistory.clear(current_user.id, trans_obj.sid, conn.db,
                              filter_json)


@blueprint.route(
    '/query_history/<int:trans_id>',
    methods=["GET"], endpoint='get_query_history'
)
@pga_login_required
def get_query_history(trans_id):
    """
    This method returns query history for user/server/database

    Args:
        sid: server id
        did: database id
    """

    _, _, conn, trans_obj, _ = check_transaction_status(trans_id)

    return QueryHistory.get(current_user.id, trans_obj.sid, conn.db)


@blueprint.route(
    '/get_macros/<int:trans_id>',
    methods=["GET"], endpoint='get_macros'
)
@blueprint.route(
    '/get_macros/<int:macro_id>/<int:trans_id>',
    methods=["GET"], endpoint='get_macro'
)
@pga_login_required
def macros(trans_id, macro_id=None, json_resp=True):
    """
    This method is used to get all the columns for data sorting dialog.

    Args:
        trans_id: unique transaction id
        macro_id: Macro id
    """

    _, _, _, _, _ = check_transaction_status(trans_id)

    return get_macros(macro_id, json_resp)


@blueprint.route(
    '/set_macros/<int:trans_id>',
    methods=["PUT"], endpoint='set_macros'
)
@pga_login_required
def update_macros(trans_id):
    """
    This method is used to get all the columns for data sorting dialog.

    Args:
        trans_id: unique transaction id
    """

    _, _, _, _, _ = check_transaction_status(trans_id)

    return set_macros()