From 107e016f9c17907682c2f2bc9d541fbee7c17fe1 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 28 Jan 2022 13:28:41 -0800 Subject: [PATCH 01/32] [AD-521] add comments and notes for starting AD-521 --- src/odbc/src/jni/java.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index dcd21b0b3..604527518 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -210,13 +210,22 @@ namespace ignite JniMethod( "getPropertiesFromConnectionString", "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", - true); + true); + + // todo code draft -AL-. After constants all defined, work on the JNI wrappers with Bruce + //const char* C_DOCUMENTDB_CONNECTION = + // "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; + //JniMethod M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = + // JniMethod( + // "getPropertiesFromConnectionString", + // "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", + // true); const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; const char* C_DRIVERMANAGER = "java/sql/DriverManager"; JniMethod M_DRIVERMANAGER_GET_CONNECTION = - JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); + JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); // true/false defines whether it is true -> static/instance const char* C_JAVA_SQL_CONNECTION = "java/sql/Connection"; JniMethod M_JAVA_SQL_CONNECTION_CLOSE = JniMethod("close", "()V", false); From 7ab94b9386955c615194c90254afc2028a62ccf8 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 31 Jan 2022 10:55:18 -0800 Subject: [PATCH 02/32] [AD-521] define constants for Java GetSshLocalPort method call --- src/odbc/include/ignite/odbc/jni/java.h | 1 + src/odbc/src/jni/java.cpp | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/odbc/include/ignite/odbc/jni/java.h b/src/odbc/include/ignite/odbc/jni/java.h index 3925aaf0a..18d0142b2 100644 --- a/src/odbc/include/ignite/odbc/jni/java.h +++ b/src/odbc/include/ignite/odbc/jni/java.h @@ -246,6 +246,7 @@ namespace ignite { jmethodID m_DocumentDbConnectionPropertiesGetPropertiesFromConnectionString; jclass c_DocumentDbConnection; + jmethodID m_DocumentDbConnectionGetSshLocalPort; jmethodID m_DocumentDbConnectionInit; jmethodID m_DocumentDbClose; diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 604527518..3f53e9dd2 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -212,16 +212,12 @@ namespace ignite "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", true); - // todo code draft -AL-. After constants all defined, work on the JNI wrappers with Bruce - //const char* C_DOCUMENTDB_CONNECTION = - // "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; - //JniMethod M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = - // JniMethod( - // "getPropertiesFromConnectionString", - // "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", - // true); + // todo code draft -AL-. After constants all defined (define constants here), work on the JNI wrappers with Bruce + const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnection"; + JniMethod M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT = + JniMethod("getSshLocalPort", "()I", false); - const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; + // const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; const char* C_DRIVERMANAGER = "java/sql/DriverManager"; JniMethod M_DRIVERMANAGER_GET_CONNECTION = @@ -437,6 +433,7 @@ namespace ignite c_DocumentDbConnection = FindClass(env, C_DOCUMENTDB_CONNECTION); //m_DocumentDbConnectionInit = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_PROPERTIES_INIT); + m_DocumentDbConnectionGetSshLocalPort = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT); c_DriverManager = FindClass(env, C_DRIVERMANAGER); m_DriverManagerGetConnection = FindMethod(env, c_DriverManager, M_DRIVERMANAGER_GET_CONNECTION); From 6c16725b0d7c9e2f028cafc842499892e27239be Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 31 Jan 2022 13:37:43 -0800 Subject: [PATCH 03/32] [AD-521] refactor code * make open brace bracket start on new line for JVMException * remove excess space --- src/odbc/src/jni/java.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 3f53e9dd2..58ce058fc 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -115,7 +115,8 @@ namespace ignite } /* --- Startup exception. --- */ - class JvmException : public std::exception { + class JvmException : public std::exception + { // No-op. }; @@ -210,7 +211,7 @@ namespace ignite JniMethod( "getPropertiesFromConnectionString", "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", - true); + true); // todo code draft -AL-. After constants all defined (define constants here), work on the JNI wrappers with Bruce const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnection"; @@ -221,7 +222,7 @@ namespace ignite const char* C_DRIVERMANAGER = "java/sql/DriverManager"; JniMethod M_DRIVERMANAGER_GET_CONNECTION = - JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); // true/false defines whether it is true -> static/instance + JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); // -AL- true/false defines whether it is true -> static/instance const char* C_JAVA_SQL_CONNECTION = "java/sql/Connection"; JniMethod M_JAVA_SQL_CONNECTION_CLOSE = JniMethod("close", "()V", false); From 1db5b3fced43519bb091f5f080177268afda99d1 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 09:10:46 -0800 Subject: [PATCH 04/32] [AD-427] Tracer Code - Limited Capability to load metadata - work-in-progress. --- .../win/include/ignite/common/concurrent_os.h | 3 + src/odbc-test/CMakeLists.txt | 117 ++--- src/odbc-test/include/odbc_test_suite.h | 8 +- src/odbc-test/src/connection_test.cpp | 73 +-- src/odbc-test/src/java_test.cpp | 222 +++++++++ src/odbc-test/src/odbc_test_suite.cpp | 33 +- src/odbc/include/ignite/odbc/connection.h | 22 +- src/odbc/include/ignite/odbc/jni/java.h | 62 ++- src/odbc/include/ignite/odbc/log.h | 12 +- .../win/include/ignite/odbc/common/common.h | 6 +- src/odbc/src/app/application_data_buffer.cpp | 2 - src/odbc/src/connection.cpp | 91 +--- src/odbc/src/jni/java.cpp | 453 +++++++++++++++--- src/odbc/src/jni/os/linux/utils.cpp | 4 +- src/odbc/src/jni/os/win/utils.cpp | 12 +- 15 files changed, 811 insertions(+), 309 deletions(-) create mode 100644 src/odbc-test/src/java_test.cpp diff --git a/src/common/os/win/include/ignite/common/concurrent_os.h b/src/common/os/win/include/ignite/common/concurrent_os.h index b1e89164c..22bf36c34 100644 --- a/src/common/os/win/include/ignite/common/concurrent_os.h +++ b/src/common/os/win/include/ignite/common/concurrent_os.h @@ -32,6 +32,9 @@ namespace ignite { namespace concurrent { + // Forward declaration + class ConditionVariable; + /** * Static class to manage memory visibility semantics. */ diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 77294465b..44a469c8f 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -28,7 +28,7 @@ find_package(Boost 1.53 REQUIRED COMPONENTS unit_test_framework chrono thread sy find_package(ODBC REQUIRED) include_directories(SYSTEM ${ODBC_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${JNI_INCLUDE_DIRS}) -include_directories(include ../odbc/include ../network/include) +include_directories(include ../odbc/include) if (WIN32) include_directories(../odbc/os/win/include) else () @@ -39,68 +39,59 @@ endif() set(SOURCES src/connection_test.cpp src/dummy_test.cpp + src/java_test.cpp src/odbc_test_suite.cpp src/test_utils.cpp + ../odbc/src/app/application_data_buffer.cpp + ../odbc/src/app/parameter.cpp + ../odbc/src/app/parameter_set.cpp + ../odbc/src/column.cpp + ../odbc/src/common/big_integer.cpp + ../odbc/src/common/bits.cpp ../odbc/src/common/concurrent.cpp + ../odbc/src/common/decimal.cpp ../odbc/src/common/utils.cpp + ../odbc/src/common_types.cpp + ../odbc/src/config/configuration.cpp + ../odbc/src/config/config_tools.cpp + ../odbc/src/config/connection_info.cpp + ../odbc/src/config/connection_string_parser.cpp + ../odbc/src/connection.cpp + ../odbc/src/cursor.cpp + ../odbc/src/diagnostic/diagnosable_adapter.cpp + ../odbc/src/diagnostic/diagnostic_record_storage.cpp + ../odbc/src/diagnostic/diagnostic_record.cpp + ../odbc/src/dsn_config.cpp + ../odbc/src/environment.cpp + ../odbc/src/ignite_error.cpp ../odbc/src/jni/java.cpp -# TODO uncomment/rework the tests after get some connectivity and functionalities working. -# src/teamcity/teamcity_boost.cpp -# src/teamcity/teamcity_messages.cpp -# src/parser_test.cpp -# src/cursor_test.cpp -# src/connection_info_test.cpp -# src/application_data_buffer_test.cpp -# src/column_test.cpp -# src/configuration_test.cpp -# src/row_test.cpp -# src/meta_queries_test.cpp -# src/utility_test.cpp -# src/queries_test.cpp -# src/queries_ssl_test.cpp -# src/sql_test_suite_fixture.cpp -# src/sql_string_functions_test.cpp -# src/sql_numeric_functions_test.cpp -# src/sql_aggregate_functions_test.cpp -# src/sql_system_functions_test.cpp -# src/sql_esc_convert_function_test.cpp -# src/sql_operators_test.cpp -# src/sql_value_expressions_test.cpp -# src/sql_types_test.cpp -# src/sql_date_time_functions_test.cpp -# src/sql_outer_join_test.cpp -# src/sql_get_info_test.cpp -# src/api_robustness_test.cpp -# src/attributes_test.cpp -# src/errors_test.cpp -# src/types_test.cpp -# src/transaction_test.cpp -# src/authentication_test.cpp -# src/sql_parsing_test.cpp -# src/streaming_test.cpp -# src/cursor_binding_test.cpp -# src/test_server.cpp -# ../odbc/src/log.cpp -# ../odbc/src/cursor.cpp -# ../odbc/src/diagnostic/diagnostic_record.cpp -# ../odbc/src/diagnostic/diagnostic_record_storage.cpp -# ../odbc/src/config/config_tools.cpp -# ../odbc/src/config/configuration.cpp -# ../odbc/src/config/connection_info.cpp -# ../odbc/src/config/connection_string_parser.cpp -# ../odbc/src/app/application_data_buffer.cpp -# ../odbc/src/ssl_mode.cpp -# ../odbc/src/sql/sql_parser.cpp -# ../odbc/src/sql/sql_lexer.cpp -# ../odbc/src/sql/sql_set_streaming_command.cpp -# ../odbc/src/sql/sql_utils.cpp -# ../odbc/src/row.cpp -# ../odbc/src/protocol_version.cpp -# ../odbc/src/column.cpp -# ../odbc/src/common_types.cpp -# ../odbc/src/utility.cpp -# ../odbc/src/result_page.cpp -# ../odbc/src/nested_tx_mode.cpp + ../odbc/src/log.cpp + ../odbc/src/message.cpp + ../odbc/src/meta/column_meta.cpp + ../odbc/src/meta/table_meta.cpp + ../odbc/src/nested_tx_mode.cpp + ../odbc/src/protocol_version.cpp + ../odbc/src/query/batch_query.cpp + ../odbc/src/query/column_metadata_query.cpp + ../odbc/src/query/data_query.cpp + ../odbc/src/query/foreign_keys_query.cpp + ../odbc/src/query/primary_keys_query.cpp + ../odbc/src/query/special_columns_query.cpp + ../odbc/src/query/streaming_query.cpp + ../odbc/src/query/type_info_query.cpp + ../odbc/src/query/table_metadata_query.cpp + ../odbc/src/sql/sql_lexer.cpp + ../odbc/src/sql/sql_parser.cpp + ../odbc/src/sql/sql_set_streaming_command.cpp + ../odbc/src/sql/sql_utils.cpp + ../odbc/src/result_page.cpp + ../odbc/src/row.cpp + ../odbc/src/ssl_mode.cpp + ../odbc/src/statement.cpp + ../odbc/src/streaming/streaming_batch.cpp + ../odbc/src/streaming/streaming_context.cpp + ../odbc/src/type_traits.cpp + ../odbc/src/utility.cpp ) if (WIN32) @@ -108,6 +99,10 @@ if (WIN32) ../odbc/os/win/src/common/concurrent_os.cpp ../odbc/os/win/src/common/platform_utils.cpp ../odbc/src/jni/os/win/utils.cpp + ../odbc/os/win/src/system_dsn.cpp + ../odbc/os/win/src/system/ui/custom_window.cpp + ../odbc/os/win/src/system/ui/dsn_configuration_window.cpp + ../odbc/os/win/src/system/ui/window.cpp ) else() # TODO: Ensure MacOS is portable. https://bitquill.atlassian.net/browse/AD-525 @@ -120,11 +115,17 @@ endif() add_executable(${TARGET} ${SOURCES}) +target_link_libraries(${TARGET} ${ODBC_LIBRARIES}) target_link_libraries(${TARGET} ${Boost_LIBRARIES} ignite ${ODBC_LIBRARY}) target_code_coverage(${TARGET} PUBLIC AUTO ALL) if (WIN32) remove_definitions(-DUNICODE=1) + add_definitions(-DTARGET_MODULE_FULL_NAME="$") + if (MSVC_VERSION GREATER_EQUAL 1900) + target_link_libraries(${TARGET} legacy_stdio_definitions odbccp32 shlwapi) + endif() + else() add_definitions(-DBOOST_TEST_DYN_LINK) endif() diff --git a/src/odbc-test/include/odbc_test_suite.h b/src/odbc-test/include/odbc_test_suite.h index 6bd00a63a..414daabf6 100644 --- a/src/odbc-test/include/odbc_test_suite.h +++ b/src/odbc-test/include/odbc_test_suite.h @@ -37,8 +37,6 @@ #include -#include "ignite/ignite.h" - namespace ignite { namespace odbc @@ -352,6 +350,12 @@ namespace ignite */ SQLRETURN PrepareQuery(const std::string& qry); + /** + * Creates the standard DSN connection string. + */ + void CreateDsnConnectionString(std::string& connectionString, + const std::string& username = std::string()) const; + /** ODBC Environment. */ SQLHENV env; diff --git a/src/odbc-test/src/connection_test.cpp b/src/odbc-test/src/connection_test.cpp index 28714a040..d28a85643 100644 --- a/src/odbc-test/src/connection_test.cpp +++ b/src/odbc-test/src/connection_test.cpp @@ -16,7 +16,7 @@ */ #ifdef _WIN32 -# include +# include #endif #include @@ -39,14 +39,7 @@ using namespace boost::unit_test; */ struct ConnectionTestSuiteFixture: odbc::OdbcTestSuite { - /** - * Constructor. - */ - ConnectionTestSuiteFixture() : - OdbcTestSuite() - { - // No-op. - } + using odbc::OdbcTestSuite::OdbcTestSuite; /** * Execute the query and return an error code. @@ -83,32 +76,10 @@ struct ConnectionTestSuiteFixture: odbc::OdbcTestSuite return code; } - static void SetConnectionString(std::string& connectionString, - const std::string& username = std::string()) { - // NOTE: Assuming we are using internal SSH tunnel - std::string user = common::GetEnv("DOC_DB_USER_NAME", "documentdb"); - std::string password = common::GetEnv("DOC_DB_PASSWORD", ""); - std::string host = common::GetEnv("DOC_DB_HOST", ""); - std::string port = "27017"; - if (!username.empty()) { - user = username; - } - - connectionString = - "DRIVER={Apache Ignite};" - "ADDRESS=" + host + ":" + port + ";" - "SCHEMA=test;" - "USER=" + user + ";" - "PASSWORD=" + password + ";"; - } - /** * Destructor. */ - ~ConnectionTestSuiteFixture() - { - // No-op. - } + ~ConnectionTestSuiteFixture() override = default; }; @@ -117,54 +88,20 @@ BOOST_FIXTURE_TEST_SUITE(ConnectionTestSuite, ConnectionTestSuiteFixture) BOOST_AUTO_TEST_CASE(TestConnectionRestore) { std::string connectionString; - SetConnectionString(connectionString); - - Connect(connectionString); - Disconnect(); - - // TODO: [AD-507] Re-enable when querying is supported. - // https://bitquill.atlassian.net/browse/AD-507 - - //// Check that query was successfully executed. - //BOOST_CHECK_EQUAL(ExecQueryAndReturnError(), ""); - - //// Query execution should throw ODBC error. - //BOOST_CHECK_EQUAL(ExecQueryAndReturnError(), "08S01"); - - //// Reusing a closed connection should not crash an application. - //BOOST_CHECK_EQUAL(ExecQueryAndReturnError(), "08001"); - - //// Check that connection was restored. - //BOOST_CHECK_EQUAL(ExecQueryAndReturnError(), ""); - -} - -BOOST_AUTO_TEST_CASE(TestConnectionMemoryLeak) -{ - std::string connectionString; - SetConnectionString(connectionString); + CreateDsnConnectionString(connectionString); Connect(connectionString); - - // TODO: [AD-507] Re-enable when querying is supported. - // https://bitquill.atlassian.net/browse/AD-507 - // ExecQuery("Select * from Test"); - Disconnect(); } BOOST_AUTO_TEST_CASE(TestConnectionInvalidUser) { std::string connectionString; - SetConnectionString(connectionString, "invaliduser"); + CreateDsnConnectionString(connectionString, "invaliduser"); ExpectConnectionReject(connectionString, "08001: Failed to establish connection with the host.\n" "Invalid username or password or user is not authorized on database 'test'. " "Please check your settings. Authorization failed for user 'invaliduser' on database 'admin' with mechanism"); - // TODO: [AD-507] Re-enable when querying is supported. - // https://bitquill.atlassian.net/browse/AD-507 - // ExecQuery("Select * from Test"); - Disconnect(); } diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp new file mode 100644 index 000000000..36ffacdcd --- /dev/null +++ b/src/odbc-test/src/java_test.cpp @@ -0,0 +1,222 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef _WIN32 +# include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_utils.h" +#include "odbc_test_suite.h" + +using namespace ignite; +using namespace ignite_test; +using namespace boost::unit_test; +using namespace odbc; +using namespace odbc::config; +using namespace odbc::jni; +using namespace odbc::jni::java; +using namespace odbc::common::concurrent; + +/** + * Test setup fixture. + */ +struct JavaTestSuiteFixture: odbc::OdbcTestSuite +{ + using odbc::OdbcTestSuite::OdbcTestSuite; + + /** + * Execute the query and return an error code. + */ + std::string ExecQueryAndReturnError() + { + SQLCHAR selectReq[] = "select count(*) from TestType"; + + SQLRETURN ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq)); + + std::string err; + + if (!SQL_SUCCEEDED(ret)) + err = ExtractErrorCode(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + return err; + } + + /** + * Extract code from ODBC error message. + * + * @param err Error message. + * @return Error code. + */ + static std::string ExtractErrorCode(const std::string& err) + { + std::string code; + + size_t idx = err.find(':'); + + if ((idx != std::string::npos) && (idx > 0)) + code = err.substr(0, idx); + + return code; + } + + SharedPointer< JniContext > GetJniContext(std::vector< char* >& opts) const { + + SharedPointer< JniContext > ctx(JniContext::Create( + &opts[0], static_cast< int >(opts.size()), JniHandlers())); + BOOST_CHECK(ctx.Get()); + return ctx; + } + + std::string GetJdbcConnectionString() const { + std::string dsnConnectionString; + CreateDsnConnectionString(dsnConnectionString); + + Configuration config; + ConnectionStringParser parser(config); + parser.ParseConnectionString(dsnConnectionString, nullptr); + std::string jdbcConnectionString = + Connection::FormatJdbcConnectionString(config); + return jdbcConnectionString; + } + + void PrepareContext() { + if (!_prepared) { + _jdbcConnectionString = GetJdbcConnectionString(); + std::string cp = ResolveDocumentDbHome(); + BuildJvmOptions(cp, _opts); + _ctx = GetJniContext(_opts); + _prepared = true; + } + } + + void CleanUpContext() { + using namespace odbc::common; + std::for_each(_opts.begin(), _opts.end(), ReleaseChars); + _opts.clear(); + _ctx = nullptr; + _prepared = false; + } + + /** + * Destructor. + */ + ~JavaTestSuiteFixture() override { + CleanUpContext(); + } + + bool _prepared = false; + + std::string _jdbcConnectionString; + + std::vector< char* > _opts; + + SharedPointer< JniContext > _ctx; +}; + + +BOOST_FIXTURE_TEST_SUITE(JavaTestSuite, JavaTestSuiteFixture) + +BOOST_AUTO_TEST_CASE(TestDriverManagerGetConnection) +{ + PrepareContext(); + + JniErrorInfo errInfo; + SharedPointer< GlobalJObject > connection; + bool success = _ctx.Get()->DriverManagerGetConnection(_jdbcConnectionString.c_str(), connection, &errInfo); + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + BOOST_FAIL(errInfo.errMsg); + } + BOOST_REQUIRE(connection.Get()); + + _ctx.Get()->ConnectionClose(connection, &errInfo); + connection = SharedPointer< GlobalJObject >(nullptr); +} + +BOOST_AUTO_TEST_CASE(TestConnectionGetMetaData) { + PrepareContext(); + + JniErrorInfo errInfo; + SharedPointer< GlobalJObject > connection; + bool success = _ctx.Get()->DriverManagerGetConnection( + _jdbcConnectionString.c_str(), connection, &errInfo); + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + BOOST_FAIL(errInfo.errMsg); + } + BOOST_REQUIRE(connection.Get()); + + SharedPointer< GlobalJObject > databaseMetaData; + if (!_ctx.Get()->ConnectionGetMetaData(connection, databaseMetaData, + &errInfo)) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + BOOST_REQUIRE(databaseMetaData.Get()); + + _ctx.Get()->ConnectionClose(connection, &errInfo); + connection = nullptr; +} + +BOOST_AUTO_TEST_CASE(TestDatabaseMetaDataGetTables) { + PrepareContext(); + + JniErrorInfo errInfo; + SharedPointer< GlobalJObject > connection; + bool success = _ctx.Get()->DriverManagerGetConnection( + _jdbcConnectionString.c_str(), connection, &errInfo); + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + BOOST_FAIL(errInfo.errMsg); + } + BOOST_REQUIRE(connection.Get()); + + SharedPointer< GlobalJObject > databaseMetaData; + if (!_ctx.Get()->ConnectionGetMetaData(connection, databaseMetaData, &errInfo)) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + BOOST_REQUIRE(databaseMetaData.Get()); + + SharedPointer< GlobalJObject > resultSet; + if (!_ctx.Get()->DatabaseMetaDataGetTables(databaseMetaData, resultSet, + &errInfo)) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + BOOST_REQUIRE(resultSet.Get()); + + _ctx.Get()->ConnectionClose(connection, &errInfo); + connection = nullptr; +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/odbc-test/src/odbc_test_suite.cpp b/src/odbc-test/src/odbc_test_suite.cpp index 1b2ece743..41fcd3b49 100644 --- a/src/odbc-test/src/odbc_test_suite.cpp +++ b/src/odbc-test/src/odbc_test_suite.cpp @@ -132,7 +132,7 @@ namespace ignite { // Releasing statement handle. SQLFreeHandle(SQL_HANDLE_STMT, stmt); - stmt = NULL; + stmt = nullptr; } if (dbc) @@ -142,7 +142,7 @@ namespace ignite // Releasing allocated handles. SQLFreeHandle(SQL_HANDLE_DBC, dbc); - dbc = NULL; + dbc = nullptr; } } @@ -221,7 +221,7 @@ namespace ignite float OdbcTestSuite::GetTestFloatField(int64_t idx) { - return static_cast(idx * 0.5f); + return static_cast(idx) * 0.5f; } void OdbcTestSuite::CheckTestFloatValue(int idx, float value) @@ -232,7 +232,7 @@ namespace ignite double OdbcTestSuite::GetTestDoubleField(int64_t idx) { - return static_cast(idx * 0.25f); + return static_cast(idx) * 0.25f; } void OdbcTestSuite::CheckTestDoubleValue(int idx, double value) @@ -243,7 +243,7 @@ namespace ignite bool OdbcTestSuite::GetTestBoolField(int64_t idx) { - return static_cast(idx % 2 == 0); + return ((idx % 2) == 0); } void OdbcTestSuite::CheckTestBoolValue(int idx, bool value) @@ -420,7 +420,7 @@ namespace ignite // Inserting values. for (SQLSMALLINT i = 0; i < recordsNum; ++i) { - key = i + 1; + key = static_cast(i) + 1; std::string val = GetTestString(i); CopyStringToBuffer(strField, val, sizeof(strField)); @@ -787,5 +787,26 @@ namespace ignite BOOST_CHECK_EQUAL(recordsNum, selectedRecordsNum); } + + void OdbcTestSuite::CreateDsnConnectionString(std::string& connectionString, + const std::string& username) const { + // NOTE: Assuming we are using internal SSH tunnel + std::string user = common::GetEnv("DOC_DB_USER_NAME", "documentdb"); + std::string password = common::GetEnv("DOC_DB_PASSWORD", ""); + std::string host = common::GetEnv("DOC_DB_HOST", ""); + std::string port = "27017"; + if (!username.empty()) { + user = username; + } + + connectionString = + "DRIVER={Apache Ignite};" + "ADDRESS=" + host + ":" + port + ";" + "SCHEMA=test;" + "USER=" + user + ";" + "PASSWORD=" + password + ";"; + } + + } } diff --git a/src/odbc/include/ignite/odbc/connection.h b/src/odbc/include/ignite/odbc/connection.h index 0a917a50d..cf1616945 100644 --- a/src/odbc/include/ignite/odbc/connection.h +++ b/src/odbc/include/ignite/odbc/connection.h @@ -22,8 +22,6 @@ #include -#include - #include "ignite/odbc/parser.h" #include "ignite/odbc/config/connection_info.h" #include "ignite/odbc/config/configuration.h" @@ -31,6 +29,9 @@ #include "ignite/odbc/streaming/streaming_context.h" #include "ignite/odbc/odbc_error.h" #include "ignite/odbc/jni/java.h" +#include + +using ignite::odbc::jni::java::GlobalJObject; namespace ignite { @@ -312,7 +313,14 @@ namespace ignite */ void SetAttribute(int attr, void* value, SQLINTEGER valueLen); - private: + /** + * Formats the JDBC connection string from configuration values. + * @return the JDBC connection string. + */ + static std::string FormatJdbcConnectionString( + const config::Configuration& config); + + private: IGNITE_NO_COPY_ASSIGNMENT(Connection); /** @@ -489,12 +497,6 @@ namespace ignite */ bool TryRestoreConnection(IgniteError& err); - /** - * Formats the JDBC connection string from configuration values. - * @return the JDBC connection string. - */ - std::string FormatJdbcConnectionString() const; - /** * Creates JVM options */ @@ -548,7 +550,7 @@ namespace ignite config::ConnectionInfo info; /** Java connection object */ - jobject connection; + SharedPointer< GlobalJObject > connection; /** JVM options */ std::vector< char* > opts; diff --git a/src/odbc/include/ignite/odbc/jni/java.h b/src/odbc/include/ignite/odbc/jni/java.h index 3925aaf0a..d85921ca0 100644 --- a/src/odbc/include/ignite/odbc/jni/java.h +++ b/src/odbc/include/ignite/odbc/jni/java.h @@ -19,10 +19,14 @@ #define _IGNITE_ODBC_JNI_JAVA #include +#include #include #include +#include + +using ignite::odbc::common::concurrent::SharedPointer; namespace ignite { namespace odbc { @@ -191,6 +195,12 @@ namespace ignite { */ bool IGNITE_IMPORT_EXPORT IsJava9OrLater(); + /** + * Builds the JVM options + */ + void BuildJvmOptions(const std::string& cp, + std::vector< char* >& opts, int xms = 256, + int xmx = 1024); /** * JNI handlers holder. */ @@ -252,8 +262,20 @@ namespace ignite { jclass c_DriverManager; jmethodID m_DriverManagerGetConnection; - jclass c_JavaSqlConnection; - jmethodID m_JavaSqlConnectionClose; + jclass c_Connection; + jmethodID m_ConnectionClose; + jmethodID m_ConnectionGetMetaData; + + jclass c_ResultSet; + jmethodID m_ResultSetNext; + jmethodID m_ResultSetGetStringByIndex; + jmethodID m_ResultSetGetIntegerByIndex; + jmethodID m_ResultSetGetStringByName; + jmethodID m_ResultSetGetIntegerByName; + jmethodID m_ResultSetWasNull; + + jclass c_DatabaseMetaData; + jmethodID m_DatabaseMetaDataGetTables; jclass c_IgniteException; @@ -290,6 +312,27 @@ namespace ignite { void Destroy(JNIEnv* env); }; + /** + * Guard to ensure global reference cleanup. + */ + class GlobalJObject { + public: + GlobalJObject(JNIEnv* e, jobject obj); + + ~GlobalJObject(); + + jobject GetRef() const; + + private: + /** Environment. */ + JNIEnv* env; + + /** Target reference. */ + jobject ref; + + IGNITE_NO_COPY_ASSIGNMENT(GlobalJObject); + }; + /** * JNI JVM wrapper. */ @@ -398,10 +441,19 @@ namespace ignite { static void SetConsoleHandler(ConsoleWriteHandler consoleHandler); static int RemoveConsoleHandler(ConsoleWriteHandler consoleHandler); - jobject DocumentDbConnect(const char* connectionString, - JniErrorInfo* errInfo); + bool DriverManagerGetConnection(const char* connectionString, SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); + void ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); + bool ConnectionGetMetaData(const SharedPointer< GlobalJObject >& connection, SharedPointer< GlobalJObject>& databaseMetaData, JniErrorInfo* errInfo); + + bool DatabaseMetaDataGetTables(const SharedPointer< GlobalJObject >& databaseMetaData, SharedPointer< GlobalJObject >& resultSet, JniErrorInfo* errInfo); - void DocumentDbDisconnect(const jobject connection, JniErrorInfo* errInfo); + bool ResultSetNext(const SharedPointer< GlobalJObject >& resultSet, bool& hasNext, + JniErrorInfo* errInfo); + bool ResultSetGetString(const jobject resultSet, int columnIndex, std::string& value, bool& wasNull, JniErrorInfo* errInfo); + bool ResultSetGetString(const jobject resultSet, const std::string& columnName, std::string& value, bool& wasNull, JniErrorInfo* errInfo); + bool ResultSetGetInteger(const jobject resultSet, int columnIndex, int& value, bool& wasNull, JniErrorInfo* errInfo); + bool ResultSetGetInteger(const jobject resultSet, const std::string& columnName, int& value, bool& wasNull, JniErrorInfo* errInfo); + bool ResultSetWasNull(const jobject resultSet, bool& value, JniErrorInfo* errInfo); int64_t TargetInLongOutLong(jobject obj, int type, int64_t memPtr, JniErrorInfo* errInfo = NULL); diff --git a/src/odbc/include/ignite/odbc/log.h b/src/odbc/include/ignite/odbc/log.h index 2e361ea20..045c01796 100644 --- a/src/odbc/include/ignite/odbc/log.h +++ b/src/odbc/include/ignite/odbc/log.h @@ -25,12 +25,12 @@ #include "ignite/odbc/common/common.h" #include "ignite/odbc/common/concurrent.h" -# define LOG_MSG(param) \ - if (ignite::odbc::Logger* p = ignite::odbc::Logger::Get()) \ - { \ - ignite::odbc::LogStream lstream(p); \ - lstream << __FUNCTION__ << ": " << param; \ - } +#define LOG_MSG(param) \ + if (ignite::odbc::Logger* p = ignite::odbc::Logger::Get()) { \ + ignite::odbc::LogStream lstream(p); \ + lstream << __FUNCTION__ << ": " << param; \ + } \ + static_assert(true, "") \ namespace ignite { diff --git a/src/odbc/os/win/include/ignite/odbc/common/common.h b/src/odbc/os/win/include/ignite/odbc/common/common.h index e7cda4b52..3ef9574e3 100644 --- a/src/odbc/os/win/include/ignite/odbc/common/common.h +++ b/src/odbc/os/win/include/ignite/odbc/common/common.h @@ -14,8 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef _IGNITE_COMMON_COMMON -#define _IGNITE_COMMON_COMMON +#ifndef _IGNITE_ODBC_COMMON_COMMON +#define _IGNITE_ODBC_COMMON_COMMON #define IGNITE_EXPORT __declspec(dllexport) #define IGNITE_IMPORT __declspec(dllimport) @@ -43,4 +43,4 @@ #define IGNITE_UNUSED(x) ((void) x) -#endif //_IGNITE_COMMON_COMMON \ No newline at end of file +#endif //_IGNITE_ODBC_COMMON_COMMON \ No newline at end of file diff --git a/src/odbc/src/app/application_data_buffer.cpp b/src/odbc/src/app/application_data_buffer.cpp index f4977bb09..0a05506e2 100644 --- a/src/odbc/src/app/application_data_buffer.cpp +++ b/src/odbc/src/app/application_data_buffer.cpp @@ -21,8 +21,6 @@ #include "ignite/odbc/common/bits.h" -#include "ignite/impl/binary/binary_utils.h" - #include "ignite/odbc/system/odbc_constants.h" #include "ignite/odbc/app/application_data_buffer.h" #include "ignite/odbc/utility.h" diff --git a/src/odbc/src/connection.cpp b/src/odbc/src/connection.cpp index d416b52d7..c737246fc 100644 --- a/src/odbc/src/connection.cpp +++ b/src/odbc/src/connection.cpp @@ -22,7 +22,6 @@ #include #include -#include #include "ignite/odbc/log.h" #include "ignite/odbc/utility.h" @@ -40,6 +39,10 @@ #include "ignite/odbc/common/concurrent.h" #include "ignite/odbc/common/utils.h" +using namespace ignite::odbc::jni::java; +using namespace ignite::odbc::common; +using namespace ignite::odbc::common::concurrent; + // Uncomment for per-byte debug. //#define PER_BYTE_DEBUG @@ -152,7 +155,7 @@ namespace ignite config = cfg; - if (connection) { + if (connection.Get()) { AddStatusRecord(SqlState::S08002_ALREADY_CONNECTED, "Already connected."); @@ -196,7 +199,7 @@ namespace ignite SqlResult::Type Connection::InternalRelease() { - if (!connection) + if (!connection.Get()) { AddStatusRecord(SqlState::S08003_NOT_CONNECTED, "Connection is not open."); @@ -212,13 +215,10 @@ namespace ignite void Connection::Close() { - if (connection) { - using namespace jni::java; - using namespace common::concurrent; + if (connection.Get()) { SharedPointer< JniContext > ctx(JniContext::Create(&opts[0], static_cast(opts.size()), JniHandlers())); JniErrorInfo errInfo; - // NOTE: DocumentDbDisconnect will notify JNI connection is no longer used - must set to nullptr. - ctx.Get()->DocumentDbDisconnect(connection, &errInfo); + ctx.Get()->ConnectionClose(connection, &errInfo); if (errInfo.code != java::IGNITE_JNI_ERR_SUCCESS) { // TODO: Determine if we need to error check the close. } @@ -398,7 +398,7 @@ namespace ignite { SQLUINTEGER *val = reinterpret_cast(buf); - *val = connection ? SQL_CD_FALSE : SQL_CD_TRUE; + *val = connection.Get() ? SQL_CD_FALSE : SQL_CD_TRUE; if (valueLen) *valueLen = SQL_IS_INTEGER; @@ -595,7 +595,7 @@ namespace ignite void Connection::EnsureConnected() { - if (connection) + if (connection.Get()) return; odbc::IgniteError err; @@ -610,25 +610,18 @@ namespace ignite { bool connected = false; - using namespace jni::java; - using namespace common::concurrent; - - if (connection) { + if (connection.Get()) { return true; } - std::string connectionString = FormatJdbcConnectionString(); + std::string connectionString = FormatJdbcConnectionString(config); JniErrorInfo errInfo; - std::string docdb_home = common::GetEnv("DOCUMENTDB_HOME") - + "\\documentdb-jdbc-1.1.0-all.jar"; - // 2. Resolve DOCUMENTDB_HOME. std::string home = jni::ResolveDocumentDbHome(); // 3. Create classpath. std::string cp = jni::CreateDocumentDbClasspath(std::string(), home); - if (cp.empty()) { err = odbc::IgniteError(odbc::IgniteError::IGNITE_ERR_JVM_NO_CLASSPATH, @@ -641,10 +634,16 @@ namespace ignite SetJvmOptions(cp); SharedPointer< JniContext > ctx(JniContext::Create(&opts[0], static_cast(opts.size()), JniHandlers(), &errInfo)); + if (errInfo.code != java::IGNITE_JNI_ERR_SUCCESS) { + IgniteError::SetError(errInfo.code, errInfo.errCls, errInfo.errMsg, err); + return false; + } if (ctx.Get()) { - jobject result = ctx.Get()->DocumentDbConnect( - connectionString.c_str(), &errInfo); - connected = (result && errInfo.code == java::IGNITE_JNI_ERR_SUCCESS); + SharedPointer< GlobalJObject > result; + bool success = ctx.Get()->DriverManagerGetConnection( + connectionString.c_str(), result, &errInfo); + connected = (success && result.Get() + && errInfo.code == java::IGNITE_JNI_ERR_SUCCESS); if (!connected) { err = odbc::IgniteError( odbc::IgniteError::IGNITE_ERR_SECURE_CONNECTION_FAILURE, @@ -660,7 +659,8 @@ namespace ignite return connected; } - std::string Connection::FormatJdbcConnectionString() const { + std::string Connection::FormatJdbcConnectionString( + const config::Configuration& config) { std::string host = "localhost"; std::string port = "27017"; if (!config.GetAddresses().empty()) { @@ -711,57 +711,14 @@ namespace ignite * @param cp Classpath. */ void Connection::SetJvmOptions(const std::string& cp) { - using namespace common; Deinit(); - - const size_t REQ_OPTS_CNT = 4; - const size_t JAVA9_OPTS_CNT = 6; - - opts.reserve(REQ_OPTS_CNT + JAVA9_OPTS_CNT); - - // 1. Set classpath. - std::string cpFull = "-Djava.class.path=" + cp; - - opts.push_back(CopyChars(cpFull.c_str())); - - // 3. Set Xms, Xmx. - std::string xmsStr = "-Xms" + std::to_string(256) + "m"; - std::string xmxStr = "-Xmx" + std::to_string(1024) + "m"; - - opts.push_back(CopyChars(xmsStr.c_str())); - opts.push_back(CopyChars(xmxStr.c_str())); - - // 4. Optional debug arguments - //std::string debugStr = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"; - //opts.push_back(CopyChars(debugStr.c_str())); - - // 5. Set file.encoding. - std::string fileEncParam = "-Dfile.encoding="; - std::string fileEncFull = fileEncParam + "UTF-8"; - opts.push_back(CopyChars(fileEncFull.c_str())); - - // Adding options for Java 9 or later - if (jni::java::IsJava9OrLater()) { - opts.push_back(CopyChars( - "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED")); - opts.push_back(CopyChars( - "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED")); - opts.push_back(CopyChars( - "--add-exports=java.management/com.sun.jmx.mbeanserver=ALL-UNNAMED")); - opts.push_back(CopyChars( - "--add-exports=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED")); - opts.push_back(CopyChars( - "--add-exports=java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED")); - opts.push_back(CopyChars( - "--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED")); - } + BuildJvmOptions(cp, opts); } /** * Deallocates all allocated data. */ void Connection::Deinit() { - using namespace common; std::for_each(opts.begin(), opts.end(), ReleaseChars); opts.clear(); } diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index dcd21b0b3..573c499be 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -23,11 +23,13 @@ #include #include +#include #include +#include #include #include -#include -#include + +using namespace ignite::odbc::common::concurrent; #ifndef JNI_VERSION_9 #define JNI_VERSION_9 0x00090000 @@ -114,6 +116,61 @@ namespace ignite return JNI_GetDefaultJavaVMInitArgs(&args) == JNI_OK; } + void BuildJvmOptions( + const std::string& cp, std::vector< char* >& opts, + int xms, int xmx) { + using namespace common; + + const size_t REQ_OPTS_CNT = 4; + const size_t JAVA9_OPTS_CNT = 6; + + opts.reserve(REQ_OPTS_CNT + JAVA9_OPTS_CNT); + + // 1. Set classpath. + std::string cpFull = "-Djava.class.path=" + cp; + + opts.push_back(CopyChars(cpFull.c_str())); + + // 3. Set Xms, Xmx. + std::string xmsStr = "-Xms" + std::to_string(xms) + "m"; + std::string xmxStr = "-Xmx" + std::to_string(xmx) + "m"; + + opts.push_back(CopyChars(xmsStr.c_str())); + opts.push_back(CopyChars(xmxStr.c_str())); + + // 4. Optional debug arguments + // std::string debugStr = + // "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"; + // opts.push_back(CopyChars(debugStr.c_str())); + + // 5. Set file.encoding. + std::string fileEncParam = "-Dfile.encoding="; + std::string fileEncFull = fileEncParam + "UTF-8"; + opts.push_back(CopyChars(fileEncFull.c_str())); + + // Adding options for Java 9 or later + if (jni::java::IsJava9OrLater()) { + opts.push_back( + CopyChars("--add-exports=java.base/" + "jdk.internal.misc=ALL-UNNAMED")); + opts.push_back(CopyChars( + "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED")); + opts.push_back( + CopyChars("--add-exports=java.management/" + "com.sun.jmx.mbeanserver=ALL-UNNAMED")); + opts.push_back( + CopyChars("--add-exports=jdk.internal.jvmstat/" + "sun.jvmstat.monitor=ALL-UNNAMED")); + opts.push_back( + CopyChars("--add-exports=java.base/" + "sun.reflect.generics.reflectiveObjects=" + "ALL-UNNAMED")); + opts.push_back(CopyChars( + "--add-opens=jdk.management/" + "com.sun.management.internal=ALL-UNNAMED")); + } + } + /* --- Startup exception. --- */ class JvmException : public std::exception { // No-op. @@ -171,55 +228,62 @@ namespace ignite delete[] errMsg; } - /** - * Guard to ensure global reference cleanup. - */ - class JniGlobalRefGuard - { - public: - JniGlobalRefGuard(JNIEnv *e, jobject obj) : env(e), ref(obj) - { - // No-op. - } - - ~JniGlobalRefGuard() - { - env->DeleteGlobalRef(ref); - } - - private: - /** Environment. */ - JNIEnv* env; - - /** Target reference. */ - jobject ref; + // Classes and method definitions. + const char* const C_THROWABLE = "java/lang/Throwable"; + JniMethod const M_THROWABLE_GET_MESSAGE = JniMethod("getMessage", "()Ljava/lang/String;", false); + JniMethod const M_THROWABLE_PRINT_STACK_TRACE = JniMethod("printStackTrace", "()V", false); - IGNITE_NO_COPY_ASSIGNMENT(JniGlobalRefGuard); - }; + const char* const C_CLASS = "java/lang/Class"; + JniMethod const M_CLASS_GET_NAME = JniMethod("getName", "()Ljava/lang/String;", false); - const char* C_THROWABLE = "java/lang/Throwable"; - JniMethod M_THROWABLE_GET_MESSAGE = JniMethod("getMessage", "()Ljava/lang/String;", false); - JniMethod M_THROWABLE_PRINT_STACK_TRACE = JniMethod("printStackTrace", "()V", false); - - const char* C_CLASS = "java/lang/Class"; - JniMethod M_CLASS_GET_NAME = JniMethod("getName", "()Ljava/lang/String;", false); - - const char* C_DOCUMENTDB_CONNECTION_PROPERTIES = + const char* const C_DOCUMENTDB_CONNECTION_PROPERTIES = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; - JniMethod M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = + JniMethod const M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = JniMethod( "getPropertiesFromConnectionString", "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", true); - const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; - - const char* C_DRIVERMANAGER = "java/sql/DriverManager"; - JniMethod M_DRIVERMANAGER_GET_CONNECTION = - JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); - - const char* C_JAVA_SQL_CONNECTION = "java/sql/Connection"; - JniMethod M_JAVA_SQL_CONNECTION_CLOSE = JniMethod("close", "()V", false); + const char* const C_RECORD_SET = "java/sql/ResultSet"; + JniMethod const M_RECORD_SET_NEXT = JniMethod("next", "()Z", false); + JniMethod const M_RECORD_SET_GET_STRING_BY_INDEX = + JniMethod( + "getString", + "(I)Ljava/lang/String;", false); + JniMethod const M_RECORD_SET_GET_STRING_BY_NAME = + JniMethod( + "getString", + "(Ljava/lang/String;)Ljava/lang/String;", false); + JniMethod const M_RECORD_SET_GET_INTEGER_BY_INDEX = + JniMethod( + "getInt", + "(I)I", false); + JniMethod const M_RECORD_SET_GET_INTEGER_BY_NAME = + JniMethod( + "getInt", + "(Ljava/lang/String;)I", false); + JniMethod const M_RECORD_SET_WAS_NULL = + JniMethod( + "wasNull", + "()Z", false); + + const char* const C_DATABASE_META_DATA = "java/sql/DatabaseMetaData"; + JniMethod const M_DATABASE_META_DATA_GET_TABLES = + JniMethod("getTables", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/ResultSet;", + false); + + const char* const C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; + + const char* const C_DRIVERMANAGER = "java/sql/DriverManager"; + JniMethod const M_DRIVERMANAGER_GET_CONNECTION = + JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); + + const char* const C_JAVA_SQL_CONNECTION = "java/sql/Connection"; + JniMethod const M_JAVA_SQL_CONNECTION_CLOSE = JniMethod("close", "()V", false); + JniMethod const M_JAVA_SQL_CONNECTION_GET_META_DATA = + JniMethod("getMetaData", + "()Ljava/sql/DatabaseMetaData;", false); // TODO: Provide a "getFullStackTrace" from DocumentDB //JniMethod M_PLATFORM_UTILS_GET_FULL_STACK_TRACE = JniMethod("getFullStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;", true); @@ -432,8 +496,20 @@ namespace ignite c_DriverManager = FindClass(env, C_DRIVERMANAGER); m_DriverManagerGetConnection = FindMethod(env, c_DriverManager, M_DRIVERMANAGER_GET_CONNECTION); - c_JavaSqlConnection = FindClass(env, C_JAVA_SQL_CONNECTION); - m_JavaSqlConnectionClose = FindMethod(env, c_JavaSqlConnection, M_JAVA_SQL_CONNECTION_CLOSE); + c_ResultSet = FindClass(env, C_RECORD_SET); + m_ResultSetNext = FindMethod(env, c_ResultSet, M_RECORD_SET_NEXT); + m_ResultSetGetStringByIndex = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_STRING_BY_INDEX); + m_ResultSetGetStringByName = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_STRING_BY_NAME); + m_ResultSetGetIntegerByIndex = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_INTEGER_BY_INDEX); + m_ResultSetGetIntegerByName = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_INTEGER_BY_NAME); + m_ResultSetWasNull = FindMethod(env, c_ResultSet, M_RECORD_SET_WAS_NULL); + + c_DatabaseMetaData = FindClass(env, C_DATABASE_META_DATA); + m_DatabaseMetaDataGetTables = FindMethod(env, c_DatabaseMetaData, M_DATABASE_META_DATA_GET_TABLES); + + c_Connection = FindClass(env, C_JAVA_SQL_CONNECTION); + m_ConnectionClose = FindMethod(env, c_Connection, M_JAVA_SQL_CONNECTION_CLOSE); + m_ConnectionGetMetaData = FindMethod(env, c_Connection, M_JAVA_SQL_CONNECTION_GET_META_DATA); } void JniMembers::Destroy(JNIEnv* env) { @@ -469,6 +545,19 @@ namespace ignite return members; } + GlobalJObject::GlobalJObject(JNIEnv* e, jobject obj) : env(e), ref(obj) { + // No-op. + } + + GlobalJObject::~GlobalJObject() { + env->DeleteGlobalRef(ref); + } + + jobject GlobalJObject::GetRef() const { + return ref; + } + + /** * Create JVM. */ @@ -508,23 +597,18 @@ namespace ignite } void RegisterNatives(JNIEnv* env) { - { - JNINativeMethod methods[5]; - - int idx = 0; - - // TODO: Investigate registering callbacks to get console and logging streams. - - //AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_CONSOLE_WRITE, reinterpret_cast(JniConsoleWrite)); - - //AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_LOG, reinterpret_cast(JniLoggerLog)); - //AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_IS_LEVEL_ENABLED, reinterpret_cast(JniLoggerIsLevelEnabled)); - - //jint res = env->RegisterNatives(FindClass(env, C_PLATFORM_CALLBACK_UTILS), methods, idx); - - //if (res != JNI_OK) - // throw JvmException(); - } + // TODO: Investigate registering callbacks to get console and logging streams. + + // JNINativeMethod methods[5]; + // int idx = 0; + // AddNativeMethod(methods + idx++, + // M_PLATFORM_CALLBACK_UTILS_CONSOLE_WRITE, + // reinterpret_cast(JniConsoleWrite)); + // AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_LOG, reinterpret_cast(JniLoggerLog)); + // AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_IS_LEVEL_ENABLED, reinterpret_cast(JniLoggerIsLevelEnabled)); + // jint res = env->RegisterNatives(FindClass(env, C_PLATFORM_CALLBACK_UTILS), methods, idx); + // if (res != JNI_OK) + // throw JvmException(); } JniContext::JniContext(JniJvm* jvm, JniHandlers hnds) : jvm(jvm), hnds(hnds) { @@ -721,29 +805,250 @@ namespace ignite } } - jobject JniContext::DocumentDbConnect(const char* connectionString, - JniErrorInfo* errInfo) { + bool JniContext::DriverManagerGetConnection( + const char* connectionString, + SharedPointer< GlobalJObject >& connection, + JniErrorInfo* errInfo) { JNIEnv* env = Attach(); - jstring jConnectionString = - env->NewStringUTF(connectionString); - jobject connection = env->CallStaticObjectMethod( + jstring jConnectionString = env->NewStringUTF(connectionString); + jobject result = env->CallStaticObjectMethod( jvm->GetMembers().c_DriverManager, - jvm->GetMembers().m_DriverManagerGetConnection, jConnectionString); + jvm->GetMembers().m_DriverManagerGetConnection, + jConnectionString); ExceptionCheck(env, errInfo); - return connection; + if (!result) { + connection = SharedPointer< GlobalJObject >(nullptr); + return false; + } + connection = SharedPointer< GlobalJObject >(new GlobalJObject(env, env->NewGlobalRef(result))); + return true; } - void JniContext::DocumentDbDisconnect(const jobject connection, JniErrorInfo* errInfo) { - if (!connection) { + void JniContext::ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo) { + if (!connection.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "Connection object must be set."; return; } JNIEnv* env = Attach(); - env->CallVoidMethod(connection, jvm->GetMembers().m_JavaSqlConnectionClose); + env->CallVoidMethod(connection.Get()->GetRef(), + jvm->GetMembers().m_ConnectionClose); + ExceptionCheck(env, errInfo); + } + + bool JniContext::ConnectionGetMetaData( + const SharedPointer< GlobalJObject >& connection, + SharedPointer< GlobalJObject >& databaseMetaData, + JniErrorInfo* errInfo) { + if (!connection.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "Connection object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + connection.Get()->GetRef(), + jvm->GetMembers().m_ConnectionGetMetaData); + ExceptionCheck(env, errInfo); + + if (!result || errInfo->code != IGNITE_JNI_ERR_SUCCESS) { + databaseMetaData = SharedPointer< GlobalJObject >(nullptr); + return false; + } + + databaseMetaData = SharedPointer< GlobalJObject >( + new GlobalJObject(env, env->NewGlobalRef(result))); + return true; + } + + bool JniContext::DatabaseMetaDataGetTables( + const SharedPointer< GlobalJObject >& databaseMetaData, + SharedPointer< GlobalJObject >& resultSet, + JniErrorInfo* errInfo) { + if (!databaseMetaData.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "DatabaseMetaData object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + databaseMetaData.Get()->GetRef(), + jvm->GetMembers().m_DatabaseMetaDataGetTables, + /* catalog */ nullptr, + /* schemaPattern */ nullptr, + /* tableNamePattern */ nullptr, + /* types[]*/ nullptr); + ExceptionCheck(env, errInfo); + + if (!result || errInfo->code != IGNITE_JNI_ERR_SUCCESS) { + resultSet = SharedPointer< GlobalJObject >(nullptr); + return false; + } + + resultSet = SharedPointer< GlobalJObject >( + new GlobalJObject(env, env->NewGlobalRef(result))); + return true; + } + + bool JniContext::ResultSetNext( + const SharedPointer< GlobalJObject >& resultSet, + bool& hasNext, JniErrorInfo* errInfo) { + if (!resultSet.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jboolean res = env->CallBooleanMethod( + resultSet.Get()->GetRef(), + jvm->GetMembers().m_ResultSetNext); + ExceptionCheck(env, errInfo); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + hasNext = res != JNI_TRUE; + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetString(const jobject resultSet, + int columnIndex, + std::string& value, + bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + resultSet, jvm->GetMembers().m_ResultSetGetStringByIndex, + columnIndex); + ExceptionCheck(env, errInfo); + + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + wasNull = !result; + if (result != nullptr) { + jboolean isCopy; + const char* utfChars = env->GetStringUTFChars( + (jstring)result, &isCopy); + value = std::string(utfChars); + env->ReleaseStringUTFChars((jstring)result, + utfChars); + } + } + + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetString(const jobject resultSet, + const std::string& columnName, + std::string& value, + bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + resultSet, jvm->GetMembers().m_ResultSetGetStringByName, + columnName); ExceptionCheck(env, errInfo); - env->DeleteLocalRef(connection); + + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + wasNull = !result; + if (result != nullptr) { + jboolean isCopy; + const char* utfChars = env->GetStringUTFChars( + (jstring)result, &isCopy); + value = std::string(utfChars); + env->ReleaseStringUTFChars((jstring)result, + utfChars); + } + } + + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetInteger(const jobject resultSet, + int columnIndex, + int& value, + bool& wasNull, + JniErrorInfo* errInfo) { + + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jint result = env->CallIntMethod( + resultSet, + jvm->GetMembers().m_ResultSetGetIntegerByIndex, + columnIndex); + ExceptionCheck(env, errInfo); + + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + value = result; + return ResultSetWasNull(resultSet, wasNull, errInfo); + } + + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetInteger(const jobject resultSet, + const std::string& columnName, + int& value, + bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jint result = env->CallIntMethod( + resultSet, + jvm->GetMembers().m_ResultSetGetIntegerByName, + columnName); + ExceptionCheck(env, errInfo); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + value = result; + return ResultSetWasNull(resultSet, wasNull, errInfo); + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetWasNull(const jobject resultSet, + bool& value, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + bool res = env->CallBooleanMethod( + resultSet, jvm->GetMembers().m_ResultSetWasNull); + ExceptionCheck(env, errInfo); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + value = res; + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; } - int64_t JniContext::TargetInLongOutLong(jobject obj, int opType, int64_t val, JniErrorInfo* err) { + int64_t JniContext::TargetInLongOutLong(jobject obj, int opType, + int64_t val, + JniErrorInfo* err) { JNIEnv* env = Attach(); int64_t res = env->CallLongMethod(obj, jvm->GetMembers().m_PlatformTarget_inLongOutLong, opType, val); diff --git a/src/odbc/src/jni/os/linux/utils.cpp b/src/odbc/src/jni/os/linux/utils.cpp index 6fd4d6e7a..fcb4a7d41 100644 --- a/src/odbc/src/jni/os/linux/utils.cpp +++ b/src/odbc/src/jni/os/linux/utils.cpp @@ -24,8 +24,8 @@ #include #include -#include "ignite/common/utils.h" -#include "ignite/common/fixed_size_array.h" +#include "ignite/odbc/common/utils.h" +#include "ignite/odbc/common/fixed_size_array.h" #include "ignite/odbc/jni/utils.h" #include "ignite/odbc/jni/java.h" diff --git a/src/odbc/src/jni/os/win/utils.cpp b/src/odbc/src/jni/os/win/utils.cpp index e41fb56af..ddeb05c59 100644 --- a/src/odbc/src/jni/os/win/utils.cpp +++ b/src/odbc/src/jni/os/win/utils.cpp @@ -18,15 +18,15 @@ #include #include -#include "ignite/common/concurrent.h" -#include "ignite/common/utils.h" -#include "ignite/common/fixed_size_array.h" +#include "ignite/odbc/common/concurrent.h" +#include "ignite/odbc/common/utils.h" +#include "ignite/odbc/common/fixed_size_array.h" #include "ignite/odbc/jni/utils.h" #include "ignite/odbc/jni/java.h" -using namespace ignite::common; -using namespace ignite::common::concurrent; +using namespace ignite::odbc::common; +using namespace ignite::odbc::common::concurrent; using namespace ignite::odbc::jni::java; @@ -409,7 +409,7 @@ namespace ignite return home; // 3. Check current work dir. - DWORD curDirLen = GetCurrentDirectoryA(0, NULL); + DWORD curDirLen = GetCurrentDirectoryA(0, nullptr); if (!curDirLen) return std::string(); From 3ad4c66d61e08331757c66c7d3e2c1d36d8fb96b Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 09:25:37 -0800 Subject: [PATCH 05/32] [AD-427] Fix Mac build. --- src/odbc/src/jni/java.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 573c499be..ee5077582 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -956,9 +956,10 @@ namespace ignite } JNIEnv* env = Attach(); + jstring jColumnName = env->NewStringUTF(columnName.c_str()); jobject result = env->CallObjectMethod( resultSet, jvm->GetMembers().m_ResultSetGetStringByName, - columnName); + jColumnName); ExceptionCheck(env, errInfo); if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { @@ -1015,10 +1016,11 @@ namespace ignite } JNIEnv* env = Attach(); + jstring jColumnName = env->NewStringUTF(columnName.c_str()); jint result = env->CallIntMethod( resultSet, jvm->GetMembers().m_ResultSetGetIntegerByName, - columnName); + jColumnName); ExceptionCheck(env, errInfo); if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { value = result; From 460ac614a10100afc4508e4431daedf53941e285 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 09:34:24 -0800 Subject: [PATCH 06/32] [AD-427] Fix Mac build. --- src/odbc/src/jni/os/linux/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc/src/jni/os/linux/utils.cpp b/src/odbc/src/jni/os/linux/utils.cpp index fcb4a7d41..a4ab1f47e 100644 --- a/src/odbc/src/jni/os/linux/utils.cpp +++ b/src/odbc/src/jni/os/linux/utils.cpp @@ -30,7 +30,7 @@ #include "ignite/odbc/jni/utils.h" #include "ignite/odbc/jni/java.h" -using namespace ignite::common; +using namespace ignite::odbc::common; using namespace ignite::odbc::jni::java; namespace ignite From af5780fed1693adc5ecadf1f091d8df67dfb79d5 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 09:46:41 -0800 Subject: [PATCH 07/32] [AD-427] Fix Windows build. --- scripts/build_driver.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build_driver.ps1 b/scripts/build_driver.ps1 index 7a38234d1..f6211738d 100644 --- a/scripts/build_driver.ps1 +++ b/scripts/build_driver.ps1 @@ -19,6 +19,7 @@ $CMAKE_TOOLCHAIN_FILE = -join($env:VCPKG_ROOT, "/scripts/buildsystems/vcpkg.cmak cmake -S $SRC_DIR ` -B $BUILD_DIR ` -A $WIN_ARCH ` + -G "Visual Studio 15 2017" -D CMAKE_BUILD_TYPE=$CONFIGURATION ` -D CMAKE_INSTALL_PREFIX=$INSTALL_DIR ` -D WITH_TESTS=ON ` From 1f52bc2966b43331ee83ea0ffb1cbba71a37a1bb Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 10:04:20 -0800 Subject: [PATCH 08/32] [AD-427] Fix Windows build. --- scripts/build_driver.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/build_driver.ps1 b/scripts/build_driver.ps1 index f6211738d..7a38234d1 100644 --- a/scripts/build_driver.ps1 +++ b/scripts/build_driver.ps1 @@ -19,7 +19,6 @@ $CMAKE_TOOLCHAIN_FILE = -join($env:VCPKG_ROOT, "/scripts/buildsystems/vcpkg.cmak cmake -S $SRC_DIR ` -B $BUILD_DIR ` -A $WIN_ARCH ` - -G "Visual Studio 15 2017" -D CMAKE_BUILD_TYPE=$CONFIGURATION ` -D CMAKE_INSTALL_PREFIX=$INSTALL_DIR ` -D WITH_TESTS=ON ` From 0e2afc3b7b7680bd5d6e43641c000ab44338c0e5 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 11:07:07 -0800 Subject: [PATCH 09/32] [AD-427] Fix Windows build. --- .github/workflows/win-build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/win-build.yml b/.github/workflows/win-build.yml index b02b4b8f5..4b7202684 100644 --- a/.github/workflows/win-build.yml +++ b/.github/workflows/win-build.yml @@ -49,8 +49,8 @@ jobs: run: | echo "C:\Program Files (x86)\WiX Toolset v3.11\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Get specific version CMake, v3.20.1 - uses: lukka/get-cmake@v3.20.1 + - name: Get latest version CMake + uses: lukka/get-cmake@latest - name: add-msbuild-to-path uses: microsoft/setup-msbuild@v1.0.2 @@ -137,8 +137,8 @@ jobs: run: | echo "C:\Program Files (x86)\WiX Toolset v3.11\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Get specific version CMake, v3.20.1 - uses: lukka/get-cmake@v3.20.1 + - name: Get latest version CMake + uses: lukka/get-cmake@latest - name: add-msbuild-to-path uses: microsoft/setup-msbuild@v1.0.2 @@ -212,8 +212,8 @@ jobs: # - name: "Update path for Java" # run: | # echo "${{ env.JAVA_HOME }}\bin\server" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # - name: Get specific version CMake, v3.20.1 - # uses: lukka/get-cmake@v3.20.1 + # - name: Get latest version CMake + # uses: lukka/get-cmake@latest # - name: add-msbuild-to-path # uses: microsoft/setup-msbuild@v1.0.2 # - name: setup-opencppcoverage-and-add-to-path From 749a1c8dea19f7b889c0f9564ba5e53b5d63a593 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 13:16:42 -0800 Subject: [PATCH 10/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 44a469c8f..01866de6f 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -116,7 +116,8 @@ endif() add_executable(${TARGET} ${SOURCES}) target_link_libraries(${TARGET} ${ODBC_LIBRARIES}) -target_link_libraries(${TARGET} ${Boost_LIBRARIES} ignite ${ODBC_LIBRARY}) +target_link_libraries(${TARGET} ${ODBC_LIBRARY}) +target_link_libraries(${TARGET} ${Boost_LIBRARIES} ignite) target_code_coverage(${TARGET} PUBLIC AUTO ALL) if (WIN32) @@ -127,7 +128,8 @@ if (WIN32) endif() else() - add_definitions(-DBOOST_TEST_DYN_LINK) + add_definitions(-DBOOST_TEST_DYN_LINK)] + target_link_libraries(${TARGET} odbccp32) endif() set(TEST_TARGET IgniteOdbcTest) From 37acdf11d9102bd255b2d1f77edacd3c4c7e995e Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 13:20:46 -0800 Subject: [PATCH 11/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 01866de6f..36c4d3bad 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -128,7 +128,7 @@ if (WIN32) endif() else() - add_definitions(-DBOOST_TEST_DYN_LINK)] + add_definitions(-DBOOST_TEST_DYN_LINK) target_link_libraries(${TARGET} odbccp32) endif() From e6df2db401330c81b30fb9be4418d849f75fe509 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 13:38:25 -0800 Subject: [PATCH 12/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 36c4d3bad..70f1631e8 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -129,7 +129,7 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) - target_link_libraries(${TARGET} odbccp32) + target_link_libraries(${TARGET} odbcinst) endif() set(TEST_TARGET IgniteOdbcTest) From 22bf6f317967baee79319ab5a8cc9e533a6610a5 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 13:57:10 -0800 Subject: [PATCH 13/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 70f1631e8..f1eb7fdb1 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -129,7 +129,7 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) - target_link_libraries(${TARGET} odbcinst) + target_link_libraries(${TARGET} odbc) endif() set(TEST_TARGET IgniteOdbcTest) From d85c63f257bf54a383cb83792a02d703bca23add Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 14:08:00 -0800 Subject: [PATCH 14/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index f1eb7fdb1..103103d74 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -129,7 +129,7 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) - target_link_libraries(${TARGET} odbc) + target_link_libraries(${TARGET} libodbc) endif() set(TEST_TARGET IgniteOdbcTest) From 0d048131f2ee2856ae22cfd73b3011c163fd9169 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 14:15:19 -0800 Subject: [PATCH 15/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 103103d74..668eddff9 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -129,7 +129,6 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) - target_link_libraries(${TARGET} libodbc) endif() set(TEST_TARGET IgniteOdbcTest) From af198102136858a17e3b74ba347cd1c256571972 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Tue, 1 Feb 2022 14:33:49 -0800 Subject: [PATCH 16/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 668eddff9..49533a7ca 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -129,6 +129,7 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) + target_link_libraries(${TARGET} libodbcinst) endif() set(TEST_TARGET IgniteOdbcTest) From 81d13024148b8c19f7100cea2357caf27a4691ad Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 2 Feb 2022 10:23:19 -0800 Subject: [PATCH 17/32] [AD-521] add changes for Java.cpp from Bruce's AD-427 branch * those changes are not included in the previous merge, and are now added --- src/odbc/src/jni/java.cpp | 464 +++++++++++++++++++++++++++++++------- 1 file changed, 382 insertions(+), 82 deletions(-) diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 58ce058fc..ee5077582 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -23,11 +23,13 @@ #include #include +#include #include +#include #include #include -#include -#include + +using namespace ignite::odbc::common::concurrent; #ifndef JNI_VERSION_9 #define JNI_VERSION_9 0x00090000 @@ -114,9 +116,63 @@ namespace ignite return JNI_GetDefaultJavaVMInitArgs(&args) == JNI_OK; } + void BuildJvmOptions( + const std::string& cp, std::vector< char* >& opts, + int xms, int xmx) { + using namespace common; + + const size_t REQ_OPTS_CNT = 4; + const size_t JAVA9_OPTS_CNT = 6; + + opts.reserve(REQ_OPTS_CNT + JAVA9_OPTS_CNT); + + // 1. Set classpath. + std::string cpFull = "-Djava.class.path=" + cp; + + opts.push_back(CopyChars(cpFull.c_str())); + + // 3. Set Xms, Xmx. + std::string xmsStr = "-Xms" + std::to_string(xms) + "m"; + std::string xmxStr = "-Xmx" + std::to_string(xmx) + "m"; + + opts.push_back(CopyChars(xmsStr.c_str())); + opts.push_back(CopyChars(xmxStr.c_str())); + + // 4. Optional debug arguments + // std::string debugStr = + // "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"; + // opts.push_back(CopyChars(debugStr.c_str())); + + // 5. Set file.encoding. + std::string fileEncParam = "-Dfile.encoding="; + std::string fileEncFull = fileEncParam + "UTF-8"; + opts.push_back(CopyChars(fileEncFull.c_str())); + + // Adding options for Java 9 or later + if (jni::java::IsJava9OrLater()) { + opts.push_back( + CopyChars("--add-exports=java.base/" + "jdk.internal.misc=ALL-UNNAMED")); + opts.push_back(CopyChars( + "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED")); + opts.push_back( + CopyChars("--add-exports=java.management/" + "com.sun.jmx.mbeanserver=ALL-UNNAMED")); + opts.push_back( + CopyChars("--add-exports=jdk.internal.jvmstat/" + "sun.jvmstat.monitor=ALL-UNNAMED")); + opts.push_back( + CopyChars("--add-exports=java.base/" + "sun.reflect.generics.reflectiveObjects=" + "ALL-UNNAMED")); + opts.push_back(CopyChars( + "--add-opens=jdk.management/" + "com.sun.management.internal=ALL-UNNAMED")); + } + } + /* --- Startup exception. --- */ - class JvmException : public std::exception - { + class JvmException : public std::exception { // No-op. }; @@ -172,60 +228,62 @@ namespace ignite delete[] errMsg; } - /** - * Guard to ensure global reference cleanup. - */ - class JniGlobalRefGuard - { - public: - JniGlobalRefGuard(JNIEnv *e, jobject obj) : env(e), ref(obj) - { - // No-op. - } - - ~JniGlobalRefGuard() - { - env->DeleteGlobalRef(ref); - } - - private: - /** Environment. */ - JNIEnv* env; - - /** Target reference. */ - jobject ref; - - IGNITE_NO_COPY_ASSIGNMENT(JniGlobalRefGuard); - }; - - const char* C_THROWABLE = "java/lang/Throwable"; - JniMethod M_THROWABLE_GET_MESSAGE = JniMethod("getMessage", "()Ljava/lang/String;", false); - JniMethod M_THROWABLE_PRINT_STACK_TRACE = JniMethod("printStackTrace", "()V", false); + // Classes and method definitions. + const char* const C_THROWABLE = "java/lang/Throwable"; + JniMethod const M_THROWABLE_GET_MESSAGE = JniMethod("getMessage", "()Ljava/lang/String;", false); + JniMethod const M_THROWABLE_PRINT_STACK_TRACE = JniMethod("printStackTrace", "()V", false); - const char* C_CLASS = "java/lang/Class"; - JniMethod M_CLASS_GET_NAME = JniMethod("getName", "()Ljava/lang/String;", false); + const char* const C_CLASS = "java/lang/Class"; + JniMethod const M_CLASS_GET_NAME = JniMethod("getName", "()Ljava/lang/String;", false); - const char* C_DOCUMENTDB_CONNECTION_PROPERTIES = + const char* const C_DOCUMENTDB_CONNECTION_PROPERTIES = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; - JniMethod M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = + JniMethod const M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = JniMethod( "getPropertiesFromConnectionString", "(Ljava/lang/String;)Lsoftware/amazon/documentdb/jdbc/DocumentDbConnectionProperties;", true); - // todo code draft -AL-. After constants all defined (define constants here), work on the JNI wrappers with Bruce - const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnection"; - JniMethod M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT = - JniMethod("getSshLocalPort", "()I", false); - - // const char* C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; - - const char* C_DRIVERMANAGER = "java/sql/DriverManager"; - JniMethod M_DRIVERMANAGER_GET_CONNECTION = - JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); // -AL- true/false defines whether it is true -> static/instance - - const char* C_JAVA_SQL_CONNECTION = "java/sql/Connection"; - JniMethod M_JAVA_SQL_CONNECTION_CLOSE = JniMethod("close", "()V", false); + const char* const C_RECORD_SET = "java/sql/ResultSet"; + JniMethod const M_RECORD_SET_NEXT = JniMethod("next", "()Z", false); + JniMethod const M_RECORD_SET_GET_STRING_BY_INDEX = + JniMethod( + "getString", + "(I)Ljava/lang/String;", false); + JniMethod const M_RECORD_SET_GET_STRING_BY_NAME = + JniMethod( + "getString", + "(Ljava/lang/String;)Ljava/lang/String;", false); + JniMethod const M_RECORD_SET_GET_INTEGER_BY_INDEX = + JniMethod( + "getInt", + "(I)I", false); + JniMethod const M_RECORD_SET_GET_INTEGER_BY_NAME = + JniMethod( + "getInt", + "(Ljava/lang/String;)I", false); + JniMethod const M_RECORD_SET_WAS_NULL = + JniMethod( + "wasNull", + "()Z", false); + + const char* const C_DATABASE_META_DATA = "java/sql/DatabaseMetaData"; + JniMethod const M_DATABASE_META_DATA_GET_TABLES = + JniMethod("getTables", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/ResultSet;", + false); + + const char* const C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; + + const char* const C_DRIVERMANAGER = "java/sql/DriverManager"; + JniMethod const M_DRIVERMANAGER_GET_CONNECTION = + JniMethod("getConnection", "(Ljava/lang/String;)Ljava/sql/Connection;", true); + + const char* const C_JAVA_SQL_CONNECTION = "java/sql/Connection"; + JniMethod const M_JAVA_SQL_CONNECTION_CLOSE = JniMethod("close", "()V", false); + JniMethod const M_JAVA_SQL_CONNECTION_GET_META_DATA = + JniMethod("getMetaData", + "()Ljava/sql/DatabaseMetaData;", false); // TODO: Provide a "getFullStackTrace" from DocumentDB //JniMethod M_PLATFORM_UTILS_GET_FULL_STACK_TRACE = JniMethod("getFullStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;", true); @@ -434,13 +492,24 @@ namespace ignite c_DocumentDbConnection = FindClass(env, C_DOCUMENTDB_CONNECTION); //m_DocumentDbConnectionInit = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_PROPERTIES_INIT); - m_DocumentDbConnectionGetSshLocalPort = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT); c_DriverManager = FindClass(env, C_DRIVERMANAGER); m_DriverManagerGetConnection = FindMethod(env, c_DriverManager, M_DRIVERMANAGER_GET_CONNECTION); - c_JavaSqlConnection = FindClass(env, C_JAVA_SQL_CONNECTION); - m_JavaSqlConnectionClose = FindMethod(env, c_JavaSqlConnection, M_JAVA_SQL_CONNECTION_CLOSE); + c_ResultSet = FindClass(env, C_RECORD_SET); + m_ResultSetNext = FindMethod(env, c_ResultSet, M_RECORD_SET_NEXT); + m_ResultSetGetStringByIndex = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_STRING_BY_INDEX); + m_ResultSetGetStringByName = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_STRING_BY_NAME); + m_ResultSetGetIntegerByIndex = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_INTEGER_BY_INDEX); + m_ResultSetGetIntegerByName = FindMethod(env, c_ResultSet, M_RECORD_SET_GET_INTEGER_BY_NAME); + m_ResultSetWasNull = FindMethod(env, c_ResultSet, M_RECORD_SET_WAS_NULL); + + c_DatabaseMetaData = FindClass(env, C_DATABASE_META_DATA); + m_DatabaseMetaDataGetTables = FindMethod(env, c_DatabaseMetaData, M_DATABASE_META_DATA_GET_TABLES); + + c_Connection = FindClass(env, C_JAVA_SQL_CONNECTION); + m_ConnectionClose = FindMethod(env, c_Connection, M_JAVA_SQL_CONNECTION_CLOSE); + m_ConnectionGetMetaData = FindMethod(env, c_Connection, M_JAVA_SQL_CONNECTION_GET_META_DATA); } void JniMembers::Destroy(JNIEnv* env) { @@ -476,6 +545,19 @@ namespace ignite return members; } + GlobalJObject::GlobalJObject(JNIEnv* e, jobject obj) : env(e), ref(obj) { + // No-op. + } + + GlobalJObject::~GlobalJObject() { + env->DeleteGlobalRef(ref); + } + + jobject GlobalJObject::GetRef() const { + return ref; + } + + /** * Create JVM. */ @@ -515,23 +597,18 @@ namespace ignite } void RegisterNatives(JNIEnv* env) { - { - JNINativeMethod methods[5]; - - int idx = 0; - - // TODO: Investigate registering callbacks to get console and logging streams. - - //AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_CONSOLE_WRITE, reinterpret_cast(JniConsoleWrite)); - - //AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_LOG, reinterpret_cast(JniLoggerLog)); - //AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_IS_LEVEL_ENABLED, reinterpret_cast(JniLoggerIsLevelEnabled)); - - //jint res = env->RegisterNatives(FindClass(env, C_PLATFORM_CALLBACK_UTILS), methods, idx); - - //if (res != JNI_OK) - // throw JvmException(); - } + // TODO: Investigate registering callbacks to get console and logging streams. + + // JNINativeMethod methods[5]; + // int idx = 0; + // AddNativeMethod(methods + idx++, + // M_PLATFORM_CALLBACK_UTILS_CONSOLE_WRITE, + // reinterpret_cast(JniConsoleWrite)); + // AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_LOG, reinterpret_cast(JniLoggerLog)); + // AddNativeMethod(methods + idx++, M_PLATFORM_CALLBACK_UTILS_LOGGER_IS_LEVEL_ENABLED, reinterpret_cast(JniLoggerIsLevelEnabled)); + // jint res = env->RegisterNatives(FindClass(env, C_PLATFORM_CALLBACK_UTILS), methods, idx); + // if (res != JNI_OK) + // throw JvmException(); } JniContext::JniContext(JniJvm* jvm, JniHandlers hnds) : jvm(jvm), hnds(hnds) { @@ -728,29 +805,252 @@ namespace ignite } } - jobject JniContext::DocumentDbConnect(const char* connectionString, - JniErrorInfo* errInfo) { + bool JniContext::DriverManagerGetConnection( + const char* connectionString, + SharedPointer< GlobalJObject >& connection, + JniErrorInfo* errInfo) { JNIEnv* env = Attach(); - jstring jConnectionString = - env->NewStringUTF(connectionString); - jobject connection = env->CallStaticObjectMethod( + jstring jConnectionString = env->NewStringUTF(connectionString); + jobject result = env->CallStaticObjectMethod( jvm->GetMembers().c_DriverManager, - jvm->GetMembers().m_DriverManagerGetConnection, jConnectionString); + jvm->GetMembers().m_DriverManagerGetConnection, + jConnectionString); ExceptionCheck(env, errInfo); - return connection; + if (!result) { + connection = SharedPointer< GlobalJObject >(nullptr); + return false; + } + connection = SharedPointer< GlobalJObject >(new GlobalJObject(env, env->NewGlobalRef(result))); + return true; } - void JniContext::DocumentDbDisconnect(const jobject connection, JniErrorInfo* errInfo) { - if (!connection) { + void JniContext::ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo) { + if (!connection.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "Connection object must be set."; return; } JNIEnv* env = Attach(); - env->CallVoidMethod(connection, jvm->GetMembers().m_JavaSqlConnectionClose); + env->CallVoidMethod(connection.Get()->GetRef(), + jvm->GetMembers().m_ConnectionClose); + ExceptionCheck(env, errInfo); + } + + bool JniContext::ConnectionGetMetaData( + const SharedPointer< GlobalJObject >& connection, + SharedPointer< GlobalJObject >& databaseMetaData, + JniErrorInfo* errInfo) { + if (!connection.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "Connection object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + connection.Get()->GetRef(), + jvm->GetMembers().m_ConnectionGetMetaData); + ExceptionCheck(env, errInfo); + + if (!result || errInfo->code != IGNITE_JNI_ERR_SUCCESS) { + databaseMetaData = SharedPointer< GlobalJObject >(nullptr); + return false; + } + + databaseMetaData = SharedPointer< GlobalJObject >( + new GlobalJObject(env, env->NewGlobalRef(result))); + return true; + } + + bool JniContext::DatabaseMetaDataGetTables( + const SharedPointer< GlobalJObject >& databaseMetaData, + SharedPointer< GlobalJObject >& resultSet, + JniErrorInfo* errInfo) { + if (!databaseMetaData.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "DatabaseMetaData object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + databaseMetaData.Get()->GetRef(), + jvm->GetMembers().m_DatabaseMetaDataGetTables, + /* catalog */ nullptr, + /* schemaPattern */ nullptr, + /* tableNamePattern */ nullptr, + /* types[]*/ nullptr); + ExceptionCheck(env, errInfo); + + if (!result || errInfo->code != IGNITE_JNI_ERR_SUCCESS) { + resultSet = SharedPointer< GlobalJObject >(nullptr); + return false; + } + + resultSet = SharedPointer< GlobalJObject >( + new GlobalJObject(env, env->NewGlobalRef(result))); + return true; + } + + bool JniContext::ResultSetNext( + const SharedPointer< GlobalJObject >& resultSet, + bool& hasNext, JniErrorInfo* errInfo) { + if (!resultSet.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jboolean res = env->CallBooleanMethod( + resultSet.Get()->GetRef(), + jvm->GetMembers().m_ResultSetNext); + ExceptionCheck(env, errInfo); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + hasNext = res != JNI_TRUE; + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetString(const jobject resultSet, + int columnIndex, + std::string& value, + bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jobject result = env->CallObjectMethod( + resultSet, jvm->GetMembers().m_ResultSetGetStringByIndex, + columnIndex); + ExceptionCheck(env, errInfo); + + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + wasNull = !result; + if (result != nullptr) { + jboolean isCopy; + const char* utfChars = env->GetStringUTFChars( + (jstring)result, &isCopy); + value = std::string(utfChars); + env->ReleaseStringUTFChars((jstring)result, + utfChars); + } + } + + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetString(const jobject resultSet, + const std::string& columnName, + std::string& value, + bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jstring jColumnName = env->NewStringUTF(columnName.c_str()); + jobject result = env->CallObjectMethod( + resultSet, jvm->GetMembers().m_ResultSetGetStringByName, + jColumnName); + ExceptionCheck(env, errInfo); + + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + wasNull = !result; + if (result != nullptr) { + jboolean isCopy; + const char* utfChars = env->GetStringUTFChars( + (jstring)result, &isCopy); + value = std::string(utfChars); + env->ReleaseStringUTFChars((jstring)result, + utfChars); + } + } + + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetInteger(const jobject resultSet, + int columnIndex, + int& value, + bool& wasNull, + JniErrorInfo* errInfo) { + + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jint result = env->CallIntMethod( + resultSet, + jvm->GetMembers().m_ResultSetGetIntegerByIndex, + columnIndex); + ExceptionCheck(env, errInfo); + + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + value = result; + return ResultSetWasNull(resultSet, wasNull, errInfo); + } + + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetGetInteger(const jobject resultSet, + const std::string& columnName, + int& value, + bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + jstring jColumnName = env->NewStringUTF(columnName.c_str()); + jint result = env->CallIntMethod( + resultSet, + jvm->GetMembers().m_ResultSetGetIntegerByName, + jColumnName); + ExceptionCheck(env, errInfo); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + value = result; + return ResultSetWasNull(resultSet, wasNull, errInfo); + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + } + + bool JniContext::ResultSetWasNull(const jobject resultSet, + bool& value, + JniErrorInfo* errInfo) { + if (!resultSet) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "ResultSet object must be set."; + return false; + } + + JNIEnv* env = Attach(); + bool res = env->CallBooleanMethod( + resultSet, jvm->GetMembers().m_ResultSetWasNull); ExceptionCheck(env, errInfo); - env->DeleteLocalRef(connection); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + value = res; + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; } - int64_t JniContext::TargetInLongOutLong(jobject obj, int opType, int64_t val, JniErrorInfo* err) { + int64_t JniContext::TargetInLongOutLong(jobject obj, int opType, + int64_t val, + JniErrorInfo* err) { JNIEnv* env = Attach(); int64_t res = env->CallLongMethod(obj, jvm->GetMembers().m_PlatformTarget_inLongOutLong, opType, val); From 77e9489a3ff9dc2ccb04a724ae5e28cc8728298b Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Wed, 2 Feb 2022 10:46:22 -0800 Subject: [PATCH 18/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 49533a7ca..1c0782395 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -116,7 +116,6 @@ endif() add_executable(${TARGET} ${SOURCES}) target_link_libraries(${TARGET} ${ODBC_LIBRARIES}) -target_link_libraries(${TARGET} ${ODBC_LIBRARY}) target_link_libraries(${TARGET} ${Boost_LIBRARIES} ignite) target_code_coverage(${TARGET} PUBLIC AUTO ALL) From f8a7225abee0337b0e882da998d2a11d8dbee8b6 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Wed, 2 Feb 2022 11:02:26 -0800 Subject: [PATCH 19/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 1c0782395..96bde3c61 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -128,7 +128,7 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) - target_link_libraries(${TARGET} libodbcinst) + target_link_libraries(${TARGET} odbcinst) endif() set(TEST_TARGET IgniteOdbcTest) From db8a769a4c7d4f75bfc187389a664972091ec32a Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Wed, 2 Feb 2022 11:39:06 -0800 Subject: [PATCH 20/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 96bde3c61..94e65eaee 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -128,7 +128,7 @@ if (WIN32) else() add_definitions(-DBOOST_TEST_DYN_LINK) - target_link_libraries(${TARGET} odbcinst) + target_link_libraries(${TARGET} iodbcinst) endif() set(TEST_TARGET IgniteOdbcTest) From 49085ee0e8c7f35fb2edd6e325d14e05bcb6681d Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Wed, 2 Feb 2022 12:12:37 -0800 Subject: [PATCH 21/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 94e65eaee..1842c3d45 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -124,11 +124,12 @@ if (WIN32) add_definitions(-DTARGET_MODULE_FULL_NAME="$") if (MSVC_VERSION GREATER_EQUAL 1900) target_link_libraries(${TARGET} legacy_stdio_definitions odbccp32 shlwapi) - endif() - -else() +else(APPLE) add_definitions(-DBOOST_TEST_DYN_LINK) target_link_libraries(${TARGET} iodbcinst) +else() + add_definitions(-DBOOST_TEST_DYN_LINK) + target_link_libraries(${TARGET} odbcinst) endif() set(TEST_TARGET IgniteOdbcTest) From 09e1f3006a324fa0c7958c94eb982cf0f4a312fc Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Wed, 2 Feb 2022 12:16:45 -0800 Subject: [PATCH 22/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 1842c3d45..99e86720b 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -124,7 +124,7 @@ if (WIN32) add_definitions(-DTARGET_MODULE_FULL_NAME="$") if (MSVC_VERSION GREATER_EQUAL 1900) target_link_libraries(${TARGET} legacy_stdio_definitions odbccp32 shlwapi) -else(APPLE) +elseif(APPLE) add_definitions(-DBOOST_TEST_DYN_LINK) target_link_libraries(${TARGET} iodbcinst) else() From e5eb2dc96da86d77e5ce8fdd4719e32f3bd1af29 Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Wed, 2 Feb 2022 12:22:03 -0800 Subject: [PATCH 23/32] [AD-427] Fix Mac build. --- src/odbc-test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/odbc-test/CMakeLists.txt b/src/odbc-test/CMakeLists.txt index 99e86720b..8edf04dbc 100644 --- a/src/odbc-test/CMakeLists.txt +++ b/src/odbc-test/CMakeLists.txt @@ -124,6 +124,7 @@ if (WIN32) add_definitions(-DTARGET_MODULE_FULL_NAME="$") if (MSVC_VERSION GREATER_EQUAL 1900) target_link_libraries(${TARGET} legacy_stdio_definitions odbccp32 shlwapi) + endif() elseif(APPLE) add_definitions(-DBOOST_TEST_DYN_LINK) target_link_libraries(${TARGET} iodbcinst) From b29dd7173afd0e1877c488145536b4f19a89e1a2 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 2 Feb 2022 13:46:45 -0800 Subject: [PATCH 24/32] [AD-521] JNI wrapper calls to iSshTunnelActive and getSshLocalPort * some draft comments are left to be cleaned up --- src/odbc/include/ignite/odbc/jni/java.h | 4 ++ src/odbc/src/jni/java.cpp | 59 +++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/odbc/include/ignite/odbc/jni/java.h b/src/odbc/include/ignite/odbc/jni/java.h index 02fdaae05..c7f49719b 100644 --- a/src/odbc/include/ignite/odbc/jni/java.h +++ b/src/odbc/include/ignite/odbc/jni/java.h @@ -257,6 +257,7 @@ namespace ignite { jclass c_DocumentDbConnection; jmethodID m_DocumentDbConnectionGetSshLocalPort; + jmethodID m_DocumentDbConnectionIsSshTunnelActive; jmethodID m_DocumentDbConnectionInit; jmethodID m_DocumentDbClose; @@ -446,6 +447,9 @@ namespace ignite { void ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); bool ConnectionGetMetaData(const SharedPointer< GlobalJObject >& connection, SharedPointer< GlobalJObject>& databaseMetaData, JniErrorInfo* errInfo); + bool DocumentDbIsSshTunnelActive(const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo* errInfo); + int32_t DocumentDbGetSshLocalPort(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); + bool DatabaseMetaDataGetTables(const SharedPointer< GlobalJObject >& databaseMetaData, SharedPointer< GlobalJObject >& resultSet, JniErrorInfo* errInfo); bool ResultSetNext(const SharedPointer< GlobalJObject >& resultSet, bool& hasNext, diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index ee5077582..dc562f593 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -274,6 +274,14 @@ namespace ignite false); const char* const C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; + // todo code draft -AL-. After constants all defined (define + // constants here), work on the JNI wrappers with Bruce + JniMethod const M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT = + JniMethod("getSshLocalPort", "()Ljava/util/Optional;", false); +// JniMethod("getSshLocalPort", "()Ljava/util/Optional;", false); + // todo add call for isSshTunnelActive + JniMethod const M_DOCUMENTDB_CONNECTION_IS_SSH_TUNNEL_ACTIVE = + JniMethod("isSshTunnelActive", "()B", false); const char* const C_DRIVERMANAGER = "java/sql/DriverManager"; JniMethod const M_DRIVERMANAGER_GET_CONNECTION = @@ -492,6 +500,8 @@ namespace ignite c_DocumentDbConnection = FindClass(env, C_DOCUMENTDB_CONNECTION); //m_DocumentDbConnectionInit = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_PROPERTIES_INIT); + m_DocumentDbConnectionGetSshLocalPort = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT); + m_DocumentDbConnectionIsSshTunnelActive = FindMethod(env, c_DocumentDbConnection, M_DOCUMENTDB_CONNECTION_IS_SSH_TUNNEL_ACTIVE); c_DriverManager = FindClass(env, C_DRIVERMANAGER); m_DriverManagerGetConnection = FindMethod(env, c_DriverManager, M_DRIVERMANAGER_GET_CONNECTION); @@ -824,6 +834,55 @@ namespace ignite return true; } + // note to self: result is stored in bool poiner isActive, this is to be consistent with other functions that + // use CallBooleanMethod. -AL- + bool JniContext::DocumentDbIsSshTunnelActive( + const SharedPointer< GlobalJObject >& connection, + bool& isActive, + JniErrorInfo* errInfo) { + // to do implement -AL- + if (!connection.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "Connection object must be set."; + return false; + } + JNIEnv* env = Attach(); + jboolean res = env->CallBooleanMethod( + jvm->GetMembers().c_DocumentDbConnection, + jvm->GetMembers().m_DocumentDbConnectionIsSshTunnelActive); + ExceptionCheck(env, errInfo); + if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + isActive = res != JNI_TRUE; + } + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + // return result; + } + + int32_t JniContext::DocumentDbGetSshLocalPort( + const SharedPointer< GlobalJObject >& connection, + JniErrorInfo* errInfo) { + if (!connection.Get()) { + errInfo->code = IGNITE_JNI_ERR_GENERIC; + errInfo->errMsg = "Connection object must be set."; + return false; + } + JNIEnv* env = Attach(); + int32_t result = env->CallIntMethod( + jvm->GetMembers().c_DocumentDbConnection, + jvm->GetMembers().m_DocumentDbConnectionGetSshLocalPort); + //jobject result = env->CallObjectMethod( + // jvm->GetMembers().c_DocumentDbConnection, + // jvm->GetMembers().m_DocumentDbConnectionGetSshLocalPort); + ExceptionCheck(env, errInfo); + //if (!result) { + // // unable to return object + // return 0; + //} else if (result.isPresent()) { + // return result.get().getInt(); + //} + return result; + } + void JniContext::ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo) { if (!connection.Get()) { errInfo->code = IGNITE_JNI_ERR_GENERIC; From bfb2b578d8e8a55005235afba25ad81be509ccf5 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 2 Feb 2022 14:42:20 -0800 Subject: [PATCH 25/32] [AD-521] debug getSshLocalPort * change function type signature from optional to int * refactor - remove comments --- src/odbc/src/jni/java.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index dc562f593..6da400326 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -274,12 +274,8 @@ namespace ignite false); const char* const C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; - // todo code draft -AL-. After constants all defined (define - // constants here), work on the JNI wrappers with Bruce JniMethod const M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT = - JniMethod("getSshLocalPort", "()Ljava/util/Optional;", false); -// JniMethod("getSshLocalPort", "()Ljava/util/Optional;", false); - // todo add call for isSshTunnelActive + JniMethod("getSshLocalPort", "()I;", false); JniMethod const M_DOCUMENTDB_CONNECTION_IS_SSH_TUNNEL_ACTIVE = JniMethod("isSshTunnelActive", "()B", false); From 58b11caf26fe1b02a65e8115cb0fde558f03e6bf Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 2 Feb 2022 18:06:18 -0800 Subject: [PATCH 26/32] [AD-521] change return value in getSshLocalPort from boolean to a 0 * try to fix access memory issue in TestDriverManagerGetConnection --- src/odbc-test/src/java_test.cpp | 3 ++- src/odbc/src/jni/java.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp index 36ffacdcd..aac4449cc 100644 --- a/src/odbc-test/src/java_test.cpp +++ b/src/odbc-test/src/java_test.cpp @@ -158,7 +158,8 @@ BOOST_AUTO_TEST_CASE(TestDriverManagerGetConnection) BOOST_REQUIRE(connection.Get()); _ctx.Get()->ConnectionClose(connection, &errInfo); - connection = SharedPointer< GlobalJObject >(nullptr); + //connection = SharedPointer< GlobalJObject >(nullptr); + connection = nullptr; // attempt to fix read error -AL- } BOOST_AUTO_TEST_CASE(TestConnectionGetMetaData) { diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 6da400326..3e759e962 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -836,7 +836,6 @@ namespace ignite const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo* errInfo) { - // to do implement -AL- if (!connection.Get()) { errInfo->code = IGNITE_JNI_ERR_GENERIC; errInfo->errMsg = "Connection object must be set."; @@ -860,7 +859,8 @@ namespace ignite if (!connection.Get()) { errInfo->code = IGNITE_JNI_ERR_GENERIC; errInfo->errMsg = "Connection object must be set."; - return false; + return 0; + // TODO double check with Bruce: should I just return 0 here? } JNIEnv* env = Attach(); int32_t result = env->CallIntMethod( From e59c35fdf6849d2316c8908cc2359abdc519455a Mon Sep 17 00:00:00 2001 From: Bruce Irschick Date: Thu, 3 Feb 2022 15:08:37 -0800 Subject: [PATCH 27/32] [AD-427] Added ResultSet.next and ResultSet.GetString() --- README.md | 11 +++++++ src/odbc-test/src/java_test.cpp | 41 ++++++++++++++++++++++-- src/odbc/include/ignite/odbc/jni/java.h | 13 ++++++-- src/odbc/src/jni/java.cpp | 42 ++++++++++++++++++------- 4 files changed, 90 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 7db369e0d..3083793b9 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,17 @@ ## Development Environment +### Environment Variables for Testing Accounts/Secrets + +The enable the test environment to run the tests against a live DocumentDB system, +set the follwoing environment variables + +1. `DOC_DB_HOST=` (e.g.: `docdb-host.cluster-cjf6q8nxfefi.us-east-2.docdb.amazonaws.com`) +2. `DOC_DB_PRIV_KEY_FILE=` (e.g.: `~/.ssh/ssh_host.pem`) +3. `DOC_DB_PASSWORD=` +4. `DOC_DB_USER=` (e.g., ec2-user@3.139.97.218) +5. `DOC_DB_USER_NAME=` + ### Windows 1. Microsoft Visual Studio (Community 2019 Verified) diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp index 36ffacdcd..09a079acf 100644 --- a/src/odbc-test/src/java_test.cpp +++ b/src/odbc-test/src/java_test.cpp @@ -92,7 +92,7 @@ struct JavaTestSuiteFixture: odbc::OdbcTestSuite SharedPointer< JniContext > ctx(JniContext::Create( &opts[0], static_cast< int >(opts.size()), JniHandlers())); - BOOST_CHECK(ctx.Get()); + BOOST_CHECK(ctx.Get() != nullptr); return ctx; } @@ -206,15 +206,50 @@ BOOST_AUTO_TEST_CASE(TestDatabaseMetaDataGetTables) { } BOOST_REQUIRE(databaseMetaData.Get()); + std::string catalog; + std::string schemaPattern; + std::string tableNamePattern; + std::vector< std::string > types({"TABLE"}); // Need to specify this to get result. SharedPointer< GlobalJObject > resultSet; - if (!_ctx.Get()->DatabaseMetaDataGetTables(databaseMetaData, resultSet, - &errInfo)) { + if (!_ctx.Get()->DatabaseMetaDataGetTables(databaseMetaData, catalog, + schemaPattern, tableNamePattern, + types, resultSet, &errInfo)) { std::string errMsg = errInfo.errMsg; _ctx.Get()->ConnectionClose(connection, &errInfo); BOOST_FAIL(errMsg); } BOOST_REQUIRE(resultSet.Get()); + bool hasNext; + if (!_ctx.Get()->ResultSetNext(resultSet, hasNext, &errInfo)) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + BOOST_REQUIRE(hasNext); + + bool wasNull; + std::string value; + // TABLE_SCHEM (i.e., database) + if (!_ctx.Get()->ResultSetGetString(resultSet, 2, value, wasNull, + &errInfo)) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + BOOST_REQUIRE(!wasNull); + BOOST_REQUIRE(value == "test"); + + // TABLE_NAME + if (!_ctx.Get()->ResultSetGetString(resultSet, 3, value, wasNull, + &errInfo)) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + BOOST_REQUIRE(!wasNull); + BOOST_REQUIRE(value.size() > 0); + _ctx.Get()->ConnectionClose(connection, &errInfo); connection = nullptr; } diff --git a/src/odbc/include/ignite/odbc/jni/java.h b/src/odbc/include/ignite/odbc/jni/java.h index d85921ca0..eb23c407b 100644 --- a/src/odbc/include/ignite/odbc/jni/java.h +++ b/src/odbc/include/ignite/odbc/jni/java.h @@ -227,6 +227,8 @@ namespace ignite { jmethodID m_Throwable_getMessage; jmethodID m_Throwable_printStackTrace; + jclass c_String; + jclass c_PlatformUtils; jmethodID m_PlatformUtils_getFullStackTrace; @@ -445,11 +447,18 @@ namespace ignite { void ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); bool ConnectionGetMetaData(const SharedPointer< GlobalJObject >& connection, SharedPointer< GlobalJObject>& databaseMetaData, JniErrorInfo* errInfo); - bool DatabaseMetaDataGetTables(const SharedPointer< GlobalJObject >& databaseMetaData, SharedPointer< GlobalJObject >& resultSet, JniErrorInfo* errInfo); + bool DatabaseMetaDataGetTables( + const SharedPointer< GlobalJObject >& databaseMetaData, + const std::string& catalog, + const std::string& schemaPattern, + const std::string& tableNamePattern, + const std::vector< std::string >& types, + SharedPointer< GlobalJObject >& resultSet, + JniErrorInfo* errInfo); bool ResultSetNext(const SharedPointer< GlobalJObject >& resultSet, bool& hasNext, JniErrorInfo* errInfo); - bool ResultSetGetString(const jobject resultSet, int columnIndex, std::string& value, bool& wasNull, JniErrorInfo* errInfo); + bool ResultSetGetString(const SharedPointer< GlobalJObject >& resultSet, int columnIndex, std::string& value, bool& wasNull, JniErrorInfo* errInfo); bool ResultSetGetString(const jobject resultSet, const std::string& columnName, std::string& value, bool& wasNull, JniErrorInfo* errInfo); bool ResultSetGetInteger(const jobject resultSet, int columnIndex, int& value, bool& wasNull, JniErrorInfo* errInfo); bool ResultSetGetInteger(const jobject resultSet, const std::string& columnName, int& value, bool& wasNull, JniErrorInfo* errInfo); diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index ee5077582..9bb5a8b51 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -236,6 +236,8 @@ namespace ignite const char* const C_CLASS = "java/lang/Class"; JniMethod const M_CLASS_GET_NAME = JniMethod("getName", "()Ljava/lang/String;", false); + const char* const C_STRING = "java/lang/String"; + const char* const C_DOCUMENTDB_CONNECTION_PROPERTIES = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; JniMethod const M_DOCUMENTDB_CONNECTION_PROPERTIES_GET_PROPERTIES_FROM_CONNECTION_STRING = @@ -430,6 +432,8 @@ namespace ignite m_Throwable_getMessage = FindMethod(env, c_Throwable, M_THROWABLE_GET_MESSAGE); m_Throwable_printStackTrace = FindMethod(env, c_Throwable, M_THROWABLE_PRINT_STACK_TRACE); + c_String = FindClass(env, C_STRING); + // TODO: Provide "getFullStackTrace" in DocumentDB //m_PlatformUtils_getFullStackTrace = FindMethod(env, c_PlatformUtils, M_PLATFORM_UTILS_GET_FULL_STACK_TRACE); } @@ -864,6 +868,10 @@ namespace ignite bool JniContext::DatabaseMetaDataGetTables( const SharedPointer< GlobalJObject >& databaseMetaData, + const std::string& catalog, + const std::string& schemaPattern, + const std::string& tableNamePattern, + const std::vector< std::string >& types, SharedPointer< GlobalJObject >& resultSet, JniErrorInfo* errInfo) { if (!databaseMetaData.Get()) { @@ -873,13 +881,23 @@ namespace ignite } JNIEnv* env = Attach(); + jstring jCatalog = env->NewStringUTF(catalog.c_str()); + jstring jSchemaPattern = env->NewStringUTF(schemaPattern.c_str()); + jstring jTableNamePattern = env->NewStringUTF(tableNamePattern.c_str()); + jobjectArray jTypes = env->NewObjectArray( + static_cast< jsize >(types.size()), jvm->GetJavaMembers().c_String, nullptr); + for (int i = 0; i < types.size(); i++) { + env->SetObjectArrayElement( + jTypes, i, env->NewStringUTF(types[i].c_str())); + } + jobject result = env->CallObjectMethod( databaseMetaData.Get()->GetRef(), jvm->GetMembers().m_DatabaseMetaDataGetTables, - /* catalog */ nullptr, - /* schemaPattern */ nullptr, - /* tableNamePattern */ nullptr, - /* types[]*/ nullptr); + jCatalog, + jSchemaPattern, + jTableNamePattern, + jTypes); ExceptionCheck(env, errInfo); if (!result || errInfo->code != IGNITE_JNI_ERR_SUCCESS) { @@ -907,17 +925,16 @@ namespace ignite jvm->GetMembers().m_ResultSetNext); ExceptionCheck(env, errInfo); if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { - hasNext = res != JNI_TRUE; + hasNext = res != JNI_FALSE; } return errInfo->code == IGNITE_JNI_ERR_SUCCESS; } - bool JniContext::ResultSetGetString(const jobject resultSet, - int columnIndex, - std::string& value, - bool& wasNull, - JniErrorInfo* errInfo) { - if (!resultSet) { + bool JniContext::ResultSetGetString( + const SharedPointer< GlobalJObject >& resultSet, + int columnIndex, std::string& value, bool& wasNull, + JniErrorInfo* errInfo) { + if (!resultSet.Get()) { errInfo->code = IGNITE_JNI_ERR_GENERIC; errInfo->errMsg = "ResultSet object must be set."; return false; @@ -925,7 +942,8 @@ namespace ignite JNIEnv* env = Attach(); jobject result = env->CallObjectMethod( - resultSet, jvm->GetMembers().m_ResultSetGetStringByIndex, + resultSet.Get()->GetRef(), + jvm->GetMembers().m_ResultSetGetStringByIndex, columnIndex); ExceptionCheck(env, errInfo); From 3d9c31031f3d7cf9f88276cdfbdce07fbb2f1262 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Thu, 3 Feb 2022 16:58:37 -0800 Subject: [PATCH 28/32] [AD-521] implement tests for JNI wrapper code * test for TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive is not yet active, need to be enabled when we can get external SSH tunnel working. * bug fix: re-implemented DocumentDbConnectionGetSshLocalPort and DocumentDbConnectionIsSshTunnelActive. connection.Get()->GetRef() is passed as first parameter because jobject is required for CallIntMethod and CallBooleanMethod. * better JNI wrapper code is needed in the future so warnings/errors pop up when we pass jobject instead of jclass to the methods. --- src/odbc-test/src/java_test.cpp | 97 +++++++++++++++++++++++++ src/odbc/include/ignite/odbc/jni/java.h | 6 +- src/odbc/src/jni/java.cpp | 35 ++++----- 3 files changed, 113 insertions(+), 25 deletions(-) diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp index aac4449cc..72cba46b5 100644 --- a/src/odbc-test/src/java_test.cpp +++ b/src/odbc-test/src/java_test.cpp @@ -187,6 +187,103 @@ BOOST_AUTO_TEST_CASE(TestConnectionGetMetaData) { connection = nullptr; } +BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPort) { + PrepareContext(); + + // get Driver manager connection + JniErrorInfo errInfo; + SharedPointer< GlobalJObject > connection; + bool success = _ctx.Get()->DriverManagerGetConnection( + _jdbcConnectionString.c_str(), connection, &errInfo); + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + BOOST_FAIL(errInfo.errMsg); + } + BOOST_REQUIRE(connection.Get()); + + // see if ssh tunnel is active + bool isActive; + success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, &errInfo); + // if tunnel is not shown as active, or operation not successful, BOOST FAIL + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errInfo.errMsg); + } + if (!isActive) { + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL("isActive is not true"); + } + + // ssh tunnel confirmed to be active, get ssh tunnel local port + int32_t port; + success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, &errInfo); + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + + // if connection successful, port should be a positive number + if (!(port > 0)) { + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL("port is not a positive number"); + } + + // close the connection after the test + _ctx.Get()->ConnectionClose(connection, &errInfo); + connection = nullptr; +} + +// TODO Enable when we can get external SSH tunnel working +BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive, * disabled()) { +//BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive) { + // test when SSH tunnel is not active, the ssh tunnel port should be 0 + // TODO do things so SSH tunnel is not active, but connection is open + PrepareContext(); + + // get Driver manager connection + JniErrorInfo errInfo; + SharedPointer< GlobalJObject > connection; + bool success = _ctx.Get()->DriverManagerGetConnection( + _jdbcConnectionString.c_str(), connection, &errInfo); + if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + BOOST_FAIL(errInfo.errMsg); + } + BOOST_REQUIRE(connection.Get()); + + // check if ssh tunnel is not active + bool isActive; + success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, &errInfo); + // if SSH tunnel is active, or operation not successful, BOOST FAIL + if (isActive || !success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errInfo.errMsg); + } + + if (isActive) { + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL("isActive is not false"); + } + + // ssh tunnel confirmed to be not active, get ssh tunnel local port + int32_t port; + success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, &errInfo); + if (errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { + std::string errMsg = errInfo.errMsg; + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL(errMsg); + } + + // if SSH tunnel not active, ssh local port number should be 0 + if (port != 0) { + _ctx.Get()->ConnectionClose(connection, &errInfo); + BOOST_FAIL("port is not equal to 0"); + } + + // close the connection after the test + _ctx.Get()->ConnectionClose(connection, &errInfo); + connection = nullptr; +} + BOOST_AUTO_TEST_CASE(TestDatabaseMetaDataGetTables) { PrepareContext(); diff --git a/src/odbc/include/ignite/odbc/jni/java.h b/src/odbc/include/ignite/odbc/jni/java.h index c7f49719b..b2acfeebd 100644 --- a/src/odbc/include/ignite/odbc/jni/java.h +++ b/src/odbc/include/ignite/odbc/jni/java.h @@ -447,8 +447,8 @@ namespace ignite { void ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); bool ConnectionGetMetaData(const SharedPointer< GlobalJObject >& connection, SharedPointer< GlobalJObject>& databaseMetaData, JniErrorInfo* errInfo); - bool DocumentDbIsSshTunnelActive(const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo* errInfo); - int32_t DocumentDbGetSshLocalPort(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo); + bool DocumentDbConnectionIsSshTunnelActive(const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo* errInfo); + bool DocumentDbConnectionGetSshLocalPort(const SharedPointer< GlobalJObject >& connection, int32_t& result, JniErrorInfo* errInfo); bool DatabaseMetaDataGetTables(const SharedPointer< GlobalJObject >& databaseMetaData, SharedPointer< GlobalJObject >& resultSet, JniErrorInfo* errInfo); @@ -694,5 +694,5 @@ namespace ignite { } // namespace jni } // namespace odbc } // namespace ignite - #endif //_IGNITE_ODBC_JNI_JAVA + diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 3e759e962..815cf91ad 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -273,11 +273,11 @@ namespace ignite "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/ResultSet;", false); - const char* const C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnectionProperties"; + const char* const C_DOCUMENTDB_CONNECTION = "software/amazon/documentdb/jdbc/DocumentDbConnection"; JniMethod const M_DOCUMENTDB_CONNECTION_GET_SSH_LOCAL_PORT = - JniMethod("getSshLocalPort", "()I;", false); + JniMethod("getSshLocalPort", "()I", false); JniMethod const M_DOCUMENTDB_CONNECTION_IS_SSH_TUNNEL_ACTIVE = - JniMethod("isSshTunnelActive", "()B", false); + JniMethod("isSshTunnelActive", "()Z", false); const char* const C_DRIVERMANAGER = "java/sql/DriverManager"; JniMethod const M_DRIVERMANAGER_GET_CONNECTION = @@ -832,7 +832,7 @@ namespace ignite // note to self: result is stored in bool poiner isActive, this is to be consistent with other functions that // use CallBooleanMethod. -AL- - bool JniContext::DocumentDbIsSshTunnelActive( + bool JniContext::DocumentDbConnectionIsSshTunnelActive( const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo* errInfo) { @@ -843,40 +843,31 @@ namespace ignite } JNIEnv* env = Attach(); jboolean res = env->CallBooleanMethod( - jvm->GetMembers().c_DocumentDbConnection, + connection.Get()->GetRef(), jvm->GetMembers().m_DocumentDbConnectionIsSshTunnelActive); ExceptionCheck(env, errInfo); if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { - isActive = res != JNI_TRUE; + isActive = res != JNI_FALSE; } return errInfo->code == IGNITE_JNI_ERR_SUCCESS; - // return result; } - int32_t JniContext::DocumentDbGetSshLocalPort( + // use a reference variable to return a value, return a boolean to indicate whether it is successful or not -AL- + bool JniContext::DocumentDbConnectionGetSshLocalPort( const SharedPointer< GlobalJObject >& connection, + int32_t& result, JniErrorInfo* errInfo) { if (!connection.Get()) { errInfo->code = IGNITE_JNI_ERR_GENERIC; errInfo->errMsg = "Connection object must be set."; - return 0; - // TODO double check with Bruce: should I just return 0 here? + return false; } JNIEnv* env = Attach(); - int32_t result = env->CallIntMethod( - jvm->GetMembers().c_DocumentDbConnection, + result = env->CallIntMethod( + connection.Get()->GetRef(), jvm->GetMembers().m_DocumentDbConnectionGetSshLocalPort); - //jobject result = env->CallObjectMethod( - // jvm->GetMembers().c_DocumentDbConnection, - // jvm->GetMembers().m_DocumentDbConnectionGetSshLocalPort); ExceptionCheck(env, errInfo); - //if (!result) { - // // unable to return object - // return 0; - //} else if (result.isPresent()) { - // return result.get().getInt(); - //} - return result; + return errInfo->code == IGNITE_JNI_ERR_SUCCESS; } void JniContext::ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo* errInfo) { From 3f8c3cbe27ab412714ea677394180c88a8a17a77 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Fri, 4 Feb 2022 09:37:06 -0800 Subject: [PATCH 29/32] [AD-521] refactor - remove comments and commented out code --- src/odbc-test/src/java_test.cpp | 3 +-- src/odbc/src/jni/java.cpp | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp index 730e62a46..e9d3c6a88 100644 --- a/src/odbc-test/src/java_test.cpp +++ b/src/odbc-test/src/java_test.cpp @@ -158,8 +158,7 @@ BOOST_AUTO_TEST_CASE(TestDriverManagerGetConnection) BOOST_REQUIRE(connection.Get()); _ctx.Get()->ConnectionClose(connection, &errInfo); - //connection = SharedPointer< GlobalJObject >(nullptr); - connection = nullptr; // attempt to fix read error -AL- + connection = nullptr; } BOOST_AUTO_TEST_CASE(TestConnectionGetMetaData) { diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index 17ad62270..be3eb2255 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -834,8 +834,6 @@ namespace ignite return true; } - // note to self: result is stored in bool poiner isActive, this is to be consistent with other functions that - // use CallBooleanMethod. -AL- bool JniContext::DocumentDbConnectionIsSshTunnelActive( const SharedPointer< GlobalJObject >& connection, bool& isActive, @@ -856,7 +854,6 @@ namespace ignite return errInfo->code == IGNITE_JNI_ERR_SUCCESS; } - // use a reference variable to return a value, return a boolean to indicate whether it is successful or not -AL- bool JniContext::DocumentDbConnectionGetSshLocalPort( const SharedPointer< GlobalJObject >& connection, int32_t& result, From 63c0dacc228957a890cd87893cedbfa35c6e64aa Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Tue, 8 Feb 2022 14:52:05 -0800 Subject: [PATCH 30/32] [AD-521] add calls to AutoCloseConnection in unit tests * pass & errInfo instead of * errInfo in DocumentDbConnectionGetSshLocalPort and DocumentDbConnectionIsSshTunnelActive. --- src/odbc-test/src/java_test.cpp | 50 +++++++------------------ src/odbc/include/ignite/odbc/jni/java.h | 6 +-- src/odbc/src/jni/java.cpp | 24 ++++++------ 3 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp index 9c7fc4525..c077835d7 100644 --- a/src/odbc-test/src/java_test.cpp +++ b/src/odbc-test/src/java_test.cpp @@ -206,51 +206,39 @@ BOOST_AUTO_TEST_CASE(TestDriverManagerGetConnection) connection = SharedPointer< GlobalJObject >(nullptr); } -// TODO change and add calls to AutoConnectionClose -AL- BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPort) { PrepareContext(); + BOOST_REQUIRE(_ctx.Get() != nullptr); // get Driver manager connection JniErrorInfo errInfo; SharedPointer< GlobalJObject > connection; - bool success = _ctx.Get()->DriverManagerGetConnection( - _jdbcConnectionString.c_str(), connection, &errInfo); + bool success = _ctx.Get()->DriverManagerGetConnection(_jdbcConnectionString.c_str(), connection, errInfo); if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { BOOST_FAIL(errInfo.errMsg); } BOOST_REQUIRE(connection.Get()); + AutoCloseConnection autoCloseConnection(_ctx, connection); // see if ssh tunnel is active bool isActive; - success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, &errInfo); + success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, errInfo); // if tunnel is not shown as active, or operation not successful, BOOST FAIL if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { - _ctx.Get()->ConnectionClose(connection, &errInfo); BOOST_FAIL(errInfo.errMsg); } - if (!isActive) { - _ctx.Get()->ConnectionClose(connection, &errInfo); - BOOST_FAIL("isActive is not true"); - } + BOOST_CHECK(isActive); // ssh tunnel confirmed to be active, get ssh tunnel local port int32_t port; - success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, &errInfo); + success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, errInfo); if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { std::string errMsg = errInfo.errMsg; - _ctx.Get()->ConnectionClose(connection, &errInfo); BOOST_FAIL(errMsg); } // if connection successful, port should be a positive number - if (!(port > 0)) { - _ctx.Get()->ConnectionClose(connection, &errInfo); - BOOST_FAIL("port is not a positive number"); - } - - // close the connection after the test - _ctx.Get()->ConnectionClose(connection, &errInfo); - connection = nullptr; + BOOST_CHECK(port > 0); } // TODO Enable when we can get external SSH tunnel working @@ -259,49 +247,39 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive, // test when SSH tunnel is not active, the ssh tunnel port should be 0 // TODO do things so SSH tunnel is not active, but connection is open PrepareContext(); + BOOST_REQUIRE(_ctx.Get() != nullptr); // get Driver manager connection JniErrorInfo errInfo; SharedPointer< GlobalJObject > connection; bool success = _ctx.Get()->DriverManagerGetConnection( - _jdbcConnectionString.c_str(), connection, &errInfo); + _jdbcConnectionString.c_str(), connection, errInfo); if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { BOOST_FAIL(errInfo.errMsg); } BOOST_REQUIRE(connection.Get()); + AutoCloseConnection autoCloseConnection(_ctx, connection); // check if ssh tunnel is not active bool isActive; - success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, &errInfo); + success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, errInfo); // if SSH tunnel is active, or operation not successful, BOOST FAIL if (isActive || !success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { - _ctx.Get()->ConnectionClose(connection, &errInfo); BOOST_FAIL(errInfo.errMsg); } - if (isActive) { - _ctx.Get()->ConnectionClose(connection, &errInfo); - BOOST_FAIL("isActive is not false"); - } + BOOST_CHECK(!isActive); // ssh tunnel confirmed to be not active, get ssh tunnel local port int32_t port; - success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, &errInfo); + success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, errInfo); if (errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { std::string errMsg = errInfo.errMsg; - _ctx.Get()->ConnectionClose(connection, &errInfo); BOOST_FAIL(errMsg); } // if SSH tunnel not active, ssh local port number should be 0 - if (port != 0) { - _ctx.Get()->ConnectionClose(connection, &errInfo); - BOOST_FAIL("port is not equal to 0"); - } - - // close the connection after the test - _ctx.Get()->ConnectionClose(connection, &errInfo); - connection = nullptr; + BOOST_CHECK_EQUAL(port, 0); } BOOST_AUTO_TEST_CASE(TestConnectionGetMetaData) { diff --git a/src/odbc/include/ignite/odbc/jni/java.h b/src/odbc/include/ignite/odbc/jni/java.h index cf1e7661e..3e84515f0 100644 --- a/src/odbc/include/ignite/odbc/jni/java.h +++ b/src/odbc/include/ignite/odbc/jni/java.h @@ -446,13 +446,13 @@ namespace ignite { static void SetConsoleHandler(ConsoleWriteHandler consoleHandler); static int RemoveConsoleHandler(ConsoleWriteHandler consoleHandler); - bool DocumentDbConnectionIsSshTunnelActive(const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo* errInfo); - bool DocumentDbConnectionGetSshLocalPort(const SharedPointer< GlobalJObject >& connection, int32_t& result, JniErrorInfo* errInfo); - bool DriverManagerGetConnection(const char* connectionString, SharedPointer< GlobalJObject >& connection, JniErrorInfo& errInfo); void ConnectionClose(const SharedPointer< GlobalJObject >& connection, JniErrorInfo& errInfo); bool ConnectionGetMetaData(const SharedPointer< GlobalJObject >& connection, SharedPointer< GlobalJObject>& databaseMetaData, JniErrorInfo& errInfo); + bool DocumentDbConnectionIsSshTunnelActive(const SharedPointer< GlobalJObject >& connection, bool& isActive, JniErrorInfo& errInfo); + bool DocumentDbConnectionGetSshLocalPort(const SharedPointer< GlobalJObject >& connection, int32_t& result, JniErrorInfo& errInfo); + bool DatabaseMetaDataGetTables( const SharedPointer< GlobalJObject >& databaseMetaData, const std::string& catalog, diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index aab360578..e3561009f 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -832,39 +832,39 @@ namespace ignite bool JniContext::DocumentDbConnectionIsSshTunnelActive( const SharedPointer< GlobalJObject >& connection, bool& isActive, - JniErrorInfo* errInfo) { + JniErrorInfo& errInfo) { if (!connection.Get()) { - errInfo->code = IGNITE_JNI_ERR_GENERIC; - errInfo->errMsg = "Connection object must be set."; + errInfo.code = IGNITE_JNI_ERR_GENERIC; + errInfo.errMsg = "Connection object must be set."; return false; } JNIEnv* env = Attach(); jboolean res = env->CallBooleanMethod( connection.Get()->GetRef(), jvm->GetMembers().m_DocumentDbConnectionIsSshTunnelActive); - ExceptionCheck(env, errInfo); - if (errInfo->code == IGNITE_JNI_ERR_SUCCESS) { + ExceptionCheck(env, &errInfo); + if (errInfo.code == IGNITE_JNI_ERR_SUCCESS) { isActive = res != JNI_FALSE; } - return errInfo->code == IGNITE_JNI_ERR_SUCCESS; + return errInfo.code == IGNITE_JNI_ERR_SUCCESS; } bool JniContext::DocumentDbConnectionGetSshLocalPort( const SharedPointer< GlobalJObject >& connection, int32_t& result, - JniErrorInfo* errInfo) { + JniErrorInfo& errInfo) { if (!connection.Get()) { - errInfo->code = IGNITE_JNI_ERR_GENERIC; - errInfo->errMsg = "Connection object must be set."; + errInfo.code = IGNITE_JNI_ERR_GENERIC; + errInfo.errMsg = "Connection object must be set."; return false; } JNIEnv* env = Attach(); result = env->CallIntMethod( connection.Get()->GetRef(), jvm->GetMembers().m_DocumentDbConnectionGetSshLocalPort); - ExceptionCheck(env, errInfo); - return errInfo->code == IGNITE_JNI_ERR_SUCCESS; - } + ExceptionCheck(env, &errInfo); + return errInfo.code == IGNITE_JNI_ERR_SUCCESS; + } bool JniContext::ConnectionGetMetaData( const SharedPointer< GlobalJObject >& connection, From a65e781be5f08dd273d15439670056818d18d687 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Tue, 8 Feb 2022 14:57:51 -0800 Subject: [PATCH 31/32] [AD-521] remove unnecessary comment --- src/odbc/src/jni/java.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/odbc/src/jni/java.cpp b/src/odbc/src/jni/java.cpp index e3561009f..885c06350 100644 --- a/src/odbc/src/jni/java.cpp +++ b/src/odbc/src/jni/java.cpp @@ -828,7 +828,6 @@ namespace ignite ExceptionCheck(env, &errInfo); } - // -AL- todo changes are needed because & errInfo should be returned instead bool JniContext::DocumentDbConnectionIsSshTunnelActive( const SharedPointer< GlobalJObject >& connection, bool& isActive, From 701e790951d1080d46dd4e58beac88f6ab0b7c08 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 9 Feb 2022 12:03:36 -0800 Subject: [PATCH 32/32] [AD-521] refactor - change case of ssh to SSH for consistency --- src/odbc-test/src/java_test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/odbc-test/src/java_test.cpp b/src/odbc-test/src/java_test.cpp index c077835d7..0f993248f 100644 --- a/src/odbc-test/src/java_test.cpp +++ b/src/odbc-test/src/java_test.cpp @@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPort) { BOOST_REQUIRE(connection.Get()); AutoCloseConnection autoCloseConnection(_ctx, connection); - // see if ssh tunnel is active + // see if SSH tunnel is active bool isActive; success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, errInfo); // if tunnel is not shown as active, or operation not successful, BOOST FAIL @@ -229,7 +229,7 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPort) { } BOOST_CHECK(isActive); - // ssh tunnel confirmed to be active, get ssh tunnel local port + // SSH tunnel confirmed to be active, get SSH tunnel local port int32_t port; success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, errInfo); if (!success || errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { @@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPort) { // TODO Enable when we can get external SSH tunnel working BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive, * disabled()) { //BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive) { - // test when SSH tunnel is not active, the ssh tunnel port should be 0 + // test when SSH tunnel is not active, the SSH tunnel port should be 0 // TODO do things so SSH tunnel is not active, but connection is open PrepareContext(); BOOST_REQUIRE(_ctx.Get() != nullptr); @@ -260,7 +260,7 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive, BOOST_REQUIRE(connection.Get()); AutoCloseConnection autoCloseConnection(_ctx, connection); - // check if ssh tunnel is not active + // check if SSH tunnel is not active bool isActive; success = _ctx.Get()->DocumentDbConnectionIsSshTunnelActive(connection, isActive, errInfo); // if SSH tunnel is active, or operation not successful, BOOST FAIL @@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive, BOOST_CHECK(!isActive); - // ssh tunnel confirmed to be not active, get ssh tunnel local port + // SSH tunnel confirmed to be not active, get SSH tunnel local port int32_t port; success = _ctx.Get()->DocumentDbConnectionGetSshLocalPort(connection, port, errInfo); if (errInfo.code != odbc::java::IGNITE_JNI_ERR_SUCCESS) { @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(TestDocumentDbConnectionGetSshTunnelPortSshTunnelNotActive, BOOST_FAIL(errMsg); } - // if SSH tunnel not active, ssh local port number should be 0 + // if SSH tunnel not active, SSH local port number should be 0 BOOST_CHECK_EQUAL(port, 0); }