복붙노트

[SQL] 사용자 지정 ODBC 드라이버를 만들기

SQL

사용자 지정 ODBC 드라이버를 만들기

내 현재의 직장에서, 우리는 많은 다른 응용 프로그램이 데이터 소스로 우리 자신의 응용 프로그램에 연결할 수 있도록 우리 자신의 ODBC 드라이버를 구현하기 위해 찾고 있습니다. 지금 우리는 엄청난 것입니다 구현 사양에 우리 자신의 드라이버를 개발, 또는 데이터의 특정 부분 '에 채우기'에 프로그래머를위한 수있는 SDK를 사용하는 옵션을 무게와 추상화의 높은 수준을 수 있도록 노력하고 있습니다.

다른 사람이 사용자 지정 ODBC 드라이버를 구현 했습니까? 당신은 어떤 함정으로 실행 했습니까? 당신은 스스로를하고 무엇 혜택을 보았는가? 당신은했다 대략 얼마나 많은 인시? 당신이 SDK를 사용하고, 만약 그렇다면, 어떤 장점 / 단점은 그 접근 방식에서 볼 않았나요?

모든 의견과 답변 주시면 감사하겠습니다. 감사!

편집 : 우리는 C로 작성되어 우리의 코드로 휴대 성을 유지하기 위해 노력하고있다

