1. 程式人生 > >GDAL開啟mdb檔案失敗解決方法(二)

GDAL開啟mdb檔案失敗解決方法(二)

上一篇http://blog.csdn.net/liminlu0314/article/details/53433014博文中說到,可以通過配置項來解決mdb檔案開啟失敗的問題。該問題主要是在64位的程式中會出現。仔細檢視gdal的程式碼,發現在原始碼中已經針對這個問題進行了修改,但是測試發現修改的不徹底。

具體的bug資訊參考http://trac.osgeo.org/gdal/ticket/5594。GDAL庫中原始碼片段如下,詳見檔案ogrodbcdatasource.cpp中的132行左右,位於函式OGRODBCDataSource::OpenMDB中。

/* -------------------------------------------------------------------- */
/*      Initialize based on the DSN.                                    */
/* -------------------------------------------------------------------- */
    CPLDebug( "ODBC", "EstablishSession(%s)", pszDSN );

    if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
    {
        int bError = TRUE;
        if( EQUAL(pszDSN, "") )//註釋掉這句話即可
        {
            // Trying with another template (#5594)
            pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=%s";
            CPLFree( pszDSN );
            pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
            snprintf( pszDSN,
                      strlen(pszNewName)+strlen(pszDSNStringTemplate)+100,
                      pszDSNStringTemplate,  pszNewName );
            CPLDebug( "ODBC", "EstablishSession(%s)", pszDSN );
            if( oSession.EstablishSession( pszDSN, NULL, NULL ) )
            {
                bError = FALSE;
            }
        }
        if( bError )
        {
            CPLError( CE_Failure, CPLE_AppDefined,
                    "Unable to initialize ODBC connection to DSN for %s,\n"
                    "%s", pszDSN, oSession.GetLastError() );
            CPLFree( pszDSN );
            return FALSE;
        }
    }

上述程式碼雖然加了匹配另一個模板,但是有個判斷if( EQUAL(pszDSN, "") ),這個判斷由於pszDSN通過上面的賦值,肯定是有值的,所以這個判斷永遠為FALSE,也就是if內的程式碼不會執行,這樣就導致修改了其實和沒有修改是一樣的。所以為了能夠在使用第一個模板失敗時,使用第二個模板,需要將if這句話註釋掉即可。

修改完重新編譯即可。

PS:最後又發現了一個問題,在開啟除錯開關之後,執行會崩潰,通過除錯發現位於該檔案的218行的 if( oTableList.GetTables() )中執行失敗,函式GetTables的原始碼如下:

int CPLODBCStatement::GetTables( const char *pszCatalog,
                                 const char *pszSchema )

{
    CPLDebug( "ODBC", "CatalogNameL: %s\nSchema name: %s",
		pszCatalog , pszSchema); //這句出問題了

#if (ODBCVER >= 0x0300)

    if( !m_poSession->IsInTransaction() )
    {
        // Commit pending transactions and set to autocommit mode.
        m_poSession->ClearTransaction();
    }

#endif
......

除錯發現在呼叫CPLDebug函式時,傳入的兩個引數均為NULL導致CPLDebug函式崩潰,此處加一個判斷就可以了。如果不啟用除錯應該也不會出問題。