示例#1
0
文件: query.py 项目: zjjxxlgb/Archery
def query(request):
    """
    获取SQL查询结果
    :param request:
    :return:
    """
    instance_name = request.POST.get('instance_name')
    sql_content = request.POST.get('sql_content')
    db_name = request.POST.get('db_name')
    limit_num = int(request.POST.get('limit_num', 0))
    schema_name = request.POST.get('schema_name', None)
    user = request.user

    result = {'status': 0, 'msg': 'ok', 'data': {}}
    try:
        instance = Instance.objects.get(instance_name=instance_name)
    except Instance.DoesNotExist:
        result['status'] = 1
        result['msg'] = '实例不存在'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    # 服务器端参数验证
    if None in [sql_content, db_name, instance_name, limit_num]:
        result['status'] = 1
        result['msg'] = '页面提交参数可能为空'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    try:
        config = SysConfig()
        # 查询前的检查,禁用语句检查,语句切分
        query_engine = get_engine(instance=instance)
        query_check_info = query_engine.query_check(db_name=db_name,
                                                    sql=sql_content)
        if query_check_info.get('bad_query'):
            # 引擎内部判断为 bad_query
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        if query_check_info.get(
                'has_star') and config.get('disable_star') is True:
            # 引擎内部判断为有 * 且禁止 * 选项打开
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        sql_content = query_check_info['filtered_sql']

        # 查询权限校验,并且获取limit_num
        priv_check_info = query_priv_check(user, instance, db_name,
                                           sql_content, limit_num)
        if priv_check_info['status'] == 0:
            limit_num = priv_check_info['data']['limit_num']
            priv_check = priv_check_info['data']['priv_check']
        else:
            result['status'] = 1
            result['msg'] = priv_check_info['msg']
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        # explain的limit_num设置为0
        limit_num = 0 if re.match(r"^explain",
                                  sql_content.lower()) else limit_num

        # 对查询sql增加limit限制或者改写语句
        sql_content = query_engine.filter_sql(sql=sql_content,
                                              limit_num=limit_num)

        # 先获取查询连接,用于后面查询复用连接以及终止会话
        query_engine.get_connection(db_name=db_name)
        thread_id = query_engine.thread_id
        max_execution_time = int(config.get('max_execution_time', 60))
        # 执行查询语句,并增加一个定时终止语句的schedule,timeout=max_execution_time
        if thread_id:
            schedule_name = f'query-{time.time()}'
            run_date = (datetime.datetime.now() +
                        datetime.timedelta(seconds=max_execution_time))
            add_kill_conn_schedule(schedule_name, run_date, instance.id,
                                   thread_id)
        with FuncTimer() as t:
            # 获取主从延迟信息
            seconds_behind_master = query_engine.seconds_behind_master
            if instance.db_type == 'pgsql':  # TODO 此处判断待优化,请在 修改传参方式后去除
                query_result = query_engine.query(db_name,
                                                  sql_content,
                                                  limit_num,
                                                  schema_name=schema_name)
            else:
                query_result = query_engine.query(db_name, sql_content,
                                                  limit_num)
        query_result.query_time = t.cost
        # 返回查询结果后删除schedule
        if thread_id:
            del_schedule(schedule_name)

        # 查询异常
        if query_result.error:
            result['status'] = 1
            result['msg'] = query_result.error
        # 数据脱敏,仅对查询无错误的结果集进行脱敏,并且按照query_check配置是否返回
        elif config.get('data_masking'):
            try:
                with FuncTimer() as t:
                    masking_result = query_engine.query_masking(
                        db_name, sql_content, query_result)
                masking_result.mask_time = t.cost
                # 脱敏出错
                if masking_result.error:
                    # 开启query_check,直接返回异常,禁止执行
                    if config.get('query_check'):
                        result['status'] = 1
                        result['msg'] = f'数据脱敏异常:{masking_result.error}'
                    # 关闭query_check,忽略错误信息,返回未脱敏数据,权限校验标记为跳过
                    else:
                        logger.warning(
                            f'数据脱敏异常,按照配置放行,查询语句:{sql_content},错误信息:{masking_result.error}'
                        )
                        query_result.error = None
                        result['data'] = query_result.__dict__
                # 正常脱敏
                else:
                    result['data'] = masking_result.__dict__
            except Exception as msg:
                # 抛出未定义异常,并且开启query_check,直接返回异常,禁止执行
                if config.get('query_check'):
                    result['status'] = 1
                    result['msg'] = f'数据脱敏异常,请联系管理员,错误信息:{msg}'
                # 关闭query_check,忽略错误信息,返回未脱敏数据,权限校验标记为跳过
                else:
                    logger.warning(
                        f'数据脱敏异常,按照配置放行,查询语句:{sql_content},错误信息:{msg}')
                    query_result.error = None
                    result['data'] = query_result.__dict__
        # 无需脱敏的语句
        else:
            result['data'] = query_result.__dict__

        # 仅将成功的查询语句记录存入数据库
        if not query_result.error:
            result['data']['seconds_behind_master'] = seconds_behind_master
            if int(limit_num) == 0:
                limit_num = int(query_result.affected_rows)
            else:
                limit_num = min(int(limit_num),
                                int(query_result.affected_rows))
            query_log = QueryLog(username=user.username,
                                 user_display=user.display,
                                 db_name=db_name,
                                 instance_name=instance.instance_name,
                                 sqllog=sql_content,
                                 effect_row=limit_num,
                                 cost_time=query_result.query_time,
                                 priv_check=priv_check,
                                 hit_rule=query_result.mask_rule_hit,
                                 masking=query_result.is_masked)
            # 防止查询超时
            try:
                query_log.save()
            except OperationalError:
                connection.close()
                query_log.save()
    except Exception as e:
        logger.error(
            f'查询异常报错,查询语句:{sql_content}\n,错误信息:{traceback.format_exc()}')
        result['status'] = 1
        result['msg'] = f'查询异常报错,错误信息:{e}'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')
    # 返回查询结果
    try:
        return HttpResponse(json.dumps(result,
                                       cls=ExtendJSONEncoderFTime,
                                       bigint_as_string=True),
                            content_type='application/json')
    # 虽然能正常返回,但是依然会乱码
    except UnicodeDecodeError:
        return HttpResponse(json.dumps(result,
                                       default=str,
                                       bigint_as_string=True,
                                       encoding='latin1'),
                            content_type='application/json')
