2005/5/9

     
 

ODBCDatabaseMetaData.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/ODBCDatabaseMetaData.cpp,v 1.7 2005/02/05 10:45:31 kommer Exp $
#include "ODBCDatabaseMetaData.h"
#include "ODBCConnection.h"
#include "ODBCDriver.h"
#include "ODBCResultSetMetaData.h"

#include <acdk/util/Properties.h>

namespace acdk {
namespace sql {
namespace odbc {

using namespace acdk::lang;

RString 
ODBCDatabaseMetaData::getStringInfo(int code) THROWS1(::acdk::sql::RSQLException)
{
  const int bufsize = 255;
  SQLCHAR buffer[bufsize];
  RODBCHandle h = _conn->_getODBCHandle();
  SQLHANDLE sqlhandle = h->_getSQLHandle();
  short reallen;
  SQLRETURN ret = SQLGetInfo(sqlhandle, (SQLUSMALLINT)code, (SQLPOINTER)buffer, bufsize - 1, &reallen);
  h->_chkSQLrcode(ret, "ODBCDatabaseMetaData::getStringInfo", __FILE__, __LINE__);
  return ODBCSTR2STR(buffer, reallen);
}

short 
ODBCDatabaseMetaData::getShortInfo(int code) THROWS1(::acdk::sql::RSQLException)
{
  RODBCHandle h = _conn->_getODBCHandle();
  SQLHANDLE sqlhandle = h->_getSQLHandle();
  short returnValue;
  short reallen;
  SQLRETURN ret = SQLGetInfo(sqlhandle, (SQLUSMALLINT)code, &returnValue, sizeof(returnValue),  &reallen);
  h->_chkSQLrcode(ret, "ODBCDatabaseMetaData::getShortInfo", __FILE__, __LINE__);
  return returnValue;
}

int 
ODBCDatabaseMetaData::getIntInfo(int code) THROWS1(::acdk::sql::RSQLException)
{
  RODBCHandle h = _conn->_getODBCHandle();
  SQLHANDLE sqlhandle = h->_getSQLHandle();
  int returnValue;
  short reallen;
  SQLRETURN ret = SQLGetInfo(sqlhandle, (SQLUSMALLINT)code, &returnValue, sizeof(returnValue),  &reallen);
  h->_chkSQLrcode(ret, "ODBCDatabaseMetaData::getIntInfo", __FILE__, __LINE__);
  return returnValue;
}

RString 
ODBCDatabaseMetaData::getNumericFunctions() THROWS1(::acdk::sql::RSQLException)
{
  struct FuncMap
  {
    int code;
    const char* name;
  };
  FuncMap m[] = 
  {
  { SQL_FN_NUM_ABS, "ABS" },
  { SQL_FN_NUM_ACOS, "ACOS" },
  { SQL_FN_NUM_ASIN, "ASIN" },
  { SQL_FN_NUM_ATAN, "ATAN" },
  { SQL_FN_NUM_ATAN2, "ATAN2" },
  { SQL_FN_NUM_CEILING,	"CEILING" },
  { SQL_FN_NUM_COS, "COS" },
  { SQL_FN_NUM_COT, "COT" },
  { SQL_FN_NUM_DEGREES, "DEGREES" },
  { SQL_FN_NUM_EXP, "EXP" },
  { SQL_FN_NUM_FLOOR, "FLOOR" },
  { SQL_FN_NUM_LOG, "LOG" },
  { SQL_FN_NUM_LOG10, "LOG10" },
  { SQL_FN_NUM_MOD, "MOD" },
  { SQL_FN_NUM_PI, "PI" },
  { SQL_FN_NUM_POWER, "POWER" },
  { SQL_FN_NUM_RADIANS, "RADIANS" },
  { SQL_FN_NUM_RAND, "RAND" },
  { SQL_FN_NUM_ROUND, "ROUND" },
  { SQL_FN_NUM_SIGN, "SIGN" },
  { SQL_FN_NUM_SIN, "SIN" },
  { SQL_FN_NUM_SQRT, "SQRT" },
  { SQL_FN_NUM_TAN, "TAN" },
  { SQL_FN_NUM_TRUNCATE, "TRUNCATE" },
  { 0, 0 }
  };
  StringBuffer sb;
  int funcs = getIntInfo(SQL_NUMERIC_FUNCTIONS);
  for (int i = 0; m[i].code != 0; ++i)
  {
    if (funcs & m[i].code)
    {
      if (sb.length() > 0)
        sb << ",";
      sb << m[i].name;
    }
  }
  return sb.toString();
}


RString 
ODBCDatabaseMetaData::getStringFunctions() THROWS1(::acdk::sql::RSQLException)
{
  struct FuncMap
  {
    int code;
    const char* name;
  };
  FuncMap m[] = 
  {
    { SQL_FN_STR_BIT_LENGTH, "BIT_LENGTH" },
    { SQL_FN_STR_CHAR_LENGTH, "CHAR_LENGTH" },
    { SQL_FN_STR_CHARACTER_LENGTH, "CHARACTER_LENGTH" },
    { SQL_FN_STR_OCTET_LENGTH, "OCTET_LENGTH" },
    { SQL_FN_STR_POSITION, "POSITION" },
    { SQL_FN_STR_ASCII, "ASCII" },
    { SQL_FN_STR_CHAR, "CHAR" },
    { SQL_FN_STR_CONCAT, "CONCAT" },
    { SQL_FN_STR_DIFFERENCE, "DIFFERENCE" },
    { SQL_FN_STR_INSERT, "INSERT" },
    { SQL_FN_STR_LCASE, "LCASE" },
    { SQL_FN_STR_LEFT, "LEFT" },
    { SQL_FN_STR_LENGTH, "LENGTH" },
    { SQL_FN_STR_LOCATE, "LOCATE" },
    { SQL_FN_STR_LOCATE_2, "LOCATE_2" },
    { SQL_FN_STR_LTRIM, "LTRIM" },
    { SQL_FN_STR_REPEAT, "REPEAT" },
    { SQL_FN_STR_REPLACE, "REPLACE" },
    { SQL_FN_STR_RIGHT, "RIGHT" },
    { SQL_FN_STR_RTRIM, "RTRIM" },
    { SQL_FN_STR_SOUNDEX, "SOUNDEX" },
    { SQL_FN_STR_SPACE, "SPACE" },
    { SQL_FN_STR_SUBSTRING, "SUBSTRING" },
    { SQL_FN_STR_UCASE, "UCASE" },
    { 0, 0 }
  };
  StringBuffer sb;
  int funcs = getIntInfo(SQL_STRING_FUNCTIONS);
  for (int i = 0; m[i].code != 0; ++i)
  {
    if (funcs & m[i].code)
    {
      if (sb.length() > 0)
        sb << ",";
      sb << m[i].name;
    }
  }
  return sb.toString();
}

RString 
ODBCDatabaseMetaData::getSystemFunctions() THROWS1(::acdk::sql::RSQLException)
{
  struct FuncMap
  {
    int code;
    const char* name;
  };
  FuncMap m[] = 
  {
    { SQL_FN_SYS_DBNAME, "DBNAME" },
    { SQL_FN_SYS_IFNULL, "IFNULL" },
    { SQL_FN_SYS_USERNAME, "USERNAME" },
    { 0, 0 }
  };
  StringBuffer sb;
  int funcs = getIntInfo(SQL_SYSTEM_FUNCTIONS);
  for (int i = 0; m[i].code != 0; ++i)
  {
    if (funcs & m[i].code)
    {
      if (sb.length() > 0)
        sb << ",";
      sb << m[i].name;
    }
  }
  return sb.toString();
}


RString 
ODBCDatabaseMetaData::getDateTimeFunctions() THROWS1(::acdk::sql::RSQLException)
{
  struct FuncMap
  {
    int code;
    const char* name;
  };
  FuncMap m[] = 
  {
    { SQL_FN_TD_CURRENT_DATE, "CURRENT_DATE" },
    { SQL_FN_TD_CURRENT_TIME, "CURRENT_TIME" },
    { SQL_FN_TD_CURRENT_TIMESTAMP, "CURRENT_TIMESTAMP" },
    { SQL_FN_TD_EXTRACT, "EXTRACT" },
    { SQL_FN_TD_CURDATE, "CURDATE" },
    { SQL_FN_TD_CURTIME, "CURTIME" },
    { SQL_FN_TD_DAYNAME, "DAYNAME" },
    { SQL_FN_TD_DAYOFMONTH, "DAYOFMONTH" }, 
    { SQL_FN_TD_DAYOFWEEK, "DAYOFWEEK" },
    { SQL_FN_TD_DAYOFYEAR, "DAYOFYEAR" },
    { SQL_FN_TD_HOUR, "HOUR" },
    { SQL_FN_TD_MINUTE, "MINUTE" },
    { SQL_FN_TD_MONTH, "MONTH" },
    { SQL_FN_TD_MONTHNAME, "MONTHNAME" },
    { SQL_FN_TD_NOW, "NOW" },
    { SQL_FN_TD_QUARTER, "QUARTER" },
    { SQL_FN_TD_SECOND, "SECOND" },
    { SQL_FN_TD_TIMESTAMPADD, "TIMESTAMPADD" },
    { SQL_FN_TD_TIMESTAMPDIFF, "TIMESTAMPDIFF" },
    { SQL_FN_TD_WEEK, "WEEK" },
    { SQL_FN_TD_YEAR, "YEAR" },
    { 0, 0 }
  };
  StringBuffer sb;
  int funcs = getIntInfo(SQL_TIMEDATE_FUNCTIONS);
  for (int i = 0; m[i].code != 0; ++i)
  {
    if (funcs & m[i].code)
    {
      if (sb.length() > 0)
        sb << ",";
      sb << m[i].name;
    }
  }
  return sb.toString();
}

bool 
ODBCDatabaseMetaData::supportsConvert(int fromType, int toType) THROWS1(::acdk::sql::RSQLException) 
{ 
  THROW0(UnsupportedOperationException); 
  struct TypeToTypeMap 
  {
    int sqlType;
    int odbcType;
  };
  TypeToTypeMap inputMap[] =
  {
    { BigIntSqlType, SQL_CONVERT_BIGINT },
    { BinarySqlType, SQL_CONVERT_BINARY },
    { BitSqlType, SQL_CONVERT_BIT },
    { CharSqlType, SQL_CONVERT_CHAR },
    { DateSqlType, SQL_CONVERT_DATE },
    { DecimalSqlType, SQL_CONVERT_DECIMAL },
    { DoubleSqlType, SQL_CONVERT_DOUBLE },
    { FloatSqlType, SQL_CONVERT_FLOAT },
    { IntegerSqlType, SQL_CONVERT_INTEGER },
    { LongVarBinarySqlType, SQL_CONVERT_LONGVARBINARY },
    { LongVarCharSqlType, SQL_CONVERT_LONGVARCHAR },
    { NumericSqlType, SQL_CONVERT_NUMERIC },
    { RealSqlType, SQL_CONVERT_REAL },
    { SmallIntSqlType, SQL_CONVERT_SMALLINT },
    { TimeSqlType, SQL_CONVERT_TIME },
    { TimeStampSqlType, SQL_CONVERT_TIMESTAMP },
    { TinyIntSqlType, SQL_CONVERT_TINYINT },
    { VarBinarySqlType, SQL_CONVERT_VARBINARY },
    { VarCharSqlType, SQL_CONVERT_VARCHAR },
    { 0, 0 }
  };
  TypeToTypeMap outputMap[] =
  {
    { BigIntSqlType, SQL_CVT_BIGINT },
    { BinarySqlType, SQL_CVT_BINARY },
    { BitSqlType, SQL_CVT_BIT },
    { CharSqlType, SQL_CVT_CHAR },
    { DateSqlType, SQL_CVT_DATE },
    { DecimalSqlType, SQL_CVT_DECIMAL },
    { DoubleSqlType, SQL_CVT_DOUBLE },
    { FloatSqlType, SQL_CVT_FLOAT },
    { IntegerSqlType, SQL_CVT_INTEGER },
    { LongVarBinarySqlType, SQL_CVT_LONGVARBINARY },
    { LongVarCharSqlType, SQL_CVT_LONGVARCHAR },
    { NumericSqlType, SQL_CVT_NUMERIC },
    { RealSqlType, SQL_CVT_REAL },
    { SmallIntSqlType, SQL_CVT_SMALLINT },
    { TimeSqlType, SQL_CVT_TIME },
    { TimeStampSqlType, SQL_CVT_TIMESTAMP },
    { TinyIntSqlType, SQL_CVT_TINYINT },
    { VarBinarySqlType, SQL_CVT_VARBINARY },
    { VarCharSqlType, SQL_CVT_VARCHAR },
    { 0, 0 }
  };
  for (int i=0; inputMap[i].sqlType != 0; ++i) 
  {
    if (inputMap[i].sqlType == fromType) 
    {
      for (int j = 0; outputMap[j].sqlType != 0; ++j) 
      {
	      if(outputMap[j].sqlType == toType) 
	        return getIntInfo(inputMap[i].odbcType) & outputMap[j].odbcType;
	    }
    }	
  }
  return false;
}


int 
ODBCDatabaseMetaData::getDefaultTransactionIsolation() THROWS1(::acdk::sql::RSQLException)
{
  int val = getIntInfo(SQL_DEFAULT_TXN_ISOLATION);
  switch(val)
  {
  case SQL_TXN_READ_UNCOMMITTED:
    return Connection::TRANSACTION_READ_UNCOMMITTED;
  case SQL_TXN_READ_COMMITTED:
    return Connection::TRANSACTION_READ_COMMITTED;
  case SQL_TXN_REPEATABLE_READ:
    return Connection::TRANSACTION_REPEATABLE_READ;
  case SQL_TXN_SERIALIZABLE:
    return Connection::TRANSACTION_SERIALIZABLE;
  default:
    return Connection::TRANSACTION_NONE;
  }
}

bool 
ODBCDatabaseMetaData::supportsTransactionIsolationLevel(int level) THROWS1(::acdk::sql::RSQLException)
{
  int val = getIntInfo(SQL_TXN_ISOLATION_OPTION);
  if (level ==  Connection::TRANSACTION_READ_UNCOMMITTED)
    return val & SQL_TXN_READ_UNCOMMITTED;
  else if (level == Connection::TRANSACTION_READ_COMMITTED)
    return val & SQL_TXN_READ_COMMITTED;
  else if (level == Connection::TRANSACTION_REPEATABLE_READ)
    return val & SQL_TXN_REPEATABLE_READ;
  /*
  else if (level == Connection::TRANSACTION_SERIALIZABLE)
    return (val &  SQL_TXN_SERIALIZABLE) || (val & SQL_TXN_VERSIONING);
    */
  return false;  
}
#if defined(ACDK_HAS_SQL_WCHAR)
#define STR2ODBCSTR(str) (str) == Nil ? (ODBC_NATIVE_CHAR*)0 : (ODBC_NATIVE_CHAR*)(str)->convertToNative()->native_c_str()

#else
/FONT>
#define STR2ODBCSTR(str) (str) == Nil ? (ODBC_NATIVE_CHAR*)0 : (ODBC_NATIVE_CHAR*)(str)->convert(CCAscii)->c_str()
#endif
/FONT>
#define STRLEN(str) (str) == Nil ? 0 : str->length()

::acdk::sql::RResultSet 
ODBCDatabaseMetaData::getTables(INP(RString) catalog, INP(RString) schemaPattern, INP(RString) namePattern) THROWS1(::acdk::sql::RSQLException)
{
  RString types = "";
  //RString types = Nil;
  //RODBCHandle h = _conn->_getODBCHandle();
  //SQLHANDLE sqlhandle = h->_getSQLHandle();
  // SQL_ALL_CATALOGS 
  // SQL_ALL_SCHEMAS 
  // SQL_ALL_TABLE_TYPES 
  RODBCStatement stm = (RODBCStatement)_conn->createStatement();
  RODBCHandle h = stm->_getODBCHandle();
  SQLHANDLE sqlhandle = h->_getSQLHandle();
  SQLRETURN  ret = SQLTables(sqlhandle, STR2ODBCSTR(catalog), STRLEN(catalog), STR2ODBCSTR(schemaPattern), STRLEN(schemaPattern),
                                        STR2ODBCSTR(namePattern), STRLEN(namePattern), STR2ODBCSTR(types), STRLEN(types));
  h->_chkSQLrcode(ret, "ODBCDatabaseMetaData::getTables", __FILE__, __LINE__);
  return new ODBCResultSet(stm, FETCH_FORWARD);
}

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