コード例 #1
0
ファイル: dealsqltext.py プロジェクト: EvanMatlon/Platform
def dealsqltext(sqltext):
    lexerSplitor = splitor.LexerSplitor()
    list_sql = []
    for sql in lexerSplitor.split(sqltext):
        sql = lexerSplitor.remove_sqlcomment(sql)  # 去除单行和多行注释 hint信息
        sql = sql.replace('\t', ' ')  #tab符改为空格
        sql = sql.replace('\n', ' ')  #换行符改为空格
        sql = sql.replace(' , ', ',')  #逗号前后空格删除
        sql = sql.replace(', ', ',')
        sql = sql.replace(' ,', ',')
        sql = sql.replace('(', ' (')  #左括号前添加空格   右括号后添加空格
        sql = sql.replace(')', ') ')
        sql = removespaces(sql)  #删除多余的空格
        #sql=sql.upper() #转为大写 这个不对 注释语句里面的值是小写的呢
        list_sql.append(sql)
        #换行符的问题

    return list_sql
コード例 #2
0
def dbause_execute(request):  #ajax
    #获取前端传入的数据和后台数据库数据
    try:
        audit_batch = request.GET['batch']
        executor = request.user.username
        re_batch_info = models.T_DMLAUDIT_BATCH_INFO.objects.get(
            audit_batch=audit_batch)
        re_modify = re_batch_info.t_dmlaudit_batch_detail_set.all()
        #获取连接串信息
        onedbinfo = cmdb.models.T_CMDB_DBINFO.objects.get(
            db_type=re_batch_info.db_type, app_name=re_batch_info.app_name)
        if onedbinfo.db_type == 'oracle':
            auditobject=dmlaudit_oracle.DmlAudit(onedbinfo.username,onedbinfo.password,onedbinfo.ipadress,\
            onedbinfo.port,onedbinfo.servicename)
        elif onedbinfo.db_type == 'mysql':
            auditobject=dmlaudit_mysql.DmlAudit(onedbinfo.username,onedbinfo.password,onedbinfo.ipadress,\
            onedbinfo.port,onedbinfo.skema)
            auditobject.execsql("SET autocommit=off")
    except:
        return HttpResponse("连接或后台数据异常,请刷新页面并重试")
    else:
        try:
            #防止DBA同时执行
            if re_batch_info.execute_status == 'init':  #必须是待执行状态
                re_batch_info.execute_status = "doing"
                re_batch_info.save()
            else:
                if re_batch_info.execute_status == 'suc':
                    return HttpResponse("已被他人执行成功")
                elif re_batch_info.execute_status == 'fail':
                    return HttpResponse("已被他人执行失败")
                elif re_batch_info.execute_status == 'doing':
                    return HttpResponse("正被他人执行中")

            #执行批次中的语句(备份)
            exefailflag = 0
            backupfailflag = 0
            execute_status = ''
            exe_failreason = ''
            #os.chdir(constant.backup_filepath)会出现报错 不要在项目中切换路径 使用绝对路径来处理
            backupflag = 0
            list_backupfilename = []

            for obj in re_modify:
                if obj.sqltype == 'update' or obj.sqltype == 'delete':  #需要备份
                    #获取备份语句并执行
                    func_name = obj.sqltype + "_change"
                    lexerSplitor = splitor.LexerSplitor()
                    uncomment_sqltext = lexerSplitor.remove_sqlcomment(
                        obj.sqltext)
                    backupsql = getattr(auditobject,
                                        func_name)(uncomment_sqltext,
                                                   1)  #这里取消注释,备份语句一般不会出错
                    #print backupsql
                    list_backup = auditobject.execsql(
                        backupsql)  #要么就是list 要么就是str
                    if isinstance(list_backup, str):
                        backupfailflag = 1  #备份语句执行失败 全流程结果
                        backupfailreason = "第" + str(
                            obj.sqlnum) + "句备份失败--" + list_backup
                        break
                    else:
                        backupfilename = str(audit_batch) + "_" + str(
                            obj.sqlnum) + ".txt"
                        form_txt.Maketxt(constant.backup_filepath,
                                         backupfilename, list_backup)  #备份到txt
                        backupflag = 1
                        list_backupfilename.append(backupfilename)

                    str_failreason = auditobject.execsql(
                        obj.sqltext)  #正常是none 报错返回str (select返回list)
                    if str_failreason is not None:  #isinstance(str_failreason,str)
                        exefailflag = 1  #语句执行失败 全流程结束
                        exefailreason = "第" + str(
                            obj.sqlnum) + "句执行失败--" + str_failreason
                        break

                else:  #不需要备份
                    str_failreason = auditobject.execsql(obj.sqltext)
                    if str_failreason is not None:
                        exefailflag = 1
                        exefailreason = "第" + str(
                            obj.sqlnum) + "句执行失败--" + str_failreason
                        break

            if backupflag == 1:
                #压缩文件
                form_txt.Makezip(constant.backup_filepath,
                                 audit_batch + '.zip', list_backupfilename)

        except:
            if re_batch_info.execute_status == 'doing':  #状态还原
                re_batch_info.execute_status = "init"
                re_batch_info.save()
            try:  #mysql下可能是超时 会话杀掉了 close_rollback会失败的
                auditobject.close_rollback()
            except:
                pass
            return HttpResponse("平台发生非预期错误,请刷新页面")
        else:

            if backupfailflag == 1:
                execute_status = 'fail'
                exe_failreason = backupfailreason
                try:  #mysql下可能是超时 会话杀掉了 close_rollback会失败的
                    auditobject.close_rollback()
                except:
                    pass

            elif exefailflag == 1:
                execute_status = 'fail'
                exe_failreason = exefailreason
                try:  #mysql下可能是超时 会话杀掉了 close_rollback会失败的
                    auditobject.close_rollback()
                except:
                    pass

            else:
                execute_status = 'suc'
                exe_failreason = ''
                auditobject.close_commit()  #提交

            #存入数据库
            re_batch_info.execute_status = execute_status
            re_batch_info.exe_failreason = exe_failreason
            re_batch_info.executor = executor
            re_batch_info.save()

            #微信
            if constant.sendwechat_flag == 1:  #微信开关打开时 发送微信
                try:
                    message_content = ''
                    if execute_status == 'fail':
                        message_content = str(
                            audit_batch) + "批次执行失败!请线下沟通(执行人:" + str(
                                executor) + ")"
                    elif execute_status == 'suc':
                        message_content = str(
                            audit_batch) + "批次执行成功!(执行人:" + str(executor) + ")"
                    if message_content != '':
                        wechat_sender = sendwechat.WeChat()  #初始化对象
                        msg_dict = wechat_sender.send_messages(
                            message_content)  #调用方法发送信息 并返回信息
                except:
                    print "微信发送失败"
                else:
                    pass

            #返回执行状态 要么suc 要么fail
            if execute_status == 'suc':
                return HttpResponse("成功")
            elif execute_status == 'fail':
                return HttpResponse("失败")