示例#2
0
def query(request):
    """
    获取SQL查询结果
    :param request:
    :return:
    """
    instance_name = request.POST.get('instance_name')
    sql_content = request.POST.get('sql_content')
    db_name = request.POST.get('db_name')
    limit_num = int(request.POST.get('limit_num', 0))
    user = request.user

    result = {'status': 0, 'msg': 'ok', 'data': {}}
    try:
        instance = Instance.objects.get(instance_name=instance_name)
    except Instance.DoesNotExist:
        result['status'] = 1
        result['msg'] = '实例不存在'
        return result

    # 服务器端参数验证
    if not (sql_content and db_name and instance_name and limit_num):
        result['status'] = 1
        result['msg'] = '页面提交参数可能为空'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    try:
        # 查询前的检查,禁用语句检查,语句切分
        query_engine = get_engine(instance=instance)
        query_check_info = query_engine.query_check(db_name=db_name,
                                                    sql=sql_content)
        if query_check_info.get('bad_query'):
            # 引擎内部判断为 bad_query
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        if query_check_info.get(
                'has_star') and SysConfig().get('disable_star') is True:
            # 引擎内部判断为有 * 且禁止 * 选项打开
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        else:
            sql_content = query_check_info['filtered_sql']

        # 查询权限校验,并且获取limit_num
        priv_check_info = query_priv_check(user, instance, db_name,
                                           sql_content, limit_num)
        if priv_check_info['status'] == 0:
            limit_num = priv_check_info['data']['limit_num']
            priv_check = priv_check_info['data']['priv_check']
        else:
            result['status'] = 1
            result['msg'] = priv_check_info['msg']
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        # explain的limit_num设置为0
        limit_num = 0 if re.match(r"^explain",
                                  sql_content.lower()) else limit_num

        # 对查询sql增加limit限制或者改写语句
        sql_content = query_engine.filter_sql(sql=sql_content,
                                              limit_num=limit_num)

        # 执行查询语句,统计执行时间
        t_start = time.time()
        query_result = query_engine.query(db_name=str(db_name),
                                          sql=sql_content,
                                          limit_num=limit_num)
        t_end = time.time()
        query_result.query_time = "%5s" % "{:.4f}".format(t_end - t_start)

        # 数据脱敏,仅对查询无错误的结果集进行脱敏
        if SysConfig().get('data_masking') and query_result.error is None:
            try:
                # 记录脱敏时间
                t_start = time.time()
                masking_result = query_engine.query_masking(
                    db_name=db_name, sql=sql_content, resultset=query_result)
                t_end = time.time()
                masking_result.mask_time = "%5s" % "{:.4f}".format(t_end -
                                                                   t_start)
                # 脱敏出错,并且开启query_check,直接返回异常,禁止执行
                if masking_result.error and SysConfig().get('query_check'):
                    result['status'] = 1
                    result['msg'] = masking_result.error
                # 脱敏出错,关闭query_check,忽略错误信息,返回未脱敏数据
                elif masking_result.error and not SysConfig().get(
                        'query_check'):
                    query_result.error = None
                    result['data'] = query_result.__dict__
                # 正常脱敏
                else:
                    result['data'] = masking_result.__dict__
            except Exception as e:
                logger.error(
                    f'数据脱敏异常,查询语句:{sql_content}\n,错误信息:{traceback.format_exc()}'
                )
                # 抛出未定义异常,并且开启query_check,直接返回异常,禁止执行
                if SysConfig().get('query_check'):
                    result['status'] = 1
                    result['msg'] = f'数据脱敏异常,请联系管理员,错误信息:{e}'
                # 关闭query_check,忽略错误信息,返回未脱敏数据
                else:
                    query_result.error = None
                    result['data'] = query_result.__dict__
        # 无需脱敏的语句
        else:
            if query_result.error:
                result['status'] = 1
                result['msg'] = query_result.error
            else:
                result['data'] = query_result.__dict__

        # 仅将成功的查询语句记录存入数据库
        if not query_result.error:
            if int(limit_num) == 0:
                limit_num = int(query_result.affected_rows)
            else:
                limit_num = min(int(limit_num),
                                int(query_result.affected_rows))
            query_log = QueryLog(username=user.username,
                                 user_display=user.display,
                                 db_name=db_name,
                                 instance_name=instance.instance_name,
                                 sqllog=sql_content,
                                 effect_row=limit_num,
                                 cost_time=query_result.query_time,
                                 priv_check=priv_check,
                                 hit_rule=query_result.mask_rule_hit,
                                 masking=query_result.is_masked)
            # 防止查询超时
            try:
                query_log.save()
            except:
                connection.close()
                query_log.save()
    except Exception as e:
        logger.error(
            f'查询异常报错,查询语句:{sql_content}\n,错误信息:{traceback.format_exc()}')
        result['status'] = 1
        result['msg'] = f'查询异常报错,错误信息:{e}'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')
    # 返回查询结果
    try:
        return HttpResponse(json.dumps(result,
                                       cls=ExtendJSONEncoder,
                                       bigint_as_string=True),
                            content_type='application/json')
    # 虽然能正常返回,但是依然会乱码
    except UnicodeDecodeError:
        return HttpResponse(json.dumps(result,
                                       default=str,
                                       bigint_as_string=True,
                                       encoding='latin1'),
                            content_type='application/json')
