/*- * Copyright 2007 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #include #if HAVE_SQL_H #include #include #include #endif //--------------------------------------------------------------------------- namespace odbcpp { //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- Database::~Database() { if( transaction_ != NULL ) transaction_->detach(); detach(); } //--------------------------------------------------------------------------- Database::Database() : envHandle_(NULL), handle_(NULL), transaction_(NULL) { } //--------------------------------------------------------------------------- Database & Database::freeHandle() { #if HAVE_SQL_H if( handle_ != NULL ){ api.SQLFreeHandle(SQL_HANDLE_DBC,handle_); handle_ = NULL; } if( envHandle_ != NULL ){ api.SQLFreeHandle(SQL_HANDLE_ENV,envHandle_); envHandle_ = NULL; } #else newObjectV1C2(ENOSYS, __PRETTY_FUNCTION__)->throwSP(); #endif return *this; } //--------------------------------------------------------------------------- EClientServer * Database::exception(SQLSMALLINT handleType,SQLHANDLE handle,utf8::String * pSqlState) const { #if HAVE_SQL_H SQLWCHAR sqlState[6], msg[SQL_MAX_MESSAGE_LENGTH]; SQLINTEGER nativeError; SQLSMALLINT msgLen, recNumber; SQLRETURN r = SQL_SUCCESS; ksys::AutoPtr e(newObject()); for( recNumber = 1; r != SQL_NO_DATA; recNumber++ ){ sqlState[0] = L'\0'; r = api.SQLGetDiagRecW( handleType, handle, recNumber, sqlState, &nativeError, msg, sizeof(msg), &msgLen ); if( r != SQL_NO_DATA ){ if( pSqlState != NULL ){ *pSqlState = sqlState; pSqlState = NULL; } e->addError(nativeError == 0 ? EINVAL : nativeError,"ODBC state: " + utf8::String(sqlState) + (nativeError != 0 ? ", native error code: " + utf8::int2Str(intmax_t(nativeError)) : utf8::String()) + (msgLen > 0 ? utf8::String(", ") + msg : utf8::String()) ); } } return e.ptr(NULL); #else newObjectV1C2(ENOSYS, __PRETTY_FUNCTION__)->throwSP(); return NULL; #endif } //--------------------------------------------------------------------------- Database & Database::create(const utf8::String &) { return *this; } //--------------------------------------------------------------------------- Database & Database::drop() { return *this; } //--------------------------------------------------------------------------- Database & Database::attach(const utf8::String & name) { #if HAVE_SQL_H if( !attached() ){ api.open(); try { SQLRETURN r = api.SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&envHandle_); if( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) exceptionHandler(newObjectV1C2(EINVAL,"ODBC SQLAllocHandle(SQL_HANDLE_ENV) failed " + utf8::String(__PRETTY_FUNCTION__))); r = api.SQLSetEnvAttr(envHandle_,SQL_ATTR_ODBC_VERSION,(SQLPOINTER) SQL_OV_ODBC3,0); if( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) exceptionHandler(exception(SQL_HANDLE_ENV,envHandle_)); r = api.SQLAllocHandle(SQL_HANDLE_DBC,envHandle_,&handle_); if( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) exceptionHandler(exception(SQL_HANDLE_ENV,envHandle_)); /*r = api.SQLSetConnectAttr(handle_,SQL_LOGIN_TIMEOUT,(SQLPOINTER) 5,0); if( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) exceptionHandler(exception(SQL_HANDLE_DBC,handle_));*/ ksys::AutoPtr connOut; connOut.alloc(sizeof(SQLWCHAR) * SQLSMALLINT((1u << (sizeof(SQLSMALLINT) * 8 - 1)) - 1)); SQLSMALLINT cbConnStrOut = 0; r = api.SQLBrowseConnectW( handle_, (name.isNull() ? connection_ : name).getUNICODEString(), SQL_NTS, connOut, SQLSMALLINT((1u << (sizeof(SQLSMALLINT) * 8 - 1)) - 1), &cbConnStrOut ); if( r == SQL_NEED_DATA ){ exceptionHandler(newObjectV1C2(EINVAL, utf8::String("ODBC SQLBrowseConnect failed, ") + connOut.ptr() + ", " + __PRETTY_FUNCTION__)); } else if( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ){ r = api.SQLDriverConnectW( handle_, NULL, (name.isNull() ? connection_ : name).getUNICODEString(), SQL_NTS, connOut, SQLSMALLINT((1u << (sizeof(SQLSMALLINT) * 8 - 1)) - 1), &cbConnStrOut, SQL_DRIVER_NOPROMPT ); if( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) exceptionHandler(exception(SQL_HANDLE_DBC,handle_)); } } catch( ksys::ExceptionSP & ){ detach(); throw; } if( !name.isNull() ) connection_ = name; } #else newObjectV1C2(ENOSYS, __PRETTY_FUNCTION__)->throwSP(); #endif return *this; } //--------------------------------------------------------------------------- Database & Database::detach() { #if HAVE_SQL_H if( attached() ){ if( transaction_ != NULL ) while( transaction_->active() ) transaction_->rollback(); ksys::EmbeddedListNode * node = statements_.first(); while( node != NULL ){ DSQLStatement::listObject(*node).freeHandle(); node = node->next(); } freeHandle(); api.close(); } #else newObjectV1C2(ENOSYS, __PRETTY_FUNCTION__)->throwSP(); #endif return *this; } //--------------------------------------------------------------------------- void Database::processingException(ksys::Exception * e) { EClientServer * p = dynamic_cast(e); if( p != NULL ){ if( p->isFatalError() ){ detach(); } } } //--------------------------------------------------------------------------- void Database::staticExceptionHandler(ksys::Exception * e) { transaction_->processingException(e); processingException(e); e->throwSP(); } //--------------------------------------------------------------------------- void Database::exceptionHandler(ksys::Exception * e) { staticExceptionHandler(e); } //--------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////// // properties /////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- Database & Database::connection(const utf8::String & connection) { if( connection_.strcasecmp(connection) != 0 ){ if( attached() ) detach(); connection_ = connection; } return *this; } //--------------------------------------------------------------------------- } // namespace odbcpp //---------------------------------------------------------------------------