コード例 #3
0
    def audit(self,sqltext):
        #输入的sqltext可能有很多的换行 有多行注释和单行注释 这不方面确定是什么类型的sql
        #所以要处理一下 当然返回入库的还是原sqltext
        lexerSplitor = splitor.LexerSplitor()
        uncomment_sqltext=lexerSplitor.remove_sqlcomment(sqltext)

        if uncomment_sqltext=='':
            return None  #纯注释语句 直接返回none


        sqltext=uncomment_sqltext #mysql的注释执行有些问题 所以统一去掉注释
        #非sql_species中类型的语句不通过执行
        for key in DmlAudit.sql_species:
            res=re.search(key,uncomment_sqltext,re.IGNORECASE|re.DOTALL)  #正则处理
            if res:
                sqltype=DmlAudit.sql_species[key]
                if sqltype=='insert':# 要判断是否是insert select
                    if re.search("(^INSERT INTO.*SELECT.*)",uncomment_sqltext,re.IGNORECASE|re.DOTALL):
                        sqltype='insert_select'
                    else:
                        break
                else:
                    break
            else:
                sqltype="other"

        #语法
        if sqltype=='other':
            grammar='invalid'
            gra_failreason="本平台禁止执行非DML语句"
            sqlplan=[]
        else:
            gra=self.connection.execsql("explain "+sqltext) #要么报错str要么返回list:执行计划
            if isinstance(gra,str):
                grammar='invalid'
                gra_failreason=gra
                sqlplan=[]
            else:
                grammar='valid'
                gra_failreason=''
                sqlplan=[]


                plan_passflag=0

                if len(gra)>=2 or gra[0][3]=='ALL':  #关联查询 、全表扫描
                    plan_passflag=1
                else:
                    plan_passflag=0



                for item in gra:
                    #item是个元祖
                    tmp_list=[]
                    for i in item:
                        tmp_list.append(str(i))
                    strtmp=' | '.join(tmp_list)
                    sqlplan.append(strtmp)
                sqlplan.insert(0,'id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra')
        #print sqltype
        #print grammar
        #print gra_failreason
        #print sqlplan

        #执行时间预估 todo
        if grammar=='valid':
            exetime='待开发'
        else:
            exetime=''
        
        #影响行数
        if grammar=='valid':
            func_name=sqltype+"_change"
            sqlchange= getattr(DmlAudit,func_name)(sqltext)
            #print eval(func_name)(sqltext) eval这里不行
            try:
                rowaffact=int(self.connection.execsql(sqlchange)[0][0])#可能异常不返回数字
            except:
                rowaffact=0
        else:
            rowaffact=0


        #print rowaffact
        #print exetime

        #最终审核结果 超过10分钟,影响1000行
        if grammar=="invalid":
            audit_status="unqualified"
        elif grammar=="valid" and rowaffact<=1000 and plan_passflag==0:# and exetime <= '00:10:00':
            audit_status="qualified"
        else:
            audit_status="semi-qualified"

        #print audit_status
        #print sqltext




        re_dict={}
        for i in ['sqltext','grammar','gra_failreason','sqlplan','rowaffact','audit_status','sqltype','exetime']:
            re_dict[i]=locals()[i]
        return re_dict