示例#3
0
文件: query.py 项目: zhanglei/Archery
def query(request):
    """
    获取SQL查询结果
    :param request:
    :return:
    """
    instance_name = request.POST.get('instance_name')
    sql_content = request.POST.get('sql_content')
    db_name = request.POST.get('db_name')
    limit_num = int(request.POST.get('limit_num', 0))
    user = request.user

    result = {'status': 0, 'msg': 'ok', 'data': {}}
    try:
        instance = Instance.objects.get(instance_name=instance_name)
    except Instance.DoesNotExist:
        result['status'] = 1
        result['msg'] = '实例不存在'
        return result

    # 服务器端参数验证
    if None in [sql_content, db_name, instance_name, limit_num]:
        result['status'] = 1
        result['msg'] = '页面提交参数可能为空'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    try:
        config = SysConfig()
        # 查询前的检查,禁用语句检查,语句切分
        query_engine = get_engine(instance=instance)
        query_check_info = query_engine.query_check(db_name=db_name,
                                                    sql=sql_content)
        if query_check_info.get('bad_query'):
            # 引擎内部判断为 bad_query
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        if query_check_info.get(
                'has_star') and config.get('disable_star') is True:
            # 引擎内部判断为有 * 且禁止 * 选项打开
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        sql_content = query_check_info['filtered_sql']

        # 查询权限校验,并且获取limit_num
        priv_check_info = query_priv_check(user, instance, db_name,
                                           sql_content, limit_num)
        if priv_check_info['status'] == 0:
            limit_num = priv_check_info['data']['limit_num']
            priv_check = priv_check_info['data']['priv_check']
        else:
            result['status'] = 1
            result['msg'] = priv_check_info['msg']
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        # explain的limit_num设置为0
        limit_num = 0 if re.match(r"^explain",
                                  sql_content.lower()) else limit_num

        # 对查询sql增加limit限制或者改写语句
        sql_content = query_engine.filter_sql(sql=sql_content,
                                              limit_num=limit_num)

        # 执行查询语句,timeout=max_execution_time
        max_execution_time = int(config.get('max_execution_time', 60))
        query_task_id = async_task(query_engine.query,
                                   db_name=str(db_name),
                                   sql=sql_content,
                                   limit_num=limit_num,
                                   timeout=max_execution_time,
                                   cached=60)
        # 等待执行结果,max_execution_time后还没有返回结果代表将会被终止
        query_task = fetch(query_task_id,
                           wait=max_execution_time * 1000,
                           cached=True)
        # 在max_execution_time内执行结束
        if query_task:
            if query_task.success:
                query_result = query_task.result
                query_result.query_time = query_task.time_taken()
            else:
                query_result = ResultSet(full_sql=sql_content)
                query_result.error = query_task.result
        # 等待超时,async_task主动关闭连接
        else:
            query_result = ResultSet(full_sql=sql_content)
            query_result.error = f'查询时间超过 {max_execution_time} 秒,已被主动终止,请优化语句或者联系管理员。'

        # 查询异常
        if query_result.error:
            result['status'] = 1
            result['msg'] = query_result.error
        # 数据脱敏,仅对查询无错误的结果集进行脱敏,并且按照query_check配置是否返回
        elif config.get('data_masking'):
            query_masking_task_id = async_task(query_engine.query_masking,
                                               db_name=db_name,
                                               sql=sql_content,
                                               resultset=query_result,
                                               cached=60)
            query_masking_task = fetch(query_masking_task_id,
                                       wait=60 * 1000,
                                       cached=True)
            if query_masking_task.success:
                masking_result = query_masking_task.result
                masking_result.mask_time = query_masking_task.time_taken()
                # 脱敏出错
                if masking_result.error:
                    # 开启query_check,直接返回异常,禁止执行
                    if config.get('query_check'):
                        result['status'] = 1
                        result['msg'] = masking_result.error
                    # 关闭query_check,忽略错误信息,返回未脱敏数据,权限校验标记为跳过
                    else:
                        query_result.error = None
                        priv_check = False
                        result['data'] = query_result.__dict__
                # 正常脱敏
                else:
                    result['data'] = masking_result.__dict__
            else:
                logger.error(
                    f'数据脱敏异常,查询语句:{sql_content}\n,错误信息:{traceback.format_exc()}'
                )
                # 抛出未定义异常,并且开启query_check,直接返回异常,禁止执行
                if config.get('query_check'):
                    result['status'] = 1
                    result[
                        'msg'] = f'数据脱敏异常,请联系管理员,错误信息:{query_masking_task.result}'
                # 关闭query_check,忽略错误信息,返回未脱敏数据,权限校验标记为跳过
                else:
                    query_result.error = None
                    priv_check = False
                    result['data'] = query_result.__dict__
        # 无需脱敏的语句
        else:
            result['data'] = query_result.__dict__

        # 仅将成功的查询语句记录存入数据库
        if not query_result.error:
            if int(limit_num) == 0:
                limit_num = int(query_result.affected_rows)
            else:
                limit_num = min(int(limit_num),
                                int(query_result.affected_rows))
            query_log = QueryLog(username=user.username,
                                 user_display=user.display,
                                 db_name=db_name,
                                 instance_name=instance.instance_name,
                                 sqllog=sql_content,
                                 effect_row=limit_num,
                                 cost_time=query_result.query_time,
                                 priv_check=priv_check,
                                 hit_rule=query_result.mask_rule_hit,
                                 masking=query_result.is_masked)
            # 防止查询超时
            try:
                query_log.save()
            except OperationalError:
                connection.close()
                query_log.save()
    except Exception as e:
        logger.error(
            f'查询异常报错,查询语句:{sql_content}\n,错误信息:{traceback.format_exc()}')
        result['status'] = 1
        result['msg'] = f'查询异常报错,错误信息:{e}'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')
    # 返回查询结果
    try:
        return HttpResponse(json.dumps(result,
                                       cls=ExtendJSONEncoder,
                                       bigint_as_string=True),
                            content_type='application/json')
    # 虽然能正常返回,但是依然会乱码
    except UnicodeDecodeError:
        return HttpResponse(json.dumps(result,
                                       default=str,
                                       bigint_as_string=True,
                                       encoding='latin1'),
                            content_type='application/json')
