end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

pypyodbc for python で db2 for i にodbc接続時、sqlエラーで固まる

https://github.com/pypyodbc/pypyodbc

pypyodbc for pythonas400のデータベースである db2 for i にodbc接続し、 sqlエラーが発生すると、固まる。

固まってしまう根本原因は、db2 for i側にあるのかもしれませんが、 pypyodbcのsrcを見ると、def ctrl_err(ht, h, val_ret, ansi) 内で 無限ループに陥っているようでした。

なので、以下のように「if i > 10: return」を追加することで、 当座をしのぐことにしました。

def ctrl_err(ht, h, val_ret, ansi):
    """Classify type of ODBC error from (type of handle, handle, return value)
    , and raise with a list"""
    func_name  = sys._getframe().f_code.co_name

    if ansi:
        state = create_buffer(22)
        Message = create_buffer(1024*4)
        ODBC_func = ODBC_API.SQLGetDiagRec
        if py_v3:
            raw_s = lambda s: bytes(s,'ascii')
        else:
            raw_s = str_8b
    else:
        state = create_buffer_u(24)
        Message = create_buffer_u(1024*4)
        ODBC_func = ODBC_API.SQLGetDiagRecW
        raw_s = unicode
    NativeError = ctypes.c_int()
    Buffer_len = c_short()
    err_list = []
    number_errors = 1

    i = 0      #### ココ
    while 1:
        ret = ODBC_func(ht, h, number_errors, state, \
            ADDR(NativeError), Message, 1024, ADDR(Buffer_len))
        i += 1     #### ココ
        if i > 10:    #### ココ
            return    #### ココ

        if ret == SQL_NO_DATA_FOUND:
            #No more data, I can raise
            #print(err_list[0][1])
            state = err_list[0][0]
            err_text = raw_s('[')+state+raw_s('] ')+err_list[0][1]
            if state[:2] in (raw_s('24'),raw_s('25'),raw_s('42')):
                raise ProgrammingError(state,err_text)
            elif state[:2] in (raw_s('22')):
                raise DataError(state,err_text)
            elif state[:2] in (raw_s('23')) or state == raw_s('40002'):
                raise IntegrityError(state,err_text)
            elif state == raw_s('0A000'):
                raise NotSupportedError(state,err_text)
            elif state in (raw_s('HYT00'),raw_s('HYT01'),raw_s('01000')):
                raise OperationalError(state,err_text)
            elif state[:2] in (raw_s('IM'),raw_s('HY')):
                raise Error(state,err_text)
            else:
                raise DatabaseError(state,err_text)
            break
        elif ret == SQL_INVALID_HANDLE:
            #The handle passed is an invalid handle
            raise ProgrammingError('', 'SQL_INVALID_HANDLE')
        elif ret == SQL_SUCCESS:
            if ansi:
                err_list.append((state.value, Message.value, NativeError.value))
            else:
                err_list.append((from_buffer_u(state), from_buffer_u(Message), NativeError.value))
            number_errors += 1
        elif ret == SQL_ERROR:
            raise ProgrammingError('', 'SQL_ERROR')