2014-07-05 4 views
5

ADO (Microsoft ActiveX Data Objects 6.1 Library)를 사용하여 연결하는 여러 데이터베이스에 의존하는 Excel 기반 응용 프로그램이 있습니다. 데이터베이스는 지역 서버에 상주하며 재사용을 위해 Scripting.Dictionary 객체에 연결을 캐시 할 수 있도록 초기 연결을 설정하는 데 오버 헤드가 있습니다. VBA에 KDB +/qodbc.dll이있는 ADO

Private moConnCacheDict As Scripting.Dictionary 

나는 KDB + qodbc.dll 데이터베이스 드라이버를 사용

나는 예기치 않은 동작을 얻을. 여러 데이터 소스 (Oracle, Sybase, Access)와 하나의 KDB 데이터베이스 인스턴스를 예상대로 연결하여 재사용 할 수 있습니다. 그러나 두 번째 KDB 데이터베이스 연결을 만들고 새 데이터 집합에 대해 쿼리를 실행하면 쿼리가 합법적이라고하더라도 데이터가 반환되지 않습니다.

Recordset.BOF = TRUE and Recordset.EOF = TRUE 

잘 실행되고 필드가 표시됩니다. 이전 지역 서버로의 연결이 유지 보인다 나는 성공적으로 내가 보면 사실에도 불구하고 원래 서버에있는 데이터,

Recordset.ActiveCommand.ActiveConnection.Properties.Item("Extended Properties") 

, 새로운 연결 문자열이를 검색 할 수 있습니다.

산은 + 연결 문자열 다음 구문 사용 다음 ADO.Recordset 항상 폐쇄 설정 참고

Private Function ExecuteQuery(sDBName As String, ByRef oRst As ADODB.Recordset, Optional bDeleteConnection As Boolean) As Boolean 
Dim oDBConn As ADODB.Connection 
Dim sSql As String 

'delete connection 
If bDeleteConnection Then Call DropConnection(sDBName) 

'get cached or new connection 
Call GetConnection(sDBName, oDBConn) 

Select Case sDBName 
Case "MAIN_US" 
    sSql = mSQL_MAIN 
Case "MD_ASIA" 
    sSql = mSQL_MDASIA 
End Select 

Set oRst = New Recordset 
oRst.Open sSql, oDBConn, adOpenKeyset, adLockPessimistic 

If Not oDBConn.State = adStateOpen Then Err.Raise vbObjectError + 1024, "ExecuteQuery", sDBName & ": Recordset Closed. Unable to execute query ->" & sSql 

ExecuteQuery = True 

End Function 

Private Function GetConnection(sDBName As String, ByRef oDBConn As ADODB.Connection) As Boolean 

If moConnCacheDict Is Nothing Then Set moConnCacheDict = New Dictionary 

If moConnCacheDict.Exists(sDBName) Then 
'get existing connection 
Set oDBConn = moConnCacheDict.Item(sDBName) 
Else 
'create connection 
Set oDBConn = New Connection 

With oDBConn 
    .Mode = adModeRead 
    Select Case sDBName 
    Case "MAIN_US" 
     .Mode = adModeReadWrite 
     .ConnectionString = mCONN_MAIN 
    Case "MD_ASIA" 
     .Mode = adModeRead 
     .ConnectionString = mCONN_MDASIA 
    End Select 

    .CursorLocation = adUseServer 
    .Open 
End With 

moConnCacheDict.Add sDBName, oDBConn 

End If 

GetConnection = True 

End Function 

Private Function DropConnection(Optional sDBName As String) As Boolean 
Dim oDBConn As ADODB.Connection 
Dim i As Integer 

    'delete object directly from cache 
    If Not moConnCacheDict Is Nothing Then 
     If sDBName = vbNullString Then 
       'close all connections 
       For i = 0 To moConnCacheDict.Count - 1 
        If Not IsEmpty(moConnCacheDict.Items(i)) Then 
         Set oDBConn = moConnCacheDict.Items(i) 
         If Not oDBConn Is Nothing Then 
          If oDBConn.State = adStateOpen Then oDBConn.Close 
          Set oDBConn = Nothing 
          Debug.Print Now, "Dropping Database Connection - " & moConnCacheDict.Keys(i) 
         End If 
        End If 
       Next i 
       Set moConnCacheDict = Nothing 
      Else 
      If moConnCacheDict.Exists(sDBName) Then 
       If Not IsEmpty(moConnCacheDict.Item(sDBName)) Then 
        Set oDBConn = moConnCacheDict.Item(sDBName) 
        If Not oDBConn Is Nothing Then 
         If oDBConn.State = adStateOpen Then oDBConn.Close 
         Set oDBConn = Nothing 
         Debug.Print Now, "Dropping Database Connection - " & "Dropping Database Connection - " & sDBName 
        End If 
       End If 
       moConnCacheDict.Remove (sDBName) 
      End If 
     End If 
    End If 