示例#4
0
def newquery(request):
    """正式提交SQL, 此处生成工单"""
    workflow_name = request.POST.get('workflow_name')
    demand_url = request.POST.get('demand_url', '')
    group_name = request.POST.get('group_name')
    instance_name = request.POST.get('instance_name')
    db_name = request.POST.get('db_name')
    first_run_time = request.POST.get('first_run_time')
    schedule_type = request.POST.get('period')
    minutes = request.POST.get('minutes')
    receivers = request.POST.getlist('receivers')
    cc_list = request.POST.getlist('cc_list')
    is_backup = False
    sql_content = request.POST.get('sql_content').strip()

    result = {'status': 0, 'msg': 'ok', 'data': {}}
    # 服务器端参数验证
    if not all([
            workflow_name, group_name, instance_name, db_name, first_run_time,
            schedule_type, sql_content
    ]):
        result['status'] = 1
        result['msg'] = '请检查提交工单填写内容是否完整'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    user = request.user
    group_id = ResourceGroup.objects.get(group_name=group_name).group_id
    instance = Instance.objects.get(instance_name=instance_name)

    # 验证组权限(用户是否在该组、该组是否有指定实例)
    try:
        user_instances(user,
                       tag_codes=['can_read']).get(instance_name=instance_name)
    except instance.DoesNotExist:
        result['status'] = 1
        result['msg'] = '你所在组未关联该实例'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    try:
        config = SysConfig()
        # 查询前的检查,禁用语句检查,语句切分
        query_engine = get_engine(instance=instance)
        query_check_info = query_engine.query_check(db_name=db_name,
                                                    sql=sql_content)
        if query_check_info.get('bad_query'):
            # 引擎内部判断为 bad_query
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        if query_check_info.get(
                'has_star') and config.get('disable_star') is True:
            # 引擎内部判断为有 * 且禁止 * 选项打开
            result['status'] = 1
            result['msg'] = query_check_info.get('msg')
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
        sql_content = query_check_info['filtered_sql']

        # 查询权限校验,并且获取limit_num
        priv_check_info = query_priv_check(user, instance, db_name,
                                           sql_content, 0)
        if priv_check_info['status'] != 0:
            result['status'] = 1
            result['msg'] = priv_check_info['msg']
            return HttpResponse(json.dumps(result),
                                content_type='application/json')
    except Exception as e:
        logger.error(
            f'查询异常报错,查询语句:{sql_content}\n,错误信息:{traceback.format_exc()}')
        result['status'] = 1
        result['msg'] = f'查询异常报错,错误信息:{e}'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')

    check_result = ReviewSet(full_sql=sql_content)
    check_result.rows = [
        ReviewResult(
            id=1,
            errlevel=0,
            stagestatus='Audit completed',
            errormessage='None',
            sql=sql_content,
            affected_rows=0,
            execute_time=0,
        )
    ]
    # 调用工作流生成工单
    # 使用事务保持数据一致性
    try:
        with transaction.atomic():
            # 存进数据库里
            sql_workflow = SqlWorkflow.objects.create(
                order_type="sqlcron_order",
                workflow_name=workflow_name,
                demand_url=demand_url,
                group_id=group_id,
                group_name=group_name,
                engineer=request.user.username,
                engineer_display=request.user.display,
                audit_auth_groups=Audit.settings(
                    group_id, WorkflowDict.workflow_type['sqlreview']),
                status='workflow_manreviewing',
                is_backup=is_backup,
                instance=instance,
                db_name=db_name,
                is_manual=0,
                syntax_type=3,  #0、未知,1、DDL,2、DML 3、QUERY'
                create_time=timezone.now(),
                run_date_start=None,
                run_date_end=None,
                cc_list=cc_list,
            )
            sql_workflow.receivers.set(
                Users.objects.filter(username__in=receivers))
            sql_workflow_content = SqlWorkflowContent.objects.create(
                workflow=sql_workflow,
                sql_content=sql_content,
                review_content=check_result.json(),
                execute_result='')
            sched = schedule(
                'sql.utils.query_sql.query',
                sql_workflow.id,
                hook='sql.utils.query_sql.query_callback',
                name=f'sqlcron-{sql_workflow.id}',
                schedule_type=schedule_type,
                minutes=minutes,
                next_run=first_run_time,
                repeats=0,  # 在审批结束前创建但不启用
                timeout=-1,
            )
            sql_workflow.schedule = sched
            sql_workflow.save()
            sql_workflow_content.save()

            # 调用工作流插入审核信息, 查询权限申请workflow_type=2
            Audit.add(WorkflowDict.workflow_type['sqlreview'], sql_workflow.id)
    except Exception as e:
        logger.error(f"提交工单报错,错误信息:{traceback.format_exc()}")
        result['status'] = 1
        result['msg'] = f'提交工单报错,错误信息:{e}'
        return HttpResponse(json.dumps(result),
                            content_type='application/json')
    else:
        # 进行消息通知
        audit_id = Audit.detail_by_workflow_id(
            workflow_id=sql_workflow.id,
            workflow_type=WorkflowDict.workflow_type['sqlreview']).audit_id
        async_task(notify_for_audit,
                   audit_id=audit_id,
                   cc_users=receivers,
                   timeout=60,
                   task_name=f'sqlreview-submit-{sql_workflow.id}')

    result['status'] = 0
    result['data'] = {
        'redirect': reverse('sql:sqlcrondetail', args=(sql_workflow.id, ))
    }
    return HttpResponse(json.dumps(result), content_type='application/json')
