Another alternative to using Data Access Objects (DAO) and Microsoft Jet is to make direct calls to the ODBC API. This provides the advantages of tight control of the resources and access to extra functionality provided by ODBC, at the disadvantage of the extra coding complexity required. There is also no way to share connections between Jet and discrete ODBC calls, so you will pay the cost of more connection overhead and the inconvenience of multiple logins. The following code examples will give you an idea of what's involved:
The following code creates a connection to an ODBC data source:
iRC = SQLAllocConnect(henv, hdbc)
If iRC <> SQL_SUCCESS Then
MsgBox "Can't allocate ODBC connection handle.", 16
Stop
Else
sConnect = "DSN=" & DSN & ";UID=" & USERNAME & ";PWD=" & PASSWORD & ";DATABASE=" & DBNAME
sConnect = sConnect & ";WSID=" & HOSTNAME & ";APP=" & APPNAME
sConnectBuffer = Space$(256)
iRC = SQLDriverConnect(hdbc, Me.hWnd, sConnect, Len(sConnect), sConnectBuffer, Len(sConnectBuffer), ilenConnect, SQL_DRIVER_NOPROMPT)
If iRC <> SQL_SUCCESS And iRC <> SQL_SUCCESS_WITH_INFO Then
DescribeError hdbc, 0 ' sub to display the error
Stop
Else
If iRC = SQL_SUCCESS_WITH_INFO Then DescribeError hdbc, 0
iRC = SQLAllocStmt(hdbc, hstmt)
If iRC <> SQL_SUCCESS Then
MsgBox "Cannot allocate statment handle", 16
Stop
End If
End If
End If
' Add the following line back to use asynchronous calls
' Attempt SQLSetStmtOption(hstmt, SQL_ASYNC_ENABLE, 1&), "Can't set Async on"
To actually execute a query, you could use code similar to:
iRC = SQLExecDirect(hstmt, sQuery, Len(sQuery))
' Add the following lines back for asynchronous execution
' Do While iRC = SQL_STILL_EXECUTING
' DoEvents
' iRC = SQLExecDirect(hstmt, sQuery, Len(sQuery))
' Loop
If iRC <> SQL_SUCCESS Then
DescribeError hdbc, hstmt
Exit Sub
End If
Following successful execution of the query, you could retrieve data using:
iRC = SQLNumResultCols(hstmt, iNumCols)
If iRC <> SQL_SUCCESS Then
DescribeError hdbc, hstmt
Exit Sub
End If
Do While SQLFetch(hstmt) = SQL_SUCCESS
sStuff = ""
For iCount = 1 To iNumCols
Attempt SQLGetData(hstmt, iCount, 1, sBuffer, iBufferLen, lOutLen), "Call to SQLGetData Failed"
If lOutLen = -1 Then
sStuff = sStuff & "NULL" & Chr$(9)
Else
sStuff = sStuff & Left$(sBuffer, lOutLen) & Chr$(9)
End If
Next iCount
Debug.Print sStuff ' output the data retrieved
Loop
Attempt SQLFreeStmt(hstmt, SQL_CLOSE), "FreeStmt Failed"
Final clean up of resources for the above code might look like:
If hstmt <> 0 Then Attempt SQLFreeStmt(hstmt, 0), "Unable to free statment handle"
If hdbc <> 0 Then Attempt SQLDisconnect(hdbc), "Unable to disconnect"
If hdbc <> 0 Then Attempt SQLFreeConnect(hdbc), "Unable to free connection handle"
Code for the Attempt subroutine is:
Sub Attempt (ResultCode As Integer, ErrorMessage As String)
If ResultCode <> SQL_SUCCESS Then
lstMsgs.AddItem Format$(ResultCode) & " - " & ErrorMessage
Stop
End If
End Sub
For more information on using direct ODBC calls from Microsoft Access, Microsoft Basic (or any Microsoft application that contains Basic), see the ODBC 2.0 SDK. This is available as part of the Microsoft Developers Network (MSDN) Level 2 subscription.