pymssql nextset() 빈값 이슈

최근에 구현한 부분에서 이상한 경험을 했는데 같은 db 프로시저를 호출하는 코드를 쓰고 테스트를 했는데 어떤 조건으로는 데이터가 순서에 맞게 잘 나오고 안나오고 하는 경우였다.

데이터는 mssql 저장 프로시저에서 2개의 결과셋을 반환하는데 첫번째에서는 보여줄 데이터의 금액, 건수 합산 데이터를 보여주고, 두번째에서는 실제 보여줄 데이터가 나오는 것이었다. 그래서 generator 를 이용해서 g.next(), g.next() 이렇게 2번 호출해서 해당 데이터를 받아오고 각각을 다른 변수에 담아서 리턴하고 있었다. 리턴된 데이터는 웹상에서 2개의 datatables 에 표시하는 식으로 구성되어 있었다.

while True:  
    result = [row for row in self.cursor]
    try:
        yield result
    except GeneratorExit:
        break
...
result_sum = g.nextset()  
result_detail = g.nextset()  

그런데 어떤 조건하에서는 이상하게 두번째 데이터가 첫번째 datatables 에 표시되는 버그가 있었다. 아무리 생각해도 이해가 되지 않아서, mssql 을 통해서 조회해보니 첫번째의 합산 결과셋이 빈칸으로 오는 것이었다. 그러면 상식적으로 첫번째 결과셋을 받는 변수에는 [] 로 나오고 두번째 결과셋을 받는 변수에는 실제 데이터가 나와야 한다. 그런데 첫번째 결과셋 변수에 두번째 결과셋 데이터가 들어가 있었다.

왜 이런 문제가 생길까?

문제의 원인은 pymssql 에서 nextset() 을 받아올때 빈 데이터를 돌려주는 경우에는 처리를 하지 못하는데 있다. 이 문제는 pymssql 의 github 레포에 가면 실제 여전히 이슈로 남아 있는 것을 볼 수가 있다.

https://github.com/pymssql/pymssql/pull/134

위의 이슈에 가보면 execute() 를 해서 sql 문을 실행했을때에는 문제가 없지만, callproc() 를 이용해서 할 경우 다른 결과를 보여준다고 한다. 그리고 pymssql 말고 mysql-python 에서는 이런 문제가 안생기는데 pymssql 에서만 생기는 것 같다.

일단 사내 서비스긴 하지만 운영되고 있는 사이트라서 급하게 고쳤는데, pymssql 에서 cursordict 형태로 데이터를 가져오기 때문에 column 명이 같이 온다. 해당 컬럼명을 통해서 해당 데이터가 첫번째 결과셋인지 두번째 결과셋인지 판별하도록 수정했다.

처음에는 이렇게 여러개의 결과셋을 반환하는 경우가 1개 밖에 없었는데 지금은 대부분의 저장프로시저들(그래봐야 5개?)이 이런식으로 리턴하고 있어서 모두 컬럼명으로 매칭하는 작업을 수행해줬다.

개인적으로 pymssql 이 좀더 설치하기가 쉬워서(pip) 자주 사용하고 있는데 이런 문제가 있는것 처음 겪었던것 같고, 처음 보고된게 2013년인데 아직 잘 처리가 안된것 같아서 좀 아쉽다. 혹시 사용하시는 분이 있다면, nextset() 을 가져오는 부분에서 반드시 위와 같이 빈값을 보내는 경우를 테스트해서 예외처리 해보시길 바란다.