2005/5/9

     
 

ODBCDriver.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_sql_odbc/src/acdk/sql/odbc/ODBCDriver.cpp,v 1.7 2005/02/05 10:45:31 kommer Exp $
#include "ODBCDriver.h"
#include "ODBCConnection.h"
#include "ODBCResultSetMetaData.h"

#include <acdk/lang/Integer.h>
#include <acdk/lang/NumberFormatException.h>

namespace acdk {
namespace sql {
namespace odbc {

using namespace acdk::lang;

ODBCDriver::ODBCDriver() 
: majorVersion(0), minorVersion(1), _envh(Nil)
{
  ACDK_SAFE_CONSTRUCTOR();

  // we may alloc _envh here, but if this fails, we should throw an exception,
  // which may not be expected within a constructor and may duce to memory-leaks.
  ::acdk::sql::DriverManager::registerDriver(this);
}

ODBCDriver::~ODBCDriver()
{
  //recursiv call !::acdk::sql::DriverManager::deregisterDriver(this);
}


RConnection
ODBCDriver::connect(INP(RString) url, INP(acdk::util::RProperties) properties) THROWS1(RSQLException)
{
  //SQLRETURN err;
  RODBCConnection conn;
  int logintimeout, pool;
  
  if (acceptsURL(url) == false) // maybe the caller is lazy
    return Nil;

  if (properties != Nil) 
  {
    RString key, res;
    key = new String("LoginTimeout");
    res = properties->getProperty(key);
    if (res != Nil) {
      try {
        logintimeout = ::acdk::lang::Integer::decode(res);
      } catch (NumberFormatException e) {
        // the caller might not catch NumberFormatException, but SQLException.
        THROW1(SQLException, "invalid Property-value for \"LoginTimeout\"");
      }      
    }
    key = Nil;
    key = new String("ConnectionPooling");
    res = properties->getProperty(key);
    if (res != Nil) {
#if ODBCVER >= 0x0300
      try {
        pool = ::acdk::lang::Integer::decode(res);
      } catch (NumberFormatException e) {
        RString tmp;
        tmp = new String("ONE_PER_DRIVER");
        if (res->equals(tmp) == true) {
          pool = SQL_CP_ONE_PER_DRIVER;
        } else {
          tmp = Nil;
          tmp = new String("ONE_PER_HENV");
          if (res->equals(tmp) == true) {
            pool = SQL_CP_ONE_PER_HENV;
          } else {
            tmp = Nil;
            tmp = new String("OFF");
            if (res->equals(tmp) == true) {
              pool = SQL_CP_OFF;
            } else {
              THROW1(SQLException, "invalid Property-value for \"ConnectionPooling\"");
            }
          }
        }
      }
#else // ODBCVER
    RString msg = RString("unsupported Property-value \"") + key + "\" for ODBC-version " + ::acdk::lang::Integer::toString(ODBCVER, 16);
    THROW1(SQLException, msg);
#endif // ODBCVER
    }
    key = Nil;
  } else {
    logintimeout = 0;
#if ODBCVER >= 0x0300
    pool = SQL_CP_DEFAULT;
#else // ODBCVER
    pool = 0;
#endif // ODBCVER
  }

  // for an ODBC-connect we need first a handle via:
  // SQLRETURN SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandlePtr);
  // for the real connect, we need SQL_HANDLE_DBC as HandleType which needs SQL_HANDLE_ENV as InputHandle.
  // so we allocate this before the needed handle with an InputHandle of SQL_NULL_HANDLE.
  
  if (_envh == Nil) {
#if ODBCVER >= 0x0300
    /*
     * maybe this is wrong and has to be disabled, but the documentation sais, that this is needed
     * for reusing pending connections, but maybe this interpretation is simply wrong.
     */
    SQLRETURN sqlret = ::SQLSetEnvAttr(0, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)pool, SQL_IS_UINTEGER);
    ACDK_NLOGP("sql", SysDebug, "SQLSetEnvAttr(0, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)pool, SQL_IS_UINTEGER)", LOG_NPV(pool, pool) << LOG_NPV(ret, sqlret));
#endif // ODBCVER

    _envh = new ODBCHandle(SQL_HANDLE_ENV);
    
    _envh->init(Nil);    
  }
  conn = new ODBCConnection(this);
  
  return &conn->init(url, properties);
}

} // odbc
} // sql
} // acdk