From: <ibr...@us...> - 2010-02-25 14:39:08
|
Revision: 3444 http://tora.svn.sourceforge.net/tora/?rev=3444&view=rev Author: ibre5041 Date: 2010-02-25 14:38:57 +0000 (Thu, 25 Feb 2010) Log Message: ----------- Option added USE_PCH (precompiled headers) Modified Paths: -------------- trunk/tora/CMakeLists.txt trunk/tora/src/CMakeLists.txt Added Paths: ----------- trunk/tora/cmake/modules/PCHSupport_26.cmake trunk/tora/src/tooracleconnection_trotl.cpp Modified: trunk/tora/CMakeLists.txt =================================================================== --- trunk/tora/CMakeLists.txt 2010-02-25 13:24:12 UTC (rev 3443) +++ trunk/tora/CMakeLists.txt 2010-02-25 14:38:57 UTC (rev 3444) @@ -9,6 +9,8 @@ OPTION(WANT_RPM "Enable additional RPM related stuff. Additional make package_rpm target" ON) OPTION(WANT_BUNDLE "Enable Mac OS X bundle build" OFF) OPTION(WANT_BUNDLE_STANDALONE "Do not copy required libs and tools into bundle (WANT_BUNDLE)" ON) +OPTION(USE_TROTL "Use trotl OCI wrapper library" OFF) +OPTION(USE_PCH "Use percompiled headers" OFF) #Set our CMake minimum version #Require 2.4.2 for Qt finding @@ -86,8 +88,8 @@ ############################################################################################################## ########## check for the CPU we build for ########## -IF (GCC) - +IF (CMAKE_COMPILER_IS_GNUCC) + EXECUTE_PROCESS( COMMAND ${CMAKE_C_COMPILER} -dumpmachine OUTPUT_VARIABLE MACHINE @@ -113,8 +115,13 @@ SET(ARCH_PPC 1) ENDIF (_machine_ppc) -ENDIF (GCC) +SET(CMAKE_CXX_FLAGS_RELEASE "-O2 ${CXX_WARNINGS}") +SET(CMAKE_C_FLAGS_RELEASE "-O2 ${CXX_WARNINGS}") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 ${CXX_WARNINGS} -ggdb3 -fno-inline -rdynamic") +SET(CMAKE_C_FLAGS_DEBUG "-O0 ${CXX_WARNINGS} -gbdb3 -fno-inline -rdynamic") +ENDIF (CMAKE_COMPILER_IS_GNUCC) + #Convert our simpler command line option to the CMake style #None, Debug, Release, .. or custom ones IF(WANT_DEBUG) @@ -136,8 +143,6 @@ ENDIF (MSVC) -SET(CMAKE_CXX_FLAGS_RELEASE "-O2 ${CXX_WARNINGS}") -SET(CMAKE_C_FLAGS_RELEASE "-O2 ${CXX_WARNINGS}") # Required for win wjen there is used an external qscintilla lib IF (WIN32 AND NOT DEFINED WANT_INTERNAL_QSCINTILLA) SET(CMAKE_CXX_FLAGS_RELEASE "/DQSCINTILLA_DLL ${CMAKE_CXX_FLAGS_RELEASE}") Added: trunk/tora/cmake/modules/PCHSupport_26.cmake =================================================================== --- trunk/tora/cmake/modules/PCHSupport_26.cmake (rev 0) +++ trunk/tora/cmake/modules/PCHSupport_26.cmake 2010-02-25 14:38:57 UTC (rev 3444) @@ -0,0 +1,331 @@ +# - Try to find precompiled headers support for GCC 3.4 and 4.x +# Once done this will define: +# +# Variable: +# PCHSupport_FOUND +# +# Macro: +# ADD_PRECOMPILED_HEADER _targetName _input _dowarn +# ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use _dowarn +# ADD_NATIVE_PRECOMPILED_HEADER _targetName _input _dowarn +# GET_NATIVE_PRECOMPILED_HEADER _targetName _input + +IF(CMAKE_COMPILER_IS_GNUCXX) + + EXEC_PROGRAM( + ${CMAKE_CXX_COMPILER} + ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion + OUTPUT_VARIABLE gcc_compiler_version) + #MESSAGE("GCC Version: ${gcc_compiler_version}") + IF(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]") + SET(PCHSupport_FOUND TRUE) + ELSE(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]") + IF(gcc_compiler_version MATCHES "3\\.4\\.[0-9]") + SET(PCHSupport_FOUND TRUE) + ENDIF(gcc_compiler_version MATCHES "3\\.4\\.[0-9]") + ENDIF(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]") + + SET(_PCH_include_prefix "-I") + +ELSE(CMAKE_COMPILER_IS_GNUCXX) + IF(WIN32) + SET(PCHSupport_FOUND TRUE) # for experimental msvc support + SET(_PCH_include_prefix "/I") + ELSE(WIN32) + SET(PCHSupport_FOUND FALSE) + ENDIF(WIN32) +ENDIF(CMAKE_COMPILER_IS_GNUCXX) + + +MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags) + + + STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name) + SET(${_out_compile_flags} ${${_flags_var_name}} ) + + IF(CMAKE_COMPILER_IS_GNUCXX) + + GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) + IF(${_targetType} STREQUAL SHARED_LIBRARY) + LIST(APPEND ${_out_compile_flags} "${${_out_compile_flags}} -fPIC") + ENDIF(${_targetType} STREQUAL SHARED_LIBRARY) + + ELSE(CMAKE_COMPILER_IS_GNUCXX) + ## TODO ... ? or does it work out of the box + ENDIF(CMAKE_COMPILER_IS_GNUCXX) + + GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES ) + FOREACH(item ${DIRINC}) + LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}${item}") + ENDFOREACH(item) + + SET(_build_type "${CMAKE_BUILD_TYPE}") + # MESSAGE(STATUS "build type: `${CMAKE_BUILD_TYPE}'") + IF (NOT _build_type) + SET(_build_type "Debug") + ENDIF (NOT _build_type) + string(TOUPPER ${_build_type} _build_type) + SET(_def_name "COMPILE_DEFINITIONS_${_build_type}") + GET_DIRECTORY_PROPERTY(_directory_flags ${_def_name}) + FOREACH(item ${_directory_flags}) + LIST(APPEND ${_out_compile_flags} "-D${item}") + ENDFOREACH(item) + # MESSAGE("_directory_flags ${_directory_flags}" ) + GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS) + #MESSAGE("_directory_flags ${_directory_flags}" ) + LIST(APPEND ${_out_compile_flags} ${_directory_flags}) + LIST(APPEND ${_out_compile_flags} ${CMAKE_CXX_FLAGS} ) + + SEPARATE_ARGUMENTS(${_out_compile_flags}) + +ENDMACRO(_PCH_GET_COMPILE_FLAGS) + + +MACRO(_PCH_WRITE_PCHDEP_CXX _targetName _include_file _dephelp) + + SET(${_dephelp} ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch_dephelp.cxx) + FILE(WRITE ${${_dephelp}} +"#include \"${_include_file}\" +int testfunction() +{ + return 0; +} +" + ) + +ENDMACRO(_PCH_WRITE_PCHDEP_CXX ) + +MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _output) + + FILE(TO_NATIVE_PATH ${_input} _native_input) + FILE(TO_NATIVE_PATH ${_output} _native_output) + + + IF(CMAKE_COMPILER_IS_GNUCXX) + IF(CMAKE_CXX_COMPILER_ARG1) + # remove leading space in compiler argument + STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1}) + + SET(${out_command} + ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input} + ) + ELSE(CMAKE_CXX_COMPILER_ARG1) + SET(${out_command} + ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input} + ) + ENDIF(CMAKE_CXX_COMPILER_ARG1) + ELSE(CMAKE_COMPILER_IS_GNUCXX) + + SET(_dummy_str "#include <${_input}>") + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pch_dummy.cpp ${_dummy_str}) + + SET(${out_command} + ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} /c /Fp${_native_output} /Yc${_native_input} pch_dummy.cpp + ) + #/out:${_output} + + ENDIF(CMAKE_COMPILER_IS_GNUCXX) + +ENDMACRO(_PCH_GET_COMPILE_COMMAND ) + + + +MACRO(_PCH_GET_TARGET_COMPILE_FLAGS _cflags _header_name _pch_path _dowarn ) + + FILE(TO_NATIVE_PATH ${_pch_path} _native_pch_path) + + IF(CMAKE_COMPILER_IS_GNUCXX) + # for use with distcc and gcc >4.0.1 if preprocessed files are accessible + # on all remote machines set + # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess + # if you want warnings for invalid header files (which is very inconvenient + # if you have different versions of the headers for different build types + # you may set _pch_dowarn + IF (_dowarn) + SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include ${CMAKE_CURRENT_BINARY_DIR}/${_header_name} -Winvalid-pch " ) + ELSE (_dowarn) + SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include ${CMAKE_CURRENT_BINARY_DIR}/${_header_name} " ) + ENDIF (_dowarn) + ELSE(CMAKE_COMPILER_IS_GNUCXX) + + set(${_cflags} "/Fp\"${_native_pch_path}\" /Yu\"${_header_name}\" /FI\"${_header_name}\" " ) + + ENDIF(CMAKE_COMPILER_IS_GNUCXX) + +ENDMACRO(_PCH_GET_TARGET_COMPILE_FLAGS ) + +MACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input _output) + GET_FILENAME_COMPONENT(_name ${_input} NAME) + GET_FILENAME_COMPONENT(_path ${_input} PATH) + SET(_output "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch/${_targetName}_${CMAKE_BUILD_TYPE}.h++") +ENDMACRO(GET_PRECOMPILED_HEADER_OUTPUT _targetName _input) + + +MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use ) + + # to do: test whether compiler flags match between target _targetName + # and _pch_output_to_use + GET_FILENAME_COMPONENT(_name ${_input} NAME) + + IF( "${ARGN}" STREQUAL "0") + SET(_dowarn 0) + ELSE( "${ARGN}" STREQUAL "0") + SET(_dowarn 1) + ENDIF("${ARGN}" STREQUAL "0") + + + _PCH_GET_TARGET_COMPILE_FLAGS(_target_cflags ${_name} ${_pch_output_to_use} ${_dowarn}) + # MESSAGE("Add flags ${_target_cflags} to ${_targetName} " ) + SET_TARGET_PROPERTIES(${_targetName} + PROPERTIES + COMPILE_FLAGS ${_target_cflags} + ) + + ADD_CUSTOM_TARGET(pch_Generate_${_targetName} + DEPENDS ${_pch_output_to_use} + ) + + ADD_DEPENDENCIES(${_targetName} pch_Generate_${_targetName} ) + +ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET) + +MACRO(ADD_PRECOMPILED_HEADER _targetName _input) + + SET(_PCH_current_target ${_targetName}) + + IF(NOT CMAKE_BUILD_TYPE) + MESSAGE(FATAL_ERROR + "This is the ADD_PRECOMPILED_HEADER macro. " + "You must set CMAKE_BUILD_TYPE!" + ) + ENDIF(NOT CMAKE_BUILD_TYPE) + + IF( "${ARGN}" STREQUAL "0") + SET(_dowarn 0) + ELSE( "${ARGN}" STREQUAL "0") + SET(_dowarn 1) + ENDIF("${ARGN}" STREQUAL "0") + + + GET_FILENAME_COMPONENT(_name ${_input} NAME) + GET_FILENAME_COMPONENT(_path ${_input} PATH) + GET_PRECOMPILED_HEADER_OUTPUT( ${_targetName} ${_input} _output) + + GET_FILENAME_COMPONENT(_outdir ${_output} PATH ) + + GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE) + _PCH_WRITE_PCHDEP_CXX(${_targetName} ${_input} _pch_dephelp_cxx) + + IF(${_targetType} STREQUAL SHARED_LIBRARY) + ADD_LIBRARY(${_targetName}_pch_dephelp SHARED ${_pch_dephelp_cxx} ) + ELSE(${_targetType} STREQUAL SHARED_LIBRARY) + ADD_LIBRARY(${_targetName}_pch_dephelp STATIC ${_pch_dephelp_cxx}) + ENDIF(${_targetType} STREQUAL SHARED_LIBRARY) + + FILE(MAKE_DIRECTORY ${_outdir}) + + + _PCH_GET_COMPILE_FLAGS(_compile_FLAGS) + + #MESSAGE("_compile_FLAGS: ${_compile_FLAGS}") + #message("COMMAND ${CMAKE_CXX_COMPILER} ${_compile_FLAGS} -x c++-header -o ${_output} ${_input}") + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${_name} PROPERTIES GENERATED 1) + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_name} + COMMAND ${CMAKE_COMMAND} -E copy ${_input} ${CMAKE_CURRENT_BINARY_DIR}/${_name} # ensure same directory! Required by gcc + DEPENDS ${_input} + ) + + #message("_command ${_input} ${_output}") + _PCH_GET_COMPILE_COMMAND(_command ${CMAKE_CURRENT_BINARY_DIR}/${_name} ${_output} ) + + #message(${_input} ) + #message("_output ${_output}") + + ADD_CUSTOM_COMMAND( + OUTPUT ${_output} + COMMAND ${_command} + DEPENDS ${_input} ${CMAKE_CURRENT_BINARY_DIR}/${_name} ${_targetName}_pch_dephelp + ) + + + ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_input} ${_output} ${_dowarn}) +ENDMACRO(ADD_PRECOMPILED_HEADER) + + +# Generates the use of precompiled in a target, +# without using depency targets (2 extra for each target) +# Using Visual, must also add ${_targetName}_pch to sources +# Not needed by Xcode + +MACRO(GET_NATIVE_PRECOMPILED_HEADER _targetName _input) + + if(CMAKE_GENERATOR MATCHES Visual*) + + SET(_dummy_str "#include \"${_input}\"\n" + "// This is required to suppress LNK4221. Very annoying.\n" + "void *g_${_targetName}Dummy = 0\;\n") + + # Use of cxx extension for generated files (as Qt does) + SET(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cxx) + if(EXISTS ${${_targetName}_pch}) + # Check if contents is the same, if not rewrite + # todo + else(EXISTS ${${_targetName}_pch}) + FILE(WRITE ${${_targetName}_pch} ${_dummy_str}) + endif(EXISTS ${${_targetName}_pch}) + endif(CMAKE_GENERATOR MATCHES Visual*) + +ENDMACRO(GET_NATIVE_PRECOMPILED_HEADER) + + +MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input) + + IF( "${ARGN}" STREQUAL "0") + SET(_dowarn 0) + ELSE( "${ARGN}" STREQUAL "0") + SET(_dowarn 1) + ENDIF("${ARGN}" STREQUAL "0") + + if(CMAKE_GENERATOR MATCHES Visual*) + # Auto include the precompile (useful for moc processing, since the use of + # precompiled is specified at the target level + # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt) + + GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) + if (${oldProps} MATCHES NOTFOUND) + SET(oldProps "") + endif(${oldProps} MATCHES NOTFOUND) + + SET(newProperties "${oldProps} /Yu\"${_input}\" /FI\"${_input}\"") + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}") + + #also inlude ${oldProps} to have the same compile options + SET_SOURCE_FILES_PROPERTIES(${${_targetName}_pch} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_input}\"") + + else(CMAKE_GENERATOR MATCHES Visual*) + + if (CMAKE_GENERATOR MATCHES Xcode) + # For Xcode, cmake needs my patch to process + # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties + + GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) + if (${oldProps} MATCHES NOTFOUND) + SET(oldProps "") + endif(${oldProps} MATCHES NOTFOUND) + + # When buiding out of the tree, precompiled may not be located + # Use full path instead. + GET_FILENAME_COMPONENT(fullPath ${_input} ABSOLUTE) + + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}") + SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") + + else (CMAKE_GENERATOR MATCHES Xcode) + + #Fallback to the "old" precompiled suppport + #ADD_PRECOMPILED_HEADER(${_targetName} ${_input} ${_dowarn}) + endif(CMAKE_GENERATOR MATCHES Xcode) + endif(CMAKE_GENERATOR MATCHES Visual*) + +ENDMACRO(ADD_NATIVE_PRECOMPILED_HEADER) Modified: trunk/tora/src/CMakeLists.txt =================================================================== --- trunk/tora/src/CMakeLists.txt 2010-02-25 13:24:12 UTC (rev 3443) +++ trunk/tora/src/CMakeLists.txt 2010-02-25 14:38:57 UTC (rev 3444) @@ -1,4 +1,5 @@ INCLUDE(ToraCompat) +INCLUDE(PCHSupport_26) #Subdirectories # ADD_SUBDIRECTORY(i18n) @@ -319,7 +320,7 @@ tonewconnection.cpp tonoblockquery.cpp #win only? toocistub.cpp - tooracleconnection.cpp +# tooracleconnection.cpp tooracleextract.cpp tooraclepreload.cpp tooutput.cpp @@ -414,6 +415,13 @@ docklets/toviewdirectory.cpp tooracletable.cpp ) + +IF(USE_TROTL) + LIST(APPEND TORA_SOURCES tooracleconnection_trotl.cpp) +ELSE(USE_TROTL) + LIST(APPEND TORA_SOURCES tooracleconnection.cpp) +ENDIF(USE_TROTL) + # compiled in icons for windows IF (WIN32 AND MSVC) SET (TORA_SOURCES ${TORA_SOURCES} tora.rc) Added: trunk/tora/src/tooracleconnection_trotl.cpp =================================================================== --- trunk/tora/src/tooracleconnection_trotl.cpp (rev 0) +++ trunk/tora/src/tooracleconnection_trotl.cpp 2010-02-25 14:38:57 UTC (rev 3444) @@ -0,0 +1,1621 @@ + +/* BEGIN_COMMON_COPYRIGHT_HEADER + * + * TOra - An Oracle Toolkit for DBA's and developers + * + * Shared/mixed copyright is held throughout files in this product + * + * Portions Copyright (C) 2000-2001 Underscore AB + * Portions Copyright (C) 2003-2005 Quest Software, Inc. + * Portions Copyright (C) 2004-2008 Numerous Other Contributors + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; only version 2 of + * the License is valid for this program. + * + * This program 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * As a special exception, you have permission to link this program + * with the Oracle Client libraries and distribute executables, as long + * as you follow the requirements of the GNU GPL in regard to all of the + * software in the executable aside from Oracle client libraries. + * + * Specifically you are not permitted to link this program with the + * Qt/UNIX, Qt/Windows or Qt Non Commercial products of TrollTech. + * And you are not permitted to distribute binaries compiled against + * these libraries. + * + * You may link this product with any GPL'd Qt library. + * + * All trademarks belong to their respective owners. + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef TO_NO_ORACLE + +#include "utils.h" +#include "tologger.h" +#include <iomanip> + +#ifdef Q_OS_WIN32 +# include "windows/cregistry.h" +#include <Windows.h> +#endif + +#include <trotl.h> + +#include "toconf.h" +#include "toconnection.h" +#include "tomain.h" +#include "tosql.h" +#include "totool.h" +#include "tooraclesetting.h" +#include "todefaultkeywords.h" + +#include <stdio.h> +#include <iostream> + +#include <qcheckbox.h> +#include <qfile.h> +#include <qinputdialog.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qregexp.h> +#include <qspinbox.h> +#include <qvalidator.h> + +#include <QString> +#include <QTextStream> + +static toSQL SQLComment("toOracleConnection:Comments", + "SELECT Column_name,Comments FROM sys.All_Col_Comments\n" + " WHERE Owner = :f1<char[100]>\n" + " AND Table_Name = :f2<char[100]>", + "Display column comments"); + +static toSQL SQLMembers("toOracleConnection:Members", + "SELECT object_name,overload,argument_name,data_type\n" + " FROM sys.All_Arguments\n" + " WHERE Owner = :f1<char[100]>\n" + " AND Package_Name = :f2<char[100]>\n" + " ORDER BY object_name,overload,DECODE(argument_name,NULL,9999,sequence)", + "Get list of package members"); + +static toSQL SQLListObjects("toOracleConnection:ListObjects", + "select a.owner,a.object_name,a.object_type,b.comments\n" + " from sys.all_objects a,\n" + " sys.all_tab_comments b\n" + " where a.owner = b.owner(+) and a.object_name = b.table_name(+)\n" + " and a.object_type = b.table_type(+) and a.object_type <> 'SYNONYM'", + "List the objects to cache for a connection, should have same " + "columns and binds"); + +static toSQL SQLListSynonyms("toOracleConnection:ListSynonyms", + "select synonym_name,table_owner,table_name\n" + " from sys.all_synonyms\n" + " where owner = :usr<char[101]> or owner = 'PUBLIC'\n" + " order by table_owner,table_name", + "List the synonyms available to a user, should have same columns and binds"); + +static void ThrowException(const ::trotl::OciException &exc) +{ + get_log(0).ts<toDecorator>( __HERE__) + << "What:" << exc.what() << std::endl + << exc.get_sql() << std::endl + << "--------------------------------------------------------------------------------" + << std::endl; + if (exc.get_code() == 24344) + throw toConnection::exception(QString::fromLatin1("ORA-24344 success with compilation error")); + else + { + toConnection::exception ret(QString::fromUtf8(exc.get_mesg())); + /*** + if (ret.isEmpty()) + { + if (exc.code != 0) + { + ret = QString::fromLatin1("ORA-") + + QString::number(exc.code) + + QString::fromLatin1(" missing error description"); + } + else if (ret.isEmpty()) + { + ret = QString::fromLatin1( + "Missing error description. This may be caused by a library " + "version mismatch. Check that your ORACLE_HOME and library path is correct."); + } + } + */ + /*** + if (exc.stm_text && strlen(exc.stm_text)) + { + ret += QString::fromLatin1("\n"); + QString sql = QString::fromUtf8((const char *)exc.stm_text); + if (exc.code >= 0) + { + QString t = QString::fromUtf8((const char *)exc.stm_text, exc.error_offset); + ret.setOffset(t.length()); + sql.insert(t.length(), QString::fromLatin1("<ERROR>")); + } + ret += sql; + } + */ + throw ret; + } +} + +class toOracleProvider : public toConnectionProvider +{ + ::trotl::OciEnv *_envp; +public: + class oracleSub : public toConnectionSub + { + public: + + ::trotl::OciConnection *_conn; + ::trotl::OciLogin *_login; + + oracleSub(::trotl::OciConnection *conn, ::trotl::OciLogin *login): + _conn(conn), _login(login) + {} + + ~oracleSub() + { + try { + delete _conn; + delete _login; + } + catch(...) + { + get_log(1).ts<toDecorator>( __HERE__) << " Ignored exception." << std::endl; + } + _conn = 0; + _login = 0; + } + + virtual void cancel(void) + { + _conn->cancel(); + } + + virtual void throwExtendedException(toConnection &conn, const ::trotl::OciException &exc) + { + get_log(0).ts<toDecorator>( __HERE__) + << "What:" << exc.what() << std::endl + << exc.get_sql() << std::endl + << "--------------------------------------------------------------------------------" + << std::endl; + if (conn.version() < "0800" && exc.get_code() == 0) + { + // Serious OCI voodoo to get the Parse error location on Oracle7 servers + // TODO + /* + Lda_Def lda; + Cda_Def cda; + if (OCISvcCtxToLda(Connection->connect_struct.svchp, + Connection->connect_struct.errhp, + &lda) == OCI_SUCCESS) + { + if (oopen(&cda, + &lda, + (OraText *)0, -1, + -1, + (OraText *)0, -1) == OCI_SUCCESS) + { + cda.peo = 0; + oparse(&cda, (OraText *)exc.stm_text, -1, FALSE, 1); + ((::trotl::OciException &)exc).code = cda.peo; + oclose(&cda); + } + OCILdaToSvcCtx(&Connection->connect_struct.svchp, + Connection->connect_struct.errhp, + &lda); + } + */ + } + ThrowException(exc); + } + }; + + class oracleQuery : public toQuery::queryImpl + { + bool Cancel; + bool Running; + bool SaveInPool; + + public: + class trotlQuery : public ::trotl::SqlStatement + { + public: + typedef ::trotl::SqlStatement super; + trotlQuery(::trotl::OciConnection &conn, + const ::trotl::tstring &stmt, // TODO QString here + ub4 lang=OCI_NTV_SYNTAX, + int bulk_rows=::trotl::g_OCIPL_BULK_ROWS) + : ::trotl::SqlStatement(conn, stmt, lang, bulk_rows) + {}; + void readValue(toQValue &value) + { + super::BindPar const &BP(get_stmt_type() == STMT_SELECT ? + get_next_column() : + get_next_out_bindpar()); + + if((_state & EXECUTED) == 0) + execute_internal(::trotl::g_OCIPL_BULK_ROWS, OCI_DEFAULT); + + if(BP.is_null(_last_buff_row)) { + value = toQValue(); + get_log(0).ts<toDecorator>( __HERE__) << "Just read: NULL" << std::endl; + } else { + switch(BP.dty) { + case SQLT_NUM: + case SQLT_VNU: { + OCINumber* vnu = (OCINumber*) &((char*)BP.valuep)[_last_buff_row * BP.value_sz ]; + sword res; + boolean isint; + res = OCINumberIsInt(_errh, vnu, &isint); + oci_check_error(__HERE__, _errh, res); + if(isint) + { + long long i; + res = OCINumberToInt(_errh, + vnu, + sizeof(long long), + OCI_NUMBER_SIGNED, + &i); + oci_check_error(__HERE__, _errh, res); + value = toQValue(i); + get_log(0).ts<toDecorator>( __HERE__) << "Just read: " << i << std::endl; + } else { + double d; + sword res = OCINumberToReal(_errh, + vnu, + sizeof(double), + &d); + oci_check_error(__HERE__, _errh, res); + value = toQValue(d); + get_log(0).ts<toDecorator>( __HERE__) << "Just read: " << d << std::endl; + } + } + break; +#ifdef ORACLE_HAS_XML + case SQLT_NTY: { // NOTE: Only one SQLT_NTY is supported - SYS.XMLTYPE + ::trotl::BindParXML const *bpx = dynamic_cast<const trotl::BindParXML *>(&BP); + assert(bpx); + if((xmlnode*)bpx->_xmlvaluep[_last_buff_row] == NULL) + { + value = toQValue(); + get_log(0).ts<toDecorator>( __HERE__) << "Just read: NULL XML" << std::endl; + } else { + std::string s(BP.get_string(_last_buff_row)); + value = toQValue(QString(s.c_str())); + get_log(0).ts<toDecorator>( __HERE__) << "Just read: \"" << s << "\"" << std::endl; + } + } + break; +#endif + case SQLT_CLOB: { + value = toQValue(QString("<CLOB>")); + } + break; + case SQLT_BLOB: { + value = toQValue(QString("<BLOB>")); + } + break; + default: + std::string s(BP.get_string(_last_buff_row)); + value = toQValue(QString(s.c_str())); + get_log(0).ts<toDecorator>( __HERE__) << "Just read: \"" << s << "\"" << std::endl; + } + } + + if(_out_pos == _column_count && BP._bind_type == BP.DEFINE_SELECT) + ++_last_buff_row; + + if(_last_buff_row == fetched_rows() && ((_state & EOF_DATA) == 0) && get_stmt_type() == STMT_SELECT) + fetch(_buff_size); + } + }; + trotlQuery * Query; + + oracleQuery(toQuery *query, oracleSub *) + : toQuery::queryImpl(query) + { + get_log(0).ts<toDecorator>( __HERE__) << std::endl; + Running = Cancel = false; + SaveInPool = false; + Query = NULL; + } + virtual ~oracleQuery() + { + if (!Query) + return; + + Query->close(); + delete Query; + } + + virtual void execute(void); + + virtual toQValue readValue(void) + { + toQValue retval; + Query->readValue(retval); + return retval; + +// const oracleQuery::trotlQuery::BindPar& bp( +// Query->_stmt_type == OCI_STMT_SELECT ? +// Query->get_curr_column() : Query->get_curr_out_bindpar()); +// try { +// switch(bp.dty) { +// case SQLT_NUM: +// case SQLT_VNU: +// { +// int i; +// (*Query) >> i; +// get_log(0).ts<toDecorator>( __HERE__) << +// "d:\t" << bp.dty << +// "\ti:\t'" << i << '\'' << std::endl; +// return toQValue(i); +// } +// default: +// { +// std::string val; +// (*Query) >> val; +// get_log(0).ts<toDecorator>( __HERE__) << +// "d:\t" << bp.dty << +// "\ts:\t'" << val << '\'' << std::endl; +// return toQValue(val.c_str()); +// } +// } +// } catch (::trotl::OciException e) { +// get_log(0).ts<toDecorator>( __HERE__) << +// e.what() << std::endl; +// return QString(); +// } catch (...) { +// get_log(0).ts<toDecorator>( __HERE__) << +// "Unknown exception" << std::endl; +// return QString(); +// } + + + /* + char *buffer = NULL; + otl_var_desc *dsc = Query->describe_next_out_var(); + if (!dsc) + throw QString::fromLatin1("Couldn't get description of next column to read"); + + oracleSub *conn = dynamic_cast<oracleSub *>(query()->connectionSub()); + if (!conn) + throw QString::fromLatin1("Internal error, not oracle sub connection"); + if (Cancel) + throw QString::fromLatin1("Cancelled while waiting to read value"); + Running = true; + SaveInPool = true; + try + { + toQValue null; + switch (dsc->ftype) + { + case otl_var_double: + case otl_var_float: + { + double d = 0; + (*Query) >> d; + Running = false; + if (Query->is_null()) + return null; + return toQValue(d); + } + break; + case otl_var_int: + case otl_var_unsigned_int: + case otl_var_short: + case otl_var_long_int: + { + int i = 0; + (*Query) >> i; + Running = false; + if (Query->is_null()) + return null; + return toQValue(i); + } + break; + case otl_var_varchar_long: + case otl_var_raw: + case otl_var_raw_long: + { + int len = toMaxLong; + if (toMaxLong < 0) + len = DEFAULT_MAX_LONG; + buffer = (char *)malloc(len + 1); + buffer[len] = 0; + otl_long_string str(buffer, len); + (*Query) >> str; + Running = false; + + if (!str.len()) { + free(buffer); + return null; + } + + QString buf; + if (dsc->ftype == otl_var_varchar_long) + { + buf = (QString::fromUtf8(buffer)); + free(buffer); + return buf; + } + else + { + QByteArray ret(buffer, str.len()); + free(buffer); + return toQValue::createBinary(ret); + } + } + case otl_var_clob: + case otl_var_blob: + { + otl_lob_stream lob; + (*Query) >> lob; + if (lob.len() == 0) + { + Running = false; + return null; + } + int len = lob.len(); + if (toMaxLong >= 0 && len > toMaxLong) + len = toMaxLong; + if (dsc->ftype == otl_var_clob) + len *= 5; + else + len *= 2; + buffer = (char *)malloc(len + 1); + buffer[0] = 0; + otl_long_string data(buffer, len); + lob >> data; + if (!lob.eof()) + { + otl_long_string sink(10000); + do + { + lob >> sink; + } + while (!lob.eof() && sink.len() > 0); + + toStatusMessage(QString::fromLatin1("Data exists past length of LOB")); + } + buffer[data.len()] = 0; + Running = false; + + if (dsc->ftype == otl_var_clob) + { + QString buf = QString::fromUtf8(buffer); + free(buffer); + return buf; + } + else + { + QByteArray ret(buffer, data.len()); + free(buffer); + return toQValue::createBinary(ret); + } + } + break; + default: // Try using char if all else fails + { + // The *5 is for raw columns or UTF expanded data, also dates and numbers + // are a bit tricky but if someone specifies a dateformat longer than 100 bytes he + // deserves everything he gets! + buffer = new char[std::max(dsc->elem_size * 5 + 1, 100)]; + buffer[0] = 0; + (*Query) >> buffer; + QString buf = QString::fromUtf8(buffer); + delete[] buffer; + + Running = false; + + if (Query->is_null()) + return null; + return buf; + } + break; + } + } + catch (const ::trotl::OciException &exc) + { + Running = false; + delete[] buffer; + if(conn && query()) + conn->throwExtendedException(query()->connection(), exc); + } + catch (...) + { + Running = false; + delete[] buffer; + throw; + } + */ + // Never get here + return QString(); //qt4 ::null; + } + + virtual void cancel(void); + + virtual bool eof(void) + { + if (!Query || Cancel) { + get_log(0).ts<toDecorator>( __HERE__) << "eof - (1) true" << std::endl; + return true; + } + try { + bool e = Query->eof(); + get_log(0).ts<toDecorator>( __HERE__) << "eof - (2) " << Query->row_count() << '\t' << e << std::endl; + return e; //Query->eof(); + } + catch (const ::trotl::OciException &exc) + { + get_log(0).ts<toDecorator>( __HERE__) << "eof - (e) true" << std::endl; + if(query()) + { + oracleSub *conn = dynamic_cast<oracleSub *>(query()->connectionSub()); + if(conn) + conn->throwExtendedException(query()->connection(), exc); + } + return true; + } + } + + virtual int rowsProcessed(void) + { + get_log(0).ts<toDecorator>( __HERE__) << "TODO: rowsProcessed A:" << std::endl; + + if (!Query) + return 0; + //return Query->get_last_row(); ???? + unsigned i = Query->get_last_row(); + get_log(0).ts<toDecorator>( __HERE__) << "TODO: rowsProcessed B: " << i << std::endl; + return i; + } + + virtual int columns(void) + { + //int descriptionLen; + //Query->describe_select(descriptionLen); + get_log(0).ts<toDecorator>( __HERE__) << "TODO: columns:" << Query->get_column_count() << std::endl; + return Query->get_column_count(); + } + + virtual std::list<toQuery::queryDescribe> describe(void) + { + get_log(0).ts<toDecorator>( __HERE__) << std::endl; + std::list<toQuery::queryDescribe> ret; + + int datatypearg1 = 0; + int datatypearg2 = 0; + get_log(0).ts<toDecorator>( __HERE__) << "TODO describe:" << std::endl; + + // TODO trotl should return const iterator + + const std::vector<trotl::ColumnType> &col = Query->get_columns(); + if(col.empty()) return ret; + std::vector<trotl::ColumnType>::const_iterator it = col.begin(); ++it; // starts with 1st + //get_log(0).ts<toDecorator>( __HERE__) << "Columns: " << q1.get_column_count() << std::endl; + for(; it != col.end(); ++it) + { + get_log(0).ts<toDecorator>( __HERE__) << "Var: " << (*it).get_type_str(true) << std::endl; + toQuery::queryDescribe desc; + desc.AlignRight = false; + desc.Name = QString::fromUtf8( (*it)._column_name.c_str() ); + desc.Datatype = QString::fromLatin1( (*it).get_type_str(true).c_str() ); + + //datatypearg1 = description[i].char_size; + desc.Datatype.sprintf(desc.Datatype.toUtf8().constData(), datatypearg1, datatypearg2); + //desc.Null = description[i].nullok; + + ret.insert(ret.end(), desc); + } + + return ret; + } + }; // class oracleQuery : public toQuery::queryImpl + + class oracleConnection : public toConnection::connectionImpl + { + ::trotl::OciEnv &_env; + QString connectString(void); + + oracleSub *oracleConv(toConnectionSub *sub) + { + oracleSub *conn = dynamic_cast<oracleSub *>(sub); + if (!conn) + throw QString::fromLatin1("Internal error, not oracle sub connection"); + return conn; + } + public: + oracleConnection(toConnection *conn, ::trotl::OciEnv &env) : + toConnection::connectionImpl(conn), _env(env) + { } + + /** Return a string representation to address an object. + * Checks if identifier has illegal characters, starts with digit, is a reserved + * word etc. - if so - returns it enclosed with quotes (otherwise returns the same string). + * Note that when identifier name returned from oracle data dictionary is in lowercase + * - it MUST be enclosed with quotes (case insensitive "normal" identifiers are always + * returned in uppercase). + * @param name The name to be quoted. + * @param quoteLowercase Enclose in quotes when identifier has lowercase letters. + * When processing data returned by dada dictionary quoteLowercase should be true + * When processing data entered by user quoteLowercase should be false + * @return String addressing table. + */ + virtual QString quote(const QString &name, const bool quoteLowercase) + { + bool ok = true; + // Identifiers starting with digit should be quoted + if (name.at(0).isDigit()) + ok = false; + else + for (int i = 0; i < name.length(); i++) + { + if ((name.at(i).toUpper() != name.at(i) && quoteLowercase) || !toIsIdent(name.at(i))) + ok = false; + } + + // Check if given identified is a reserved word + int i = 0; + while (ok && (DefaultKeywords[i] != NULL)) + { + if (name.compare(DefaultKeywords[i], Qt::CaseInsensitive) == 0) + ok = false; + i++; + } + if (ok) + return name.toUpper(); + else + return QString::fromLatin1("\"") + name + QString::fromLatin1("\""); + } + virtual QString unQuote(const QString &str) + { + if (str.at(0).toLatin1() == '\"' && str.at(str.length() - 1).toLatin1() == '\"') + return str.left(str.length() - 1).right(str.length() - 2); + return str.toUpper(); + } + + virtual std::list<toConnection::objectName> objectNames(void) + { + std::list<toConnection::objectName> ret; + + std::list<toQValue> par; + toQuery objects(connection(), toQuery::Long, + SQLListObjects, par); + toConnection::objectName cur; + while (!objects.eof()) + { + cur.Owner = objects.readValueNull(); + cur.Name = objects.readValueNull(); + cur.Type = objects.readValueNull(); + cur.Comment = objects.readValueNull(); + ret.insert(ret.end(), cur); + } + get_log(0).ts<toDecorator>( __HERE__) + << "++++ objectNames +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + << std::endl; + + return ret; + } + virtual std::map<QString, toConnection::objectName> synonymMap(std::list<toConnection::objectName> &objects) + { + std::map<QString, toConnection::objectName> ret; + + toConnection::objectName cur; + cur.Type = QString::fromLatin1("A"); + std::list<toQValue> par; + par.insert(par.end(), toQValue(connection().user().toUpper())); + toQuery synonyms(connection(), toQuery::Long, + SQLListSynonyms, par); + std::list<toConnection::objectName>::iterator i = objects.begin(); + while (!synonyms.eof()) + { + QString synonym = synonyms.readValueNull(); + cur.Owner = synonyms.readValueNull(); + cur.Name = synonyms.readValueNull(); + while (i != objects.end() && (*i) < cur) + i++; + if (i == objects.end()) + break; + if (cur.Name == (*i).Name && cur.Owner == (*i).Owner) + { + ret[synonym] = (*i); + (*i).Synonyms.insert((*i).Synonyms.end(), synonym); + } + } + get_log(0).ts<toDecorator>( __HERE__) + << "++++ synonymMap ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + << std::endl; + + return ret; + } + virtual toQDescList columnDesc(const toConnection::objectName &table) + { + toBusy busy; + if (table.Type == QString::fromLatin1("PACKAGE")) + { + toQDescList ret; + try + { + toQuery::queryDescribe desc; + desc.Datatype = ("MEMBER"); + desc.Null = false; + QString lastName; + QString lastOver; + toQuery member(connection(), SQLMembers, table.Owner, table.Name); + bool hasArgs = false; + while (!member.eof()) + { + QString name = member.readValue(); + QString overld = member.readValue(); + QString arg = member.readValueNull(); + QString type = member.readValueNull(); + if (lastName != name || overld != lastOver) + { + if (hasArgs) + desc.Name += ")"; + if (!desc.Name.isEmpty()) + ret.insert(ret.end(), desc); + desc.Name = name; + lastName = name; + lastOver = overld; + hasArgs = false; + } + if (arg.isEmpty()) + { + if (hasArgs) + { + desc.Name += ")"; + hasArgs = false; + } + desc.Name += " RETURNING "; + } + else + { + if (hasArgs) + desc.Name += ", "; + else + { + desc.Name += "("; + hasArgs = true; + } + desc.Name += arg; + desc.Name += " "; + } + desc.Name += type; + } + if (desc.Name.contains("(")) + desc.Name += ")"; + if (!desc.Name.isEmpty()) + ret.insert(ret.end(), desc); + } + catch (...) + { + get_log(1).ts<toDecorator>( __HERE__) << " Ignored exception." << std::endl; + } + return ret; + } + + std::map<QString, QString> comments; + try + { + toQuery comment(connection(), SQLComment, table.Owner, table.Name); + while (!comment.eof()) + { + QString col = comment.readValue(); + comments[col] = comment.readValueNull(); + } + } + catch (...) + { + get_log(1).ts<toDecorator>( __HERE__) << " Ignored exception." << std::endl; + } + + try + { + toQuery query(connection()); +#ifdef OTL_STREAM_POOLING_ON + // Need to clear the stream cache first. + oracleSub *sub = dynamic_cast<oracleSub *>(query.connectionSub()); + sub->Lock.down(); + sub->Connection->set_stream_pool_size(std::max(toConfigurationSingle::Instance().openCursors(), 1)); + sub->Lock.up(); +#endif + + QString SQL = QString::fromLatin1("SELECT * FROM \""); + SQL += table.Owner; + SQL += QString::fromLatin1("\".\""); + SQL += table.Name; + SQL += QString::fromLatin1("\" WHERE NULL=NULL"); + toQList par; + query.execute(SQL, par); + toQDescList desc = query.describe(); + for (toQDescList::iterator j = desc.begin();j != desc.end();j++) + (*j).Comment = comments[(*j).Name]; + + return desc; + } + catch ( ... ) + { + throw; + } + + toQDescList ret; + return ret; + } + + virtual void commit(toConnectionSub *sub) + { + oracleSub *conn = oracleConv(sub); + try + { + conn->_conn->commit(); + } + catch (const ::trotl::OciException &exc) + { + ThrowException(exc); + } + } + virtual void rollback(toConnectionSub *sub) + { + oracleSub *conn = oracleConv(sub); + try + { + conn->_conn->rollback(); + } + catch (const ::trotl::OciException &exc) + { + ThrowException(exc); + } + } + + virtual toConnectionSub *createConnection(void); + + void closeConnection(toConnectionSub *conn) + { + delete conn; + } + + virtual QString version(toConnectionSub *sub) + { + oracleSub *connp = oracleConv(sub); + try + { + ::trotl::OciLogin &login( *(connp->_login) ); + ::std::stringstream version; + version << login._server.versionNumber() << "." + << login._server.releaseNumber() << "." + << login._server.updateNumber() << "." + << login._server.portReleaseNumber() << "." + << login._server.portUpdateNumber(); + + return QString(version.str().c_str()); + } + catch (::trotl::OciException e) { + get_log(0).ts<toDecorator>( __HERE__) << e.what() << std::endl; + } + catch (...) + { + get_log(1).ts<toDecorator>( __HERE__) << " Ignored exception." << std::endl; + // Ignore any errors here + } + return QString::QString(); + } + + virtual toQuery::queryImpl *createQuery(toQuery *query, toConnectionSub *sub) + { + return new oracleQuery(query, oracleConv(sub)); + } + + + /* TODO I have no idea when this method is used. + instance of toQuery is created and then dropped - why ? + NOTE: there is one more execute method + */ + virtual void execute(toConnectionSub *sub, const QString &sql, toQList ¶ms) + { + oracleSub *conn = oracleConv(sub); + get_log(0).ts<toDecorator>( __HERE__) << std::endl; + if ( params.empty() ) + { + try + { + std::string _sql(sql.toUtf8().constData()); + oracleQuery::trotlQuery query(*conn->_conn, _sql); + query.execute_internal(::trotl::g_OCIPL_BULK_ROWS, OCI_DEFAULT); + //otl_cursor::direct_exec(*(conn->Connection), sql.toUtf8().constData()); + //TODO + get_log(0).ts<toDecorator>( __HERE__) << "TODO: otl_cursor::direct_exec" << std::endl; + } + catch (const ::trotl::OciException &exc) + { + conn->throwExtendedException(connection(), exc); + } + } + else + toQuery query(connection(), sql, params); + } + + virtual void parse(toConnectionSub *sub, const QString &sql) + { + oracleSub *conn = oracleConv(sub); + try + { + //oracleQuery::oracleSqlStatement s1(*conn->_conn, sql.toUtf8().constData()); + oracleQuery::trotlQuery s1(*conn->_conn, ::std::string(sql.toUtf8().constData())); + //conn->Connection->reset_throw_count(); + //conn->Connection->syntax_check(sql.toUtf8().constData()); + + } + catch (const ::trotl::OciException &exc) + { + //conn->Connection->throw_count++; + ThrowException(exc); + } + } + + }; // class oracleConnection : public toConnection::connectionImpl + + toOracleProvider(void) + : toConnectionProvider("Oracle", false) + {} + + virtual void initialize(void) + { + //toMaxLong = toConfigurationSingle::Instance().maxLong(); + ::trotl::g_OCIPL_MAX_LONG = ( toConfigurationSingle::Instance().maxLong() == -1 ? ::trotl::g_OCIPL_MAX_LONG : toConfigurationSingle::Instance().maxLong() ); + ::trotl::OciEnvAlloc *_envallocp = new ::trotl::OciEnvAlloc; + + _envp = new ::trotl::OciEnv(*_envallocp); + + //get_log(0).ts<toDecorator>( __HERE__) << "TODO: initialize" << std::endl << __HERE__ << std::endl; + + addProvider("Oracle"); + } + + virtual toConnection::connectionImpl *provideConnection(const QString &, toConnection *conn) + { + return new oracleConnection(conn, *_envp); + } + + virtual std::list<QString> providedOptions(const QString &) + { + std::list<QString> ret; + ret.insert(ret.end(), "*SQL*Net"); + ret.insert(ret.end(), "-"); + ret.insert(ret.end(), "SYS_OPER"); + ret.insert(ret.end(), "SYS_DBA"); + return ret; + } + + virtual std::list<QString> providedHosts(const QString &) + { + std::list<QString> ret; + ret.insert(ret.end(), QString::null); + ret.insert(ret.end(), QString::fromLatin1("SQL*Net")); + return ret; + } + + virtual std::list<QString> providedDatabases(const QString &, + const QString &host, + const QString &, + const QString &) + { + QString str; +#ifdef Q_OS_WIN32 + + CRegistry registry; + DWORD siz = 1024; + char buffer[1024]; + try + { + if (registry.GetStringValue(HKEY_LOCAL_MACHINE, + "SOFTWARE\\ORACLE\\HOME0", + "TNS_ADMIN", + buffer, siz)) + { + if (siz > 0) + str = buffer; + else + throw 0; + } + else + throw 0; + } + catch (...) + { + try + { + if (registry.GetStringValue(HKEY_LOCAL_MACHINE, + "SOFTWARE\\ORACLE\\HOME0", + "ORACLE_HOME", + buffer, siz)) + { + if (siz > 0) + { + str = buffer; + str += "\\network\\admin"; + } + else + throw 0; + } + else + throw 0; + } + catch (...) + { + if (GetEnvironmentVariableA("TNS_ADMIN", buffer, siz) > 0) + str = buffer; + } + } + str.append(QString::fromLatin1("/tnsnames.ora")); +#else + if (getenv("TNS_ADMIN")) + { + str = getenv("TNS_ADMIN"); + } + else + { + str = getenv("ORACLE_HOME"); + str.append(QString::fromLatin1("/network/admin")); + } + + str.append(QString::fromLatin1("/tnsnames.ora")); + + + + str = QString("/home/ibrezina/.tnsnames.ora"); +#endif + std::list<QString> ret; + + QFile file(str); + if (!file.open(QIODevice::ReadOnly)) + return ret; + + QTextStream in(&file); + QByteArray barray = in.readAll().toUtf8(); + const char *buf = barray.constData(); + + int begname = -1; + int parambeg = -1; + int pos = 0; + int param = 0; + while (pos < barray.size()) + { + if (buf[pos] == '#') + { + while (pos < barray.size() && buf[pos] != '\n') + pos++; + } + else if (buf[pos] == '=') + { + if (param == 0) + { + if (begname >= 0 && !host.isEmpty()) + ret.insert(ret.end(), QString::fromLatin1(buf + begname, pos - begname)); + } + } + else if (buf[pos] == '(') + { + begname = -1; + parambeg = pos + 1; + param++; + } + else if (buf[pos] == ')') + { + if (parambeg >= 0 && host.isEmpty()) + { + QString tmp = QString::fromLatin1(buf + parambeg, pos - parambeg); + tmp.replace(QRegExp(QString::fromLatin1("\\s+")), QString::null); + if (tmp.toLower().startsWith(QString::fromLatin1("sid="))) + ret.insert(ret.end(), tmp.mid(4)); + } + begname = -1; + parambeg = -1; + param--; + } + else if (!isspace(buf[pos]) && begname < 0) + { + begname = pos; + } + pos++; + } + return ret; + } + + virtual QWidget *providerConfigurationTab(const QString &provider, QWidget *parent); +}; + +static toOracleProvider OracleProvider; + +void toOracleProvider::oracleQuery::execute(void) +{ + get_log(0).ts<toDecorator>( __HERE__) << std::endl; + + oracleSub *conn = dynamic_cast<oracleSub *>(query()->connectionSub()); + if (!conn) + throw QString::fromLatin1("Internal error, not oracle sub connection"); + try + { + if(Query) delete Query; + Query = NULL; + + if (Cancel) + throw QString::fromLatin1("Query aborted before started"); + Running = true; + + QRegExp stripnl("\r"); + QString sql = this->query()->sql(); + sql.replace(stripnl, ""); + + get_log(0).ts<toDecorator>( __HERE__) << "SQL:" << ::std::string(sql.toUtf8().constData()) << std::endl; + + //Query = new oracleQuery::oracleSqlStatement(*conn->_conn, sql.toUtf8().constData()); + Query = new oracleQuery::trotlQuery(*conn->_conn, ::std::string(sql.toUtf8().constData())); + // TODO autocommit ?? + // Query->set_commit(0); + //if (toQValue::numberFormat() == 0) + // Query->set_all_column_types(otl_all_num2str | otl_all_date2str); + //else + // Query->set_all_column_types(otl_all_date2str); + + //Query->open(1, sql.toUtf8().constData(), *(conn->Connection)); + } + catch (const ::trotl::OciException &exc) + { + delete Query; + Query = NULL; + + Running = false; + conn->throwExtendedException(query()->connection(), exc); + } + try + { + //otl_null null; + for (toQList::iterator i = query()->params().begin();i != query()->params().end();i++) + { + const trotlQuery::BindPar& bp = (*Query).get_curr_in_bindpar(); + + if( (bp._bind_type & ( trotlQuery::BindPar::BIND_IN | trotlQuery::BindPar::BIND_OUT )) == 0) + throw toConnection::exception(QString::fromLatin1("Fatal pruser error - invalid BindPar")); + + if( bp.bind_typename == "int" /*&& (*i).isInt()*/ ) { + (*Query) << (*i).toInt(); + get_log(0).ts<toDecorator>( __HERE__) + << "VERY VERY TODO: bind param(i):'" + << bp.bind_name << "'\t" + << (*i).toInt() << " of:" << query()->params().size() << std::endl; + } else if( (bp.bind_typename == "char" || bp.bind_typename == "varchar") && (*i).isString()) { + std::string param((const char*)((*i).toString().toUtf8().constData())); + get_log(0).ts<toDecorator>( __HERE__) + << "VERY VERY TODO: bind param(s):'" + << bp.bind_name << "'\t" + << param << " of:" << query()->params().size() << std::endl; + + (*Query) << ::std::string((const char*)((*i).toString().toUtf8().constData())); + get_log(0).ts<toDecorator>( __HERE__) + << "VERY VERY TODO: bind param:" + << ::std::string((const char*)((*i).toString().toUtf8().constData())) << std::endl; + } else { + std::cerr << "Fatal pruser error - unsupported BindPar:" << std::endl; + throw toConnection::exception( + QString::fromLatin1("Fatal pruser error - unsupported BindPar:") + bp.bind_typename.c_str()); + exit(-1); + } + + + // TODO + /* + if ((*i).isNull()) + (*Query) << null; + else + { + otl_var_desc *next = Query->describe_next_in_var(); + if (next) + { + switch (next->ftype) + { + case otl_var_double: + case otl_var_float: + (*Query) << (*i).toDouble(); + break; + case otl_var_int: + case otl_var_unsigned_int: + case otl_var_short: + case otl_var_long_int: + (*Query) << (*i).toInt(); + break; + case otl_var_raw_long: + case otl_var_blob: + if ((*i).isBinary()) + { + QByteArray arr = (*i).toByteArray(); + otl_long_string str(arr, arr.size(), arr.size()); + (*Query) << str; + break; + } + // Intentially left out break + case otl_var_varchar_long: + case otl_var_clob: + { + QString buf = (*i).toUtf8(); + otl_long_string str(buf.toUtf8().constData(), buf.length(), buf.length()); + (*Query) << str; + } + break; + default: + (*Query) << (*i).toUtf8().toUtf8().constData(); + break; + } + } + else + { + printf("ERROR: More parameters than binds\n"); + } + } + */ + } + + Running = false; + } + catch (const ::trotl::OciException &exc) + { + delete Query; + Query = NULL; + + Running = false; + conn->throwExtendedException(query()->connection(), exc); + } +} + +void toOracleProvider::oracleQuery::cancel(void) +{ + if(!Running || Cancel) + return; + + oracleSub *conn = dynamic_cast<oracleSub *>(query()->connectionSub()); + if (!conn) + throw QString::fromLatin1("Internal error, not oracle sub connection"); + + conn->_conn->cancel(); + Cancel = true; +} + + +QString toOracleProvider::oracleConnection:: connectString(void) +{ + QString ret; + ret = connection().user().toUtf8(); + ret += QString::fromLatin1("/"); + ret += connection().password().toUtf8(); + if (!connection().host().isEmpty()) + { + ret += QString::fromLatin1("@"); + ret += connection().database().toUtf8(); + } + return ret; +} + +toConnectionSub* toOracleProvider::oracleConnection::createConnection(void) +{ + ::trotl::OciConnection *conn = NULL; + ::trotl::OciLogin *login = NULL; + QString oldSid; + + std::set<QString> options = connection().options(); + + bool sqlNet = (options.find("SQL*Net") != options.end()); + if (!sqlNet) + { + oldSid = getenv("ORACLE_SID"); + toSetEnv("ORACLE_SID", connection().database()); + } + try + { + int session_mode = OCI_DEFAULT; + if (options.find("SYS_OPER") != options.end()) + session_mode = OCI_SYSOPER; + else if (options.find("SYS_DBA") != options.end()) + session_mode = OCI_SYSDBA; + do + { + +#ifdef OTL_STREAM_POOLING_ON + conn->set_stream_pool_size(std::max(toConfigurationSingle::Instance().openCursors(), 1)); +#endif + /* TODO + if (!sqlNet) + conn->server_attach(); + else + */ + QString user = connection().user(); + QString pass = connection().password(); + + try + { + // TODO what does _login destructor? and where is it? + /*::trotl::OciLogin */ login = new ::trotl::OciLogin(_env, + ::trotl::LoginPara( + user.isEmpty() ? "" : user.toUtf8().constData(), + pass.isEmpty() ? "" : pass.toUtf8().constData(), + connection().database().toUtf8().constData() + ), + (ub4) session_mode); + conn = new ::trotl::OciConnection(_env, *login); + + ::get_log(0).ts<toDecorator>( __HERE__) << "Oracle database version: " + << ::std::hex << ::std::showbase << ::std::setw(10) + << ::std::setfill('0') << ::std::internal + << login->_server._version << ::std::endl + << login->_server._version_string << ::std::endl + << login->_server.versionNumber() << "." + << login->_server.releaseNumber() << "." + << login->_server.updateNumber() << "." + << login->_server.portReleaseNumber() << "." + << login->_server.portUpdateNumber() + << ::std::dec << ::std::endl; + + } + catch (const ::trotl::OciException &exc) + { + get_log(0).ts<toDecorator>( __HERE__) + << "TODO: catch" << std::endl << __HERE__ << std::endl; + if (toThread::mainThread() && exc.get_code() == 28001) + { + bool ok = false; + QString newpass = QInputDialog::getText( + toMainWidget(), + qApp->translate("toOracleConnection", "Password expired"), + qApp->translate("toOracleConnection", "Enter new password"), + QLineEdit::Password, + QString::null, + &ok); + if (!ok) + throw exc; + + QString newpass2 = QInputDialog::getText( + toMainWidget(), + qApp->translate("toOracleConnection", "Password expired"), + qApp->translate("toOracleConnection", "Enter password again for confirmation"), + QLineEdit::Password, + QString::null, + &ok); + + if (!ok) + throw exc; + + if (newpass2 != newpass) + throw qApp->translate("toOracleConnection", "The two passwords doesn't match"); + QString nputf = newpass; + if( login ) delete login; + login = new ::trotl::OciLogin(_env, + ::trotl::LoginAndPChangePara( + user.isEmpty() ? "" : user.toUtf8().constData(), + pass.isEmpty() ? "" : pass.toUtf8().constData(), + newpass.isEmpty() ? "" : newpass.toUtf8().constData(), + connection().database().toUtf8().constData() + ), + (ub4) session_mode); + conn = new ::trotl::OciConnection(_env, *login); + + connection().setPassword(newpass); + } else { + get_log(0).ts<toDecorator>( __HERE__) << std::endl; + throw exc; + } // (toThread::mainThread() && exc.get_code() == 28001) + } // catch (const ::trotl::OciException &exc) + } + while (!conn); + } + catch (const ::trotl::OciException &exc) + { + if (!sqlNet) + { + if (oldSid.isNull()) + toUnSetEnv("ORACLE_SID"); + else + toSetEnv("ORACLE_SID", oldSid.toLatin1()); + } + delete conn; + ThrowException(exc); + } + if (!sqlNet) + { + if (oldSid.isNull()) + toUnSetEnv("ORACLE_SID"); + else + { + toSetEnv("ORACLE_SID", oldSid.toLatin1()); + } + } + + try + { + QString str = QString::fromLatin1("ALTER SESSION SET NLS_DATE_FORMAT = '"); + str += toConfigurationSingle::Instance().dateFormat(); + str += QString::fromLatin1("'"); + oracleQuery::trotlQuery date(*conn, ::std::string(str.toAscii().constData())); + } + catch (...) + { + printf("Failed to set new default date format for session\n"); + toStatusMessage(QObject::tr("Failed to set new default date format for session: %1") + .arg(toConfigurationSingle::Instance().dateFormat())); + } + + try + { + //oracleQuery::oracleSqlStatement info(*conn, + oracleQuery::trotlQuery info(*conn, + "BEGIN\n" + " SYS.DBMS_APPLICATION_INFO.SET_CLIENT_INFO('" TOAPPNAME + " (http://tora.sf.net)" + "');\n" + " SYS.DBMS_APPLICATION_INFO.SET_MODULE('" TOAPPNAME "','Access Database');\n" + "END;"); + } + catch (...) + { + printf("Failed to set client info for session\n"); + } + + return new oracleSub(conn, login); +} + +/* +** 11g version, see $ORACLE_HOME/rdbms/admin/utlxplan.sql +*/ +static toSQL SQLCreatePlanTable(toSQL::TOSQL_CREATEPLAN, + "CREATE TABLE %1 (\n" + "STATEMENT_ID VARCHAR2(30),\n" + "PLAN_ID NUMBER,\n" + "TIMESTAMP DATE,\n" + "REMARKS VARCHAR2(4000),\n" + "OPERATION VARCHAR2(30),\n" + "OPTIONS VARCHAR2(255),\n" + "OBJECT_NODE VARCHAR2(128),\n" + "OBJECT_OWNER VARCHAR2(30),\n" + "OBJECT_NAME VARCHAR2(30),\n" + "OBJECT_ALIAS VARCHAR2(65),\n" + "OBJECT_INSTANCE NUMERIC,\n" + "OBJECT_TYPE VARCHAR2(30),\n" + "OPTIMIZER VARCHAR2(255),\n" + "SEARCH_COLUMNS NUMBER,\n" + "ID NUMERIC,\n" + "PARENT_ID NUMERIC,\n" + "DEPTH NUMERIC,\n" + "POSITION NUMERIC,\n" + "COST NUMERIC,\n" + "CARDINALITY NUMERIC,\n" + "BYTES NUMERIC,\n" + "OTHER_TAG VARCHAR2(255),\n" + "PARTITION_START VARCHAR2(255),\n" + "PARTITION_STOP VARCHAR2(255),\n" + "PARTITION_ID NUMERIC,\n" + "OTHER LONG,\n" + "DISTRIBUTION VARCHAR2(30),\n" + "CPU_COST NUMERIC,\n" + "IO_COST NUMERIC,\n" + "TEMP_SPACE NUMERIC,\n" + "ACCESS_PREDICATES VARCHAR2(4000),\n" + "FILTER_PREDICATES VARCHAR2(4000),\n" + "PROJECTION VARCHAR2(4000),\n" + "TIME NUMERIC,\n" + "QBLOCK_NAME VARCHAR2(30),\n" + "OTHER_XML CLOB\n" + ")", + "Create plan table, must have same % signs"); + ... [truncated message content] |