2005/5/9

     
 

ODBCStatement.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/ODBCStatement.cpp,v 1.6 2005/03/08 18:55:38 kommer Exp $

#include "ODBCStatement.h"
#include "ODBCResultSet.h"
#include "ODBCHandle.h"
#include "ODBCConnection.h"
#include "ODBCDriver.h"
#include "ODBCResultSetMetaData.h"

#include <acdk/lang/Integer.h>
#include <acdk/util/Properties.h>

#if !defined(ACDK_MINI)
#include <acdk/lang/Thread.h>
#endif
/FONT>
#include <acdk/lang/System.h>

namespace acdk {
namespace sql {
namespace odbc {

using namespace acdk::lang;

ODBCStatement::ODBCStatement(INP(RODBCConnection) conn) 
: _stmth(Nil)
, _conn(conn)
//, _rset(Nil)
, _sql(Nil)
, _queryTimeout(0)
, _maxLength(-1)
, _maxRows(-1)
, _scanEscapes(true)
, _scrollableCursors(false)
, _direction(FETCH_UNKNOWN) 
{
}

ODBCStatement::~ODBCStatement() 
{ 
  ACDK_NLOG("acdk.sql.odbc", Debug, "ODBCStatement::~ODBCStatement");
  close(); 
}
 
//virtual
RODBCStatement
ODBCStatement::init(INP(::acdk::util::RProperties) prop)
{
  if (_stmth != Nil)
    return this;

  _stmth = new ODBCHandle(SQL_HANDLE_STMT);

  _stmth->init(_conn->_getODBCHandle());

  /*
   * while we had many things to do for initializing driver and connection, statement is only a skeleton object
   * created by RConnection::CreateStatement, which is filled just before execution with more data...
   */
  return this;
}

//virtual
void
ODBCStatement::deinit()
{
  if (_stmth != Nil) 
  {
    _stmth->deinit();
    _stmth = Nil;
  }
  _conn = Nil;
}

//virtual
void
ODBCStatement::setScrollableCursor(bool enable)
{
#if ODBCVER >= 0x0300
  _scrollableCursors = enable;
  if (_stmth == Nil)
    return;
  _stmth->_setSQLFlag(SQL_ATTR_CURSOR_SCROLLABLE, (_scrollableCursors == true)? SQL_SCROLLABLE : SQL_NONSCROLLABLE);
#else // ODBCVER
  RString msg = RString("can't change ScrollableCursor-mode in odbc-version ") + ::acdk::lang::Integer::toString(ODBCVER, 16);
  ::acdk::sql::RSQLException ex = new SQLException(msg);
  if (_stmth != Nil) {
    _stmth->_addException(ex);
    SQLTHROW(_stmth->_getExceptions());
  } else {
    SQLTHROW(ex);
  }
#endif // ODBCVER
}

//virtual
bool
ODBCStatement::getScrollableCursor()
{
#if ODBCVER >= 0x0300
  return _scrollableCursors;
#else // ODBCVER
  RString msg = RString("can't examine ScrollableCursor-mode in odbc-version ") + ::acdk::lang::Integer::toString(ODBCVER, 16);
  ::acdk::sql::RSQLException ex = new SQLException(msg);
  if (_stmth != Nil) {
    _stmth->_addException(ex);
    SQLTHROW(_stmth->_getExceptions());
  } else {
    SQLTHROW(ex);
  }
  return false; // keep gcc quiet
#endif // ODBCVER
}

//virtual
RResultSet
ODBCStatement::getResultSet()
{
  return new ODBCResultSet(this, _direction);
}

//virtual
RConnection
ODBCStatement::getConnection()
{
  return &_conn; //can't be inline, or gcc will fail.
}

//virtual
void
ODBCStatement::close()
{
  if (_stmth != Nil) 
  {
    _stmth->_clearWarnings();
    _stmth->_clearExceptions();
  }
  deinit();
}

//virtual
bool
ODBCStatement::execute(INP(RString) sql)
{
  SQLSMALLINT ccnt = 0;
  
  if (_stmth == Nil) 
    THROW1(SQLException, "invalid Statement-object");
  
  _sql = Nil;
#if defined(ACDK_ODBC_DEBUG)
  System::err->println(RString("SQLODBC [") + Integer::toString(Thread::currentThreadId().threadID()) + "]: executing \"" + sql + "\"");
#endif
/FONT>
  RString nsql = ODBC_STR2NSTR(sql);
  ODBC_NATIVE_CHAR* tptr = ODBC_STR2NCSRT(nsql);
  int len = nsql->length();
  callSQL2(_stmth, SQLExecDirect, tptr, len);

  _sql = sql;

  //_rset = new ODBCResultSet(this, _direction);  
  /*
   * SQLNumResultCols() is the only possibility to determine, if
   * any resultset is available after execution. the column-count
   * will be >= 1 if there's at least one ResultSet.
   */
  callSQL1(_stmth, SQLNumResultCols, &ccnt);
  
  return (ccnt > 0)? true : false;
}

//virtual
RResultSet
ODBCStatement::executeQuery(INP(RString) sql)
{
  
  if (execute(sql) != true) {
    RString msg = RString("no resultset for query \"") + sql + "\"";
    ::acdk::sql::RSQLException ex = new SQLException(msg);
    if (_stmth != Nil) {
      _stmth->_addException(ex);
      SQLTHROW(_stmth->_getExceptions());
    } else {
      SQLTHROW(ex);
    }
  }
  return getResultSet();
}

//virtual
int
ODBCStatement::executeUpdate(INP(RString) sql)
{
  SQLINTEGER rcnt = 0;

  execute(sql);
  
  callSQL1(_stmth, SQLRowCount, &rcnt);
  
  return rcnt;
}

//virtual
void
ODBCStatement::setFetchDirection(int direction)
{
  switch (direction) {
    case FETCH_UNKNOWN:
    case FETCH_REVERSE:
    case FETCH_FORWARD:
      _direction = (FetchDirection)direction;
      break;
    default:
      RString msg = RString("invalid value for direction: ") + ::acdk::lang::Integer::toString(direction);
      ::acdk::sql::RSQLException ex = new SQLException(msg);
      if (_stmth != Nil) {
        _stmth->_addException(ex);
        SQLTHROW(_stmth->_getExceptions());
      } else {
        SQLTHROW(ex);
      }
      break;
  }
}

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