해결법

  1. ==============================

    1.내가하지 않은,하지만 난 한 번 정확히 이런 짓을 한 회사에서 인터뷰했다. 그들이 만들었다 MUMPS 같은 아키텍처의 같은 종류의 AMPS라는 4GL / DBMS 제품 - 통합 4GL과 계층 데이터베이스 (예 : 시스템의 전체 장르는 1970 년대에 나왔다). 그들은 꽤 상당한 레거시 코드베이스와 MS Access를 사용하여 연결하고자하는 고객을했다.

    내가하지 않은,하지만 난 한 번 정확히 이런 짓을 한 회사에서 인터뷰했다. 그들이 만들었다 MUMPS 같은 아키텍처의 같은 종류의 AMPS라는 4GL / DBMS 제품 - 통합 4GL과 계층 데이터베이스 (예 : 시스템의 전체 장르는 1970 년대에 나왔다). 그들은 꽤 상당한 레거시 코드베이스와 MS Access를 사용하여 연결하고자하는 고객을했다.

    저를 인터뷰 리드 개발자는이에 대한 몇 가지 전쟁 이야기를 공유했다. 분명히 할 대단히 고통스러운 가볍게 가지고 가면 안된다. 그러나, 그들은 실제로 implemnenting에 성공했다.

    이 일에 대한 하나 개의 대안은 (SAP BW의 라인을 따라) 데이터 마트 / BI 제품을 제공하는 것 그 같은 스타 또는 눈송이 스키마로 더 친숙한 형식으로 외부 데이터베이스와 마사지를 선물한다 응용 프로그램 데이터를.

    이는 실시간 액세스를 지원하지 않는 고통,하지만 ODBC 드라이버보다 구현 (그리고 더 중요한 것은 유지)하는 것이 훨씬 쉬울 수 있습니다. 당신의 실시간 액세스 요구 사항이 합리적으로 predicitable 및 제한이 있다면, 당신은 아마도 사람들을 지원하는 웹 서비스 API를 노출 할 수있다.

  2. ==============================

    2.또 다른 옵션 : 대신 ODBC 드라이버를 만드는, 즉 와이어 프로토콜을 말한다 백 엔드를 구현하는 다른 데이터베이스 사용 (예를 들어 PostgreSQL을 또는 MySQL을).

    또 다른 옵션 : 대신 ODBC 드라이버를 만드는, 즉 와이어 프로토콜을 말한다 백 엔드를 구현하는 다른 데이터베이스 사용 (예를 들어 PostgreSQL을 또는 MySQL을).

    사용자는 다운로드하고 예를 PostgreSQL의 ODBC 드라이버를 사용 할 수 있습니다.

    당신이 에뮬레이션을 선택 정확히 무엇을 백 엔드 데이터베이스 와이어 프로토콜 형식이 설명되어 얼마나 잘에 가장 의존 아마한다.

    모두 포스트 그레스와 MySQL은 클라이언트 - 서버 프로토콜에 대한 괜찮은 문서가 있습니다.

    PostgreSQL의 와이어 프로토콜의 부분을 인식하는 서버 백엔드의 간단한 예 파이썬 2.7 이하이다. 예제 스크립트는 포트 9876을 수신 서버가 나는 psql의 -h localhost를 -p 9876 서버에 연결 명령을 사용하여 만듭니다. 실행 된 모든 쿼리는 열 ABC와 DEF와 두 개의 행, 모든 값을 NULL로 결과 세트를 반환합니다.

    PostgreSQL의 워드 프로세서를 읽고 꽤 간단한 PostgreSQL의 호환 백 엔드를 구현하기 위해 만들 것 실제 프로토콜 트래픽을 검사 Wireshark와 같은 것을 사용.

    import SocketServer
    import struct
    
    def char_to_hex(char):
        retval = hex(ord(char))
        if len(retval) == 4:
            return retval[-2:]
        else:
            assert len(retval) == 3
            return "0" + retval[-1]
    
    def str_to_hex(inputstr):
        return " ".join(char_to_hex(char) for char in inputstr)
    
    class Handler(SocketServer.BaseRequestHandler):
        def handle(self):
            print "handle()"
            self.read_SSLRequest()
            self.send_to_socket("N")
    
            self.read_StartupMessage()
            self.send_AuthenticationClearText()
            self.read_PasswordMessage()
            self.send_AuthenticationOK()
            self.send_ReadyForQuery()
            self.read_Query()
            self.send_queryresult()
    
        def send_queryresult(self):
            fieldnames = ['abc', 'def']
            HEADERFORMAT = "!cih"
            fields = ''.join(self.fieldname_msg(name) for name in fieldnames)
            rdheader = struct.pack(HEADERFORMAT, 'T', struct.calcsize(HEADERFORMAT) - 1 + len(fields), len(fieldnames))
            self.send_to_socket(rdheader + fields)
    
            rows = [[1, 2], [3, 4]]
            DRHEADER = "!cih"
            for row in rows:
                dr_data = struct.pack("!ii", -1, -1)
                dr_header = struct.pack(DRHEADER, 'D', struct.calcsize(DRHEADER) - 1 + len(dr_data), 2)
                self.send_to_socket(dr_header + dr_data)
    
            self.send_CommandComplete()
            self.send_ReadyForQuery()
    
        def send_CommandComplete(self):
            HFMT = "!ci"
            msg = "SELECT 2\x00"
            self.send_to_socket(struct.pack(HFMT, "C", struct.calcsize(HFMT) - 1 + len(msg)) + msg)
    
        def fieldname_msg(self, name):
            tableid = 0
            columnid = 0
            datatypeid = 23
            datatypesize = 4
            typemodifier = -1
            format_code = 0 # 0=text 1=binary
            return name + "\x00" + struct.pack("!ihihih", tableid, columnid, datatypeid, datatypesize, typemodifier, format_code)
    
        def read_socket(self):
            print "Trying recv..."
            data = self.request.recv(1024)
            print "Received {} bytes: {}".format(len(data), repr(data))
            print "Hex: {}".format(str_to_hex(data))
            return data
    
        def send_to_socket(self, data):
            print "Sending {} bytes: {}".format(len(data), repr(data))
            print "Hex: {}".format(str_to_hex(data))
            return self.request.sendall(data)
    
        def read_Query(self):
            data = self.read_socket()
            msgident, msglen = struct.unpack("!ci", data[0:5])
            assert msgident == "Q"
            print data[5:]
    
    
        def send_ReadyForQuery(self):
            self.send_to_socket(struct.pack("!cic", 'Z', 5, 'I'))
    
        def read_PasswordMessage(self):
            data = self.read_socket()
            b, msglen = struct.unpack("!ci", data[0:5])
            assert b == "p"
            print "Password: {}".format(data[5:])
    
    
        def read_SSLRequest(self):
            data = self.read_socket()
            msglen, sslcode = struct.unpack("!ii", data)
            assert msglen == 8
            assert sslcode == 80877103
    
        def read_StartupMessage(self):
            data = self.read_socket()
            msglen, protoversion = struct.unpack("!ii", data[0:8])
            print "msglen: {}, protoversion: {}".format(msglen, protoversion)
            assert msglen == len(data)
            parameters_string = data[8:]
            print parameters_string.split('\x00')
    
        def send_AuthenticationOK(self):
            self.send_to_socket(struct.pack("!cii", 'R', 8, 0))
    
        def send_AuthenticationClearText(self):
            self.send_to_socket(struct.pack("!cii", 'R', 8, 3))
    
    if __name__ == "__main__":
        server = SocketServer.TCPServer(("localhost", 9876), Handler)
        try:
            server.serve_forever()
        except:
            server.shutdown()
    

    예를 들어 명령 행 psql의 세션 :

    [~]
    $ psql -h localhost -p 9876
    Password:
    psql (9.1.6, server 0.0.0)
    WARNING: psql version 9.1, server version 0.0.
             Some psql features might not work.
    Type "help" for help.
    
    codeape=> Select;
     abc | def
    -----+-----
         |
         |
    (2 rows)
    
    codeape=>
    

    (하지만 난 아직 시도하지 않은) PostgreSQL의 프로토콜이 잘 작동해야 말을 ODBC 드라이버.

  3. ==============================

    3.ODBC 드라이버는 매우 복잡하다 - 쓰기 하나에 결정이 가볍게 할 수 없습니다. 검토 기존의 오픈 소스 드라이버는 예제를위한 좋은 방법이지만 대부분은 API에 관계없이 OS 플랫폼의 동일합니다 :) 모방 할 수 없습니다 shortcommings 있습니다. MSSQL / Sybase 용 FreeTDS를 내가 본 것보다 오픈 소스 ODBC 드라이버 구현 중 하나 있습니다.

    ODBC 드라이버는 매우 복잡하다 - 쓰기 하나에 결정이 가볍게 할 수 없습니다. 검토 기존의 오픈 소스 드라이버는 예제를위한 좋은 방법이지만 대부분은 API에 관계없이 OS 플랫폼의 동일합니다 :) 모방 할 수 없습니다 shortcommings 있습니다. MSSQL / Sybase 용 FreeTDS를 내가 본 것보다 오픈 소스 ODBC 드라이버 구현 중 하나 있습니다.

    응용 프로그램을 제어하는 ​​경우에 당신은 적절한 시간에 스펙의 단지 아주 작은 부분 집합이 될 수 있습니다 무엇을 구현 멀리 얻을 수 있습니다. 제대로 할 수 상당히 더 많은 노력을 필요로 할 수있는 범용 환경에서 사용하십시오. 단순히 래퍼 통화 수십를 구현하는 것 외에 내 머리 위로 떨어져 당신은 또한 구현해야합니다 :

  4. ==============================

    4.나는 ODBC 드라이버를 구현하지만, 당신이 오픈 소스 구현으로 시작하여 자신 만의 사용자 정의를 추가 할 수 있다는 제안을 제공하고 싶어하지 않았습니다. 이것은 당신이 훨씬 더 빨리 시작할 수 있습니다.

    나는 ODBC 드라이버를 구현하지만, 당신이 오픈 소스 구현으로 시작하여 자신 만의 사용자 정의를 추가 할 수 있다는 제안을 제공하고 싶어하지 않았습니다. 이것은 당신이 훨씬 더 빨리 시작할 수 있습니다.

    적어도 두 가지 옵션이 있습니다 :

    표준 ODBC에 부합하는 클라이언트 API와 유닉스 / 리눅스에서 실행되는 반대로이 패키지는 Windows에서 실행하는 경우 그러나, 그것은 분명하지 않다. 당신이없는 나는이 당신 관련성이 있는지 모르는, 그래서 당신이 사용하고있는 플랫폼 상태를 않습니다.

  5. ==============================

    5.이 게시물이 지금은 조금 오래된,하지만 가치는 당신이 ODBC 드라이버가해야 할 경우,이 같은 SDK를 사용할 수있는 언급 : http://www.simba.com/drivers/simba-engine-sdk/이 처리한다 점의 대부분은 다른 답변에서 제기하고 당신에게 구현하는 매우 단순화 된 인터페이스를 제공 중.

    이 게시물이 지금은 조금 오래된,하지만 가치는 당신이 ODBC 드라이버가해야 할 경우,이 같은 SDK를 사용할 수있는 언급 : http://www.simba.com/drivers/simba-engine-sdk/이 처리한다 점의 대부분은 다른 답변에서 제기하고 당신에게 구현하는 매우 단순화 된 인터페이스를 제공 중.

    나는 조금 편견이야 있지만 SDK를 사용하여 당신이해야 할 노력하고 무엇에 대한 ODBC 드라이버를 만들기 위해 매우 쉽게 그것을 확인하지 그래서 나는 심바에 대한 작업에 일어난다. 당신은 당신이 코딩에서 어느 정도 실력이라면 오일에가는 뭔가를 얻을 수 있습니다.

    다른 게시물 중 하나는, 그러나이 작동하지 않습니다 점을 시작으로 인 unixODBC 또는이 iODBC을 권장합니다. 그것은 드라이버 관리자 (인 unixODBC이 iODBC 등)과 드라이버 사이의 구별을 실현하는 것이 중요합니다. 드라이버 관리자는 드라이버로 직접 연결해야 할 필요성을 제거 응용 프로그램과 드라이버 사이의 중간 사람 역할을합니다.

    당신은 시작 지점으로 포스트 그레스 또는 MySQL의 드라이버로 시작하고 자신의 데이터베이스를 사용하도록 포크 수있다, 그러나 이것은 사소한 작업이 될 가능성이있다. 처음부터 드라이버를 만드는 것은 훨씬 더 어렵다 가능성 진행 (예상보다 높은) 유지 보수 비용이있을 것이다. 만큼 당신이이 방법의 비용을 알고, 그것은 가능한 일뿐만 아니라 수 있습니다.

  6. from https://stackoverflow.com/questions/335008/creating-a-custom-odbc-driver by cc-by-sa and MIT license