diff --git a/IscDbc/JString.cpp b/IscDbc/JString.cpp index 07f8340c..93fb9751 100644 --- a/IscDbc/JString.cpp +++ b/IscDbc/JString.cpp @@ -199,7 +199,7 @@ const char* JString::getString() return (string) ? string : ""; } -JString::operator const char* () +JString::operator const char* () const { /************************************** * diff --git a/IscDbc/JString.h b/IscDbc/JString.h index 907067f7..7488da58 100644 --- a/IscDbc/JString.h +++ b/IscDbc/JString.h @@ -61,7 +61,7 @@ class JString void Format (const char*, ...); const char *getString(); - operator const char*(); + operator const char*() const; JString& operator = (const char *string); JString& operator = (const JString& string); JString& operator+=(const char *string); diff --git a/IscDbc/SQLError.cpp b/IscDbc/SQLError.cpp index d37b6baf..447f2f9b 100644 --- a/IscDbc/SQLError.cpp +++ b/IscDbc/SQLError.cpp @@ -112,7 +112,7 @@ SQLError::~SQLError () throw() } -int SQLError::getSqlcode () +int SQLError::getSqlcode () const { /************************************** * @@ -128,7 +128,7 @@ int SQLError::getSqlcode () return sqlcode; } -int SQLError::getFbcode () +int SQLError::getFbcode () const { /************************************** * @@ -144,7 +144,7 @@ int SQLError::getFbcode () return fbcode; } -const char *SQLError::getText () +const char *SQLError::getText () const { /************************************** * @@ -160,7 +160,7 @@ const char *SQLError::getText () return text; } -SQLError::operator const char* () +SQLError::operator const char* () const { /************************************** * @@ -193,7 +193,7 @@ SQLError::SQLError( int code, __int64 codefb, const char * txt, ...) fbcode = (int) codefb; } -const char* SQLError::getTrace() +const char* SQLError::getTrace() const { return stackTrace; } diff --git a/IscDbc/SQLError.h b/IscDbc/SQLError.h index 2b6aa630..5e9d35ee 100644 --- a/IscDbc/SQLError.h +++ b/IscDbc/SQLError.h @@ -33,18 +33,18 @@ class SQLError : public SQLException public: virtual int release(); virtual void addRef(); - virtual const char* getTrace(); + virtual const char* getTrace() const; SQLError (int sqlcode, __int64 fbcode, const char *text, ...); SQLError (SqlCode sqlcode, const char *text, ...); SQLError (Stream *trace, SqlCode code, const char *txt,...); ~SQLError() throw(); - virtual int getFbcode (); - virtual int getSqlcode (); - virtual const char *getText(); + virtual int getFbcode () const; + virtual int getSqlcode () const; + virtual const char *getText() const; //void Delete(); - operator const char*(); + operator const char*() const; int fbcode; int sqlcode; diff --git a/IscDbc/SQLException.h b/IscDbc/SQLException.h index e720c27a..156aff55 100644 --- a/IscDbc/SQLException.h +++ b/IscDbc/SQLException.h @@ -42,10 +42,10 @@ class DllExport SQLException : public std::exception public: //virtual void addRef() = 0; //virtual int release() = 0; - virtual int getFbcode () = 0; - virtual int getSqlcode () = 0; - virtual const char *getText() = 0; - virtual const char *getTrace() = 0; + virtual int getFbcode () const = 0; + virtual int getSqlcode () const = 0; + virtual const char *getText() const = 0; + virtual const char *getTrace() const = 0; }; }; // end namespace IscDbcLibrary diff --git a/OdbcConnection.cpp b/OdbcConnection.cpp index 4e2a2776..035574a7 100644 --- a/OdbcConnection.cpp +++ b/OdbcConnection.cpp @@ -1026,10 +1026,14 @@ SQLRETURN OdbcConnection::sqlNativeSql( SQLCHAR * inStatementText, SQLINTEGER te outText = (const char *)tempNative; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError( "HY000", exception ); + postError("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError("HY000", ex); return SQL_ERROR; } @@ -1125,6 +1129,14 @@ SQLRETURN OdbcConnection::sqlDisconnect() if (connection->getTransactionPending()) return sqlReturn (SQL_ERROR, "25000", "Invalid transaction state"); + auto handle_error = [&](const char* state, auto& ex) -> SQLRETURN + { + postError("01002", ex); + connection = NULL; + connected = false; + return SQL_SUCCESS_WITH_INFO; + }; + try { connection->commit(); @@ -1132,13 +1144,13 @@ SQLRETURN OdbcConnection::sqlDisconnect() connection = NULL; connected = false; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("01002", exception); - connection = NULL; - connected = false; - return SQL_SUCCESS_WITH_INFO; + return handle_error("01002", ex); + } + catch (const std::exception &ex) + { + return handle_error("01002", ex); } return sqlSuccess(); @@ -1632,6 +1644,21 @@ SQLRETURN OdbcConnection::connect(const char *sharedLibrary, const char * databa { Properties *properties = NULL; + // Shared rollback for both catch handlers below. `connection` may be + // NULL if createConnection() itself threw before assignment, so it has + // to be checked before close(). + auto rollbackPartialConnect = [&]() { + if ( env->envShare ) + env->envShare = NULL; + if ( properties ) + properties->release(); + if ( connection ) + { + connection->close(); + connection = NULL; + } + }; + try { connection = createConnection(); @@ -1709,19 +1736,15 @@ SQLRETURN OdbcConnection::connect(const char *sharedLibrary, const char * databa WcsToMbs = connection->getConnectionWcsToMbs(); MbsToWcs = connection->getConnectionMbsToWcs(); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - if ( env->envShare ) - env->envShare = NULL; - - if ( properties ) - properties->release(); - - connection->close(); - connection = NULL; - - return sqlReturn( SQL_ERROR, "08004", exception.getText(), exception.getSqlcode() ); + rollbackPartialConnect(); + return sqlReturn( SQL_ERROR, "08004", ex.getText(), ex.getSqlcode() ); + } + catch (const std::exception &ex) + { + rollbackPartialConnect(); + return sqlReturn( SQL_ERROR, "08004", ex.what(), 0 ); } connected = true; @@ -1746,10 +1769,14 @@ SQLRETURN OdbcConnection::sqlEndTran(int operation) connection->rollbackAuto(); } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("S1000", exception); + postError ("S1000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("S1000", ex); return SQL_ERROR; } @@ -1764,10 +1791,14 @@ SQLRETURN OdbcConnection::sqlExecuteCreateDatabase(const char * sqlString) { connection->sqlExecuteCreateDatabase( sqlString ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError( "HY000", ex ); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError( "HY000", exception ); + postError( "HY000", ex ); return SQL_ERROR; } @@ -2178,10 +2209,13 @@ void OdbcConnection::initUserEvents( PODBC_EVENTS_BLOCK_INFO infoEvents ) userEventsInterfase->events = infoEvents->events; userEventsInterfase->count = infoEvents->count; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError( "HY000", exception ); + postError( "HY000", ex ); + } + catch (const std::exception &ex) + { + postError( "HY000", ex ); } } @@ -2199,10 +2233,13 @@ void OdbcConnection::updateResultEvents( char *updated ) nextNameEvent->changed = userEvents->isChanged( i ); } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError( "HY000", ex ); + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError( "HY000", exception ); + postError( "HY000", ex ); } } @@ -2212,10 +2249,13 @@ void OdbcConnection::requeueEvents() { userEvents->queEvents( userEventsInterfase ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError( "HY000", ex ); + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError( "HY000", exception ); + postError( "HY000", ex ); } } diff --git a/OdbcDesc.cpp b/OdbcDesc.cpp index fcd51e1f..7ac15def 100644 --- a/OdbcDesc.cpp +++ b/OdbcDesc.cpp @@ -805,10 +805,14 @@ SQLRETURN OdbcDesc::sqlGetDescField(int recNumber, int fieldId, SQLPOINTER ptr, return returnStringInfo (ptr, bufferLength, lengthPtr, (char*)string); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -1216,10 +1220,14 @@ SQLRETURN OdbcDesc::sqlGetDescRec( SQLSMALLINT recNumber, *scalePtr = record->scale; *nullablePtr = record->nullable; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -1245,13 +1253,10 @@ SQLRETURN OdbcDesc::sqlSetDescRec( SQLSMALLINT recNumber, if ( bDefined == false ) return sqlReturn (SQL_ERROR, "HY091", "Invalid descriptor field identifier"); - if (recNumber) - { - if ( recNumber > headCount ) - return sqlReturn (SQL_NO_DATA_FOUND, "HY021", "Inconsistent descriptor information"); + if ( recNumber > headCount ) + return sqlReturn (SQL_NO_DATA_FOUND, "HY021", "Inconsistent descriptor information"); - record = getDescRecord (recNumber); - } + record = getDescRecord (recNumber); try { @@ -1264,10 +1269,14 @@ SQLRETURN OdbcDesc::sqlSetDescRec( SQLSMALLINT recNumber, record->octetLengthPtr = stringLengthPtr; record->indicatorPtr = indicatorPtr; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } diff --git a/OdbcEnv.cpp b/OdbcEnv.cpp index b932412b..6e5d7d36 100644 --- a/OdbcEnv.cpp +++ b/OdbcEnv.cpp @@ -132,10 +132,14 @@ SQLRETURN OdbcEnv::sqlEndTran(int operation) { envShare->sqlEndTran (operation); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -192,10 +196,14 @@ SQLRETURN OdbcEnv::sqlGetEnvAttr(int attribute, SQLPOINTER ptr, int bufferLength if (lengthPtr) *lengthPtr = sizeof (int); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -222,10 +230,14 @@ SQLRETURN OdbcEnv::sqlSetEnvAttr(int attribute, SQLPOINTER value, int length) return sqlReturn (SQL_ERROR, "HYC00", "Optional feature not implemented"); } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } diff --git a/OdbcJdbcSetup/DsnDialog.cpp b/OdbcJdbcSetup/DsnDialog.cpp index a71ef1fa..18756e62 100644 --- a/OdbcJdbcSetup/DsnDialog.cpp +++ b/OdbcJdbcSetup/DsnDialog.cpp @@ -743,6 +743,14 @@ void CDsnDialog::OnTestConnection( HWND hDlg ) GetWindowText( hDlg, strHeadDlg, sizeof ( strHeadDlg ) ); + auto handle_error = [&](const char* text) + { + char buffer[2048]; + sprintf(buffer, "%s\n%s", _TR(IDS_MESSAGE_02, "Connection failed!"), text); + removeNameFileDBfromMessage(buffer); + MessageBox(hDlg, TEXT(buffer), TEXT(strHeadDlg), MB_ICONERROR | MB_OK); + }; + try { CServiceClient services; @@ -789,16 +797,13 @@ void CDsnDialog::OnTestConnection( HWND hDlg ) MessageBox( hDlg, _TR( IDS_MESSAGE_01, "Connection successful!" ), TEXT( strHeadDlg ), MB_ICONINFORMATION | MB_OK ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - char buffer[2048]; - JString text = exception.getText(); - - sprintf( buffer, "%s\n%s", _TR( IDS_MESSAGE_02, "Connection failed!" ), (const char*)text ); - removeNameFileDBfromMessage ( buffer ); - - MessageBox( hDlg, TEXT( buffer ), TEXT( strHeadDlg ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } } #endif diff --git a/OdbcJdbcSetup/ServiceClient.cpp b/OdbcJdbcSetup/ServiceClient.cpp index bfd52467..7e835dd7 100644 --- a/OdbcJdbcSetup/ServiceClient.cpp +++ b/OdbcJdbcSetup/ServiceClient.cpp @@ -84,11 +84,8 @@ bool CServiceClient::initServices( const char *sharedLibrary ) if ( !properties ) return false; } - catch ( std::exception &ex ) + catch (const std::exception &ex) // SQLException is derived from the std::exception and should be also caught here { - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - if ( services ) { services->release(); @@ -143,11 +140,8 @@ bool CServiceClient::createDatabase() properties ); connection->close(); } - catch ( std::exception &ex ) + catch (const std::exception &ex) // SQLException is derived from the std::exception and should be also caught here { - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - if ( connection ) connection->close(); @@ -187,11 +181,8 @@ bool CServiceClient::dropDatabase() properties ); connection->close(); } - catch ( std::exception &ex ) + catch (const std::exception &ex) // SQLException is derived from the std::exception and should be also caught here { - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - if ( connection ) connection->close(); diff --git a/OdbcJdbcSetup/ServiceTabBackup.cpp b/OdbcJdbcSetup/ServiceTabBackup.cpp index 9961a777..ef1b93ea 100644 --- a/OdbcJdbcSetup/ServiceTabBackup.cpp +++ b/OdbcJdbcSetup/ServiceTabBackup.cpp @@ -179,6 +179,17 @@ void CServiceTabBackup::onStartBackup() return; } + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + writeFooterToLogFile(); + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_VIEW_LOG), !logPathFile.IsEmpty()); + + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + MessageBox(NULL, buffer, TEXT("Error!"), MB_ICONERROR | MB_OK); + }; + try { DWORD dwWritten; @@ -234,17 +245,13 @@ void CServiceTabBackup::onStartBackup() SendMessage( hWndBar, PBM_SETPOS, (WPARAM)100 , (LPARAM)NULL ); EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - writeFooterToLogFile(); - EnableWindow( GetDlgItem( hDlg, IDOK ), TRUE ); - EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); - - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf(buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - MessageBox( NULL, buffer, TEXT( "Error!" ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } services.closeService(); diff --git a/OdbcJdbcSetup/ServiceTabRepair.cpp b/OdbcJdbcSetup/ServiceTabRepair.cpp index 8de57c8c..5e3a6da9 100644 --- a/OdbcJdbcSetup/ServiceTabRepair.cpp +++ b/OdbcJdbcSetup/ServiceTabRepair.cpp @@ -200,6 +200,17 @@ void CServiceTabRepair::startRepairDatabase() return; } + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + writeFooterToLogFile(); + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_VIEW_LOG), !logPathFile.IsEmpty()); + + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + MessageBox(NULL, buffer, TEXT("Error!"), MB_ICONERROR | MB_OK); + }; + try { DWORD dwWritten; @@ -301,17 +312,13 @@ void CServiceTabRepair::startRepairDatabase() SendMessage( hWndBar, PBM_SETPOS, (WPARAM)100 , (LPARAM)NULL ); EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - writeFooterToLogFile(); - EnableWindow( GetDlgItem( hDlg, IDOK ), TRUE ); - EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); - - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf(buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - MessageBox( NULL, buffer, TEXT( "Error!" ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } services.closeService(); diff --git a/OdbcJdbcSetup/ServiceTabRestore.cpp b/OdbcJdbcSetup/ServiceTabRestore.cpp index cffd5fbc..e47b7747 100644 --- a/OdbcJdbcSetup/ServiceTabRestore.cpp +++ b/OdbcJdbcSetup/ServiceTabRestore.cpp @@ -205,6 +205,17 @@ void CServiceTabRestore::onStartRestore() return; } + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + writeFooterToLogFile(); + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_VIEW_LOG), !logPathFile.IsEmpty()); + + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + MessageBox(NULL, buffer, TEXT("Error!"), MB_ICONERROR | MB_OK); + }; + try { DWORD dwWritten; @@ -263,17 +274,13 @@ void CServiceTabRestore::onStartRestore() SendMessage( hWndBar, PBM_SETPOS, (WPARAM)100 , (LPARAM)NULL ); EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - writeFooterToLogFile(); - EnableWindow( GetDlgItem( hDlg, IDOK ), TRUE ); - EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); - - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf(buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - MessageBox( NULL, buffer, TEXT( "Error!" ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } services.closeService(); diff --git a/OdbcJdbcSetup/ServiceTabStatistics.cpp b/OdbcJdbcSetup/ServiceTabStatistics.cpp index fb0d7c53..5d6bed58 100644 --- a/OdbcJdbcSetup/ServiceTabStatistics.cpp +++ b/OdbcJdbcSetup/ServiceTabStatistics.cpp @@ -177,6 +177,17 @@ void CServiceTabStatistics::onStartStatistics() return; } + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + writeFooterToLogFile(); + EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); + EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_VIEW_LOG), !logPathFile.IsEmpty()); + + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + MessageBox(NULL, buffer, TEXT("Error!"), MB_ICONERROR | MB_OK); + }; + try { DWORD dwWritten; @@ -219,17 +230,13 @@ void CServiceTabStatistics::onStartStatistics() SendMessage( hWndBar, PBM_SETPOS, (WPARAM)100 , (LPARAM)NULL ); EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - writeFooterToLogFile(); - EnableWindow( GetDlgItem( hDlg, IDOK ), TRUE ); - EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_VIEW_LOG ), !logPathFile.IsEmpty() ); - - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf(buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - MessageBox( NULL, buffer, TEXT( "Error!" ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } services.closeService(); diff --git a/OdbcJdbcSetup/Setup.cpp b/OdbcJdbcSetup/Setup.cpp index 0e7ea5ad..4c46e95a 100644 --- a/OdbcJdbcSetup/Setup.cpp +++ b/OdbcJdbcSetup/Setup.cpp @@ -950,6 +950,13 @@ bool Setup::addDsn() char buffer[1024]; CServiceClient services; + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + SQLPostInstallerError(ODBC_ERROR_CREATE_DSN_FAILED, buffer); + }; + if ( !services.initServices( jdbcDriver ) ) { JString text; @@ -1068,13 +1075,13 @@ bool Setup::addDsn() return true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf( buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - SQLPostInstallerError( ODBC_ERROR_CREATE_DSN_FAILED, buffer ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } } return false; @@ -1128,13 +1135,13 @@ bool Setup::addDsn() return true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf( buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - SQLPostInstallerError( ODBC_ERROR_CREATE_DSN_FAILED, buffer ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } } return false; @@ -1168,13 +1175,13 @@ bool Setup::addDsn() return true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) { - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf( buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - SQLPostInstallerError( ODBC_ERROR_CREATE_DSN_FAILED, buffer ); + handle_error(ex.what()); } } return false; @@ -1198,6 +1205,13 @@ bool Setup::addDsn() bool Setup::removeDsn() { + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + SQLPostInstallerError(ODBC_ERROR_REMOVE_DSN_FAILED, buffer); + }; + if ( !dsn.IsEmpty() ) SQLRemoveDSNFromIni (dsn); @@ -1338,13 +1352,13 @@ bool Setup::removeDsn() return true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) { - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf( buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - SQLPostInstallerError( ODBC_ERROR_CREATE_DSN_FAILED, buffer ); + handle_error(ex.what()); } } return false; @@ -1398,13 +1412,13 @@ bool Setup::removeDsn() return true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf( buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - SQLPostInstallerError( ODBC_ERROR_CREATE_DSN_FAILED, buffer ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } } return false; @@ -1438,13 +1452,13 @@ bool Setup::removeDsn() return true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) { - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf( buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - SQLPostInstallerError( ODBC_ERROR_CREATE_DSN_FAILED, buffer ); + handle_error(ex.what()); } } return false; diff --git a/OdbcJdbcSetup/UsersTabUsers.cpp b/OdbcJdbcSetup/UsersTabUsers.cpp index 873665f4..c986fff7 100644 --- a/OdbcJdbcSetup/UsersTabUsers.cpp +++ b/OdbcJdbcSetup/UsersTabUsers.cpp @@ -267,6 +267,15 @@ void CUsersTabUsers::onEditUser( enumEditUser enOption ) int lengthOut; char bufferOut[1024]; + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_GET_INFO), TRUE); + + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + MessageBox(NULL, buffer, TEXT("Error!"), MB_ICONERROR | MB_OK); + }; + try { @@ -307,15 +316,13 @@ void CUsersTabUsers::onEditUser( enumEditUser enOption ) EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_GET_INFO ), TRUE ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_GET_INFO ), TRUE ); - - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf(buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - MessageBox( NULL, buffer, TEXT( "Error!" ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } services.closeService(); @@ -341,6 +348,15 @@ void CUsersTabUsers::onGetUsersList() return; } + auto handle_error = [&](const char* text, int sqlcode = 0, int fbcode = 0) + { + EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_GET_INFO), TRUE); + + char buffer[1024]; + sprintf(buffer, "sqlcode %d, fbcode %d - %s", sqlcode, fbcode, text); + MessageBox(NULL, buffer, TEXT("Error!"), MB_ICONERROR | MB_OK); + }; + try { @@ -398,15 +414,13 @@ void CUsersTabUsers::onGetUsersList() EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_GET_INFO ), TRUE ); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - EnableWindow( GetDlgItem( hDlg, IDC_BUTTON_GET_INFO ), TRUE ); - - char buffer[1024]; - SQLException &exception = (SQLException&)ex; - JString text = exception.getText(); - sprintf(buffer, "sqlcode %d, fbcode %d - %s", exception.getSqlcode(), exception.getFbcode(), (const char*)text ); - MessageBox( NULL, buffer, TEXT( "Error!" ), MB_ICONERROR | MB_OK ); + handle_error(ex.getText(), ex.getSqlcode(), ex.getFbcode()); + } + catch (const std::exception &ex) + { + handle_error(ex.what()); } delete[] bufferOut; diff --git a/OdbcObject.cpp b/OdbcObject.cpp index b904179a..0055d1d8 100644 --- a/OdbcObject.cpp +++ b/OdbcObject.cpp @@ -258,11 +258,20 @@ void OdbcObject::clearErrors() } -OdbcError* OdbcObject::postError(const char * sqlState, SQLException &exception) +OdbcError* OdbcObject::postError(const char * sqlState, const SQLException &exception) { return postError( new OdbcError( exception.getSqlcode(), exception.getFbcode(), sqlState, exception.getText() ) ); } +// Companion overload for std::exception. C++ catch ordering means a call +// site that catches SQLException first will dispatch the SQLException +// overload above and only reach this one for non-SQLException objects, so +// we can use what() directly without any runtime type check. +OdbcError* OdbcObject::postError(const char * sqlState, const std::exception &ex) +{ + return postError( new OdbcError( 0, 0, sqlState, ex.what() ) ); +} + const char * OdbcObject::getString(char * * temp, const UCHAR * string, int length, const char *defaultValue) { if (!string) diff --git a/OdbcObject.h b/OdbcObject.h index 9f891c4f..076bd0a5 100644 --- a/OdbcObject.h +++ b/OdbcObject.h @@ -57,7 +57,8 @@ class OdbcObject SQLRETURN sqlGetDiagRec (int handleType, int recNumber, SQLCHAR*sqlState,SQLINTEGER*nativeErrorPtr,SQLCHAR*messageText,int bufferLength,SQLSMALLINT*textLengthPtr); OdbcError* postError (const char *state, JString msg); const char * getString (char **temp, const UCHAR *string, int length, const char *defaultValue); - OdbcError* postError (const char *sqlState, SQLException &exception); + OdbcError* postError (const char *sqlState, const SQLException &exception); + OdbcError* postError (const char *sqlState, const std::exception &ex); void operator <<(OdbcObject * obj); void clearErrors(); OdbcError* postError (OdbcError *error); diff --git a/OdbcStatement.cpp b/OdbcStatement.cpp index b5e4b428..028a40d9 100644 --- a/OdbcStatement.cpp +++ b/OdbcStatement.cpp @@ -131,6 +131,7 @@ #include #include #include +#include #include "IscDbc/Connection.h" #include "IscDbc/SQLException.h" #include "OdbcEnv.h" @@ -151,15 +152,15 @@ namespace OdbcJdbcLibrary { using namespace IscDbcLibrary; -void TraceOutput(char * msg, intptr_t val) +static void TraceOutput(char * msg, intptr_t val) { char buf[80]; - sprintf( buf, "\t%s = %ld : %p\n", msg, val, (void*)val ); + sprintf( buf, "\t%s = %" PRIu64 " : %p\n", msg, val, (void*)val ); OutputDebugString(buf); } -// Bound Address + Binding Offset + ((Row Number – 1) x Element Size) -// *ptr = binding->pointer + bindOffsetPtr + ((1 – 1) * rowBindType); // <-- for single row +// Bound Address + Binding Offset + ((Row Number - 1) x Element Size) +// *ptr = binding->pointer + bindOffsetPtr + ((1 - 1) * rowBindType); // <-- for single row #define GETBOUNDADDRESS(binding) ( (uintptr_t)binding->dataPtr + ( applicationParamDescriptor->headBindType ? (uintptr_t)bindOffsetPtr : 0 ) ); ////////////////////////////////////////////////////////////////////// @@ -302,10 +303,14 @@ SQLRETURN OdbcStatement::sqlTables(SQLCHAR * catalog, int catLength, DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getTables (cat, scheme, tbl, numberTypes, typeVector)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -329,10 +334,14 @@ SQLRETURN OdbcStatement::sqlTablePrivileges(SQLCHAR * catalog, int catLength, DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getTablePrivileges (cat, scheme, tbl)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -358,10 +367,14 @@ SQLRETURN OdbcStatement::sqlColumnPrivileges(SQLCHAR * catalog, int catLength, DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getColumnPrivileges (cat, scheme, tbl, col)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -479,10 +492,14 @@ SQLRETURN OdbcStatement::sqlPrepare(SQLCHAR * sql, int sqlLength) } } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -710,10 +727,14 @@ SQLRETURN OdbcStatement::sqlBindCol(int column, int targetType, SQLPOINTER targe bulkInsert = NULL; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -740,6 +761,14 @@ SQLRETURN OdbcStatement::fetchData() SQLLEN *&bindOffsetPtr = applicationRowDescriptor->headBindOffsetPtr; SQLLEN *bindOffsetPtrSave = bindOffsetPtr; + auto handle_error = [&](const char* state, auto& ex) -> SQLRETURN + { + bindOffsetPtr = bindOffsetPtrSave; + OdbcError* error = postError(state, ex); + error->setRowNumber(rowNumber); + return SQL_ERROR; + }; + try { int nRow = 0; @@ -818,13 +847,13 @@ SQLRETURN OdbcStatement::fetchData() return SQL_NO_DATA; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - bindOffsetPtr = bindOffsetPtrSave; - OdbcError *error = postError ("HY000", exception); - error->setRowNumber (rowNumber); - return SQL_ERROR; + return handle_error("HY000", ex); + } + catch (const std::exception &ex) + { + return handle_error("HY000", ex); } return sqlSuccess(); @@ -1298,6 +1327,20 @@ SQLRETURN OdbcStatement::sqlBulkOperations( int operation ) if ( !resultSet ) return sqlReturn( SQL_ERROR, "24000", "Invalid cursor state" ); + auto handle_error = [&](const char* state, auto& ex) -> SQLRETURN + { + if (bulkInsert) + { + if (bulkInsert->infoPosted) + *this << bulkInsert; + + bulkInsert->statement->rollbackLocal(); + } + + postError(state, ex); + return SQL_ERROR; + }; + try { switch ( operation ) @@ -1406,19 +1449,13 @@ SQLRETURN OdbcStatement::sqlBulkOperations( int operation ) return sqlReturn( SQL_ERROR, "IM001", (const char*)"Driver does not support this function" ); } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - if ( bulkInsert ) - { - if ( bulkInsert->infoPosted ) - *this << bulkInsert; - - bulkInsert->statement->rollbackLocal(); - } - - SQLException &exception = (SQLException&)ex; - postError( "HY000", exception ); - return SQL_ERROR; + return handle_error("HY000", ex); + } + catch (const std::exception &ex) + { + return handle_error("HY000", ex); } return sqlSuccess(); @@ -1522,10 +1559,14 @@ SQLRETURN OdbcStatement::sqlColumns(SQLCHAR * catalog, int catLength, SQLCHAR * DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getColumns (cat, scheme, tbl, col)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -1564,10 +1605,14 @@ SQLRETURN OdbcStatement::sqlFreeStmt(int option) break; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -1627,10 +1672,14 @@ SQLRETURN OdbcStatement::sqlStatistics(SQLCHAR * catalog, int catLength, unique == SQL_INDEX_UNIQUE, reservedSic == SQL_QUICK)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -1652,10 +1701,14 @@ SQLRETURN OdbcStatement::sqlPrimaryKeys(SQLCHAR * catalog, int catLength, SQLCHA DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getPrimaryKeys (cat, scheme, tbl)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -1685,10 +1738,14 @@ SQLRETURN OdbcStatement::sqlForeignKeys (SQLCHAR * pkCatalog, int pkCatLength, DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getCrossReference (pkCat, pkScheme,pkTbl,fkCat,fkScheme,fkTbl)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -1715,10 +1772,14 @@ SQLRETURN OdbcStatement::sqlNumParams(SWORD * params) if( params ) *params = statement->getNumParams(); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } else if( params ) @@ -1766,10 +1827,14 @@ SQLRETURN OdbcStatement::sqlDescribeCol(int col, OutputDebugString (tempDebugStr); #endif } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -1897,10 +1962,14 @@ SQLRETURN OdbcStatement::sqlGetData(int column, int cType, PTR pointer, SQLLEN b return SQL_SUCCESS_WITH_INFO; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } } @@ -1920,10 +1989,14 @@ SQLRETURN OdbcStatement::sqlExecute() parameterNeedData = 0; retcode = (this->*execute)(); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + retcode = SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); retcode = SQL_ERROR; } @@ -1944,10 +2017,14 @@ SQLRETURN OdbcStatement::sqlExecDirect(SQLCHAR * sql, int sqlLength) parameterNeedData = 0; retcode = (this->*execute)(); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -2037,10 +2114,14 @@ SQLRETURN OdbcStatement::sqlDescribeParam(int parameter, SWORD * sqlType, SQLULE if (nullable) *nullable = (metaData->isNullable (parameter)) ? SQL_NULLABLE : SQL_NO_NULLS; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -2290,10 +2371,14 @@ SQLRETURN OdbcStatement::sqlBindParameter(int parameter, int type, int cType, registrationOutParameter = false; } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -2306,10 +2391,14 @@ SQLRETURN OdbcStatement::sqlCancel() { cancel = true; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -2331,10 +2420,14 @@ SQLRETURN OdbcStatement::sqlProcedures(SQLCHAR * catalog, int catLength, SQLCHAR DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getProcedures (cat, scheme, procedures)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -2357,10 +2450,14 @@ SQLRETURN OdbcStatement::sqlProcedureColumns(SQLCHAR * catalog, int catLength, S DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getProcedureColumns (cat, scheme, procedures, columns)); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -2384,10 +2481,14 @@ SQLRETURN OdbcStatement::sqlSetCursorName(SQLCHAR * name, int nameLength) setPreCursorName = false; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -2403,10 +2504,14 @@ SQLRETURN OdbcStatement::sqlCloseCursor() setPreCursorName = false; releaseResultSet(); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -2560,10 +2665,14 @@ SQLRETURN OdbcStatement::sqlGetStmtAttr(int attribute, SQLPOINTER ptr, int buffe if (lengthPtr) *lengthPtr = sizeof (intptr_t); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -2577,10 +2686,14 @@ SQLRETURN OdbcStatement::sqlGetCursorName(SQLCHAR *name, int bufferLength, SQLSM { returnStringInfo (name, bufferLength, nameLength, cursorName); } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } return sqlSuccess(); @@ -2981,10 +3094,14 @@ SQLRETURN OdbcStatement::executeCommit() statement->commitLocal(); return SQL_SUCCESS; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError( "S1000", ex ); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError( "S1000", exception ); + postError( "S1000", ex ); return SQL_ERROR; } } @@ -3003,10 +3120,14 @@ SQLRETURN OdbcStatement::executeRollback() statement->rollbackLocal(); return SQL_SUCCESS; } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError( "S1000", ex ); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError( "S1000", exception ); + postError( "S1000", ex ); return SQL_ERROR; } } @@ -3034,10 +3155,14 @@ SQLRETURN OdbcStatement::sqlGetTypeInfo(int dataType) DatabaseMetaData *metaData = connection->getMetaData(); setResultSet (metaData->getTypeInfo (dataType), false); } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -3109,10 +3234,14 @@ SQLRETURN OdbcStatement::sqlParamData(SQLPOINTER *ptr) *(uintptr_t*)ptr = GETBOUNDADDRESS(binding); } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + retcode = SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); retcode = SQL_ERROR; } @@ -3479,10 +3608,14 @@ SQLRETURN OdbcStatement::sqlSetStmtAttr(int attribute, SQLPOINTER ptr, int lengt return sqlReturn (SQL_ERROR, "HYC00", "Optional feature not implemented"); } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -3511,10 +3644,14 @@ SQLRETURN OdbcStatement::sqlRowCount(SQLLEN *rowCount) *rowCount = -1; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) + { + postError ("HY000", ex); return SQL_ERROR; } @@ -3651,10 +3788,14 @@ SQLRETURN OdbcStatement::sqlColAttribute( int column, int fieldId, SQLPOINTER at } } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } @@ -3705,10 +3846,14 @@ SQLRETURN OdbcStatement::sqlSpecialColumns(unsigned short rowId, SQLCHAR * catal eof = true; } } - catch ( std::exception &ex ) + catch (const SQLException &ex) + { + postError ("HY000", ex); + return SQL_ERROR; + } + catch (const std::exception &ex) { - SQLException &exception = (SQLException&)ex; - postError ("HY000", exception); + postError ("HY000", ex); return SQL_ERROR; } diff --git a/tests/test_connect_options.cpp b/tests/test_connect_options.cpp index b5162e93..d5ff4e32 100644 --- a/tests/test_connect_options.cpp +++ b/tests/test_connect_options.cpp @@ -3,6 +3,7 @@ // Tests SQLConnect, SQLDriverConnect, attribute persistence, and transaction behavior. #include "test_helpers.h" +#include #include #include @@ -709,3 +710,129 @@ TEST_F(ConnectionResetTest, ResetResetsQueryTimeout) { EXPECT_EQ(timeout, 0u) << "Query timeout should be 0 after connection reset"; } + +// ===== Negative SQLDriverConnect tests ===== +// +// When SQLDriverConnect fails the driver must populate a well-formed diagnostic +// record. A failed call that returns an empty SQLSTATE, a wild native code or +// a message whose strlen does not match the reported length leaves callers +// with no way to recover or branch on the error. + +namespace { + +// Replace the value of a single connection-string key (case-insensitive). If +// the key isn't present the original string is returned unchanged. +std::string ReplaceConnKey(const std::string &conn, + const std::string &key, + const std::string &newValue) { + std::string out; + size_t pos = 0; + while (pos < conn.size()) { + size_t end = conn.find(';', pos); + if (end == std::string::npos) end = conn.size(); + std::string token = conn.substr(pos, end - pos); + size_t eq = token.find('='); + std::string tokKey = (eq != std::string::npos) ? token.substr(0, eq) : token; + std::string tokKeyLower = tokKey; + std::string keyLower = key; + for (auto &c : tokKeyLower) c = (char)tolower((unsigned char)c); + for (auto &c : keyLower) c = (char)tolower((unsigned char)c); + if (tokKeyLower == keyLower) + out += tokKey + "=" + newValue; + else + out += token; + if (end < conn.size()) out += ';'; + pos = end + 1; + } + return out; +} + +} // namespace + +// Failed login (wrong password) must produce a well-formed diagnostic record. +// Note: Firebird in embedded/local-trusted-auth mode (which CI uses) does not +// check the password, so this test skips itself when the connect unexpectedly +// succeeds. +TEST_F(ConnectOptionsTest, BadPasswordReturnsValidDiagRec) { + AllocEnvAndDbc(); + + std::string badConn = ReplaceConnKey(GetConnectionString(), + "PWD", "invalid-password-xyz"); + + SQLCHAR outStr[1024] = {}; + SQLSMALLINT outLen = 0; + SQLRETURN rc = SQLDriverConnect(hDbc, NULL, + (SQLCHAR*)badConn.c_str(), SQL_NTS, + outStr, sizeof(outStr), &outLen, + SQL_DRIVER_NOPROMPT); + if (SQL_SUCCEEDED(rc)) { + GTEST_SKIP() << "Connect succeeded despite invalid password; the " + "Firebird server is using embedded or trusted " + "authentication and won't exercise the failure path."; + } + + SQLCHAR sqlState[6] = {}; + SQLINTEGER native = 0; + SQLCHAR msg[1024] = {}; + SQLSMALLINT msgLen = 0; + SQLRETURN drc = SQLGetDiagRec(SQL_HANDLE_DBC, hDbc, 1, sqlState, &native, + msg, sizeof(msg), &msgLen); + ASSERT_EQ(drc, SQL_SUCCESS) + << "SQLGetDiagRec must return a record after SQLDriverConnect failure"; + + EXPECT_EQ(strlen((char*)sqlState), 5u) + << "SQLSTATE must be exactly 5 chars, got '" + << (char*)sqlState << "' (len=" << strlen((char*)sqlState) << ")"; + + EXPECT_EQ((size_t)msgLen, strlen((char*)msg)) + << "Reported message length (" << msgLen + << ") must match strlen of returned message (" + << strlen((char*)msg) << "); message='" << (char*)msg << "'"; + + EXPECT_GT(strlen((char*)msg), 1u) + << "Message must contain more than a single byte; got '" + << (char*)msg << "'"; +} + +// Failed connect to a nonexistent database must also produce a well-formed +// diagnostic record. +TEST_F(ConnectOptionsTest, NonexistentDatabaseReturnsValidDiagRec) { + AllocEnvAndDbc(); + + // Build a connection string with the same Driver but pointing at a path + // that cannot exist. Try both spellings: Database= and Dbname=. + std::string bogus = "/nonexistent/path/no-such-database.fdb"; + std::string badConn = ReplaceConnKey(GetConnectionString(), "Database", bogus); + badConn = ReplaceConnKey(badConn, "Dbname", bogus); + + SQLCHAR outStr[1024] = {}; + SQLSMALLINT outLen = 0; + SQLRETURN rc = SQLDriverConnect(hDbc, NULL, + (SQLCHAR*)badConn.c_str(), SQL_NTS, + outStr, sizeof(outStr), &outLen, + SQL_DRIVER_NOPROMPT); + ASSERT_FALSE(SQL_SUCCEEDED(rc)) + << "Connect to nonexistent database was expected to fail"; + + SQLCHAR sqlState[6] = {}; + SQLINTEGER native = 0; + SQLCHAR msg[1024] = {}; + SQLSMALLINT msgLen = 0; + SQLRETURN drc = SQLGetDiagRec(SQL_HANDLE_DBC, hDbc, 1, sqlState, &native, + msg, sizeof(msg), &msgLen); + ASSERT_EQ(drc, SQL_SUCCESS) + << "SQLGetDiagRec must return a record after SQLDriverConnect failure"; + + EXPECT_EQ(strlen((char*)sqlState), 5u) + << "SQLSTATE must be exactly 5 chars, got '" + << (char*)sqlState << "' (len=" << strlen((char*)sqlState) << ")"; + + EXPECT_EQ((size_t)msgLen, strlen((char*)msg)) + << "Reported message length (" << msgLen + << ") must match strlen of returned message (" + << strlen((char*)msg) << "); message='" << (char*)msg << "'"; + + EXPECT_GT(strlen((char*)msg), 1u) + << "Message must contain more than a single byte; got '" + << (char*)msg << "'"; +}