コード例 #4
0
    def audit(self, sqltext):
        #输入的sqltext可能有很多的换行 有多行注释和单行注释 这不方面确定是什么类型的sql
        #所以要处理一下 当然返回入库的还是原sqltext
        lexerSplitor = splitor.LexerSplitor()
        uncomment_sqltext = lexerSplitor.remove_sqlcomment(sqltext)

        if uncomment_sqltext == '':
            return None  #纯注释语句 直接返回none

        #非sql_species中类型的语句不通过执行
        for key in DmlAudit.sql_species:
            res = re.search(
                key, uncomment_sqltext, re.IGNORECASE | re.DOTALL
            )  #正则处理 忽略大小写|Make the '.' special character match any character at all
            if res:
                sqltype = DmlAudit.sql_species[key]
                #print sqltype
                if sqltype == 'insert':  # 要判断是否是insert select
                    if re.search("(^INSERT\s*INTO.*SELECT.*)",
                                 uncomment_sqltext, re.IGNORECASE | re.DOTALL):
                        sqltype = 'insert_select'
                        break
                    else:
                        break
                else:
                    break
            else:
                sqltype = "other"
        #print sqltype

        #语法
        if sqltype == 'other':
            grammar = 'invalid'
            gra_failreason = "本平台禁止执行非DML语句"
        else:
            gra = self.connection.execsql("explain plan for " +
                                          sqltext)  #要么报错str要么就是none
            if gra:
                grammar = 'invalid'
                gra_failreason = gra
            else:
                grammar = 'valid'
                gra_failreason = ''

        #print grammar
        #print gra_failreason

        #执行计划详情 预估行数和执行时间
        sqlplan = []
        rowaffact = 0
        exetime = ''
        if grammar == 'valid':
            re_sqlplan = self.connection.execsql(
                "select * from table(dbms_xplan.display)")
            #select * from table(dbms_xplan.display('','','OUTLINE'));
            for item in re_sqlplan:
                sqlplan.append(item[0])

            if sqltype == 'insert':
                tmp_exeplan = re_sqlplan[4][0].split(
                    '|')  #第一行有效数据 insert一般没有plan hash value
                #insert如果有sequence 那么有plan hash value 这个时候tmp_exeplan长度一般为1
                if len(tmp_exeplan) < 8:
                    tmp_exeplan = re_sqlplan[5][0].split('|')  #第一行有效数据
            else:
                tmp_exeplan = re_sqlplan[5][0].split('|')  #第一行有效数据

            #预估执行时间
            exetime = tmp_exeplan[7].strip()
            if exetime == '':  # Bytes有时候不展示 那么7就是空 拿6
                exetime = tmp_exeplan[6].strip()

            #预估影响行数
            evaluate_rows = tmp_exeplan[4]

            rows_value = re.search('\d+', evaluate_rows.strip(), 0).group(0)

            rows_unit = ''
            if re.search('\D+', evaluate_rows.strip(), 0):
                rows_unit = re.search('\D+', evaluate_rows.strip(), 0).group(0)
            if rows_unit == 'K':
                evaluate_rows = int(rows_value) * 1000
            elif rows_unit == 'M':
                evaluate_rows = int(rows_value) * 1000 * 1000
            else:
                evaluate_rows = int(rows_value)

            #返回影响行数  如果预估的行数比较少 那么执行并返回精确的行数
            if evaluate_rows >= 1000:
                rowaffact = evaluate_rows
            else:
                func_name = sqltype + "_change"
                sqlchange = getattr(DmlAudit,
                                    func_name)(uncomment_sqltext)  #非注释语句进行改写
                #print sqlchange
                try:
                    rowaffact = int(self.connection.execsql(sqlchange)[0]
                                    [0])  #可能异常不返回数字的str
                except:
                    rowaffact = evaluate_rows

        #print rowaffact
        #print exetime
        #print sqlplan 列表

        #最终审核结果 超过10分钟,影响1000行
        if grammar == "invalid":
            audit_status = "unqualified"
        elif grammar == "valid" and rowaffact <= 1000 and exetime <= '00:10:00':
            audit_status = "qualified"
        else:
            audit_status = "semi-qualified"

        #print audit_status
        #print sqltext
        #audit_status="semi-qualified"#全部是待评估 用于测试

        re_dict = {}
        for i in [
                'sqltext', 'grammar', 'gra_failreason', 'sqlplan', 'rowaffact',
                'audit_status', 'sqltype', 'exetime'
        ]:
            re_dict[i] = locals()[i]
        #print re_dict
        return re_dict