示例#5
0
def query(request):
    """
    获取SQL查询结果
    :param request:
    :return:
    """
    instance_name = request.POST.get('instance_name')
    sql_content = request.POST.get('sql_content')
    db_name = request.POST.get('db_name')
    limit_num = request.POST.get('limit_num')
    user = request.user

    result = {'status': 0, 'msg': 'ok', 'data': {}}
    try:
        instance = Instance.objects.get(instance_name=instance_name)
    except Instance.DoesNotExist:
        result['status'] = 1
        result['msg'] = '实例不存在'
        return result

    # 服务器端参数验证
    if sql_content is None or db_name is None or instance_name is None or limit_num is None:
        result['status'] = 1
        result['msg'] = '页面提交参数可能为空'
        return HttpResponse(json.dumps(result), content_type='application/json')

    # 删除注释语句,进行语法判断
    sql_content = sqlparse.format(sql_content.strip(), strip_comments=True)
    sql_list = sqlparse.split(sql_content)
    # 执行第一条有效sql
    sql_content = sql_list[0].rstrip(';')
    if re.match(r"^select|^show|^explain", sql_content, re.I) is None:
        result['status'] = 1
        result['msg'] = '仅支持^select|^show|^explain语法,请联系管理员!'
        return HttpResponse(json.dumps(result), content_type='application/json')

    try:
        # 查询权限校验
        priv_check_info = query_priv_check(user, instance_name, db_name, sql_content, limit_num)
        if priv_check_info['status'] == 0:
            limit_num = priv_check_info['data']['limit_num']
            priv_check = priv_check_info['data']['priv_check']
        else:
            result['status'] = priv_check_info['status']
            result['msg'] = priv_check_info['msg']
            data = ResultSet(full_sql=sql_content)
            data.error = priv_check_info['msg']
            result['data'] = data.__dict__
            return HttpResponse(json.dumps(result), content_type='application/json')
        limit_num = 0 if re.match(r"^explain", sql_content.lower()) else limit_num

        # 查询检查
        query_engine = get_engine(instance=instance)
        filter_result = query_engine.query_check(db_name=db_name, sql=sql_content, limit_num=limit_num)
        if filter_result.get('bad_query'):
            # 引擎内部判断为 bad_query
            result['status'] = 1
            result['msg'] = filter_result.get('msg')
            return HttpResponse(json.dumps(result), content_type='application/json')
        if filter_result.get('has_star') and SysConfig().get('disable_star') is True:
            # 引擎内部判断为有 * 且禁止 * 选项打开
            result['status'] = 1
            result['msg'] = filter_result.get('msg')
            return HttpResponse(json.dumps(result), content_type='application/json')
        else:
            sql_content = filter_result['filtered_sql']
        sql_content = sql_content + ';'

        # 执行查询语句,统计执行时间
        t_start = time.time()
        query_result = query_engine.query(db_name=str(db_name), sql=sql_content, limit_num=limit_num)
        t_end = time.time()
        query_result.query_time = "%5s" % "{:.4f}".format(t_end - t_start)

        # 数据脱敏,同样需要检查配置,是否开启脱敏,语法树解析是否允许出错继续执行
        hit_rule = 0 if re.match(r"^select", sql_content.lower()) else 2  # 查询是否命中脱敏规则,0, '未知', 1, '命中', 2, '未命中'
        masking = 2  # 查询结果是否正常脱敏,1, '是', 2, '否'
        t_start = time.time()
        # 仅对正确查询的语句进行脱敏
        if SysConfig().get('data_masking') and re.match(r"^select", sql_content.lower()) and query_result.error is None:
            try:
                query_result = query_engine.query_masking(db_name=db_name, sql=sql_content, resultset=query_result)
                if query_result.is_critical is True and SysConfig().get('query_check'):
                    masking_result = {'status': query_result.status,
                                      'msg': query_result.error,
                                      'data': query_result.__dict__}
                    return HttpResponse(json.dumps(masking_result), content_type='application/json')
                else:
                    # 重置脱敏结果,返回未脱敏数据
                    query_result.status = 0
                    query_result.error = None
                    # 实际未命中, 则显示为未做脱敏
                    if query_result.is_masked:
                        masking = 1
                        hit_rule = 1
            except Exception:
                logger.error(traceback.format_exc())
                # 报错, 未脱敏, 未命中
                hit_rule = 2
                masking = 2
                if SysConfig().get('query_check'):
                    result['status'] = 1
                    result['msg'] = '脱敏数据报错,请联系管理员'
                    return HttpResponse(json.dumps(result), content_type='application/json')

        t_end = time.time()
        query_result.mask_time = "%5s" % "{:.4f}".format(t_end - t_start)
        sql_result = query_result.__dict__

        result['data'] = sql_result

        # 成功的查询语句记录存入数据库
        if sql_result.get('error'):
            pass
        else:
            if int(limit_num) == 0:
                limit_num = int(sql_result['affected_rows'])
            else:
                limit_num = min(int(limit_num), int(sql_result['affected_rows']))
            query_log = QueryLog(
                username=user.username,
                user_display=user.display,
                db_name=db_name,
                instance_name=instance.instance_name,
                sqllog=sql_content,
                effect_row=limit_num,
                cost_time=query_result.query_time,
                priv_check=priv_check,
                hit_rule=hit_rule,
                masking=masking
            )
            # 防止查询超时
            try:
                query_log.save()
            except:
                connection.close()
                query_log.save()
    except Exception as e:
        logger.error(traceback.format_exc())
        result['status'] = 1
        result['msg'] = str(e)

    # 返回查询结果
    try:
        return HttpResponse(json.dumps(result, cls=ExtendJSONEncoder, bigint_as_string=True),
                            content_type='application/json')
    except Exception:
        return HttpResponse(json.dumps(result, default=str, bigint_as_string=True, encoding='latin1'),
                            content_type='application/json')