对oracmd的简单封装

# -*- coding: gbk -*-

import os
import sys
import io
import subprocess
import _winreg

try:        # 解除30天试用限制,Version>2.9。小于此版是ASProtect加密
    _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER, r'Software\Withdata\OraCmd')
except:
    pass

def exists_oracmd():
    """是否存在 oracmd.exe 文件并返回文件名
    """
    oracmd_exe = 'oracmd.exe'
    cur_path = os.path.dirname(__file__)
    cmd_file = os.path.join(cur_path, oracmd_exe)

    if os.path.exists(cmd_file):
        return cmd_file
    else:
        raise RuntimeError('文件 {} 不存在!'.format(cmd_file))


class OraCmd(object):
    def __init__(self, userid):
        self.userid = userid     # username/password@host:port:SID

        if sys.version_info[0]==2:
            self._st=subprocess.STARTUPINFO
            self._st.dwFlags=subprocess.STARTF_USESHOWWINDOW
            self._st.wShowWindow=subprocess.SW_HIDE
        else:
            self._st = subprocess.STARTUPINFO(dwFlags=subprocess.STARTF_USESHOWWINDOW,
                                             wShowWindow=subprocess.SW_HIDE)

    def __oracmd_unload(self, query, delimiter, filename=None):
        userid_ = "userid={}".format(self.userid)
        query_ = "query={}".format(query)
        delimiter_ = "delimiter={}".format(delimiter)

        run_oracmd = exists_oracmd()
        args = [run_oracmd, userid_, "task=unload", query_, delimiter_, "quit=y", "prompt=n"]

        if filename:
            datafile_ = "datafile={}".format(filename)
            args.append(datafile_)

        pipe = subprocess.Popen(args, stdout = subprocess.PIPE, stdin = subprocess.PIPE,
                                stderr = subprocess.PIPE, startupinfo = self._st)

        return pipe

    def unload_file(self, query, delimiter, filename=None):
        """执行SQL语句,并将结果输出到文件中
        """
        if not filename:
            filename = tempfile.mktemp()  # 临时文件名

        pipe = self.__oracmd_unload(query, delimiter, filename)
        pipe.wait()

        #! 未连上orale或query语句错误,不会实际生成filename文件
        if os.path.exists(filename):
            return filename
        else:
            return None

    def fetch(self, query, delimiter=':,', readone=False):
        """query[IN]: select * from ......
           delimiter[IN]: (",", "|", "#", "TAB", "WHITESPACE")
        RETURN:
            [] 或 None: 未查询到结果
            [[a1,b1,...], [a2,b2,...]...] 或 [a,b,...]: 所有项都是string, 其中返回的Null是''
        """
        pipe = self.__oracmd_unload(query, delimiter)
        sout = io.open(pipe.stdout.fileno(), 'rb', closefd=False)
        lines = ''
        while True:
            buf = sout.read1(1024)
            if len(buf) == 0: break
            lines += buf
            if readone:
                if '\r\n' in lines: break

        # SQL执行成功:---------------------------------------------------------
        # 1:有数据
        # ver<=2.1
        #     A1,B1,C1\r\nA2,B2,C2\r\n...Am,Bm,Cm\r\n
        #     尾部是\r\n,是一个空行,分解返回后会多一个['']
        # ver>=2.2 remove the blank line at the end of the unload file.
        #     A1,B1,C1\r\nA2,B2,C2\r\n...Am,Bm,CmUnload succeeded. X records.\r\n0 h  0 m  0 s\r\n
        #     尾部是Unload succeeded. X records.\r\n0 h  0 m  0 s\r\n
        # 2:无数据
        # ver<=2.1 ''
        # ver>=2.2 Unload succeeded. 0 records.\r\n0 h  0 m  0 s\r\n
        # 取值:不论版本也不论有无数据,[:-2]消除最后的\r\n,
        #       然后split('Unload succeeded.')[0]

        # SQL执行失败:---------------------------------------------------------
        # ver<=2.1,返回的是''
        # ver>=2.2, 错误提示\n\r\nUnload failed. \r\n0 h  0 m  0 s\r\n

##        print repr(lines)

        lines = lines[:-2].split('Unload succeeded.')[0]

        if lines=='' or 'Unload failed.' in lines:
            row = None if readone else []
        else:
            rows = lines.split('\r\n')
            row = [r.split(delimiter) for r in rows]
            row = row[0] if readone else row
        return row

    def fetchone(self, query, delimiter=':,'):
        row = self.fetch(query, delimiter=':,', readone=True)
        return row


if __name__ == '__main__':

    userid = "nhzx/[email protected]:1521:rmis"
    query_day = "SELECT rq, lm, rz FROM V_NHZX "\
                " WHERE RQ >= TO_DATE('{}','yyyy-mm-dd') order by rq desc"

    query = query_day.format('2021-08-01')

    rmis = OraCmd(userid)

    rmis.unload_file(query, ':,', r'z:\test.txt')

    row = rmis.fetchone(query)
    if row:
        print row, '\n---------------'

    row = rmis.fetch(query)
    for i in row:
        print i


 

你可能感兴趣的:(python)