DropConnection = True 

End Function 

(: I는 예를 들어 사용되는 코어 VBA 기능을 포함했다

DRIVER=kdb+;DBQ=XXXXX;UID=XXXXX;PWD=XXXXX; 

을 호출자가 아무 것도하지 않음).

문제를 해결할 수있는 유일한 방법은 모든 데이터베이스 연결을 (공급자에 관계없이) 닫은 다음 원하는 지역 서버에 다시 연결하는 것입니다. 이것은 기존의 모든 연결을 다시 열어야하기 때문에 비효율적입니다. 또한 현재 통합 문서에서이 작업을 수행하는 것만으로는 충분하지 않습니다. 이 작업은 응용 프로그램 수준에서 수행해야합니다. ANY 데이터베이스에 대한 모든 ADO 연결이 아직 열려 있으면 새 KDB + ADO 연결을 만들 수 있지만 여전히 이전 인스턴스을 가리 킵니다.

나는 KDB + 연결 개체의 오류 속성을 보았다 두 개의 오류가 있습니다

  1. 여러 단계 OLE DB 작업을하는 동안 오류가 발생했습니다가. 가능한 경우 각 OLE DB 상태 값을 확인하십시오. 어떤 일도 행해지 지 않았다.
  2. 공급자가이 속성을 지원하지 않습니다.

이 내용은 http://support.microsoft.com/kb/269495에 문서화되어 있지만 레지스트리에 CLSID가 없으므로 제안 된 변경 사항을 시험 할 수 없습니다.

나는 다음과 같은 메시지가 나타나면 ODBC 로깅을 설정하는 경우 :

EXCEL     8dc-22d0 EXIT SQLGetInfoW with return code -1 (SQL_ERROR) 
    HDBC    0x02131EA8 
    UWORD      151 <SQL_KEYSET_CURSOR_ATTRIBUTES2> 
    PTR     0x003C4FB0 
    SWORD      4 
    SWORD *    0x00000000 

    DIAG [S1096] [Microsoft][ODBC Driver Manager] Information type out of range (0) 

이 어쨌든 오류에 대한 책임을 질 것인가를?

언제나 그렇듯이 도움이나 제안을 많이 주시면 감사하겠습니다.

+1

나에게 KDB + OLE DB 드라이버의 버그와 비슷합니다. 저의 제안은 * 최소한의 재현 가능한 예제를 생성하는 것입니다 (두 개의 KDB + 연결을 열고 두 번째 연결이 있어야 함을 보여주고 버그 리포트로 KDB + 개발자에게 보냅니다). – Heinzi

답변

0

당신이보고있는 것은 드라이버의 버그이며, 최신 드라이버를 찾아야합니다.

코드를 직접 실행하고 테스트하지 않은 경우 (주석 대신) 완전한 대답을 제공해서는 안되지만 연결 개체의 속성 컬렉션을 열거하고 연결 풀링을 찾으십시오. .

연결 풀링을 0으로 설정하면 (또는 속성 값의 vartype을 보는 것으로 추측 할 수있는 것에 따라 false로 설정 됨) 유망한 해결 방법입니다. 다른 옵션은 앞으로 나아갈 수있는 레코드 세트를 사용하는 것입니다.

NB : 몇 년 전에 적절한 OLEDB 드라이브를 작성하기위한 오픈 소스 프로젝트가 있었지만,보기에는 점점 희미 해 보였습니다.

+0

연결 개체에 연결 풀링이라는 속성이없고 전달 만 아무 것도 수행하지 않았습니다. 어쨌든 고마워. – user2579685

+0

연결 개체의 속성 컬렉션을 열거합니다. iConnection.Printi & vbtab &) .value 다음 i –