From 6ea4644635cfeaffaab4263a4f679f15522da47b Mon Sep 17 00:00:00 2001 From: Byungwook Kim Date: Wed, 11 Dec 2024 17:56:51 +0900 Subject: [PATCH 01/11] [CBRD-25713] revert to MAX CHAR Length (#5702) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit http://jira.cubrid.org/browse/CBRD-25713 테스트 케이스에 반영하기 위해 임시로 예전 길이로 변경합니다. --- src/compat/dbtype_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compat/dbtype_def.h b/src/compat/dbtype_def.h index a1e71ccd86..9334f59e4c 100644 --- a/src/compat/dbtype_def.h +++ b/src/compat/dbtype_def.h @@ -541,7 +541,7 @@ extern "C" * Change the maximum length of CHAR type to 2048 for memory allocation and performance. * Refer to CBRD-25713 */ -#define DB_MAX_CHAR_PRECISION 2048 +#define DB_MAX_CHAR_PRECISION (DB_MAX_STRING_LENGTH/4) /* The maximum precision that can be specified for a CHARACTER VARYING domain.*/ #define DB_MAX_VARCHAR_PRECISION DB_MAX_STRING_LENGTH From 1ea4a86e0a5a960b8918d3f7a921adb25af9f957 Mon Sep 17 00:00:00 2001 From: Hyung-Gyu Ryoo Date: Thu, 12 Dec 2024 00:58:32 +0900 Subject: [PATCH 02/11] [CBRD-25184] PL/CSQL phase-1 internal release (#5438) http://jira.cubrid.org/browse/CBRD-25184 ## Overview This commit incorporates numerous updates from the PL/CSQL feature branch into the develop branch. These updates focus on enhanced functionality for PL/CSQL, stored procedure management, and significant bug fixes to ensure improved performance, stability, and usability. This commit also includes essential refactoring and utility updates. --- ## New Features ### 1. Interrupt Handling in PL/CSQL (CBRD-25726, CBRD-25703) - Enhanced the PL/CSQL system to handle user-initiated interrupts effectively during both compilation and execution processes, improving responsiveness and stability. - **CBRD-25726**: Managed interrupts during the compilation of stored procedures. This feature ensures that long-running compilations can be terminated gracefully, reducing system downtime and enhancing user control. - **CBRD-25703**: Handled user interrupts such as query cancellations and transaction kills during the execution of PL/CSQL tasks. This addition provides users with better control over long-running or unintended tasks. - **Key Changes**: - Extended the `pl_execution_context` class to incorporate interrupt handling functionalities for both compilation and execution phases. - Implemented mechanisms to detect and process interrupt signals during query execution, ensuring clean termination and resource release. - Updated internal logic to safely handle rollback or cancellation requests during ongoing operations. ### 2. Stored Procedure Enhancements #### User Schema Support for Stored Procedures (CBRD-25506) - **Description**: - Introduced schema-specific ownership for stored procedures, allowing procedures to be associated with specific user schemas. This enhancement improves security, simplifies schema management, and provides a more logical organization of stored procedures. - **Key Changes**: - Updated syntax to support schema-specific operations, such as `GRANT EXECUTE ON PROCEDURE [schema_name].[sp_name] TO user`. - Implemented stricter permission checks to prevent unauthorized access to schema-specific procedures. #### Default Parameter Values (CBRD-25261) - **Description**: - Added functionality to define default values for parameters in stored procedures. This feature reduces the need for redundant procedure overloads and simplifies procedure calls by allowing optional parameters. - **Key Changes**: - Enabled syntax for specifying default parameter values using `DEFAULT` or `:=`. - Added semantic checks to ensure compatibility between parameter types and default values. - Restricted the use of default values for `OUT` and `INOUT` mode parameters. #### RECOMPILE Functionality (CBRD-25106) - **Description**: - Simplified the process of recompiling stored procedures by introducing the `ALTER PROCEDURE/FUNCTION [schema_name].[name] COMPILE` command. This enhancement eliminates the need to drop and recreate procedures for recompilation. - **Key Changes**: - Added support for the `ALTER ... COMPILE` syntax. - Improved error handling and debugging capabilities during recompilation. ### 3. Authorization Improvements #### GRANT/REVOKE Support for Procedures and Functions (CBRD-25210) - **Description**: - Extended the GRANT and REVOKE commands to include support for stored procedures and functions, ensuring fine-grained control over execution privileges. - **Key Changes**: - Introduced syntax for granting and revoking execution permissions on procedures and functions. - Example: ```sql GRANT EXECUTE ON PROCEDURE my_procedure TO user; REVOKE EXECUTE ON PROCEDURE my_procedure FROM user; ``` ### 4. Database Utility Updates #### New Utility Name (CBRD-25453) - **Description**: - Renamed the `cubrid javasp` utility to `cubrid pl` to better align with the PL/CSQL management functionalities. This change reflects the broader capabilities of the utility in managing procedural language operations. - **Key Changes**: - Updated command-line interfaces and documentation to reflect the new utility name. - Retained `cubrid javasp` as an alias for backward compatibility. --- ## Bug Fixes ### 1. Stored Procedure Issues #### Core Dumps During SP Operations (CBRD-25704) - **Description**: - Fixed critical issues causing core dumps during stored procedure unloading and execution. These issues were primarily triggered by improper handling of synonyms and default parameter values in certain scenarios. - **Key Changes**: - Improved the handling of user schemas and default values to prevent crashes. - Enhanced stability during procedure unloading and execution. #### Error Message Standardization (CBRD-25673) - **Description**: - Addressed inconsistencies in error messages related to non-existent stored procedures. Updated messages now provide clearer context and align with standard naming conventions. - **Key Changes**: - Refined error messages to improve user comprehension and debugging efficiency. #### Query Handler Lifecycle Management (CBRD-25292, CBRD-25389) - **Description**: - Resolved issues where query handler objects, created during the generation of PL's static and dynamic SQL at the time of `COMMIT` or `ROLLBACK`, were prematurely removed, leading to access violations and memory deallocation errors. - Ensured that query handlers and cursors remain accessible even after `COMMIT` or `ROLLBACK`, allowing safe and limited interactions with previously created handlers. - This update improves the robustness of query handler management and ensures stable PL/CSQL operations during transactional workflows. - **Key Changes**: - Introduced a deferred cleanup mechanism for `query_handler` instances and associated resources (`DB_SESSION`, `QUERY CURSOR`), ensuring their removal only after the main SQL call completes. - Enhanced synchronization to address CAS core crashes and incomplete PL session termination. ### 2. Authorization and Security #### Catalog Checks (CBRD-25681) - **Description**: - Resolved vulnerabilities allowing unauthorized execution of stored procedures due to incorrect handling of `_db_auth` catalog entries. Enhanced security measures ensure that only authorized users can execute procedures. - **Key Changes**: - Strengthened semantic checks for `_db_auth` entries. - Prevented unauthorized users from executing stored procedures. #### Static SQL Handling (CBRD-25563) - **Description**: - Fixed authorization bypass issues occurring during the translation of system vclasses in static SQL queries. These issues previously allowed unauthorized access to system resources. - **Key Changes**: - Implemented stricter permission checks for rewritten queries. ### 3. System Stability #### Improved PL Server Management (CBRD-25688) - **Description**: - Enhanced the PL server management processes to address issues related to process termination and restart. These improvements ensure reliable server operations and reduced downtime. - **Key Changes**: - Improved the restart behavior of the PL server utility (`cubrid pl`). - Enhanced error handling during process termination and restart. --- ## Performance Improvements ### 1. Caching for PL/CSQL object code (CBRD-25370) - **Description**: - Introduced a caching mechanism for PL/CSQL object code. This enhancement reduces execution times for frequently used procedures by minimizing redundant operations. - **Key Changes**: - Implemented grouped class loaders for optimized memory management. - Reduced compilation overhead for recurring procedure calls. ### 2. Optimized Query Execution (CBRD-25416) - **Description**: - Addressed inefficiencies caused by legacy method transformations for stored procedures with column arguments. These transformations involved creating unnecessary join structures like Lateral Joins (CSELECT) with tables, leading to suboptimal query execution plans. - Removed this transformation, as it caused performance issues such as inefficient index scans, improper outer joins, and unnecessary computation during execution. - Developed an execution plan for stored procedures/functions similar to built-in functions, maintaining their operational correctness and improving overall efficiency. - **Key Changes**: - **Removed Method Transformation**: Eliminated the creation of inline-view-like structures (called method scan) for stored procedures and functions with column arguments, preventing redundant computations. - **Intermediate Representation**: Introduced the `pl_signature` structure for storing intermediate representations of procedures/functions for use in execution plans. - **Improved Resource Management**: Reorganized execution resources by creating the `pl_execution_stack_context` for stack-level resource management and the `pl_session` structure for session-level handling. - **Optimization Adjustments**: - Disabled constant folding for procedures/functions with constant arguments, ensuring runtime evaluation. - This change leads to enhance outer join and index skip operations for correctness and performance. --- ## Deprecated Features - Removed redundant methods, constants, and legacy behaviors related to outdated stored procedure handling. - Deprecated the `cubrid javasp` utility in favor of `cubrid pl`. --- ## Known Issues - Additional performance optimizations for PL/CSQL code caching and interrupt handling are planned for future updates. - Certain legacy bugs related to `_db_auth` catalog operations remain under review. --- ## Key Contributors - **Hyung-Gyu Ryoo** (@hgryoo) - **Na Hyunik** (@hyunikn) - **Jongmin Won** (@jongmin-won) --- .circleci/config.yml | 7 +- .github/CODEOWNERS | 3 +- contrib/msg/de_DE.utf8/cubrid.msg | 10 +- contrib/msg/de_DE.utf8/utils.msg | 6 +- contrib/msg/es_ES.utf8/cubrid.msg | 10 +- contrib/msg/es_ES.utf8/utils.msg | 6 +- contrib/msg/fr_FR.utf8/cubrid.msg | 10 +- contrib/msg/fr_FR.utf8/utils.msg | 6 +- contrib/msg/it_IT.utf8/cubrid.msg | 10 +- contrib/msg/it_IT.utf8/utils.msg | 6 +- contrib/msg/ja_JP.utf8/cubrid.msg | 10 +- contrib/msg/ja_JP.utf8/utils.msg | 6 +- contrib/msg/km_KH.utf8/cubrid.msg | 10 +- contrib/msg/km_KH.utf8/utils.msg | 6 +- contrib/msg/ro_RO.utf8/cubrid.msg | 10 +- contrib/msg/ro_RO.utf8/utils.msg | 6 +- contrib/msg/tr_TR.utf8/cubrid.msg | 10 +- contrib/msg/tr_TR.utf8/utils.msg | 6 +- contrib/msg/vi_VN.utf8/cubrid.msg | 10 +- contrib/msg/vi_VN.utf8/utils.msg | 6 +- contrib/msg/zh_CN.utf8/cubrid.msg | 10 +- contrib/msg/zh_CN.utf8/utils.msg | 6 +- contrib/scripts/check_reserved.sql | 2 +- cs/CMakeLists.txt | 17 +- cubrid/CMakeLists.txt | 38 +- demo/CMakeLists.txt | 5 - demo/plcsql/README.md | 478 ---- ...orStaticSqlLoop-test-without-condition.sql | 11 - demo/plcsql/demo_global_semantics_serial.sql | 6 - demo/plcsql/demo_global_semantics_type.sql | 12 - demo/plcsql/demo_global_semantics_udpf.sql | 7 - demo/plcsql/demo_hello.sql | 4 - demo/plcsql/demo_hello_ret.sql | 4 - demo/plcsql/test_ddl.sql | 11 - demo/plcsql/test_dml_delete.sql | 27 - demo/plcsql/test_dml_insert.sql | 77 - demo/plcsql/test_dml_truncate.sql | 8 - demo/plcsql/test_query_cursor_hostvar.sql | 22 - demo/plcsql/test_query_cursor_simple.sql | 11 - .../test_query_cursor_simple_nocond.sql | 11 - demo/plcsql/test_query_single_row.sql | 16 - demo/plcsql/test_query_single_row_const.sql | 14 - .../test_semantic_error_unknown_tbl.sql | 4 - .../test_semantic_error_wrong_literal.sql | 7 - demo/plcsql/test_tcl_commit.sql | 30 - demo/plcsql/test_tcl_rollback.sql | 45 - msg/en_US.utf8/cubrid.msg | 28 +- msg/en_US.utf8/utils.msg | 6 +- msg/ko_KR.utf8/cubrid.msg | 31 +- msg/ko_KR.utf8/utils.msg | 6 +- pl_engine/pl_server/build.gradle.kts | 3 + .../pl_server/src/main/antlr/PlcLexer.g4 | 5 + .../pl_server/src/main/antlr/PlcParser.g4 | 66 +- .../java/com/cubrid/jsp/ExecuteThread.java | 218 +- .../src/main/java/com/cubrid/jsp/Server.java | 61 +- .../java/com/cubrid/jsp/ServerConfig.java | 105 + .../java/com/cubrid/jsp/StoredProcedure.java | 202 +- .../main/java/com/cubrid/jsp/SysParam.java | 103 + .../java/com/cubrid/jsp/TargetMethod.java | 84 +- .../com/cubrid/jsp/TargetMethodCache.java | 3 +- .../jsp/classloader/SessionClassLoader.java | 93 + .../classloader/SessionClassLoaderGroup.java | 38 + .../SessionClassLoaderManager.java | 68 + .../java/com/cubrid/jsp/code/ClassAccess.java | 141 + .../com/cubrid/jsp/code/CompiledCode.java | 89 + .../com/cubrid/jsp/code/CompiledCodeSet.java | 133 + .../java/com/cubrid/jsp/code/MemoryClass.java | 70 + .../com/cubrid/jsp/code/MemoryClassCache.java | 61 + .../java/com/cubrid/jsp/code/Signature.java | 82 + .../java/com/cubrid/jsp/code/SourceCode.java | 61 + .../jsp/compiler/MemoryFileManager.java | 79 + .../jsp/compiler/MemoryJavaCompiler.java | 103 + .../java/com/cubrid/jsp/context/Context.java | 65 +- .../java/com/cubrid/jsp/data/AuthInfo.java | 51 + .../com/cubrid/jsp/data/CUBRIDPacker.java | 171 +- .../com/cubrid/jsp/data/CUBRIDUnpacker.java | 124 +- .../java/com/cubrid/jsp/data/CompileInfo.java | 8 + .../com/cubrid/jsp/data/CompileRequest.java | 44 + .../com/cubrid/jsp/impl/SUBindParameter.java | 4 +- .../com/cubrid/jsp/impl/SUConnection.java | 5 +- .../cubrid/jsp/protocol/BootstrapRequest.java | 31 + .../com/cubrid/jsp/protocol/PrepareArgs.java | 17 +- .../com/cubrid/jsp/protocol/RequestCode.java | 4 + .../com/cubrid/jsp/value/BooleanValue.java | 9 +- .../java/com/cubrid/jsp/value/ByteValue.java | 7 +- .../com/cubrid/jsp/value/DateTimeParser.java | 9 +- .../java/com/cubrid/jsp/value/DateValue.java | 17 +- .../com/cubrid/jsp/value/DatetimeValue.java | 19 +- .../com/cubrid/jsp/value/DoubleValue.java | 11 +- .../java/com/cubrid/jsp/value/FloatValue.java | 11 +- .../java/com/cubrid/jsp/value/IntValue.java | 8 +- .../java/com/cubrid/jsp/value/LongValue.java | 10 +- .../java/com/cubrid/jsp/value/NullValue.java | 7 +- .../com/cubrid/jsp/value/NumericValue.java | 9 +- .../java/com/cubrid/jsp/value/OidValue.java | 17 +- .../com/cubrid/jsp/value/ResultSetValue.java | 3 + .../java/com/cubrid/jsp/value/SetValue.java | 202 +- .../java/com/cubrid/jsp/value/ShortValue.java | 8 +- .../com/cubrid/jsp/value/StringValue.java | 74 +- .../java/com/cubrid/jsp/value/TimeValue.java | 13 +- .../com/cubrid/jsp/value/TimestampValue.java | 19 +- .../main/java/com/cubrid/jsp/value/Value.java | 11 +- .../com/cubrid/jsp/value/ValueUtilities.java | 61 + .../java/com/cubrid/plcsql/compiler/Misc.java | 12 + .../plcsql/compiler/ParseTreeConverter.java | 146 +- .../plcsql/compiler/PlcsqlCompilerMain.java | 55 +- .../com/cubrid/plcsql/compiler/ast/Unit.java | 21 +- .../cubrid/plcsql/compiler/type/TypeChar.java | 2 +- .../cubrid/plcsql/predefined/sp/SpLib.java | 99 +- sa/CMakeLists.txt | 44 +- src/api/db_stub.c | 4 +- src/base/error_code.h | 15 +- src/base/memory_alloc.c | 31 + src/base/memory_alloc.h | 1 + src/base/message_catalog.h | 1 + src/base/msgcat_glossary.hpp | 44 + src/base/object_representation.h | 2 - src/base/packer.cpp | 3 +- src/base/porting.c | 16 + src/base/porting.h | 3 + src/base/process_util.c | 64 +- src/base/process_util.h | 9 +- src/base/system_parameter.c | 211 +- src/base/system_parameter.h | 13 +- src/base/xserver_interface.h | 6 - src/communication/network.h | 2 +- src/communication/network_callback_cl.cpp | 58 + src/communication/network_callback_cl.hpp | 59 + src/communication/network_callback_sr.cpp | 106 + src/communication/network_callback_sr.hpp | 81 + src/communication/network_cl.c | 21 +- src/communication/network_common.cpp | 2 + src/communication/network_interface_cl.c | 192 +- src/communication/network_interface_cl.h | 17 +- src/communication/network_interface_sr.c | 167 +- src/communication/network_interface_sr.h | 11 +- src/communication/network_sr.c | 6 +- src/compat/db_admin.c | 139 +- src/compat/db_method_static.cpp | 8 +- src/compat/db_obj.c | 24 + src/compat/dbi.h | 8 + src/compat/dbi_compat.h | 10 +- src/compat/dbtype_def.h | 16 +- src/connection/connection_defs.h | 1 - src/connection/connection_globals.h | 22 - src/connection/connection_sr.c | 69 +- src/connection/connection_sr.h | 3 - src/connection/server_support.c | 4 +- src/executables/commdb.c | 32 - src/executables/compactdb.c | 2 - src/executables/compactdb_cl.c | 2 - src/executables/csql.c | 6 +- src/executables/master.c | 94 +- src/executables/master_request.c | 71 - src/executables/master_request.h | 1 - src/executables/master_server_monitor.cpp | 477 ---- src/executables/master_server_monitor.hpp | 175 -- src/executables/migrate.c | 1 - src/executables/{javasp.cpp => pl.cpp} | 368 ++- src/executables/plcsql.cpp | 22 +- src/executables/server.c | 47 +- src/executables/unload_object.c | 1 + src/executables/unload_schema.c | 435 ++- src/executables/unloaddb.c | 2 - src/executables/util_cs.c | 10 - src/executables/util_sa.c | 36 - src/executables/util_service.c | 329 +-- src/executables/utility.h | 14 +- src/loaddb/load_db.c | 2 - src/loaddb/load_sa_loader.cpp | 5 + src/method/method_callback.cpp | 158 +- src/method/method_callback.hpp | 16 +- src/method/method_compile.cpp | 137 - src/method/method_connection.hpp | 61 - src/method/method_connection_cl.cpp | 69 - src/method/method_connection_cl.hpp | 89 - src/method/method_connection_java.cpp | 177 -- src/method/method_connection_java.hpp | 66 - src/method/method_connection_pool.cpp | 158 -- src/method/method_connection_pool.hpp | 91 - src/method/method_connection_sr.cpp | 144 - src/method/method_connection_sr.hpp | 67 - src/method/method_def.cpp | 434 --- src/method/method_def.hpp | 171 -- src/method/method_invoke.hpp | 134 - src/method/method_invoke_builtin.cpp | 80 - src/method/method_invoke_group.cpp | 493 ---- src/method/method_invoke_java.cpp | 703 ----- src/method/method_query_handler.cpp | 14 + src/method/method_query_handler.hpp | 5 + src/method/method_scan.cpp | 45 +- src/method/method_scan.hpp | 4 +- src/method/method_struct_invoke.cpp | 108 +- src/method/method_struct_invoke.hpp | 56 +- src/method/method_struct_value.cpp | 17 +- src/method/query_method.cpp | 83 +- src/method/query_method.hpp | 2 +- src/object/authenticate.c | 2 + src/object/authenticate.h | 12 +- src/object/authenticate_access_auth.cpp | 695 ++++- src/object/authenticate_access_auth.hpp | 31 +- src/object/authenticate_access_user.cpp | 35 +- src/object/authenticate_cache.cpp | 261 +- src/object/authenticate_cache.hpp | 32 +- src/object/authenticate_constants.h | 11 +- src/object/authenticate_context.cpp | 97 +- src/object/authenticate_context.hpp | 14 + src/object/authenticate_grant.cpp | 764 +++++- src/object/authenticate_grant.hpp | 10 +- src/object/authenticate_migration.cpp | 62 +- src/object/authenticate_owner.cpp | 36 +- src/object/object_representation.c | 182 +- src/object/schema_class_truncator.cpp | 8 +- src/object/schema_manager.c | 25 +- src/object/schema_system_catalog.cpp | 1 + src/object/schema_system_catalog_builder.cpp | 4 +- src/object/schema_system_catalog_constants.h | 1 + .../schema_system_catalog_definition.hpp | 1 - src/object/schema_system_catalog_install.cpp | 65 +- src/object/schema_system_catalog_install.hpp | 1 + ...hema_system_catalog_install_query_spec.cpp | 164 +- src/object/trigger_manager.c | 2 +- src/optimizer/query_graph.c | 22 +- src/parser/csql_grammar.y | 387 ++- src/parser/csql_lexer.l | 74 +- src/parser/keyword.c | 3 + src/parser/method_transform.c | 27 +- src/parser/name_resolution.c | 152 +- src/parser/parse_dbi.c | 4 + src/parser/parse_evaluate.c | 8 + src/parser/parse_tree.c | 1 + src/parser/parse_tree.h | 42 +- src/parser/parse_tree_cl.c | 101 +- src/parser/parser.h | 5 + src/parser/parser_message.h | 8 + src/parser/parser_support.c | 550 ++-- src/parser/semantic_check.c | 183 +- src/parser/view_transform.c | 16 +- src/parser/xasl_generation.c | 375 +-- src/parser/xasl_regu_alloc.cpp | 17 +- src/parser/xasl_regu_alloc.hpp | 27 + src/query/execute_schema.c | 124 +- src/query/execute_statement.c | 92 + src/query/execute_statement.h | 1 + src/query/fetch.c | 26 + src/query/query_dump.c | 9 + src/query/query_executor.c | 42 +- src/query/regu_var.cpp | 18 + src/query/regu_var.hpp | 5 +- src/query/scan_manager.c | 6 +- src/query/scan_manager.h | 3 +- src/query/stream_to_xasl.c | 322 ++- src/query/xasl.h | 9 +- src/query/xasl_to_stream.c | 427 ++- src/session/session.c | 25 +- src/session/session.h | 5 +- src/sp/Makefile_jspserver | 34 - src/sp/jsp_cl.c | 1647 ----------- src/sp/jsp_cl.cpp | 2438 +++++++++++++++++ src/sp/jsp_cl.h | 63 +- src/sp/jsp_file.h | 69 - src/sp/method_invoke_group.cpp | 253 ++ src/{method => sp}/method_invoke_group.hpp | 65 +- src/sp/{jsp_comm.c => pl_comm.c} | 52 +- src/sp/{jsp_comm.h => pl_comm.h} | 27 +- src/sp/pl_compile_handler.cpp | 162 ++ src/sp/pl_compile_handler.hpp | 58 + src/sp/pl_connection.cpp | 405 +++ src/sp/pl_connection.hpp | 176 ++ src/sp/pl_execution_stack_context.cpp | 228 ++ src/sp/pl_execution_stack_context.hpp | 188 ++ src/sp/pl_executor.cpp | 972 +++++++ src/sp/pl_executor.hpp | 124 + src/sp/{jsp_file.c => pl_file.c} | 66 +- src/sp/pl_file.h | 69 + .../pl_query_cursor.cpp} | 40 +- .../pl_query_cursor.hpp} | 18 +- .../pl_session.cpp} | 282 +- .../pl_session.hpp} | 84 +- src/sp/pl_signature.cpp | 429 +++ src/sp/pl_signature.hpp | 131 + ...p_sr.h => pl_signature_packing_helper.hpp} | 31 +- src/sp/pl_sr.cpp | 621 +++++ src/sp/pl_sr.h | 47 + src/sp/{jsp_sr.c => pl_sr_jvm.cpp} | 383 ++- .../pl_struct_compile.cpp} | 73 +- .../pl_struct_compile.hpp} | 37 +- src/sp/sp_catalog.cpp | 1023 +++++++ src/sp/sp_catalog.hpp | 203 ++ src/sp/sp_code.cpp | 264 ++ src/sp/sp_code.hpp | 55 + src/sp/sp_constants.hpp | 179 ++ src/storage/oid.c | 6 +- src/storage/oid.h | 3 + src/transaction/boot_cl.c | 6 + src/transaction/boot_sr.c | 26 +- src/transaction/log_tran_table.c | 47 +- src/transaction/transaction_cl.c | 2 +- src/win_tools/ctrlservice/ctrlservice.cpp | 8 +- src/win_tools/cubridservice/cubridservice.cpp | 16 +- .../method_compile.hpp => xasl/xasl_sp.hpp} | 40 +- util/CMakeLists.txt | 17 +- win/cubridcs/cubridcs.def | 4 + win/cubridsa/cubridsa.def | 28 +- 304 files changed, 17534 insertions(+), 10864 deletions(-) delete mode 100644 demo/plcsql/README.md delete mode 100644 demo/plcsql/StmtForStaticSqlLoop-test-without-condition.sql delete mode 100644 demo/plcsql/demo_global_semantics_serial.sql delete mode 100644 demo/plcsql/demo_global_semantics_type.sql delete mode 100644 demo/plcsql/demo_global_semantics_udpf.sql delete mode 100644 demo/plcsql/demo_hello.sql delete mode 100644 demo/plcsql/demo_hello_ret.sql delete mode 100644 demo/plcsql/test_ddl.sql delete mode 100644 demo/plcsql/test_dml_delete.sql delete mode 100644 demo/plcsql/test_dml_insert.sql delete mode 100644 demo/plcsql/test_dml_truncate.sql delete mode 100644 demo/plcsql/test_query_cursor_hostvar.sql delete mode 100644 demo/plcsql/test_query_cursor_simple.sql delete mode 100644 demo/plcsql/test_query_cursor_simple_nocond.sql delete mode 100644 demo/plcsql/test_query_single_row.sql delete mode 100644 demo/plcsql/test_query_single_row_const.sql delete mode 100644 demo/plcsql/test_semantic_error_unknown_tbl.sql delete mode 100644 demo/plcsql/test_semantic_error_wrong_literal.sql delete mode 100644 demo/plcsql/test_tcl_commit.sql delete mode 100644 demo/plcsql/test_tcl_rollback.sql create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/SysParam.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoader.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderGroup.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderManager.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/ClassAccess.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCode.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCodeSet.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClass.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClassCache.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/Signature.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/SourceCode.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryFileManager.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryJavaCompiler.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/AuthInfo.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileRequest.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/BootstrapRequest.java create mode 100644 src/base/msgcat_glossary.hpp create mode 100644 src/communication/network_callback_cl.cpp create mode 100644 src/communication/network_callback_cl.hpp create mode 100644 src/communication/network_callback_sr.cpp create mode 100644 src/communication/network_callback_sr.hpp delete mode 100644 src/executables/master_server_monitor.cpp delete mode 100644 src/executables/master_server_monitor.hpp rename src/executables/{javasp.cpp => pl.cpp} (50%) delete mode 100644 src/method/method_compile.cpp delete mode 100644 src/method/method_connection.hpp delete mode 100644 src/method/method_connection_cl.cpp delete mode 100644 src/method/method_connection_cl.hpp delete mode 100644 src/method/method_connection_java.cpp delete mode 100644 src/method/method_connection_java.hpp delete mode 100644 src/method/method_connection_pool.cpp delete mode 100644 src/method/method_connection_pool.hpp delete mode 100644 src/method/method_connection_sr.cpp delete mode 100644 src/method/method_connection_sr.hpp delete mode 100644 src/method/method_def.cpp delete mode 100644 src/method/method_def.hpp delete mode 100644 src/method/method_invoke.hpp delete mode 100644 src/method/method_invoke_builtin.cpp delete mode 100644 src/method/method_invoke_group.cpp delete mode 100644 src/method/method_invoke_java.cpp delete mode 100644 src/sp/Makefile_jspserver delete mode 100644 src/sp/jsp_cl.c create mode 100644 src/sp/jsp_cl.cpp delete mode 100644 src/sp/jsp_file.h create mode 100644 src/sp/method_invoke_group.cpp rename src/{method => sp}/method_invoke_group.hpp (60%) rename src/sp/{jsp_comm.c => pl_comm.c} (88%) rename src/sp/{jsp_comm.h => pl_comm.h} (71%) create mode 100644 src/sp/pl_compile_handler.cpp create mode 100644 src/sp/pl_compile_handler.hpp create mode 100644 src/sp/pl_connection.cpp create mode 100644 src/sp/pl_connection.hpp create mode 100644 src/sp/pl_execution_stack_context.cpp create mode 100644 src/sp/pl_execution_stack_context.hpp create mode 100644 src/sp/pl_executor.cpp create mode 100644 src/sp/pl_executor.hpp rename src/sp/{jsp_file.c => pl_file.c} (54%) create mode 100644 src/sp/pl_file.h rename src/{method/method_query_cursor.cpp => sp/pl_query_cursor.cpp} (89%) rename src/{method/method_query_cursor.hpp => sp/pl_query_cursor.hpp} (87%) rename src/{method/method_runtime_context.cpp => sp/pl_session.cpp} (55%) rename src/{method/method_runtime_context.hpp => sp/pl_session.hpp} (62%) create mode 100644 src/sp/pl_signature.cpp create mode 100644 src/sp/pl_signature.hpp rename src/sp/{jsp_sr.h => pl_signature_packing_helper.hpp} (55%) create mode 100644 src/sp/pl_sr.cpp create mode 100644 src/sp/pl_sr.h rename src/sp/{jsp_sr.c => pl_sr_jvm.cpp} (68%) rename src/{method/method_compile_def.cpp => sp/pl_struct_compile.cpp} (90%) rename src/{method/method_compile_def.hpp => sp/pl_struct_compile.hpp} (85%) create mode 100644 src/sp/sp_catalog.cpp create mode 100644 src/sp/sp_catalog.hpp create mode 100644 src/sp/sp_code.cpp create mode 100644 src/sp/sp_code.hpp create mode 100644 src/sp/sp_constants.hpp rename src/{method/method_compile.hpp => xasl/xasl_sp.hpp} (52%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 435f588d3d..6f3ade3ff0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,7 @@ test_defaults: &test_defaults shell: /bin/bash environment: _JAVA_OPTIONS: -Xmx1g + BRANCH_TESTCASES: feature/plcsql-p1 command: | ulimit -c 1 /entrypoint.sh checkout @@ -50,7 +51,7 @@ jobs: build: <<: *defaults environment: - MAKEFLAGS: -j 10 + MAKEFLAGS: -j 8 resource_class: large steps: - checkout @@ -149,4 +150,6 @@ workflows: requires: - build - - build-windows + - build-windows: + requires: + - build diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ea260ec4c0..939832b8ec 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -23,7 +23,7 @@ /src/broker/ @kisoo-han /src/cm_common/ @kisoo-han /src/compat/ @beyondykk9 -/src/jsp/ @beyondykk9 +/src/sp/ @beyondykk9 /src/method/ @beyondykk9 /src/optimizer/ @shparkcubrid /src/parser/ @beyondykk9 @@ -51,3 +51,4 @@ /src/thread @beyondykk9 /src/loaddb @kisoo-han +/pl_engine @beyondykk9 diff --git a/contrib/msg/de_DE.utf8/cubrid.msg b/contrib/msg/de_DE.utf8/cubrid.msg index 0262ec6470..c137fc259b 100644 --- a/contrib/msg/de_DE.utf8/cubrid.msg +++ b/contrib/msg/de_DE.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ $ LOADDB 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Letzter Fehler +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Letzter Fehler $set 6 MSGCAT_SET_INTERNAL 1 Fehler in Fehler-Subsystem (Zeile %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Außer virtuellem Speicher: %1$d Bytes können nicht zugewiesen werden. diff --git a/contrib/msg/de_DE.utf8/utils.msg b/contrib/msg/de_DE.utf8/utils.msg index 9bbe93bc47..2285891622 100644 --- a/contrib/msg/de_DE.utf8/utils.msg +++ b/contrib/msg/de_DE.utf8/utils.msg @@ -157,7 +157,7 @@ Vorhandene Serviceutilities:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Vorhandene Administratorutilities:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Vorhandene Befehle:\n\ 42 Parameter ist Ungültig.\n 43 Datei(%1$s) offene Fehler.\n 44 Cubrid Utility, Version %1$s\n\ -Anwendung: %2$s javasp [args]\n\ +Anwendung: %2$s pl [args]\n\ \n\ Vorhandene Befehle:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/es_ES.utf8/cubrid.msg b/contrib/msg/es_ES.utf8/cubrid.msg index 753aa31a42..e6dbc954a8 100644 --- a/contrib/msg/es_ES.utf8/cubrid.msg +++ b/contrib/msg/es_ES.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ Verifique la ruta del archivo de claves (_keys) y asegúrese de que incluya la c 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Ultimo error +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Ultimo error $set 6 MSGCAT_SET_INTERNAL 1 Error en subsistema de error (linea %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Sin memoria virtual: incapaz de asignar %1$d bytes. diff --git a/contrib/msg/es_ES.utf8/utils.msg b/contrib/msg/es_ES.utf8/utils.msg index c7f80c04cc..bced20a445 100644 --- a/contrib/msg/es_ES.utf8/utils.msg +++ b/contrib/msg/es_ES.utf8/utils.msg @@ -157,7 +157,7 @@ Utilidades de servicio disponible:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Utilidades de administrador disponible:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Comando disponible: \n\ 42 Argumento invalido.\n 43 Error al abrir archivo (%1$s).\n 44 utilidad de cubrid, version %1$s\n\ -uso: %2$s javasp [args]\n\ +uso: %2$s pl [args]\n\ \n\ Comando disponible:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/fr_FR.utf8/cubrid.msg b/contrib/msg/fr_FR.utf8/cubrid.msg index 7729f06c27..bbe0e738c2 100644 --- a/contrib/msg/fr_FR.utf8/cubrid.msg +++ b/contrib/msg/fr_FR.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ Vérifiez le chemin du fichier de clé (_keys) et assurez-vous qu'il inclut la c 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Dernière erreur +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Dernière erreur $set 6 MSGCAT_SET_INTERNAL 1 Erreur dans le sous-système d'erreur (ligne %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Mémoire virtuelle épuisée: impossible d'allouer %1$d octets. diff --git a/contrib/msg/fr_FR.utf8/utils.msg b/contrib/msg/fr_FR.utf8/utils.msg index 51da8d5181..97696d8624 100644 --- a/contrib/msg/fr_FR.utf8/utils.msg +++ b/contrib/msg/fr_FR.utf8/utils.msg @@ -157,7 +157,7 @@ Utilitaires de service disponibles\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Utilitaires d'administrateur disponibles:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Commandes disponibles:\n\ 42 Argument invalide.\n 43 Erreur d'ouverture du fichier(%1$s).\n 44 utilitaire CUBRID, version %1$s\n\ -usage: %2$s javasp [args]\n\ +usage: %2$s pl [args]\n\ \n\ Commandes disponibles:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/it_IT.utf8/cubrid.msg b/contrib/msg/it_IT.utf8/cubrid.msg index db528edf19..96f1bfe793 100644 --- a/contrib/msg/it_IT.utf8/cubrid.msg +++ b/contrib/msg/it_IT.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ Controllare il percorso del file della chiave (_keys) e assicurarsi che includa 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Ultimo errore +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Ultimo errore $set 6 MSGCAT_SET_INTERNAL 1 Errore nel sottosistema di errore (linea %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Fuori di memoria virtuale: Impossibile allocare %1$d byte. diff --git a/contrib/msg/it_IT.utf8/utils.msg b/contrib/msg/it_IT.utf8/utils.msg index 19f1af94c0..9753fdd233 100644 --- a/contrib/msg/it_IT.utf8/utils.msg +++ b/contrib/msg/it_IT.utf8/utils.msg @@ -157,7 +157,7 @@ Servizi disponibili:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Utilità amministrazione disponibili:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Commandi disponibili:\n\ 42 Argomento non valido.\n 43 Errore di apertura file(%1$s).\n 44 utilità cubrid, versione %1$s\n\ -uso: %2$s javasp [args]\n\ +uso: %2$s pl [args]\n\ \n\ Commandi disponibili:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/ja_JP.utf8/cubrid.msg b/contrib/msg/ja_JP.utf8/cubrid.msg index 7d8a0ddc43..f11473cf27 100644 --- a/contrib/msg/ja_JP.utf8/cubrid.msg +++ b/contrib/msg/ja_JP.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ $ LOADDB 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 ラストエラー +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 ラストエラー $set 6 MSGCAT_SET_INTERNAL 1 エラーサブシステムにエラー発生(ライン %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 バチャールメモリーが足りません。: %1$dバイトがアロケーションできません。 diff --git a/contrib/msg/ja_JP.utf8/utils.msg b/contrib/msg/ja_JP.utf8/utils.msg index bcaac83211..d0dc0f3739 100644 --- a/contrib/msg/ja_JP.utf8/utils.msg +++ b/contrib/msg/ja_JP.utf8/utils.msg @@ -157,7 +157,7 @@ cubrid 管理者ユーティリティー、バージョン %1$s\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ 正しい管理者ユーティリティー名:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ cubrid 管理者ユーティリティー、バージョン %1$s\n\ 42 無効なパラメーターです。\n 43 ファイル「%1$s」のオープンに失敗しました。\n 44 cubridユーティリティー、バージョン %1$s\n\ -使い方: %2$s javasp <コマンド> [パラメーター]\n\ +使い方: %2$s pl <コマンド> [パラメーター]\n\ \n\ 正しいコマンド:\n\ - start [データベース名]\n\ - stop [データベース名]\n\ restart [データベース名]\n\ status [データベース名]\n 45 cubridユーティリティー、バージョン %1$s\n\ diff --git a/contrib/msg/km_KH.utf8/cubrid.msg b/contrib/msg/km_KH.utf8/cubrid.msg index 6abf7e0698..525ea7cd9c 100644 --- a/contrib/msg/km_KH.utf8/cubrid.msg +++ b/contrib/msg/km_KH.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Last Error +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. diff --git a/contrib/msg/km_KH.utf8/utils.msg b/contrib/msg/km_KH.utf8/utils.msg index 53fbe8b633..e100d59e0b 100644 --- a/contrib/msg/km_KH.utf8/utils.msg +++ b/contrib/msg/km_KH.utf8/utils.msg @@ -157,7 +157,7 @@ Available service's utilities:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Available administrator's utilities:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Available command:\n\ 42 Invalid argument.\n 43 File(%1$s) open error.\n 44 cubrid utility, version %1$s\n\ -usage: %2$s javasp [args]\n\ +usage: %2$s pl [args]\n\ \n\ Available command:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/ro_RO.utf8/cubrid.msg b/contrib/msg/ro_RO.utf8/cubrid.msg index 81391a4ce7..d6452c4416 100644 --- a/contrib/msg/ro_RO.utf8/cubrid.msg +++ b/contrib/msg/ro_RO.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ Verificați calea fișierului cheie (_keys) și asigurați-vă că acesta includ 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Ultima eroare +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Ultima eroare $set 6 MSGCAT_SET_INTERNAL 1 Eroare în subsistemul de erori (linia %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Memorie virtuală epuizată: nu s-au putut aloca %1$d bytes. diff --git a/contrib/msg/ro_RO.utf8/utils.msg b/contrib/msg/ro_RO.utf8/utils.msg index 40e423bc4a..cb6f231559 100644 --- a/contrib/msg/ro_RO.utf8/utils.msg +++ b/contrib/msg/ro_RO.utf8/utils.msg @@ -157,7 +157,7 @@ Utilitare de serviciu disponibile:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Utilitare de administrare disponibile:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Comenzi disponibile:\n\ 42 Argument invalid.\n 43 Eroare la deschiderea fişierului(%1$s).\n 44 utilitar CUBRID, versiunea %1$s\n\ -utilizare: %2$s javasp [args]\n\ +utilizare: %2$s pl [args]\n\ \n\ Comenzi disponibile:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/tr_TR.utf8/cubrid.msg b/contrib/msg/tr_TR.utf8/cubrid.msg index 0fa6891ae5..2c87c6619b 100644 --- a/contrib/msg/tr_TR.utf8/cubrid.msg +++ b/contrib/msg/tr_TR.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ Anahtar dosyasının (_keys) yolunu kontrol edin ve uygun anahtarı içerdiğind 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Son Hata +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Son Hata $set 6 MSGCAT_SET_INTERNAL 1 Alt Hata içinde hata (satır %1$d): @@ -1937,7 +1938,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Sanal bellek yetersiz: %1$d bayt bölüm ayıramadı. diff --git a/contrib/msg/tr_TR.utf8/utils.msg b/contrib/msg/tr_TR.utf8/utils.msg index ec9f0a279d..04fb5aa058 100644 --- a/contrib/msg/tr_TR.utf8/utils.msg +++ b/contrib/msg/tr_TR.utf8/utils.msg @@ -157,7 +157,7 @@ Mevcut hizmetin programları:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Mevcut yönetici programları:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Mevcut komut:\n\ 42 Değişken geçersiz.\n 43 (%1$s) dosya açma hatası.\n 44 cubrid yardımcı programı, sürüm %1$s\n\ -kullanım: %2$s javasp [args]\n\ +kullanım: %2$s pl [args]\n\ \n\ Mevcut komut:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/vi_VN.utf8/cubrid.msg b/contrib/msg/vi_VN.utf8/cubrid.msg index 96ebb1c07a..eac8d47166 100644 --- a/contrib/msg/vi_VN.utf8/cubrid.msg +++ b/contrib/msg/vi_VN.utf8/cubrid.msg @@ -1452,8 +1452,9 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 Last Error +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1944,7 +1945,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. diff --git a/contrib/msg/vi_VN.utf8/utils.msg b/contrib/msg/vi_VN.utf8/utils.msg index 8ce230523f..0b80a30829 100644 --- a/contrib/msg/vi_VN.utf8/utils.msg +++ b/contrib/msg/vi_VN.utf8/utils.msg @@ -157,7 +157,7 @@ Available service's utilities:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Available administrator's utilities:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Available command:\n\ 42 Invalid argument.\n 43 File(%1$s) open error.\n 44 cubrid utility, version %1$s\n\ -usage: %2$s javasp [args]\n\ +usage: %2$s pl [args]\n\ \n\ Available command:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/contrib/msg/zh_CN.utf8/cubrid.msg b/contrib/msg/zh_CN.utf8/cubrid.msg index b6bc389bb9..953d0dbcc9 100644 --- a/contrib/msg/zh_CN.utf8/cubrid.msg +++ b/contrib/msg/zh_CN.utf8/cubrid.msg @@ -1446,8 +1446,9 @@ $ LOADDB 1359 Java VM crashed: %1$s 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s - -1361 最后一个错误. +1361 Dropping system generated stored procedure is not allowed. +1362 PL/CSQL Stored procedure/function does not support Invoker's rights +1363 最后一个错误. $set 6 MSGCAT_SET_INTERNAL 1 在错误子系统中错误 (line %1$d): @@ -1938,7 +1939,10 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 Unsupported return type '%1$s' of the stored procedure 321 %TYPE type specification is allowed only for PL/CSQL 322 Table column '%1$s.%2$s' has not been defined -323 Stored procedure/function '%1$s' has OUT or IN OUT arguments +323 Stored procedure/function "%1$s" does not exist. +324 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +325 Only trailing default parameter is allowed: invalid at '%1$s'. +326 Stored procedure/function '%1$s' has OUT or IN OUT arguments $set 9 MSGCAT_SET_PARSER_RUNTIME 1 虚拟内存耗尽: 无法申请 %1$d 字节. diff --git a/contrib/msg/zh_CN.utf8/utils.msg b/contrib/msg/zh_CN.utf8/utils.msg index 9f2af417d3..2d92f513a3 100644 --- a/contrib/msg/zh_CN.utf8/utils.msg +++ b/contrib/msg/zh_CN.utf8/utils.msg @@ -157,7 +157,7 @@ cubrid 管理工具,版本 %1$s\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ 可用的管理员工具:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ cubrid 管理工具,版本 %1$s\n\ 42 无效的参数.\n 43 打开文件 (%1$s) 时出错.\n 44 cubrid 应用工具, 版本 %1$s\n\ -用法: %2$s javasp <命令> [参数]\n\ +用法: %2$s pl <命令> [参数]\n\ \n\ 可用命令:\n\ - start [数据库名]\n\ - stop [数据库名]\n\ restart [数据库名]\n\ status [数据库名]\n 45 cubrid 应用工具, 版本 %1$s\n\ diff --git a/contrib/scripts/check_reserved.sql b/contrib/scripts/check_reserved.sql index 11efc3dda8..f70a477d12 100644 --- a/contrib/scripts/check_reserved.sql +++ b/contrib/scripts/check_reserved.sql @@ -31,7 +31,7 @@ UNION ALL SELECT 'stored_proc', sp_name, '', '' FROM _db_stored_procedure WHERE sp_name IN :reserved UNION ALL -SELECT 'stored_proc_arg', arg_name, '', sp_name +SELECT 'stored_proc_arg', arg_name, '', sp_of.sp_name FROM _db_stored_procedure_args WHERE arg_name IN :reserved UNION ALL SELECT 'user', name, '', '' diff --git a/cs/CMakeLists.txt b/cs/CMakeLists.txt index 91b4336eeb..65fef46f6e 100644 --- a/cs/CMakeLists.txt +++ b/cs/CMakeLists.txt @@ -122,6 +122,7 @@ set(BASE_SOURCES ${BASE_DIR}/pinning.cpp ${BASE_DIR}/porting.c ${BASE_DIR}/printer.cpp + ${BASE_DIR}/process_util.c ${BASE_DIR}/release_string.c ${BASE_DIR}/resource_tracker.cpp ${BASE_DIR}/sha1.c @@ -187,6 +188,7 @@ set(CONNECTION_SOURCES set(COMMUNICATION_SOURCES ${COMMUNICATION_DIR}/network_common.cpp + ${COMMUNICATION_DIR}/network_callback_cl.cpp ${COMMUNICATION_DIR}/network_interface_cl.c ${COMMUNICATION_DIR}/network_cl.c ${COMMUNICATION_DIR}/network_histogram.cpp @@ -306,16 +308,15 @@ set(OBJECT_HEADERS ) set(SP_SOURCES - ${SP_DIR}/jsp_cl.c - ${SP_DIR}/jsp_comm.c - ${SP_DIR}/jsp_file.c + ${SP_DIR}/jsp_cl.cpp + ${SP_DIR}/pl_signature.cpp + ${SP_DIR}/pl_comm.c + ${SP_DIR}/pl_struct_compile.cpp + ${SP_DIR}/sp_catalog.cpp ) set(METHOD_SOURCES - ${METHOD_DIR}/method_connection_cl.cpp - ${METHOD_DIR}/method_compile_def.cpp ${METHOD_DIR}/method_callback.cpp - ${METHOD_DIR}/method_def.cpp ${METHOD_DIR}/method_error.cpp ${METHOD_DIR}/method_oid_handler.cpp ${METHOD_DIR}/method_query_handler.cpp @@ -554,14 +555,14 @@ if(WIN32) target_link_libraries(cubridcs LINK_PRIVATE ws2_32) set_target_properties(cubridcs PROPERTIES LINK_FLAGS "/DEF:\"${CMAKE_SOURCE_DIR}/win/cubridcs/cubridcs.def\"" LINK_FLAGS_RELEASE "/NODEFAULTLIB:libcmt.lib" LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt.lib") endif(WIN32) -target_include_directories(cubridcs PRIVATE ${FLEX_INCLUDE_DIRS} ${EP_INCLUDES}) +target_include_directories(cubridcs PRIVATE ${FLEX_INCLUDE_DIRS} ${JAVA_INC} ${EP_INCLUDES}) if(UNIX) target_link_libraries(cubridcs LINK_PRIVATE -Wl,-whole-archive ${EP_LIBS} -Wl,-no-whole-archive) target_link_libraries(cubridcs PUBLIC stdc++fs) target_link_libraries(cubridcs LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) target_link_libraries(cubridcs LINK_PUBLIC rt) else(UNIX) - target_link_libraries(cubridcs LINK_PRIVATE ${EP_LIBS}) + target_link_libraries(cubridcs LINK_PRIVATE ${EP_LIBS} ${JVM_LIBS}) endif(UNIX) # for dblink target_link_libraries(cubridcs PUBLIC cascci) diff --git a/cubrid/CMakeLists.txt b/cubrid/CMakeLists.txt index 9d1b8f8b21..08b185d1c8 100644 --- a/cubrid/CMakeLists.txt +++ b/cubrid/CMakeLists.txt @@ -196,6 +196,7 @@ set(CONNECTION_SOURCES set(COMMUNICATION_SOURCES ${COMMUNICATION_DIR}/network_common.cpp + ${COMMUNICATION_DIR}/network_callback_sr.cpp ${COMMUNICATION_DIR}/network_interface_sr.c ${COMMUNICATION_DIR}/network_sr.c ) @@ -280,23 +281,30 @@ set(OBJECT_HEADERS ) set(SP_SOURCES - ${SP_DIR}/jsp_comm.c - ${SP_DIR}/jsp_file.c - ${SP_DIR}/jsp_sr.c - ) + ${SP_DIR}/method_invoke_group.cpp + ${SP_DIR}/pl_connection.cpp + ${SP_DIR}/pl_compile_handler.cpp + ${SP_DIR}/pl_execution_stack_context.cpp + ${SP_DIR}/pl_executor.cpp + ${SP_DIR}/pl_query_cursor.cpp + ${SP_DIR}/pl_session.cpp + ${SP_DIR}/pl_signature.cpp + ${SP_DIR}/pl_comm.c + ${SP_DIR}/pl_file.c + ${SP_DIR}/pl_sr.cpp + ${SP_DIR}/pl_sr_jvm.cpp + ${SP_DIR}/sp_code.cpp + ) + +set(SP_HEADERS + ${SP_DIR}/pl_connection.hpp + ${SP_DIR}/pl_execution_stack_context.hpp + ${SP_DIR}/pl_signature.hpp + ${SP_DIR}/pl_struct_compile.cpp +) set(METHOD_SOURCES - ${METHOD_DIR}/method_connection_java.cpp - ${METHOD_DIR}/method_connection_sr.cpp - ${METHOD_DIR}/method_connection_pool.cpp - ${METHOD_DIR}/method_compile_def.cpp - ${METHOD_DIR}/method_compile.cpp - ${METHOD_DIR}/method_def.cpp ${METHOD_DIR}/method_error.cpp - ${METHOD_DIR}/method_invoke_builtin.cpp - ${METHOD_DIR}/method_invoke_group.cpp - ${METHOD_DIR}/method_invoke_java.cpp - ${METHOD_DIR}/method_query_cursor.cpp ${METHOD_DIR}/method_query_util.cpp ${METHOD_DIR}/method_struct_invoke.cpp ${METHOD_DIR}/method_struct_value.cpp @@ -305,7 +313,6 @@ set(METHOD_SOURCES ${METHOD_DIR}/method_struct_schema_info.cpp ${METHOD_DIR}/method_struct_parameter_info.cpp ${METHOD_DIR}/method_scan.cpp - ${METHOD_DIR}/method_runtime_context.cpp ${METHOD_DIR}/query_method.cpp ) @@ -528,6 +535,7 @@ set (CUBRID_LIB_HEADERS ${OBJECT_HEADERS} ${QUERY_HEADERS} ${STORAGE_HEADERS} + ${SP_HEADERS} ${THREAD_HEADERS} ${TRANSACTION_HEADERS} ${XASL_HEADERS} diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index 9dbd42e631..a01ae376f4 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -21,11 +21,6 @@ install(FILES ${CMAKE_SOURCE_DIR}/demo/demodb_schema DESTINATION ${CUBRID_DEMODIR}) -install(DIRECTORY - ${CMAKE_SOURCE_DIR}/demo/plcsql - DESTINATION ${CUBRID_DEMODIR} -) - if(UNIX) set(DEMODB_SCRIPT make_cubrid_demo.sh) else(UNIX) diff --git a/demo/plcsql/README.md b/demo/plcsql/README.md deleted file mode 100644 index f903993bda..0000000000 --- a/demo/plcsql/README.md +++ /dev/null @@ -1,478 +0,0 @@ -# PLCSQL Demonstaration - -## Table of Contents - -1. [DBMS_OUTPUT](##-1.-DBMS_OUTPUT.put_line) -2. [Static SQL](##-2.-Static-SQL) -3. [TCL](##-3.-TCL-(COMMIT/ROLLBACK)) -4. [Procedure/Function](##-4.-Procedure/Function) -5. [%TYPE](##-5.-%TYPE) -6. [Pseudocolumn](##-6.-Pseudocolumn) ---- -## 1. DBMS_OUTPUT.put_line -- [demo_hello.sql](./demo_hello.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/demo_hello.sql -``` - -``` --- test -csql -u public demodb -;server-output on - call demo_hello (); -;ex -``` - -``` --- expected -Hello CUBRID PL/CSQL! -``` ---- -## 2. Static SQL -### 2.1 Query - Single Rows -- [test_query_single_row_const.sql](./test_query_single_row_const.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_query_single_row_const.sql -``` - -``` --- test -csql -u public demodb -;server-output on - select test_query_single_row_const (); -;ex -``` -``` --- expected - test_query_single_row_const() -=============================== - 10615 -``` - -- [test_query_single_row.sql](./test_query_single_row.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_query_single_row.sql -``` - -``` --- sample -11847 'Kim Yong-Bae' -11844 'Kim Taek Soo' -11843 'Kim Tae-Gyun' -11842 'Kim Soo-Kyung' -11836 'Kim Moon-Soo' -11833 'Kim Min-Soo' -11830 'Kim Kyung-Seok' -11829 'Kim Kyong-Hun' -11828 'Kim Ki-Tai' -11827 'Kim Jung-Chul' -11825 'Kim Jong-Shin' -11823 'Kim In-Sub' -11820 'Kim Han-Soo' -``` -``` --- test -csql -u public demodb -;server-output on - select test_query_single_row (11828); -;ex -``` -``` --- expected - test_query_single_row(11828) -====================== - 'Kim Ki-Tai' -``` -### 2.2 Query - Cursor -- [test_query_cursor_simple_nocond.sql](./test_query_cursor_simple_nocond.sql) -- [test_query_cursor_simple.sql](./test_query_cursor_simple.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_query_cursor_simple_nocond.sql -csql -u public demodb -i $CUBRID/demo/plcsql/test_query_cursor_simple.sql -``` - -``` --- test -csql -u public demodb -;server-output on - select test_query_cursor_simple_nocond (); - select test_query_cursor_simple (); -;ex -``` -``` --- expected - test_query_cursor_simple_nocond() -=================================== - 10999 - - test_query_cursor_simple() -============================ - 10615 -``` - -- [test_query_cursor_hostvar.sql](./test_query_cursor_hostvar.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_query_cursor_hostvar.sql -``` - -``` --- test -csql -u public demodb -;server-output on - select test_query_cursor_hostvar (); -;ex -``` -``` --- expected - test_query_cursor_hostvar() -====================== - 'Han Myung-Woo' -``` -### 2.3 DDL (Dynamic SQL), DML - -#### Dynmaic SQL -- [test_ddl.sql](./test_ddl.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_ddl.sql -``` - -``` --- test -csql -u public demodb -;server-output on - call test_ddl (); - desc a_tbl1; -;ex -``` -``` --- expected -creating a_tbl1 table is succeed! - - Field Type Null Key Default Extra -==================================================================================================================================== - 'id' 'INTEGER' 'YES' 'UNI' NULL '' - 'name' 'VARCHAR(1073741823)' 'YES' '' NULL '' - 'phone' 'VARCHAR(1073741823)' 'YES' '' '000-0000' '' -``` - -#### INSERT -- [test_dml_insert.sql](./test_dml_insert.sql) -- [test_dml_truncate.sql](./test_dml_truncate.sql) -``` --- preparation and registration -csql -u public demodb - drop table if exists a_tbl1; - CREATE TABLE a_tbl1(id INT UNIQUE, name VARCHAR, phone VARCHAR DEFAULT '000-0000'); -;ex - -csql -u public demodb -i $CUBRID/demo/plcsql/test_dml_insert.sql -csql -u public demodb -i $CUBRID/demo/plcsql/test_dml_truncate.sql -``` - -``` --- test -csql -u public demodb -;server-output on - call test_dml_insert (); -;ex -``` - -``` --- expected -/* (((((( */INSERT INTO a_tbl1 SET id=6, name='eee';/* (((((( */ -/* (((((( */INSERT INTO a_tbl1 SET id=6, name='eee';/* (((((( */ is succeed -[Test 1] ===================================================================== -Expected: -6 eee 666-6666 -Actual: -6 eee 666-6666 -[Test 1] OK -[Test 2] ===================================================================== -Expected: -7 ggg 777-7777 -Actual: -7 ggg 777-7777 -[Test 2] OK -``` - -#### TRUNCATE -``` --- test -csql -u public demodb -;server-output on - call test_dml_truncate (); - SELECT * FROM a_tbl1; -;ex -``` - -``` --- expected -There are no results. -``` - -#### DELETE -- [test_dml_delete.sql](./test_dml_delete.sql) -``` --- preparation -csql -u public demodb - DROP TABLE a_tbl; - CREATE TABLE a_tbl( - id INT NOT NULL, - phone VARCHAR(10)); - INSERT INTO a_tbl VALUES(1,'111-1111'), (2,'222-2222'), (3, '333-3333'), (4, NULL), (5, NULL); -;ex -``` -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_dml_delete.sql -``` - -``` --- test -csql -u public demodb -;server-output on - call test_dml_delete (); -;ex -``` -``` --- expected -111-1111 -222-2222 -333-3333 -``` - -## 3. TCL (COMMIT/ROLLBACK) - -### COMMIT -- [test_tcl_commit.sql](./test_tcl_commit.sql) -``` --- preparation -csql -u public demodb - DROP TABLE IF EXISTS test_tcl_tbl; - CREATE TABLE test_tcl_tbl (code INT, name STRING); -;ex -``` -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_tcl_commit.sql -``` - -``` --- test (;set pl_transaction_control=yes) -csql -u public demodb -;set pl_transaction_control=yes -;autocommit off -;server-output on - TRUNCATE test_tcl_tbl; - COMMIT; - SELECT * FROM test_tcl_tbl; - CALL test_tcl_commit (); - ROLLBACK; -- rollback in csql session - - SELECT * FROM test_tcl_tbl; -- committed rows should be displayed - ROLLBACK; -;ex -``` -``` --- expected - -// CALL test_tcl_commit (); -code = 3, name = ccc -code = 4, name = ddd - -// SELECT * FROM test_tcl_tbl; - code name -=================================== - 1 'aaa' - 2 'bbb' - 3 'ccc' - 4 'ddd' -``` - -``` --- test (;set pl_transaction_control=no) -csql -u public demodb -;set pl_transaction_control=no -;autocommit off -;server-output on - TRUNCATE test_tcl_tbl; - COMMIT; -- COMMIT is required to ensure TRUNCATE is executed according to the TRUNCATE spec. - - SELECT * FROM test_tcl_tbl; - CALL test_tcl_commit (); - ROLLBACK; -- rollback in csql session - SELECT * FROM test_tcl_tbl; -- COMMIT in test_tcl_commit () must be ignored - ROLLBACK; -;ex -``` - -``` --- expected - -// CALL test_tcl_commit (); -code = 3, name = ccc -code = 4, name = ddd - -// SELECT * FROM test_tcl_tbl; -There are no results. -``` - -### ROLLBACK -- [test_tcl_rollback.sql](./test_tcl_rollback.sql) -``` --- preparation -csql -u public demodb - DROP TABLE IF EXISTS test_tcl_tbl2; - CREATE TABLE test_tcl_tbl2 (code INT, name STRING); -;ex -``` -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/test_tcl_rollback.sql -``` - -``` --- test (;set pl_transaction_control=yes) -csql -u public demodb -;set pl_transaction_control=yes -;set autocommit off -;server-output on - TRUNCATE test_tcl_tbl2; - COMMIT; - CALL test_tcl_rollback (); - COMMIT; - SELECT * FROM test_tcl_tbl2; -;ex -``` - -``` --- expected - code name -=================================== - 1 'aaa' - 2 'bbb' - 3 'ccc' - 4 'ddd' -``` - -``` --- test (;set pl_transaction_control=no) -csql -u public demodb -;set pl_transaction_control=no -;set autocommit off -;server-output on - TRUNCATE test_tcl_tbl2; - COMMIT; - CALL test_tcl_rollback (); - COMMIT; - SELECT * FROM test_tcl_tbl2; -;ex -``` - -``` --- expected - code name -=================================== - 1 'aaa' - 2 'bbb' - 3 'ccc' - 4 'ddd' - 6 'daf' - 7 'qwe' -``` - ---- -## 4. Procedure/Function -- [demo_hello_ret.sql](./demo_hello_ret.sql) -- [demo_global_semantics_udpf.sql](./demo_global_semantics_udpf.sql) -``` --- registration -csql -u public demodb -i $CUBRID/demo/plcsql/demo_hello_ret.sql -csql -u public demodb -i $CUBRID/demo/plcsql/demo_global_semantics_udpf.sql -``` - -``` --- test -csql -u public demodb -;server-output on - select demo_global_semantics_udpf (); -;ex -``` - -``` --- expected - demo_global_semantics_udpf() -====================== - 'hello cubrid' - -Hello CUBRID PL/CSQL! -``` ---- -## 5. %TYPE -- [demo_global_semantics_type.sql](./demo_global_semantics_type.sql) --- registration -``` -csql -u public demodb -i $CUBRID/demo/plcsql/demo_global_semantics_type.sql -``` - -``` --- test -csql -u public demodb -;server-output on - select demo_global_semantics_type (); -;ex -``` -``` --- expected - demo_global_semantics_type() -====================== - 'Chung Min-Tae' -``` ---- -## 6. Pseudocolumn - -### 6.1 Serial -- [demo_global_semantics_serial.sql](./demo_global_semantics_serial.sql) -``` --- preparation -csql -u public demodb - DROP SERIAL demo_pl_serial; - CREATE SERIAL demo_pl_serial; -;ex -``` - --- registration -``` -csql -u public demodb -i $CUBRID/demo/plcsql/demo_global_semantics_serial.sql -``` - -``` --- test -csql -u public demodb -;server-output on - select demo_global_semantics_serial (); - select demo_global_semantics_serial (); - select demo_global_semantics_serial (); -;ex -``` - -``` --- expected - demo_global_semantics_serial() -====================== - 1 - - demo_global_semantics_serial() -====================== - 2 - - demo_global_semantics_serial() -====================== - 3 -``` diff --git a/demo/plcsql/StmtForStaticSqlLoop-test-without-condition.sql b/demo/plcsql/StmtForStaticSqlLoop-test-without-condition.sql deleted file mode 100644 index 31d44c652f..0000000000 --- a/demo/plcsql/StmtForStaticSqlLoop-test-without-condition.sql +++ /dev/null @@ -1,11 +0,0 @@ -create or replace function StmtForStaticSqlLoop_test_without_condition() return int as -i int; -begin - i := 0; - for r in (select code, name from athlete) loop - i := r.code; - EXIT; - end loop; - - return i; -end; diff --git a/demo/plcsql/demo_global_semantics_serial.sql b/demo/plcsql/demo_global_semantics_serial.sql deleted file mode 100644 index e9d074c592..0000000000 --- a/demo/plcsql/demo_global_semantics_serial.sql +++ /dev/null @@ -1,6 +0,0 @@ -create or replace function demo_global_semantics_serial() return numeric as -i numeric; -begin - i := demo_pl_serial.NEXT_VALUE; - return i; -end; \ No newline at end of file diff --git a/demo/plcsql/demo_global_semantics_type.sql b/demo/plcsql/demo_global_semantics_type.sql deleted file mode 100644 index 328cfa7168..0000000000 --- a/demo/plcsql/demo_global_semantics_type.sql +++ /dev/null @@ -1,12 +0,0 @@ -create or replace function demo_global_semantics_type() return string as -v_name athlete.name%TYPE; -g char(1) := 'M'; -n char(3) := 'KOR'; - -begin - for r in (select name from athlete where gender = g and nation_code = n) loop - v_name := r.name; - EXIT; - end loop; - return v_name; -end; \ No newline at end of file diff --git a/demo/plcsql/demo_global_semantics_udpf.sql b/demo/plcsql/demo_global_semantics_udpf.sql deleted file mode 100644 index f25fecaaf1..0000000000 --- a/demo/plcsql/demo_global_semantics_udpf.sql +++ /dev/null @@ -1,7 +0,0 @@ -create or replace function demo_global_semantics_udpf() return varchar as -m varchar; -begin - demo_hello (); - m := demo_hello_ret (); - return m; -end; \ No newline at end of file diff --git a/demo/plcsql/demo_hello.sql b/demo/plcsql/demo_hello.sql deleted file mode 100644 index d9db0445e5..0000000000 --- a/demo/plcsql/demo_hello.sql +++ /dev/null @@ -1,4 +0,0 @@ -create or replace procedure demo_hello() as -begin - DBMS_OUTPUT.put_line('Hello CUBRID PL/CSQL!'); -end; diff --git a/demo/plcsql/demo_hello_ret.sql b/demo/plcsql/demo_hello_ret.sql deleted file mode 100644 index 0581d99eea..0000000000 --- a/demo/plcsql/demo_hello_ret.sql +++ /dev/null @@ -1,4 +0,0 @@ -create or replace function demo_hello_ret() return varchar as -begin - return 'hello cubrid'; -end; diff --git a/demo/plcsql/test_ddl.sql b/demo/plcsql/test_ddl.sql deleted file mode 100644 index 6022a519d0..0000000000 --- a/demo/plcsql/test_ddl.sql +++ /dev/null @@ -1,11 +0,0 @@ -create or replace procedure test_ddl() as - i int; - n varchar; - p varchar; - - new_table VARCHAR := 'a_tbl1'; -begin - EXECUTE IMMEDIATE 'drop table if exists ' || new_table; - EXECUTE IMMEDIATE 'CREATE TABLE ' || new_table || ' (id INT UNIQUE, name VARCHAR, phone VARCHAR DEFAULT ''000-0000'');'; - DBMS_OUTPUT.put_line ('creating ' || new_table || ' table is succeed!'); -end; diff --git a/demo/plcsql/test_dml_delete.sql b/demo/plcsql/test_dml_delete.sql deleted file mode 100644 index 0a0be734af..0000000000 --- a/demo/plcsql/test_dml_delete.sql +++ /dev/null @@ -1,27 +0,0 @@ -/* https://www.cubrid.org/manual/en/11.2/sql/query/update.html */ -/* -DROP TABLE a_tbl; -CREATE TABLE a_tbl( - id INT NOT NULL, - phone VARCHAR(10)); -INSERT INTO a_tbl VALUES(1,'111-1111'), (2,'222-2222'), (3, '333-3333'), (4, NULL), (5, NULL); -*/ -create or replace procedure test_dml_delete() as - p varchar; -begin - DELETE FROM a_tbl WHERE phone IS NULL; - -/* - id phone -=================================== - 1 '111-1111' - 2 '222-2222' - 3 '333-3333' - 5 NULL -*/ - - for r in (SELECT phone FROM a_tbl) loop - p := r.phone; - DBMS_OUTPUT.PUT_LINE(p); - end loop; -end; diff --git a/demo/plcsql/test_dml_insert.sql b/demo/plcsql/test_dml_insert.sql deleted file mode 100644 index cc94cefaf1..0000000000 --- a/demo/plcsql/test_dml_insert.sql +++ /dev/null @@ -1,77 +0,0 @@ -/* https://www.cubrid.org/manual/en/11.2/sql/query/insert.html */ -/* - drop table if exists a_tbl1; - CREATE TABLE a_tbl1(id INT UNIQUE, name VARCHAR, phone VARCHAR DEFAULT '000-0000'); -*/ -create or replace procedure test_dml_insert() as - i int; - n varchar; - p varchar; - - new_table VARCHAR := 'a_tbl1'; - temp VARCHAR := ''; -begin --- 0) ---insert default values with DEFAULT keyword before VALUES - INSERT INTO a_tbl1 DEFAULT VALUES; - ---insert multiple rows - INSERT INTO a_tbl1 VALUES (1,'aaa', DEFAULT),(2,'bbb', DEFAULT); - ---insert a single row specifying column values for all - INSERT INTO a_tbl1 VALUES (3,'ccc', '333-3333'); - ---insert two rows specifying column values for only - INSERT INTO a_tbl1(id) VALUES (4), (5); - ---insert a single row with SET clauses - - temp := temp || '/* (('; - temp := temp || '(((( */'; - - temp := temp || 'INSERT INTO a_tbl1 SET id=6, name=''eee'';'; - - temp := temp || '/* (('; - temp := temp || '(((( */'; - - DBMS_OUTPUT.put_line (temp); - - EXECUTE IMMEDIATE temp; - DBMS_OUTPUT.put_line(temp || ' is succeed'); - - INSERT INTO a_tbl1 SET id=7, phone='777-7777'; - --- 1) - DBMS_OUTPUT.PUT_LINE('[Test 1] ====================================================================='); - INSERT INTO a_tbl1 SET id=6, phone='000-0000' ON DUPLICATE KEY UPDATE phone='666-6666'; - --- 2) - DBMS_OUTPUT.PUT_LINE('Expected: '); - DBMS_OUTPUT.PUT_LINE(6 || ' ' || 'eee' || ' ' || '666-6666'); - - DBMS_OUTPUT.PUT_LINE('Actual: '); - for r in (SELECT id, name, phone FROM a_tbl1 WHERE id=6) loop - i := r.id; - n := r.name; - p := r.phone; - DBMS_OUTPUT.PUT_LINE(i || ' ' || n || ' ' || p); - end loop; - DBMS_OUTPUT.PUT_LINE('[Test 1] OK'); - --- 3) - DBMS_OUTPUT.PUT_LINE('[Test 2] ====================================================================='); - DBMS_OUTPUT.PUT_LINE('Expected: '); - DBMS_OUTPUT.PUT_LINE(7 || ' ' || 'ggg' || ' ' || '777-7777'); - - INSERT INTO a_tbl1 SELECT * FROM a_tbl1 WHERE id=7 ON DUPLICATE KEY UPDATE name='ggg'; - - DBMS_OUTPUT.PUT_LINE('Actual: '); - for r in (SELECT id, name, phone FROM a_tbl1 WHERE id=7) loop - i := r.id; - n := r.name; - p := r.phone; - DBMS_OUTPUT.PUT_LINE(i || ' ' || n || ' ' || p); - end loop; - - DBMS_OUTPUT.PUT_LINE('[Test 2] OK'); -end; diff --git a/demo/plcsql/test_dml_truncate.sql b/demo/plcsql/test_dml_truncate.sql deleted file mode 100644 index c15666cc59..0000000000 --- a/demo/plcsql/test_dml_truncate.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* https://www.cubrid.org/manual/en/11.2/sql/query/truncate.html */ -/* - -*/ -create or replace procedure test_dml_truncate() as -begin - truncate TABLE a_tbl1; -end; diff --git a/demo/plcsql/test_query_cursor_hostvar.sql b/demo/plcsql/test_query_cursor_hostvar.sql deleted file mode 100644 index c87a288df2..0000000000 --- a/demo/plcsql/test_query_cursor_hostvar.sql +++ /dev/null @@ -1,22 +0,0 @@ -create or replace function test_query_cursor_hostvar() return varchar as - g char(1) := 'M'; - n char(3) := 'KOR'; - - i int; - m varchar; -begin - i := 0; - for r in (select code, name from athlete where gender = g and nation_code = n) loop - i := r.code; - m := r.name; - end loop; - - return m; -exception -when no_data_found then - return 'no_data'; -when too_many_rows then - return 'too_many'; -when others then - return 'others'; -end; diff --git a/demo/plcsql/test_query_cursor_simple.sql b/demo/plcsql/test_query_cursor_simple.sql deleted file mode 100644 index 75c86dc67e..0000000000 --- a/demo/plcsql/test_query_cursor_simple.sql +++ /dev/null @@ -1,11 +0,0 @@ -create or replace function test_query_cursor_simple() return int as -i int; -begin - i := 0; - for r in (select code, name from athlete where gender = 'M' and nation_code = 'KOR') loop - i := r.code; - EXIT; - end loop; - - return i; -end; diff --git a/demo/plcsql/test_query_cursor_simple_nocond.sql b/demo/plcsql/test_query_cursor_simple_nocond.sql deleted file mode 100644 index 3f0ca2a8b3..0000000000 --- a/demo/plcsql/test_query_cursor_simple_nocond.sql +++ /dev/null @@ -1,11 +0,0 @@ -create or replace function test_query_cursor_simple_nocond() return int as -i int; -begin - i := 0; - for r in (select code, name from athlete) loop - i := r.code; - EXIT; - end loop; - - return i; -end; \ No newline at end of file diff --git a/demo/plcsql/test_query_single_row.sql b/demo/plcsql/test_query_single_row.sql deleted file mode 100644 index fa20469f93..0000000000 --- a/demo/plcsql/test_query_single_row.sql +++ /dev/null @@ -1,16 +0,0 @@ -create or replace function test_query_single_row(c int) return string as - g char(1) := 'M'; - n char(3) := 'KOR'; - - m varchar; -begin - select name into m from athlete where gender = g and nation_code = n and code = c; - return m; -exception -when no_data_found then - return 'no_data_found'; -when too_many_rows then - return 'too_many_rows'; -when others then - return 'others'; -end; diff --git a/demo/plcsql/test_query_single_row_const.sql b/demo/plcsql/test_query_single_row_const.sql deleted file mode 100644 index 02c8fe4c59..0000000000 --- a/demo/plcsql/test_query_single_row_const.sql +++ /dev/null @@ -1,14 +0,0 @@ -create or replace function test_query_single_row_const() return int as - c int; - m varchar; -begin - select code, name INTO c, m from athlete where gender = 'M' and nation_code = 'KOR' LIMIT 1; - return c; -exception -when no_data_found then - return 0; -when too_many_rows then - return 100; -when others then - return -1; -end; diff --git a/demo/plcsql/test_semantic_error_unknown_tbl.sql b/demo/plcsql/test_semantic_error_unknown_tbl.sql deleted file mode 100644 index 942665b2f8..0000000000 --- a/demo/plcsql/test_semantic_error_unknown_tbl.sql +++ /dev/null @@ -1,4 +0,0 @@ -create or replace procedure test_semantic_error_unknown_tbl() as -begin - insert into unknown_tbl(t) values (time'12:13:14'); -end; diff --git a/demo/plcsql/test_semantic_error_wrong_literal.sql b/demo/plcsql/test_semantic_error_wrong_literal.sql deleted file mode 100644 index 1577716389..0000000000 --- a/demo/plcsql/test_semantic_error_wrong_literal.sql +++ /dev/null @@ -1,7 +0,0 @@ -/* - create table test_insert(t time); -*/ -create or replace procedure test_wrong_literal() as -begin - insert into test_insert(t) values (time'12:13:14.123'); -- wrong time literal -end; diff --git a/demo/plcsql/test_tcl_commit.sql b/demo/plcsql/test_tcl_commit.sql deleted file mode 100644 index 5b5dca1fa6..0000000000 --- a/demo/plcsql/test_tcl_commit.sql +++ /dev/null @@ -1,30 +0,0 @@ -/* -csql -u public demodb -DROP TABLE IF EXISTS test_tcl_tbl; -CREATE TABLE test_tcl_tbl (code INT, name STRING); - -csql -u public demodb -;autocommit off -;server-output on -TRUNCATE test_tcl_tbl; -CALL test_tcl_commit (); -ROLLBACK; -- rollback in csql session -SELECT * FROM test_tcl_tbl; -- committed rows should be displayed -*/ -create or replace procedure test_tcl_commit() as - i int; - n varchar; -begin - INSERT INTO test_tcl_tbl VALUES (1,'aaa'); - INSERT INTO test_tcl_tbl VALUES (2,'bbb'); - INSERT INTO test_tcl_tbl VALUES (3,'ccc'); - INSERT INTO test_tcl_tbl VALUES (4,'ddd'); - COMMIT; - - for r in (SELECT code, name FROM test_tcl_tbl WHERE code > 2) loop - i := r.code; - n := r.name; - DBMS_OUTPUT.PUT_LINE(i); - DBMS_OUTPUT.PUT_LINE('code = ' || i || ' name = ' || n); - end loop; -end; diff --git a/demo/plcsql/test_tcl_rollback.sql b/demo/plcsql/test_tcl_rollback.sql deleted file mode 100644 index 64304b7a9b..0000000000 --- a/demo/plcsql/test_tcl_rollback.sql +++ /dev/null @@ -1,45 +0,0 @@ -/* -=====[PREAPRE SCHEMA]======================================= -DROP TABLE IF EXISTS test_tcl_tbl2; -CREATE TABLE test_tcl_tbl2 (code INT, name STRING); - -=====[TEST]================================================= -;set autocommit off -;server-output on - -TRUNCATE test_tcl_tbl2; -CALL test_tcl_rollback (); -COMMIT; -SELECT * FROM test_tcl_tbl2; - -=====[Expected]============================================= - Expected: - === === - - code name - =================================== - 1 'aaa' - 2 'bbb' - 3 'ccc' - 4 'ddd' -*/ -create or replace procedure test_tcl_rollback () as - i int; - n varchar; -begin - INSERT INTO test_tcl_tbl2 VALUES (1,'aaa'); - INSERT INTO test_tcl_tbl2 VALUES (2,'bbb'); - INSERT INTO test_tcl_tbl2 VALUES (3,'ccc'); - INSERT INTO test_tcl_tbl2 VALUES (4,'ddd'); - COMMIT; - - INSERT INTO test_tcl_tbl2 VALUES (6,'daf'); - INSERT INTO test_tcl_tbl2 VALUES (7,'qwe'); - ROLLBACK; - - for r in (SELECT code, name FROM test_tcl_tbl2 WHERE code > 2) loop - i := r.code; - n := r.name; - DBMS_OUTPUT.PUT_LINE('code = ' || i || ', name = ' || n); - end loop; -end; diff --git a/msg/en_US.utf8/cubrid.msg b/msg/en_US.utf8/cubrid.msg index 01f06b7c7e..e16e6cb681 100644 --- a/msg/en_US.utf8/cubrid.msg +++ b/msg/en_US.utf8/cubrid.msg @@ -215,12 +215,12 @@ $set 5 MSGCAT_SET_ERROR 143 Encountered a class with no owner. 144 Unable to access user object. 145 Cannot issue grant/revoke commands to yourself. -146 Cannot issue GRANT/REVOKE to owner of a class. +146 Cannot issue GRANT/REVOKE to owner of a %1$s. 147 No GRANT option. 148 Cannot obtain write lock on authorization object. 149 Cannot create instance of authorization object. 150 Cannot revoke privileges from self. -151 Cannot revoke privileges from owner of a class. +151 Cannot revoke privileges from owner of a %1$s. 152 GRANT not found. 153 No authorization privileges in effect for the database. 154 Incomplete authorization installation - no authorization privileges in effect for the database. @@ -236,7 +236,7 @@ $set 5 MSGCAT_SET_ERROR 164 User "%1$s" already exists. 165 User "%1$s" is invalid. 166 Invalid user specified. -167 DBA, members of DBA group and class owner can perform the operation. +167 DBA, members of DBA group and %1$s owner can perform the operation. 168 Member not found. 169 Cannot remove user %1$s from the database. 170 No user logged in. @@ -1452,8 +1452,12 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1361 Invalid result cache for subquery. 1362 Locale '%1$s' is unavailable. +1363 Dropping system generated stored procedure is not allowed. +1364 PL/CSQL Stored procedure/function does not support Invoker's rights. -1363 Last Error +1365 Only DBA and the owner can grant the %1$s privilege. + +1366 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1949,6 +1953,14 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 324 '%1$s' is not a record variable. 325 The argument specifying the language must be a string literal. +325 The argument specifying the language must be a string literal. +326 Stored procedure/function "%1$s" does not exist. +327 Attempting to assign DEFAULT on an Out parameter is not allowed: '%1$s'. +328 Only trailing default parameter is allowed: invalid at '%1$s'. +329 Grant option is not allowed for %1$s. + + + $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. 2 Transaction isolation level must be 4, 5 or 6. @@ -2232,3 +2244,11 @@ including those from the current backup level and higher.\n 28 The time(%1$s) specified must be after the time(%2$s) of the specified backup.\n 29 COMMENT: Log archive %1$s, which contains log pages before %2$lld, is not needed any longer by any HA utilities.\n 30 Number of active log archives has been exceeded the max desired number. + +$set 17 MSGCAT_SET_GLOSSARY +1 class +2 trigger +3 serial +4 server +5 synonym +6 procedure diff --git a/msg/en_US.utf8/utils.msg b/msg/en_US.utf8/utils.msg index 182cb53ac5..83bb00bb9f 100644 --- a/msg/en_US.utf8/utils.msg +++ b/msg/en_US.utf8/utils.msg @@ -157,7 +157,7 @@ Available service's utilities:\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ Available administrator's utilities:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ Available command:\n\ 42 Invalid argument.\n 43 File(%1$s) open error.\n 44 cubrid utility, version %1$s\n\ -usage: %2$s javasp [args]\n\ +usage: %2$s pl [args]\n\ \n\ Available command:\n\ - start [database-name]\n\ - stop [database-name]\n\ restart [database-name]\n\ status [database-name]\n 45 cubrid utility, version %1$s\n\ diff --git a/msg/ko_KR.utf8/cubrid.msg b/msg/ko_KR.utf8/cubrid.msg index cfa1ec39fe..e07f91be2e 100644 --- a/msg/ko_KR.utf8/cubrid.msg +++ b/msg/ko_KR.utf8/cubrid.msg @@ -215,12 +215,12 @@ $set 5 MSGCAT_SET_ERROR 143 소유자가 없는 클래스가 발생하였습니다. 144 사용자 오브젝트를 액세스할 수 없습니다. 145 자기 자신에 대해 GRANT/REVOKE 명령할 수 없습니다. -146 클래스 소유자에 대해 GRANT/REVOKE 명령할 수 없습니다. +146 %1$s 소유자에 대해 GRANT/REVOKE 명령할 수 없습니다. 147 GRANT 옵션이 없습니다. 148 권한 부여 오브젝트에 대해 쓰기 락을 얻을 수 없습니다. 149 권한 부여 오브젝트의 인스턴스를 생성할 수 없습니다. 150 자기 자신의 권한은 해제할 수 없습니다. -151 클래스 소유자의 권한은 해제할 수 없습니다. +151 %1$s 소유자의 권한은 해제할 수 없습니다. 152 GRANT가 없습니다. 153 데이터베이스에 대한 권한 부여 권리가 없습니다. 154 불완전한 권한 부여 설정 - 데이터베이스에 대한 권한 부여 권리가 없습니다. @@ -236,7 +236,7 @@ $set 5 MSGCAT_SET_ERROR 164 사용자 "%1$s" 이(가) 이미 존재합니다. 165 사용자 "%1$s" 을(를) 확인하십시오. 166 유효하지 않은 사용자가 지정되었습니다. -167 클래스 소유자만이 오퍼레이션을 수행할 수 있습니다. +167 %1$s 소유자만이 오퍼레이션을 수행할 수 있습니다. 168 멤버를 찾을 수 없습니다. 169 데이터베이스에서 사용자를 제거할 수 없습니다. 170 로그인된 사용자가 없습니다. @@ -1450,10 +1450,13 @@ $ LOADDB 1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s 1361 부질의 캐시가 잘못되었습니다. - 1362 언어 '%1$s'에 대한 로캘은 사용 가능하지 않습니다. +1363 시스템 생성 stored procedure를 삭제(drop)할 수 없습니다. +1364 PL/CSQL 저장 프로시저/함수는 호출자 권한을 지원하지 않습니다. + +1365 DBA 및 소유자만 %1$s 권한을 부여할 수 있습니다. -1363 마지막 에러 +1366 마지막 에러 $set 6 MSGCAT_SET_INTERNAL 1 에러 서브 시스템에 에러 발생(라인 %1$d): @@ -1945,10 +1948,18 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 320 '%1$s'는 Stored Procedure에서 지원하지 않는 결과 타입입니다 321 %TYPE 타입 지정은 PL/CSQL에서만 사용 가능합니다 322 테이블 컬럼 '%1$s.%2$s'이 정의되지 않았습니다 -323 Stored procedure/function '%1$s' 이(가) OUT 또는 IN OUT 인수를 가지고 있습니다. +323 저장 프로시저/함수 '%1$s' 이(가) OUT 또는 IN OUT 인수를 가지고 있습니다. 324 '%1$s'은 레코드 변수가 아닙니다. 325 언어를 지정하는 인수는 문자열 리터럴이어야 합니다. +325 언어를 지정하는 인수는 문자열 리터럴이어야 합니다. +326 저장 프로시저/함수 "%1$s"이(가) 존재하지 않습니다. +327 Out 매개변수에 DEFAULT를 할당하는 것은 허용되지 않습니다: '%1$s'. +328 오직 후행 기본 인수만 허용합니다: '%1$s' 에서 유효하지 않음. +329 %1$s에 대해 GRANT 옵션을 부여할 수 없습니다. + + + $set 9 MSGCAT_SET_PARSER_RUNTIME 1 가상 메모리 없음: %1$d 바이트를 할당할 수 없습니다. 2 트랜잭션 isolation 레벨은 1, 2, 3, 4, 5, 6 중에서 지정되어야 합니다. @@ -2232,3 +2243,11 @@ $set 16 MSGCAT_SET_LOG 28 복구 시점(%1$s)은 반드시 백업 시점(%2$s) 이후로 지정해야 합니다. \n 29 COMMENT: 보관 로그 %1$s는 로그 페이지 %2$lld 이전까지만 포함되어 HA 유틸리티에서 더 이상 사용되지 않습니다. 30 보관 로그의 개수가 허용 최대치를 초과했습니다. + +$set 17 MSGCAT_SET_GLOSSARY +1 클래스 +2 트리거 +3 시리얼 +4 서버 +5 동의어 +6 프로시저 diff --git a/msg/ko_KR.utf8/utils.msg b/msg/ko_KR.utf8/utils.msg index 3f4f024236..ee3e2cee3b 100644 --- a/msg/ko_KR.utf8/utils.msg +++ b/msg/ko_KR.utf8/utils.msg @@ -157,7 +157,7 @@ cubrid 관리자 유틸리티, 버전 %1$s\n\ gateway\n\ manager\n\ heartbeat\n\ - javasp\n\ + pl\n\ \n\ 가용한 관리자 유틸리티 이름:\n\ addvoldb\n\ @@ -262,11 +262,9 @@ cubrid 관리자 유틸리티, 버전 %1$s\n\ 42 인자가 잘못되었습니다.\n 43 파일(%1$s)을 열지 못했습니다.\n 44 cubrid 유틸리티, 버전 %1$s\n\ -사용법: %2$s javasp <명령어> [인자]\n\ +사용법: %2$s pl <명령어> [인자]\n\ \n\ 가용한 명령어:\n\ - start [데이터베이스 이름]\n\ - stop [데이터베이스 이름]\n\ restart [데이터베이스 이름]\n\ status [데이터베이스 이름]\n 45 cubrid 유틸리티, 버전 %1$s\n\ diff --git a/pl_engine/pl_server/build.gradle.kts b/pl_engine/pl_server/build.gradle.kts index 8ee0fbf52c..c65c3b4f43 100644 --- a/pl_engine/pl_server/build.gradle.kts +++ b/pl_engine/pl_server/build.gradle.kts @@ -52,6 +52,9 @@ dependencies { implementation("org.apache.commons:commons-text:1.10.0") implementation("org.apache.commons:commons-collections4:4.4") implementation("org.apache.commons:commons-lang3:3.13.0") + implementation("commons-io:commons-io:2.15.1") + implementation("org.apache.commons:commons-compress:1.25.0") + implementation("org.antlr:antlr4-runtime:4.9.3") // CUBRID JDBC diff --git a/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 b/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 index bdf8847d2a..ce66a16ee7 100644 --- a/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 +++ b/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 @@ -45,6 +45,7 @@ TRUNCATE: T R U N C A T E { staticSqlParenMatch++; checkFi // other keywords AND: A N D ; AS: A S ; +AUTHID: A U T H I D ; AUTONOMOUS_TRANSACTION: A U T O N O M O U S '_' T R A N S A C T I O N ; BEGIN: B E G I N ; BETWEEN: B E T W E E N ; @@ -52,6 +53,7 @@ BIGINT: B I G I N T ; BOOLEAN: B O O L E A N ; BY: B Y ; CASE: C A S E ; +CALLER: C A L L E R ; CHARACTER: C H A R A C T E R ; CHAR: C H A R ; CLOSE: C L O S E ; @@ -60,6 +62,7 @@ COMMIT: C O M M I T ; CONSTANT: C O N S T A N T ; CONTINUE: C O N T I N U E ; CREATE: C R E A T E ; +CURRENT_USER: C U R R E N T '_' U S E R ; CURSOR: C U R S O R ; DATE: D A T E ; DATETIME: D A T E T I M E ; @@ -70,6 +73,7 @@ DEC: D E C ; DECIMAL: D E C I M A L ; DECLARE: D E C L A R E ; DEFAULT: D E F A U L T ; +DEFINER: D E F I N E R ; DIV: D I V ; DOUBLE: D O U B L E ; ELSE: E L S E ; @@ -106,6 +110,7 @@ OPEN: O P E N ; OR_REPLACE: O R SPACE+ R E P L A C E ; OR: O R ; OUT: O U T ; +OWNER: O W N E R ; PERCENT_FOUND: '%' SPACE* F O U N D ; PERCENT_ISOPEN: '%' SPACE* I S O P E N ; PERCENT_NOTFOUND: '%' SPACE* N O T F O U N D ; diff --git a/pl_engine/pl_server/src/main/antlr/PlcParser.g4 b/pl_engine/pl_server/src/main/antlr/PlcParser.g4 index 33661dca9e..4b950c8177 100644 --- a/pl_engine/pl_server/src/main/antlr/PlcParser.g4 +++ b/pl_engine/pl_server/src/main/antlr/PlcParser.g4 @@ -39,8 +39,13 @@ create_routine ; routine_definition - : (PROCEDURE | FUNCTION) identifier ( (LPAREN parameter_list RPAREN)? | LPAREN RPAREN ) (RETURN type_spec)? - (IS | AS) (LANGUAGE PLCSQL)? seq_of_declare_specs? body (SEMICOLON)? + : (PROCEDURE | FUNCTION) routine_uniq_name ( (LPAREN parameter_list RPAREN)? | LPAREN RPAREN ) (RETURN type_spec)? + (authid_spec)? (IS | AS) (LANGUAGE PLCSQL)? seq_of_declare_specs? body (SEMICOLON)? + ; + +routine_uniq_name + : (owner=identifier '.')? name=identifier + | '[' (owner=identifier '.')? name=identifier ']' /* rewritten query */ ; parameter_list @@ -48,8 +53,13 @@ parameter_list ; parameter - : parameter_name IN? type_spec (COMMENT CHAR_STRING)? # parameter_in - | parameter_name ( IN? OUT | INOUT ) type_spec (COMMENT CHAR_STRING)? # parameter_out + : parameter_name IN? type_spec default_value_part? (COMMENT CHAR_STRING)? # parameter_in + | parameter_name ( IN? OUT | INOUT ) type_spec (COMMENT CHAR_STRING)? # parameter_out + ; + +authid_spec + : AUTHID (DEFINER | OWNER) # authid_owner + | AUTHID (CALLER | CURRENT_USER) # authid_caller ; default_value_part @@ -211,7 +221,11 @@ return_statement ; procedure_call - : (DBMS_OUTPUT '.')? routine_name function_argument? + : proc_call_name function_argument? + ; + +proc_call_name + : (owner=identifier '.')? (DBMS_OUTPUT '.')? name=identifier ; body @@ -345,6 +359,7 @@ atom | record_field # field_exp | function_call # call_exp | identifier # id_exp + | keyword_builtin_func # builtin_func | case_expression # case_exp | SQL PERCENT_ROWCOUNT # sql_rowcount_exp // this must go before the cursor_attr_exp line | cursor_exp ( PERCENT_ISOPEN | PERCENT_FOUND | PERCENT_NOTFOUND | PERCENT_ROWCOUNT ) # cursor_attr_exp @@ -358,7 +373,29 @@ record_field ; function_call - : function_name function_argument + : func_call_name function_argument + ; + +func_call_name + : (owner=identifier '.')? name=func_name + ; + +func_name + : identifier + | keyword_builtin_func + ; + +keyword_builtin_func + : CURRENT_USER + | DATE + | DEFAULT + | IF + | INSERT + | MOD + | REPLACE + | TIME + | TIMESTAMP + | TRUNCATE ; relational_operator @@ -449,10 +486,6 @@ restricted_using_element : (IN)? expression ; -routine_name - : identifier - ; - parameter_name : identifier ; @@ -574,20 +607,7 @@ quoted_string identifier : REGULAR_ID | DELIMITED_ID - ; - -function_name - : identifier - | DATE - | DEFAULT - | IF - | INSERT - | MOD - | REPLACE | REVERSE - | TIME - | TIMESTAMP - | TRUNCATE ; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ExecuteThread.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ExecuteThread.java index f4fb35083f..1b46aa7a55 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ExecuteThread.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ExecuteThread.java @@ -32,41 +32,47 @@ package com.cubrid.jsp; import com.cubrid.jsp.classloader.ClassLoaderManager; +import com.cubrid.jsp.code.CompiledCode; +import com.cubrid.jsp.code.CompiledCodeSet; +import com.cubrid.jsp.code.SourceCode; +import com.cubrid.jsp.compiler.MemoryJavaCompiler; import com.cubrid.jsp.context.Context; import com.cubrid.jsp.context.ContextManager; +import com.cubrid.jsp.data.AuthInfo; import com.cubrid.jsp.data.CUBRIDPacker; import com.cubrid.jsp.data.CUBRIDUnpacker; import com.cubrid.jsp.data.CompileInfo; +import com.cubrid.jsp.data.CompileRequest; import com.cubrid.jsp.data.DataUtilities; import com.cubrid.jsp.exception.ExecuteException; import com.cubrid.jsp.exception.TypeMismatchException; +import com.cubrid.jsp.protocol.BootstrapRequest; import com.cubrid.jsp.protocol.Header; import com.cubrid.jsp.protocol.PrepareArgs; import com.cubrid.jsp.protocol.RequestCode; import com.cubrid.jsp.value.Value; -import com.cubrid.jsp.value.ValueUtilities; import com.cubrid.plcsql.compiler.PlcsqlCompilerMain; import com.cubrid.plcsql.predefined.PlcsqlRuntimeError; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.net.Socket; import java.nio.ByteBuffer; +import java.nio.file.Files; import java.nio.file.Path; import java.sql.SQLException; +import java.util.Base64; import java.util.List; -import javax.tools.JavaCompiler; -import javax.tools.ToolProvider; +import java.util.Map; +import org.apache.commons.compress.archivers.jar.JarArchiveEntry; +import org.apache.commons.compress.archivers.jar.JarArchiveOutputStream; public class ExecuteThread extends Thread { - - public static String charSet = "UTF-8"; - private Socket client; private DataInputStream input; @@ -117,11 +123,6 @@ public void closeSocket() { client = null; output = null; - // charSet = null; - } - - public void setCharSet(String conCharsetName) { - // this.charSet = conCharsetName; } @Override @@ -137,11 +138,6 @@ public void run() { * the following two request codes are for processing java stored procedure * routine */ - case RequestCode.PREPARE_ARGS: - { - processPrepare(); - break; - } case RequestCode.INVOKE_SP: { processStoredProcedure(); @@ -155,7 +151,12 @@ public void run() { break; } - /* the following request codes are for javasp utility */ + /* the following request codes are for system requests */ + case RequestCode.UTIL_BOOTSTRAP: + { + processBootstrap(); + break; + } case RequestCode.UTIL_PING: { String ping = Server.getServer().getServerName(); @@ -273,12 +274,15 @@ private Header listenCommand() throws Exception { ctx = ContextManager.getContext(header.id); ctx.checkHeader(header); - ByteBuffer payloadBuffer = - ByteBuffer.wrap( - inputBuffer.array(), - unpacker.getCurrentPosition(), - unpacker.getCurrentLimit() - unpacker.getCurrentPosition()); - ctx.getInboundQueue().add(payloadBuffer); + int startOffset = unpacker.getCurrentPosition(); + int payloadSize = unpacker.getCurrentLimit() - startOffset; + if (payloadSize > 0) { + ByteBuffer payloadBuffer = + ByteBuffer.wrap(inputBuffer.array(), startOffset, payloadSize); + + ctx.getInboundQueue().add(payloadBuffer); + } + return header; } @@ -304,67 +308,120 @@ public CUBRIDUnpacker getUnpacker() { return unpacker; } - private void processPrepare() throws Exception { + private void processStoredProcedure() throws Exception { unpacker.setBuffer(ctx.getInboundQueue().take()); + + // prepare if (prepareArgs == null) { prepareArgs = new PrepareArgs(unpacker); } else { prepareArgs.readArgs(unpacker); } - ctx.checkTranId(prepareArgs.getTranId()); - } - private void processStoredProcedure() throws Exception { - unpacker.setBuffer(ctx.getInboundQueue().take()); long id = unpacker.unpackBigint(); int tid = unpacker.unpackInt(); ctx.checkTranId(tid); StoredProcedure procedure = makeStoredProcedure(unpacker); + Value result = procedure.invoke(); /* send results */ sendResult(result, procedure); } + private void writeJar(CompiledCodeSet codeSet, OutputStream jarStream) throws IOException { + JarArchiveOutputStream jaos = null; + try { + jaos = new JarArchiveOutputStream(new BufferedOutputStream(jarStream)); + + for (Map.Entry entry : codeSet.getCodeList()) { + JarArchiveEntry jae = + new JarArchiveEntry(entry.getValue().getClassNameWithExtention()); + byte[] arr = entry.getValue().getByteCode(); + jae.setSize(arr.length); + jaos.putArchiveEntry(jae); + jaos.write(arr); + jaos.flush(); + // ByteArrayInputStream bis = new + // ByteArrayInputStream(entry.getValue().getByteCode()); + // IOUtils.copy(bis, jaos); + // bis.close(); + + jaos.closeArchiveEntry(); + } + } catch (IOException e) { + throw e; + } finally { + if (jaos != null) { + jaos.flush(); + jaos.finish(); + jaos.close(); + } + } + } + + private void processBootstrap() throws Exception { + unpacker.setBuffer(ctx.getInboundQueue().take()); + + int result = 1; // failed + try { + BootstrapRequest request = new BootstrapRequest(unpacker); + Server.bootstrap(request); + result = 0; // no error + } catch (Exception e) { + // ignore, 1 will be returned + Server.log(e); + } + + resultBuffer.clear(); /* prepare to put */ + packer.setBuffer(resultBuffer); + packer.packInt(result); + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + } + private void processCompile() throws Exception { unpacker.setBuffer(ctx.getInboundQueue().take()); - boolean verbose = unpacker.unpackBool(); - String inSource = unpacker.unpackCString(); + + CompileRequest request = new CompileRequest(unpacker); + + // TODO: Pass CompileRequest directly to compilePLCSQL () + boolean verbose = false; + if (request.mode.contains("v")) { + verbose = true; + } + String inSource = request.code; + String owner = request.owner; CompileInfo info = null; try { - info = PlcsqlCompilerMain.compilePLCSQL(inSource, verbose); + info = PlcsqlCompilerMain.compilePLCSQL(inSource, owner, verbose); if (info.errCode == 0) { - Path javaFilePath = - ClassLoaderManager.getDynamicPath().resolve(info.className + ".java"); - File file = javaFilePath.toFile(); - if (file.exists()) { - file.delete(); - } - new FileWriter(file).append(info.translated).close(); - - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - if (compiler == null) { - throw new IllegalStateException( - "Cannot find the system Java compiler. Check that your class path includes tools.jar"); + MemoryJavaCompiler compiler = new MemoryJavaCompiler(); + SourceCode sCode = new SourceCode(info.className, info.translated); + CompiledCodeSet codeSet = compiler.compile(sCode); + + int mode = 1; // 0: temp file mode, 1: memory stream mode + byte[] data = null; + + // write to persistent + if (mode == 0) { + Path jarPath = + ClassLoaderManager.getDynamicPath().resolve(info.className + ".jar"); + OutputStream jarStream = Files.newOutputStream(jarPath); + writeJar(codeSet, jarStream); + data = Files.readAllBytes(jarPath); + Files.deleteIfExists(jarPath); + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + writeJar(codeSet, baos); + data = baos.toByteArray(); } - Path cubrid_env_root = Server.getServer().getRootPath(); - String javacOpts[] = { - "-classpath", cubrid_env_root + "/java/pl_server.jar", file.getPath() - }; - - if (compiler.run(null, null, null, javacOpts) != 0) { - String command = - "javac " - + javaFilePath - + " -cp " - + cubrid_env_root - + "/java/pl_server.jar"; - throw new RuntimeException(command); - } + info.compiledType = 1; // TODO: always jar + info.compiledCode = Base64.getEncoder().encode(data); } } catch (Exception e) { info = @@ -373,6 +430,7 @@ private void processCompile() throws Exception { throw new RuntimeException(e); } finally { CUBRIDPacker packer = new CUBRIDPacker(ByteBuffer.allocate(1024)); + info.pack(packer); Context.getCurrentExecuteThread().sendCommand(RequestCode.COMPILE, packer.getBuffer()); } @@ -380,57 +438,47 @@ private void processCompile() throws Exception { private StoredProcedure makeStoredProcedure(CUBRIDUnpacker unpacker) throws Exception { String methodSig = unpacker.unpackCString(); + String authUser = unpacker.unpackCString(); + int lang = unpacker.unpackInt(); int paramCount = unpacker.unpackInt(); Value[] arguments = prepareArgs.getArgs(); - Value[] methodArgs = new Value[paramCount]; for (int i = 0; i < paramCount; i++) { - int pos = unpacker.unpackInt(); int mode = unpacker.unpackInt(); int type = unpacker.unpackInt(); + Value val = arguments[i]; - Value val = arguments[pos]; val.setMode(mode); val.setDbType(type); - - methodArgs[i] = val; } int returnType = unpacker.unpackInt(); boolean transactionControl = unpacker.unpackBool(); getCurrentContext().setTransactionControl(transactionControl); - storedProcedure = new StoredProcedure(methodSig, methodArgs, returnType); + storedProcedure = new StoredProcedure(methodSig, lang, authUser, arguments, returnType); return storedProcedure; } private void returnOutArgs(StoredProcedure sp, CUBRIDPacker packer) throws IOException, ExecuteException, TypeMismatchException { Value[] args = sp.getArgs(); - for (int i = 0; i < args.length; i++) { + for (int i = 0; args != null && i < args.length; i++) { if (args[i].getMode() > Value.IN) { - Value v = sp.makeOutValue(args[i].getResolved()); - packer.packValue( - ValueUtilities.resolveValue(args[i].getDbType(), v), - args[i].getDbType(), - this.charSet); + Value v = sp.makeOutValue(i); + packer.packValue(v, args[i].getDbType()); } } } private void sendResult(Value result, StoredProcedure procedure) throws IOException, ExecuteException, TypeMismatchException { - Object resolvedResult = null; - if (result != null) { - resolvedResult = ValueUtilities.resolveValue(procedure.getReturnType(), result); - } - resultBuffer.clear(); /* prepare to put */ packer.setBuffer(resultBuffer); packer.packInt(RequestCode.RESULT); packer.align(DataUtilities.MAX_ALIGNMENT); - packer.packValue(resolvedResult, procedure.getReturnType(), this.charSet); + packer.packValue(result, procedure.getReturnType()); returnOutArgs(procedure, packer); resultBuffer = packer.getBuffer(); @@ -472,4 +520,20 @@ private void sendError(String exception) throws IOException { resultBuffer = packer.getBuffer(); writeBuffer(resultBuffer); } + + private void sendAuthCommand(int command, String authName) throws Exception { + AuthInfo info = new AuthInfo(command, authName); + CUBRIDPacker packer = new CUBRIDPacker(ByteBuffer.allocate(128)); + packer.packInt(RequestCode.REQUEST_CHANGE_AUTH_RIGHTS); + info.pack(packer); + Context.getCurrentExecuteThread().sendCommand(packer.getBuffer()); + + ByteBuffer responseBuffer = Context.getCurrentExecuteThread().receiveBuffer(); + CUBRIDUnpacker unpacker = new CUBRIDUnpacker(responseBuffer); + /* read header, dummy */ + Header header = new Header(unpacker); + ByteBuffer payload = unpacker.unpackBuffer(); + unpacker.setBuffer(payload); + int responseCode = unpacker.unpackInt(); + } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/Server.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/Server.java index 770c8d525a..10418cd05e 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/Server.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/Server.java @@ -32,6 +32,8 @@ package com.cubrid.jsp; import com.cubrid.jsp.classloader.ClassLoaderManager; +import com.cubrid.jsp.exception.TypeMismatchException; +import com.cubrid.jsp.protocol.BootstrapRequest; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; @@ -41,7 +43,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.ZoneOffset; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; @@ -243,6 +244,27 @@ public static void stop(int status) { } } + public static void bootstrap(BootstrapRequest request) { + SysParam[] systemParameters = request.getSystemParameters(); + for (SysParam sysParam : systemParameters) { + config.getSystemParameters().put(sysParam.getParamId(), sysParam); + } + + config.initializeCharset(); + } + + public static boolean getSystemParameterBool(int id) { + try { + SysParam param = config.getSystemParameters().get(id); + if (param != null) { + return param.getParamValue().toInt() != 0; + } + } catch (TypeMismatchException e) { + } + + return false; + } + public static void main(String[] args) throws Exception { Server.start(args); } @@ -266,40 +288,7 @@ public boolean getShutdown() { return shutdown.get(); } - // ---------------------------------------------------------------------- - // The following two methods are temporary mock implementation - - public static final int SYS_PARAM_COMPAT_NUMERIC_DIVISION_SCALE = 1; - public static final int SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR = 2; - public static final int SYS_PARAM_ORACLE_STYLE_EMPTY_STRING = 3; - public static final int SYS_PARAM_TIMEZONE = 4; - - public static boolean getSystemParameterBool(int code) { - switch (code) { - case SYS_PARAM_COMPAT_NUMERIC_DIVISION_SCALE: - return false; - case SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR: - return false; - case SYS_PARAM_ORACLE_STYLE_EMPTY_STRING: - return false; - default: - assert (false); - return false; - } - } - - private static final ZoneOffset tz = ZoneOffset.of("+09:00"); - - public static ZoneOffset getSystemParameterTimezone(int code) { - switch (code) { - case SYS_PARAM_TIMEZONE: - return tz; - default: - assert (false); - return null; - } + public static ServerConfig getConfig() { + return config; } - - // - // ---------------------------------------------------------------------- } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ServerConfig.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ServerConfig.java index 4f71ee1ad7..d4b0f6c02f 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ServerConfig.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ServerConfig.java @@ -1,6 +1,42 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + package com.cubrid.jsp; import java.io.File; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.HashMap; import org.apache.commons.lang3.StringUtils; public class ServerConfig { @@ -20,6 +56,12 @@ public class ServerConfig { private final String socketType; // TCP or UDS private final String socketInfo; // port number or socket file path + // System settings + private HashMap systemParameters; + + private Charset serverCharset; + private ZoneId serverTimeZone; + public ServerConfig( String name, String version, String rPath, String dbPath, String socketInfo) { this.name = name; @@ -37,6 +79,10 @@ public ServerConfig( this.socketInfo = socketInfo; this.socketType = StringUtils.isNumeric(socketInfo) ? "TCP" : "UDS"; + + this.systemParameters = new HashMap(); + this.serverTimeZone = null; + this.serverCharset = StandardCharsets.UTF_8; } public String getName() { @@ -70,4 +116,63 @@ public String getDatabasePath() { public String getSocketInfo() { return socketInfo; } + + public HashMap getSystemParameters() { + return systemParameters; + } + + public ZoneId getTimeZone() { + if (serverTimeZone == null) { + // get the timezone from the system parameters + SysParam sysParam = systemParameters.get(SysParam.TIMEZONE); + serverTimeZone = ZoneId.of(sysParam.getParamValue().toString()); + } + + if (serverTimeZone == null) { + // if the timezone is not set, use the default timezone (UTC) + serverTimeZone = ZoneOffset.UTC; + } + + return serverTimeZone; + } + + public Charset getServerCharset() { + return serverCharset; + } + + public int getServerCodesetId() { + return SysParam.getCodesetId(serverCharset); + } + + public void initializeCharset() { + SysParam sysParam = systemParameters.get(SysParam.INTL_COLLATION); + String collation = sysParam.getParamValue().toString(); + String codeset = null; + String[] codesetList = collation.split("_"); + if (codesetList == null) { + codeset = collation; + } else { + codeset = codesetList[0]; + } + + // tune the codeset name java understands + if (codeset.equalsIgnoreCase("utf-8") || codeset.equalsIgnoreCase("utf8")) { + codeset = "UTF-8"; + } else if (codeset.equalsIgnoreCase("ksc-euc") || codeset.equalsIgnoreCase("euckr")) { + codeset = "EUC-KR"; + } else if (codeset.equalsIgnoreCase("iso88591")) { + codeset = "ISO-8859-1"; + } else if (codeset.equalsIgnoreCase("ascii")) { + codeset = "UTF-8"; // ascii is a subset of UTF-8 + } + + try { + serverCharset = Charset.forName(codeset); + } catch (Exception e) { + // java.nio.charset.IllegalCharsetNameException + Server.log(e); + serverCharset = StandardCharsets.UTF_8; + } + System.setProperty("file.encoding", serverCharset.toString()); + } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java index 325da85eb0..85c5db86ef 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java @@ -31,29 +31,23 @@ package com.cubrid.jsp; +import com.cubrid.jsp.classloader.ServerClassLoader; +import com.cubrid.jsp.code.ClassAccess; +import com.cubrid.jsp.code.CompiledCodeSet; +import com.cubrid.jsp.code.Signature; +import com.cubrid.jsp.context.Context; import com.cubrid.jsp.context.ContextManager; import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.ExecuteException; import com.cubrid.jsp.exception.TypeMismatchException; -import com.cubrid.jsp.value.BooleanValue; -import com.cubrid.jsp.value.ByteValue; -import com.cubrid.jsp.value.DateValue; -import com.cubrid.jsp.value.DatetimeValue; -import com.cubrid.jsp.value.DoubleValue; -import com.cubrid.jsp.value.FloatValue; -import com.cubrid.jsp.value.IntValue; -import com.cubrid.jsp.value.LongValue; -import com.cubrid.jsp.value.NumericValue; -import com.cubrid.jsp.value.OidValue; -import com.cubrid.jsp.value.ResultSetValue; +import com.cubrid.jsp.value.NullValue; import com.cubrid.jsp.value.SetValue; -import com.cubrid.jsp.value.ShortValue; -import com.cubrid.jsp.value.StringValue; -import com.cubrid.jsp.value.TimeValue; import com.cubrid.jsp.value.Value; +import com.cubrid.jsp.value.ValueUtilities; import cubrid.sql.CUBRIDOID; import java.lang.reflect.Method; import java.math.BigDecimal; +import java.sql.Connection; import java.sql.Date; import java.sql.ResultSet; import java.sql.Time; @@ -61,32 +55,99 @@ public class StoredProcedure { private String signature; + private String authUser; private Value[] args; private int returnType; + private int lang; + + private Class targetClass; private TargetMethod target; private Object[] cachedResolved; - public StoredProcedure(String signature, Value[] args, int returnType) throws Exception { + // METHOD_TYPE in method_def.hpp + private static final int LANG_JAVASP = 3; + private static final int LANG_PLCSQL = 4; + + public StoredProcedure( + String signature, int lang, String authUser, Value[] args, int returnType) + throws Exception { this.signature = signature; + this.authUser = authUser; this.args = args; this.returnType = returnType; - this.target = - ContextManager.getContextofCurrentThread().getTargetMethodCache().get(signature); + this.lang = lang; + + this.target = findTargetMethod(signature); + this.cachedResolved = null; checkArgs(); } + private TargetMethod findTargetMethod(String sigString) throws Exception { + Context ctx = ContextManager.getContextofCurrentThread(); + + Connection conn = ctx.getConnection(); + Signature sig = Signature.parse(sigString); + + Class c = null; + ClassNotFoundException ex = null; + if (lang == LANG_PLCSQL) { + try { + c = ctx.getSessionCLManager().findClass(sig.getClassName()); + if (c == null) { + CompiledCodeSet codeset = ClassAccess.getObjectCode(conn, sig); + if (codeset != null) { + c = ctx.getSessionCLManager().loadClass(codeset); + } + } + } catch (ClassNotFoundException e) { + ex = e; + } + } else if (lang == LANG_JAVASP) { + try { + c = ctx.getOldClassLoader().loadClass(sig.getClassName()); + } catch (ClassNotFoundException e) { + ex = e; + } + } else { + assert false; + throw new ClassNotFoundException(sig.getClassName()); + } + + // find a class in static directory and system loader + if (c == null) { + c = ServerClassLoader.getInstance().loadClass(sig.getClassName()); + } + + if (c == null) { + throw ex; + } + + targetClass = c; + TargetMethod target = new TargetMethod(sig); + return target; + } + public Object[] getResolved() { + if (args == null) { + return null; + } + Object[] resolved = new Object[args.length]; for (int i = 0; i < args.length; i++) { resolved[i] = args[i].getResolved(); } + return resolved; } private void checkArgs() throws TypeMismatchException { + if (args == null) { + return; + } + Class[] argsTypes = target.getArgsTypes(); if (argsTypes.length != args.length) { throw new TypeMismatchException( @@ -95,7 +156,6 @@ private void checkArgs() throws TypeMismatchException { + ", but " + args.length); } - for (int i = 0; i < argsTypes.length; i++) { Object resolved; if (args[i] == null) { @@ -280,104 +340,26 @@ private void checkArgs() throws TypeMismatchException { } public Value invoke() throws Exception { - Method m = target.getMethod(); + Method m = target.getMethod(targetClass); if (cachedResolved == null) { cachedResolved = getResolved(); } Object result = m.invoke(null, cachedResolved); - return makeReturnValue(result); - } - - public Value makeOutValue(Object object) throws ExecuteException, TypeMismatchException { - Object obj = null; - if (object instanceof byte[]) { - obj = new Byte(((byte[]) object)[0]); - } else if (object instanceof short[]) { - obj = new Short(((short[]) object)[0]); - } else if (object instanceof int[]) { - obj = new Integer(((int[]) object)[0]); - } else if (object instanceof long[]) { - obj = new Long(((long[]) object)[0]); - } else if (object instanceof float[]) { - obj = new Float(((float[]) object)[0]); - } else if (object instanceof double[]) { - obj = new Double(((double[]) object)[0]); - } else if (object instanceof byte[][]) { - obj = ((byte[][]) object)[0]; - } else if (object instanceof short[][]) { - obj = ((short[][]) object)[0]; - } else if (object instanceof int[][]) { - obj = ((int[][]) object)[0]; - } else if (object instanceof long[][]) { - obj = ((long[][]) object)[0]; - } else if (object instanceof float[][]) { - obj = ((float[][]) object)[0]; - } else if (object instanceof double[][]) { - obj = ((double[][]) object)[0]; - } else if (object instanceof Object[]) { - obj = ((Object[]) object)[0]; - } - - return makeReturnValue(obj); + return ValueUtilities.createValueFrom(result); } - public Value makeReturnValue(Object o) throws ExecuteException, TypeMismatchException { - Value val = null; - - if (o == null) { - return null; - } else if (o instanceof Boolean) { - val = new BooleanValue(((Boolean) o).booleanValue()); - } else if (o instanceof Byte) { - val = new ByteValue(((Byte) o).byteValue()); - } else if (o instanceof Character) { - val = new StringValue(((Character) o).toString()); - } else if (o instanceof Short) { - val = new ShortValue(((Short) o).shortValue()); - } else if (o instanceof Integer) { - val = new IntValue(((Integer) o).intValue()); - } else if (o instanceof Long) { - val = new LongValue(((Long) o).longValue()); - } else if (o instanceof Float) { - val = new FloatValue(((Float) o).floatValue()); - } else if (o instanceof Double) { - val = new DoubleValue(((Double) o).doubleValue()); - } else if (o instanceof BigDecimal) { - val = new NumericValue(((BigDecimal) o)); - } else if (o instanceof String) { - val = new StringValue((String) o); - } else if (o instanceof java.sql.Date) { - val = new DateValue((java.sql.Date) o); - } else if (o instanceof java.sql.Time) { - val = new TimeValue((java.sql.Time) o); - } else if (o instanceof java.sql.Timestamp) { - val = - new DatetimeValue( - (java.sql.Timestamp) - o); // DatetimeValue allows more values than TimestampValue - } else if (o instanceof CUBRIDOID) { - val = new OidValue((CUBRIDOID) o); - } else if (o instanceof ResultSet) { - val = new ResultSetValue((ResultSet) o); - } else if (o instanceof byte[]) { - val = new SetValue((byte[]) o); - } else if (o instanceof short[]) { - val = new SetValue((short[]) o); - } else if (o instanceof int[]) { - val = new SetValue((int[]) o); - } else if (o instanceof long[]) { - val = new SetValue((long[]) o); - } else if (o instanceof float[]) { - val = new SetValue((float[]) o); - } else if (o instanceof double[]) { - val = new SetValue((double[]) o); - } else if (o instanceof Object[]) { - val = new SetValue((Object[]) o); + public Value makeOutValue(int idx) throws TypeMismatchException, ExecuteException { + Class[] argsTypes = target.getArgsTypes(); + if (argsTypes[idx].isArray()) { + Value resolved = ValueUtilities.createValueFrom(cachedResolved[idx]); + if (resolved instanceof SetValue) { + return ((SetValue) resolved).toValueArray()[0]; + } else { + return resolved; + } } else { - throw new ExecuteException("Not supported data type: '" + o.getClass().getName() + "'"); + return new NullValue(); } - - return val; } public int getReturnType() { @@ -399,4 +381,8 @@ public String getSignature() { public TargetMethod getTarget() { return target; } + + public String getAuthUser() { + return authUser; + } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/SysParam.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/SysParam.java new file mode 100644 index 0000000000..eb3bff91b7 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/SysParam.java @@ -0,0 +1,103 @@ +package com.cubrid.jsp; + +import com.cubrid.jsp.data.CUBRIDUnpacker; +import com.cubrid.jsp.exception.TypeMismatchException; +import com.cubrid.jsp.protocol.UnPackableObject; +import com.cubrid.jsp.value.Value; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public class SysParam implements UnPackableObject { + + // see src/base/system_parameter.h + public static final int ORACLE_STYLE_EMPTY_STRING = 95; + public static final int COMPAT_NUMERIC_DIVISION_SCALE = 100; + public static final int INTL_NUMBER_LANG = 193; + public static final int INTL_DATE_LANG = 194; + public static final int INTL_COLLATION = 206; + public static final int TIMEZONE = 249; + public static final int ORACLE_COMPAT_NUMBER_BEHAVIOR = 334; + + // codeset + public static final int CODESET_ASCII = 0; + public static final int CODESET_RAW_BITS = 1; + public static final int CODESET_RAW_BYTES = 2; + public static final int CODESET_ISO88591 = 3; + public static final int CODESET_KSC5601_EUC = 4; + public static final int CODESET_UTF8 = 5; + + public static Charset CHARSET_EUCKR = null; + + public static String getCodesetString(int codeset) { + switch (codeset) { + case CODESET_ASCII: + return StandardCharsets.US_ASCII.toString(); + case CODESET_RAW_BITS: + case CODESET_RAW_BYTES: + break; + case CODESET_ISO88591: + return StandardCharsets.ISO_8859_1.toString(); + case CODESET_KSC5601_EUC: + if (CHARSET_EUCKR == null) { + CHARSET_EUCKR = Charset.forName("EUC-KR"); + } + return CHARSET_EUCKR.toString(); + default: + break; + } + + return "UTF-8"; // default + } + + public static int getCodesetId(Charset charset) { + if (charset.equals(StandardCharsets.US_ASCII)) { + return CODESET_ASCII; + } else if (charset.equals(StandardCharsets.ISO_8859_1)) { + return CODESET_ISO88591; + } else if (charset.equals(CHARSET_EUCKR)) { + return CODESET_KSC5601_EUC; + } else { + return CODESET_UTF8; + } + } + + private int paramId; + private int paramType; + private Value paramValue; + + public SysParam(CUBRIDUnpacker unpacker) { + unpack(unpacker); + } + + public int getParamId() { + return paramId; + } + + public Value getParamValue() { + return paramValue; + } + + public int getParamType() { + return paramType; + } + + public String toString() { + return "SystemParameter [paramId=" + + paramId + + ", paramType=" + + paramType + + ", paramValue=" + + paramValue + + "]"; + } + + @Override + public void unpack(CUBRIDUnpacker unpacker) { + try { + this.paramId = unpacker.unpackInt(); // paramId + this.paramType = unpacker.unpackInt(); // paramType + this.paramValue = unpacker.unpackValue(paramType); + } catch (TypeMismatchException e) { + } + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java index 54ee4bb6e3..ebce29579a 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java @@ -31,8 +31,7 @@ package com.cubrid.jsp; -import com.cubrid.jsp.context.Context; -import com.cubrid.jsp.context.ContextManager; +import com.cubrid.jsp.code.Signature; import com.cubrid.jsp.exception.ExecuteException; import cubrid.sql.CUBRIDOID; import java.lang.reflect.Method; @@ -55,47 +54,10 @@ public class TargetMethod { initdescriptorMap(); } - public TargetMethod(String signature) throws Exception { - int argStart = signature.indexOf('(') + 1; - if (argStart < 0) { - throw new IllegalArgumentException("Parenthesis '(' not found"); - } - int argEnd = signature.indexOf(')'); - if (argEnd < 0) { - throw new IllegalArgumentException("Parenthesis ')' not found"); - } - int nameStart = signature.substring(0, argStart).lastIndexOf('.') + 1; - - if (signature.charAt(0) == '\'') { - className = signature.substring(1, nameStart - 1).trim(); - } else { - className = signature.substring(0, nameStart - 1).trim(); - } - - methodName = signature.substring(nameStart, argStart - 1).trim(); - String args = signature.substring(argStart, argEnd); - argsTypes = classesFor(args); - } - - private Class getClass(String name) throws ClassNotFoundException { - Context ctx = ContextManager.getContextofCurrentThread(); - ClassLoader cl = ctx.getClassLoader(); - Class c = null; - try { - c = cl.loadClass(name); - assert c != null; - return c; - } catch (ClassNotFoundException e) { - // ignore - } - - try { - c = Server.class.getClassLoader().loadClass(name); - assert c != null; - return c; - } catch (ClassNotFoundException e) { - throw e; - } + public TargetMethod(Signature signature) throws Exception { + className = signature.getClassName(); + methodName = signature.getMethodName(); + argsTypes = classesFor(signature.getArgs()); } private Class[] classesFor(String args) throws ClassNotFoundException, ExecuteException { @@ -141,7 +103,10 @@ private Class classFor(String className) throws ClassNotFoundException, Execu if (argClassMap.containsKey(className)) { return argClassMap.get(className); } else { - return getClass(className); + // TODO: + // return ClassAccess.getClass(ContextManager.getContextofCurrentThread(), className); + // unknown class + throw new ClassNotFoundException(className); } } @@ -182,6 +147,18 @@ private static void initArgClassMap() { argClassMap.put("java.lang.Double", Double.class); argClassMap.put("java.lang.String", String.class); argClassMap.put("java.lang.Object", Object.class); + + argClassMap.put("Boolean", Boolean.class); + argClassMap.put("Byte", Byte.class); + argClassMap.put("Character", Character.class); + argClassMap.put("Short", Short.class); + argClassMap.put("Integer", Integer.class); + argClassMap.put("Long", Long.class); + argClassMap.put("Float", Float.class); + argClassMap.put("Double", Double.class); + argClassMap.put("String", String.class); + argClassMap.put("Object", Object.class); + argClassMap.put("java.math.BigDecimal", BigDecimal.class); argClassMap.put("java.sql.Date", Date.class); argClassMap.put("java.sql.Time", Time.class); @@ -198,6 +175,18 @@ private static void initArgClassMap() { argClassMap.put("[Ljava.lang.Double;", Double[].class); argClassMap.put("[Ljava.lang.String;", String[].class); argClassMap.put("[Ljava.lang.Object;", Object[].class); + + argClassMap.put("[LBoolean;", Boolean[].class); + argClassMap.put("[LByte;", Byte[].class); + argClassMap.put("[LCharacter;", Character[].class); + argClassMap.put("[LShort;", Short[].class); + argClassMap.put("[LInteger;", Integer[].class); + argClassMap.put("[LLong;", Long[].class); + argClassMap.put("[LFloat;", Float[].class); + argClassMap.put("[LDouble;", Double[].class); + argClassMap.put("[LString;", String[].class); + argClassMap.put("[LObject;", Object[].class); + argClassMap.put("[Ljava.math.BigDecimal;", BigDecimal[].class); argClassMap.put("[Ljava.sql.Date;", Date[].class); argClassMap.put("[Ljava.sql.Time;", Time[].class); @@ -219,12 +208,7 @@ private static void initdescriptorMap() { descriptorMap.put("double", "D"); } - public Method getMethod() - throws SecurityException, NoSuchMethodException, ClassNotFoundException { - Class c = getClass(className); - if (c == null) { - throw new ClassNotFoundException(className); - } + public Method getMethod(Class c) throws SecurityException, NoSuchMethodException { try { return c.getMethod(methodName, argsTypes); } catch (NoSuchMethodException e) { diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java index 60a6c500e2..0dd3c7a9e3 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java @@ -45,7 +45,8 @@ public TargetMethod get(String signature) throws Exception { method = methods.get(signature); if (method == null) { - method = new TargetMethod(signature); + // TODO (CBRD-25370) : disabled temporary + // method = new TargetMethod(signature); methods.put(signature, method); } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoader.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoader.java new file mode 100644 index 0000000000..7c57049879 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoader.java @@ -0,0 +1,93 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.classloader; + +import com.cubrid.jsp.code.CompiledCode; +import com.cubrid.jsp.code.CompiledCodeSet; +import java.util.Map.Entry; +import java.util.UUID; + +public class SessionClassLoader extends ClassLoader { + + private String id = null; + private CompiledCodeSet code = null; + + public SessionClassLoader(CompiledCodeSet code) { + id = UUID.randomUUID().toString(); + this.code = code; + } + + public String getId() { + return id; + } + + public CompiledCodeSet getCode() { + return code; + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + Class mainCls = findLoadedClass(name); + if (mainCls != null) { + // already loaded + } else { + try { + mainCls = super.loadClass(name); + if (mainCls != null) { + return mainCls; + } + } catch (ClassNotFoundException e) { + // ignore + } + + // find in codesets + if (code != null) { + for (Entry entry : code.getCodeList()) { + Class cls = null; + String className = entry.getKey(); + byte[] classBytes = entry.getValue().getByteCode(); + cls = defineClass(className, classBytes, 0, classBytes.length); + if (name.equals(className)) { + mainCls = cls; + } + } + } + } + + return mainCls; + } + + public void clear() { + id = null; + code = null; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderGroup.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderGroup.java new file mode 100644 index 0000000000..cbb6f52bd0 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderGroup.java @@ -0,0 +1,38 @@ +package com.cubrid.jsp.classloader; + +import com.cubrid.jsp.code.CompiledCodeSet; +import java.util.HashMap; +import java.util.Map; + +public class SessionClassLoaderGroup { + + Map classLoaders = null; + + public SessionClassLoaderGroup() { + classLoaders = new HashMap<>(); + } + + public void clear() { + classLoaders.clear(); + classLoaders = null; + } + + public Class loadClass(CompiledCodeSet code) throws ClassNotFoundException { + String name = code.getMainClassName(); + SessionClassLoader cl = classLoaders.get(name); + if (cl != null) { + CompiledCodeSet loadedCode = cl.getCode(); + if (loadedCode.getTimeStamp() != code.getTimeStamp()) { + // create new SessionClassLoader + cl.clear(); + cl = new SessionClassLoader(code); + classLoaders.put(name, cl); + } + } else { + cl = new SessionClassLoader(code); + classLoaders.put(name, cl); + } + + return cl.loadClass(name); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderManager.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderManager.java new file mode 100644 index 0000000000..e84a6e58bf --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/SessionClassLoaderManager.java @@ -0,0 +1,68 @@ +package com.cubrid.jsp.classloader; + +import com.cubrid.jsp.code.CompiledCodeSet; +import com.cubrid.jsp.code.MemoryClass; +import java.util.HashMap; +import java.util.Map; + +public class SessionClassLoaderManager { + + private long id; + + private Map sessionScopedLoadedCode; //
+ + private SessionClassLoaderGroup sessionClassLoaderGroup; + + public SessionClassLoaderManager(long id) { + this.id = id; + sessionScopedLoadedCode = new HashMap<>(); + sessionClassLoaderGroup = new SessionClassLoaderGroup(); + } + + public Class loadClass(CompiledCodeSet code) throws ClassNotFoundException { + if (code == null) { + return null; + } + + String className = code.getMainClassName(); + MemoryClass mCls = null; + if (!sessionScopedLoadedCode.containsKey(className)) { + mCls = new MemoryClass(className); + mCls.setCode(code); + sessionScopedLoadedCode.put(className, mCls); + } + + Class loadedClass = sessionClassLoaderGroup.loadClass(code); + if (mCls != null && loadedClass != null) { + mCls.setLoadedClass(loadedClass); + } + + return loadedClass; + } + + public Class findClass(String mainClassName) { + MemoryClass mCls = null; + if (sessionScopedLoadedCode.containsKey(mainClassName)) { + mCls = sessionScopedLoadedCode.get(mainClassName); + } + + if (mCls != null) { + return mCls.getLoadedClass(); + } + + return null; + } + + public void clear() { + sessionScopedLoadedCode.clear(); + + if (sessionClassLoaderGroup != null) { + sessionClassLoaderGroup.clear(); + } + sessionClassLoaderGroup = new SessionClassLoaderGroup(); + } + + public long getId() { + return id; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/ClassAccess.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/ClassAccess.java new file mode 100644 index 0000000000..fffad3ce5f --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/ClassAccess.java @@ -0,0 +1,141 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ +package com.cubrid.jsp.code; + +import com.cubrid.jsp.context.Context; +import com.cubrid.jsp.data.CUBRIDPacker; +import com.cubrid.jsp.data.CUBRIDUnpacker; +import com.cubrid.jsp.exception.TypeMismatchException; +import com.cubrid.jsp.protocol.Header; +import com.cubrid.jsp.protocol.RequestCode; +import com.cubrid.jsp.value.Value; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Base64; + +public class ClassAccess { + public static String getCodeMeta(Connection conn, String name) throws SQLException { + String ts = null; + String sql = + "SELECT created_time, is_static, is_system_generated FROM _db_stored_procedure_code WHERE name = ?"; + PreparedStatement prepStmt = conn.prepareStatement(sql); + prepStmt.setString(1, name); + + ResultSet rs = prepStmt.executeQuery(); + if (rs.next()) { + ts = rs.getString(1); + } + rs.close(); + return ts; + } + + public static String getTransactionKey(Connection conn, String name) + throws IOException, TypeMismatchException { + String ts = null; + + sendGetCodeAttr("created_time"); + + Value val = receiveCodeAttrValue(); + if (val != null) { + ts = val.toString(); + } + + return ts; + } + + public static byte[] getObjectCodeBytes(Connection conn, String name) + throws IOException, TypeMismatchException { + byte[] jar = null; + + sendGetCodeAttr("ocode"); + + Value val = receiveCodeAttrValue(); + if (val != null) { + String base64Str = val.toString(); + jar = Base64.getDecoder().decode(base64Str); + } + + return jar; + } + + public static CompiledCodeSet getObjectCode(Connection conn, Signature sig) throws Exception { + CompiledCodeSet code = null; + String className = sig.getClassName(); + + String tKey = null; + try { + tKey = getTransactionKey(conn, className); + } catch (Exception e) { + } + + if (tKey == null) { + return null; + } + + byte[] jarCode = ClassAccess.getObjectCodeBytes(conn, className); + if (jarCode != null) { + code = CompiledCodeSet.loadFromJar(className, jarCode); + code.setTimestamp(tKey); + } + + return code; + } + + private static void sendGetCodeAttr(String attr_name) throws IOException { + CUBRIDPacker packer = new CUBRIDPacker(ByteBuffer.allocate(1024)); + packer.packInt(RequestCode.REQUEST_CODE_ATTR); + packer.packString(attr_name); + Context.getCurrentExecuteThread().sendCommand(packer.getBuffer()); + } + + private static Value receiveCodeAttrValue() throws IOException, TypeMismatchException { + ByteBuffer responseBuffer = Context.getCurrentExecuteThread().receiveBuffer(); + CUBRIDUnpacker unpacker = new CUBRIDUnpacker(responseBuffer); + + Header header = new Header(unpacker); + ByteBuffer payload = unpacker.unpackBuffer(); + + unpacker.setBuffer(payload); + + int error = unpacker.unpackInt(); + if (error == 0) { + int param_type = unpacker.unpackInt(); + Value val = unpacker.unpackValue(param_type); + return val; + } + + return null; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCode.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCode.java new file mode 100644 index 0000000000..5336d24707 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCode.java @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.code; + +import com.cubrid.jsp.Server; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import javax.tools.SimpleJavaFileObject; + +public class CompiledCode extends SimpleJavaFileObject { + private String className = null; + private ByteArrayOutputStream baos = null; + + private byte[] byteCode = null; + + public CompiledCode(String className) throws java.net.URISyntaxException { + super(new URI(className), Kind.CLASS); + + int idx = className.indexOf("."); + if (idx != -1) { + this.className = className.substring(0, idx); + + } else { + this.className = className; + } + this.baos = new ByteArrayOutputStream(); + } + + public String getClassName() { + return className; + } + + public String getClassNameWithExtention() { + return className + ".class"; + } + + public byte[] getByteCode() { + if (byteCode == null) { + byteCode = baos.toByteArray(); + try { + baos.close(); + } catch (IOException e) { + // ignore + } + } + return byteCode; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return new String(getByteCode(), Server.getConfig().getServerCharset()); + } + + @Override + public OutputStream openOutputStream() throws IOException { + return baos; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCodeSet.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCodeSet.java new file mode 100644 index 0000000000..839593a351 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/CompiledCodeSet.java @@ -0,0 +1,133 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.code; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.compress.archivers.jar.JarArchiveEntry; +import org.apache.commons.compress.archivers.jar.JarArchiveInputStream; + +public class CompiledCodeSet { + + private String mainClass = null; + private long timestamp = -1; + private Map codeMap = null; + + public CompiledCodeSet(String mainClass, Collection codeList) { + this.mainClass = mainClass; + this.codeMap = + codeList.stream() + .collect(Collectors.toMap(CompiledCode::getClassName, item -> item)); + } + + public String getMainClassName() { + return mainClass; + } + + public void add(CompiledCode c) { + codeMap.put(c.getClassName(), c); + } + + public void addAll(Collection cl) { + Map map = + cl.stream().collect(Collectors.toMap(CompiledCode::getClassName, item -> item)); + codeMap.putAll(map); + } + + public Set> getCodeList() { + return codeMap.entrySet(); + } + + public void setTimestamp(String tsString) { + timestamp = Long.parseLong(tsString); + } + + public void setTimestamp(long ts) { + timestamp = ts; + } + + public long getTimeStamp() { + return timestamp; + } + + public void clear() { + mainClass = null; + codeMap.clear(); + } + + public static CompiledCodeSet loadFromJar(String mainClass, byte[] jarString) throws Exception { + + List codeList = new ArrayList<>(); + + try (final JarArchiveInputStream jarIn = + new JarArchiveInputStream(new ByteArrayInputStream(jarString))) { + JarArchiveEntry jarEntry; + while ((jarEntry = jarIn.getNextEntry()) != null) { + if (jarEntry.isDirectory()) { + continue; + } + final String key = jarEntry.getName(); + CompiledCode c = new CompiledCode(key); + OutputStream os = c.openOutputStream(); + + final long fileSize = jarEntry.getSize(); + byte[] buffer = null; + if (fileSize > 0) { + + buffer = new byte[(int) fileSize]; + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while (true) { + int qwe = jarIn.read(); + if (qwe == -1) break; + baos.write(qwe); + } + buffer = baos.toByteArray(); + } + jarIn.read(buffer); + os.write(buffer); + // IOUtils.copy (jarIn, os, fileSize); + codeList.add(c); + } + } + + return new CompiledCodeSet(mainClass, codeList); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClass.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClass.java new file mode 100644 index 0000000000..0bbfaf901f --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClass.java @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.code; + +// cacheable Class object in-memory +public class MemoryClass { + + private String className = null; + private CompiledCodeSet loadedCode = null; + private Class loadedClass = null; + + public MemoryClass(String className) { + this.className = className; + } + + public String getClassName() { + return className; + } + + public void setCode(CompiledCodeSet codeset) { + clear(); + this.loadedCode = codeset; + } + + public Class getLoadedClass() { + return loadedClass; + } + + public void setLoadedClass(Class loadedClass) { + this.loadedClass = loadedClass; + } + + public void clear() { + if (this.loadedCode != null) { + this.loadedCode.clear(); + this.loadedCode = null; + } + + loadedClass = null; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClassCache.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClassCache.java new file mode 100644 index 0000000000..faf58b3554 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/MemoryClassCache.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.code; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MemoryClassCache { + + private Map classMap = null; + + // singleton + private static class LazyHolder { + private static final MemoryClassCache INSTANCE = new MemoryClassCache(null); + } + + public static MemoryClassCache getInstance() { + return LazyHolder.INSTANCE; + } + + public MemoryClassCache(MemoryClassCache parent) { + this.classMap = new ConcurrentHashMap<>(); + } + + public MemoryClass getByClassName(String className) { + return classMap.get(className); + } + + public void put(MemoryClass mCls) { + classMap.put(mCls.getClassName(), mCls); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/Signature.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/Signature.java new file mode 100644 index 0000000000..5359656b14 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/Signature.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ +package com.cubrid.jsp.code; + +public class Signature { + private String className; + private String methodName; + private String args; + + public Signature(String cName, String mName, String args) { + className = cName; + methodName = mName; + this.args = args; + } + + public String getClassName() { + return className; + } + + public String getMethodName() { + return methodName; + } + + public String getArgs() { + return args; + } + + public static Signature parse(String signature) { + String className = null; + String methodName = null; + String args = null; + + int argStart = signature.indexOf('(') + 1; + if (argStart < 0) { + throw new IllegalArgumentException("Parenthesis '(' not found"); + } + int argEnd = signature.indexOf(')'); + if (argEnd < 0) { + throw new IllegalArgumentException("Parenthesis ')' not found"); + } + int nameStart = signature.substring(0, argStart).lastIndexOf('.') + 1; + + if (signature.charAt(0) == '\'') { + className = signature.substring(1, nameStart - 1); + } else { + className = signature.substring(0, nameStart - 1); + } + + methodName = signature.substring(nameStart, argStart - 1); + args = signature.substring(argStart, argEnd); + + return new Signature(className, methodName, args); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/SourceCode.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/SourceCode.java new file mode 100644 index 0000000000..94f26e1f44 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/code/SourceCode.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.code; + +import java.net.URI; +import javax.tools.SimpleJavaFileObject; + +public class SourceCode extends SimpleJavaFileObject { + private String className; + private String code; + + public SourceCode(String className, String code) { + super( + URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), + Kind.SOURCE); + this.code = code; + this.className = className; + } + + public String getClassName() { + return className; + } + + public String getCode() { + return code; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return code; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryFileManager.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryFileManager.java new file mode 100644 index 0000000000..16958507c4 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryFileManager.java @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.compiler; + +import com.cubrid.jsp.code.CompiledCode; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; + +public class MemoryFileManager extends ForwardingJavaFileManager { + + private List codeList = new ArrayList(); + + protected MemoryFileManager(JavaFileManager fileManager) { + super(fileManager); + } + + @Override + public JavaFileObject getJavaFileForOutput( + JavaFileManager.Location location, + String className, + JavaFileObject.Kind kind, + FileObject sibling) + throws IOException { + try { + CompiledCode c = new CompiledCode(className); + + // register CompiledCode in GlobalClassStore + codeList.add(c); + + return c; + } catch (Exception e) { + throw new RuntimeException( + "Error occurs while creating output class file in memory for " + className, e); + } + } + + @Override + public ClassLoader getClassLoader(JavaFileManager.Location location) { + return null; + } + + public List getCodeList() { + return codeList; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryJavaCompiler.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryJavaCompiler.java new file mode 100644 index 0000000000..4285cb6256 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/compiler/MemoryJavaCompiler.java @@ -0,0 +1,103 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.compiler; + +import com.cubrid.jsp.Server; +import com.cubrid.jsp.code.CompiledCodeSet; +import com.cubrid.jsp.code.SourceCode; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; + +public class MemoryJavaCompiler { + + private JavaCompiler compiler; + private List options = new ArrayList<>(); + + public MemoryJavaCompiler() { + compiler = ToolProvider.getSystemJavaCompiler(); + if (compiler == null) { + throw new IllegalStateException( + "Cannot find the system Java compiler. Check that your class path includes tools.jar"); + } + + Path cubrid_env_root = Server.getServer().getRootPath(); + useOptions("-encoding", Server.getConfig().getServerCharset().toString()); + useOptions("-classpath", cubrid_env_root + "/java/pl_server.jar"); + } + + public synchronized void useOptions(String... options) { + this.options.addAll(Arrays.asList(options)); + } + + public synchronized CompiledCodeSet compile(SourceCode code) { + DiagnosticCollector collector = new DiagnosticCollector<>(); + MemoryFileManager fileManager = + new MemoryFileManager(compiler.getStandardFileManager(null, null, null)); + JavaCompiler.CompilationTask task = + compiler.getTask(null, fileManager, collector, options, null, Arrays.asList(code)); + + boolean result = task.call(); + if (!result || collector.getDiagnostics().size() > 0) { + String exceptionMsg = new String("Unable to compile the source"); + boolean hasErrors = false; + + for (Diagnostic d : collector.getDiagnostics()) { + switch (d.getKind()) { + case NOTE: + case MANDATORY_WARNING: + case WARNING: + break; + case OTHER: + case ERROR: + default: + hasErrors = true; + break; + } + } + + if (hasErrors) { + throw new RuntimeException(exceptionMsg.toString()); + } + } + + assert (code.getClassName() != null); + + return new CompiledCodeSet(code.getClassName(), fileManager.getCodeList()); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/Context.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/Context.java index 103e282156..5082c747ac 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/Context.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/Context.java @@ -32,13 +32,16 @@ package com.cubrid.jsp.context; import com.cubrid.jsp.ExecuteThread; +import com.cubrid.jsp.Server; import com.cubrid.jsp.TargetMethodCache; import com.cubrid.jsp.classloader.ClassLoaderManager; import com.cubrid.jsp.classloader.ContextClassLoader; +import com.cubrid.jsp.classloader.SessionClassLoaderManager; import com.cubrid.jsp.jdbc.CUBRIDServerSideConnection; import com.cubrid.jsp.protocol.Header; import com.cubrid.plcsql.builtin.MessageBuffer; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; @@ -55,7 +58,7 @@ public class Context { private int prevRequestId = 0; // charset - private String charSet = "UTF-8"; + private Charset sessionCharset = null; // single server-side connection per Context private CUBRIDServerSideConnection connection = null; @@ -66,7 +69,8 @@ public class Context { private Properties clientInfo = null; // dynamic classLoader for a session - private ContextClassLoader classLoader = null; + private SessionClassLoaderManager sessionClassLoaderManager = null; + private ContextClassLoader oldClassLoader = null; // file // method cache private TargetMethodCache methodCache = null; @@ -75,6 +79,7 @@ public class Context { private boolean transactionControl = false; // Connection Properties + private static Properties DEFAULT_CONNECTION_INFO = new Properties(); private Properties connectionInfo = null; // message buffer for DBMS_OUTPUT @@ -88,6 +93,10 @@ public long getSessionId() { return sessionId; } + public synchronized Connection getConnection() { + return getConnection(DEFAULT_CONNECTION_INFO); + } + public synchronized Connection getConnection(Properties prop) { if (this.connection == null) { this.connectionInfo = prop; @@ -116,8 +125,11 @@ public LinkedBlockingQueue getInboundQueue() { return inBound; } - public String getCharset() { - return charSet; + public Charset getSessionCharset() { + if (sessionCharset == null) { + sessionCharset = Server.getConfig().getServerCharset(); + } + return sessionCharset; } public void checkHeader(Header header) { @@ -132,20 +144,25 @@ public void checkHeader(Header header) { public void checkTranId(int tid) { if (tranactionId == -1) { tranactionId = tid; - classLoader = new ContextClassLoader(); + oldClassLoader = new ContextClassLoader(); } else if (tranactionId != tid) { // re-cretae dynamic class loader - if (classLoader - .getInitializedTime() - .compareTo( - ClassLoaderManager.getLastModifiedTimeOfPath( - ClassLoaderManager.getDynamicPath())) - != 0) { - classLoader = new ContextClassLoader(); + if (oldClassLoader != null + && oldClassLoader + .getInitializedTime() + .compareTo( + ClassLoaderManager.getLastModifiedTimeOfPath( + ClassLoaderManager.getDynamicPath())) + != 0) { + oldClassLoader = new ContextClassLoader(); methodCache.clear(); } clear(); tranactionId = tid; + + if (sessionClassLoaderManager != null) { + sessionClassLoaderManager.clear(); + } } } @@ -166,12 +183,20 @@ public MessageBuffer getMessageBuffer() { return messageBuffer; } - public ClassLoader getClassLoader() { - if (classLoader == null) { - classLoader = new ContextClassLoader(); + public SessionClassLoaderManager getSessionCLManager() { + if (sessionClassLoaderManager == null) { + sessionClassLoaderManager = new SessionClassLoaderManager(sessionId); } - return classLoader; + return sessionClassLoaderManager; + } + + public ClassLoader getOldClassLoader() { + if (oldClassLoader == null) { + oldClassLoader = new ContextClassLoader(); + } + + return oldClassLoader; } public TargetMethodCache getTargetMethodCache() { @@ -191,9 +216,11 @@ public boolean canTransactionControl() { return true; } - String tcProp = connectionInfo.getProperty("transaction_control"); - if (tcProp != null && "true".equalsIgnoreCase(tcProp)) { - return true; + if (connectionInfo != null) { + String tcProp = connectionInfo.getProperty("transaction_control"); + if (tcProp != null && "true".equalsIgnoreCase(tcProp)) { + return true; + } } return false; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/AuthInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/AuthInfo.java new file mode 100644 index 0000000000..57b20dcedb --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/AuthInfo.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.data; + +import com.cubrid.jsp.protocol.PackableObject; + +public class AuthInfo implements PackableObject { + + public int command = -1; + public String authName = ""; + + public AuthInfo(int command, String authName) { + this.command = command; + this.authName = authName; + } + + @Override + public void pack(CUBRIDPacker packer) { + packer.packInt(command); + packer.packString(authName); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java index 8802374c73..2077da81dd 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java @@ -31,14 +31,24 @@ package com.cubrid.jsp.data; +import com.cubrid.jsp.Server; +import com.cubrid.jsp.SysParam; +import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.jsp.jdbc.CUBRIDServerSideResultSet; import com.cubrid.jsp.protocol.PackableObject; +import com.cubrid.jsp.value.NullValue; +import com.cubrid.jsp.value.SetValue; +import com.cubrid.jsp.value.StringValue; +import com.cubrid.jsp.value.Value; import com.cubrid.plcsql.predefined.sp.SpLib; import cubrid.sql.CUBRIDOID; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.sql.Date; import java.sql.ResultSet; +import java.sql.Timestamp; import java.text.SimpleDateFormat; public class CUBRIDPacker { @@ -98,11 +108,12 @@ public void packDouble(double value) { } public void packString(String value) { - packCString(value.getBytes()); + Charset charset = Server.getConfig().getServerCharset(); + packCString(value.getBytes(charset)); } - public void packString(String value, String charset) throws UnsupportedEncodingException { - packCString(value.getBytes(charset)); + public void packString(String value, int codeset) throws UnsupportedEncodingException { + packCString(value.getBytes(SysParam.getCodesetString(codeset))); } public void packOID(SOID oid) { @@ -149,8 +160,134 @@ public void packPrimitiveBytes(ByteBuffer b) { buffer.put(b.array(), 0, b.position()); } - // TODO: legacy implementation, this function will be modified - public void packValue(Object result, int ret_type, String charset) + public void packValue(Value value, int dbType) + throws UnsupportedEncodingException, TypeMismatchException { + if (value == null || value instanceof NullValue) { + dbType = DBType.DB_NULL; + } + + switch (dbType) { + case DBType.DB_INT: + packInt(dbType); + packInt(value.toInt()); + break; + case DBType.DB_SHORT: + packInt(dbType); + packShort(value.toShort()); + break; + case DBType.DB_BIGINT: + packInt(dbType); + packBigInt(value.toLong()); + break; + case DBType.DB_FLOAT: + packInt(dbType); + packFloat(value.toFloat()); + break; + case DBType.DB_DOUBLE: + case DBType.DB_MONETARY: + packInt(dbType); + packDouble(value.toDouble()); + break; + + case DBType.DB_CHAR: + case DBType.DB_STRING: + packInt(dbType); + if (value instanceof StringValue) { + packInt(value.getCodeSet()); + packCString(value.toByteArray()); + } else { + packInt(value.getCodeSet()); + packString(value.toString(), value.getCodeSet()); + } + break; + + case DBType.DB_NUMERIC: + packInt(dbType); + packString(value.toBigDecimal().toPlainString()); + break; + + case DBType.DB_DATE: + packInt(dbType); + Date d = value.toDate(); + if (d.equals(SpLib.ZERO_DATE)) { + packString("0000-00-00"); + } else { + packString(d.toString()); + } + break; + case DBType.DB_TIME: + packInt(dbType); + packString(value.toTime().toString()); + break; + + case DBType.DB_TIMESTAMP: + case DBType.DB_DATETIME: + packInt(dbType); + + Timestamp ts = null; + if (dbType == DBType.DB_DATETIME) { + ts = value.toDatetime(); + if (ts.equals(SpLib.ZERO_DATETIME)) { + packString("0000-00-00 00:00:00.000"); + } else { + packString(ts.toString()); + } + } else { + ts = value.toTimestamp(); + if (SpLib.isZeroTimestamp((java.sql.Timestamp) ts)) { + packString("0000-00-00 00:00:00"); + } else { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + packString(formatter.format(ts)); + } + } + break; + + case DBType.DB_OID: + case DBType.DB_OBJECT: + packInt(dbType); + byte[] oid = value.toOid().getOID(); + packOID(new SOID(oid)); + break; + + case DBType.DB_SET: + case DBType.DB_MULTISET: + case DBType.DB_SEQUENCE: + packInt(dbType); + + Object[] values = null; + if (value instanceof SetValue) { + values = (Value[]) ((SetValue) value).toValueArray(); + if (values != null) { + packInt(values.length); + for (int i = 0; i < values.length; i++) { + int dt = DBType.DB_NULL; + if (values[i] != null) { + dt = ((Value) values[i]).getDbType(); + } + packValue((Value) values[i], dt); + } + } + } + + if (values == null) { + values = value.toObjectArray(); + packObject(values, dbType, value.getCodeSet()); + } + break; + + case DBType.DB_RESULTSET: + packInt(dbType); + packBigInt(value.toLong()); + break; + + default: + packInt(DBType.DB_NULL); + break; + } + } + + public void packObject(Object result, int ret_type, int codeset) throws UnsupportedEncodingException { if (result == null) { packInt(DBType.DB_NULL); @@ -167,24 +304,25 @@ public void packValue(Object result, int ret_type, String charset) packInt(DBType.DB_FLOAT); packFloat(((Float) result).floatValue()); } else if (result instanceof Double) { - packInt(ret_type); + packInt(DBType.DB_DOUBLE); packDouble(((Double) result).doubleValue()); } else if (result instanceof BigDecimal) { packInt(DBType.DB_NUMERIC); - packString(((BigDecimal) result).toPlainString(), charset); + packString(((BigDecimal) result).toPlainString(), codeset); } else if (result instanceof String) { packInt(DBType.DB_STRING); - packString((String) result, charset); + packInt(codeset); + packString((String) result, codeset); } else if (result instanceof java.sql.Date) { packInt(DBType.DB_DATE); if (result.equals(SpLib.ZERO_DATE)) { - packString("0000-00-00", charset); + packString("0000-00-00", codeset); } else { - packString(result.toString(), charset); + packString(result.toString(), codeset); } } else if (result instanceof java.sql.Time) { packInt(DBType.DB_TIME); - packString(result.toString(), charset); + packString(result.toString(), codeset); } else if (result instanceof java.sql.Timestamp) { packInt(ret_type); if (ret_type == DBType.DB_DATETIME) { @@ -216,16 +354,15 @@ public void packValue(Object result, int ret_type, String charset) packInt(array.length); for (int i = 0; i < array.length; i++) { array[i] = new Integer(((int[]) result)[i]); - packValue(array[i], ret_type, charset); + packObject(array[i], DBType.DB_INT, codeset); } - packValue(array, ret_type, charset); } else if (result instanceof short[]) { int length = ((short[]) result).length; Short[] array = new Short[length]; packInt(array.length); for (int i = 0; i < array.length; i++) { array[i] = new Short(((short[]) result)[i]); - packValue(array, ret_type, charset); + packObject(array, DBType.DB_SHORT, codeset); } } else if (result instanceof float[]) { int length = ((float[]) result).length; @@ -233,7 +370,7 @@ public void packValue(Object result, int ret_type, String charset) packInt(array.length); for (int i = 0; i < array.length; i++) { array[i] = new Float(((float[]) result)[i]); - packValue(array[i], ret_type, charset); + packObject(array[i], DBType.DB_FLOAT, codeset); } } else if (result instanceof double[]) { int length = ((double[]) result).length; @@ -241,7 +378,7 @@ public void packValue(Object result, int ret_type, String charset) packInt(array.length); for (int i = 0; i < array.length; i++) { array[i] = new Double(((double[]) result)[i]); - packValue(array[i], ret_type, charset); + packObject(array[i], DBType.DB_DOUBLE, codeset); } } else if (result instanceof Object[]) { packInt(ret_type); @@ -249,7 +386,7 @@ public void packValue(Object result, int ret_type, String charset) packInt(arr.length); for (int i = 0; i < arr.length; i++) { - packValue(arr[i], ret_type, charset); + packObject(arr[i], ret_type, codeset); } } else { // FIXME: treat as NULL diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java index 27e3d03f36..54f5947906 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.data; +import com.cubrid.jsp.Server; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.jsp.value.*; import java.nio.ByteBuffer; @@ -105,7 +106,7 @@ public String unpackCString() { byte[] str = new byte[len]; buffer.get(str); align(DataUtilities.INT_ALIGNMENT); - return new String(str); + return new String(str, Server.getConfig().getServerCharset()); } else { align(DataUtilities.INT_ALIGNMENT); return ""; @@ -114,9 +115,15 @@ public String unpackCString() { public byte[] unpackCStringByteArray() { int len = unpackStringSize(); - byte[] str = new byte[len]; - buffer.get(str); - return str; + if (len > 0) { + byte[] str = new byte[len]; + buffer.get(str); + align(DataUtilities.INT_ALIGNMENT); + return str; + } else { + align(DataUtilities.INT_ALIGNMENT); + return new byte[0]; + } } public int unpackStringSize() { @@ -181,7 +188,8 @@ public Value unpackValue(int paramType) throws TypeMismatchException { break; case DBType.DB_CHAR: case DBType.DB_STRING: - arg = new StringValue(unpackCString()); + int codeset = unpackInt(); + arg = new StringValue(unpackCStringByteArray(), codeset); break; case DBType.DB_DATE: { @@ -244,7 +252,7 @@ public Value unpackValue(int paramType) throws TypeMismatchException { case DBType.DB_OID: case DBType.DB_OBJECT: { - SOID soid = new SOID(this); + SOID soid = unpackOID(); arg = new OidValue(soid); } break; @@ -258,113 +266,11 @@ public Value unpackValue(int paramType) throws TypeMismatchException { return arg; } - public Value unpackValue(int paramType, int mode, int dbType) throws TypeMismatchException { - Value arg = null; - switch (paramType) { - case DBType.DB_SHORT: - arg = new ShortValue(unpackShort(), mode, dbType); - break; - case DBType.DB_INT: - arg = new IntValue(unpackInt(), mode, dbType); - break; - case DBType.DB_BIGINT: - arg = new LongValue(unpackBigint(), mode, dbType); - break; - case DBType.DB_FLOAT: - arg = new FloatValue(unpackFloat(), mode, dbType); - break; - case DBType.DB_DOUBLE: - case DBType.DB_MONETARY: - arg = new DoubleValue(unpackDouble(), mode, dbType); - break; - case DBType.DB_NUMERIC: - arg = new NumericValue(unpackCString(), mode, dbType); - break; - case DBType.DB_CHAR: - case DBType.DB_STRING: - arg = new StringValue(unpackCString(), mode, dbType); - break; - case DBType.DB_DATE: - { - int year = unpackInt(); - int month = unpackInt(); - int day = unpackInt(); - - arg = new DateValue(year, month, day, mode, dbType); - } - break; - case DBType.DB_TIME: - { - int hour = unpackInt(); - int min = unpackInt(); - int sec = unpackInt(); - - Calendar cal = Calendar.getInstance(); - cal.set(0, 0, 0, hour, min, sec); - - arg = new TimeValue(hour, min, sec, mode, dbType); - } - break; - case DBType.DB_TIMESTAMP: - { - int year = unpackInt(); - int month = unpackInt(); - int day = unpackInt(); - int hour = unpackInt(); - int min = unpackInt(); - int sec = unpackInt(); - arg = new TimestampValue(year, month, day, hour, min, sec, mode, dbType); - } - break; - case DBType.DB_DATETIME: - { - int year = unpackInt(); - int month = unpackInt(); - int day = unpackInt(); - int hour = unpackInt(); - int min = unpackInt(); - int sec = unpackInt(); - int msec = unpackInt(); - arg = new DatetimeValue(year, month, day, hour, min, sec, msec, mode, dbType); - } - break; - case DBType.DB_SET: - case DBType.DB_MULTISET: - case DBType.DB_SEQUENCE: - { - int nCol = unpackInt(); - arg = new SetValue(unpackSetValue(nCol), mode, dbType); - } - break; - case DBType.DB_OID: - case DBType.DB_OBJECT: - { - SOID oid = new SOID(this); - arg = new OidValue(oid, mode, dbType); - } - break; - case DBType.DB_RESULTSET: - { - long queryId = unpackBigint(); - arg = new ResultSetValue(queryId); - } - break; - case DBType.DB_NULL: - arg = new NullValue(mode, dbType); - break; - default: - // unknown type - break; - } - return arg; - } - private Value[] unpackSetValue(int paramCount) throws TypeMismatchException { Value[] args = new Value[paramCount]; for (int i = 0; i < paramCount; i++) { int paramType = unpackInt(); - // FIXME: dbType=0 is dummy, it is from legacy code. I'm not sure about it - Value arg = unpackValue(paramType, Value.IN, 0); + Value arg = unpackValue(paramType); args[i] = (arg); } return args; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileInfo.java index b09e349f86..b68aa3c325 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileInfo.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileInfo.java @@ -44,6 +44,9 @@ public class CompileInfo implements PackableObject { public String className = null; public String signature = null; + public int compiledType = -1; + public byte[] compiledCode = null; + public CompileInfo(int code, int line, int column, String msg) { assert code < 0; @@ -73,6 +76,11 @@ public void pack(CUBRIDPacker packer) { packer.packString(createStmt); packer.packString(className); packer.packString(signature); + + packer.packInt(compiledType); + if (compiledType >= 0) { + packer.packCString(compiledCode); + } } } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileRequest.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileRequest.java new file mode 100644 index 0000000000..29a80f2a1a --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileRequest.java @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2016 CUBRID Corporation. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +package com.cubrid.jsp.data; + +public class CompileRequest { + public String code = null; + public String owner = null; + public String mode = null; + + public CompileRequest(CUBRIDUnpacker unpacker) { + code = unpacker.unpackCString(); + owner = unpacker.unpackCString(); + mode = unpacker.unpackCString(); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUBindParameter.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUBindParameter.java index cc609baa7b..f911ac3f29 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUBindParameter.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUBindParameter.java @@ -30,7 +30,7 @@ */ package com.cubrid.jsp.impl; -import com.cubrid.jsp.ExecuteThread; +import com.cubrid.jsp.Server; import com.cubrid.jsp.data.CUBRIDPacker; import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.jdbc.CUBRIDServerSideJDBCErrorCode; @@ -108,7 +108,7 @@ synchronized void pack(CUBRIDPacker packer) throws UnsupportedEncodingException int cnt = paramMode.length; packer.packInt(cnt); for (int i = 0; i < cnt; i++) { - packer.packValue(values[i], types[i], ExecuteThread.charSet); + packer.packObject(values[i], types[i], Server.getConfig().getServerCodesetId()); packer.packInt((int) paramMode[i]); } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java index 36c8fdbe6f..6b5bc99d2f 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.impl; +import com.cubrid.jsp.Server; import com.cubrid.jsp.context.Context; import com.cubrid.jsp.data.CUBRIDPacker; import com.cubrid.jsp.data.CUBRIDUnpacker; @@ -264,7 +265,7 @@ public void putByOID(CUBRIDOID oid, String[] attributeName, Object values[]) } int type = DBType.getObjectDBtype(values[i]); - packer.packValue(values[i], type, "UTF-8"); + packer.packObject(values[i], type, Server.getConfig().getServerCodesetId()); } } else { packer.packInt(0); @@ -313,7 +314,7 @@ protected CUBRIDUnpacker collectionCmd( if (value != null) { packer.packInt(1); // has value int type = DBType.getObjectDBtype(value); - packer.packValue(value, type, "UTF-8"); + packer.packObject(value, type, Server.getConfig().getServerCodesetId()); } else { packer.packInt(0); // has value } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/BootstrapRequest.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/BootstrapRequest.java new file mode 100644 index 0000000000..683fd3115e --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/BootstrapRequest.java @@ -0,0 +1,31 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.SysParam; +import com.cubrid.jsp.data.CUBRIDUnpacker; + +public class BootstrapRequest implements UnPackableObject { + + private SysParam[] sysParam; + + public BootstrapRequest(CUBRIDUnpacker unpacker) { + unpack(unpacker); + } + + @Override + public void unpack(CUBRIDUnpacker unpacker) { + int size = unpacker.unpackInt(); + sysParam = new SysParam[size]; + + try { + for (int i = 0; i < size; i++) { + sysParam[i] = new SysParam(unpacker); + } + } catch (Exception e) { + // do nothing + } + } + + public SysParam[] getSystemParameters() { + return sysParam; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PrepareArgs.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PrepareArgs.java index d52e29d727..cd723d5ce7 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PrepareArgs.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PrepareArgs.java @@ -24,7 +24,7 @@ public Value[] getArgs() { public int getArgCount() { if (arguments == null) { - return -1; + return 0; } else { return arguments.length; } @@ -39,15 +39,16 @@ public void readArgs(CUBRIDUnpacker unpacker) throws TypeMismatchException { tranId = unpacker.unpackInt(); int argCount = unpacker.unpackInt(); - if (arguments == null || argCount != arguments.length) { + if (argCount > 0) { arguments = new Value[argCount]; - } - - for (int i = 0; i < arguments.length; i++) { - int paramType = unpacker.unpackInt(); + for (int i = 0; i < arguments.length; i++) { + int paramType = unpacker.unpackInt(); - Value arg = unpacker.unpackValue(paramType); - arguments[i] = (arg); + Value arg = unpacker.unpackValue(paramType); + arguments[i] = (arg); + } + } else { + arguments = null; } } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/RequestCode.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/RequestCode.java index 59fc505d7b..fa0c182ea8 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/RequestCode.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/RequestCode.java @@ -17,6 +17,10 @@ public class RequestCode { public static final int REQUEST_GLOBAL_SEMANTICS = 0xA1; public static final int REQUEST_BUILTIN_FUNCTION = 0xA4; + public static final int REQUEST_CHANGE_AUTH_RIGHTS = 0xC8; + public static final int REQUEST_CODE_ATTR = 0xC9; + + public static final int UTIL_BOOTSTRAP = 0xDD; public static final int UTIL_PING = 0xDE; public static final int UTIL_STATUS = 0xEE; public static final int UTIL_TERMINATE_THREAD = 0xFE; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java index fce60cfda7..7b6bbe047d 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; public class BooleanValue extends Value { @@ -46,13 +47,7 @@ public BooleanValue(boolean b) { if (b) { value = 1; } - } - - public BooleanValue(boolean b, int mode) { - super(mode); - if (b) { - value = 1; - } + this.dbType = DBType.DB_INT; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ByteValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ByteValue.java index 070f2279da..2f5d00c79c 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ByteValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ByteValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import java.math.BigDecimal; @@ -45,11 +46,7 @@ protected String getTypeName() { public ByteValue(byte value) { super(); this.value = value; - } - - public ByteValue(byte value, int mode) { - super(mode); - this.value = value; + this.dbType = DBType.DB_CHAR; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateTimeParser.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateTimeParser.java index 7aff87659a..1c680bb7f8 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateTimeParser.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateTimeParser.java @@ -38,6 +38,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Arrays; @@ -150,12 +151,12 @@ public static ZonedDateTime parseZonedDateAndTime(String s, boolean forDatetime) // get timezone offset LocalDateTime localPart; - ZoneOffset zone; + ZoneId zone; int delim = s.lastIndexOf(" "); if (delim < 0) { // no timezone offset localPart = parseLocalDateAndTime(s, forDatetime); - zone = Server.getSystemParameterTimezone(Server.SYS_PARAM_TIMEZONE); + zone = Server.getConfig().getTimeZone(); } else { String dt = s.substring(0, delim); String z = s.substring(delim + 1); @@ -165,7 +166,7 @@ public static ZonedDateTime parseZonedDateAndTime(String s, boolean forDatetime) } catch (DateTimeException e) { // z turn out not to be a timezone offset. try timezone omitted string localPart = parseLocalDateAndTime(s, forDatetime); - zone = Server.getSystemParameterTimezone(Server.SYS_PARAM_TIMEZONE); + zone = Server.getConfig().getTimeZone(); } } @@ -270,7 +271,7 @@ private static LocalDateTime parseLocalDateAndTime(String s, boolean millis) { } private static int getCurrentYear() { - ZoneOffset timezone = Server.getSystemParameterTimezone(Server.SYS_PARAM_TIMEZONE); + ZoneId timezone = Server.getConfig().getTimeZone(); return ZonedDateTime.now(timezone).getYear(); } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateValue.java index 3c9a87e96a..52ea89580d 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.sql.Date; @@ -55,20 +56,7 @@ public DateValue(int year, int mon, int day) throws TypeMismatchException { if (!SpLib.checkDate(date)) { throw new TypeMismatchException("invalid Date " + date); } - } - - public DateValue(int year, int mon, int day, int mode, int dbType) - throws TypeMismatchException { - super(mode); - Calendar cal = Calendar.getInstance(); - cal.set(year, mon, day, 0, 0, 0); - cal.set(Calendar.MILLISECOND, 0); - - date = new Date(cal.getTimeInMillis()); - if (!SpLib.checkDate(date)) { - throw new TypeMismatchException("invalid Date " + date); - } - this.dbType = dbType; + this.dbType = DBType.DB_DATE; } public DateValue(Date date) throws TypeMismatchException { @@ -76,6 +64,7 @@ public DateValue(Date date) throws TypeMismatchException { throw new TypeMismatchException("invalid Date " + date); } this.date = date; + this.dbType = DBType.DB_DATE; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DatetimeValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DatetimeValue.java index e90af1aaf0..8cb88b49bf 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DatetimeValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DatetimeValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.sql.Date; @@ -55,32 +56,18 @@ public DatetimeValue(int year, int mon, int day, int hour, int min, int sec, int c.set(Calendar.MILLISECOND, msec); timestamp = new Timestamp(c.getTimeInMillis()); + this.dbType = DBType.DB_DATETIME; if (!SpLib.checkDatetime(timestamp)) { throw new TypeMismatchException("invalid Datetime " + timestamp); } } - public DatetimeValue( - int year, int mon, int day, int hour, int min, int sec, int msec, int mode, int dbType) - throws TypeMismatchException { - super(mode); - - Calendar c = Calendar.getInstance(); - c.set(year, mon, day, hour, min, sec); - c.set(Calendar.MILLISECOND, msec); - - timestamp = new Timestamp(c.getTimeInMillis()); - if (!SpLib.checkDatetime(timestamp)) { - throw new TypeMismatchException("invalid Datetime " + timestamp); - } - this.dbType = dbType; - } - public DatetimeValue(Timestamp timestamp) throws TypeMismatchException { if (timestamp != null && !SpLib.checkDatetime(timestamp)) { throw new TypeMismatchException("invalid Datetime " + timestamp); } this.timestamp = timestamp; + this.dbType = DBType.DB_DATETIME; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DoubleValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DoubleValue.java index 95814c8784..225a599b6c 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DoubleValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DoubleValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.math.BigDecimal; @@ -51,15 +52,7 @@ public DoubleValue(double value) throws TypeMismatchException { throw new TypeMismatchException("invalid double " + value); } this.value = value; - } - - public DoubleValue(double value, int mode, int dbType) throws TypeMismatchException { - super(mode); - if (!Double.isFinite(value)) { - throw new TypeMismatchException("invalid double " + value); - } - this.value = value; - this.dbType = dbType; + this.dbType = DBType.DB_DOUBLE; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/FloatValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/FloatValue.java index 3aec4f44a1..832131cac1 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/FloatValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/FloatValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.math.BigDecimal; @@ -51,15 +52,7 @@ public FloatValue(float value) throws TypeMismatchException { throw new TypeMismatchException("invalid float " + value); } this.value = value; - } - - public FloatValue(float value, int mode, int dbType) throws TypeMismatchException { - super(mode); - if (!Float.isFinite(value)) { - throw new TypeMismatchException("invalid float " + value); - } - this.value = value; - this.dbType = dbType; + this.dbType = DBType.DB_FLOAT; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/IntValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/IntValue.java index 2e0f3187c5..86b854144c 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/IntValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/IntValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.math.BigDecimal; @@ -48,12 +49,7 @@ protected String getTypeName() { public IntValue(int value) { super(); this.value = value; - } - - public IntValue(int value, int mode, int dbType) { - super(mode); - this.value = value; - this.dbType = dbType; + this.dbType = DBType.DB_INT; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/LongValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/LongValue.java index bbc4a22709..35c531bbbc 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/LongValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/LongValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.math.BigDecimal; @@ -48,12 +49,7 @@ protected String getTypeName() { public LongValue(long value) { super(); this.value = value; - } - - public LongValue(long value, int mode, int dbType) { - super(mode); - this.value = value; - this.dbType = dbType; + this.dbType = DBType.DB_BIGINT; } @Override @@ -68,7 +64,7 @@ public short toShort() throws TypeMismatchException { @Override public int toInt() throws TypeMismatchException { - return SpLib.convBigintToShort(value); + return SpLib.convBigintToInt(value); } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NullValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NullValue.java index febe6e9c1e..7dae72c0e6 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NullValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NullValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.jsp.impl.SUConnection; import cubrid.sql.CUBRIDOID; @@ -48,11 +49,7 @@ protected String getTypeName() { public NullValue() { super(); - } - - public NullValue(int mode, int dbType) { - super(mode); - this.dbType = dbType; + this.dbType = DBType.DB_NULL; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NumericValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NumericValue.java index d9ac6974e7..68f70820a8 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NumericValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/NumericValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.math.BigDecimal; @@ -47,6 +48,7 @@ protected String getTypeName() { public NumericValue(String value) { super(); this.value = SpLib.convStringToNumeric(value); + this.dbType = DBType.DB_NUMERIC; } public NumericValue(BigDecimal value) throws TypeMismatchException { @@ -55,12 +57,7 @@ public NumericValue(BigDecimal value) throws TypeMismatchException { throw new TypeMismatchException("precision exceeds 38: " + value); } this.value = value; - } - - public NumericValue(String value, int mode, int dbType) { - super(mode); - this.value = SpLib.convStringToNumeric(value); - this.dbType = dbType; + this.dbType = DBType.DB_NUMERIC; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/OidValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/OidValue.java index 2cee524859..60e51b6e13 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/OidValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/OidValue.java @@ -32,6 +32,7 @@ package com.cubrid.jsp.value; import com.cubrid.jsp.Server; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.data.SOID; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.jsp.jdbc.CUBRIDServerSideConnection; @@ -51,26 +52,14 @@ protected String getTypeName() { public OidValue(SOID oid) { oidValue = oid; + this.dbType = DBType.DB_OID; } public OidValue(CUBRIDOID oid) { byte[] bOid = oid.getOID(); oidValue = new SOID(bOid); this.oidObject = oid; - } - - public OidValue(SOID oid, int mode, int dbType) { - super(mode); - this.oidValue = oid; - this.dbType = dbType; - } - - public OidValue(CUBRIDOID oid, int mode, int dbType) { - super(mode); - this.oidObject = oid; - byte[] bOid = oid.getOID(); - oidValue = new SOID(bOid); - this.dbType = dbType; + this.dbType = DBType.DB_OID; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ResultSetValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ResultSetValue.java index 04f048d6cf..4582b54c0a 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ResultSetValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ResultSetValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.impl.SUConnection; import com.cubrid.jsp.jdbc.CUBRIDServerSideOutResultSet; import com.cubrid.jsp.jdbc.CUBRIDServerSideResultSet; @@ -48,12 +49,14 @@ protected String getTypeName() { public ResultSetValue(long queryId) { super(); this.queryId = queryId; + this.dbType = DBType.DB_RESULTSET; } public ResultSetValue(ResultSet rset) { super(); this.rset = rset; this.queryId = ((CUBRIDServerSideResultSet) rset).getQueryId(); + this.dbType = DBType.DB_RESULTSET; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/SetValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/SetValue.java index 15050272d9..0db8940b63 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/SetValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/SetValue.java @@ -31,6 +31,8 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; +import com.cubrid.jsp.exception.ExecuteException; import com.cubrid.jsp.exception.TypeMismatchException; import cubrid.sql.CUBRIDOID; import java.math.BigDecimal; @@ -44,72 +46,92 @@ protected String getTypeName() { return TYPE_NAME_SET; } - private Object[] values; + private Value[] values; + private Object[] objects; public SetValue(Value[] args) throws TypeMismatchException { super(); - values = toObjectArray(args); - } - - public SetValue(Value[] args, int mode, int dbType) throws TypeMismatchException { - super(mode); - values = toObjectArray(args); - this.dbType = dbType; - } - - public SetValue(Object[] objects) { - this.values = objects; + this.values = args; + this.objects = toJavaObjectArray(args); + this.dbType = DBType.DB_SET; + } + + public SetValue(Object[] objects) throws TypeMismatchException { + this.objects = objects; + setValuesFromObjects(); + } + + private void setValuesFromObjects() throws TypeMismatchException { + if (objects != null) { + this.values = new Value[objects.length]; + for (int i = 0; i < objects.length; i++) { + try { + this.values[i] = ValueUtilities.createValueFrom(objects[i]); + } catch (ExecuteException e) { + this.values[i] = new NullValue(); + assert false; // This should never happen + } + } + } + this.dbType = DBType.DB_SET; } - public SetValue(byte[] objects) { + public SetValue(byte[] objects) throws TypeMismatchException { Object[] array = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { array[i] = new Byte(objects[i]); } - this.values = array; + this.objects = array; + this.dbType = DBType.DB_SET; + setValuesFromObjects(); } - public SetValue(short[] objects) { + public SetValue(short[] objects) throws TypeMismatchException { Object[] array = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { array[i] = new Short(objects[i]); } - this.values = array; + this.objects = array; + setValuesFromObjects(); } - public SetValue(int[] objects) { + public SetValue(int[] objects) throws TypeMismatchException { Object[] array = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { array[i] = new Integer(objects[i]); } - this.values = array; + this.objects = array; + setValuesFromObjects(); } - public SetValue(long[] objects) { + public SetValue(long[] objects) throws TypeMismatchException { Object[] array = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { array[i] = new Long(objects[i]); } - this.values = array; + this.objects = array; + setValuesFromObjects(); } - public SetValue(float[] objects) { + public SetValue(float[] objects) throws TypeMismatchException { Object[] array = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { array[i] = new Float(objects[i]); } - this.values = array; + this.objects = array; + setValuesFromObjects(); } - public SetValue(double[] objects) { + public SetValue(double[] objects) throws TypeMismatchException { Object[] array = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { array[i] = new Double(objects[i]); } - this.values = array; + this.objects = array; + setValuesFromObjects(); } - private Object[] toObjectArray(Value[] args) throws TypeMismatchException { + private Object[] toJavaObjectArray(Value[] args) throws TypeMismatchException { Object[] array = new Object[args.length]; for (int i = 0; i < args.length; i++) { @@ -118,14 +140,18 @@ private Object[] toObjectArray(Value[] args) throws TypeMismatchException { return array; } + public Value[] toValueArray() throws TypeMismatchException { + return values; + } + @Override public Object[] toObjectArray() throws TypeMismatchException { - return values; + return objects; } @Override public Object toObject() throws TypeMismatchException { - return values; + return objects; } @Override @@ -133,13 +159,13 @@ public String toString() { StringBuffer buf = new StringBuffer(); buf.append("{"); - for (int i = 0; i < values.length; i++) { - if (values[i] == null) { + for (int i = 0; i < objects.length; i++) { + if (objects[i] == null) { buf.append("null"); } else { - buf.append(values[i].toString()); + buf.append(objects[i].toString()); } - if (i < values.length - 1) { + if (i < objects.length - 1) { buf.append(", "); } } @@ -149,190 +175,190 @@ public String toString() { @Override public byte[] toByteArray() throws TypeMismatchException { - byte[] array = new byte[values.length]; + byte[] array = new byte[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = ((Byte) values[i]).byteValue(); + for (int i = 0; i < objects.length; i++) { + array[i] = ((Byte) objects[i]).byteValue(); } return array; } @Override public short[] toShortArray() throws TypeMismatchException { - short[] array = new short[values.length]; + short[] array = new short[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = ((Short) values[i]).shortValue(); + for (int i = 0; i < objects.length; i++) { + array[i] = ((Short) objects[i]).shortValue(); } return array; } @Override public int[] toIntegerArray() throws TypeMismatchException { - int[] array = new int[values.length]; + int[] array = new int[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = ((Integer) values[i]).intValue(); + for (int i = 0; i < objects.length; i++) { + array[i] = ((Integer) objects[i]).intValue(); } return array; } @Override public long[] toLongArray() throws TypeMismatchException { - long[] array = new long[values.length]; + long[] array = new long[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = ((Long) values[i]).longValue(); + for (int i = 0; i < objects.length; i++) { + array[i] = ((Long) objects[i]).longValue(); } return array; } @Override public float[] toFloatArray() throws TypeMismatchException { - float[] array = new float[values.length]; + float[] array = new float[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = ((Float) values[i]).floatValue(); + for (int i = 0; i < objects.length; i++) { + array[i] = ((Float) objects[i]).floatValue(); } return array; } @Override public double[] toDoubleArray() throws TypeMismatchException { - double[] array = new double[values.length]; + double[] array = new double[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = ((Double) values[i]).doubleValue(); + for (int i = 0; i < objects.length; i++) { + array[i] = ((Double) objects[i]).doubleValue(); } return array; } @Override public BigDecimal[] toBigDecimalArray() throws TypeMismatchException { - BigDecimal[] array = new BigDecimal[values.length]; + BigDecimal[] array = new BigDecimal[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (BigDecimal) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (BigDecimal) objects[i]; } return array; } @Override public Date[] toDateArray() throws TypeMismatchException { - Date[] array = new Date[values.length]; + Date[] array = new Date[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Date) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Date) objects[i]; } return array; } @Override public Time[] toTimeArray() throws TypeMismatchException { - Time[] array = new Time[values.length]; + Time[] array = new Time[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Time) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Time) objects[i]; } return array; } @Override public Timestamp[] toTimestampArray() throws TypeMismatchException { - Timestamp[] array = new Timestamp[values.length]; + Timestamp[] array = new Timestamp[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Timestamp) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Timestamp) objects[i]; } return array; } @Override public Timestamp[] toDatetimeArray() throws TypeMismatchException { - Timestamp[] array = new Timestamp[values.length]; + Timestamp[] array = new Timestamp[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Timestamp) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Timestamp) objects[i]; } return array; } @Override public String[] toStringArray() throws TypeMismatchException { - String[] array = new String[values.length]; + String[] array = new String[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (String) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (String) objects[i]; } return array; } @Override public Byte[] toByteObjArray() throws TypeMismatchException { - Byte[] array = new Byte[values.length]; + Byte[] array = new Byte[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Byte) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Byte) objects[i]; } return array; } @Override public Double[] toDoubleObjArray() throws TypeMismatchException { - Double[] array = new Double[values.length]; + Double[] array = new Double[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Double) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Double) objects[i]; } return array; } @Override public Float[] toFloatObjArray() throws TypeMismatchException { - Float[] array = new Float[values.length]; + Float[] array = new Float[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Float) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Float) objects[i]; } return array; } @Override public Integer[] toIntegerObjArray() throws TypeMismatchException { - Integer[] array = new Integer[values.length]; + Integer[] array = new Integer[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Integer) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Integer) objects[i]; } return array; } @Override public Long[] toLongObjArray() throws TypeMismatchException { - Long[] array = new Long[values.length]; + Long[] array = new Long[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Long) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Long) objects[i]; } return array; } @Override public Short[] toShortObjArray() throws TypeMismatchException { - Short[] array = new Short[values.length]; + Short[] array = new Short[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (Short) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (Short) objects[i]; } return array; } @Override public CUBRIDOID[] toOidArray() throws TypeMismatchException { - CUBRIDOID[] array = new CUBRIDOID[values.length]; + CUBRIDOID[] array = new CUBRIDOID[objects.length]; - for (int i = 0; i < values.length; i++) { - array[i] = (CUBRIDOID) values[i]; + for (int i = 0; i < objects.length; i++) { + array[i] = (CUBRIDOID) objects[i]; } return array; } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ShortValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ShortValue.java index 5e3a5cb55a..dcc8de8df4 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ShortValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ShortValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.math.BigDecimal; @@ -48,12 +49,7 @@ protected String getTypeName() { public ShortValue(short value) { super(); this.value = value; - } - - public ShortValue(short value, int mode, int dbType) { - super(mode); - this.value = value; - this.dbType = dbType; + this.dbType = DBType.DB_SHORT; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/StringValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/StringValue.java index cc29c39221..7e553de145 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/StringValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/StringValue.java @@ -31,8 +31,12 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.Server; +import com.cubrid.jsp.SysParam; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; +import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.sql.Date; import java.sql.Time; @@ -44,111 +48,129 @@ protected String getTypeName() { return TYPE_NAME_STRING; } - private String value; + private byte[] primitiveValue; - public StringValue(String value) { + public StringValue(byte[] value, int codeset) { super(); - this.value = value; + this.primitiveValue = value; + this.codeset = codeset; + this.resolved = null; + this.dbType = DBType.DB_STRING; + } + + public StringValue(byte[] value) { + this(value, Server.getConfig().getServerCodesetId()); } - public StringValue(String value, int mode, int dbType) { - super(mode); - this.value = value; - this.dbType = dbType; + public StringValue(String value) { + this(value.getBytes(Server.getConfig().getServerCharset())); } @Override public byte toByte() throws TypeMismatchException { - return SpLib.convStringToByte(value); + return SpLib.convStringToByte(toString()); + } + + @Override + public byte[] toByteArray() throws TypeMismatchException { + return primitiveValue; } @Override public short toShort() throws TypeMismatchException { - return SpLib.convStringToShort(value); + return SpLib.convStringToShort(toString()); } @Override public int toInt() throws TypeMismatchException { - return SpLib.convStringToInt(value); + return SpLib.convStringToInt(toString()); } @Override public long toLong() throws TypeMismatchException { - return SpLib.convStringToBigint(value); + return SpLib.convStringToBigint(toString()); } @Override public float toFloat() throws TypeMismatchException { - return SpLib.convStringToFloat(value); + return SpLib.convStringToFloat(toString()); } @Override public double toDouble() throws TypeMismatchException { - return SpLib.convStringToDouble(value); + return SpLib.convStringToDouble(toString()); } @Override public Byte toByteObject() throws TypeMismatchException { - return SpLib.convStringToByte(value); + return SpLib.convStringToByte(toString()); } @Override public Short toShortObject() throws TypeMismatchException { - return SpLib.convStringToShort(value); + return SpLib.convStringToShort(toString()); } @Override public Integer toIntegerObject() throws TypeMismatchException { - return SpLib.convStringToInt(value); + return SpLib.convStringToInt(toString()); } @Override public Long toLongObject() throws TypeMismatchException { - return SpLib.convStringToBigint(value); + return SpLib.convStringToBigint(toString()); } @Override public Float toFloatObject() throws TypeMismatchException { - return SpLib.convStringToFloat(value); + return SpLib.convStringToFloat(toString()); } @Override public Double toDoubleObject() throws TypeMismatchException { - return SpLib.convStringToDouble(value); + return SpLib.convStringToDouble(toString()); } @Override public Date toDate() throws TypeMismatchException { - return SpLib.convStringToDate(value); + return SpLib.convStringToDate(toString()); } @Override public Time toTime() throws TypeMismatchException { - return SpLib.convStringToTime(value); + return SpLib.convStringToTime(toString()); } @Override public Timestamp toTimestamp() throws TypeMismatchException { - return SpLib.convStringToTimestamp(value); + return SpLib.convStringToTimestamp(toString()); } @Override public Timestamp toDatetime() throws TypeMismatchException { - return SpLib.convStringToDatetime(value); + return SpLib.convStringToDatetime(toString()); } @Override public BigDecimal toBigDecimal() throws TypeMismatchException { - return SpLib.convStringToNumeric(value); + return SpLib.convStringToNumeric(toString()); } @Override public Object toObject() throws TypeMismatchException { - return value; + return toString(); } @Override public String toString() { - return value; + if (resolved == null) { + try { + resolved = new String(primitiveValue, SysParam.getCodesetString(this.codeset)); + } catch (UnsupportedEncodingException e) { + // just return null + Server.log(e); + } + } + return (String) resolved; } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimeValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimeValue.java index ac74140133..74df731983 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimeValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimeValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.sql.Time; @@ -51,20 +52,12 @@ public TimeValue(int hour, int min, int sec) { cal.set(Calendar.MILLISECOND, 0); this.time = new Time(cal.getTimeInMillis()); - } - - public TimeValue(int hour, int min, int sec, int mode, int dbType) { - super(mode); - Calendar cal = Calendar.getInstance(); - cal.set(0, 0, 0, hour, min, sec); - cal.set(Calendar.MILLISECOND, 0); - - this.time = new Time(cal.getTimeInMillis()); - this.dbType = dbType; + this.dbType = DBType.DB_TIME; } public TimeValue(Time time) { this.time = time; + this.dbType = DBType.DB_TIME; assert time.getTime() % 1000L == 0; } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimestampValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimestampValue.java index 9757907df4..25e20d899c 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimestampValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/TimestampValue.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.plcsql.predefined.sp.SpLib; import java.sql.Date; @@ -54,33 +55,19 @@ public TimestampValue(int year, int mon, int day, int hour, int min, int sec) cal.set(Calendar.MILLISECOND, 0); this.timestamp = new Timestamp(cal.getTimeInMillis()); + this.dbType = DBType.DB_TIMESTAMP; if (SpLib.checkTimestamp(timestamp) == null) { throw new TypeMismatchException("invalid Timestamp " + timestamp); } } - public TimestampValue( - int year, int mon, int day, int hour, int min, int sec, int mode, int dbType) - throws TypeMismatchException { - super(mode); - Calendar cal = Calendar.getInstance(); - cal.clear(); - cal.set(year, mon, day, hour, min, sec); - cal.set(Calendar.MILLISECOND, 0); - - this.timestamp = new Timestamp(cal.getTimeInMillis()); - if (SpLib.checkTimestamp(timestamp) == null) { - throw new TypeMismatchException("invalid Timestamp " + timestamp); - } - this.dbType = dbType; - } - public TimestampValue(Timestamp timestamp) throws TypeMismatchException { if (timestamp != null && (timestamp.getTime() % 1000L != 0L || SpLib.checkTimestamp(timestamp) == null)) { throw new TypeMismatchException("invalid Timestamp " + timestamp); } this.timestamp = timestamp; + this.dbType = DBType.DB_TIMESTAMP; } @Override diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/Value.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/Value.java index 543f230e07..438ccbeb2c 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/Value.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/Value.java @@ -31,6 +31,7 @@ package com.cubrid.jsp.value; +import com.cubrid.jsp.Server; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.jsp.impl.SUConnection; import cubrid.sql.CUBRIDOID; @@ -48,13 +49,11 @@ public abstract class Value { protected int mode; protected Object resolved; protected int dbType; + protected int codeset; public Value() { this.mode = IN; - } - - public Value(int mode) { - this.mode = mode; + this.codeset = Server.getConfig().getServerCodesetId(); } public void setMode(int mode) { @@ -329,6 +328,10 @@ public void setDbType(int type) { dbType = type; } + public int getCodeSet() { + return codeset; + } + // ----------------------------------------------------- private String getCastErrMsg(String targetType) { diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ValueUtilities.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ValueUtilities.java index dae02f629e..e390816ffc 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ValueUtilities.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ValueUtilities.java @@ -32,7 +32,11 @@ package com.cubrid.jsp.value; import com.cubrid.jsp.data.DBType; +import com.cubrid.jsp.exception.ExecuteException; import com.cubrid.jsp.exception.TypeMismatchException; +import cubrid.sql.CUBRIDOID; +import java.math.BigDecimal; +import java.sql.ResultSet; public class ValueUtilities { public static Object resolveValue(int dbType, Value value) throws TypeMismatchException { @@ -92,4 +96,61 @@ public static Object resolveValue(int dbType, Value value) throws TypeMismatchEx } return resolvedResult; } + + public static Value createValueFrom(Object o) throws TypeMismatchException, ExecuteException { + Value val = null; + + if (o == null) { + val = new NullValue(); + } else if (o instanceof Boolean) { + val = new BooleanValue(((Boolean) o).booleanValue()); + } else if (o instanceof Byte) { + val = new ByteValue(((Byte) o).byteValue()); + } else if (o instanceof Short) { + val = new ShortValue(((Short) o).shortValue()); + } else if (o instanceof Integer) { + val = new IntValue(((Integer) o).intValue()); + } else if (o instanceof Long) { + val = new LongValue(((Long) o).longValue()); + } else if (o instanceof Float) { + val = new FloatValue(((Float) o).floatValue()); + } else if (o instanceof Double) { + val = new DoubleValue(((Double) o).doubleValue()); + } else if (o instanceof BigDecimal) { + val = new NumericValue(((BigDecimal) o)); + } else if (o instanceof String) { + val = new StringValue((String) o); + } else if (o instanceof java.sql.Date) { + val = new DateValue((java.sql.Date) o); + } else if (o instanceof java.sql.Time) { + val = new TimeValue((java.sql.Time) o); + } else if (o instanceof java.sql.Timestamp) { + val = + new DatetimeValue( + (java.sql.Timestamp) + o); // DatetimeValue allows more values than TimestampValue + } else if (o instanceof CUBRIDOID) { + val = new OidValue((CUBRIDOID) o); + } else if (o instanceof ResultSet) { + val = new ResultSetValue((ResultSet) o); + } else if (o instanceof byte[]) { + val = new StringValue((byte[]) o); + } else if (o instanceof short[]) { + val = new SetValue((short[]) o); + } else if (o instanceof int[]) { + val = new SetValue((int[]) o); + } else if (o instanceof long[]) { + val = new SetValue((long[]) o); + } else if (o instanceof float[]) { + val = new SetValue((float[]) o); + } else if (o instanceof double[]) { + val = new SetValue((double[]) o); + } else if (o instanceof Object[]) { + val = new SetValue((Object[]) o); + } else { + throw new ExecuteException("Not supported data type: '" + o.getClass().getName() + "'"); + } + + return val; + } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Misc.java b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Misc.java index 4666596881..a8c5ced44f 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Misc.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Misc.java @@ -38,6 +38,7 @@ import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.TerminalNode; public class Misc { @@ -91,6 +92,17 @@ public static String detachPkgName(String routineName) { return idx >= 0 ? routineName.substring(idx + 1) : routineName; } + public static int[] getLineColumnOf(TerminalNode node) { + if (node == null) { + return UNKNOWN_LINE_COLUMN; + } + + Token start = node.getSymbol(); + assert start != null; + + return new int[] {start.getLine(), start.getCharPositionInLine() + 1}; + } + public static int[] getLineColumnOf(ParserRuleContext ctx) { if (ctx == null) { return UNKNOWN_LINE_COLUMN; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ParseTreeConverter.java b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ParseTreeConverter.java index 46ed3aeb40..4d51c5862a 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ParseTreeConverter.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ParseTreeConverter.java @@ -36,13 +36,12 @@ import com.cubrid.jsp.data.ColumnInfo; import com.cubrid.jsp.data.DBType; import com.cubrid.jsp.value.DateTimeParser; +import com.cubrid.plcsql.compiler.antlrgen.PlcParser.Create_routineContext; import com.cubrid.plcsql.compiler.antlrgen.PlcParserBaseVisitor; import com.cubrid.plcsql.compiler.antlrgen.StaticSqlWithRecordsLexer; import com.cubrid.plcsql.compiler.antlrgen.StaticSqlWithRecordsParser; import com.cubrid.plcsql.compiler.ast.*; -import com.cubrid.plcsql.compiler.error.SemanticError; -import com.cubrid.plcsql.compiler.error.SyntaxError; -import com.cubrid.plcsql.compiler.error.UndeclaredId; +import com.cubrid.plcsql.compiler.error.*; import com.cubrid.plcsql.compiler.serverapi.*; import com.cubrid.plcsql.compiler.type.*; import java.math.BigDecimal; @@ -70,8 +69,10 @@ public class ParseTreeConverter extends PlcParserBaseVisitor { public final SymbolStack symbolStack = new SymbolStack(); - public ParseTreeConverter(InstanceStore iStore) { + public ParseTreeConverter(InstanceStore iStore, String spOwner, String spRevision) { this.iStore = iStore; + this.spOwner = Misc.getNormalizedText(spOwner); + this.spRevision = spRevision; } public void askServerSemanticQuestions() { @@ -231,10 +232,9 @@ public AstNode visitSql_script(Sql_scriptContext ctx) { @Override public Unit visitCreate_routine(Create_routineContext ctx) { - previsitRoutine_definition(ctx.routine_definition(), null); DeclRoutine decl = visitRoutine_definition(ctx.routine_definition()); - return new Unit(ctx, autonomousTransaction, connectionRequired, imports, decl); + return new Unit(ctx, autonomousTransaction, connectionRequired, decl, spRevision); } @Override @@ -244,7 +244,7 @@ public NodeList visitParameter_list(Parameter_listContext ctx) { return EMPTY_PARAMS; } - boolean ofTopLevel = symbolStack.getCurrentScope().level == 2; + boolean ofTopLevel = symbolStack.getCurrentScope().level == (SymbolStack.LEVEL_MAIN + 1); NodeList ret = new NodeList<>(); if (ofTopLevel) { for (ParameterContext pc : ctx.parameter()) { @@ -947,9 +947,31 @@ public Expr visitRecord_field(Record_fieldContext ctx) { @Override public Expr visitFunction_call(Function_callContext ctx) { - String name = Misc.getNormalizedText(ctx.function_name()); + String name = Misc.getNormalizedText(ctx.func_call_name().name); NodeList args = visitFunction_argument(ctx.function_argument()); + if (ctx.func_call_name().owner != null) { + // This has an owner name + + String owner = Misc.getNormalizedText(ctx.func_call_name().owner); + if (owner.equals(spOwner) && name.equals(spName) && isSpFunc) { + + // OK: recursive call of the stored function being defined + // Note that owner name is unused afterwards. + } else { + + // This has an owner name and the target function is not the SP being defined + // Take this as a global function call. + connectionRequired = true; + + String uniqName = owner + '.' + name; + ExprGlobalFuncCall ret = new ExprGlobalFuncCall(ctx, uniqName, args); + semanticQuestions.put(ret, new ServerAPI.FunctionSignature(uniqName)); + + return ret; // done + } + } + DeclFunc decl = symbolStack.getDeclFunc(name); if (decl == null) { @@ -1247,17 +1269,17 @@ public AstNode visitCursor_definition(Cursor_definitionContext ctx) { @Override public DeclRoutine visitRoutine_definition(Routine_definitionContext ctx) { - if (ctx.LANGUAGE() != null && symbolStack.getCurrentScope().level > 1) { + if (ctx.LANGUAGE() != null + && symbolStack.getCurrentScope().level > SymbolStack.LEVEL_MAIN) { int[] lineColumn = Misc.getLineColumnOf(ctx); throw new SyntaxError( lineColumn[0], lineColumn[1], "illegal keywords LANGUAGE PLCSQL for a local procedure/function"); } + String name = Misc.getNormalizedText(ctx.routine_uniq_name().name); - String name = Misc.getNormalizedText(ctx.identifier()); boolean isFunction = (ctx.PROCEDURE() == null); - symbolStack.pushSymbolTable( name, isFunction ? Misc.RoutineType.FUNC : Misc.RoutineType.PROC); @@ -1418,7 +1440,7 @@ public Expr visitIdentifier(IdentifierContext ctx) { if (idUsedInCurrentDeclPart != null) { idUsedInCurrentDeclPart.put( - name, new UseAndDeclLevel(ctx, symbolStack.LEVEL_PREDEFINED)); + name, new UseAndDeclLevel(ctx, SymbolStack.LEVEL_PREDEFINED)); } // this is possibly a global function call @@ -1489,6 +1511,32 @@ public Expr visitIdentifier(IdentifierContext ctx) { throw new RuntimeException("unreachable"); } + @Override + public Expr visitKeyword_builtin_func(Keyword_builtin_funcContext ctx) { + String name = Misc.getNormalizedText(ctx); + + Decl decl = symbolStack.getDeclForIdExpr(name); + assert decl != null; + Scope scope = symbolStack.getCurrentScope(); + if (idUsedInCurrentDeclPart != null && decl.scope.level < scope.level) { + idUsedInCurrentDeclPart.put(name, new UseAndDeclLevel(ctx, decl.scope.level)); + } + + if (decl instanceof DeclId) { + return new ExprId(ctx, name, scope, (DeclId) decl); + } else if (decl instanceof DeclFunc) { + if (decl.scope().level == SymbolStack.LEVEL_PREDEFINED) { + connectionRequired = true; + return new ExprBuiltinFuncCall(ctx, name, EMPTY_ARGS); + } else { + return new ExprLocalFuncCall(ctx, name, EMPTY_ARGS, scope, (DeclFunc) decl); + } + } + + assert false : "unreachable"; + throw new RuntimeException("unreachable"); + } + @Override public Stmt visitContinue_statement(Continue_statementContext ctx) { @@ -2107,16 +2155,41 @@ public StmtRollback visitRollback_statement(Rollback_statementContext ctx) { @Override public AstNode visitProcedure_call(Procedure_callContext ctx) { - String name = Misc.getNormalizedText(ctx.routine_name()); - if (ctx.DBMS_OUTPUT() != null && dbmsOutputProc.contains(name)) { + String name = Misc.getNormalizedText(ctx.proc_call_name().name); + NodeList args = visitFunction_argument(ctx.function_argument()); + + if (ctx.proc_call_name().owner != null) { + // This has an owner name + + String owner = Misc.getNormalizedText(ctx.proc_call_name().owner); + if (owner.equals(spOwner) + && ctx.proc_call_name().DBMS_OUTPUT() == null + && name.equals(spName) + && !isSpFunc) { + + // OK: recursive call of the stored procedure being defined + // Note that owner name is unused afterwards. + } else { + + // This has an owner name and the target procedure is not the SP being defined + // Take this as a global procedure call. + connectionRequired = true; + + String uniqName = owner + '.' + name; + StmtGlobalProcCall ret = new StmtGlobalProcCall(ctx, uniqName, args); + semanticQuestions.put(ret, new ServerAPI.ProcedureSignature(uniqName)); + + return ret; // done + } + } + + if (ctx.proc_call_name().DBMS_OUTPUT() != null && dbmsOutputProc.contains(name)) { // DBMS_OUTPUT is not an actual package but just a syntactic "ornament" to ease // migration from Oracle. // NOTE: users cannot define a procedure of this name because of '$' name = "DBMS_OUTPUT$" + name; } - NodeList args = visitFunction_argument(ctx.function_argument()); - DeclProc decl = symbolStack.getDeclProc(name); if (decl == null) { @@ -2361,7 +2434,11 @@ private static class UseAndDeclLevel { private final LinkedHashMap semanticQuestions = new LinkedHashMap<>(); - private final Set imports = new TreeSet<>(); + private final String spOwner; + private final String spRevision; + + private String spName; + private boolean isSpFunc; private int exHandlerDepth; @@ -2457,7 +2534,40 @@ private void previsitCursor_definition(Cursor_definitionContext ctx) { private void previsitRoutine_definition( Routine_definitionContext ctx, Map store) { - String name = Misc.getNormalizedText(ctx.identifier()); + String name = Misc.getNormalizedText(ctx.routine_uniq_name().name); + + if (symbolStack.getCurrentScope().level > SymbolStack.LEVEL_MAIN) { + + // local procedure/function + + if (ctx.LANGUAGE() != null) { + throw new SemanticError( + Misc.getLineColumnOf(ctx.LANGUAGE()), // s083 + "illegal keywords LANGUAGE PLCSQL for a local procedure/function"); + } + if (ctx.authid_spec() != null) { + throw new SemanticError( + Misc.getLineColumnOf(ctx.LANGUAGE()), // s084 + "illegal keyword AUTHID for a local procedure/function"); + } + if (ctx.routine_uniq_name().owner != null) { + throw new SemanticError( + Misc.getLineColumnOf(ctx.routine_uniq_name().owner), // s085 + "owner specification is not allowed for local procedures/functions"); + } + } else { + + // SP being defined + + assert symbolStack.getCurrentScope().level == SymbolStack.LEVEL_MAIN; + spName = name; + isSpFunc = (ctx.PROCEDURE() == null); + } + + if (ctx.routine_uniq_name().owner != null) { + String owner = Misc.getNormalizedText(ctx.routine_uniq_name().owner); + assert owner.equals(spOwner); + } // push a temporary symbol table, in order not to corrupt the current symbol table with the // parameters diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/PlcsqlCompilerMain.java b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/PlcsqlCompilerMain.java index b986c75b60..345847de86 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/PlcsqlCompilerMain.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/PlcsqlCompilerMain.java @@ -46,7 +46,16 @@ public class PlcsqlCompilerMain { - public static CompileInfo compilePLCSQL(String in, boolean verbose) { + // temporary code - the owner and revision strings will come from the server + private static int revision = 1; + + public static CompileInfo compilePLCSQL(String in, String owner, boolean verbose) { + return compilePLCSQL(in, verbose, owner, Integer.toString(revision++)); + } + // end of temporary code + + public static CompileInfo compilePLCSQL( + String in, boolean verbose, String owner, String revision) { // System.out.println("[TEMP] text to the compiler"); // System.out.println(in); @@ -54,7 +63,7 @@ public static CompileInfo compilePLCSQL(String in, boolean verbose) { int optionFlags = verbose ? OPT_VERBOSE : 0; CharStream input = CharStreams.fromString(in); try { - return compileInner(new InstanceStore(), input, optionFlags); + return compileInner(new InstanceStore(), input, optionFlags, owner, revision); } catch (SyntaxError e) { CompileInfo err = new CompileInfo(-1, e.line, e.column, e.getMessage()); return err; @@ -84,6 +93,15 @@ private static ParseTree parse( } PlcLexerEx lexer = new PlcLexerEx(input); + + LexerErrorIndicator lei = new LexerErrorIndicator(); + lexer.removeErrorListeners(); + lexer.addErrorListener(lei); + + if (lei.hasError) { + throw new SyntaxError(lei.line, lei.column, lei.msg); + } + CommonTokenStream tokens = new CommonTokenStream(lexer); PlcParser parser = new PlcParser(tokens); @@ -133,7 +151,11 @@ private static long logElapsedTime(StringBuilder logStore, String msg, long t0) } private static CompileInfo compileInner( - InstanceStore iStore, CharStream input, int optionFlags) { + InstanceStore iStore, + CharStream input, + int optionFlags, + String owner, + String revision) { boolean verbose = (optionFlags & OPT_VERBOSE) > 0; @@ -175,7 +197,7 @@ private static CompileInfo compileInner( // ------------------------------------------ // converting parse tree to AST - ParseTreeConverter converter = new ParseTreeConverter(iStore); + ParseTreeConverter converter = new ParseTreeConverter(iStore, owner, revision); Unit unit = (Unit) converter.visit(tree); if (verbose) { @@ -228,6 +250,31 @@ private static CompileInfo compileInner( return info; } + private static class LexerErrorIndicator extends BaseErrorListener { + + boolean hasError; + int line; + int column; + String msg; + + @Override + public void syntaxError( + Recognizer recognizer, + Object offendingSymbol, + int line, + int charPositionInLine, + String msg, + RecognitionException e) { + + if (msg.startsWith("token recognition error")) { + this.hasError = true; + this.line = line; + this.column = charPositionInLine + 1; // charPositionInLine starts from 0 + this.msg = msg; + } + } + } + private static class SyntaxErrorIndicator extends BaseErrorListener { boolean hasError; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Unit.java b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Unit.java index 101adc30a6..5f3c07a2d4 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Unit.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Unit.java @@ -32,7 +32,6 @@ import com.cubrid.plcsql.compiler.visitor.AstVisitor; import java.sql.*; -import java.util.Set; import org.antlr.v4.runtime.ParserRuleContext; public class Unit extends AstNode { @@ -44,23 +43,23 @@ public R accept(AstVisitor visitor) { public final boolean autonomousTransaction; public final boolean connectionRequired; - public final Set imports; public final DeclRoutine routine; + public final String revision; public Unit( ParserRuleContext ctx, boolean autonomousTransaction, boolean connectionRequired, - Set imports, - DeclRoutine routine) { + DeclRoutine routine, + String revision) { super(ctx); assert routine.scope.level == 1; this.autonomousTransaction = autonomousTransaction; this.connectionRequired = connectionRequired; - this.imports = imports; this.routine = routine; + this.revision = revision; } public String getJavaSignature() { @@ -95,25 +94,15 @@ public String getClassName() { if (className == null) { String kindStr = routine.isProcedure() ? "Proc" : "Func"; - className = String.format("%s_%s", kindStr, routine.name); + className = String.format("%s_%s_%s", kindStr, routine.name, revision); } return className; } - public String[] getImportsArray() { - if (imports.size() == 0) { - return new String[] {"// no imports"}; - } else { - return imports.toArray(dummyStrArr); - } - } - // ------------------------------------------ // Private // ------------------------------------------ - private static final String[] dummyStrArr = new String[0]; - private String className; } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeChar.java b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeChar.java index fb5ca0c0f0..e5101817ef 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeChar.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeChar.java @@ -34,7 +34,7 @@ public class TypeChar extends Type { - public static final int MAX_LEN = 2048; + public static final int MAX_LEN = 268435455; public final int length; diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/predefined/sp/SpLib.java b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/predefined/sp/SpLib.java index 2b1963d8bf..c33ea2ecb2 100644 --- a/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/predefined/sp/SpLib.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/plcsql/predefined/sp/SpLib.java @@ -31,6 +31,7 @@ package com.cubrid.plcsql.predefined.sp; import com.cubrid.jsp.Server; +import com.cubrid.jsp.SysParam; import com.cubrid.jsp.value.DateTimeParser; import com.cubrid.plcsql.builtin.DBMS_OUTPUT; import com.cubrid.plcsql.compiler.CoercionScheme; @@ -48,7 +49,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.ZoneOffset; +import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; @@ -701,7 +702,7 @@ public static Boolean opNot(Boolean l) { // is null @Operator(coercionScheme = CoercionScheme.ObjectOp) public static Boolean opIsNull(Object l) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -778,7 +779,7 @@ public static Double opNeg(Double l) { @Operator(coercionScheme = CoercionScheme.ArithOp) public static Object opNeg(Object l) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -853,7 +854,7 @@ public static Long opBitCompli(Long l) { @Operator(coercionScheme = CoercionScheme.IntArithOp) public static Object opBitCompli(Object l) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -940,7 +941,7 @@ public static Boolean opEq(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opEq(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -953,7 +954,7 @@ public static Boolean opEq(String l, String r) { } public static Boolean opEqChar(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1036,7 +1037,7 @@ public static Boolean opEqTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opEq(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1061,7 +1062,7 @@ public static Boolean opNullSafeEq(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opNullSafeEq(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1074,7 +1075,7 @@ public static Boolean opNullSafeEq(String l, String r) { } public static Boolean opNullSafeEqChar(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1169,7 +1170,7 @@ public static Boolean opNullSafeEqTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opNullSafeEq(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1197,7 +1198,7 @@ public static Boolean opNeq(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opNeq(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1284,7 +1285,7 @@ public static Boolean opNeqTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opNeq(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1310,7 +1311,7 @@ public static Boolean opLe(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opLe(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1323,7 +1324,7 @@ public static Boolean opLe(String l, String r) { } public static Boolean opLeChar(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1406,7 +1407,7 @@ public static Boolean opLeTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opLe(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1430,7 +1431,7 @@ public static Boolean opGe(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opGe(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1443,7 +1444,7 @@ public static Boolean opGe(String l, String r) { } public static Boolean opGeChar(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1526,7 +1527,7 @@ public static Boolean opGeTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opGe(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1550,7 +1551,7 @@ public static Boolean opLt(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opLt(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1563,7 +1564,7 @@ public static Boolean opLt(String l, String r) { } public static Boolean opLtChar(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1646,7 +1647,7 @@ public static Boolean opLtTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opLt(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1671,7 +1672,7 @@ public static Boolean opGt(Boolean l, Boolean r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opGt(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1684,7 +1685,7 @@ public static Boolean opGt(String l, String r) { } public static Boolean opGtChar(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1767,7 +1768,7 @@ public static Boolean opGtTimestamp(Timestamp l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.CompOp) public static Boolean opGt(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -1795,7 +1796,7 @@ public static Boolean opBetween(Boolean o, Boolean lower, Boolean upper) { @Operator(coercionScheme = CoercionScheme.NAryCompOp) public static Boolean opBetween(String o, String lower, String upper) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(o)) { o = null; } @@ -1814,7 +1815,7 @@ public static Boolean opBetween(String o, String lower, String upper) { } public static Boolean opBetweenChar(String o, String lower, String upper) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(o)) { o = null; } @@ -1929,7 +1930,7 @@ public static Boolean opBetweenTimestamp(Timestamp o, Timestamp lower, Timestamp @Operator(coercionScheme = CoercionScheme.NAryCompOp) public static Boolean opBetween(Object o, Object lower, Object upper) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(o)) { o = null; } @@ -1967,7 +1968,7 @@ public static Boolean opIn(String o, String... arr) { public static Boolean opInChar(String o, String... arr) { assert arr != null; - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(o)) { o = null; } @@ -1980,7 +1981,7 @@ public static Boolean opInChar(String o, String... arr) { boolean nullFound = false; for (String p : arr) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(p)) { p = null; } @@ -2085,7 +2086,7 @@ public static Boolean opInTimestamp(Timestamp o, Timestamp... arr) { public static Boolean opIn(Object o, Object... arr) { assert arr != null; - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(o)) { o = null; } @@ -2096,7 +2097,7 @@ public static Boolean opIn(Object o, Object... arr) { } boolean nullFound = false; for (Object p : arr) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(p)) { p = null; } @@ -2196,7 +2197,7 @@ public static Double opMult(Double l, Double r) { @Operator(coercionScheme = CoercionScheme.ArithOp) public static Object opMult(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -2222,7 +2223,7 @@ public static Object opDiv(Short l, Short r) { if (r.equals((short) 0)) { throw new ZERO_DIVIDE(); } - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_COMPAT_NUMBER_BEHAVIOR)) { return opDiv(BigDecimal.valueOf(l.longValue()), BigDecimal.valueOf(r.longValue())); } else { return (short) (l / r); @@ -2237,7 +2238,7 @@ public static Object opDiv(Integer l, Integer r) { if (r.equals(0)) { throw new ZERO_DIVIDE(); } - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_COMPAT_NUMBER_BEHAVIOR)) { return opDiv(BigDecimal.valueOf(l.longValue()), BigDecimal.valueOf(r.longValue())); } else { return l / r; @@ -2253,7 +2254,7 @@ public static Object opDiv(Long l, Long r) { throw new ZERO_DIVIDE(); } - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_COMPAT_NUMBER_BEHAVIOR)) { return opDiv(BigDecimal.valueOf(l), BigDecimal.valueOf(r)); } else { return l / r; @@ -2275,7 +2276,7 @@ public static BigDecimal opDiv(BigDecimal l, BigDecimal r) { int s2 = r.scale(); int scale; - if (Server.getSystemParameterBool(Server.SYS_PARAM_COMPAT_NUMERIC_DIVISION_SCALE)) { + if (Server.getSystemParameterBool(SysParam.COMPAT_NUMERIC_DIVISION_SCALE)) { scale = Math.max(s1, s2); } else { scale = Math.max(9, Math.max(s1, s2)); @@ -2324,7 +2325,7 @@ public static Double opDiv(Double l, Double r) { @Operator(coercionScheme = CoercionScheme.ArithOp) public static Object opDiv(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -2377,7 +2378,7 @@ public static Long opDivInt(Long l, Long r) { @Operator(coercionScheme = CoercionScheme.IntArithOp) public static Object opDivInt(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -2430,7 +2431,7 @@ public static Long opMod(Long l, Long r) { @Operator(coercionScheme = CoercionScheme.IntArithOp) public static Object opMod(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -2450,7 +2451,7 @@ public static Object opMod(Object l, Object r) { // + @Operator(coercionScheme = CoercionScheme.ArithOp) public static String opAdd(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (l == null) { l = EMPTY_STRING; } @@ -2644,7 +2645,7 @@ public static Timestamp opAddTimestamp(Long l, Timestamp r) { @Operator(coercionScheme = CoercionScheme.ArithOp) public static Object opAdd(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -2878,7 +2879,7 @@ public static Timestamp opSubtractTimestamp(Timestamp l, Long r) { @Operator(coercionScheme = CoercionScheme.ArithOp) public static Object opSubtract(Object l, Object r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(l)) { l = null; } @@ -2898,7 +2899,7 @@ public static Object opSubtract(Object l, Object r) { // || @Operator(coercionScheme = CoercionScheme.StringOp) public static String opConcat(String l, String r) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (l == null) { l = EMPTY_STRING; } @@ -3149,7 +3150,7 @@ public static String convTimestampToString(Timestamp e) { } Instant instant = Instant.ofEpochMilli(e.getTime()); - ZoneOffset timezone = Server.getSystemParameterTimezone(Server.SYS_PARAM_TIMEZONE); + ZoneId timezone = Server.getConfig().getTimeZone(); ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, timezone); return zdt.format(TIMESTAMP_FORMAT); } @@ -3202,7 +3203,7 @@ public static String convDoubleToString(Double e) { return null; } - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_COMPAT_NUMBER_BEHAVIOR)) { BigDecimal bd = new BigDecimal(e.doubleValue(), doubleToStringContext); return detachTrailingZeros(bd.toPlainString()); } else { @@ -3286,7 +3287,7 @@ public static String convFloatToString(Float e) { return null; } - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_COMPAT_NUMBER_BEHAVIOR)) { BigDecimal bd = new BigDecimal(e.doubleValue(), floatToStringContext); return detachTrailingZeros(bd.toPlainString()); } else { @@ -3361,7 +3362,7 @@ public static String convNumericToString(BigDecimal e) { return null; } - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_COMPAT_NUMBER_BEHAVIOR)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_COMPAT_NUMBER_BEHAVIOR)) { return detachTrailingZeros(e.toPlainString()); } else { return e.toString(); @@ -4275,7 +4276,7 @@ private static Boolean commonOpGt(Comparable l, Comparable r) { private static Boolean commonOpIn(Object o, Object... arr) { assert arr != null; - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(o)) { o = null; } @@ -4286,7 +4287,7 @@ private static Boolean commonOpIn(Object o, Object... arr) { } boolean nullFound = false; for (Object p : arr) { - if (Server.getSystemParameterBool(Server.SYS_PARAM_ORACLE_STYLE_EMPTY_STRING)) { + if (Server.getSystemParameterBool(SysParam.ORACLE_STYLE_EMPTY_STRING)) { if (EMPTY_STRING.equals(p)) { p = null; } diff --git a/sa/CMakeLists.txt b/sa/CMakeLists.txt index bd78136554..130822f842 100644 --- a/sa/CMakeLists.txt +++ b/sa/CMakeLists.txt @@ -98,6 +98,7 @@ set(BASE_SOURCES ${BASE_DIR}/pinnable_buffer.cpp ${BASE_DIR}/pinning.cpp ${BASE_DIR}/printer.cpp + ${BASE_DIR}/process_util.c ${BASE_DIR}/ini_parser.c ${BASE_DIR}/system_parameter.c ${BASE_DIR}/fault_injection.c @@ -184,6 +185,8 @@ set(CONNECTION_SOURCES ) set(COMMUNICATION_SOURCES + ${COMMUNICATION_DIR}/network_callback_cl.cpp + ${COMMUNICATION_DIR}/network_callback_sr.cpp ${COMMUNICATION_DIR}/network_interface_cl.c ${COMMUNICATION_DIR}/network_histogram.cpp ) @@ -343,35 +346,41 @@ set(OBJECT_HEADERS ) set(SP_SOURCES - ${SP_DIR}/jsp_cl.c - ${SP_DIR}/jsp_comm.c - ${SP_DIR}/jsp_file.c - ${SP_DIR}/jsp_sr.c - ) + ${SP_DIR}/jsp_cl.cpp + ${SP_DIR}/method_invoke_group.cpp + ${SP_DIR}/pl_connection.cpp + ${SP_DIR}/pl_compile_handler.cpp + ${SP_DIR}/pl_execution_stack_context.cpp + ${SP_DIR}/pl_executor.cpp + ${SP_DIR}/pl_query_cursor.cpp + ${SP_DIR}/pl_session.cpp + ${SP_DIR}/pl_signature.cpp + ${SP_DIR}/pl_comm.c + ${SP_DIR}/pl_file.c + ${SP_DIR}/pl_sr.cpp + ${SP_DIR}/pl_sr_jvm.cpp + ${SP_DIR}/sp_catalog.cpp + ${SP_DIR}/sp_code.cpp + ) + +set(SP_HEADERS + ${SP_DIR}/pl_connection.hpp + ${SP_DIR}/pl_execution_stack_context.hpp + ${SP_DIR}/pl_signature.hpp + ${SP_DIR}/pl_struct_compile.cpp +) set(METHOD_SOURCES ${METHOD_DIR}/method_callback.cpp - ${METHOD_DIR}/method_connection_cl.cpp - ${METHOD_DIR}/method_connection_sr.cpp - ${METHOD_DIR}/method_connection_java.cpp - ${METHOD_DIR}/method_connection_pool.cpp - ${METHOD_DIR}/method_compile_def.cpp - ${METHOD_DIR}/method_compile.cpp - ${METHOD_DIR}/method_def.cpp ${METHOD_DIR}/method_error.cpp ${METHOD_DIR}/method_scan.cpp - ${METHOD_DIR}/method_invoke_builtin.cpp - ${METHOD_DIR}/method_invoke_java.cpp ${METHOD_DIR}/method_struct_parameter_info.cpp ${METHOD_DIR}/method_struct_invoke.cpp ${METHOD_DIR}/method_struct_value.cpp ${METHOD_DIR}/method_struct_query.cpp ${METHOD_DIR}/method_struct_oid_info.cpp - ${METHOD_DIR}/method_invoke_group.cpp - ${METHOD_DIR}/method_runtime_context.cpp ${METHOD_DIR}/method_query_util.cpp ${METHOD_DIR}/method_query_handler.cpp - ${METHOD_DIR}/method_query_cursor.cpp ${METHOD_DIR}/method_oid_handler.cpp ${METHOD_DIR}/query_method.cpp ) @@ -634,6 +643,7 @@ add_library(cubridsa SHARED ${EXECUTABLE_SOURCES} ${HEAPLAYER_SOURCES} ${SP_SOURCES} + ${SP_HEADERS} ${METHOD_SOURCES} ${MONITOR_HEADERS} ${MONITOR_SOURCES} diff --git a/src/api/db_stub.c b/src/api/db_stub.c index 7fee17a7e2..7331dd7368 100644 --- a/src/api/db_stub.c +++ b/src/api/db_stub.c @@ -36,7 +36,7 @@ #include "system_parameter.h" #include "authenticate.h" #include "object_accessor.h" -#include "jsp_sr.h" +#include "pl_sr.h" #define API_PROGRAM_NAME "CUBRID C API" @@ -2708,7 +2708,7 @@ conn_restart_client (CI_CONN_STRUCTURE * pconn, const char *program, int print_v #if !defined(WINDOWS) #if defined(SA_MODE) && defined(LINUX) - if (!jsp_jvm_is_loaded ()) + if (!pl_jvm_is_loaded ()) { prev_sigfpe_handler = os_set_signal_handler (SIGFPE, sigfpe_handler); } diff --git a/src/base/error_code.h b/src/base/error_code.h index 114e687e1a..8edfe4e24a 100644 --- a/src/base/error_code.h +++ b/src/base/error_code.h @@ -1132,7 +1132,7 @@ #define ER_SP_INVALID_NAME -904 #define ER_SP_NETWORK_ERROR -905 #define ER_SP_INVAILD_JAVA_METHOD -906 -#define ER_SP_DROP_NOT_ALLOWED -907 +#define ER_SP_DROP_NOT_ALLOWED_PRIVILEGES -907 #define ER_SP_TOO_MANY_ARG_COUNT -908 #define ER_BO_MISSING_OR_INVALID_CATALOG -909 @@ -1738,12 +1738,19 @@ #define ER_SP_SERVER_CRASHED -1359 #define ER_SP_COMPILE_ERROR -1360 +#define ER_QPROC_RESULT_CACHE_INVALID -1361 + +#define ER_LOCALE_LANG_NOT_AVAILABLE -1362 +#define ER_SP_DROP_NOT_ALLOWED_SYSTEM_GENERATED -1363 +#define ER_SP_INVOKERS_RIGHTS_NOT_SUPPORTED -1364 + + +#define ER_AU_OWNER_ONLY_GRANT_PRIVILEGE -1365 + +#define ER_LAST_ERROR -1366 -#define ER_QPROC_RESULT_CACHE_INVALID -1361 -#define ER_LOCALE_LANG_NOT_AVAILABLE -1362 -#define ER_LAST_ERROR -1363 /* * CAUTION! diff --git a/src/base/memory_alloc.c b/src/base/memory_alloc.c index ce814b47c0..f9ab4fe0a5 100644 --- a/src/base/memory_alloc.c +++ b/src/base/memory_alloc.c @@ -718,6 +718,37 @@ db_private_strdup (THREAD_ENTRY * thrd, const char *s) return cp; } + +/* + * db_private_strndup () - duplicate string with size. memory for the duplicated + * string is obtanined by db_private_alloc + * return: pointer to duplicated str + * thrd(in): thread conext if it is server, otherwise NULL + * s(in): source string + * size(in): source string size + */ +char * +db_private_strndup (THREAD_ENTRY * thrd, const char *s, size_t size) +{ + char *cp; + + /* fast return */ + if (s == NULL) + { + return NULL; + } + + cp = (char *) db_private_alloc (thrd, size + 1); + + if (cp != NULL) + { + memcpy (cp, s, size); + cp[size] = '\0'; + } + + return cp; +} + /* * db_private_free () - call free function for current private heap * return: diff --git a/src/base/memory_alloc.h b/src/base/memory_alloc.h index 75ee1d0ad1..e5386bd109 100644 --- a/src/base/memory_alloc.h +++ b/src/base/memory_alloc.h @@ -278,6 +278,7 @@ extern "C" { #endif extern char *db_private_strdup (THREAD_ENTRY * thrd, const char *s); + extern char *db_private_strndup (THREAD_ENTRY * thrd, const char *s, size_t size); #ifdef __cplusplus } #endif diff --git a/src/base/message_catalog.h b/src/base/message_catalog.h index caf127b7bd..5e85f57ccb 100644 --- a/src/base/message_catalog.h +++ b/src/base/message_catalog.h @@ -52,6 +52,7 @@ #define MSGCAT_SET_LOCK 14 #define MSGCAT_SET_IO 15 #define MSGCAT_SET_LOG 16 +#define MSGCAT_SET_GLOSSARY 17 /* Message id in the set MSGCAT_SET_GENERAL */ #define MSGCAT_GENERAL_DATABASE_INIT 1 diff --git a/src/base/msgcat_glossary.hpp b/src/base/msgcat_glossary.hpp new file mode 100644 index 0000000000..a3b3561a54 --- /dev/null +++ b/src/base/msgcat_glossary.hpp @@ -0,0 +1,44 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +// +// Message catalog set for glossary +// + +#ifndef _MSGCAT_SET_GLOSSARY_HPP_ +#define _MSGCAT_SET_GLOSSARY_HPP_ + +#include "message_catalog.h" + +/* + * Message id in the set MSGCAT_SET_GLOSSARY + * in the message catalog MSGCAT_CATALOG_CUBRID (file cubrid.msg). + */ + +#define MSGCAT_GLOSSARY_START 1 +#define MSGCAT_GLOSSARY_CLASS 1 +#define MSGCAT_GLOSSARY_TRIGGER 2 +#define MSGCAT_GLOSSARY_SERIAL 3 +#define MSGCAT_GLOSSARY_SERVER 4 +#define MSGCAT_GLOSSARY_SYNONYM 5 +#define MSGCAT_GLOSSARY_PROCEDURE 6 + +#define MSGCAT_GET_GLOSSARY_MSG(id) \ + msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_GLOSSARY, id) + +#endif // _MSGCAT_SET_GLOSSARY_HPP_ diff --git a/src/base/object_representation.h b/src/base/object_representation.h index c5b0fdb8fe..102b6c6210 100644 --- a/src/base/object_representation.h +++ b/src/base/object_representation.h @@ -1111,7 +1111,6 @@ extern char *or_unpack_setref (char *ptr, DB_SET ** ref); extern char *or_pack_listid (char *ptr, void *listid); extern char *or_pack_lock (char *ptr, LOCK lock); extern char *or_pack_set_header (char *buf, DB_TYPE stype, DB_TYPE etype, int bound_bits, int size); -extern char *or_pack_method_sig_list (char *ptr, void *method_sig_list); extern char *or_pack_set_node (char *ptr, void *set_node); #if defined(ENABLE_UNUSED_FUNCTION) extern char *or_pack_elo (char *ptr, void *elo); @@ -1187,7 +1186,6 @@ extern int or_packed_varbit_length (int bitlen); * this file (it references DB_TYPE) */ extern int or_listid_length (void *listid); -extern int or_method_sig_list_length (void *method_sig_list_ptr); extern int or_set_node_length (void *set_node_ptr); #if defined(ENABLE_UNUSED_FUNCTION) extern int or_elo_length (void *elo_ptr); diff --git a/src/base/packer.cpp b/src/base/packer.cpp index cae2af6ce8..2eecf7dd2f 100644 --- a/src/base/packer.cpp +++ b/src/base/packer.cpp @@ -720,7 +720,8 @@ namespace cubpacking if (len >= max_str_size) { - assert (false); + assert (max_str_size == 0); + align (INT_ALIGNMENT); return; } if (len > 0) diff --git a/src/base/porting.c b/src/base/porting.c index f8d7eda312..f21b4cb93c 100644 --- a/src/base/porting.c +++ b/src/base/porting.c @@ -2549,6 +2549,22 @@ strtof_win (const char *nptr, char **endptr) f_val = (float) d_val; return f_val; } + +char * +strndup_win (const char *src, size_t size) +{ + char *dest = (char *) malloc (size + 1); + if (dest == NULL) + { + return NULL; + } + + memcpy (dest, src, size); + dest[size] = '\0'; + + return dest; +} + #endif #ifndef HAVE_STRLCPY diff --git a/src/base/porting.h b/src/base/porting.h index 89e1bdba7f..a4cabe3b47 100644 --- a/src/base/porting.h +++ b/src/base/porting.h @@ -155,6 +155,8 @@ extern char *realpath (const char *path, char *resolved_path); #define vfprintf _vfprintf_p #define vprintf _vprintf_p #define strtof strtof_win +#define strndup strndup_win + #if defined (_WIN32) #define mktime mktime_for_win32 #endif @@ -997,6 +999,7 @@ extern int str_to_float (float *ret_p, char **end_p, const char *str_p); #if defined (WINDOWS) extern float strtof_win (const char *nptr, char **endptr); +extern char *strndup_win (const char *src, size_t size); #endif #ifndef HAVE_STRLCPY diff --git a/src/base/process_util.c b/src/base/process_util.c index 2ffdb5d7e6..4885d01a10 100644 --- a/src/base/process_util.c +++ b/src/base/process_util.c @@ -40,8 +40,8 @@ #include "memory_wrapper.hpp" int -create_child_process (const char *const argv[], int wait_flag, const char *stdin_file, char *stdout_file, - char *stderr_file, int *exit_status) +create_child_process (const char *path, const char *const argv[], int wait_flag, const char *stdin_file, + char *stdout_file, char *stderr_file, int *exit_status) { #if defined(WINDOWS) int new_pid; @@ -126,8 +126,7 @@ create_child_process (const char *const argv[], int wait_flag, const char *stdin } res = - CreateProcess (argv[0], cmd_arg_ptr, NULL, NULL, inherit_flag, CREATE_NO_WINDOW, NULL, NULL, &start_info, - &proc_info); + CreateProcess (path, cmd_arg_ptr, NULL, NULL, inherit_flag, CREATE_NO_WINDOW, NULL, NULL, &start_info, &proc_info); free (cmd_arg_ptr); if (res == FALSE) @@ -329,7 +328,7 @@ create_child_process (const char *const argv[], int wait_flag, const char *stdin } } - rc = execv ((const char *) argv[0], (char *const *) argv); + rc = execv (path, (char *const *) argv); assert (false); return rc; } @@ -363,3 +362,58 @@ create_child_process (const char *const argv[], int wait_flag, const char *stdin } } #endif + +/* + * is_terminated_process() - test if the process is terminated + * return: true if the process is terminated, otherwise false + * pid(in): process id + */ +bool +is_terminated_process (const int pid) +{ +#if defined(WINDOWS) + HANDLE h_process; + + h_process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid); + if (h_process == NULL) + { + return true; + } + else + { + CloseHandle (h_process); + return false; + } +#else /* WINDOWS */ + if (kill (pid, 0) == -1) + { + return true; + } + else + { + return false; + } +#endif /* WINDOWS */ +} + +/* + * terminate_process() - terminate the process of given pid + * return: void + * pid(in): process id + */ +void +terminate_process (int pid) +{ +#if defined(WINDOWS) + HANDLE phandle; + + phandle = OpenProcess (PROCESS_TERMINATE, FALSE, pid); + if (phandle) + { + TerminateProcess (phandle, 0); + CloseHandle (phandle); + } +#else /* ! WINDOWS */ + kill (pid, SIGTERM); +#endif /* ! WINDOWS */ +} diff --git a/src/base/process_util.h b/src/base/process_util.h index 3f9618f33c..ef6b42a604 100644 --- a/src/base/process_util.h +++ b/src/base/process_util.h @@ -24,8 +24,11 @@ #ifndef _PROCESS_UTIL_H_ #define _PROCESS_UTIL_H_ -int -create_child_process (const char *const argv[], int wait_flag, const char *stdin_file, char *stdout_file, - char *stderr_file, int *exit_status); +#include "porting.h" +EXPORT_IMPORT int create_child_process (const char *path, const char *const argv[], int wait_flag, + const char *stdin_file, char *stdout_file, char *stderr_file, int *exit_status); + +EXPORT_IMPORT bool is_terminated_process (const int pid); +EXPORT_IMPORT void terminate_process (const int pid); #endif /* _PROCESS_UTIL_H_ */ diff --git a/src/base/system_parameter.c b/src/base/system_parameter.c index 0c9c413059..76ffde8b29 100644 --- a/src/base/system_parameter.c +++ b/src/base/system_parameter.c @@ -434,6 +434,16 @@ static const char sysprm_ha_conf_file_name[] = "cubrid_ha.conf"; #define PRM_NAME_JAVA_STORED_PROCEDURE_UDS "java_stored_procedure_uds" +#define PRM_NAME_STORED_PROCEDURE "stored_procedure" + +#define PRM_NAME_STORED_PROCEDURE_PORT "stored_procedure_port" + +#define PRM_NAME_STORED_PROCEDURE_JVM_OPTIONS "stored_procedure_vm_options" + +#define PRM_NAME_STORED_PROCEDURE_DEBUG "stored_procedure_debug" + +#define PRM_NAME_STORED_PROCEDURE_UDS "stored_procedure_uds" + #define PRM_NAME_ALLOW_TRUNCATED_STRING "allow_truncated_string" #define PRM_NAME_COMPAT_PRIMARY_KEY "compat_primary_key" @@ -2305,29 +2315,29 @@ int PRM_ER_LOG_TDE = false; static int prm_er_log_tde_default = false; static unsigned int prm_er_log_tde_flag = 0; -bool PRM_JAVA_STORED_PROCEDURE = true; -static bool prm_java_stored_procedure_default = true; -static unsigned int prm_java_stored_procedure_flag = 0; +bool PRM_STORED_PROCEDURE = true; +static bool prm_stored_procedure_default = true; +static unsigned int prm_stored_procedure_flag = 0; -int PRM_JAVA_STORED_PROCEDURE_PORT = 0; -static int prm_java_stored_procedure_port_default = 0; -static int prm_java_stored_procedure_port_upper = 65535; -static int prm_java_stored_procedure_port_lower = 0; -static unsigned int prm_java_stored_procedure_port_flag = 0; +int PRM_STORED_PROCEDURE_PORT = 0; +static int prm_stored_procedure_port_default = 0; +static int prm_stored_procedure_port_upper = 65535; +static int prm_stored_procedure_port_lower = 0; +static unsigned int prm_stored_procedure_port_flag = 0; -const char *PRM_JAVA_STORED_PROCEDURE_JVM_OPTIONS = ""; -static const char *prm_java_stored_procedure_jvm_options_default = ""; -static unsigned int prm_java_stored_procedure_jvm_options_flag = 0; +const char *PRM_STORED_PROCEDURE_JVM_OPTIONS = ""; +static const char *prm_stored_procedure_jvm_options_default = ""; +static unsigned int prm_stored_procedure_jvm_options_flag = 0; -int PRM_JAVA_STORED_PROCEDURE_DEBUG = -1; -static int prm_java_stored_procedure_debug_default = -1; -static int prm_java_stored_procedure_debug_upper = 65535; -static int prm_java_stored_procedure_debug_lower = -1; -static unsigned int prm_java_stored_procedure_debug_flag = 0; +int PRM_STORED_PROCEDURE_DEBUG = -1; +static int prm_stored_procedure_debug_default = -1; +static int prm_stored_procedure_debug_upper = 65535; +static int prm_stored_procedure_debug_lower = -1; +static unsigned int prm_stored_procedure_debug_flag = 0; -bool PRM_JAVA_STORED_PROCEDURE_UDS = true; -static bool prm_java_stored_procedure_uds_default = true; -static unsigned int prm_java_stored_procedure_uds_flag = 0; +bool PRM_STORED_PROCEDURE_UDS = true; +static bool prm_stored_procedure_uds_default = true; +static unsigned int prm_stored_procedure_uds_flag = 0; bool PRM_ALLOW_TRUNCATED_STRING = false; static bool prm_allow_truncated_string_default = false; @@ -3548,7 +3558,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_ORACLE_STYLE_EMPTY_STRING, PRM_NAME_ORACLE_STYLE_EMPTY_STRING, - (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_FOR_QRY_STRING | PRM_FORCE_SERVER), + (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_FOR_QRY_STRING | PRM_FORCE_SERVER | PRM_FOR_PL_CONTEXT), PRM_BOOLEAN, &prm_oracle_style_empty_string_flag, (void *) &prm_oracle_style_empty_string_default, @@ -3604,7 +3614,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_COMPAT_NUMERIC_DIVISION_SCALE, PRM_NAME_COMPAT_NUMERIC_DIVISION_SCALE, - (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_USER_CHANGE | PRM_FOR_SESSION | PRM_FOR_HA_CONTEXT), + (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_USER_CHANGE | PRM_FOR_SESSION | PRM_FOR_HA_CONTEXT | PRM_FOR_PL_CONTEXT), PRM_BOOLEAN, &prm_compat_numeric_division_scale_flag, (void *) &prm_compat_numeric_division_scale_default, @@ -3626,7 +3636,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_AUTO_RESTART_SERVER, PRM_NAME_AUTO_RESTART_SERVER, - (PRM_FOR_CLIENT | PRM_USER_CHANGE), + (PRM_FOR_SERVER | PRM_USER_CHANGE), PRM_BOOLEAN, &prm_auto_restart_server_flag, (void *) &prm_auto_restart_server_default, @@ -4665,7 +4675,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_INTL_NUMBER_LANG, PRM_NAME_INTL_NUMBER_LANG, - (PRM_FOR_CLIENT | PRM_USER_CHANGE | PRM_FOR_SESSION | PRM_FOR_QRY_STRING | PRM_FOR_HA_CONTEXT), + (PRM_FOR_CLIENT | PRM_USER_CHANGE | PRM_FOR_SESSION | PRM_FOR_QRY_STRING | PRM_FOR_HA_CONTEXT | PRM_FOR_PL_CONTEXT), PRM_STRING, &prm_intl_number_lang_flag, (void *) &prm_intl_number_lang_default, @@ -4676,7 +4686,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_INTL_DATE_LANG, PRM_NAME_INTL_DATE_LANG, - (PRM_FOR_CLIENT | PRM_USER_CHANGE | PRM_FOR_SESSION | PRM_FOR_QRY_STRING | PRM_FOR_HA_CONTEXT), + (PRM_FOR_CLIENT | PRM_USER_CHANGE | PRM_FOR_SESSION | PRM_FOR_QRY_STRING | PRM_FOR_HA_CONTEXT | PRM_FOR_PL_CONTEXT), PRM_STRING, &prm_intl_date_lang_flag, (void *) &prm_intl_date_lang_default, @@ -4817,7 +4827,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_INTL_COLLATION, PRM_NAME_INTL_COLLATION, - (PRM_FOR_CLIENT | PRM_FOR_SESSION | PRM_USER_CHANGE | PRM_FOR_HA_CONTEXT), + (PRM_FOR_CLIENT | PRM_FOR_SESSION | PRM_USER_CHANGE | PRM_FOR_HA_CONTEXT | PRM_FOR_PL_CONTEXT), PRM_STRING, &prm_intl_collation_flag, (void *) &prm_intl_collation_default, @@ -5311,7 +5321,8 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_TIMEZONE, PRM_NAME_TIMEZONE, - (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_FOR_SESSION | PRM_USER_CHANGE | PRM_FOR_QRY_STRING | PRM_FOR_HA_CONTEXT), + (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_FOR_SESSION | PRM_USER_CHANGE | PRM_FOR_QRY_STRING | PRM_FOR_HA_CONTEXT | + PRM_FOR_PL_CONTEXT), PRM_STRING, &prm_timezone_flag, (void *) &prm_timezone_default, @@ -6025,33 +6036,33 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_JAVA_STORED_PROCEDURE, PRM_NAME_JAVA_STORED_PROCEDURE, - (PRM_FOR_SERVER), + (PRM_FOR_SERVER | PRM_HIDDEN), PRM_BOOLEAN, - &prm_java_stored_procedure_flag, - (void *) &prm_java_stored_procedure_default, - (void *) &PRM_JAVA_STORED_PROCEDURE, + &prm_stored_procedure_flag, + (void *) &prm_stored_procedure_default, + (void *) &PRM_STORED_PROCEDURE, (void *) NULL, (void *) NULL, (char *) NULL, (DUP_PRM_FUNC) NULL, (DUP_PRM_FUNC) NULL}, {PRM_ID_JAVA_STORED_PROCEDURE_PORT, PRM_NAME_JAVA_STORED_PROCEDURE_PORT, - (PRM_FOR_SERVER), + (PRM_FOR_SERVER | PRM_HIDDEN), PRM_INTEGER, - &prm_java_stored_procedure_port_flag, - (void *) &prm_java_stored_procedure_port_default, - (void *) &PRM_JAVA_STORED_PROCEDURE_PORT, - (void *) &prm_java_stored_procedure_port_upper, (void *) &prm_java_stored_procedure_port_lower, + &prm_stored_procedure_port_flag, + (void *) &prm_stored_procedure_port_default, + (void *) &PRM_STORED_PROCEDURE_PORT, + (void *) &prm_stored_procedure_port_upper, (void *) &prm_stored_procedure_port_lower, (char *) NULL, (DUP_PRM_FUNC) NULL, (DUP_PRM_FUNC) NULL}, - {PRM_ID_JAVA_STORED_PROCEDURE_JVM_OPTIONS, + {PRM_ID_STORED_PROCEDURE_JVM_OPTIONS, PRM_NAME_JAVA_STORED_PROCEDURE_JVM_OPTIONS, - (PRM_FOR_SERVER), + (PRM_FOR_SERVER | PRM_HIDDEN), PRM_STRING, - &prm_java_stored_procedure_jvm_options_flag, - (void *) &prm_java_stored_procedure_jvm_options_default, - (void *) &PRM_JAVA_STORED_PROCEDURE_JVM_OPTIONS, + &prm_stored_procedure_jvm_options_flag, + (void *) &prm_stored_procedure_jvm_options_default, + (void *) &PRM_STORED_PROCEDURE_JVM_OPTIONS, (void *) NULL, (void *) NULL, (char *) NULL, (DUP_PRM_FUNC) NULL, @@ -6060,20 +6071,20 @@ SYSPRM_PARAM prm_Def[] = { PRM_NAME_JAVA_STORED_PROCEDURE_DEBUG, (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_HIDDEN), PRM_INTEGER, - &prm_java_stored_procedure_debug_flag, - (void *) &prm_java_stored_procedure_debug_default, - (void *) &PRM_JAVA_STORED_PROCEDURE_DEBUG, + &prm_stored_procedure_debug_flag, + (void *) &prm_stored_procedure_debug_default, + (void *) &PRM_STORED_PROCEDURE_DEBUG, (void *) NULL, (void *) NULL, (char *) NULL, (DUP_PRM_FUNC) NULL, (DUP_PRM_FUNC) NULL}, {PRM_ID_JAVA_STORED_PROCEDURE_UDS, PRM_NAME_JAVA_STORED_PROCEDURE_UDS, - (PRM_FOR_SERVER), + (PRM_FOR_SERVER | PRM_HIDDEN), PRM_BOOLEAN, - &prm_java_stored_procedure_uds_flag, - (void *) &prm_java_stored_procedure_uds_default, - (void *) &PRM_JAVA_STORED_PROCEDURE_UDS, + &prm_stored_procedure_uds_flag, + (void *) &prm_stored_procedure_uds_default, + (void *) &PRM_STORED_PROCEDURE_UDS, (void *) NULL, (void *) NULL, (char *) NULL, (DUP_PRM_FUNC) NULL, @@ -6277,7 +6288,7 @@ SYSPRM_PARAM prm_Def[] = { (DUP_PRM_FUNC) NULL}, {PRM_ID_ORACLE_COMPAT_NUMBER_BEHAVIOR, PRM_NAME_ORACLE_COMPAT_NUMBER_BEHAVIOR, - (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_FORCE_SERVER), + (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_FORCE_SERVER | PRM_FOR_PL_CONTEXT), PRM_BOOLEAN, &prm_oracle_compat_number_behavior_flag, (void *) &prm_oracle_compat_number_behavior_default, @@ -6448,6 +6459,61 @@ SYSPRM_PARAM prm_Def[] = { (void *) &prm_max_subquery_cache_size_lower, (char *) NULL, (DUP_PRM_FUNC) NULL, + (DUP_PRM_FUNC) NULL}, + {PRM_ID_STORED_PROCEDURE, + PRM_NAME_STORED_PROCEDURE, + (PRM_FOR_SERVER), + PRM_BOOLEAN, + &prm_stored_procedure_flag, + (void *) &prm_stored_procedure_default, + (void *) &PRM_STORED_PROCEDURE, + (void *) NULL, (void *) NULL, + (char *) NULL, + (DUP_PRM_FUNC) NULL, + (DUP_PRM_FUNC) NULL}, + {PRM_ID_STORED_PROCEDURE_PORT, + PRM_NAME_STORED_PROCEDURE_PORT, + (PRM_FOR_SERVER), + PRM_INTEGER, + &prm_stored_procedure_port_flag, + (void *) &prm_stored_procedure_port_default, + (void *) &PRM_STORED_PROCEDURE_PORT, + (void *) &prm_stored_procedure_port_upper, (void *) &prm_stored_procedure_port_lower, + (char *) NULL, + (DUP_PRM_FUNC) NULL, + (DUP_PRM_FUNC) NULL}, + {PRM_ID_STORED_PROCEDURE_JVM_OPTIONS, + PRM_NAME_STORED_PROCEDURE_JVM_OPTIONS, + (PRM_FOR_SERVER), + PRM_STRING, + &prm_stored_procedure_jvm_options_flag, + (void *) &prm_stored_procedure_jvm_options_default, + (void *) &PRM_STORED_PROCEDURE_JVM_OPTIONS, + (void *) NULL, (void *) NULL, + (char *) NULL, + (DUP_PRM_FUNC) NULL, + (DUP_PRM_FUNC) NULL}, + {PRM_ID_STORED_PROCEDURE_DEBUG, + PRM_NAME_STORED_PROCEDURE_DEBUG, + (PRM_FOR_CLIENT | PRM_FOR_SERVER | PRM_HIDDEN), + PRM_INTEGER, + &prm_stored_procedure_debug_flag, + (void *) &prm_stored_procedure_debug_default, + (void *) &PRM_STORED_PROCEDURE_DEBUG, + (void *) NULL, (void *) NULL, + (char *) NULL, + (DUP_PRM_FUNC) NULL, + (DUP_PRM_FUNC) NULL}, + {PRM_ID_STORED_PROCEDURE_UDS, + PRM_NAME_STORED_PROCEDURE_UDS, + (PRM_FOR_SERVER), + PRM_BOOLEAN, + &prm_stored_procedure_uds_flag, + (void *) &prm_stored_procedure_uds_default, + (void *) &PRM_STORED_PROCEDURE_UDS, + (void *) NULL, (void *) NULL, + (char *) NULL, + (DUP_PRM_FUNC) NULL, (DUP_PRM_FUNC) NULL} }; @@ -7450,7 +7516,7 @@ prm_load_by_section (INI_TABLE * ini, const char *section, bool ignore_section, } } - if (strcmp (section, "common") == 0 && strcmp (prm->name, PRM_NAME_JAVA_STORED_PROCEDURE_PORT) == 0) + if (strcmp (section, "common") == 0 && strcmp (prm->name, PRM_NAME_STORED_PROCEDURE_PORT) == 0) { error = PRM_ERR_CANNOT_CHANGE; prm_report_bad_entry (key + sec_len, ini->lineno[i], error, file); @@ -9204,6 +9270,53 @@ xsysprm_dump_server_parameters (FILE * outfp) { sysprm_dump_parameters (outfp); } + +/* + * xsysprm_get_pl_context_parameters () - obtain values for parameters + * marked as PRM_FOR_PL_CONTEXT + * + * return : list of values + * + */ +SYSPRM_ASSIGN_VALUE * +xsysprm_get_pl_context_parameters (void) +{ + SYSPRM_ASSIGN_VALUE *pl_ctx_values = NULL, *last_assign = NULL; + SYSPRM_PARAM *prm = NULL; + int i; + + for (i = 0; i < NUM_PRM; i++) + { + prm = GET_PRM (i); + if (PRM_IS_FOR_PL_CONTEXT (prm->static_flag)) + { + SYSPRM_ASSIGN_VALUE *change_val = (SYSPRM_ASSIGN_VALUE *) malloc (sizeof (SYSPRM_ASSIGN_VALUE)); + if (change_val == NULL) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (SYSPRM_ASSIGN_VALUE)); + goto cleanup; + } + change_val->prm_id = (PARAM_ID) i; + change_val->next = NULL; + sysprm_set_sysprm_value_from_parameter (&change_val->value, prm); + if (pl_ctx_values != NULL) + { + last_assign->next = change_val; + last_assign = change_val; + } + else + { + pl_ctx_values = last_assign = change_val; + } + } + } + + return pl_ctx_values; + +cleanup: + sysprm_free_assign_values (&pl_ctx_values); + return NULL; +} #endif /* !CS_MODE */ /* diff --git a/src/base/system_parameter.h b/src/base/system_parameter.h index 2ea92fcbe0..354e0d348d 100644 --- a/src/base/system_parameter.h +++ b/src/base/system_parameter.h @@ -452,6 +452,7 @@ enum param_id PRM_ID_JAVA_STORED_PROCEDURE_JVM_OPTIONS, PRM_ID_JAVA_STORED_PROCEDURE_DEBUG, PRM_ID_JAVA_STORED_PROCEDURE_UDS, + PRM_ID_ALLOW_TRUNCATED_STRING, PRM_ID_TB_DEFAULT_REUSE_OID, PRM_ID_USE_STAT_ESTIMATION, @@ -486,8 +487,14 @@ enum param_id PRM_ID_ENABLE_MEMORY_MONITORING, PRM_ID_MAX_SUBQUERY_CACHE_SIZE, + + PRM_ID_STORED_PROCEDURE, + PRM_ID_STORED_PROCEDURE_PORT, + PRM_ID_STORED_PROCEDURE_JVM_OPTIONS, + PRM_ID_STORED_PROCEDURE_DEBUG, + PRM_ID_STORED_PROCEDURE_UDS, /* change PRM_LAST_ID when adding new system parameters */ - PRM_LAST_ID = PRM_ID_MAX_SUBQUERY_CACHE_SIZE + PRM_LAST_ID = PRM_ID_STORED_PROCEDURE_UDS }; typedef enum param_id PARAM_ID; @@ -571,6 +578,7 @@ extern "C" #define PRM_HAS_TIME_UNIT(x) (x & PRM_TIME_UNIT) #define PRM_DIFFERENT_UNIT(x) (x & PRM_DIFFER_UNIT) #define PRM_IS_FOR_HA_CONTEXT(x) (x & PRM_FOR_HA_CONTEXT) +#define PRM_IS_FOR_PL_CONTEXT(x) (x & PRM_FOR_PL_CONTEXT) #define PRM_IS_GET_SERVER(x) (x & PRM_GET_SERVER) #define PRM_IS_DEPRECATED(x) (x & PRM_DEPRECATED) #define PRM_IS_OBSOLETED(x) (x & PRM_OBSOLETED) @@ -608,6 +616,8 @@ extern "C" * this flag only can be set if the parameter has PRM_FOR_CLIENT, * PRM_FOR_SERVER, and PRM_USER_CHANGE flags. */ +#define PRM_FOR_PL_CONTEXT 0x00020000 /* is for PL parameter */ + #define PRM_DEPRECATED 0x40000000 /* is deprecated */ #define PRM_OBSOLETED 0x80000000 /* is obsoleted */ @@ -729,6 +739,7 @@ extern "C" extern void xsysprm_obtain_server_parameters (SYSPRM_ASSIGN_VALUE * prm_values); extern SYSPRM_ASSIGN_VALUE *xsysprm_get_force_server_parameters (void); extern void xsysprm_dump_server_parameters (FILE * fp); + extern SYSPRM_ASSIGN_VALUE *xsysprm_get_pl_context_parameters (void); #endif /* !CS_MODE */ extern int sysprm_set_force (const char *pname, const char *pvalue); diff --git a/src/base/xserver_interface.h b/src/base/xserver_interface.h index 2ca0cbee9d..8fb3e8456e 100644 --- a/src/base/xserver_interface.h +++ b/src/base/xserver_interface.h @@ -56,7 +56,6 @@ struct compile_context; struct xasl_cache_ent; struct xasl_stream; struct xasl_node_header; -struct method_sig_list; extern int xboot_initialize_server (const BOOT_CLIENT_CREDENTIAL * client_credential, BOOT_DB_PATH_INFO * db_path_info, bool db_overwrite, const char *file_addmore_vols, volatile DKNPAGES db_npages, @@ -294,11 +293,6 @@ extern bool xlogtb_does_active_user_exist (THREAD_ENTRY * thread_p, const char * extern int xlocator_demote_class_lock (THREAD_ENTRY * thread_p, const OID * class_oid, LOCK lock, LOCK * ex_lock); extern bool xtran_should_connection_reset (THREAD_ENTRY * thread_p, bool has_updated); extern int xsession_set_tran_auto_commit (THREAD_ENTRY * thread_p, bool auto_commit); - -// *INDENT-OFF* -extern int xmethod_invoke_fold_constants (THREAD_ENTRY * thread_p, const method_sig_list &sig_list, std::vector> &args, DB_VALUE &result); -// *INDENT-ON* - extern void xsynonym_remove_xasl_by_oid (THREAD_ENTRY * thread_p, OID * oidp); #endif /* _XSERVER_INTERFACE_H_ */ diff --git a/src/communication/network.h b/src/communication/network.h index fd4f7a118b..8f5a80774b 100644 --- a/src/communication/network.h +++ b/src/communication/network.h @@ -257,7 +257,7 @@ enum net_server_request NET_SERVER_VACUUM_DUMP, - NET_SERVER_METHOD_FOLD_CONSTANTS, + NET_SERVER_PL_CALL, NET_SERVER_SUPPLEMENT_STMT, diff --git a/src/communication/network_callback_cl.cpp b/src/communication/network_callback_cl.cpp new file mode 100644 index 0000000000..2b6c6574e4 --- /dev/null +++ b/src/communication/network_callback_cl.cpp @@ -0,0 +1,58 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "network_callback_cl.hpp" + +#include "network_interface_cl.h" /* net_client_send_data */ +#include "method_callback.hpp" + +static unsigned int xs_conn_info [METHOD_MAX_RECURSION_DEPTH + 1]; + +std::queue & +xs_get_data_queue () +{ + return cubmethod::get_callback_handler()->get_data_queue (); +} + +#if defined (CS_MODE) +void +xs_set_conn_info (int idx, unsigned int rc) +{ + xs_conn_info [idx] = rc; +} + +unsigned int +xs_get_conn_info (int idx) +{ + return xs_conn_info [idx]; +} + +int +xs_queue_send () +{ + int depth = tran_get_libcas_depth () - 1; + int rc = xs_get_conn_info (depth); + + assert (!xs_get_data_queue().empty()); + + cubmem::extensible_block &blk = xs_get_data_queue().front (); + int error = net_client_send_data (net_client_get_server_host(), rc, blk.get_ptr (), blk.get_size()); + xs_get_data_queue().pop (); + return error; +} +#endif \ No newline at end of file diff --git a/src/communication/network_callback_cl.hpp b/src/communication/network_callback_cl.hpp new file mode 100644 index 0000000000..373d121e8e --- /dev/null +++ b/src/communication/network_callback_cl.hpp @@ -0,0 +1,59 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#ifndef _NETWORK_CALLBACK_CL_HPP_ +#define _NETWORK_CALLBACK_CL_HPP_ + +#include +#include + +#include "thread_compat.hpp" +#include "mem_block.hpp" /* cubmem::block */ +#include "packer.hpp" /* packing_packer */ + +#if defined (CS_MODE) +void xs_set_conn_info (int idx, unsigned int rc); +unsigned int xs_get_conn_info (int idx); +int xs_queue_send (); +#endif + +std::queue &xs_get_data_queue (); + +template +int xs_pack_and_queue (Args &&... args) +{ + packing_packer packer; + cubmem::extensible_block eb; + packer.set_buffer_and_pack_all (eb, std::forward (args)...); + eb.extend_to (packer.get_current_size ()); // ensure eb.get_size () == packer.get_current_size () + + xs_get_data_queue().push (std::move (eb)); + return NO_ERROR; +} + +template +int xs_send_queue (Args &&... args) +{ + xs_pack_and_queue (std::forward (args)...); +#if defined (CS_MODE) + xs_queue_send (); +#endif + return NO_ERROR; +} + +#endif // _NETWORK_CALLBACK_CL_HPP_ diff --git a/src/communication/network_callback_sr.cpp b/src/communication/network_callback_sr.cpp new file mode 100644 index 0000000000..54956b8c59 --- /dev/null +++ b/src/communication/network_callback_sr.cpp @@ -0,0 +1,106 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "network_callback_sr.hpp" + +#include "network.h" /* METHOD_CALL */ +#include "network_interface_sr.h" /* xs_receive_data_from_client() */ +#include "object_representation.h" /* OR_ */ +#include "server_support.h" /* css_send_reply_and_data_to_client(), css_get_comm_request_id() */ + +#if !defined (SERVER_MODE) +#include "query_method.hpp" +#include "method_callback.hpp" +#endif + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +#if defined (SERVER_MODE) +int xs_callback_send (cubthread::entry *thread_p, const cubmem::extensible_block &mem) +{ + OR_ALIGNED_BUF (OR_INT_SIZE * 2) a_reply; + char *reply = OR_ALIGNED_BUF_START (a_reply); + + /* pack headers */ + char *ptr = or_pack_int (reply, (int) METHOD_CALL); + ptr = or_pack_int (ptr, (int) mem.get_size ()); + +#if !defined(NDEBUG) + /* suppress valgrind UMW error */ + memset (ptr, 0, OR_ALIGNED_BUF_SIZE (a_reply) - (ptr - reply)); +#endif + + if (thread_p == NULL || thread_p->conn_entry == NULL) + { + return ER_FAILED; + } + + /* send */ + unsigned int rid = css_get_comm_request_id (thread_p); + return css_send_reply_and_data_to_client (thread_p->conn_entry, rid, reply, OR_ALIGNED_BUF_SIZE (a_reply), + (char * )mem.get_read_ptr(), (int) mem.get_size ()); +} + +int xs_callback_receive (cubthread::entry *thread_p, const xs_callback_func &func) +{ + cubmem::block buffer (0, nullptr); + + int error = xs_receive_data_from_client (thread_p, &buffer.ptr, (int *) &buffer.dim); + if (error == NO_ERROR && er_errid () == NO_ERROR) + { + error = func (buffer); + } + else + { + if (error == NO_ERROR) + { + error = er_errid (); // ER_SP_TOO_MANY_NESTED_CALL, ER_INTERRUPTED... (interrupt reasons) + } + } + + free_and_init (buffer.ptr); + return error; +} +#else +static std::queue & +xs_get_data_queue_from_cl () +{ + return cubmethod::get_callback_handler()->get_data_queue (); +} + +int xs_callback_send (cubthread::entry *thread_p, const cubmem::extensible_block &ext_blk) +{ + packing_unpacker unpacker (ext_blk.get_read_ptr (), ext_blk.get_size ()); + return method_dispatch (unpacker); +} + +int xs_callback_receive (cubthread::entry *thread_p, const xs_callback_func &func) +{ + std::queue &queue = xs_get_data_queue_from_cl (); + + assert (!queue.empty()); + + cubmem::extensible_block &blk = queue.front (); + cubmem::block buffer (blk.get_size(), blk.get_ptr()); + int error = func (buffer); + + queue.pop (); + return error; +} +#endif diff --git a/src/communication/network_callback_sr.hpp b/src/communication/network_callback_sr.hpp new file mode 100644 index 0000000000..b4de606362 --- /dev/null +++ b/src/communication/network_callback_sr.hpp @@ -0,0 +1,81 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#ifndef _NETWORK_CALLBACK_SR_HPP_ +#define _NETWORK_CALLBACK_SR_HPP_ + +#include +#include + +#include "error_code.h" +#include "thread_compat.hpp" +#include "mem_block.hpp" /* cubmem::block */ +#include "packer.hpp" /* packing_packer */ + +////////////////////////////////////////////////////////////////////////// +// Packing data +////////////////////////////////////////////////////////////////////////// +template +cubmem::extensible_block pack_data (Args &&... args) +{ + packing_packer packer; + cubmem::extensible_block eb; + packer.set_buffer_and_pack_all (eb, std::forward (args)...); + return eb; +} + +template +cubmem::block pack_data_block (Args &&... args) +{ + packing_packer packer; + cubmem::extensible_block eb; + packer.set_buffer_and_pack_all (eb, std::forward (args)...); + cubmem::block b (packer.get_current_size(), eb.release_ptr()); + return b; +} + +////////////////////////////////////////////////////////////////////////// +// Send/Receive +////////////////////////////////////////////////////////////////////////// +using xs_callback_func = std::function ; + +int xs_callback_receive (cubthread::entry *thread_p, const xs_callback_func &func); +int xs_callback_send (cubthread::entry *thread_p, const cubmem::extensible_block &mem); + +template +int xs_callback_send_args (cubthread::entry *thread_p, Args &&... args) +{ + const cubmem::extensible_block b = std::move (pack_data (std::forward (args)...)); + return xs_callback_send (thread_p, b); +} + +template +int xs_callback_send_and_receive (cubthread::entry *thread_p, const xs_callback_func &func, Args &&... args) +{ + int error_code = NO_ERROR; + + error_code = xs_callback_send_args (thread_p, std::forward (args)...); + if (error_code != NO_ERROR) + { + return error_code; + } + + return xs_callback_receive (thread_p, func); +} + +#endif // _NETWORK_CALLBACK_SR_HPP_ diff --git a/src/communication/network_cl.c b/src/communication/network_cl.c index b23805c3fc..72a0c89afd 100644 --- a/src/communication/network_cl.c +++ b/src/communication/network_cl.c @@ -48,7 +48,8 @@ #include "environment_variable.h" #include "boot_cl.h" #include "query_method.hpp" -#include "method_def.hpp" +#include "method_callback.hpp" + #include "release_string.h" #include "log_comm.h" #include "file_io.h" @@ -1714,6 +1715,15 @@ net_client_request_with_callback (int request, char *argbuf, int argsize, char * } while (server_request != END_CALLBACK && server_request != QUERY_END); + /* + * delete deferred query handlers during PL execution + * TODO: move it to proper place + */ + if (!tran_is_in_libcas ()) + { + cubmethod::get_callback_handler ()->free_deferred_query_handler (); + } + if (histo_is_collecting ()) { int recevied = replysize @@ -1907,6 +1917,15 @@ net_client_request_method_callback (int request, char *argbuf, int argsize, char } while (server_request != END_CALLBACK); + /* + * delete deferred query handlers during PL execution + * TODO: move it to proper place + */ + if (!tran_is_in_libcas ()) + { + cubmethod::get_callback_handler ()->free_deferred_query_handler (); + } + if (histo_is_collecting ()) { int recevied = replysize + (replydatasize_ptr ? *replydatasize_ptr : 0); diff --git a/src/communication/network_common.cpp b/src/communication/network_common.cpp index d424dbbb0e..104a983cb0 100644 --- a/src/communication/network_common.cpp +++ b/src/communication/network_common.cpp @@ -218,6 +218,8 @@ const char *net_server_request_name[NET_SERVER_REQUEST_END] = "NET_SERVER_LD_UPDATE_STATS", "NET_SERVER_VACUUM_DUMP", + "NET_SERVER_PL_CALL", + "NET_SERVER_SUPPLEMENT_STMT", "NET_SERVER_CDC_START_SESSION", diff --git a/src/communication/network_interface_cl.c b/src/communication/network_interface_cl.c index f7a698641c..8e4c74779a 100644 --- a/src/communication/network_interface_cl.c +++ b/src/communication/network_interface_cl.c @@ -46,7 +46,7 @@ #include "locator_sr.h" #include "query_executor.h" #include "transaction_sr.h" -#include "jsp_sr.h" +#include "pl_sr.h" #include "vacuum.h" #include "serial.h" #endif /* defined (SA_MODE) */ @@ -67,15 +67,20 @@ #include "db_query.h" #include "dbtype.h" #include "compile_context.h" + #if defined (SA_MODE) #include "thread_manager.hpp" +#include "pl_compile_handler.hpp" +#include "pl_executor.hpp" #endif // SA_MODE + #include "xasl.h" #include "lob_locator.hpp" #include "crypt_opfunc.h" #include "method_error.hpp" #include "message_catalog.h" #include "utility.h" +#include "sp_constants.hpp" /* * Use db_clear_private_heap instead of db_destroy_private_heap @@ -9083,14 +9088,14 @@ sysprm_dump_server_parameters (FILE * outfp) } /* - * jsp_get_server_port - + * pl_get_server_port - * * return: * * NOTE: */ int -jsp_get_server_port (void) +pl_get_server_port (void) { #if defined(CS_MODE) int req_error; @@ -9115,7 +9120,7 @@ jsp_get_server_port (void) #else /* CS_MODE */ int port; THREAD_ENTRY *thread_p = enter_server (); - port = jsp_server_port_from_info (); + port = pl_server_port_from_info (); exit_server (*thread_p); return port; #endif /* !CS_MODE */ @@ -10965,23 +10970,23 @@ loaddb_update_stats (bool verbose) } int -method_invoke_fold_constants (const method_sig_list & sig_list, - std::vector < std::reference_wrapper < DB_VALUE >> &args, DB_VALUE & result) +pl_call (const cubpl::pl_signature & sig, const std::vector < std::reference_wrapper < DB_VALUE >> &args, + std::vector < DB_VALUE > &out_args, DB_VALUE & result) { + int req_error = NO_ERROR; #if defined(CS_MODE) char *data_reply = NULL; int data_reply_size = 0; - int req_error = NO_ERROR; packing_packer packer; cubmem::extensible_block eb; - packer.set_buffer_and_pack_all (eb, sig_list, args); + packer.set_buffer_and_pack_all (eb, sig, args); { OR_ALIGNED_BUF (OR_INT_SIZE * 3) a_reply; char *reply = OR_ALIGNED_BUF_START (a_reply); - req_error = net_client_request_method_callback (NET_SERVER_METHOD_FOLD_CONSTANTS, eb.get_ptr (), + req_error = net_client_request_method_callback (NET_SERVER_PL_CALL, eb.get_ptr (), (int) packer.get_current_size (), reply, OR_ALIGNED_BUF_SIZE (a_reply), &data_reply, &data_reply_size); if (req_error != NO_ERROR) @@ -10999,29 +11004,10 @@ method_invoke_fold_constants (const method_sig_list & sig_list, if (data_reply != NULL) { packing_unpacker unpacker (data_reply, (size_t) data_reply_size); - // *INDENT-OFF* - std::vector out_args; - // *INDENT-ON* - unpacker.unpack_all (result, out_args); - - method_sig_node *sig = sig_list.method_sig; - for (int i = 0; i < sig->num_method_args; i++) + if (data_reply_size > 0) { - if (sig->arg_info.arg_mode[i] == METHOD_ARG_MODE_IN) - { - continue; - } - - int pos = sig->method_arg_pos[i]; - - DB_VALUE & arg = args[pos]; - DB_VALUE & out_arg = out_args[pos]; - - db_value_clear (&arg); - db_value_clone (&out_arg, &arg); + unpacker.unpack_all (result, out_args); } - - pr_clear_value_vector (out_args); } else { @@ -11035,8 +11021,11 @@ method_invoke_fold_constants (const method_sig_list & sig_list, packing_unpacker unpacker (data_reply, (size_t) data_reply_size); int error_code; std::string error_msg; - unpacker.unpack_all (error_code, error_msg); - cubmethod::handle_method_error (error_code, error_msg); + if (data_reply_size > 0) + { + unpacker.unpack_all (error_code, error_msg); + cubmethod::handle_method_error (error_code, error_msg); + } } if (data_reply != NULL) @@ -11045,39 +11034,63 @@ method_invoke_fold_constants (const method_sig_list & sig_list, } return req_error; -#else /* CS_MODE */ - int error_code = NO_ERROR; - +#else + packing_packer packer; + cubmem::extensible_block eb; THREAD_ENTRY *thread_p = enter_server (); - error_code = xmethod_invoke_fold_constants (thread_p, sig_list, args, result); + { + DB_VALUE ret_value; + cubpl::executor executor ((cubpl::pl_signature &) sig); + req_error = executor.fetch_args_peek (args); + if (req_error == NO_ERROR) + { + req_error = executor.execute (ret_value); + } - cubmethod::runtime_context * rctx = cubmethod::get_rctx (thread_p); - assert (rctx); + if (req_error == NO_ERROR) + { + /* 3) pack */ + packer.set_buffer_and_pack_all (eb, ret_value, executor.get_out_args ()); + } + else + { + std::string err_msg = executor.get_stack ()->get_error_message (); + if (err_msg.empty () && req_error != ER_SP_EXECUTE_ERROR) + { + err_msg.assign (er_msg ()); + } - cubmethod::method_invoke_group * top_on_stack = rctx->top_stack (); - assert (top_on_stack); + if (req_error != ER_SM_INVALID_METHOD_ENV) /* FIXME: error possibly occured in builtin method, It should be handled at CAS */ + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_EXECUTE_ERROR, 1, err_msg); + } - if (error_code != NO_ERROR) - { - if (rctx->is_interrupted ()) - { - rctx->set_local_error_for_interrupt (); - } - else if (error_code != ER_SM_INVALID_METHOD_ENV) /* FIXME: error possibly occured in builtin method, It should be handled at CAS */ - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_EXECUTE_ERROR, 1, top_on_stack->get_error_msg ().c_str ()); - } - } + packer.set_buffer_and_pack_all (eb, er_errid (), err_msg); + } - top_on_stack->reset (true); - top_on_stack->end (); - rctx->pop_stack (thread_p, top_on_stack); + db_value_clear (&ret_value); + } exit_server (*thread_p); - return error_code; -#endif /* !CS_MODE */ + // unpack after exit_server (): ownership of the private allocated objects should be out of server mode + packing_unpacker unpacker (eb.get_ptr (), (size_t) packer.get_current_size ()); + if (req_error == NO_ERROR) + { + db_make_null (&result); + unpacker.unpack_all (result, out_args); + } + else + { + int error_code; + std::string error_msg; + unpacker.unpack_all (error_code, error_msg); + cubmethod::handle_method_error (error_code, error_msg); + } + + return req_error; +#endif } /* @@ -11306,10 +11319,10 @@ flashback_get_loginfo (int trid, char *user, OID * classlist, int num_class, LOG } int -plcsql_transfer_file (const std::string & input_file, const bool & verbose, PLCSQL_COMPILE_INFO & compile_info) +plcsql_transfer_file (const PLCSQL_COMPILE_REQUEST & compile_request, PLCSQL_COMPILE_RESPONSE & compile_response) { + int req_error = NO_ERROR; #if defined(CS_MODE) - int rc = ER_FAILED; packing_packer packer; cubmem::extensible_block eb; char *ptr = NULL; @@ -11317,14 +11330,13 @@ plcsql_transfer_file (const std::string & input_file, const bool & verbose, PLCS char *data_reply = NULL; int data_reply_size = 0; - packer.set_buffer_and_pack_all (eb, verbose, input_file); + packer.set_buffer_and_pack_all (eb, compile_request); OR_ALIGNED_BUF (3 * OR_INT_SIZE) a_reply; char *reply = OR_ALIGNED_BUF_START (a_reply); - int req_error = net_client_request_method_callback (NET_SERVER_PLCSQL_TRANSFER_FILE, eb.get_ptr (), - (int) packer.get_current_size (), - reply, OR_ALIGNED_BUF_SIZE (a_reply), &data_reply, - &data_reply_size); + req_error = net_client_request_method_callback (NET_SERVER_PLCSQL_TRANSFER_FILE, eb.get_ptr (), + (int) packer.get_current_size (), + reply, OR_ALIGNED_BUF_SIZE (a_reply), &data_reply, &data_reply_size); if (req_error != NO_ERROR) { goto error; @@ -11340,16 +11352,29 @@ plcsql_transfer_file (const std::string & input_file, const bool & verbose, PLCS if (data_reply != NULL) { packing_unpacker unpacker (data_reply, (size_t) data_reply_size); - unpacker.unpack_all (compile_info); - rc = NO_ERROR; + if (data_reply_size > 0) + { + unpacker.unpack_all (compile_response); + } } error: - // TODO error handling if (req_error != NO_ERROR) { - // TODO: er_set (...): set proper error - rc = req_error; + if (data_reply != NULL) + { + packing_unpacker unpacker (data_reply, (size_t) data_reply_size); + if (data_reply_size > 0) + { + unpacker.unpack_all (compile_response); + } + } + + if (compile_response.err_code == NO_ERROR) + { + compile_response.err_code = (er_errid () != NO_ERROR) ? er_errid () : req_error; + compile_response.err_msg = er_msg ()? er_msg () : "unknown error"; + } } if (data_reply != NULL) @@ -11357,9 +11382,36 @@ plcsql_transfer_file (const std::string & input_file, const bool & verbose, PLCS free_and_init (data_reply); } - return rc; + return req_error; #else /* CS_MODE */ - return NO_ERROR; + int success = ER_FAILED; + + cubmem::extensible_block eb; + THREAD_ENTRY *thread_p = enter_server (); + + { + cubpl::compile_handler compile_handler; + success = compile_handler.compile (compile_request, eb); + } + + exit_server (*thread_p); + + // unpack after exit_server (): ownership of the private allocated objects should be out of server mode + if (success == NO_ERROR) + { + packing_unpacker unpacker (eb.get_ptr (), eb.get_size ()); + if (eb.get_size () > 0) + { + unpacker.unpack_all (compile_response); + } + } + else + { + compile_response.err_code = (er_errid () != NO_ERROR) ? er_errid () : success; + compile_response.err_msg = er_msg ()? er_msg () : "unknown error"; + } + + return success; #endif /* !CS_MODE */ } diff --git a/src/communication/network_interface_cl.h b/src/communication/network_interface_cl.h index 0e225077fa..5b268d1872 100644 --- a/src/communication/network_interface_cl.h +++ b/src/communication/network_interface_cl.h @@ -51,10 +51,11 @@ #include "parse_tree.h" #include "load_common.hpp" #include "timezone_lib_common.h" -#include "method_def.hpp" + #include "dynamic_array.h" #include "flashback_cl.h" -#include "method_compile_def.hpp" +#include "pl_struct_compile.hpp" +#include "pl_signature.hpp" #include "memory_monitor_common.hpp" // forward declarations @@ -299,7 +300,7 @@ extern int db_local_transaction_id (DB_VALUE * trid); extern int qp_get_server_info (PARSER_CONTEXT * parser, int server_info_bits); extern int locator_redistribute_partition_data (OID * class_oid, int no_oids, OID * oid_list); -extern int jsp_get_server_port (void); +extern int pl_get_server_port (void); extern int repl_log_get_append_lsa (LOG_LSA * lsa); extern int repl_set_info (REPL_INFO * repl_info); @@ -446,8 +447,6 @@ extern int loaddb_destroy (); extern int loaddb_interrupt (); extern int loaddb_update_stats (bool verbose); -extern int method_invoke_fold_constants (const method_sig_list & sig_list, - std::vector < std::reference_wrapper < DB_VALUE >> &args, DB_VALUE & result); extern int flashback_get_and_show_summary (dynamic_array * class_list, const char *user, time_t start_time, time_t end_time, FLASHBACK_SUMMARY_INFO_MAP * summary, OID ** oid_list, char **invalid_class, time_t * invalid_time); @@ -456,9 +455,11 @@ extern int flashback_get_loginfo (int trid, char *user, OID * classlist, int num int *invalid_class_idx); /* PL/CSQL */ -EXPORT_IMPORT extern int plcsql_transfer_file (const std::string & input_file, const bool & verbose, - PLCSQL_COMPILE_INFO & compile_info); - +EXPORT_IMPORT extern int plcsql_transfer_file (const PLCSQL_COMPILE_REQUEST & compile_request, + PLCSQL_COMPILE_RESPONSE & compile_response); +EXPORT_IMPORT extern int pl_call (const cubpl::pl_signature & sig, + const std::vector < std::reference_wrapper < DB_VALUE >> &args, + std::vector < DB_VALUE > &out_args, DB_VALUE & result); /* memmon */ extern int mmon_get_server_info (MMON_SERVER_INFO & server_info); diff --git a/src/communication/network_interface_sr.c b/src/communication/network_interface_sr.c index 5a2509aedb..1f0ca0742d 100644 --- a/src/communication/network_interface_sr.c +++ b/src/communication/network_interface_sr.c @@ -63,7 +63,7 @@ #include "statistics.h" #include "chartype.h" #include "heap_file.h" -#include "jsp_sr.h" +#include "pl_sr.h" #include "replication.h" #include "server_support.h" #include "connection_sr.h" @@ -86,11 +86,14 @@ #include "elo.h" #include "transaction_transient.hpp" #include "method_invoke_group.hpp" -#include "method_runtime_context.hpp" #include "log_manager.h" #include "crypt_opfunc.h" #include "flashback.h" -#include "method_compile.hpp" +#include "pl_struct_compile.hpp" +#include "pl_compile_handler.hpp" +#include "pl_session.hpp" +#include "pl_executor.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" @@ -160,8 +163,8 @@ stran_server_commit_internal (THREAD_ENTRY * thread_p, unsigned int rid, bool re state = xtran_server_commit (thread_p, retain_lock); - cubmethod::runtime_context * rctx = cubmethod::get_rctx (thread_p); - if (!rctx || rctx->is_running () == false || rctx->get_depth () == 0) + PL_SESSION *session = cubpl::get_session (); + if (!session || session->is_running () == false) { net_cleanup_server_queues (rid); } @@ -198,8 +201,8 @@ stran_server_abort_internal (THREAD_ENTRY * thread_p, unsigned int rid, bool * s state = xtran_server_abort (thread_p); - cubmethod::runtime_context * rctx = cubmethod::get_rctx (thread_p); - if (!rctx || rctx->is_running () == false || rctx->get_depth () == 0) + PL_SESSION *session = cubpl::get_session (); + if (!session || session->is_running () == false) { net_cleanup_server_queues (rid); } @@ -6647,50 +6650,6 @@ sct_check_rep_dir (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int css_send_data_to_client (thread_p->conn_entry, rid, reply, OR_ALIGNED_BUF_SIZE (a_reply)); } -/* - * xs_send_method_call_info_to_client - - * - * return: - * - * list_id(in): - * method_sig_list(in): - * - * NOTE: - */ -int -xs_send_method_call_info_to_client (THREAD_ENTRY * thread_p, qfile_list_id * list_id, method_sig_list * methsg_list) -{ - int length = 0; - char *databuf; - char *ptr; - unsigned int rid; - OR_ALIGNED_BUF (OR_INT_SIZE * 2) a_reply; - char *reply = OR_ALIGNED_BUF_START (a_reply); - - rid = css_get_comm_request_id (thread_p); - length = or_listid_length ((void *) list_id); - length += or_method_sig_list_length ((void *) methsg_list); - ptr = or_pack_int (reply, (int) METHOD_CALL); - ptr = or_pack_int (ptr, length); - -#if !defined(NDEBUG) - /* suppress valgrind UMW error */ - memset (ptr, 0, OR_ALIGNED_BUF_SIZE (a_reply) - (ptr - reply)); -#endif - - databuf = (char *) db_private_alloc (thread_p, length); - if (databuf == NULL) - { - return ER_FAILED; - } - - ptr = or_pack_listid (databuf, (void *) list_id); - ptr = or_pack_method_sig_list (ptr, (void *) methsg_list); - css_send_reply_and_data_to_client (thread_p->conn_entry, rid, reply, OR_ALIGNED_BUF_SIZE (a_reply), databuf, length); - db_private_free_and_init (thread_p, databuf); - return NO_ERROR; -} - /* * xs_receive_data_from_client - * @@ -8080,7 +8039,7 @@ stran_get_local_transaction_id (THREAD_ENTRY * thread_p, unsigned int rid, char } /* - * sjsp_get_server_port - + * spl_get_server_port - * * return: * @@ -8089,12 +8048,12 @@ stran_get_local_transaction_id (THREAD_ENTRY * thread_p, unsigned int rid, char * NOTE: */ void -sjsp_get_server_port (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen) +spl_get_server_port (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen) { OR_ALIGNED_BUF (OR_INT_SIZE) a_reply; char *reply = OR_ALIGNED_BUF_START (a_reply); - (void) or_pack_int (reply, jsp_server_port_from_info ()); + (void) or_pack_int (reply, pl_server_port_from_info ()); css_send_data_to_client (thread_p->conn_entry, rid, reply, OR_ALIGNED_BUF_SIZE (a_reply)); } @@ -10547,6 +10506,84 @@ cdc_check_client_connection () } } +void +spl_call (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen) +{ + int error_code = NO_ERROR; + packing_unpacker unpacker (request, (size_t) reqlen); + + DB_VALUE ret_value; + db_make_null (&ret_value); + + /* 1) unpack arguments */ + cubpl::pl_signature sig; + std::vector < DB_VALUE > args; + unpacker.unpack_all (sig, args); + + std::vector < std::reference_wrapper < DB_VALUE >> ref_args (args.begin (), args.end ()); + + /* 2) invoke */ + cubpl::executor executor (sig); + error_code = executor.fetch_args_peek (ref_args); + if (error_code == NO_ERROR) + { + error_code = executor.execute (ret_value); + } + + packing_packer packer; + cubmem::extensible_block eb; + if (error_code == NO_ERROR) + { + /* 3) pack */ + packer.set_buffer_and_pack_all (eb, ret_value, executor.get_out_args ()); + } + else + { + std::string err_msg = executor.get_stack ()->get_error_message (); + if (err_msg.empty () && error_code != ER_SP_EXECUTE_ERROR) + { + err_msg.assign (er_msg ()); + } + + if (error_code != ER_SM_INVALID_METHOD_ENV) /* FIXME: error possibly occured in builtin method, It should be handled at CAS */ + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_EXECUTE_ERROR, 1, err_msg.c_str ()); + } + packer.set_buffer_and_pack_all (eb, er_errid (), err_msg); + (void) return_error_to_client (thread_p, rid); + } + + char *reply_data = eb.get_ptr (); + int reply_data_size = (int) packer.get_current_size (); + + OR_ALIGNED_BUF (OR_INT_SIZE * 3) a_reply; + char *reply = OR_ALIGNED_BUF_START (a_reply); + char *ptr = or_pack_int (reply, (int) END_CALLBACK); + ptr = or_pack_int (ptr, reply_data_size); + ptr = or_pack_int (ptr, error_code); + + // clear + //if (top_on_stack) + // { + // top_on_stack->reset (true); + // top_on_stack->end (); + // } + + css_send_reply_and_data_to_client (thread_p->conn_entry, rid, reply, OR_ALIGNED_BUF_SIZE (a_reply), reply_data, + reply_data_size); + +/* + if (top_on_stack) + { + rctx->pop_stack (thread_p, top_on_stack); + } +*/ + + pr_clear_value_vector (args); + db_value_clear (&ret_value); +} + +#if 0 void smethod_invoke_fold_constants (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen) { @@ -10593,7 +10630,7 @@ smethod_invoke_fold_constants (THREAD_ENTRY * thread_p, unsigned int rid, char * // *INDENT-ON* for (int i = 0; i < sig->num_method_args; i++) { - if (sig->arg_info.arg_mode[i] == METHOD_ARG_MODE_IN) + if (sig->arg_info->arg_mode[i] == METHOD_ARG_MODE_IN) { continue; } @@ -10669,6 +10706,7 @@ smethod_invoke_fold_constants (THREAD_ENTRY * thread_p, unsigned int rid, char * db_value_clear (&ret_value); sig_list.freemem (); } +#endif void scdc_start_session (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen) @@ -11282,23 +11320,16 @@ sflashback_get_loginfo (THREAD_ENTRY * thread_p, unsigned int rid, char *request void splcsql_transfer_file (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen) { - packing_unpacker unpacker (request, (size_t) reqlen); - - bool verbose; - std::string input_string; - unpacker.unpack_all (verbose, input_string); + int error = ER_FAILED; + PLCSQL_COMPILE_REQUEST compile_request; - cubmethod::runtime_context * ctx = NULL; - session_get_method_runtime_context (thread_p, ctx); + packing_unpacker unpacker (request, (size_t) reqlen); + unpacker.unpack_all (compile_request); - int error = ER_FAILED; cubmem::extensible_block ext_blk; - if (ctx) - { - error = cubmethod::invoke_compile (*thread_p, *ctx, input_string, verbose, ext_blk); - } + cubpl::compile_handler compile_handler; + error = compile_handler.compile (compile_request, ext_blk); - // Error code and is_ignored. OR_ALIGNED_BUF (3 * OR_INT_SIZE) a_reply; char *reply = OR_ALIGNED_BUF_START (a_reply); char *ptr = or_pack_int (reply, (int) END_CALLBACK); diff --git a/src/communication/network_interface_sr.h b/src/communication/network_interface_sr.h index 142478d99b..4aba905049 100644 --- a/src/communication/network_interface_sr.h +++ b/src/communication/network_interface_sr.h @@ -37,7 +37,6 @@ #include "thread_compat.hpp" // forward definitions -struct method_sig_list; struct qfile_list_id; extern TRAN_STATE return_error_to_client (THREAD_ENTRY * thread_p, unsigned int rid); @@ -151,8 +150,7 @@ extern void smnt_server_stop_stats (THREAD_ENTRY * thread_p, unsigned int rid, c extern void smnt_server_copy_stats (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void smnt_server_copy_global_stats (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void sct_check_rep_dir (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); -extern int xs_send_method_call_info_to_client (THREAD_ENTRY * thread_p, qfile_list_id * list_id, - method_sig_list * methsg_list); + extern int xs_receive_data_from_client (THREAD_ENTRY * thread_p, char **area, int *datasize); extern int xs_receive_data_from_client_with_timeout (THREAD_ENTRY * thread_p, char **area, int *datasize, int timeout); @@ -184,7 +182,7 @@ extern void sprm_server_get_force_parameters (THREAD_ENTRY * thread_p, unsigned extern void sprm_server_dump_parameters (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void shf_has_instance (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void stran_get_local_transaction_id (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); -extern void sjsp_get_server_port (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); +extern void spl_get_server_port (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void srepl_set_info (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void srepl_log_get_append_lsa (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void slocator_check_fk_validity (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); @@ -244,8 +242,6 @@ extern void sloaddb_interrupt (THREAD_ENTRY * thread_p, unsigned int rid, char * extern void sloaddb_update_stats (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void ssession_stop_attached_threads (void *session); -extern void smethod_invoke_fold_constants (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); - /* For CDC */ extern void slog_supplement_statement (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void scdc_start_session (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); @@ -258,8 +254,9 @@ extern void scdc_end_session (THREAD_ENTRY * thread_p, unsigned int rid, char *r extern void sflashback_get_summary (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); extern void sflashback_get_loginfo (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); -/* PL/CSQL */ +/* PL */ extern void splcsql_transfer_file (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); +extern void spl_call (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); /* memmon */ extern void smmon_get_server_info (THREAD_ENTRY * thread_p, unsigned int rid, char *request, int reqlen); diff --git a/src/communication/network_sr.c b/src/communication/network_sr.c index 0bfc923c85..765035dfba 100644 --- a/src/communication/network_sr.c +++ b/src/communication/network_sr.c @@ -555,7 +555,7 @@ net_server_init (void) /* JSP */ req_p = &net_Requests[NET_SERVER_JSP_GET_SERVER_PORT]; req_p->action_attribute = IN_TRANSACTION; - req_p->processing_function = sjsp_get_server_port; + req_p->processing_function = spl_get_server_port; /* replication */ req_p = &net_Requests[NET_SERVER_REPL_INFO]; @@ -712,9 +712,9 @@ net_server_init (void) req_p = &net_Requests[NET_SERVER_VACUUM_DUMP]; req_p->processing_function = svacuum_dump; - req_p = &net_Requests[NET_SERVER_METHOD_FOLD_CONSTANTS]; + req_p = &net_Requests[NET_SERVER_PL_CALL]; req_p->action_attribute = IN_TRANSACTION; - req_p->processing_function = smethod_invoke_fold_constants; + req_p->processing_function = spl_call; req_p = &net_Requests[NET_SERVER_SUPPLEMENT_STMT]; req_p->processing_function = slog_supplement_statement; diff --git a/src/compat/db_admin.c b/src/compat/db_admin.c index 545c76fb70..823c495fcb 100644 --- a/src/compat/db_admin.c +++ b/src/compat/db_admin.c @@ -56,7 +56,7 @@ #include "execute_schema.h" #include "network_interface_cl.h" #if defined(SA_MODE) -#include "jsp_sr.h" +#include "pl_sr.h" #endif /* SA_MODE */ #include "jsp_cl.h" #include "execute_statement.h" @@ -928,7 +928,7 @@ db_restart (const char *program, int print_version, const char *volume) install_static_methods (); #if !defined(WINDOWS) #if defined(SA_MODE) && (defined(LINUX) || defined(x86_SOLARIS)) - if (!jsp_jvm_is_loaded ()) + if (!pl_jvm_is_loaded ()) { prev_sigfpe_handler = os_set_signal_handler (SIGFPE, sigfpe_handler); } @@ -1811,6 +1811,39 @@ db_set_user_comment (DB_OBJECT * user, const char *comment) return (retval); } +/* + * db_get_object_type() - This returns database object type of given MOP + * return : DB_OBJECT_TYPE + * obj_(in) : an object + * + */ +// TODO: find better solution +DB_OBJECT_TYPE +db_get_object_type (MOP obj_) +{ + DB_OBJECT_TYPE ret_val = DB_OBJECT_UNKNOWN; + + assert (obj_->class_mop != NULL); + + OID *mop = WS_OID (obj_->class_mop); + if (OID_EQ (mop, WS_OID (sm_Root_class_mop))) + { + // table, view + ret_val = DB_OBJECT_CLASS; + } + else + { + // database object types except (v)class + MOP sp_class_mop = sm_find_class (CT_STORED_PROC_NAME); + if (sp_class_mop && OID_EQ (mop, WS_OID (sp_class_mop))) + { + ret_val = DB_OBJECT_PROCEDURE; + } + } + + return ret_val; +} + /* * db_grant() -This is the basic mechanism for passing permissions to other * users. The authorization type is one of the numeric values defined @@ -1827,18 +1860,62 @@ db_set_user_comment (DB_OBJECT * user, const char *comment) * */ int -db_grant (MOP user, MOP class_, AU_TYPE auth, int grant_option) +db_grant (MOP user, MOP obj_, AU_TYPE auth, int grant_option) { - int retval; + int retval = NO_ERROR; + DB_OBJECT_TYPE object_type; CHECK_CONNECT_ERROR (); - CHECK_2ARGS_ERROR (user, class_); + CHECK_2ARGS_ERROR (user, obj_); CHECK_MODIFICATION_ERROR (); - retval = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, NULL); + object_type = db_get_object_type (obj_); + if (object_type == DB_OBJECT_CLASS) + { + retval = do_check_partitioned_class (obj_, CHECK_PARTITION_SUBS, NULL); + } + if (!retval) { - retval = au_grant (user, class_, auth, (bool) grant_option); + retval = au_grant (object_type, user, obj_, auth, (bool) grant_option); + } + + return (retval); +} + +/* + * db_grant_object() -This is the basic mechanism for passing permissions to other + * users. The authorization type is one of the numeric values defined + * by the DB_AUTH enumeration. If more than one authorization is to + * be granted, the values in DB_AUTH can be combined using the C bitwise + * "or" operator |. Errors are likely if the currently logged in user + * was not the owner of the class and was not given the grant_option for + * the desired authorization types. + * return : error code + * object_type(in) : an object type + * user(in) : a user object + * obj_(in) : an object + * auth(in) : an authorization type + * grant_option(in) : true if the grant option is to be added + * + */ +int +db_grant_object (DB_OBJECT_TYPE object_type, DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth, int grant_option) +{ + int retval = NO_ERROR; + + CHECK_CONNECT_ERROR (); + CHECK_2ARGS_ERROR (user, obj_); + CHECK_MODIFICATION_ERROR (); + + if (object_type == DB_OBJECT_CLASS) + { + retval = do_check_partitioned_class (obj_, CHECK_PARTITION_SUBS, NULL); + } + + if (!retval) + { + retval = au_grant (object_type, user, obj_, auth, (bool) grant_option); } return (retval); @@ -1854,18 +1931,56 @@ db_grant (MOP user, MOP class_, AU_TYPE auth, int grant_option) * */ int -db_revoke (MOP user, MOP class_mop, AU_TYPE auth) +db_revoke (MOP user, MOP obj_, AU_TYPE auth) { - int retval; + int retval = NO_ERROR; + DB_OBJECT_TYPE object_type; + + CHECK_CONNECT_ERROR (); + CHECK_2ARGS_ERROR (user, obj_); + CHECK_MODIFICATION_ERROR (); + + object_type = db_get_object_type (obj_); + if (object_type == DB_OBJECT_CLASS) + { + retval = do_check_partitioned_class (obj_, CHECK_PARTITION_SUBS, NULL); + } + + if (!retval) + { + retval = au_revoke (object_type, user, obj_, auth, NULL); + } + + return (retval); +} + +/* + * db_revoke_object() - This is the basic mechanism for revoking previously granted + * authorizations. A prior authorization must have been made. + * returns : error code + * object_type(in) : an object type + * user(in) : a user object + * class_mop(in): a class object + * auth(in) : the authorization type(s) to revoke + * + */ +int +db_revoke_object (DB_OBJECT_TYPE object_type, MOP user, MOP obj_, AU_TYPE auth) +{ + int retval = NO_ERROR; CHECK_CONNECT_ERROR (); - CHECK_2ARGS_ERROR (user, class_mop); + CHECK_2ARGS_ERROR (user, obj_); CHECK_MODIFICATION_ERROR (); - retval = do_check_partitioned_class (class_mop, CHECK_PARTITION_SUBS, NULL); + if (object_type == DB_OBJECT_CLASS) + { + retval = do_check_partitioned_class (obj_, CHECK_PARTITION_SUBS, NULL); + } + if (!retval) { - retval = au_revoke (user, class_mop, auth); + retval = au_revoke (object_type, user, obj_, auth, NULL); } return (retval); diff --git a/src/compat/db_method_static.cpp b/src/compat/db_method_static.cpp index 60970f4fc5..40a6590a92 100644 --- a/src/compat/db_method_static.cpp +++ b/src/compat/db_method_static.cpp @@ -20,6 +20,8 @@ * db_method_static.cpp: implement static method links and their implementation */ +#include "msgcat_glossary.hpp" + #include "dbi.h" /* db_ */ #include "dbtype.h" #include "dbtype_def.h" @@ -357,7 +359,7 @@ au_add_member_method (MOP user, DB_VALUE *returnval, DB_VALUE *memval) else { error = ER_AU_NOT_OWNER; - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_CLASS)); } } else @@ -424,7 +426,7 @@ au_drop_member_method (MOP user, DB_VALUE *returnval, DB_VALUE *memval) else { error = ER_AU_NOT_OWNER; - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_CLASS)); } } else @@ -976,7 +978,7 @@ au_change_sp_owner_method (MOP obj, DB_VALUE *returnval, DB_VALUE *sp, DB_VALUE { if (owner != NULL && DB_IS_STRING (owner) && !DB_IS_NULL (owner) && db_get_string (owner) != NULL) { - sp_mop = jsp_find_stored_procedure (db_get_string (sp)); + sp_mop = jsp_find_stored_procedure (db_get_string (sp), DB_AUTH_NONE); if (sp_mop != NULL) { user = au_find_user (db_get_string (owner)); diff --git a/src/compat/db_obj.c b/src/compat/db_obj.c index e961293fa9..5c48bf0e34 100644 --- a/src/compat/db_obj.c +++ b/src/compat/db_obj.c @@ -52,6 +52,7 @@ #include "schema_system_catalog_constants.h" #include "dbtype.h" #include "printer.hpp" +#include "jsp_cl.h" /* * OBJECT CREATION/DELETION @@ -1913,3 +1914,26 @@ db_get_serial_next_value_ex (const char *serial_name, DB_VALUE * serial_value, i return result; } + +/* + * db_find_procedure() - This function locates a procedure (function) with the given name. + * NULL is returned if a procedure by this name does not exist, or it the + * user does not have the appropriate access privilege for the procedure. + * If NULL is returned, the system sets the global error status to a value + * that indicates the exact nature of the error. + * return : procedure object (NULL if error) + * name(in): procedure name + */ + +DB_OBJECT * +db_find_procedure (const char *name) +{ + DB_OBJECT *retval; + + CHECK_CONNECT_NULL (); + CHECK_1ARG_NULL (name); + + retval = jsp_find_stored_procedure (name, DB_AUTH_NONE); + + return retval; +} diff --git a/src/compat/dbi.h b/src/compat/dbi.h index fc5e82be8f..74f2b077c5 100644 --- a/src/compat/dbi.h +++ b/src/compat/dbi.h @@ -153,6 +153,9 @@ extern "C" extern int db_set_user_comment (DB_OBJECT * user, const char *comment); extern int db_grant (DB_OBJECT * user, DB_OBJECT * classobj, DB_AUTH auth, int grant_option); extern int db_revoke (DB_OBJECT * user, DB_OBJECT * classobj, DB_AUTH auth); + extern int db_grant_object (DB_OBJECT_TYPE obj_type, DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth, + int grant_option); + extern int db_revoke_object (DB_OBJECT_TYPE obj_type, DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth); extern int db_check_authorization (DB_OBJECT * op, DB_AUTH auth); extern int db_check_authorization_and_grant_option (MOP op, DB_AUTH auth); extern int db_get_class_privilege (DB_OBJECT * op, unsigned int *auth); @@ -416,6 +419,9 @@ extern "C" extern int db_trigger_action (DB_OBJECT * trobj, char **action); extern int db_trigger_comment (DB_OBJECT * trobj, char **comment); +/* Procedure functions */ + extern DB_OBJECT *db_find_procedure (const char *name); + /* Schema template functions */ extern DB_CTMPL *dbt_create_class (const char *name); extern DB_CTMPL *dbt_create_vclass (const char *name); @@ -742,6 +748,8 @@ extern "C" extern void db_clear_host_connected (void); extern char *db_get_database_version (void); + + extern DB_OBJECT_TYPE db_get_object_type (DB_OBJECT * obj_); #ifdef __cplusplus } #endif diff --git a/src/compat/dbi_compat.h b/src/compat/dbi_compat.h index b3a1d921cd..ce13ff58e9 100644 --- a/src/compat/dbi_compat.h +++ b/src/compat/dbi_compat.h @@ -212,8 +212,11 @@ extern "C" extern int db_drop_member (DB_OBJECT * user, DB_OBJECT * member); extern int db_set_password (DB_OBJECT * user, const char *oldpass, const char *newpass); extern int db_set_user_comment (DB_OBJECT * user, const char *comment); - extern int db_grant (DB_OBJECT * user, DB_OBJECT * classobj, DB_AUTH auth, int grant_option); - extern int db_revoke (DB_OBJECT * user, DB_OBJECT * classobj, DB_AUTH auth); + extern int db_grant (DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth, int grant_option); + extern int db_revoke (DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth); + extern int db_grant_object (DB_OBJECT_TYPE obj_type, DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth, + int grant_option); + extern int db_revoke_object (DB_OBJECT_TYPE obj_type, DB_OBJECT * user, DB_OBJECT * obj_, DB_AUTH auth); extern int db_check_authorization (DB_OBJECT * op, DB_AUTH auth); extern int db_check_authorization_and_grant_option (MOP op, DB_AUTH auth); extern int db_get_class_privilege (DB_OBJECT * op, unsigned int *auth); @@ -453,6 +456,9 @@ extern "C" extern int db_trigger_action (DB_OBJECT * trobj, char **action); extern int db_trigger_comment (DB_OBJECT * trobj, char **comment); +/* Procedure functions */ + extern DB_OBJECT *db_find_procedure (const char *name); + /* Schema template functions */ extern DB_CTMPL *dbt_create_class (const char *name); extern DB_CTMPL *dbt_create_vclass (const char *name); diff --git a/src/compat/dbtype_def.h b/src/compat/dbtype_def.h index 9334f59e4c..a20c719f1f 100644 --- a/src/compat/dbtype_def.h +++ b/src/compat/dbtype_def.h @@ -484,6 +484,17 @@ extern "C" DB_INSTANCE_OF_A_VCLASS_OF_A_CLASS = 'c', DB_INSTANCE_OF_A_VCLASS_OF_A_PROXY = 'd', DB_INSTANCE_OF_NONUPDATABLE_OBJECT = 'e' + } DB_INSTANCE_TYPE; + + typedef enum + { + DB_OBJECT_UNKNOWN = -1, + DB_OBJECT_CLASS = 0, /* TABLE, VIEW (_db_class) */ + DB_OBJECT_TRIGGER = 1, /* TRIGGER (_db_trigger) */ + DB_OBJECT_SERIAL = 2, /* SERIAL (db_serial) */ + DB_OBJECT_SERVER = 3, /* SERVER (db_server) */ + DB_OBJECT_SYNONYM = 4, /* SYNONYM (_db_synonym) */ + DB_OBJECT_PROCEDURE = 5 /* PROCEDURE, FUNCTION (_db_stored_procedure) */ } DB_OBJECT_TYPE; /* session state id */ @@ -537,9 +548,8 @@ extern "C" /* The lower limit for a number that can be represented by a numeric type */ #define DB_NUMERIC_UNDERFLOW_LIMIT 1e-38 -/* - * Change the maximum length of CHAR type to 2048 for memory allocation and performance. - * Refer to CBRD-25713 +/* The maximum precision of CHAR(n) domain that can be specified for an INTL_UTF8_MAX_CHAR_SIZE. + * We may need to define this functionally as the maximum precision will depend on the size multiplier of the codeset. */ #define DB_MAX_CHAR_PRECISION (DB_MAX_STRING_LENGTH/4) diff --git a/src/connection/connection_defs.h b/src/connection/connection_defs.h index fb36d7f900..994196c70c 100644 --- a/src/connection/connection_defs.h +++ b/src/connection/connection_defs.h @@ -107,7 +107,6 @@ enum css_client_request CANCEL_SHUTDOWN = 15, GET_SHUTDOWN_TIME = 16, KILL_SERVER_IMMEDIATE = 17, - SHUTDOWN_REVIVING_SERVER = 18, GET_REPL_LIST = 20, /* REPL: get the info. for a process */ GET_ALL_LIST = 21, /* REPL: get the info. for all processes */ GET_REPL_COUNT = 22, /* REPL: get the # of repl processes */ diff --git a/src/connection/connection_globals.h b/src/connection/connection_globals.h index 06973ebb48..20cb63c761 100644 --- a/src/connection/connection_globals.h +++ b/src/connection/connection_globals.h @@ -32,8 +32,6 @@ #define CSS_MAX_CLIENT_COUNT 4000 -#define CSS_SERVER_PROC_REGISTER_INITIALIZER {-1, "", 0, "", ""} - typedef bool (*CSS_CHECK_CLIENT_TYPE) (BOOT_CLIENT_TYPE client_type); typedef int (*CSS_GET_MAX_CONN_NUM) (void); @@ -59,26 +57,6 @@ typedef struct css_conn_rule_info int num_curr_conn; } CSS_CONN_RULE_INFO; -/* - * server register resource message body - */ - -/* process register */ -typedef struct css_server_proc_register CSS_SERVER_PROC_REGISTER; -struct css_server_proc_register -{ - static constexpr int CSS_SERVER_MAX_SZ_SERVER_NAME = 256; - static constexpr int CSS_SERVER_MAX_SZ_PROC_EXEC_PATH = 128; - static constexpr int CSS_SERVER_MAX_SZ_PROC_ARGS = 1024; - - int pid; - char server_name[CSS_SERVER_MAX_SZ_SERVER_NAME]; - int server_name_length; - - char exec_path[CSS_SERVER_MAX_SZ_PROC_EXEC_PATH]; - char args[CSS_SERVER_MAX_SZ_PROC_ARGS]; -}; - extern int css_Service_id; extern const char *css_Service_name; diff --git a/src/connection/connection_sr.c b/src/connection/connection_sr.c index d76848d12f..260a07670f 100644 --- a/src/connection/connection_sr.c +++ b/src/connection/connection_sr.c @@ -151,9 +151,6 @@ CSS_THREAD_FN css_Request_handler = NULL; /* This will handle closed connection errors */ CSS_THREAD_FN css_Connection_error_handler = NULL; -static char css_Server_exec_path[PATH_MAX]; -static char **css_Server_argv; - #define CSS_CONN_IDX(conn_arg) ((conn_arg) - css_Conn_array) #define CSS_FREE_CONN_MSG "Free count = %d, head = %d" @@ -1076,32 +1073,6 @@ css_common_connect (CSS_CONN_ENTRY * conn, unsigned short *rid, return NULL; } -/* - * css_set_proc_register() - make a server proc register. - * return: - * server_name(in): - * server_name_lenth(in): - * proc_register(out): - */ -static void -css_set_proc_register (const char *server_name, int server_name_length, CSS_SERVER_PROC_REGISTER * proc_register) -{ - char *p, *last; - char **argv; - - memcpy (proc_register->server_name, server_name, server_name_length); - proc_register->server_name_length = server_name_length; - proc_register->pid = getpid (); - strncpy_bufsize (proc_register->exec_path, css_Server_exec_path); - - p = (char *) proc_register->args; - last = p + proc_register->CSS_SERVER_MAX_SZ_PROC_ARGS; - for (argv = css_Server_argv; *argv; argv++) - { - p += snprintf (p, MAX ((last - p), 0), "%s ", *argv); - } -} - /* * css_connect_to_master_server() - Connect to the master from the server. * return: connection entry if success, or NULL @@ -1122,9 +1093,6 @@ css_connect_to_master_server (int master_port_id, const char *server_name, int n std::string pname; int datagram_fd, socket_fd; #endif - const char *data; - int data_length; - CSS_SERVER_PROC_REGISTER proc_register = CSS_SERVER_PROC_REGISTER_INITIALIZER; css_Service_id = master_port_id; if (GETHOSTNAME (hname, CUB_MAXHOSTNAMELEN) != 0) @@ -1140,27 +1108,18 @@ css_connect_to_master_server (int master_port_id, const char *server_name, int n } /* select the connection protocol */ - - // TODO : When supporting the Windows environment, It will be modified to send the same data - // (proc_register) for the Windows protocol (SERVER_REQUEST_NEW) as well. - if (css_Server_use_new_connection_protocol) { // Windows connection_protocol = SERVER_REQUEST_NEW; - data = server_name; - data_length = name_length; } else { // Linux and Unix connection_protocol = SERVER_REQUEST; - css_set_proc_register (server_name, name_length, &proc_register); - data = (const char *) &proc_register; - data_length = sizeof (proc_register); } - if (css_common_connect (conn, &rid, hname, connection_protocol, data, data_length, master_port_id) == NULL) + if (css_common_connect (conn, &rid, hname, connection_protocol, server_name, name_length, master_port_id) == NULL) { goto fail_end; } @@ -3163,29 +3122,3 @@ css_free_user_access_status (void) return; } - -/* - * css_set_exec_path () - - * return: none - * - * exec_path(in): - */ -void -css_set_exec_path (char *exec_path) -{ - assert (exec_path != NULL); - strncpy (css_Server_exec_path, exec_path, sizeof (css_Server_exec_path) - 1); -} - -/* - * css_set_argv () - - * return: none - * - * argv(in): - */ -void -css_set_argv (char **argv) -{ - assert (argv != NULL); - css_Server_argv = argv; -} diff --git a/src/connection/connection_sr.h b/src/connection/connection_sr.h index b639786fdf..f34f096002 100644 --- a/src/connection/connection_sr.h +++ b/src/connection/connection_sr.h @@ -192,7 +192,4 @@ extern void css_set_user_access_status (const char *db_user, const char *host, c extern void css_get_user_access_status (int num_user, LAST_ACCESS_STATUS ** access_status_array); extern void css_free_user_access_status (void); -extern void css_set_exec_path (char *exec_path); -extern void css_set_argv (char **argv); - #endif /* _CONNECTION_SR_H_ */ diff --git a/src/connection/server_support.c b/src/connection/server_support.c index 0a61e368b7..3255f503f3 100644 --- a/src/connection/server_support.c +++ b/src/connection/server_support.c @@ -66,7 +66,7 @@ #include "log_manager.h" #include "network.h" #include "object_representation.h" -#include "jsp_sr.h" +#include "pl_sr.h" #include "show_scan.h" #if defined(WINDOWS) #include "wintcp.h" @@ -321,7 +321,7 @@ css_setup_server_loop (void) #endif /* not WINDOWS */ #if defined(SA_MODE) && (defined(LINUX) || defined(x86_SOLARIS) || defined(HPUX)) - if (!jsp_jvm_is_loaded ()) + if (!pl_jvm_is_loaded ()) { (void) os_set_signal_handler (SIGFPE, SIG_IGN); } diff --git a/src/executables/commdb.c b/src/executables/commdb.c index cfd1f99a81..95860490dd 100644 --- a/src/executables/commdb.c +++ b/src/executables/commdb.c @@ -135,8 +135,6 @@ static bool commdb_Arg_deact_confirm_no_server = false; static char *commdb_Arg_host_name = NULL; static bool commdb_Arg_ha_start_util_process = false; static char *commdb_Arg_ha_util_process_args = NULL; -static bool commdb_Arg_shutdown_reviving_server = false; -static char *commdb_Arg_shutdown_reviving_server_name = NULL; /* * send_request_no_args() - send request without argument @@ -1065,18 +1063,6 @@ process_ha_start_util_process (CSS_CONN_ENTRY * conn, char *args) return error; } -/* - * process_shutdown_reviving_server() - shutdown reviving server - * return: none - * server_name(in) : server name - * conn(in) : connection info - */ -static void -process_shutdown_reviving_server (CSS_CONN_ENTRY * conn, char *server_name) -{ - send_request_one_arg (conn, SHUTDOWN_REVIVING_SERVER, server_name, (int) strlen (server_name) + 1); -} - /* * process_batch_command() - process user command in batch mode * return: none @@ -1193,11 +1179,6 @@ process_batch_command (CSS_CONN_ENTRY * conn) return process_ha_start_util_process (conn, (char *) commdb_Arg_ha_util_process_args); } - if (commdb_Arg_shutdown_reviving_server) - { - process_shutdown_reviving_server (conn, (char *) commdb_Arg_shutdown_reviving_server_name); - } - return NO_ERROR; } @@ -1240,7 +1221,6 @@ main (int argc, char **argv) {COMMDB_HOST_L, 1, 0, COMMDB_HOST_S}, {COMMDB_HA_ADMIN_INFO_L, 0, 0, COMMDB_HA_ADMIN_INFO_S}, {COMMDB_HA_START_UTIL_PROCESS_L, 1, 0, COMMDB_HA_START_UTIL_PROCESS_S}, - {COMMDB_SHUTDOWN_REVIVING_SERVER_L, 1, 0, COMMDB_SHUTDOWN_REVIVING_SERVER_S}, {0, 0, 0, 0} }; @@ -1389,14 +1369,6 @@ main (int argc, char **argv) commdb_Arg_ha_util_process_args = strdup (optarg); commdb_Arg_ha_start_util_process = true; break; - case COMMDB_SHUTDOWN_REVIVING_SERVER_S: - if (commdb_Arg_shutdown_reviving_server_name != NULL) - { - free_and_init (commdb_Arg_shutdown_reviving_server_name); - } - commdb_Arg_shutdown_reviving_server_name = strdup (optarg); - commdb_Arg_shutdown_reviving_server = true; - break; default: util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT); goto usage; @@ -1467,10 +1439,6 @@ main (int argc, char **argv) { free_and_init (commdb_Arg_ha_util_process_args); } - if (commdb_Arg_shutdown_reviving_server_name != NULL) - { - free_and_init (commdb_Arg_shutdown_reviving_server_name); - } return status; } diff --git a/src/executables/compactdb.c b/src/executables/compactdb.c index decfb5187b..79baa4a44d 100644 --- a/src/executables/compactdb.c +++ b/src/executables/compactdb.c @@ -141,8 +141,6 @@ compactdb (UTIL_FUNCTION_ARG * arg) } } - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); if ((error = db_login ("DBA", NULL)) || (error = db_restart (arg->argv0, TRUE, database_name))) diff --git a/src/executables/compactdb_cl.c b/src/executables/compactdb_cl.c index 48561e4ac4..44bf7c891b 100644 --- a/src/executables/compactdb_cl.c +++ b/src/executables/compactdb_cl.c @@ -871,8 +871,6 @@ compactdb (UTIL_FUNCTION_ARG * arg) } } - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); if (standby_compactdb_flag) diff --git a/src/executables/csql.c b/src/executables/csql.c index 1c8777d41e..e2be472c5e 100644 --- a/src/executables/csql.c +++ b/src/executables/csql.c @@ -1539,11 +1539,11 @@ csql_set_server_output (CSQL_ARGUMENT * csql_arg, bool server_output) csql_arg->pl_server_output = server_output; if (server_output) { - csql_execute_query ("CALL enable (50000);"); + csql_execute_query ("CALL dbms_output.enable (50000);"); } else { - csql_execute_query ("CALL disable ();"); + csql_execute_query ("CALL dbms_output.disable ();"); } } @@ -1844,7 +1844,7 @@ csql_print_server_output (const CSQL_ARGUMENT * csql_arg) bool print_header = true; do { - errors = csql_execute_query ("CALL get_line (:pl_output_str, :pl_output_status);"); + errors = csql_execute_query ("CALL dbms_output.get_line (:pl_output_str, :pl_output_status);"); if (errors != 0) { break; diff --git a/src/executables/master.c b/src/executables/master.c index 030350db9a..6249bce0a5 100644 --- a/src/executables/master.c +++ b/src/executables/master.c @@ -59,7 +59,6 @@ #include "error_manager.h" #include "connection_globals.h" #include "connection_cl.h" -#include "system_parameter.h" #if defined(WINDOWS) #include "wintcp.h" #else /* ! WINDOWS */ @@ -74,7 +73,6 @@ #include "message_catalog.h" #include "dbi.h" #include "util_func.h" -#include "master_server_monitor.hpp" static void css_master_error (const char *error_string); static int css_master_timeout (void); @@ -82,7 +80,8 @@ static int css_master_init (int cport, SOCKET * clientfd); static void css_reject_client_request (CSS_CONN_ENTRY * conn, unsigned short rid, int reason); static void css_reject_server_request (CSS_CONN_ENTRY * conn, int reason); static void css_accept_server_request (CSS_CONN_ENTRY * conn, int reason); -static void css_accept_new_request (CSS_CONN_ENTRY * conn, unsigned short rid, char *buffer); +static void css_accept_new_request (CSS_CONN_ENTRY * conn, unsigned short rid, char *server_name, + int server_name_length); static void css_accept_old_request (CSS_CONN_ENTRY * conn, unsigned short rid, SOCKET_QUEUE_ENTRY * entry, char *server_name, int server_name_length); static void css_register_new_server (CSS_CONN_ENTRY * conn, unsigned short rid); @@ -320,53 +319,39 @@ css_accept_server_request (CSS_CONN_ENTRY * conn, int reason) * return: none * conn(in) * rid(in) - * buffer(in) - * + * server_name(in) + * server_name_length(in) */ static void -css_accept_new_request (CSS_CONN_ENTRY * conn, unsigned short rid, char *buffer) +css_accept_new_request (CSS_CONN_ENTRY * conn, unsigned short rid, char *server_name, int server_name_length) { char *datagram; - char *server_name; int datagram_length; SOCKET server_fd = INVALID_SOCKET; int length; - int server_name_length; CSS_CONN_ENTRY *datagram_conn; SOCKET_QUEUE_ENTRY *entry; - CSS_SERVER_PROC_REGISTER *proc_register = (CSS_SERVER_PROC_REGISTER *) buffer; datagram = NULL; datagram_length = 0; - css_accept_server_request (conn, SERVER_REQUEST_ACCEPTED); - if (css_receive_data (conn, rid, &datagram, &datagram_length, -1) == NO_ERRORS) { - if (datagram != NULL && css_tcp_master_datagram (datagram, &server_fd)) { datagram_conn = css_make_conn (server_fd); #if defined(DEBUG) css_Active_server_count++; #endif - css_add_request_to_socket_queue (datagram_conn, false, proc_register->server_name, server_fd, READ_WRITE, 0, + css_add_request_to_socket_queue (datagram_conn, false, server_name, server_fd, READ_WRITE, 0, &css_Master_socket_anchor); - - // Note : server_name is usually packed(appended) information of server_name, version_string, env_var, pid, - // packed from css_pack_server_name(). Since there are some cases that returns server_name and server_name_length - // as NULL, we need to check if server_name is packed information or not. - length = (int) strlen (proc_register->server_name) + 1; - server_name_length = proc_register->server_name_length; - - assert (length <= DB_MAX_IDENTIFIER_LENGTH); - + length = (int) strlen (server_name) + 1; if (length < server_name_length) { - entry = css_return_entry_of_server (proc_register->server_name, css_Master_socket_anchor); + entry = css_return_entry_of_server (server_name, css_Master_socket_anchor); if (entry != NULL) { - server_name = proc_register->server_name + length; + server_name += length; entry->version_string = (char *) malloc (strlen (server_name) + 1); if (entry->version_string != NULL) { @@ -389,19 +374,6 @@ css_accept_new_request (CSS_CONN_ENTRY * conn, unsigned short rid, char *buffer) } } } - - if (!entry->ha_mode) - { -#if !defined(WINDOWS) - if (auto_Restart_server) - { - /* *INDENT-OFF* */ - master_Server_monitor->produce_job (server_monitor::job_type::REGISTER_SERVER, proc_register->pid, - proc_register->exec_path, proc_register->args, proc_register->server_name); - /* *INDENT-ON* */ - } -#endif - } } } if (datagram) @@ -468,26 +440,20 @@ css_accept_old_request (CSS_CONN_ENTRY * conn, unsigned short rid, SOCKET_QUEUE_ static void css_register_new_server (CSS_CONN_ENTRY * conn, unsigned short rid) { - int data_length; - char *data = NULL; + int name_length; + char *server_name = NULL; SOCKET_QUEUE_ENTRY *entry; - // Note: css_register_new_server() is used in two situations: - // 1. When a client requests to connect a cub_server to cub_master, which is already registered. - // 2. When a new cub_server requests to register itself to cub_master. - // For the first situation, css_register_new_server() receives the server name as data. - // For the second situation, css_register_new_server() receives CSS_SERVER_PROC_REGISTER as data. - // css_register_new_server determines which case it is by checking if the entry is NULL or not. - - if (css_receive_data (conn, rid, &data, &data_length, -1) == NO_ERRORS) + /* read server name */ + if (css_receive_data (conn, rid, &server_name, &name_length, -1) == NO_ERRORS) { - entry = css_return_entry_of_server (data, css_Master_socket_anchor); + entry = css_return_entry_of_server (server_name, css_Master_socket_anchor); if (entry != NULL) { if (IS_INVALID_SOCKET (entry->fd)) { /* accept a server that was auto-started */ - css_accept_old_request (conn, rid, entry, data, data_length); + css_accept_old_request (conn, rid, entry, server_name, name_length); } else { @@ -502,17 +468,18 @@ css_register_new_server (CSS_CONN_ENTRY * conn, unsigned short rid) #if defined(DEBUG) css_Active_server_count++; #endif - css_add_request_to_socket_queue (conn, false, data, conn->fd, READ_WRITE, 0, &css_Master_socket_anchor); + css_add_request_to_socket_queue (conn, false, server_name, conn->fd, READ_WRITE, 0, + &css_Master_socket_anchor); #else /* ! WINDOWS */ /* accept a request from a new server */ - css_accept_new_request (conn, rid, data); + css_accept_new_request (conn, rid, server_name, name_length); #endif /* ! WINDOWS */ } } - if (data != NULL) + if (server_name != NULL) { - free_and_init (data); + free_and_init (server_name); } #if !defined(WINDOWS) @@ -1013,15 +980,6 @@ css_check_master_socket_input (int *count, fd_set * fd_var) css_Active_server_count--; } #endif - -#if !defined(WINDOWS) - if (auto_Restart_server) - { - /* *INDENT-OFF* */ - master_Server_monitor->produce_job (server_monitor::job_type::REVIVE_SERVER, -1, "", "", temp->name); - /* *INDENT-ON* */ - } -#endif css_remove_entry_by_conn (temp->conn_ptr, &css_Master_socket_anchor); } } @@ -1263,18 +1221,6 @@ main (int argc, char **argv) goto cleanup; } } - - auto_Restart_server = prm_get_bool_value (PRM_ID_AUTO_RESTART_SERVER); - - // Since master_Server_monitor is a module for restarting abnormally terminated cub_server, - // it is initialized only when the 'auto_restart_server' parameter is set to true. - - if (auto_Restart_server) - { - // *INDENT-OFF* - master_Server_monitor.reset (new server_monitor ()); - // *INDENT-ON* - } #endif conn = css_make_conn (css_Master_socket_fd[0]); diff --git a/src/executables/master_request.c b/src/executables/master_request.c index 683e05952f..20ae262051 100644 --- a/src/executables/master_request.c +++ b/src/executables/master_request.c @@ -56,7 +56,6 @@ #include "master_util.h" #include "master_request.h" #include "master_heartbeat.h" -#include "master_server_monitor.hpp" #if defined (SUPPRESS_STRLEN_WARNING) #define strlen(s1) ((int) strlen(s1)) @@ -531,14 +530,6 @@ css_process_kill_slave (CSS_CONN_ENTRY * conn, unsigned short request_id, char * snprintf (buffer, MASTER_TO_SRV_MSG_SIZE, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_MASTER, MASTER_MSG_SERVER_STATUS), server_name, timeout); -#if !defined(WINDOWS) - if (auto_Restart_server) - { - /* *INDENT-OFF* */ - master_Server_monitor->produce_job (server_monitor::job_type::UNREGISTER_SERVER, -1, "", "", server_name); - /* *INDENT-ON* */ - } -#endif css_process_start_shutdown (temp, timeout * 60, buffer); } snprintf (buffer, MASTER_TO_SRV_MSG_SIZE, @@ -606,54 +597,6 @@ css_process_kill_immediate (CSS_CONN_ENTRY * conn, unsigned short request_id, ch } } -/* - * css_process_start_shutdown_by_name() - * return: none - * server_name(in/out) - */ -void -css_process_start_shutdown_by_name (char *server_name) -{ -#if !defined(WINDOWS) - SOCKET_QUEUE_ENTRY *temp; - char buffer[MASTER_TO_SRV_MSG_SIZE]; - - (void) pthread_mutex_lock (&css_Master_socket_anchor_lock); - - for (temp = css_Master_socket_anchor; temp; temp = temp->next) - { - if ((temp->name != NULL) && (strcmp (temp->name, server_name) == 0)) - { - /* Send a shutdown request to the specified cub_server with a timeout of 0. - * Buffer will be unused in the receiving function (css_process_shutdown_request). */ - css_process_start_shutdown (temp, 0, buffer); - } - } - (void) pthread_mutex_unlock (&css_Master_socket_anchor_lock); -#endif -} - - -/* - * css_process_shutdown_reviving_server() - * return: none - * conn(in) - * request_id(in) - * server_name(in/out) - */ -static void -css_process_shutdown_reviving_server (CSS_CONN_ENTRY * conn, unsigned short request_id, char *server_name) -{ -#if !defined(WINDOWS) - if (auto_Restart_server) - { - /* *INDENT-OFF* */ - master_Server_monitor->produce_job (server_monitor::job_type::SHUTDOWN_SERVER, -1, "", "", server_name); - /* *INDENT-ON* */ - } -#endif -} - /* * css_send_term_signal() - send a signal to the target process * return: none @@ -766,14 +709,6 @@ css_process_shutdown (char *time_buffer) memset (buffer, 0, sizeof (buffer)); snprintf (buffer, MASTER_TO_SRV_MSG_SIZE, msgcat_message (MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_MASTER, MASTER_MSG_GOING_DOWN), timeout); -#if !defined(WINDOWS) - if (auto_Restart_server) - { - /* INDENT-OFF */ - master_Server_monitor.reset (); - /* INDENT-ON */ - } -#endif for (temp = css_Master_socket_anchor; temp; temp = temp->next) { @@ -1986,12 +1921,6 @@ css_process_info_request (CSS_CONN_ENTRY * conn) css_process_kill_immediate (conn, request_id, buffer); } break; - case SHUTDOWN_REVIVING_SERVER: - if (buffer != NULL) - { - css_process_shutdown_reviving_server (conn, request_id, buffer); - } - break; case GET_ALL_COUNT: css_process_all_count_info (conn, request_id); break; diff --git a/src/executables/master_request.h b/src/executables/master_request.h index 2141b8d608..f55fc605c0 100644 --- a/src/executables/master_request.h +++ b/src/executables/master_request.h @@ -57,5 +57,4 @@ extern SOCKET_QUEUE_ENTRY *css_add_request_to_socket_queue (CSS_CONN_ENTRY * con SOCKET fd, int fd_type, int pid, SOCKET_QUEUE_ENTRY ** anchor_p); extern SOCKET_QUEUE_ENTRY *css_return_entry_by_conn (CSS_CONN_ENTRY * conn_p, SOCKET_QUEUE_ENTRY ** anchor_p); -extern void css_process_start_shutdown_by_name (char *server_name); #endif /* _MASTER_REQUEST_H_ */ diff --git a/src/executables/master_server_monitor.cpp b/src/executables/master_server_monitor.cpp deleted file mode 100644 index 92da0ee0cf..0000000000 --- a/src/executables/master_server_monitor.cpp +++ /dev/null @@ -1,477 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -// -// master_server_monitor.cpp - Server Revive monitoring module -// - -#include -#include -#include -#include - -#include "master_server_monitor.hpp" - -std::unique_ptr master_Server_monitor = nullptr; -bool auto_Restart_server = false; - -server_monitor::server_monitor () -{ - - m_server_entry_map = std::unordered_map (); - - { - std::lock_guard lock (m_server_monitor_mutex); - m_thread_shutdown = false; - } - - start_monitoring_thread (); - _er_log_debug (ARG_FILE_LINE, "[Server Monitor] Monitoring started."); -} - -// In server_monitor destructor, it should guarentee that -// m_monitoring_thread is terminated before m_monitor_list is deleted. -server_monitor::~server_monitor () -{ - stop_monitoring_thread (); - _er_log_debug (ARG_FILE_LINE, "[Server Monitor] Monitoring finished."); -} - -void -server_monitor::start_monitoring_thread () -{ - m_monitoring_thread = std::make_unique (&server_monitor::server_monitor_thread_worker, this); -} - -void -server_monitor::stop_monitoring_thread () -{ - { - std::lock_guard lock (m_server_monitor_mutex); - m_thread_shutdown = true; - } - m_monitor_cv_consumer.notify_all(); - - m_monitoring_thread->join(); -} - -void -server_monitor::server_monitor_thread_worker () -{ - job job; - - while (true) - { - { - std::unique_lock lock (m_server_monitor_mutex); - - m_monitor_cv_consumer.wait (lock, [this] - { - return !m_job_queue.empty () || m_thread_shutdown; - }); - - if (m_thread_shutdown) - { - break; - } - else - { - assert (!m_job_queue.empty ()); - consume_job (job); - } - } - process_job (job); - } -} - -void -server_monitor::register_server_entry (int pid, const std::string &exec_path, const std::string &args, - const std::string &server_name - ) -{ - auto entry = m_server_entry_map.find (server_name); - - if (entry != m_server_entry_map.end ()) - { - entry->second.set_pid (pid); - entry->second.set_need_revive (false); - entry->second.set_last_revived_time (std::chrono::steady_clock::now ()); - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server entry has been registered. (pid : %d)", - server_name.c_str(), pid); - } - else - { - m_server_entry_map.emplace (std::move (server_name), server_entry (pid, exec_path, args, - std::chrono::steady_clock::time_point ())); - - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server entry has been registered newly. (pid : %d)", - server_name.c_str(), pid); - } -} - -void -server_monitor::remove_server_entry (const std::string &server_name) -{ - auto entry = m_server_entry_map.find (server_name); - assert (entry != m_server_entry_map.end ()); - - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server entry has been unregistered. (pid : %d)", - server_name.c_str(), entry->second.get_pid()); - - m_server_entry_map.erase (entry); -} - -void -server_monitor::revive_server (const std::string &server_name) -{ - int error_code; - - // Unacceptable revive time difference is set to be 120 seconds - // as the timediff of server restart mechanism of heartbeat. - constexpr int SERVER_MONITOR_UNACCEPTABLE_REVIVE_TIMEDIFF_IN_SECS = 120; - std::chrono::steady_clock::time_point tv; - int out_pid; - - auto entry = m_server_entry_map.find (server_name); - - if (entry != m_server_entry_map.end ()) - { - entry->second.set_need_revive (true); - - tv = std::chrono::steady_clock::now (); - auto timediff = std::chrono::duration_cast (tv - - entry->second.get_last_revived_time()).count(); - bool revived_before = entry->second.get_last_revived_time () != std::chrono::steady_clock::time_point (); - - // If the server is abnormally terminated and revived within a short period of time, it is considered as a repeated failure. - // For HA server, heartbeat handle this case as demoting the server from master to slave and keep trying to revive the server. - // However, in this case, the server_monitor will not try to revive the server due to following reasons. - // 1. preventing repeated creation of core files. - // 2. The service cannot be recovered even if revived if the server abnormally terminates again within a short time. - - // TODO: Consider retry count for repeated failure case, and give up reviving the server after several retries. - // TODO: The timediff value continues to increase if REVIVE_SERVER handling is repeated. Thus, the if condition will always be - // true after the first evaluation. Therefore, evaluating the timediff only once when producing the REVIVE_SERVER job is needed. - // (Currently, it is impossible since last_revived_time is stored in server_entry, which is not synchronized structure between monitor and main thread.) - - if (!revived_before || timediff > SERVER_MONITOR_UNACCEPTABLE_REVIVE_TIMEDIFF_IN_SECS) - { - out_pid = try_revive_server (entry->second.get_exec_path(), entry->second.get_argv()); - if (out_pid == -1) - { - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Failed to fork server process. Server monitor try to revive server again.", - entry->first.c_str()); - produce_job_internal (job_type::REVIVE_SERVER, -1, "", "", entry->first); - } - else - { - entry->second.set_pid (out_pid); - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server monitor is waiting for server to be registered. (pid : %d)", - entry->first.c_str(), entry->second.get_pid()); - produce_job_internal (job_type::CONFIRM_REVIVE_SERVER, -1, "", "", - entry->first); - } - return; - } - else - { - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server process failures occurred again within a short period of time(%d sec). It will no longer be revived automatically. (pid : %d)", - entry->first.c_str(), SERVER_MONITOR_UNACCEPTABLE_REVIVE_TIMEDIFF_IN_SECS, entry->second.get_pid()); - m_server_entry_map.erase (entry); - return; - } - } -} - -void -server_monitor::check_server_revived (const std::string &server_name) -{ - int error_code; - auto entry = m_server_entry_map.find (server_name); - - if (entry != m_server_entry_map.end ()) - { - error_code = kill (entry->second.get_pid (), 0); - if (error_code) - { - if (errno == ESRCH) - { - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Revived server process can not be found. Server monitor will try to revive server again. (pid : %d)", - entry->first.c_str(), entry->second.get_pid()); - produce_job_internal (job_type::REVIVE_SERVER, -1, "", "", entry->first); - } - else - { - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Failed to revive server due to unknown error from kill() function. It will no longer be revived automatically. (pid : %d)", - entry->first.c_str(), entry->second.get_pid()); - kill (entry->second.get_pid (), SIGKILL); - m_server_entry_map.erase (entry); - } - } - else if (entry->second.get_need_revive ()) - { - // Server revive confirm interval is set to be 1 second to avoid busy waiting. - constexpr int SERVER_MONITOR_CONFIRM_REVIVE_INTERVAL_IN_SECS = 1; - - std::this_thread::sleep_for (std::chrono::seconds (SERVER_MONITOR_CONFIRM_REVIVE_INTERVAL_IN_SECS)); - - produce_job_internal (job_type::CONFIRM_REVIVE_SERVER, -1, "", "", - entry->first); - - } - else - { - _er_log_debug (ARG_FILE_LINE, "[Server Monitor] [%s] Server revive success. (pid : %d)", - entry->first.c_str(), - entry->second.get_pid()); - } - return; - } -} - -int -server_monitor::try_revive_server (const std::string &exec_path, char *const *argv) -{ - pid_t pid; - - pid = fork (); - if (pid < 0) - { - return -1; - } - else if (pid == 0) - { - execv (exec_path.c_str(), argv); - } - else - { - return pid; - } -} -void -server_monitor::shutdown_server (const std::string &server_name) -{ - int rv; - auto entry = m_server_entry_map.find (server_name); - - if (entry != m_server_entry_map.end ()) - { - - if (entry->second.get_need_revive ()) - { - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server is shutdown. Reviving the server will not be tried.", - server_name.c_str()); - } - else - { - css_process_start_shutdown_by_name (const_cast (server_name.c_str())); - - _er_log_debug (ARG_FILE_LINE, - "[Server Monitor] [%s] Server is already revived. Server monitor will terminate the server. (pid : %d)", - server_name.c_str(), entry->second.get_pid()); - } - m_server_entry_map.erase (entry); - } -} - -void -server_monitor::produce_job_internal (job_type job_type, int pid, const std::string &exec_path, - const std::string &args, const std::string &server_name) -{ - std::lock_guard lock (m_server_monitor_mutex); - m_job_queue.emplace (job_type, pid, exec_path, args, server_name); -} - -void -server_monitor::produce_job (job_type job_type, int pid, const std::string &exec_path, - const std::string &args, const std::string &server_name) -{ - produce_job_internal (job_type, pid, exec_path, args, server_name); - m_monitor_cv_consumer.notify_all(); -} - -void -server_monitor::consume_job (job &consume_job) -{ - consume_job = std::move (m_job_queue.front ()); - m_job_queue.pop (); -} - -void -server_monitor::process_job (job &consume_job) -{ - switch (consume_job.get_job_type ()) - { - case job_type::REGISTER_SERVER: - register_server_entry (consume_job.get_pid(), consume_job.get_exec_path(), consume_job.get_args(), - consume_job.get_server_name()); - - break; - case job_type::UNREGISTER_SERVER: - remove_server_entry (consume_job.get_server_name()); - break; - case job_type::REVIVE_SERVER: - revive_server (consume_job.get_server_name()); - break; - case job_type::CONFIRM_REVIVE_SERVER: - check_server_revived (consume_job.get_server_name()); - break; - case job_type::SHUTDOWN_SERVER: - shutdown_server (consume_job.get_server_name()); - break; - case job_type::JOB_MAX: - default: - assert (false); - break; - } -} - -server_monitor::job:: -job (job_type job_type, int pid, const std::string &exec_path, const std::string &args, - const std::string &server_name) - : m_job_type {job_type} - , m_pid {pid} - , m_exec_path {exec_path} - , m_args {args} - , m_server_name {server_name} -{ -} - -server_monitor::job_type -server_monitor::job::get_job_type () const -{ - return m_job_type; -} - -int -server_monitor::job::get_pid () const -{ - return m_pid; -} - -std::string -server_monitor::job::get_exec_path () const -{ - return m_exec_path; -} - -std::string -server_monitor::job::get_args () const -{ - return m_args; -} - -std::string -server_monitor::job::get_server_name () const -{ - return m_server_name; -} - -server_monitor::server_entry:: -server_entry (int pid, const std::string &exec_path, const std::string &args, - std::chrono::steady_clock::time_point revive_time) - : m_pid {pid} - , m_exec_path {exec_path} - , m_need_revive {false} - , m_last_revived_time {revive_time} -{ - if (args.size() > 0) - { - proc_make_arg (args); - } -} - -int -server_monitor::server_entry::get_pid () const -{ - return m_pid; -} - -std::string -server_monitor::server_entry::get_exec_path () const -{ - return m_exec_path; -} - -char *const * -server_monitor::server_entry::get_argv () const -{ - return m_argv.get (); -} - -bool -server_monitor::server_entry::get_need_revive () const -{ - return m_need_revive; -} - -std::chrono::steady_clock::time_point -server_monitor::server_entry::get_last_revived_time () const -{ - return m_last_revived_time; -} - -void -server_monitor::server_entry::set_pid (int pid) -{ - m_pid = pid; -} - -void -server_monitor::server_entry::set_exec_path (const std::string &exec_path) -{ - m_exec_path = exec_path; -} - -void -server_monitor::server_entry::set_need_revive (bool need_revive) -{ - m_need_revive = need_revive; -} - -void -server_monitor::server_entry::set_last_revived_time (std::chrono::steady_clock::time_point revive_time) -{ - m_last_revived_time = revive_time; -} - -void -server_monitor::server_entry::proc_make_arg (const std::string &args) -{ - //argv is type of std::unique_ptr - m_argv = std::make_unique (args.size () + 1); - std::istringstream iss (args); - std::string arg; - int i = 0; - while (std::getline (iss, arg, ' ')) - { - m_argv[i] = new char[arg.size () + 1]; - std::copy (arg.begin (), arg.end (), m_argv[i]); - i++; - } - m_argv[args.size()] = nullptr; -} diff --git a/src/executables/master_server_monitor.hpp b/src/executables/master_server_monitor.hpp deleted file mode 100644 index f8ca8dd3c2..0000000000 --- a/src/executables/master_server_monitor.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * master_server_monitor.hpp - - */ - -#ifndef _MASTER_SERVER_MONITOR_HPP_ -#define _MASTER_SERVER_MONITOR_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "connection_globals.h" -#include "master_request.h" - -class server_monitor -{ - - public: - - enum class job_type - { - REGISTER_SERVER = 0, - UNREGISTER_SERVER = 1, - REVIVE_SERVER = 2, - CONFIRM_REVIVE_SERVER = 3, - SHUTDOWN_SERVER = 4, - JOB_MAX - }; - - private: - - class job - { - - public: - - job (job_type job_type, int pid, const std::string &exec_path, const std::string &args, - const std::string &server_name); - job () : m_job_type (job_type::JOB_MAX) {}; - ~job () {}; - - job (const job &) = default; - job (job &&) = default; - - job &operator= (const job &) = delete; - job &operator= (job &&) = default; - - job_type get_job_type () const; - int get_pid () const; - std::string get_exec_path () const; - std::string get_args () const; - std::string get_server_name () const; - - private: - - job_type m_job_type; // job type - int m_pid; // process ID of server process - std::string m_exec_path; // executable path of server process - std::string m_args; // arguments of server process - std::string m_server_name; // server name - }; - - public: - - server_monitor (); - ~server_monitor (); - - server_monitor (const server_monitor &) = delete; - server_monitor (server_monitor &&) = delete; - - server_monitor &operator = (const server_monitor &) = delete; - server_monitor &operator = (server_monitor &&) = delete; - - void register_server_entry (int pid, const std::string &exec_path, const std::string &args, - const std::string &server_name); - void remove_server_entry (const std::string &server_name); - void revive_server (const std::string &server_name); - int try_revive_server (const std::string &exec_path, char *const *argv); - void check_server_revived (const std::string &server_name); - void shutdown_server (const std::string &server_name); - - void produce_job_internal (job_type job_type, int pid, const std::string &exec_path, const std::string &args, - const std::string &server_name); - void produce_job (job_type job_type, int pid, const std::string &exec_path, const std::string &args, - const std::string &server_name); - - void consume_job (job &consune_job); - void process_job (job &consume_job); - - private: - - class server_entry - { - public: - server_entry (int pid, const std::string &exec_path, const std::string &args, - std::chrono::steady_clock::time_point revive_time); - ~server_entry () {}; - - server_entry (const server_entry &) = delete; - server_entry (server_entry &&) = default; - - server_entry &operator= (const server_entry &) = delete; - server_entry &operator= (server_entry &&other) - { - if (this != &other) - { - m_pid = other.m_pid; - m_need_revive = other.m_need_revive; - m_last_revived_time = other.m_last_revived_time; - m_exec_path = other.m_exec_path; - m_argv = std::move (other.m_argv); - } - return *this; - } - - int get_pid () const; - std::string get_exec_path () const; - char *const *get_argv () const; - bool get_need_revive () const; - std::chrono::steady_clock::time_point get_last_revived_time () const; - - void set_pid (int pid); - void set_exec_path (const std::string &exec_path); - void set_need_revive (bool need_revive); - void set_last_revived_time (std::chrono::steady_clock::time_point revive_time); - - void proc_make_arg (const std::string &args); - - private: - int m_pid; // process ID of server process - std::string m_exec_path; // executable path of server process - std::unique_ptr m_argv; // arguments of server process - volatile bool m_need_revive; // need to be revived by monitoring thread - std::chrono::steady_clock::time_point m_last_revived_time; // last revived time - }; - - std::unordered_map m_server_entry_map; // map of server entries - std::unique_ptr m_monitoring_thread; // monitoring thread - std::queue m_job_queue; // job queue for monitoring thread - bool m_thread_shutdown; // flag to shutdown monitoring thread - std::mutex m_server_monitor_mutex; // lock that syncs m_job_queue and m_thread_shutdown - std::condition_variable m_monitor_cv_consumer; // condition variable for m_job_queue empty check - - void start_monitoring_thread (); - void stop_monitoring_thread (); - void server_monitor_thread_worker (); -}; - -extern std::unique_ptr master_Server_monitor; -extern bool auto_Restart_server; - -#endif diff --git a/src/executables/migrate.c b/src/executables/migrate.c index f0cee450c8..9ebabcb5f6 100644 --- a/src/executables/migrate.c +++ b/src/executables/migrate.c @@ -468,7 +468,6 @@ main (int argc, char *argv[]) } sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); AU_DISABLE_PASSWORDS (); diff --git a/src/executables/javasp.cpp b/src/executables/pl.cpp similarity index 50% rename from src/executables/javasp.cpp rename to src/executables/pl.cpp index 45bff40e8d..4e58a0c9de 100644 --- a/src/executables/javasp.cpp +++ b/src/executables/pl.cpp @@ -18,7 +18,7 @@ /* - * javasp.cpp - utility java stored procedure server main routine + * pl.cpp - utility PL JVM server main routine * */ @@ -54,6 +54,7 @@ #include #endif /* not WINDOWS */ +#include "process_util.h" #include "environment_variable.h" #include "system_parameter.h" #include "error_code.h" @@ -63,10 +64,10 @@ #include "databases_file.h" #include "object_representation.h" #include "method_struct_invoke.hpp" -#include "method_connection_java.hpp" - -#include "jsp_file.h" -#include "jsp_sr.h" +#include "pl_connection.hpp" +#include "pl_comm.h" +#include "pl_file.h" +#include "pl_sr.h" #include "packer.hpp" @@ -75,9 +76,9 @@ #include #include -#define JAVASP_PING_LEN PATH_MAX +#define PL_PING_LEN PATH_MAX -#define JAVASP_PRINT_ERR_MSG(...) \ +#define PL_PRINT_ERR_MSG(...) \ do {\ fprintf (stderr, __VA_ARGS__);\ }while (0) @@ -88,25 +89,22 @@ #define NULL_DEVICE "/dev/null" #endif -static int javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name, const std::string &path); -static int javasp_stop_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name); -static int javasp_status_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name); - -static void javasp_dump_status (FILE *fp, JAVASP_STATUS_INFO status_info); -static int javasp_ping_server (const int server_port, const char *db_name, char *buf); -static bool javasp_is_running (const int server_port, const std::string &db_name); +static int pl_start_server (const PL_SERVER_INFO pl_info, const std::string &db_name, const std::string &path); +static int pl_stop_server (const PL_SERVER_INFO pl_info, const std::string &db_name); +static int pl_status_server (const PL_SERVER_INFO pl_info, const std::string &db_name); -static bool javasp_is_terminated_process (int pid); -static void javasp_terminate_process (int pid); +static void pl_dump_status (FILE *fp, PL_STATUS_INFO status_info); +static int pl_ping_server (const PL_SERVER_INFO pl_info, const char *db_name, char *buf); +static bool pl_is_running (const PL_SERVER_INFO pl_info, const std::string &db_name); -static int javasp_get_server_info (const std::string &db_name, JAVASP_SERVER_INFO &info); -static int javasp_check_argument (int argc, char *argv[], std::string &command, std::string &db_name); -static int javasp_check_database (const std::string &db_name, std::string &db_path); +static int pl_get_server_info (const std::string &db_name, PL_SERVER_INFO &info); +static int pl_check_argument (int argc, char *argv[], std::string &command, std::string &db_name); +static int pl_check_database (const std::string &db_name, std::string &db_path); -static int javasp_get_port_param (); +static int pl_get_port_param (); #if !defined(WINDOWS) -static void javasp_signal_handler (int sig); +static void pl_signal_handler (int sig); #endif static bool is_signal_handling = false; @@ -114,7 +112,7 @@ static char executable_path[PATH_MAX]; static std::string command; static std::string db_name; -static JAVASP_SERVER_INFO running_info = JAVASP_SERVER_INFO_INITIALIZER; +static PL_SERVER_INFO running_info = PL_SERVER_INFO_INITIALIZER; /* * main() - javasp main function @@ -127,19 +125,19 @@ main (int argc, char *argv[]) FILE *redirect = NULL; /* for ping */ #if defined(WINDOWS) - FARPROC jsp_old_hook = NULL; + FARPROC pl_old_hook = NULL; #else if (os_set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR) { return ER_GENERIC_ERROR; } - os_set_signal_handler (SIGABRT, javasp_signal_handler); - os_set_signal_handler (SIGILL, javasp_signal_handler); - os_set_signal_handler (SIGFPE, javasp_signal_handler); - os_set_signal_handler (SIGBUS, javasp_signal_handler); - os_set_signal_handler (SIGSEGV, javasp_signal_handler); - os_set_signal_handler (SIGSYS, javasp_signal_handler); + os_set_signal_handler (SIGABRT, pl_signal_handler); + os_set_signal_handler (SIGILL, pl_signal_handler); + os_set_signal_handler (SIGFPE, pl_signal_handler); + os_set_signal_handler (SIGBUS, pl_signal_handler); + os_set_signal_handler (SIGSEGV, pl_signal_handler); + os_set_signal_handler (SIGSYS, pl_signal_handler); #endif /* WINDOWS */ { @@ -151,7 +149,7 @@ main (int argc, char *argv[]) er_init (NULL_DEVICE, ER_NEVER_EXIT); /* check arguments, get command and database name */ - status = javasp_check_argument (argc, argv, command, db_name); + status = pl_check_argument (argc, argv, command, db_name); if (status != NO_ERROR) { return ER_GENERIC_ERROR; @@ -159,7 +157,7 @@ main (int argc, char *argv[]) /* check database exists and get path name of database */ std::string pathname; - status = javasp_check_database (db_name, pathname); + status = pl_check_database (db_name, pathname); if (status != NO_ERROR) { goto exit; @@ -177,13 +175,13 @@ main (int argc, char *argv[]) er_init (er_msg_file, ER_NEVER_EXIT); } - /* try to create info dir and get absolute path for info file; $CUBRID/var/javasp_.info */ - JAVASP_SERVER_INFO jsp_info = JAVASP_SERVER_INFO_INITIALIZER; - status = javasp_get_server_info (db_name, jsp_info); + /* try to create info dir and get absolute path for info file; $CUBRID/var/pl_.info */ + PL_SERVER_INFO pl_info = PL_SERVER_INFO_INITIALIZER; + status = pl_get_server_info (db_name, pl_info); if (status != NO_ERROR && command.compare ("start") != 0) { char info_path[PATH_MAX], err_msg[PATH_MAX + 32]; - javasp_get_info_file (info_path, PATH_MAX, db_name.c_str ()); + pl_get_info_file (info_path, PATH_MAX, db_name.c_str ()); snprintf (err_msg, sizeof (err_msg), "Error while opening file (%s)", info_path); er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_START_JVM, 1, err_msg); goto exit; @@ -191,7 +189,7 @@ main (int argc, char *argv[]) #if defined(WINDOWS) // socket startup for windows - windows_socket_startup (jsp_old_hook); + windows_socket_startup (pl_old_hook); #endif /* WINDOWS */ /* @@ -203,33 +201,34 @@ main (int argc, char *argv[]) if ((redirect = freopen (NULL_DEVICE, "w", stderr)) == NULL) { assert (false); - return ER_GENERIC_ERROR; + goto exit; } // check process is running - if (jsp_info.pid == JAVASP_PID_DISABLED || javasp_is_terminated_process (jsp_info.pid) == true) + if (pl_info.pid == PL_PID_DISABLED || is_terminated_process (pl_info.pid) == true) { - // NO_CONNECTION - javasp_reset_info (db_name.c_str ()); + fprintf (stdout, "NO_PROCESS"); goto exit; } - char buffer[JAVASP_PING_LEN] = {0}; + char buffer[PL_PING_LEN] = {0}; if (status == NO_ERROR) { - status = javasp_ping_server (jsp_info.port, db_name.c_str (), buffer); + status = pl_ping_server (pl_info, db_name.c_str (), buffer); } if (status == NO_ERROR) { std::string ping_db_name; - packing_unpacker unpacker (buffer, JAVASP_PING_LEN); + packing_unpacker unpacker (buffer, PL_PING_LEN); unpacker.unpack_string (ping_db_name); fprintf (stdout, "%s", ping_db_name.c_str ()); } else { + fprintf (stdout, "NO_CONNECTION"); + status = NO_ERROR; goto exit; } @@ -246,43 +245,51 @@ main (int argc, char *argv[]) /* javasp command main routine */ if (command.compare ("start") == 0) { - // check java stored procedure is not enabled - if (prm_get_bool_value (PRM_ID_JAVA_STORED_PROCEDURE) == false) - { - fprintf (stdout, "%s system parameter is not enabled\n", prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE)); - status = ER_SP_CANNOT_START_JVM; - goto exit; - } - - status = javasp_start_server (jsp_info, db_name, pathname); + status = pl_start_server (pl_info, db_name, pathname); if (status == NO_ERROR) { command = "running"; - javasp_read_info (db_name.c_str(), running_info); + pl_read_info (db_name.c_str(), running_info); do { - SLEEP_MILISEC (0, 100); +#if defined (WINDOWS) + DWORD parent_ppid = GetCurrentProcessId(); + HANDLE hParent = OpenProcess (SYNCHRONIZE, FALSE, parent_ppid); + DWORD result = WaitForSingleObject (hParent, INFINITE); + CloseHandle (hParent); + if (result == WAIT_OBJECT_0) + { + ExitProcess (0); + } +#else + if (getppid () == 1) + { + // parent process is terminated + break; + } +#endif + sleep (1); } while (true); } } else if (command.compare ("stop") == 0) { - status = javasp_stop_server (jsp_info, db_name); + status = pl_stop_server (pl_info, db_name); } else if (command.compare ("status") == 0) { - status = javasp_status_server (jsp_info, db_name); + status = pl_status_server (pl_info, db_name); } else { - JAVASP_PRINT_ERR_MSG ("Invalid command: %s\n", command.c_str ()); + PL_PRINT_ERR_MSG ("Invalid command: %s\n", command.c_str ()); status = ER_GENERIC_ERROR; } #if defined(WINDOWS) // socket shutdown for windows - windows_socket_shutdown (jsp_old_hook); + windows_socket_shutdown (pl_old_hook); #endif /* WINDOWS */ } @@ -294,10 +301,6 @@ main (int argc, char *argv[]) { fprintf (stdout, "ERROR"); } - else - { - fprintf (stdout, "NO_CONNECTION"); - } if (redirect) { @@ -308,7 +311,7 @@ main (int argc, char *argv[]) { if (er_has_error ()) { - JAVASP_PRINT_ERR_MSG ("%s\n", er_msg ()); + PL_PRINT_ERR_MSG ("%s\n", er_msg ()); } } @@ -316,9 +319,9 @@ main (int argc, char *argv[]) } #if !defined(WINDOWS) -static void javasp_signal_handler (int sig) +static void pl_signal_handler (int sig) { - JAVASP_SERVER_INFO jsp_info = JAVASP_SERVER_INFO_INITIALIZER; + PL_SERVER_INFO pl_info = PL_SERVER_INFO_INITIALIZER; if (os_set_signal_handler (sig, SIG_DFL) == SIG_ERR) { @@ -330,16 +333,15 @@ static void javasp_signal_handler (int sig) return; } - int status = javasp_get_server_info (db_name, jsp_info); // if failed, - if (status == NO_ERROR && jsp_info.pid != JAVASP_PID_DISABLED) + int status = pl_get_server_info (db_name, pl_info); // if failed, + if (status == NO_ERROR && pl_info.pid != PL_PID_DISABLED) { - (void) envvar_bindir_file (executable_path, PATH_MAX, UTIL_JAVASP_NAME); if (command.compare ("running") != 0 || db_name.empty ()) { return; } - if (running_info.pid == jsp_info.pid && running_info.port == jsp_info.port) + if (running_info.pid == pl_info.pid && running_info.port == pl_info.port) { is_signal_handling = true; } @@ -348,68 +350,59 @@ static void javasp_signal_handler (int sig) return; } - int pid = fork (); - if (pid == 0) // child - { - execl (executable_path, UTIL_JAVASP_NAME, "start", db_name.c_str (), NULL); - exit (0); - } - else - { - // error handling in parent - std::string err_msg; + // error handling in parent + std::string err_msg; - void *addresses[64]; - int nn_addresses = backtrace (addresses, sizeof (addresses) / sizeof (void *)); - char **symbols = backtrace_symbols (addresses, nn_addresses); + void *addresses[64]; + int nn_addresses = backtrace (addresses, sizeof (addresses) / sizeof (void *)); + char **symbols = backtrace_symbols (addresses, nn_addresses); - err_msg += "pid ("; - err_msg += std::to_string (pid); - err_msg += ")\n"; + err_msg += "pid ("; + err_msg += std::to_string (getpid ()); + err_msg += ")\n"; - for (int i = 0; i < nn_addresses; i++) + for (int i = 0; i < nn_addresses; i++) + { + err_msg += symbols[i]; + if (i < nn_addresses - 1) { - err_msg += symbols[i]; - if (i < nn_addresses - 1) - { - err_msg += "\n"; - } + err_msg += "\n"; } - free (symbols); + } + free (symbols); - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_SERVER_CRASHED, 1, err_msg.c_str ()); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_SERVER_CRASHED, 1, err_msg.c_str ()); - exit (1); - } + exit (1); } else { // resume signal hanlding - os_set_signal_handler (sig, javasp_signal_handler); + os_set_signal_handler (sig, pl_signal_handler); is_signal_handling = false; } } #endif static int -javasp_get_port_param () +pl_get_port_param () { int prm_port = 0; #if defined (WINDOWS) const bool is_uds_mode = false; #else - const bool is_uds_mode = prm_get_bool_value (PRM_ID_JAVA_STORED_PROCEDURE_UDS); + const bool is_uds_mode = prm_get_bool_value (PRM_ID_STORED_PROCEDURE_UDS); #endif - prm_port = (is_uds_mode) ? JAVASP_PORT_UDS_MODE : prm_get_integer_value (PRM_ID_JAVA_STORED_PROCEDURE_PORT); + prm_port = (is_uds_mode) ? PL_PORT_UDS_MODE : prm_get_integer_value (PRM_ID_STORED_PROCEDURE_PORT); return prm_port; } static int -javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name, const std::string &path) +pl_start_server (const PL_SERVER_INFO pl_info, const std::string &db_name, const std::string &path) { int status = NO_ERROR; - if (jsp_info.pid != JAVASP_PID_DISABLED && javasp_is_running (jsp_info.port, db_name)) + if (pl_info.pid != PL_PID_DISABLED && pl_is_running (pl_info, db_name)) { status = ER_GENERIC_ERROR; } @@ -420,14 +413,13 @@ javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_na setsid (); #endif er_clear (); // clear error before string JVM - status = jsp_start_server (db_name.c_str (), path.c_str (), javasp_get_port_param ()); - + status = pl_start_jvm_server (db_name.c_str (), path.c_str (), pl_get_port_param ()); if (status == NO_ERROR) { - JAVASP_SERVER_INFO jsp_new_info { getpid(), jsp_server_port () }; + PL_SERVER_INFO pl_new_info { getpid(), pl_server_port () }; - javasp_unlink_info (db_name.c_str ()); - if ((javasp_open_info_dir () && javasp_write_info (db_name.c_str (), jsp_new_info))) + pl_unlink_info (db_name.c_str ()); + if ((pl_open_info_dir () && pl_write_info (db_name.c_str (), pl_new_info))) { /* succeed */ } @@ -435,7 +427,7 @@ javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_na { /* failed to write info file */ char info_path[PATH_MAX], err_msg[PATH_MAX + 32]; - javasp_get_info_file (info_path, PATH_MAX, db_name.c_str ()); + pl_get_info_file (info_path, PATH_MAX, db_name.c_str ()); snprintf (err_msg, sizeof (err_msg), "Error while writing to file: (%s)", info_path); er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_START_JVM, 1, err_msg); status = ER_SP_CANNOT_START_JVM; @@ -447,77 +439,78 @@ javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_na } static int -javasp_stop_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name) +pl_stop_server (const PL_SERVER_INFO pl_info, const std::string &db_name) { - SOCKET socket = INVALID_SOCKET; - int status = NO_ERROR; +#define MAX_RETRY_COUNT 10 + int status = ER_FAILED; + int retry_count = 0; - socket = jsp_connect_server (db_name.c_str (), jsp_info.port); - if (socket != INVALID_SOCKET) + if (pl_info.pid != -1 && !is_terminated_process (pl_info.pid)) { - cubmethod::header header (DB_EMPTY_SESSION, SP_CODE_UTIL_TERMINATE_SERVER, 0); - status = mcon_send_data_to_java (socket, header); + terminate_process (pl_info.pid); - javasp_reset_info (db_name.c_str ()); - jsp_disconnect_server (socket); - - if (jsp_info.pid != -1 && !javasp_is_terminated_process (jsp_info.pid)) + while (retry_count < MAX_RETRY_COUNT) { - javasp_terminate_process (jsp_info.pid); + if (is_terminated_process (pl_info.pid) == true) + { + status = NO_ERROR; + break; + } + usleep (10); + retry_count++; } - - javasp_reset_info (db_name.c_str ()); } return status; } static int -javasp_status_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name) +pl_status_server (const PL_SERVER_INFO pl_info, const std::string &db_name) { int status = NO_ERROR; - SOCKET socket = INVALID_SOCKET; cubmem::block buffer; - socket = jsp_connect_server (db_name.c_str(), jsp_info.port); - if (socket != INVALID_SOCKET) + cubpl::connection_pool connection_pool (1, db_name, pl_info.port, true); + cubpl::connection_view cv = connection_pool.claim (); + if (cv->is_valid()) { cubmethod::header header (DB_EMPTY_SESSION, SP_CODE_UTIL_STATUS, 0); - status = mcon_send_data_to_java (socket, header); + status = cv->send_buffer_args (header); if (status != NO_ERROR) { goto exit; } - status = cubmethod::mcon_read_data_from_java (socket, buffer); + status = cv->receive_buffer (buffer); if (status != NO_ERROR) { goto exit; } - int num_args = 0; - JAVASP_STATUS_INFO status_info; + if (status == NO_ERROR) + { + int num_args = 0; + PL_STATUS_INFO status_info; - status_info.pid = jsp_info.pid; + status_info.pid = pl_info.pid; - packing_unpacker unpacker (buffer.ptr, buffer.dim); + packing_unpacker unpacker (buffer.ptr, buffer.dim); - unpacker.unpack_int (status_info.port); - unpacker.unpack_string (status_info.db_name); - unpacker.unpack_int (num_args); - std::string arg; - for (int i = 0; i < num_args; i++) - { - unpacker.unpack_string (arg); - status_info.vm_args.push_back (arg); - } + unpacker.unpack_int (status_info.port); + unpacker.unpack_string (status_info.db_name); + unpacker.unpack_int (num_args); + std::string arg; + for (int i = 0; i < num_args; i++) + { + unpacker.unpack_string (arg); + status_info.vm_args.push_back (arg); + } - javasp_dump_status (stdout, status_info); + pl_dump_status (stdout, status_info); + } } exit: - jsp_disconnect_server (socket); - if (buffer.ptr) { free_and_init (buffer.ptr); @@ -527,23 +520,24 @@ javasp_status_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_n } static int -javasp_ping_server (const int server_port, const char *db_name, char *buf) +pl_ping_server (const PL_SERVER_INFO pl_info, const char *db_name, char *buf) { int status = NO_ERROR; - SOCKET socket = INVALID_SOCKET; cubmem::block ping_blk {0, NULL}; - socket = jsp_connect_server (db_name, server_port); - if (socket != INVALID_SOCKET) + cubpl::connection_pool connection_pool (1, db_name, pl_info.port, true); + cubpl::connection_view cv = connection_pool.claim (); + + if (cv->is_valid()) { cubmethod::header header (DB_EMPTY_SESSION, SP_CODE_UTIL_PING, 0); - status = mcon_send_data_to_java (socket, header); + status = cv->send_buffer_args (header); if (status != NO_ERROR) { goto exit; } - status = cubmethod::mcon_read_data_from_java (socket, ping_blk); + status = cv->receive_buffer (ping_blk); if (status != NO_ERROR) { goto exit; @@ -557,14 +551,13 @@ javasp_ping_server (const int server_port, const char *db_name, char *buf) delete [] ping_blk.ptr; } - jsp_disconnect_server (socket); return er_errid (); } static void -javasp_dump_status (FILE *fp, JAVASP_STATUS_INFO status_info) +pl_dump_status (FILE *fp, PL_STATUS_INFO status_info) { - if (status_info.port == JAVASP_PORT_UDS_MODE) + if (status_info.port == PL_PORT_UDS_MODE) { fprintf (fp, "Java Stored Procedure Server (%s, pid %d, UDS)\n", status_info.db_name.c_str (), status_info.pid); } @@ -587,12 +580,12 @@ javasp_dump_status (FILE *fp, JAVASP_STATUS_INFO status_info) } static bool -javasp_is_running (const int server_port, const std::string &db_name) +pl_is_running (const PL_SERVER_INFO pl_info, const std::string &db_name) { // check server running bool result = false; - char buffer[JAVASP_PING_LEN] = {0}; - if (javasp_ping_server (server_port, db_name.c_str (), buffer) == NO_ERROR) + char buffer[PL_PING_LEN] = {0}; + if (pl_ping_server (pl_info, db_name.c_str (), buffer) == NO_ERROR) { if (db_name.compare (0, db_name.size (), buffer) == 0) { @@ -602,62 +595,11 @@ javasp_is_running (const int server_port, const std::string &db_name) return result; } -/* - * javasp_is_terminated_process () - - * return: - * pid(in): - * TODO there exists same function in file_io.c and util_service.c - */ -static bool -javasp_is_terminated_process (int pid) -{ -#if defined(WINDOWS) - HANDLE h_process; - - h_process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid); - if (h_process == NULL) - { - return true; - } - else - { - CloseHandle (h_process); - return false; - } -#else /* WINDOWS */ - if (kill (pid, 0) == -1) - { - return true; - } - else - { - return false; - } -#endif /* WINDOWS */ -} - -static void -javasp_terminate_process (int pid) -{ -#if defined(WINDOWS) - HANDLE phandle; - - phandle = OpenProcess (PROCESS_TERMINATE, FALSE, pid); - if (phandle) - { - TerminateProcess (phandle, 0); - CloseHandle (phandle); - } -#else /* ! WINDOWS */ - kill (pid, SIGTERM); -#endif /* ! WINDOWS */ -} - static int -javasp_get_server_info (const std::string &db_name, JAVASP_SERVER_INFO &info) +pl_get_server_info (const std::string &db_name, PL_SERVER_INFO &info) { - if (javasp_open_info_dir () - && javasp_read_info (db_name.c_str(), info)) + if (pl_open_info_dir () + && pl_read_info (db_name.c_str(), info)) { return NO_ERROR; } @@ -668,7 +610,7 @@ javasp_get_server_info (const std::string &db_name, JAVASP_SERVER_INFO &info) } static int -javasp_check_database (const std::string &db_name, std::string &path) +pl_check_database (const std::string &db_name, std::string &path) { int status = NO_ERROR; @@ -688,7 +630,7 @@ javasp_check_database (const std::string &db_name, std::string &path) } static int -javasp_check_argument (int argc, char *argv[], std::string &command, std::string &db_name) +pl_check_argument (int argc, char *argv[], std::string &command, std::string &db_name) { int status = NO_ERROR; @@ -706,7 +648,7 @@ javasp_check_argument (int argc, char *argv[], std::string &command, std::string else { status = ER_GENERIC_ERROR; - JAVASP_PRINT_ERR_MSG ("Invalid number of arguments: %d\n", argc); + PL_PRINT_ERR_MSG ("Invalid number of arguments: %d\n", argc); } if (status == NO_ERROR) @@ -717,7 +659,7 @@ javasp_check_argument (int argc, char *argv[], std::string &command, std::string if (it == commands.end()) { status = ER_GENERIC_ERROR; - JAVASP_PRINT_ERR_MSG ("Invalid command: %s\n", command.c_str ()); + PL_PRINT_ERR_MSG ("Invalid command: %s\n", command.c_str ()); } } diff --git a/src/executables/plcsql.cpp b/src/executables/plcsql.cpp index 44cea5b07e..f07325b72e 100644 --- a/src/executables/plcsql.cpp +++ b/src/executables/plcsql.cpp @@ -49,7 +49,7 @@ static std::string input_string; static bool verbose = false; // output -static PLCSQL_COMPILE_INFO compile_info; +static PLCSQL_COMPILE_RESPONSE compile_response; #define DB_PLCSQL_AS_ARGS(arg) \ arg.db_name.data(), arg.user_name.data(), arg.passwd.data(), NULL, DB_CLIENT_TYPE_PLCSQL_HELPER @@ -254,31 +254,37 @@ main (int argc, char *argv[]) PLCSQL_LOG ("[Compile PL/CSQL]"); /* Call network interface API to send a input file (PL/CSQL program) */ - if (plcsql_transfer_file (input_string, verbose, compile_info) != NO_ERROR) + + PLCSQL_COMPILE_REQUEST compile_request; + compile_request.code = input_string; + compile_request.mode = (verbose == true) ? "v" : ""; + compile_request.owner = "DBA"; // dummy + + if (plcsql_transfer_file (compile_request, compile_response) != NO_ERROR) { PLCSQL_LOG ("Transferring or Translating PL/CSQL program is failed"); goto exit_on_end; } - if (compile_info.err_code == 0) + if (compile_response.err_code == 0) { PLCSQL_LOG ("[Output File]"); - PLCSQL_LOG (compile_info.translated_code); + PLCSQL_LOG (compile_response.translated_code); PLCSQL_LOG ("[Stored Routine Definition]"); - PLCSQL_LOG (compile_info.register_stmt); + PLCSQL_LOG (compile_response.register_stmt); } else { PLCSQL_LOG ("[Compile Error Info]"); - PLCSQL_LOG ("error at : " << compile_info.err_line); - PLCSQL_LOG ("error message : " << compile_info.err_msg); + PLCSQL_LOG ("error at : " << compile_response.err_line); + PLCSQL_LOG ("error message : " << compile_response.err_msg); goto exit_on_end; } // Execute SQL { - const std::string &sql = compile_info.register_stmt; + const std::string &sql = compile_response.register_stmt; if (sql.empty ()) { PLCSQL_LOG_FORCE ("Invalid SQL string"); diff --git a/src/executables/server.c b/src/executables/server.c index c021d456ac..431e24a4c1 100644 --- a/src/executables/server.c +++ b/src/executables/server.c @@ -50,7 +50,6 @@ #include "system_parameter.h" #include "perf_monitor.h" #include "util_func.h" -#include "connection_sr.h" #if defined(WINDOWS) #include "wintcp.h" #else /* !defined (WINDOWS) */ @@ -207,6 +206,8 @@ CreateMiniDump (struct _EXCEPTION_POINTERS *pException, char *db_name) static void crash_handler (int signo, siginfo_t * siginfo, void *dummyp) { + int pid; + if (signo != SIGABRT && siginfo != NULL && siginfo->si_code <= 0) { register_fatal_signal_handler (signo); @@ -217,6 +218,47 @@ crash_handler (int signo, siginfo_t * siginfo, void *dummyp) { return; } + + if (!BO_IS_SERVER_RESTARTED () || !prm_get_bool_value (PRM_ID_AUTO_RESTART_SERVER)) + { + return; + } + + pid = fork (); + if (pid == 0) + { + char err_log[PATH_MAX]; + int ppid; + int fd, fd_max; + + fd_max = css_get_max_socket_fds (); + + for (fd = 3; fd < fd_max; fd++) + { + close (fd); + } + + ppid = getppid (); + while (1) + { + if (kill (ppid, 0) < 0) + { + break; + } + sleep (1); + } + + unmask_signal (signo); + + if (prm_get_string_value (PRM_ID_ER_LOG_FILE) != NULL) + { + snprintf (err_log, PATH_MAX, "%s.%d", prm_get_string_value (PRM_ID_ER_LOG_FILE), ppid); + rename (prm_get_string_value (PRM_ID_ER_LOG_FILE), err_log); + } + + execl (executable_path, executable_path, database_name, NULL); + exit (0); + } } #if !defined (NDEBUG) @@ -312,9 +354,6 @@ main (int argc, char **argv) hb_set_exec_path (executable_path); hb_set_argv (argv); - css_set_exec_path (executable_path); - css_set_argv (argv); - /* create a new session */ setsid (); #endif diff --git a/src/executables/unload_object.c b/src/executables/unload_object.c index afd3ebc55c..5e982ad672 100644 --- a/src/executables/unload_object.c +++ b/src/executables/unload_object.c @@ -133,6 +133,7 @@ static const char *prohibited_classes[] = { CT_DATATYPE_NAME, CT_STORED_PROC_NAME, CT_STORED_PROC_ARGS_NAME, + CT_STORED_PROC_CODE_NAME, CT_PARTITION_NAME, CT_COLLATION_NAME, CT_CHARSET_NAME, diff --git a/src/executables/unload_schema.c b/src/executables/unload_schema.c index e3a552b1db..12ef126b85 100644 --- a/src/executables/unload_schema.c +++ b/src/executables/unload_schema.c @@ -58,6 +58,7 @@ #include "object_print.h" #include "dbtype.h" #include "tde.h" +#include "sp_catalog.hpp" #define CLASS_NAME_MAX 80 @@ -158,9 +159,8 @@ typedef enum typedef enum { - SYNONYM_NAME, + SYNONYM_UNIQUE_NAME, SYNONYM_OWNER, - SYNONYM_OWNER_NAME, SYNONYM_IS_PUBLIC, SYNONYM_TARGET_NAME, SYNONYM_TARGET_OWNER_NAME, @@ -231,8 +231,13 @@ static void emit_method_def (extract_context & ctxt, print_output & output_ctx, static void emit_methfile_def (print_output & output_ctx, DB_METHFILE * methfile); static void emit_partition_parts (print_output & output_ctx, SM_PARTITION * partition_info, int partcnt); static void emit_partition_info (extract_context & ctxt, print_output & output_ctx, MOP clsobj); + +static int emit_stored_procedure_pre (extract_context & ctxt, print_output & output_ctx); +static int emit_stored_procedure_post (extract_context & ctxt, print_output & output_ctx); static int emit_stored_procedure_args (print_output & output_ctx, int arg_cnt, DB_SET * arg_set); -static int emit_stored_procedure (extract_context & ctxt, print_output & output_ctx); +static int emit_stored_procedure_code (extract_context & ctxt, print_output & output_ctx, const char *code_name, + const char *owner_name, DB_VALUE * comment); + static int emit_foreign_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes); static int emit_grant (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes); static void emit_unique_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes); @@ -266,7 +271,6 @@ static int create_filename_schema_info (const char *output_dirname, const char * const size_t filename_size); static void str_tolower (char *str); -static bool is_builtin_package_function (const char *sp_name); static PARSER_VARCHAR *do_recreate_where_clause_or_function_attr (PARSER_CONTEXT ** parser, const char *class_name, DB_CONSTRAINT * constraint, bool where_clause); @@ -1124,9 +1128,11 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) DB_QUERY_RESULT *query_result; DB_QUERY_ERROR query_error; DB_VALUE values[SYNONYM_VALUE_INDEX_MAX]; - const char *synonym_name = NULL; + char *synonym_name = NULL; DB_OBJECT *synonym_owner = NULL; - const char *synonym_owner_name = NULL; + const char *synonym_unique_name = NULL; + char synonym_owner_name[DB_MAX_IDENTIFIER_LENGTH]; + synonym_owner_name[0] = '\0'; int is_public = 0; const char *target_name = NULL; const char *target_owner_name = NULL; @@ -1139,27 +1145,26 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) size_t uppercase_user_size = 0; size_t query_size = 0; char *query = NULL; - char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' }; + char synonym_output_owner[DB_MAX_USER_LENGTH + 4]; + synonym_output_owner[0] = '\0'; DB_OBJLIST *cl = NULL; const char *name = NULL; - char temp_schema[DB_MAX_CLASS_LENGTH] = { '\0' }; + char temp_schema[DB_MAX_IDENTIFIER_LENGTH] = { '\0' }; // *INDENT-OFF* - const char *query_all = "SELECT [name], " - "[owner], " - "[owner].[name], " + const char *query_all = "SELECT [unique_name], " + "[owner], " "[is_public], " "[target_name], " - "[target_owner].[name], " + "LOWER([target_owner].[name]), " "[comment] " "FROM [_db_synonym]"; - const char *query_user = "SELECT [name], " + const char *query_user = "SELECT [unique_name], " "[owner], " - "[owner].[name], " "[is_public], " "[target_name], " - "[target_owner].[name], " + "LOWER([target_owner].[name]), " "[comment] " "FROM [_db_synonym]" "WHERE [owner].[name] = '%s'"; @@ -1223,8 +1228,7 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) /* Validation of the result value */ switch (i) { - case SYNONYM_NAME: - case SYNONYM_OWNER_NAME: + case SYNONYM_UNIQUE_NAME: case SYNONYM_TARGET_NAME: case SYNONYM_TARGET_OWNER_NAME: { @@ -1272,9 +1276,8 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) } } - synonym_name = db_get_string (&values[SYNONYM_NAME]); + synonym_unique_name = db_get_string (&values[SYNONYM_UNIQUE_NAME]); synonym_owner = db_get_object (&values[SYNONYM_OWNER]); - synonym_owner_name = db_get_string (&values[SYNONYM_OWNER_NAME]); is_public = db_get_int (&values[SYNONYM_IS_PUBLIC]); target_name = db_get_string (&values[SYNONYM_TARGET_NAME]); target_owner_name = db_get_string (&values[SYNONYM_TARGET_OWNER_NAME]); @@ -1291,8 +1294,7 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) { name = db_get_class_name (cl->op); - str_tolower ((char *) target_owner_name); - snprintf (temp_schema, DB_MAX_CLASS_LENGTH, "%s%s%s", (target_owner_name), ".", target_name); + snprintf (temp_schema, DB_MAX_IDENTIFIER_LENGTH, "%s%s%s", (target_owner_name), ".", target_name); if (strcmp (temp_schema, name) == 0) { @@ -1317,10 +1319,11 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) output_ctx ("CREATE PRIVATE"); } - PRINT_OWNER_NAME (synonym_owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner, - sizeof (output_owner)); + SPLIT_USER_SPECIFIED_NAME (synonym_unique_name, synonym_owner_name, synonym_name); + PRINT_OWNER_NAME (synonym_owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), synonym_output_owner, + sizeof (synonym_owner_name)); - output_ctx (" SYNONYM %s%s%s%s FOR %s%s%s.%s%s%s", output_owner, + output_ctx (" SYNONYM %s%s%s%s FOR %s%s%s.%s%s%s", synonym_output_owner, PRINT_IDENTIFIER (synonym_name), PRINT_IDENTIFIER (target_owner_name), PRINT_IDENTIFIER (target_name)); @@ -1432,7 +1435,7 @@ extract_schema (extract_context & ctxt, print_output & schema_output_ctx) err_count++; } - if (required_class_only == false && emit_stored_procedure (ctxt, schema_output_ctx) != NO_ERROR) + if (required_class_only == false && emit_stored_procedure_pre (ctxt, schema_output_ctx) != NO_ERROR) { err_count++; } @@ -1489,6 +1492,11 @@ extract_schema (extract_context & ctxt, print_output & schema_output_ctx) err_count++; } + if (required_class_only == false && emit_stored_procedure_post (ctxt, schema_output_ctx) != NO_ERROR) + { + err_count++; + } + if (ctxt.classes != NULL && (emit_foreign_key (ctxt, schema_output_ctx, ctxt.classes) != NO_ERROR)) { err_count++; @@ -4305,34 +4313,6 @@ emit_partition_info (extract_context & ctxt, print_output & output_ctx, MOP clso output_ctx (";\n"); } -// TODO: quick fix -static bool -is_builtin_package_function (const char *sp_name) -{ - static const char *builtin_list[] = { - "enable", - "disable", - "put", - "put_line", - "new_line", - "get_line", - "get_lines", - NULL - }; - - int dim, i; - - dim = DIM (builtin_list); - for (i = 0; i < dim; i++) - { - if (builtin_list[i] != NULL && strcasecmp (builtin_list[i], sp_name) == 0) - { - return true; - } - } - return false; -} - /* * emit_stored_procedure_args - emit stored procedure arguments * return: 0 if success, error count otherwise @@ -4405,21 +4385,26 @@ emit_stored_procedure_args (print_output & output_ctx, int arg_cnt, DB_SET * arg } /* - * emit_stored_procedure - emit stored procedure + * emit_stored_procedure_pre - emit stored procedure (Dummy PL/CSQL and Java SP) * return: void * output_ctx(in/out): output context */ static int -emit_stored_procedure (extract_context & ctxt, print_output & output_ctx) +emit_stored_procedure_pre (extract_context & ctxt, print_output & output_ctx) { MOP cls, obj, owner; DB_OBJLIST *sp_list = NULL, *cur_sp; - DB_VALUE sp_name_val, sp_type_val, arg_cnt_val, args_val, rtn_type_val, method_val, comment_val; + DB_VALUE unique_name_val, sp_name_val, pkg_name_val, sp_type_val, arg_cnt_val, lang_val, generated_val, args_val, + rtn_type_val, class_val, method_val, directive_val, comment_val; DB_VALUE owner_val, owner_name_val; - int sp_type, rtn_type, arg_cnt, save; + int sp_type, rtn_type, arg_cnt, directive, save; DB_SET *arg_set; int err; int err_count = 0; + char owner_name[DB_MAX_USER_LENGTH]; + owner_name[0] = '\0'; + char output_owner[DB_MAX_USER_LENGTH + 4]; + output_owner[0] = '\0'; AU_DISABLE (save); @@ -4435,45 +4420,72 @@ emit_stored_procedure (extract_context & ctxt, print_output & output_ctx) { obj = cur_sp->op; - if ((err = db_get (obj, SP_ATTR_SP_TYPE, &sp_type_val)) != NO_ERROR - || (err = db_get (obj, SP_ATTR_NAME, &sp_name_val)) != NO_ERROR - || (err = db_get (obj, SP_ATTR_ARG_COUNT, &arg_cnt_val)) != NO_ERROR - || (err = db_get (obj, SP_ATTR_ARGS, &args_val)) != NO_ERROR - || ((err = db_get (obj, SP_ATTR_RETURN_TYPE, &rtn_type_val)) != NO_ERROR) - || (err = db_get (obj, SP_ATTR_TARGET, &method_val)) != NO_ERROR - || (err = db_get (obj, SP_ATTR_OWNER, &owner_val)) != NO_ERROR - || (err = db_get (obj, SP_ATTR_COMMENT, &comment_val)) != NO_ERROR) + if ((err = db_get (obj, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_LANG, &lang_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_OWNER, &owner_val)) != NO_ERROR) { err_count++; continue; } - const char *sp_name = db_get_string (&sp_name_val); - if (is_builtin_package_function (sp_name)) + if (db_get_int (&generated_val) == 1) { continue; } - if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false) + // owner + owner = db_get_object (&owner_val); + err = db_get (owner, "name", &owner_name_val); + if (err != NO_ERROR) { - owner = db_get_object (&owner_val); - err = db_get (owner, "name", &owner_name_val); - if (err != NO_ERROR) - { - err_count++; - continue; - } + err_count++; + continue; + } + if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false) + { if (strcasecmp (ctxt.login_user, db_get_string (&owner_name_val)) != 0) { + db_value_clear (&owner_name_val); continue; } } + if ((err = db_get (obj, SP_ATTR_SP_TYPE, &sp_type_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_UNIQUE_NAME, &unique_name_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_NAME, &sp_name_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_PKG, &pkg_name_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_ARG_COUNT, &arg_cnt_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_ARGS, &args_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_RETURN_TYPE, &rtn_type_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_DIRECTIVE, &directive_val)) != NO_ERROR) + { + err_count++; + continue; + } + sp_type = db_get_int (&sp_type_val); + output_ctx ("\nCREATE %s", sp_type == SP_TYPE_PROCEDURE ? "PROCEDURE" : "FUNCTION"); - output_ctx (" %s%s%s (", PRINT_IDENTIFIER (db_get_string (&sp_name_val))); + // unique_name + const char *unique_name = db_get_string (&unique_name_val); + // sp_name + const char *sp_name = db_get_string (&sp_name_val); + sm_qualifier_name (unique_name, owner_name, DB_MAX_USER_LENGTH); + PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner, + sizeof (output_owner)); + + if (!DB_IS_NULL (&pkg_name_val)) + { + const char *pkg_name = db_get_string (&pkg_name_val); + output_ctx (" %s%s%s.%s%s%s (", PRINT_IDENTIFIER (pkg_name), PRINT_IDENTIFIER (sp_name)); + db_value_clear (&pkg_name_val); + } + else + { + output_ctx (" %s%s%s%s (", output_owner, PRINT_IDENTIFIER (sp_name)); + } arg_cnt = db_get_int (&arg_cnt_val); arg_set = db_get_set (&args_val); @@ -4499,16 +4511,104 @@ emit_stored_procedure (extract_context & ctxt, print_output & output_ctx) } } - output_ctx ("AS LANGUAGE JAVA NAME '%s'", db_get_string (&method_val)); + // authid + directive = db_get_int (&directive_val); + if (directive & SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_CALLER) + { + output_ctx ("AUTHID CALLER "); + } + else + { + output_ctx ("AUTHID OWNER "); + } - if (!DB_IS_NULL (&comment_val)) + int sp_lang = db_get_int (&lang_val); + if (sp_lang == SP_LANG_PLCSQL) { - output_ctx (" COMMENT "); - desc_value_print (output_ctx, &comment_val); + output_ctx ("AS LANGUAGE PLCSQL BEGIN "); + output_ctx + ("RAISE_APPLICATION_ERROR(1000, '%s%s%s%s: incomplete during loaddb'); /* __CUBRID_NO_BODY__ */", + output_owner, PRINT_IDENTIFIER (sp_name)); + output_ctx (" END;\n"); } + else + { + if ((err = db_get (obj, SP_ATTR_TARGET_CLASS, &class_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_TARGET_METHOD, &method_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_COMMENT, &comment_val)) != NO_ERROR) + { + err_count++; + continue; + } - output_ctx (";\n"); + output_ctx ("AS LANGUAGE JAVA NAME '%s.%s'", db_get_string (&class_val), db_get_string (&method_val)); + db_value_clear (&class_val); + db_value_clear (&method_val); + + if (!DB_IS_NULL (&comment_val)) + { + output_ctx (" COMMENT "); + desc_value_print (output_ctx, &comment_val); + } + output_ctx (";\n"); + } + db_value_clear (&sp_name_val); + db_value_clear (&unique_name_val); + db_value_clear (&owner_name_val); + } + + db_objlist_free (sp_list); + AU_ENABLE (save); + + return err_count; +} + +/* + * emit_stored_procedure_post - emit stored procedure + * return: void + * output_ctx(in/out): output context + */ +static int +emit_stored_procedure_post (extract_context & ctxt, print_output & output_ctx) +{ + MOP cls, obj, owner; + DB_OBJLIST *sp_list = NULL, *cur_sp; + DB_VALUE lang_val, owner_val, owner_name_val, generated_val, class_val, comment_val; + int save; + int err; + int err_count = 0; + const char *owner_name; + + AU_DISABLE (save); + + cls = db_find_class (SP_CLASS_NAME); + if (cls == NULL) + { + AU_ENABLE (save); + return 1; + } + + sp_list = db_get_all_objects (cls); + for (cur_sp = sp_list; cur_sp; cur_sp = cur_sp->next) + { + obj = cur_sp->op; + + if ((err = db_get (obj, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_LANG, &lang_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_OWNER, &owner_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_COMMENT, &comment_val)) != NO_ERROR) + { + err_count++; + continue; + } + + if (db_get_int (&generated_val) == 1) + { + continue; + } + + // owner owner = db_get_object (&owner_val); err = db_get (owner, "name", &owner_name_val); if (err != NO_ERROR) @@ -4517,10 +4617,35 @@ emit_stored_procedure (extract_context & ctxt, print_output & output_ctx) continue; } - if (ctxt.is_dba_user || ctxt.is_dba_group_member) + owner_name = db_get_string (&owner_name_val); + if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false) { - output_ctx ("call [change_sp_owner]('%s', '%s') on class [db_root];\n", db_get_string (&sp_name_val), - db_get_string (&owner_name_val)); + if (strcasecmp (ctxt.login_user, owner_name) != 0) + { + db_value_clear (&owner_name_val); + continue; + } + } + + int sp_lang = db_get_int (&lang_val); + if (sp_lang == SP_LANG_PLCSQL) + { + if ((err = db_get (obj, SP_ATTR_TARGET_CLASS, &class_val)) != NO_ERROR) + { + err_count++; + continue; + } + + const char *target_class = db_get_string (&class_val); + err = emit_stored_procedure_code (ctxt, output_ctx, target_class, owner_name, &comment_val); + output_ctx ("\n"); + + db_value_clear (&class_val); + if (err > 0) + { + err_count++; + continue; + } } db_value_clear (&owner_name_val); @@ -4532,6 +4657,112 @@ emit_stored_procedure (extract_context & ctxt, print_output & output_ctx) return err_count; } +/* + * emit_stored_procedure_code - emit stored procedure code + * return: 0 if success, error count otherwise + * code_name(in): code name + * owner_name(in): owner name + */ +static int +emit_stored_procedure_code (extract_context & ctxt, print_output & output_ctx, const char *code_name, + const char *owner_name, DB_VALUE * comment) +{ + MOP obj; + int save, err = NO_ERROR; + DB_VALUE value, stype_val, scode_val; + int stype; + PARSER_CONTEXT *parser = NULL; + PT_NODE **scode_ptr; + char *scode_ptr_result = NULL; + char downcase_owner_name[DB_MAX_USER_LENGTH]; + downcase_owner_name[0] = '\0'; + + AU_DISABLE (save); + + db_make_string (&value, code_name); + obj = db_find_unique (db_find_class (SP_CODE_CLASS_NAME), SP_ATTR_CLS_NAME, &value); + if (obj == NULL) + { + err = ER_FAILED; + goto exit; + } + + + if ((err = db_get (obj, SP_ATTR_SOURCE_TYPE, &stype_val)) != NO_ERROR + || (err = db_get (obj, SP_ATTR_SOURCE_CODE, &scode_val)) != NO_ERROR) + { + goto exit; + } + + stype = db_get_int (&stype_val); + if (stype == SPSC_PLCSQL) + { + const char *scode = db_get_string (&scode_val); + parser = parser_create_parser (); + if (parser == NULL) + { + err = ER_FAILED; + goto exit; + } + + scode_ptr = parser_parse_string (parser, scode); + if (scode_ptr != NULL) + { + if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false) + { + parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME; + } + else + { + PT_NODE *sp_name = (*scode_ptr)->info.sp.name; + if (sp_name->info.name.resolved == NULL) + { + sm_downcase_name (owner_name, downcase_owner_name, DB_MAX_USER_LENGTH); + sp_name->info.name.resolved = pt_append_string (parser, NULL, downcase_owner_name); + } + } + + parser->flag.is_parsing_unload_schema = 1; + scode_ptr_result = parser_print_tree_with_quotes (parser, *scode_ptr); + } + + if (scode_ptr_result) + { + output_ctx ("\n%s", scode_ptr_result); + if (!DB_IS_NULL (comment)) + { + if ((*scode_ptr)->info.sp.comment == NULL) + { + output_ctx ("\nCOMMENT "); + } + else + { + output_ctx ("COMMENT "); + } + desc_value_print (output_ctx, comment); + } + } + else + { + output_ctx ("\n/* error occurs: %s \n\n %s; \n*/", parser->error_buffer ? parser->error_buffer : "", scode); + } + } + output_ctx (";"); + +exit: + + if (parser) + { + parser_free_parser (parser); + } + + db_value_clear (&value); + db_value_clear (&scode_val); + AU_ENABLE (save); + + return err; +} + /* * emit_foreign_key - emit foreign key * return: NO_ERROR if successful, error code otherwise @@ -5161,7 +5392,12 @@ extract_procedure (extract_context & ctxt) if (required_class_only == false) { - err = emit_stored_procedure (ctxt, output_ctx); + err = emit_stored_procedure_pre (ctxt, output_ctx); + } + + if (required_class_only == false) + { + err = emit_stored_procedure_post (ctxt, output_ctx); } fflush (output_file); @@ -5790,8 +6026,9 @@ static int emit_grant (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes) { int err = NO_ERROR; - DB_OBJLIST *cl; + DB_OBJLIST *cl, *cls, *sp_list = NULL; const char *name; + MOP sp_owner; int is_partitioned = 0; if (ctxt.do_auth) @@ -5803,7 +6040,21 @@ emit_grant (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * clas { continue; } - err = au_export_grants (ctxt, output_ctx, cl->op); + err = au_export_grants (ctxt, output_ctx, cl->op, DB_OBJECT_CLASS); + } + + sp_list = db_get_all_objects (db_find_class (SP_CLASS_NAME)); + for (cls = sp_list; cls; cls = cls->next) + { + if (!au_is_dba_group_member (Au_user)) + { + sp_owner = jsp_get_owner (cls->op); + if (!ws_is_same_object (sp_owner, Au_user)) + { + continue; + } + } + err = au_export_grants (ctxt, output_ctx, cls->op, DB_OBJECT_PROCEDURE); } } @@ -5902,11 +6153,6 @@ extract_split_schema_files (extract_context & ctxt) err_count++; } - if (extract_procedure (ctxt) != NO_ERROR) - { - err_count++; - } - if (extract_server (ctxt) != NO_ERROR) { err_count++; @@ -5937,6 +6183,11 @@ extract_split_schema_files (extract_context & ctxt) err_count++; } + if (extract_procedure (ctxt) != NO_ERROR) + { + err_count++; + } + if (extract_pk (ctxt) != NO_ERROR) { err_count++; diff --git a/src/executables/unloaddb.c b/src/executables/unloaddb.c index 05d488089d..94ff8b90e4 100644 --- a/src/executables/unloaddb.c +++ b/src/executables/unloaddb.c @@ -263,8 +263,6 @@ unloaddb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", database_name, exec_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - /* support for SUPPORT_DEDUPLICATE_KEY_MODE */ sysprm_set_force (prm_get_name (PRM_ID_PRINT_INDEX_DETAIL), utility_get_option_bool_value (arg_map, UNLOAD_SKIP_INDEX_DETAIL_S) ? "no" : "yes"); diff --git a/src/executables/util_cs.c b/src/executables/util_cs.c index e97863db6f..b6e83d6e0d 100644 --- a/src/executables/util_cs.c +++ b/src/executables/util_cs.c @@ -263,8 +263,6 @@ backupdb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", database_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); /* disable authorization for this operation */ db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -482,7 +480,6 @@ addvoldb (UTIL_FUNCTION_ARG * arg) /* tuning system parameters */ sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); @@ -786,8 +783,6 @@ checkdb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", database_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -973,7 +968,6 @@ spacedb (UTIL_FUNCTION_ARG * arg) /* tuning system parameters */ sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); /* should have little copyright herald message ? */ AU_DISABLE_PASSWORDS (); @@ -2293,8 +2287,6 @@ paramdump (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", database_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - #if defined (CS_MODE) /* should have little copyright herald message ? */ AU_DISABLE_PASSWORDS (); @@ -3672,8 +3664,6 @@ vacuumdb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", database_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); if (dump_flag) { diff --git a/src/executables/util_sa.c b/src/executables/util_sa.c index fab2803d74..0027979cf3 100644 --- a/src/executables/util_sa.c +++ b/src/executables/util_sa.c @@ -634,7 +634,6 @@ createdb (UTIL_FUNCTION_ARG * arg) /* tuning system parameters */ sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); sysprm_set_force (prm_get_name (PRM_ID_XASL_CACHE_MAX_ENTRIES), "-1"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); sysprm_set_force (prm_get_name (PRM_ID_SUPPLEMENTAL_LOG), "0"); AU_DISABLE_PASSWORDS (); @@ -709,26 +708,6 @@ createdb (UTIL_FUNCTION_ARG * arg) db_commit_transaction (); - { - /* FIXME!! Register Built-in Packages, The following lines should be moved */ - char built_in_package_spec[7][1024] = { - "CREATE OR REPLACE PROCEDURE enable (s INT) AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.enable(int)';", - "CREATE OR REPLACE PROCEDURE disable () AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.disable()';", - "CREATE OR REPLACE PROCEDURE put (str String) AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.put(java.lang.String)';", - "CREATE OR REPLACE PROCEDURE put_line (str STRING) AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.putLine(java.lang.String)';", - "CREATE OR REPLACE PROCEDURE new_line () AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.newLine()';", - "CREATE OR REPLACE PROCEDURE get_line (line OUT STRING, status OUT INT) AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.getLine(java.lang.String[], int[])';", - "CREATE OR REPLACE PROCEDURE get_lines (lines OUT STRING, cnt OUT INT) AS LANGUAGE JAVA NAME 'com.cubrid.plcsql.builtin.DBMS_OUTPUT.getLines(java.lang.String[], int[])';" - }; - - for (int i = 0; i < 7; i++) - { - execute_query (built_in_package_spec[i]); - } - - db_commit_transaction (); - } - if (user_define_file != NULL) { if (parse_user_define_file (user_define_file, output_file) != NO_ERROR) @@ -836,7 +815,6 @@ deletedb (UTIL_FUNCTION_ARG * arg) /* tuning system parameters */ sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); @@ -1065,8 +1043,6 @@ restoredb (UTIL_FUNCTION_ARG * arg) return EXIT_SUCCESS; } - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -1151,7 +1127,6 @@ renamedb (UTIL_FUNCTION_ARG * arg) /* tuning system parameters */ sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); @@ -1264,8 +1239,6 @@ installdb (UTIL_FUNCTION_ARG * arg) cfg_added = true; - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -1375,7 +1348,6 @@ copydb (UTIL_FUNCTION_ARG * arg) /* tuning system parameters */ sysprm_set_force (prm_get_name (PRM_ID_PB_NBUFFERS), "1024"); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); @@ -1458,8 +1430,6 @@ optimizedb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", db_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -1608,8 +1578,6 @@ diagdb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", db_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -2768,8 +2736,6 @@ synccolldb (UTIL_FUNCTION_ARG * arg) snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_%s.err", db_name, arg->command_name); er_init (er_msg_file, ER_NEVER_EXIT); - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); @@ -4751,8 +4717,6 @@ restoreslave (UTIL_FUNCTION_ARG * arg) return EXIT_SUCCESS; } - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - AU_DISABLE_PASSWORDS (); db_set_client_type (DB_CLIENT_TYPE_ADMIN_UTILITY); db_login ("DBA", NULL); diff --git a/src/executables/util_service.c b/src/executables/util_service.c index 270286b9e4..3511fa6f14 100644 --- a/src/executables/util_service.c +++ b/src/executables/util_service.c @@ -52,6 +52,7 @@ #include "release_string.h" #include "dynamic_array.h" #include "heartbeat.h" +#include "process_util.h" #include @@ -69,8 +70,8 @@ typedef enum UTIL_HELP = 6, UTIL_VERSION = 7, ADMIN = 8, - JAVASP_UTIL = 20, - GATEWAY = 21 + PL_UTIL = 20, // JAVASP_UTIL + GATEWAY = 21, } UTIL_SERVICE_INDEX_E; typedef enum @@ -119,10 +120,11 @@ typedef enum typedef enum { - JAVASP_SERVER_RUNNING = 0, - JAVASP_SERVER_STOPPED, - JAVASP_SERVER_STATUS_ERROR -} UTIL_JAVASP_SERVER_STATUS_E; + PL_SERVER_RUNNING = 0, + PL_SERVER_STOPPED, + PL_SERVER_STATUS_ERROR, + PL_SERVER_STARTING +} UTIL_PL_SERVER_STATUS_E; typedef struct { @@ -143,7 +145,7 @@ typedef struct #define UTIL_TYPE_MANAGER "manager" #define UTIL_TYPE_HEARTBEAT "heartbeat" #define UTIL_TYPE_HB_SHORT "hb" -#define UTIL_TYPE_JAVASP "javasp" +#define UTIL_TYPE_PL "pl" #define UTIL_TYPE_GATEWAY "gateway" static UTIL_SERVICE_OPTION_MAP_T us_Service_map[] = { @@ -153,7 +155,7 @@ static UTIL_SERVICE_OPTION_MAP_T us_Service_map[] = { {MANAGER, UTIL_TYPE_MANAGER, MASK_MANAGER}, {HEARTBEAT, UTIL_TYPE_HEARTBEAT, MASK_HEARTBEAT}, {HEARTBEAT, UTIL_TYPE_HB_SHORT, MASK_HEARTBEAT}, - {JAVASP_UTIL, UTIL_TYPE_JAVASP, MASK_JAVASP}, + {PL_UTIL, UTIL_TYPE_PL, MASK_PL}, {GATEWAY, UTIL_TYPE_GATEWAY, MASK_GATEWAY}, {UTIL_HELP, "--help", MASK_ALL}, {UTIL_VERSION, "--version", MASK_ALL}, @@ -223,7 +225,7 @@ static UTIL_SERVICE_OPTION_MAP_T us_Service_map[] = { static UTIL_SERVICE_OPTION_MAP_T us_Command_map[] = { {START, COMMAND_TYPE_START, MASK_ALL}, {STOP, COMMAND_TYPE_STOP, MASK_ALL}, - {RESTART, COMMAND_TYPE_RESTART, MASK_SERVICE | MASK_SERVER | MASK_BROKER | MASK_GATEWAY | MASK_JAVASP}, + {RESTART, COMMAND_TYPE_RESTART, MASK_SERVICE | MASK_SERVER | MASK_BROKER | MASK_GATEWAY | MASK_PL}, {STATUS, COMMAND_TYPE_STATUS, MASK_ALL}, {DEREGISTER, COMMAND_TYPE_DEREG, MASK_HEARTBEAT}, {LIST, COMMAND_TYPE_LIST, MASK_HEARTBEAT}, @@ -270,11 +272,10 @@ static int process_server (int command_type, int argc, char **argv, bool show_us static int process_broker (int command_type, int argc, const char **argv, bool process_window_service); static int process_gateway (int command_type, int argc, const char **argv, bool process_window_service); static int process_manager (int command_type, bool process_window_service); -static int process_javasp (int command_type, int argc, const char **argv, bool show_usage, bool suppress_message, - bool process_window_service, bool ha_mode); -static int process_javasp_start (const char *db_name, bool suppress_message, bool process_window_service); -static int process_javasp_stop (const char *db_name, bool suppress_message, bool process_window_service); -static int process_javasp_status (const char *db_name, bool suppress_message); +static int process_pl (int command_type, int argc, const char **argv, bool show_usage, bool suppress_message, + bool process_window_service, bool ha_mode); +static int process_pl_restart (const char *db_name, bool suppress_message, bool process_window_service); +static int process_pl_status (const char *db_name, bool suppress_message); static int process_heartbeat (int command_type, int argc, const char **argv); static int process_heartbeat_start (HA_CONF * ha_conf, int argc, const char **argv); static int process_heartbeat_stop (HA_CONF * ha_conf, int argc, const char **argv); @@ -294,15 +295,13 @@ static void hide_cmd_line_args (char **args); static int process_master (int command_type); static void print_message (FILE * output, int message_id, ...); static void print_result (const char *util_name, int status, int command_type); -static bool is_terminated_process (const int pid); static char *make_exec_abspath (char *buf, int buf_len, char *cmd); static const char *command_string (int command_type); static bool is_server_running (const char *type, const char *server_name, int pid); -static int shutdown_reviving_server (const char *server_name); static int is_broker_running (void); static int is_gateway_running (void); static UTIL_MANAGER_SERVER_STATUS_E is_manager_running (unsigned int sleep_time); -static UTIL_JAVASP_SERVER_STATUS_E is_javasp_running (const char *server_name); +static UTIL_PL_SERVER_STATUS_E is_pl_running (const char *server_name); static void get_server_names (const char *type, char **name_buffer); #if defined(WINDOWS) @@ -377,6 +376,9 @@ command_string (int command_type) case START: command = PRINT_CMD_START; break; + case RESTART: + command = PRINT_CMD_RESTART; + break; case STATUS: command = PRINT_CMD_STATUS; break; @@ -659,7 +661,7 @@ main (int argc, char *argv[]) { process_window_service = false; } - else if ((util_type == SERVER || util_type == BROKER || util_type == GATEWAY || util_type == JAVASP_UTIL) + else if ((util_type == SERVER || util_type == BROKER || util_type == GATEWAY || util_type == PL_UTIL) && (argc > 4) && strcmp ((char *) argv[4], "--for-windows-service") == 0) { process_window_service = false; @@ -692,9 +694,9 @@ main (int argc, char *argv[]) status = process_heartbeat (command_type, argc - 3, (const char **) &argv[3]); #endif /* !WINDOWs */ break; - case JAVASP_UTIL: + case PL_UTIL: // PL_UTIL status = - process_javasp (command_type, argc - 3, (const char **) &argv[3], true, false, process_window_service, false); + process_pl (command_type, argc - 3, (const char **) &argv[3], true, false, process_window_service, false); break; case GATEWAY: status = process_gateway (command_type, argc - 3, (const char **) &argv[3], process_window_service); @@ -1361,8 +1363,6 @@ process_service (int command_type, bool process_window_service) { if (!are_all_services_stopped (0, process_window_service)) { - (void) process_javasp (command_type, 0, NULL, false, false, process_window_service, false); - if (strcmp (get_property (SERVICE_START_SERVER), PROPERTY_ON) == 0 && us_Property_map[SERVER_START_LIST].property_value != NULL && us_Property_map[SERVER_START_LIST].property_value[0] != '\0') @@ -1418,7 +1418,7 @@ process_service (int command_type, bool process_window_service) const char *args[] = { "-b" }; (void) process_server (command_type, 0, NULL, false, true, false); - (void) process_javasp (command_type, 0, NULL, true, false, false, false); + (void) process_pl (command_type, 0, NULL, true, false, false, false); (void) process_broker (command_type, 1, args, false); (void) process_gateway (command_type, 1, args, false); (void) process_manager (command_type, false); @@ -1606,22 +1606,6 @@ is_server_running (const char *type, const char *server_name, int pid) } } -/* - * shutdown_reviving_server - - * - * return: - * - * type(in): - * server_name(in): - * pid(in): - */ -static int -shutdown_reviving_server (const char *server_name) -{ - const char *args[] = { UTIL_COMMDB_NAME, COMMDB_SHUTDOWN_REVIVING_SERVER, server_name, NULL }; - return proc_execute (UTIL_COMMDB_NAME, args, true, false, false, NULL); -} - /* * process_server - * @@ -1788,13 +1772,6 @@ process_server (int command_type, int argc, char **argv, bool show_usage, bool c status = ER_GENERIC_ERROR; } print_result (PRINT_SERVER_NAME, status, command_type); - - /* run javasp server if DB server is started successfully */ - if (status == NO_ERROR) - { - (void) process_javasp (command_type, 1, (const char **) &token, false, true, - process_window_service, false); - } } } } @@ -1808,13 +1785,6 @@ process_server (int command_type, int argc, char **argv, bool show_usage, bool c break; } - /* try to stop javasp server first */ - if (is_javasp_running (token) == JAVASP_SERVER_RUNNING) - { - (void) process_javasp (command_type, 1, (const char **) &token, false, true, process_window_service, - false); - } - print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_3S, PRINT_SERVER_NAME, PRINT_CMD_STOP, token); if (is_server_running (CHECK_SERVER, token, 0)) @@ -1862,7 +1832,6 @@ process_server (int command_type, int argc, char **argv, bool show_usage, bool c status = ER_GENERIC_ERROR; print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_SERVER_NAME, token); util_log_write_errid (MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_SERVER_NAME, token); - shutdown_reviving_server (token); } } break; @@ -2795,14 +2764,14 @@ process_manager (int command_type, bool process_window_service) } /* - * is_javasp_running - + * is_pl_running - * * return: * */ -static UTIL_JAVASP_SERVER_STATUS_E -is_javasp_running (const char *server_name) +static UTIL_PL_SERVER_STATUS_E +is_pl_running (const char *server_name) { static const char PING_CMD[] = " ping "; static const int PING_CMD_LEN = sizeof (PING_CMD); @@ -2811,7 +2780,7 @@ is_javasp_running (const char *server_name) char buf[PATH_MAX] = { 0 }; char cmd[PATH_MAX] = { 0 }; - (void) envvar_bindir_file (cmd, PATH_MAX, UTIL_JAVASP_NAME); + (void) envvar_bindir_file (cmd, PATH_MAX, UTIL_PL_NAME); strcat (cmd, PING_CMD); strcat (cmd, server_name); @@ -2819,195 +2788,161 @@ is_javasp_running (const char *server_name) input = popen (cmd, "r"); if (input == NULL) { - return JAVASP_SERVER_STATUS_ERROR; + return PL_SERVER_STATUS_ERROR; } memset (buf, '\0', sizeof (buf)); if (fgets (buf, PATH_MAX, input) == NULL) { pclose (input); - return JAVASP_SERVER_STATUS_ERROR; + return PL_SERVER_STATUS_ERROR; } if (strcmp (buf, server_name) == 0) { pclose (input); - return JAVASP_SERVER_RUNNING; + return PL_SERVER_RUNNING; + } + else if (strcmp (buf, "NO_PROCESS") == 0) + { + pclose (input); + return PL_SERVER_STOPPED; } else if (strcmp (buf, "NO_CONNECTION") == 0) { pclose (input); - return JAVASP_SERVER_STOPPED; + return PL_SERVER_STARTING; } else { pclose (input); - return JAVASP_SERVER_STATUS_ERROR; + return PL_SERVER_STATUS_ERROR; } } static int -process_javasp_start (const char *db_name, bool suppress_message, bool process_window_service) +process_pl_restart (const char *db_name, bool suppress_message, bool process_window_service) { - static const int wait_timeout = 30; + int status = NO_ERROR; + static const int wait_timeout = 10; int waited_secs = 0; - int pid = 0; - int status = ER_GENERIC_ERROR; if (!suppress_message) { - print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_3S, PRINT_JAVASP_NAME, PRINT_CMD_START, db_name); + print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_3S, PRINT_PL_NAME, PRINT_CMD_RESTART, db_name); } - UTIL_JAVASP_SERVER_STATUS_E javasp_status = is_javasp_running (db_name); - if (javasp_status == JAVASP_SERVER_RUNNING) + if (!is_server_running (CHECK_SERVER, db_name, 0)) { + status = ER_GENERIC_ERROR; if (!suppress_message) { - print_message (stdout, MSGCAT_UTIL_GENERIC_ALREADY_RUNNING_2S, PRINT_JAVASP_NAME, db_name); + print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_SERVER_NAME, db_name); } - util_log_write_errid (MSGCAT_UTIL_GENERIC_ALREADY_RUNNING_2S, PRINT_JAVASP_NAME, db_name); } - else + + if (status == NO_ERROR) { if (process_window_service) { #if defined(WINDOWS) - const char *args[] = { UTIL_WIN_SERVICE_CONTROLLER_NAME, PRINT_CMD_JAVASP, - COMMAND_TYPE_START, db_name, NULL + const char *args[] = { UTIL_WIN_SERVICE_CONTROLLER_NAME, PRINT_CMD_PL, + COMMAND_TYPE_STOP, db_name, NULL }; + status = proc_execute (UTIL_WIN_SERVICE_CONTROLLER_NAME, args, true, false, false, NULL); #endif } else { - const char *args[] = { UTIL_JAVASP_NAME, db_name, NULL }; - status = proc_execute (UTIL_JAVASP_NAME, args, false, false, false, &pid); + const char *args[] = { UTIL_PL_NAME, COMMAND_TYPE_STOP, db_name, NULL }; + status = proc_execute (UTIL_PL_NAME, args, true, false, false, NULL); + sleep (1); } - status = ER_GENERIC_ERROR; - while (status != NO_ERROR && waited_secs < wait_timeout) + UTIL_PL_SERVER_STATUS_E pl_status; + do { - if (pid != 0 && is_terminated_process (pid)) - { - break; - } + // The pl server needs a few seconds to accept ping request + pl_status = is_pl_running (db_name); + status = (pl_status == PL_SERVER_RUNNING) ? NO_ERROR : ER_GENERIC_ERROR; + sleep (1); // wait to stop - javasp_status = is_javasp_running (db_name); - if (javasp_status == JAVASP_SERVER_RUNNING) + if (!is_server_running (CHECK_SERVER, db_name, 0)) { - status = NO_ERROR; - break; - } - else - { - sleep (1); /* wait to start */ - waited_secs++; - - if (javasp_status == JAVASP_SERVER_STOPPED) - { - util_log_write_errstr ("Waiting for javasp server to start... (%d / %d)\n", waited_secs, - wait_timeout); - } - else + status = ER_GENERIC_ERROR; + if (!suppress_message) { - if (waited_secs > 3) - { - /* invalid database name or failed to open info file, wait upto 3 seconds */ - break; - } + print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_SERVER_NAME, db_name); } + break; } + + waited_secs++; } - if (!suppress_message) - { - print_result (PRINT_JAVASP_NAME, status, START); - } - else - { - fprintf (stdout, "Calling java stored procedure %s allowed\n", (status == NO_ERROR) ? "is" : "is not"); - } + while (status != NO_ERROR && waited_secs < wait_timeout); + } + + if (!suppress_message) + { + print_result (PRINT_PL_NAME, status, RESTART); } + return status; } static int -process_javasp_stop (const char *db_name, bool suppress_message, bool process_window_service) +process_pl_status (const char *db_name) { int status = NO_ERROR; - static const int wait_timeout = 5; + + static const int wait_timeout = 10; int waited_secs = 0; + UTIL_PL_SERVER_STATUS_E pl_status; - if (!suppress_message) - { - print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_3S, PRINT_JAVASP_NAME, PRINT_CMD_STOP, db_name); - } - UTIL_JAVASP_SERVER_STATUS_E javasp_status = is_javasp_running (db_name); - if (javasp_status == JAVASP_SERVER_RUNNING) + do { - if (process_window_service) + if (!is_server_running (CHECK_SERVER, db_name, 0)) { -#if defined(WINDOWS) - const char *args[] = { UTIL_WIN_SERVICE_CONTROLLER_NAME, PRINT_CMD_JAVASP, - COMMAND_TYPE_STOP, db_name, NULL - }; - - status = proc_execute (UTIL_WIN_SERVICE_CONTROLLER_NAME, args, true, false, false, NULL); -#endif + status = ER_GENERIC_ERROR; + print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_SERVER_NAME, db_name); + return status; } - else + + + pl_status = is_pl_running (db_name); + if (pl_status == PL_SERVER_RUNNING) { - const char *args[] = { UTIL_JAVASP_NAME, COMMAND_TYPE_STOP, db_name, NULL }; - status = proc_execute (UTIL_JAVASP_NAME, args, true, false, false, NULL); - do + const char *args[] = { UTIL_PL_NAME, COMMAND_TYPE_STATUS, db_name, NULL }; + status = proc_execute (UTIL_PL_NAME, args, true, false, false, NULL); + if (status == NO_ERROR) { - status = (is_javasp_running (db_name) == JAVASP_SERVER_RUNNING) ? ER_GENERIC_ERROR : NO_ERROR; - sleep (1); /* wait to stop */ - waited_secs++; + break; } - while (status != NO_ERROR && waited_secs < wait_timeout); - } - if (!suppress_message) - { - print_result (PRINT_JAVASP_NAME, status, STOP); } - } - else - { - status = ER_GENERIC_ERROR; - if (!suppress_message) + else { - print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_JAVASP_NAME, db_name); + status = ER_GENERIC_ERROR; } - util_log_write_errid (MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_JAVASP_NAME, db_name); - } - return status; -} - -static int -process_javasp_status (const char *db_name) -{ - int status = NO_ERROR; - UTIL_JAVASP_SERVER_STATUS_E javasp_status = is_javasp_running (db_name); - if (javasp_status == JAVASP_SERVER_RUNNING) - { - const char *args[] = { UTIL_JAVASP_NAME, COMMAND_TYPE_STATUS, db_name, NULL }; - status = proc_execute (UTIL_JAVASP_NAME, args, true, false, false, NULL); + // retry + sleep (1); + waited_secs++; } - else + while (status != NO_ERROR && waited_secs < wait_timeout); + + if (status != NO_ERROR) { - status = ER_GENERIC_ERROR; - print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_JAVASP_NAME, db_name); - util_log_write_errid (MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_JAVASP_NAME, db_name); + print_message (stdout, MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_PL_NAME, db_name); + util_log_write_errid (MSGCAT_UTIL_GENERIC_NOT_RUNNING_2S, PRINT_PL_NAME, db_name); } return status; } static int -process_javasp (int command_type, int argc, const char **argv, bool show_usage, bool suppress_message, - bool process_window_service, bool ha_mode) +process_pl (int command_type, int argc, const char **argv, bool show_usage, bool suppress_message, + bool process_window_service, bool ha_mode) { const int buf_size = 4096; char *buf = NULL; @@ -3027,7 +2962,7 @@ process_javasp (int command_type, int argc, const char **argv, bool show_usage, get_server_names (server_type, &buf); } } - else /* cubrid javasp command */ + else /* cubrid pl command */ { buf = (char *) calloc (sizeof (char), buf_size); strncpy (buf, argv[0], buf_size); @@ -3037,7 +2972,7 @@ process_javasp (int command_type, int argc, const char **argv, bool show_usage, { if (show_usage) { - util_service_usage (JAVASP_UTIL); + util_service_usage (PL_UTIL); util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_CMD); } status = ER_GENERIC_ERROR; @@ -3046,7 +2981,7 @@ process_javasp (int command_type, int argc, const char **argv, bool show_usage, if (command_type == STATUS && !suppress_message) { - print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_2S, PRINT_JAVASP_NAME, PRINT_CMD_STATUS); + print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_2S, PRINT_PL_NAME, PRINT_CMD_STATUS); } list = buf; @@ -3060,17 +2995,22 @@ process_javasp (int command_type, int argc, const char **argv, bool show_usage, switch (command_type) { case START: - status = process_javasp_start (db_name, suppress_message, process_window_service); + if (!suppress_message) + { + print_message (stderr, MSGCAT_UTIL_GENERIC_SERVICE_INVALID_CMD, PRINT_CMD_START); + } break; case STOP: - status = process_javasp_stop (db_name, suppress_message, process_window_service); + if (!suppress_message) + { + print_message (stderr, MSGCAT_UTIL_GENERIC_SERVICE_INVALID_CMD, PRINT_CMD_STOP); + } break; case RESTART: - status = process_javasp_stop (db_name, suppress_message, process_window_service); - status = process_javasp_start (db_name, suppress_message, process_window_service); + status = process_pl_restart (db_name, suppress_message, process_window_service); break; case STATUS: - status = process_javasp_status (db_name); + status = process_pl_status (db_name); break; default: status = ER_GENERIC_ERROR; @@ -4001,9 +3941,6 @@ us_hb_deactivate (const char *hostname, bool immediate_stop) args[opt_idx++] = COMMDB_HB_DEACT_IMMEDIATELY; } - /* stop javasp server */ - (void) process_javasp (STOP, 0, NULL, false, true, false, true); - /* stop all HA processes including cub_server */ args[opt_idx] = COMMDB_HA_DEACT_STOP_ALL; status = proc_execute (UTIL_COMMDB_NAME, args, true, false, false, NULL); @@ -4052,9 +3989,6 @@ us_hb_process_stop (HA_CONF * ha_conf, const char *db_name) print_message (stdout, MSGCAT_UTIL_GENERIC_START_STOP_2S, PRINT_HA_PROCS_NAME, PRINT_CMD_STOP); - /* stop javasp server */ - (void) process_javasp (STOP, 1, (const char **) &db_name, false, true, false, true); - status = us_hb_copylogdb_stop (ha_conf, db_name, NULL, NULL); if (status != NO_ERROR) { @@ -5216,7 +5150,7 @@ load_properties (void) bool gateway_flag = false; bool manager_flag = false; bool heartbeat_flag = false; - bool javasp_flag = false; + bool pl_flag = false; char *value = NULL; @@ -5327,36 +5261,3 @@ get_property (int property_type) { return us_Property_map[property_type].property_value; } - -/* - * is_terminated_process() - test if the process is terminated - * return: true if the process is terminated, otherwise false - * pid(in): process id - */ -static bool -is_terminated_process (const int pid) -{ -#if defined(WINDOWS) - HANDLE h_process; - - h_process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid); - if (h_process == NULL) - { - return true; - } - else - { - CloseHandle (h_process); - return false; - } -#else /* WINDOWS */ - if (kill (pid, 0) == -1) - { - return true; - } - else - { - return false; - } -#endif /* WINDOWS */ -} diff --git a/src/executables/utility.h b/src/executables/utility.h index c1630f4c29..5681833401 100644 --- a/src/executables/utility.h +++ b/src/executables/utility.h @@ -126,7 +126,7 @@ typedef enum MSGCAT_UTIL_GENERIC_MANAGER_NOT_INSTALLED = 41, MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT = 42, MSGCAT_UTIL_GENERIC_FILEOPEN_ERROR = 43, - /* javasp usage = 44 ? */ + /* pl usage = 44 ? */ /* gateway usage = 45 ? */ MSGCAT_UTIL_GENERIC_CLASSNAME_EXCEED_MAX_LENGTH = 46, MSGCAT_UTIL_GENERIC_CLASSNAME_INVALID_FORMAT = 47, @@ -894,7 +894,7 @@ typedef struct _ha_config #define UTIL_CUBRID "cubrid" UTIL_EXE_EXT #define UTIL_COPYLOGDB "copylogdb" UTIL_EXE_EXT #define UTIL_APPLYLOGDB "applylogdb" UTIL_EXE_EXT -#define UTIL_JAVASP_NAME "cub_javasp" UTIL_EXE_EXT +#define UTIL_PL_NAME "cub_pl" UTIL_EXE_EXT #define UTIL_PLCSQL_HELPER_NAME "plcsql_helper" UTIL_EXE_EXT #define PROPERTY_ON "on" @@ -908,7 +908,7 @@ typedef struct _ha_config #define PRINT_GATEWAY_NAME "cubrid gateway" #define PRINT_MANAGER_NAME "cubrid manager server" #define PRINT_HEARTBEAT_NAME "cubrid heartbeat" -#define PRINT_JAVASP_NAME "cubrid javasp" +#define PRINT_PL_NAME "cubrid pl" #define PRINT_HA_PROCS_NAME "HA processes" #define PRINT_CMD_SERVICE "service" @@ -916,9 +916,10 @@ typedef struct _ha_config #define PRINT_CMD_GATEWAY "gateway" #define PRINT_CMD_MANAGER "manager" #define PRINT_CMD_SERVER "server" -#define PRINT_CMD_JAVASP "javasp" +#define PRINT_CMD_PL "pl" #define PRINT_CMD_START "start" +#define PRINT_CMD_RESTART "restart" #define PRINT_CMD_STOP "stop" #define PRINT_CMD_STATUS "status" #define PRINT_CMD_DEREG "deregister" @@ -959,7 +960,6 @@ typedef struct _ha_config #define COMMDB_HA_ADMIN_INFO "--admin-info" #define COMMDB_VERBOSE_OUTPUT "--verbose" #define COMMDB_HA_START_UTIL_PROCESS "-t" -#define COMMDB_SHUTDOWN_REVIVING_SERVER "--shutdown-reviving-server" #define ACLDB_RELOAD "-r" @@ -971,7 +971,7 @@ typedef struct _ha_config #define MASK_GATEWAY 0x10 #define MASK_ADMIN 0x20 #define MASK_HEARTBEAT 0x40 -#define MASK_JAVASP 0x80 +#define MASK_PL 0x80 /* utility option list */ #define UTIL_OPTION_CREATEDB "createdb" @@ -1532,8 +1532,6 @@ typedef struct _ha_config #define COMMDB_HA_ADMIN_INFO_L "admin-info" #define COMMDB_HA_START_UTIL_PROCESS_S 't' #define COMMDB_HA_START_UTIL_PROCESS_L "start-ha-util-process" -#define COMMDB_SHUTDOWN_REVIVING_SERVER_S 12116 -#define COMMDB_SHUTDOWN_REVIVING_SERVER_L "shutdown-reviving-server" /* paramdump option list */ #define PARAMDUMP_OUTPUT_FILE_S 'o' diff --git a/src/loaddb/load_db.c b/src/loaddb/load_db.c index 90c8fcbd08..8c4e10c4f5 100644 --- a/src/loaddb/load_db.c +++ b/src/loaddb/load_db.c @@ -564,8 +564,6 @@ loaddb_internal (UTIL_FUNCTION_ARG * arg, int dba_mode) sysprm_set_force (prm_get_name (PRM_ID_SR_NBUFFERS), LOAD_INDEX_MIN_SORT_BUFFER_PAGES_STRING); } - sysprm_set_force (prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE), "no"); - /* open loaddb log file */ sprintf (log_file_name, "%s_%s", args.volume.c_str (), LOADDB_LOG_FILENAME_SUFFIX); loaddb_log_file = fopen (log_file_name, "w+"); diff --git a/src/loaddb/load_sa_loader.cpp b/src/loaddb/load_sa_loader.cpp index 46ad642b46..a18a0fe93c 100644 --- a/src/loaddb/load_sa_loader.cpp +++ b/src/loaddb/load_sa_loader.cpp @@ -72,6 +72,7 @@ #include "utility.h" #include "work_space.h" #include "schema_system_catalog_constants.h" +#include "pl_sr.h" using namespace cubload; @@ -6369,6 +6370,8 @@ ldr_sa_load (load_args *args, int *status, bool *interrupted) locator_Dont_check_foreign_key = true; ldr_init (args); + pl_server_init (args->volume.c_str ()); + /* set the flag to indicate what type of interrupts to raise If logging has been disabled set commit flag. If * logging is enabled set abort flag. */ @@ -6541,6 +6544,8 @@ ldr_sa_load (load_args *args, int *status, bool *interrupted) ldr_final (); + pl_server_destroy (); + if (ldr_Driver != NULL) { delete ldr_Driver; diff --git a/src/method/method_callback.cpp b/src/method/method_callback.cpp index c5dac8a9d0..58e4cc965a 100644 --- a/src/method/method_callback.cpp +++ b/src/method/method_callback.cpp @@ -19,12 +19,9 @@ #include "method_callback.hpp" #include "dbi.h" -#include "api_compat.h" - #include "ddl_log.h" -#include "method_def.hpp" -#include "method_compile.hpp" +#include "pl_struct_compile.hpp" #include "method_query_util.hpp" #include "method_struct_oid_info.hpp" #include "method_schema_info.hpp" @@ -44,10 +41,13 @@ #include "transform.h" #include "execute_statement.h" #include "schema_manager.h" +#include "network_callback_cl.hpp" extern int ux_create_srv_handle_with_method_query_result (DB_QUERY_RESULT *result, int stmt_type, int num_column, DB_QUERY_TYPE *column_info, bool is_holdable); +using namespace cubpl; + namespace cubmethod { callback_handler::callback_handler (int max_query_handler) @@ -116,6 +116,9 @@ namespace cubmethod case METHOD_CALLBACK_GET_GLOBAL_SEMANTICS: error = get_global_semantics (unpacker); break; + case METHOD_CALLBACK_CHANGE_RIGHTS: + error = change_rights (unpacker); + break; default: assert (false); error = ER_FAILED; @@ -123,7 +126,7 @@ namespace cubmethod } #if defined (CS_MODE) - mcon_send_queue_data_to_server (); + xs_queue_send (); #else /* do nothing for SA_MODE */ #endif @@ -134,34 +137,37 @@ namespace cubmethod int callback_handler::end_transaction (packing_unpacker &unpacker) { + int error_code = NO_ERROR; int command; // commit : 1, abort : 2 unpacker.unpack_all (command); if (command == 1) { - db_commit_transaction (); + error_code = db_commit_transaction (); } else if (command == 2) { - db_abort_transaction (); + error_code = db_abort_transaction (); } else { assert (false); + error_code = ER_FAILED; } - free_query_handle_all (true); + if (error_code != NO_ERROR) + { + m_error_ctx.set_error (db_error_code (), db_error_string (1), __FILE__, __LINE__); + } if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, 1); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, 1); } - - return NO_ERROR; } int @@ -169,16 +175,16 @@ namespace cubmethod { std::string sql; int flag; - unpacker.unpack_all (sql, flag); + TRANID tid; + unpacker.unpack_all (sql, flag, tid); /* find in m_sql_handler_map */ - query_handler *handler = get_query_handler_by_sql (sql); - if (handler != nullptr) - { - /* found in statement handler cache */ - handler->set_is_occupied (true); - } - else + query_handler *handler = get_query_handler_by_sql (sql, [&] (query_handler *h) + { + return h->get_is_occupied() == false && (h->get_tran_id () == NULL_TRANID || h->get_tran_id() == tid); + }); + + if (handler == nullptr) { /* not found in statement handler cache */ handler = new_query_handler (); @@ -194,6 +200,7 @@ namespace cubmethod { // add to statement handler cache m_sql_handler_map.emplace (sql, handler->get_id ()); + handler->set_tran_id (tid); } else { @@ -202,9 +209,11 @@ namespace cubmethod } } - /* DDL audit */ - if (handler) + if (handler != nullptr) { + handler->set_is_occupied (true); + + /* DDL audit */ DB_SESSION *hdl_session = handler->get_db_session(); logddl_set_callback_stmt (handler->get_statement_type(), (char *) sql.c_str (), sql.size (), m_error_ctx.get_error (), ((hdl_session && hdl_session->parser) ? & (hdl_session->parser->hide_pwd_info) : NULL)); @@ -212,11 +221,11 @@ namespace cubmethod if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, handler->get_prepare_info ()); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, handler->get_prepare_info ()); } } @@ -268,11 +277,11 @@ namespace cubmethod if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, handler->get_execute_info ()); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, handler->get_execute_info ()); } } @@ -290,12 +299,12 @@ namespace cubmethod make_outresult_info info; query_handler->set_prepare_column_list_info (info.column_infos); query_handler->set_qresult_info (info.qresult_info); - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, info); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, info); } /* unexpected error, should not be here */ m_error_ctx.set_error (METHOD_CALLBACK_ER_INTERNAL, NULL, __FILE__, __LINE__); - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } int @@ -315,11 +324,11 @@ namespace cubmethod get_generated_keys_info info = handler->generated_keys (); if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, info); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, info); } } @@ -354,11 +363,11 @@ namespace cubmethod oid_get_info info = get_oid_handler()->oid_get (request.oid, request.attr_names); if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, info); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, info); } } @@ -371,11 +380,11 @@ namespace cubmethod int result = get_oid_handler()->oid_put (request.oid, request.attr_names, request.db_values); if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, result); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, result); } } @@ -393,11 +402,11 @@ namespace cubmethod int res_code = get_oid_handler()->oid_cmd (oid, cmd, res); if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, res_code, res); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, res_code, res); } } @@ -417,11 +426,11 @@ namespace cubmethod if (m_error_ctx.has_error()) { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, m_error_ctx); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, result); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, result); } } @@ -579,11 +588,11 @@ namespace cubmethod if (error == NO_ERROR) { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, response); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, response); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, response); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, response); } } @@ -599,7 +608,8 @@ namespace cubmethod AU_DISABLE (save); { - mop_p = jsp_find_stored_procedure (name); + // TODO + mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE); if (mop_p == NULL) { assert (er_errid () != NO_ERROR); @@ -864,11 +874,48 @@ namespace cubmethod if (error == NO_ERROR) { - return mcon_pack_and_queue (METHOD_RESPONSE_SUCCESS, response); + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, response); } else { - return mcon_pack_and_queue (METHOD_RESPONSE_ERROR, response); + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, response); + } + } + + int + callback_handler::change_rights (packing_unpacker &unpacker) + { + int error = NO_ERROR; + + int command; + std::string auth_user_name; + unpacker.unpack_int (command); + + if (command == 0) // PUSH + { + unpacker.unpack_string (auth_user_name); + MOP user = au_find_user (auth_user_name.c_str ()); + if (user == NULL) + { + error = ER_FAILED; + } + else + { + au_perform_push_user (user); + } + } + else // POP + { + au_perform_pop_user (); + } + + if (error == NO_ERROR) + { + return xs_pack_and_queue (METHOD_RESPONSE_SUCCESS, 1); + } + else + { + return xs_pack_and_queue (METHOD_RESPONSE_ERROR, 0); } } @@ -939,7 +986,7 @@ namespace cubmethod // clear handler ID> m_sql_handler_map.erase (m_query_handlers[id]->get_sql_stmt()); - delete m_query_handlers[id]; + m_deferred_query_free_handler.push_back (m_query_handlers[id]); m_query_handlers[id] = nullptr; } else @@ -958,6 +1005,16 @@ namespace cubmethod } } + void + callback_handler::free_deferred_query_handler () + { + for (auto it = m_deferred_query_free_handler.begin(); it != m_deferred_query_free_handler.end(); it++) + { + delete *it; + } + m_deferred_query_free_handler.clear(); + } + query_handler * callback_handler::get_query_handler_by_query_id (const uint64_t qid) { @@ -973,12 +1030,12 @@ namespace cubmethod } query_handler * - callback_handler::get_query_handler_by_sql (const std::string &sql) + callback_handler::get_query_handler_by_sql (const std::string &sql, std::function cond) { for (auto it = m_sql_handler_map.lower_bound (sql); it != m_sql_handler_map.upper_bound (sql); it++) { query_handler *handler = get_query_handler_by_id (it->second); - if (handler != nullptr && handler->get_is_occupied() == false) + if (handler != nullptr && cond (handler)) { /* found */ return handler; @@ -988,12 +1045,19 @@ namespace cubmethod return nullptr; } + std::queue & + callback_handler::get_data_queue () + { + return m_data_queue; + } + ////////////////////////////////////////////////////////////////////////// // Global method callback handler interface ////////////////////////////////////////////////////////////////////////// static callback_handler handler (100); - callback_handler *get_callback_handler (void) + callback_handler * + get_callback_handler (void) { return &handler; } diff --git a/src/method/method_callback.hpp b/src/method/method_callback.hpp index c54ceca10e..669dd6532b 100644 --- a/src/method/method_callback.hpp +++ b/src/method/method_callback.hpp @@ -29,9 +29,8 @@ #include #include +#include -#include "method_connection_cl.hpp" -#include "method_def.hpp" #include "method_error.hpp" #include "method_oid_handler.hpp" #include "method_query_handler.hpp" @@ -73,14 +72,18 @@ namespace cubmethod void free_query_handle (int id, bool is_free); void free_query_handle_all (bool is_free); + void free_deferred_query_handler (); /* find query handler */ query_handler *get_query_handler_by_id (const int id); query_handler *get_query_handler_by_query_id (const uint64_t qid); /* used for out resultset */ - query_handler *get_query_handler_by_sql (const std::string &sql); /* used for statement handler cache */ + query_handler *get_query_handler_by_sql (const std::string &sql, + std::function cond); /* used for statement handler cache */ oid_handler *get_oid_handler (); + std::queue &get_data_queue (); + private: /* handle related to query */ int end_transaction (packing_unpacker &unpacker); @@ -102,6 +105,9 @@ namespace cubmethod int get_sql_semantics (packing_unpacker &unpacker); int get_global_semantics (packing_unpacker &unpacker); + /* handle auth */ + int change_rights (packing_unpacker &unpacker); + /* ported from cas_handle */ query_handler *new_query_handler (); @@ -112,6 +118,10 @@ namespace cubmethod std::vector m_query_handlers; oid_handler *m_oid_handler; + + std::queue m_data_queue; + + std::list m_deferred_query_free_handler; }; ////////////////////////////////////////////////////////////////////////// diff --git a/src/method/method_compile.cpp b/src/method/method_compile.cpp deleted file mode 100644 index 1b8e5ad829..0000000000 --- a/src/method/method_compile.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_compile.hpp" - -#include "jsp_comm.h" -#include "method_runtime_context.hpp" -#include "method_connection_sr.hpp" -#include "method_connection_java.hpp" -#include "method_compile_def.hpp" -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ -#if defined (SERVER_MODE) || defined (SA_MODE) - int callback_send_and_receive (cubthread::entry &thread_ref, runtime_context &ctx, - const SOCKET java_socket, cubpacking::packable_object &obj) - { - int error = NO_ERROR; - - SESSION_ID s_id = thread_ref.conn_entry->session_id; - header header (s_id, METHOD_REQUEST_CALLBACK, ctx.get_and_increment_request_id ()); - error = method_send_data_to_client (&thread_ref, header, obj); - if (error != NO_ERROR) - { - return error; - } - - auto reponse_lambda = [&] (cubmem::block & b) - { - header.req_id = ctx.get_and_increment_request_id (); - return mcon_send_data_to_java (java_socket, header, b); - }; - - error = xs_receive (&thread_ref, reponse_lambda); - return error; - } - - int invoke_compile (cubthread::entry &thread_ref, runtime_context &ctx, const std::string &program, - const bool &verbose, cubmem::extensible_block &out_blk) - { - int error = NO_ERROR; - connection *conn = ctx.get_connection_pool().claim(); - SESSION_ID s_id = thread_ref.conn_entry->session_id; - header header (s_id, SP_CODE_COMPILE, ctx.get_and_increment_request_id ()); - SOCKET socket = conn->get_socket (); - { - error = mcon_send_data_to_java (socket, header, verbose, program); - if (error != NO_ERROR) - { - goto exit; - } - - int code; - do - { - cubmem::block response_blk; - error = cubmethod::mcon_read_data_from_java (socket, response_blk); - if (error != NO_ERROR || response_blk.dim == 0) - { - error = ER_FAILED; - goto exit; - } - - packing_unpacker unpacker (response_blk); - unpacker.unpack_int (code); - - char *aligned_ptr = PTR_ALIGN (unpacker.get_curr_ptr(), MAX_ALIGNMENT); - cubmem::block payload_blk ((size_t) (unpacker.get_buffer_end() - aligned_ptr), - aligned_ptr); - - switch (code) - { - case METHOD_REQUEST_COMPILE: - { - out_blk.extend_to (payload_blk.dim); - std::memcpy (out_blk.get_ptr (), payload_blk.ptr, payload_blk.dim); - error = NO_ERROR; - break; - } - - case METHOD_REQUEST_SQL_SEMANTICS: - { - packing_unpacker respone_unpacker (payload_blk); - sql_semantics_request request; - respone_unpacker.unpack_all (request); - error = callback_send_and_receive (thread_ref, ctx, socket, request); - break; - } - - case METHOD_REQUEST_GLOBAL_SEMANTICS: - { - packing_unpacker respone_unpacker (payload_blk); - global_semantics_request request; - respone_unpacker.unpack_all (request); - error = callback_send_and_receive (thread_ref, ctx, socket, request); - break; - } - } - - // free phase - if (response_blk.dim > 0) - { - free (response_blk.ptr); - } - - if (error != NO_ERROR) - { - break; - } - } - while (code != METHOD_REQUEST_COMPILE); - -exit: - ctx.get_connection_pool().retire (conn, true); - - return error; - } - } -#endif -} diff --git a/src/method/method_connection.hpp b/src/method/method_connection.hpp deleted file mode 100644 index 0ba027d0b2..0000000000 --- a/src/method/method_connection.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * method_connection.hpp - */ - -#ifndef _METHOD_CONNECTION_HPP_ -#define _METHOD_CONNECTION_HPP_ - -#include - -#include "porting.h" - -#include "mem_block.hpp" /* cubmem::block */ -#include "packer.hpp" /* packing_packer */ - -// thread_entry.hpp -namespace cubthread -{ - class entry; -} - -namespace cubmethod -{ - template - cubmem::extensible_block mcon_pack_data (Args &&... args) - { - packing_packer packer; - cubmem::extensible_block eb; - packer.set_buffer_and_pack_all (eb, std::forward (args)...); - return eb; - } - - template - cubmem::block mcon_pack_data_block (Args &&... args) - { - packing_packer packer; - cubmem::extensible_block eb; - packer.set_buffer_and_pack_all (eb, std::forward (args)...); - cubmem::block b (packer.get_current_size(), eb.release_ptr()); - return b; - } -} - -#endif // _METHOD_CONNECTION_HPP_ diff --git a/src/method/method_connection_cl.cpp b/src/method/method_connection_cl.cpp deleted file mode 100644 index 26f825d679..0000000000 --- a/src/method/method_connection_cl.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_connection_cl.hpp" - - -namespace cubmethod -{ - static std::queue s_data_queue; - - std::queue &mcon_get_data_queue () - { - return s_data_queue; - } - -#if defined (CS_MODE) - static method_server_conn_info s_conn_info [METHOD_MAX_RECURSION_DEPTH + 1]; - - void mcon_set_connection_info (int idx, int rc) - { - method_server_conn_info &info = s_conn_info [idx]; - info.rc = rc; - } - - method_server_conn_info *get_connection_info (int idx) - { - if (idx <= METHOD_MAX_RECURSION_DEPTH) - { - return &s_conn_info[idx]; - } - else - { - return nullptr; - } - } - - int - mcon_send_queue_data_to_server () - { - int depth = tran_get_libcas_depth () - 1; - method_server_conn_info *info = get_connection_info (depth); - - assert (info); - assert (!mcon_get_data_queue().empty()); - - cubmem::extensible_block &blk = mcon_get_data_queue().front (); - int error = net_client_send_data (net_client_get_server_host(), info->rc, blk.get_ptr (), blk.get_size()); - mcon_get_data_queue().pop (); - return error; - } - -#endif - -} // cubmethod diff --git a/src/method/method_connection_cl.hpp b/src/method/method_connection_cl.hpp deleted file mode 100644 index 5f936d6be5..0000000000 --- a/src/method/method_connection_cl.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * method_connection_cl.hpp - */ - -#ifndef _METHOD_CONNECTION_CL_HPP_ -#define _METHOD_CONNECTION_CL_HPP_ - -#if defined (SERVER_MODE) -#error does not belong to server -#endif // SERVER_MODE - -#include - -#include "network_interface_cl.h" -#include "method_def.hpp" -#include "mem_block.hpp" -#include "packer.hpp" -#include "transaction_cl.h" - -struct method_server_conn_info -{ - unsigned int rc; -}; - -namespace cubmethod -{ - ////////////////////////////////////////////////////////////////////////// - // Data Queue - ////////////////////////////////////////////////////////////////////////// - - std::queue &mcon_get_data_queue (); - - template - int mcon_pack_and_queue (Args &&... args) - { - packing_packer packer; - cubmem::extensible_block eb; - packer.set_buffer_and_pack_all (eb, std::forward (args)...); - eb.extend_to (packer.get_current_size ()); // ensure eb.get_size () == packer.get_current_size () - - mcon_get_data_queue().push (std::move (eb)); - return NO_ERROR; - } - -#if defined (CS_MODE) - ////////////////////////////////////////////////////////////////////////// - // Interface to communicate with DB Server - ////////////////////////////////////////////////////////////////////////// - - void mcon_set_connection_info (int idx, int rc); - method_server_conn_info *get_connection_info (int idx); - int mcon_send_queue_data_to_server (); - - template - int mcon_send_data_to_server (Args &&... args) - { - mcon_pack_and_queue (std::forward (args)...); - mcon_send_queue_data_to_server (); - return NO_ERROR; - } -#else - template - int mcon_send_data_to_server (Args &&... args) - { - mcon_pack_and_queue (std::forward (args)...); - return NO_ERROR; - } -#endif -} // cubmethod - -#endif // _METHOD_CONNECTION_CL_HPP_ diff --git a/src/method/method_connection_java.cpp b/src/method/method_connection_java.cpp deleted file mode 100644 index 10684a41a4..0000000000 --- a/src/method/method_connection_java.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_connection_java.hpp" -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ - int - mcon_send_buffer_to_java (SOCKET socket, const cubmem::block &blk) - { - int error = NO_ERROR; - OR_ALIGNED_BUF (OR_INT_SIZE) a_request; - char *request = OR_ALIGNED_BUF_START (a_request); - - int request_size = (int) blk.dim; - or_pack_int (request, request_size); - - int nbytes = jsp_writen (socket, request, OR_INT_SIZE); - if (nbytes != OR_INT_SIZE) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, nbytes); - error = er_errid (); - return error; - } - - nbytes = jsp_writen (socket, blk.ptr, blk.dim); - if (nbytes != (int) blk.dim) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, nbytes); - error = er_errid (); - } - return error; - } - - int mcon_read_data_from_java (const SOCKET socket, cubmem::extensible_block &b) - { - int res_size = 0; - int nbytes = 0; - - nbytes = jsp_readn_with_timeout (socket, (char *) &res_size, OR_INT_SIZE, -1); - if (nbytes != OR_INT_SIZE) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, nbytes); - return er_errid (); - } - - res_size = ntohl (res_size); - if (res_size > 0) - { - cubmem::extensible_block ext_blk; - ext_blk.extend_to (res_size); - - nbytes = jsp_readn_with_timeout (socket, ext_blk.get_ptr (), res_size, -1); - if (nbytes != res_size) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, - nbytes); - return er_errid (); - } - - b = std::move (ext_blk); - } - return NO_ERROR; - } - - int mcon_read_data_from_java (const SOCKET socket, cubmem::block &b) - { - int res_size = 0; - int nbytes = 0; - - nbytes = jsp_readn_with_timeout (socket, (char *) &res_size, OR_INT_SIZE, -1); - if (nbytes != OR_INT_SIZE) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, nbytes); - return er_errid (); - } - - res_size = ntohl (res_size); - if (res_size > 0) - { - cubmem::extensible_block ext_blk; - ext_blk.extend_to (res_size); - - nbytes = jsp_readn_with_timeout (socket, ext_blk.get_ptr (), res_size, -1); - if (nbytes != res_size) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, - nbytes); - return er_errid (); - } - - cubmem::block blk (res_size, ext_blk.release_ptr()); - b = std::move (blk); - } - - return NO_ERROR; - } - - int mcon_read_data_from_java (const SOCKET socket, cubmem::block &b, const mcon_callback_func &interrupt_func) - { - int res_size = 0; - int nbytes = 0; - do - { - int status = interrupt_func (); - if (status != NO_ERROR) - { - return status; - } - - nbytes = jsp_readn (socket, (char *) &res_size, OR_INT_SIZE); - if (nbytes < 0 && errno == ETIMEDOUT) - { - continue; - } - else if (nbytes != OR_INT_SIZE) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, nbytes); - return er_errid (); - } - } - while (nbytes < 0 && errno == ETIMEDOUT); - - res_size = ntohl (res_size); - if (res_size > 0) - { - do - { - int status = interrupt_func (); - if (status != NO_ERROR) - { - return status; - } - - cubmem::extensible_block ext_blk; - ext_blk.extend_to (res_size); - - nbytes = jsp_readn (socket, ext_blk.get_ptr (), res_size); - if (nbytes < 0 && errno == ETIMEDOUT) - { - continue; - } - else if (nbytes != res_size) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, - nbytes); - return er_errid (); - } - - cubmem::block blk (res_size, ext_blk.release_ptr()); - b = std::move (blk); - } - while (nbytes < 0 && errno == ETIMEDOUT); - } - - return NO_ERROR; - } - - -} // namespace cubmethod diff --git a/src/method/method_connection_java.hpp b/src/method/method_connection_java.hpp deleted file mode 100644 index 437492dc48..0000000000 --- a/src/method/method_connection_java.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * method_connection_java.hpp: Interface to communicate with Java SP Server - */ - -#ifndef _METHOD_CONNECTION_JAVA_HPP_ -#define _METHOD_CONNECTION_JAVA_HPP_ - -#include "porting.h" - -#include "method_connection.hpp" - -#include - -#include "jsp_comm.h" -#include "object_representation.h" /* OR_ */ - -namespace cubmethod -{ - using mcon_callback_func = std::function ; - using mcon_callback_func_with_sock = std::function ; - - ////////////////////////////////////////////////////////////////////////// - // Interface to communicate with Java SP Server - ////////////////////////////////////////////////////////////////////////// - EXPORT_IMPORT int mcon_send_buffer_to_java (SOCKET socket, const cubmem::block &blk); - - template - int mcon_send_data_to_java (SOCKET socket, Args &&... args) - { - cubmem::block b = std::move (mcon_pack_data_block (std::forward (args)...)); - int status = mcon_send_buffer_to_java (socket, b); - if (b.is_valid ()) - { - delete [] b.ptr; - b.ptr = NULL; - b.dim = 0; - } - return status; - } - - EXPORT_IMPORT int mcon_read_data_from_java (const SOCKET socket, cubmem::extensible_block &b); - - EXPORT_IMPORT int mcon_read_data_from_java (const SOCKET socket, cubmem::block &b); - EXPORT_IMPORT int mcon_read_data_from_java (const SOCKET socket, cubmem::block &b, - const mcon_callback_func &interrupt_func); -} - -#endif // _METHOD_CONNECTION_JAVA_HPP_ diff --git a/src/method/method_connection_pool.cpp b/src/method/method_connection_pool.cpp deleted file mode 100644 index 9bea3f8e2a..0000000000 --- a/src/method/method_connection_pool.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_connection_pool.hpp" - -#include "boot_sr.h" -#include "jsp_sr.h" /* jsp_server_port(), jsp_connect_server() */ -#include "jsp_comm.h" /* jsp_disconnect_server (), jsp_ping () */ -#include "jsp_file.h" /* javasp_read_info() */ - -#if defined (SERVER_MODE) -#include "server_support.h" -#endif -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ - connection_pool::connection_pool (int pool_size) - : m_pool_size (pool_size) - , m_queue () - , m_mutex () - { - // - } - - connection_pool::~connection_pool () - { - while (!m_queue.empty ()) - { - connection *conn = m_queue.front (); - m_queue.pop (); - delete conn; - } - } - - connection * - connection_pool::claim () - { - std::unique_lock ulock (m_mutex); - - if (!m_queue.empty ()) - { - connection *conn = m_queue.front (); - m_queue.pop (); - ulock.unlock (); - - // test socket - if (conn->is_valid() == false) - { - jsp_disconnect_server (conn->m_socket); // disconnect connecting with ExecuteThread in invalid state - conn->m_socket = jsp_connect_server (boot_db_name (), jsp_server_port_from_info ()); - } - - return conn; - } - - // new connection - SOCKET socket = jsp_connect_server (boot_db_name (), jsp_server_port_from_info ()); - return new connection (this, socket); - } - - void - connection_pool::retire (connection *&claimed, bool kill) - { - std::unique_lock ulock (m_mutex); - if (claimed == nullptr) - { - return; - } - - // test connection - if (kill == false && claimed->is_valid () == true) - { - if ((int) m_queue.size () < m_pool_size) - { - m_queue.push (claimed); - return; - } - else - { - // overflow - kill = true; - } - } - - if (kill) - { - assert (claimed != nullptr); - if (claimed) - { - delete claimed; - claimed = nullptr; - } - } - } - - int - connection_pool::max_size () const - { - return m_pool_size; - } - - connection::connection (connection_pool *pool, SOCKET socket) - : m_pool (pool), m_socket (socket) - { - // - } - - connection::~connection () - { - m_pool = nullptr; - jsp_disconnect_server (m_socket); - } - - bool - connection::is_valid () - { - return (m_socket != INVALID_SOCKET); - } - - SOCKET - connection::get_socket () - { - return m_socket; - } - - bool - connection::is_jvm_running () - { - JAVASP_SERVER_INFO info; - javasp_read_info (boot_db_name (), info); - if (info.pid == -1) - { - return false; - } - else - { - return true; - } - } - -} // namespace cubmethod diff --git a/src/method/method_connection_pool.hpp b/src/method/method_connection_pool.hpp deleted file mode 100644 index 9a4767fb35..0000000000 --- a/src/method/method_connection_pool.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * method_connection_pool.hpp - */ - -#ifndef _METHOD_CONNECTION_POOL_HPP_ -#define _METHOD_CONNECTION_POOL_HPP_ - -#if !defined (SERVER_MODE) && !defined (SA_MODE) -#error Belongs to server module -#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ - -#include -#include - -#include "porting.h" // SOCKET - -namespace cubmethod -{ - // forward declaration - class connection; - - class connection_pool - { - public: - connection_pool () = delete; - explicit connection_pool (int pool_size); - ~connection_pool (); - - connection_pool (connection_pool &&other) = delete; // Not MoveConstructible - connection_pool (const connection_pool ©) = delete; // Not CopyConstructible - - connection_pool &operator= (connection_pool &&other) = delete; // Not MoveAssignable - connection_pool &operator= (const connection_pool ©) = delete; // Not CopyAssignable - - connection *claim (); - void retire (connection *&claimed, bool kill); - - int max_size () const; - - private: - int m_pool_size; - std::queue m_queue; - std::mutex m_mutex; - }; - - class connection - { - - friend connection_pool; - - public: - connection () = delete; - ~connection (); - - connection (const connection ©) = delete; // Not CopyConstructible - connection &operator= (const connection ©) = delete; // Not CopyAssignable - - connection (connection &&c) = default; - connection &operator= (connection &&other) = delete; - - bool is_valid (); - SOCKET get_socket (); - bool is_jvm_running (); - - private: - explicit connection (connection_pool *pool, SOCKET socket); - - connection_pool *m_pool; - SOCKET m_socket; - }; -} // namespace cubmethod - -#endif // _METHOD_CONNECTION_POOL_HPP_ diff --git a/src/method/method_connection_sr.cpp b/src/method/method_connection_sr.cpp deleted file mode 100644 index 4f137c78e4..0000000000 --- a/src/method/method_connection_sr.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_connection_sr.hpp" - -#include "porting.h" -#if defined (SERVER_MODE) -#include "network.h" /* METHOD_CALL */ -#include "network_interface_sr.h" /* xs_receive_data_from_client() */ -#include "server_support.h" /* css_send_reply_and_data_to_client(), css_get_comm_request_id() */ -#else -#include "query_method.hpp" -#include "method_callback.hpp" -#endif - -#include "object_representation.h" /* OR_ */ -#include "jsp_comm.h" /* jsp_writen() */ -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ -////////////////////////////////////////////////////////////////////////// -// General interface to communicate with CAS -////////////////////////////////////////////////////////////////////////// -#if defined (SERVER_MODE) - int xs_send (cubthread::entry *thread_p, const cubmem::extensible_block &mem) - { - OR_ALIGNED_BUF (OR_INT_SIZE * 2) a_reply; - char *reply = OR_ALIGNED_BUF_START (a_reply); - - /* pack headers */ - char *ptr = or_pack_int (reply, (int) METHOD_CALL); - ptr = or_pack_int (ptr, (int) mem.get_size ()); - -#if !defined(NDEBUG) - /* suppress valgrind UMW error */ - memset (ptr, 0, OR_ALIGNED_BUF_SIZE (a_reply) - (ptr - reply)); -#endif - - if (thread_p == NULL || thread_p->conn_entry == NULL) - { - return ER_FAILED; - } - - /* send */ - unsigned int rid = css_get_comm_request_id (thread_p); - return css_send_reply_and_data_to_client (thread_p->conn_entry, rid, reply, OR_ALIGNED_BUF_SIZE (a_reply), - (char * )mem.get_read_ptr(), (int) mem.get_size ()); - } - - int xs_receive (cubthread::entry *thread_p, const xs_callback_func &func) - { - cubmem::block buffer (0, nullptr); - - int error = xs_receive_data_from_client (thread_p, &buffer.ptr, (int *) &buffer.dim); - if (error == NO_ERROR && er_errid () == NO_ERROR) - { - error = func (buffer); - } - else - { - if (error == NO_ERROR) - { - error = er_errid (); // ER_SP_TOO_MANY_NESTED_CALL, ER_INTERRUPTED... (interrupt reasons) - } - } - - free_and_init (buffer.ptr); - return error; - } - - int xs_receive (cubthread::entry *thread_p, SOCKET socket, const xs_callback_func_with_sock &func) - { - cubmem::block buffer (0, nullptr); - - int error = xs_receive_data_from_client (thread_p, &buffer.ptr, (int *) &buffer.dim); - if (error == NO_ERROR && er_errid () == NO_ERROR) - { - error = func (socket, buffer); - } - else - { - if (error == NO_ERROR) - { - error = er_errid (); // ER_SP_TOO_MANY_NESTED_CALL, ER_INTERRUPTED... (interrupt reasons) - } - } - - free_and_init (buffer.ptr); - return error; - } -#else // SA_MODE - int xs_send (cubthread::entry *thread_p, const cubmem::extensible_block &ext_blk) - { - packing_unpacker unpacker (ext_blk.get_read_ptr (), ext_blk.get_size ()); - return method_dispatch (unpacker); - } - - int xs_receive (cubthread::entry *thread_p, const xs_callback_func &func) - { - std::queue &queue = mcon_get_data_queue (); - - assert (!queue.empty()); - - cubmem::extensible_block &blk = queue.front (); - cubmem::block buffer (blk.get_size(), blk.get_ptr()); - int error = func (buffer); - - queue.pop (); - return error; - } - - int xs_receive (cubthread::entry *thread_p, SOCKET socket, const xs_callback_func_with_sock &func) - { - std::queue &queue = mcon_get_data_queue (); - - assert (!queue.empty()); - - cubmem::extensible_block &blk = queue.front (); - cubmem::block buffer (blk.get_size(), blk.get_ptr()); - - int error = func (socket, buffer); - - queue.pop (); - return error; - } -#endif -} // namespace cubmethod diff --git a/src/method/method_connection_sr.hpp b/src/method/method_connection_sr.hpp deleted file mode 100644 index 94d79e7110..0000000000 --- a/src/method/method_connection_sr.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * method_connection_sr.hpp - */ - -#ifndef _METHOD_CONNECTION_SR_HPP_ -#define _METHOD_CONNECTION_SR_HPP_ - -#ident "$Id$" - -#if !defined (SERVER_MODE) && !defined (SA_MODE) -#error Belongs to server module -#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ - -#include - -#include "porting.h" -#include "method_connection.hpp" - -// thread_entry.hpp -namespace cubthread -{ - class entry; -} - -namespace cubmem -{ - class block; -} - -namespace cubmethod -{ - using xs_callback_func = std::function ; - using xs_callback_func_with_sock = std::function ; - - ////////////////////////////////////////////////////////////////////////// - // Interface to communicate with CAS - ////////////////////////////////////////////////////////////////////////// - int xs_receive (cubthread::entry *thread_p, const xs_callback_func &func); - int xs_receive (cubthread::entry *thread_p, SOCKET socket, const xs_callback_func_with_sock &func); - int xs_send (cubthread::entry *thread_p, const cubmem::extensible_block &mem); - template - int method_send_data_to_client (cubthread::entry *thread_p, Args &&... args) - { - const cubmem::extensible_block b = std::move (mcon_pack_data (std::forward (args)...)); - return xs_send (thread_p, b); - } -} - -#endif // _METHOD_CONNECTION_SR_HPP_ diff --git a/src/method/method_def.cpp b/src/method/method_def.cpp deleted file mode 100644 index f42748cd86..0000000000 --- a/src/method/method_def.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_def.hpp" - -#include "memory_private_allocator.hpp" -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -method_sig_node::method_sig_node () -{ - next = nullptr; - method_name = nullptr; - method_type = METHOD_TYPE_NONE; - num_method_args = 0; - method_arg_pos = nullptr; -} - -method_sig_node::~method_sig_node () -{ - freemem (); -} - -method_sig_node::method_sig_node (method_sig_node &&obj) -{ - next = std::move (obj.next); - - method_name = obj.method_name; - method_type = obj.method_type; - method_arg_pos = obj.method_arg_pos; - num_method_args = obj.num_method_args; - - obj.method_name = nullptr; - obj.method_arg_pos = nullptr; - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - class_name = obj.class_name; - obj.class_name = nullptr; - } - else - { - arg_info.arg_mode = obj.arg_info.arg_mode; - arg_info.arg_type = obj.arg_info.arg_type; - - obj.arg_info.arg_mode = nullptr; - obj.arg_info.arg_type = nullptr; - } -} - -method_sig_node::method_sig_node (const method_sig_node &obj) -{ - if (obj.next != nullptr) - { - next = (METHOD_SIG *) db_private_alloc (NULL, sizeof (METHOD_SIG)); - *next = * (obj.next); - } - else - { - next = nullptr; - } - - if (obj.method_name != nullptr) - { - int method_name_len = strlen (obj.method_name); - method_name = (char *) db_private_alloc (NULL, method_name_len + 1); - strncpy (method_name, obj.method_name, method_name_len); - } - - method_type = obj.method_type; - num_method_args = obj.num_method_args; - - if (obj.num_method_args > 0) - { - method_arg_pos = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args + 1)); - for (int n = 0; n < num_method_args + 1; n++) - { - method_arg_pos[n] = obj.method_arg_pos[n]; - } - } - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - if (obj.class_name != nullptr) - { - int class_name_len = strlen (obj.class_name); - class_name = (char *) db_private_alloc (NULL, class_name_len + 1); - strncpy (class_name, obj.class_name, class_name_len); - } - } - else - { - if (num_method_args > 0) - { - arg_info.arg_mode = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args)); - arg_info.arg_type = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args)); - for (int n = 0; n < num_method_args; n++) - { - arg_info.arg_mode[n] = obj.arg_info.arg_mode[n]; - arg_info.arg_type[n] = obj.arg_info.arg_type[n]; - } - } - else - { - arg_info.arg_mode = nullptr; - arg_info.arg_type = nullptr; - } - } -} - -void -method_sig_node::pack (cubpacking::packer &serializator) const -{ - serializator.pack_c_string (method_name, strlen (method_name)); - - serializator.pack_int (method_type); - serializator.pack_int (num_method_args); - - for (int i = 0; i < num_method_args + 1; i++) - { - serializator.pack_int (method_arg_pos[i]); - } - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - serializator.pack_c_string (class_name, strlen (class_name)); - } - else - { - for (int i = 0; i < num_method_args; i++) - { - serializator.pack_int (arg_info.arg_mode[i]); - } - for (int i = 0; i < num_method_args; i++) - { - serializator.pack_int (arg_info.arg_type[i]); - } - serializator.pack_int (arg_info.result_type); - } -} - -size_t -method_sig_node::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const -{ - size_t size = serializator.get_packed_int_size (start_offset); /* num_methods */ - - size += serializator.get_packed_c_string_size (method_name, strlen (method_name), size); - - /* method type and num_method_args */ - size += serializator.get_packed_int_size (size); - size += serializator.get_packed_int_size (size); - - for (int i = 0; i < num_method_args + 1; i++) - { - size += serializator.get_packed_int_size (size); /* method_sig->method_arg_pos[i] */ - } - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - size += serializator.get_packed_c_string_size (class_name, strlen (class_name), size); - } - else - { - for (int i = 0; i < num_method_args; i++) - { - size += serializator.get_packed_int_size (size); /* method_sig->arg_info.arg_mode[i] */ - size += serializator.get_packed_int_size (size); /* method_sig->arg_info.arg_type[i] */ - } - size += serializator.get_packed_int_size (size); /* method_sig->arg_info.result_type */ - } - - return size; -} - -method_sig_node & -method_sig_node::operator= (const method_sig_node &obj) -{ - if (this != &obj) - { - if (obj.next != nullptr) - { - next = (METHOD_SIG *) db_private_alloc (NULL, sizeof (METHOD_SIG)); - *next = * (obj.next); - } - else - { - next = nullptr; - } - - if (obj.method_name != nullptr) - { - int method_name_len = strlen (obj.method_name); - method_name = (char *) db_private_alloc (NULL, method_name_len + 1); - strncpy (method_name, obj.method_name, method_name_len); - } - - method_type = obj.method_type; - num_method_args = obj.num_method_args; - if (obj.num_method_args > 0) - { - - method_arg_pos = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args + 1)); - for (int n = 0; n < num_method_args + 1; n++) - { - method_arg_pos[n] = obj.method_arg_pos[n]; - } - } - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - if (obj.class_name != nullptr) - { - int class_name_len = strlen (obj.class_name); - class_name = (char *) db_private_alloc (NULL, class_name_len + 1); - strncpy (class_name, obj.class_name, class_name_len); - } - } - else - { - if (num_method_args > 0) - { - arg_info.arg_mode = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args)); - arg_info.arg_type = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args)); - for (int n = 0; n < num_method_args; n++) - { - arg_info.arg_mode[n] = obj.arg_info.arg_mode[n]; - arg_info.arg_type[n] = obj.arg_info.arg_type[n]; - } - } - else - { - arg_info.arg_mode = nullptr; - arg_info.arg_type = nullptr; - } - } - } - return *this; -} - -void -method_sig_node::unpack (cubpacking::unpacker &deserializator) -{ - next = nullptr; - - cubmem::extensible_block method_name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; - deserializator.unpack_string_to_memblock (method_name_blk); - method_name = method_name_blk.release_ptr (); - - int type; - deserializator.unpack_int (type); - method_type = static_cast (type); - deserializator.unpack_int (num_method_args); - - method_arg_pos = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args + 1)); - for (int n = 0; n < num_method_args + 1; n++) - { - deserializator.unpack_int (method_arg_pos[n]); - } - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - class_name = nullptr; - cubmem::extensible_block class_name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; - deserializator.unpack_string_to_memblock (class_name_blk); - class_name = class_name_blk.release_ptr (); - } - else - { - if (num_method_args > 0) - { - arg_info.arg_mode = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args)); - arg_info.arg_type = (int *) db_private_alloc (NULL, sizeof (int) * (num_method_args)); - - for (int i = 0; i < num_method_args; i++) - { - deserializator.unpack_int (arg_info.arg_mode[i]); - } - - for (int i = 0; i < num_method_args; i++) - { - deserializator.unpack_int (arg_info.arg_type[i]); - } - } - else - { - arg_info.arg_mode = nullptr; - arg_info.arg_type = nullptr; - } - - deserializator.unpack_int (arg_info.result_type); - } -} - -void -method_sig_node::freemem () -{ - if (method_name != nullptr) - { - db_private_free_and_init (NULL, method_name); - } - - if (method_arg_pos != nullptr) - { - db_private_free_and_init (NULL, method_arg_pos); - } - - if (method_type == METHOD_TYPE_NONE) - { - // - } - else if (method_type != METHOD_TYPE_JAVA_SP) - { - if (class_name != nullptr) - { - db_private_free_and_init (NULL, class_name); - } - } - else - { - if (arg_info.arg_mode != nullptr) - { - db_private_free_and_init (NULL, arg_info.arg_mode); - } - if (arg_info.arg_type != nullptr) - { - db_private_free_and_init (NULL, arg_info.arg_type); - } - } -} - -void -method_sig_list::freemem () -{ - METHOD_SIG *sig = method_sig; - while (sig) - { - METHOD_SIG *next = sig->next; - - sig->freemem (); - db_private_free_and_init (NULL, sig); /* itself */ - - sig = next; - } -} - -void -method_sig_list::pack (cubpacking::packer &serializator) const -{ - serializator.pack_int (num_methods); - - METHOD_SIG *sig_p = method_sig; - while (sig_p) - { - sig_p->pack (serializator); - sig_p = sig_p->next; - } -} - -size_t -method_sig_list::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const -{ - size_t size = serializator.get_packed_int_size (start_offset); /* num_methods */ - - METHOD_SIG *sig_p = method_sig; - while (sig_p) - { - size += sig_p->get_packed_size (serializator, size); - sig_p = sig_p->next; - } - return size; -} - -void -method_sig_list::unpack (cubpacking::unpacker &deserializator) -{ - deserializator.unpack_int (num_methods); - - method_sig = nullptr; - if (num_methods > 0) - { - method_sig = (METHOD_SIG *) db_private_alloc (NULL, sizeof (METHOD_SIG)); - METHOD_SIG *method_sig_p = method_sig; - for (int i = 0; i < num_methods; i++) - { - method_sig_p->unpack (deserializator); - - if (i != num_methods - 1) /* last */ - { - method_sig_p->next = (METHOD_SIG *) db_private_alloc (NULL, sizeof (METHOD_SIG)); - } - - method_sig_p = method_sig_p->next; - } - } -} diff --git a/src/method/method_def.hpp b/src/method/method_def.hpp deleted file mode 100644 index 406aeb870c..0000000000 --- a/src/method/method_def.hpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2008 Search Solution Corporation - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -// -// method_def.hpp - define structures used by method feature -// - -#ifndef _METHOD_DEF_H_ -#define _METHOD_DEF_H_ - -#include - -#include "packer.hpp" -#include "packable_object.hpp" - -#define METHOD_MAX_RECURSION_DEPTH 15 - -using METHOD_GROUP_ID = std::uint64_t; -using METHOD_REQ_ID = int; - -typedef enum -{ - METHOD_SUCCESS = 1, - METHOD_EOF, - METHOD_ERROR -} METHOD_CALL_STATUS; - -enum METHOD_TYPE -{ - METHOD_TYPE_NONE = 0, - METHOD_TYPE_INSTANCE_METHOD, - METHOD_TYPE_CLASS_METHOD, - METHOD_TYPE_JAVA_SP -}; - -enum METHOD_REQUEST -{ - METHOD_REQUEST_ARG_PREPARE = 0x40, - METHOD_REQUEST_INVOKE = 0x01, - METHOD_REQUEST_CALLBACK = 0x08, - METHOD_REQUEST_END = 0x20, - - METHOD_REQUEST_COMPILE = 0x80, - METHOD_REQUEST_SQL_SEMANTICS = 0xA0, - METHOD_REQUEST_GLOBAL_SEMANTICS = 0xA1 -}; - -enum METHOD_RESPONSE -{ - METHOD_RESPONSE_SUCCESS, - METHOD_RESPONSE_ERROR -}; - -enum METHOD_CALLBACK_RESPONSE -{ - METHOD_CALLBACK_END_TRANSACTION = 1, - METHOD_CALLBACK_QUERY_PREPARE = 2, - METHOD_CALLBACK_QUERY_EXECUTE = 3, - METHOD_CALLBACK_GET_DB_PARAMETER = 4, - - METHOD_CALLBACK_CURSOR = 7, - METHOD_CALLBACK_FETCH = 8, - METHOD_CALLBACK_GET_SCHEMA_INFO = 9, - - METHOD_CALLBACK_OID_GET = 10, - METHOD_CALLBACK_OID_PUT = 11, - METHOD_CALLBACK_OID_CMD = 17, - METHOD_CALLBACK_COLLECTION = 18, - - // METHOD_CALLBACK_GET_DB_VERSION = 15, - - METHOD_CALLBACK_NEXT_RESULT = 19, - - METHOD_CALLBACK_EXECUTE_BATCH = 20, - METHOD_CALLBACK_EXECUTE_ARRAY = 21, - - METHOD_CALLBACK_CURSOR_UPDATE = 22, - - METHOD_CALLBACK_MAKE_OUT_RS = 33, - METHOD_CALLBACK_GET_GENERATED_KEYS = 34, - - METHOD_CALLBACK_LOB_NEW = 35, - METHOD_CALLBACK_LOB_WRITE = 36, - METHOD_CALLBACK_LOB_READ = 37, - - METHOD_CALLBACK_CURSOR_CLOSE = 42, - - // COMPILE - METHOD_CALLBACK_GET_SQL_SEMANTICS = 100, - METHOD_CALLBACK_GET_GLOBAL_SEMANTICS = 101, -}; - -enum METHOD_ARG_MODE -{ - METHOD_ARG_MODE_IN = 1, - METHOD_ARG_MODE_OUT, - METHOD_ARG_MODE_INOUT -}; - -typedef struct method_arg_info METHOD_ARG_INFO; -struct method_arg_info -{ - int *arg_mode; /* IN, OUT, INOUT */ - int *arg_type; /* DB_TYPE */ - int result_type; /* DB_TYPE */ - - method_arg_info () = default; -}; - -typedef struct method_sig_node METHOD_SIG; -struct method_sig_node -{ - /* method signature */ - METHOD_SIG *next; - char *method_name; /* method name */ - METHOD_TYPE method_type; /* instance or class method */ - int num_method_args; /* number of arguments */ - int *method_arg_pos; /* arg position in list file */ - - union - { - char *class_name; /* class name for the class method */ - METHOD_ARG_INFO arg_info; /* argument info for javasp's server-side calling */ - }; - - void pack (cubpacking::packer &serializator) const; - void unpack (cubpacking::unpacker &deserializator); - size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset = 0) const; - - void freemem (); - - method_sig_node &operator= (const method_sig_node &rhs); - - method_sig_node (); - method_sig_node (method_sig_node &&); // move constructor - method_sig_node (const method_sig_node &obj); // copy constructor - ~method_sig_node (); -}; - -struct method_sig_list : public cubpacking::packable_object -{ - /* signature for methods */ - METHOD_SIG *method_sig; /* one method signature */ - int num_methods; /* number of signatures */ - - void pack (cubpacking::packer &serializator) const; - void unpack (cubpacking::unpacker &deserializator); - size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset = 0) const; - - void freemem (); - - method_sig_list () = default; -}; -typedef struct method_sig_list METHOD_SIG_LIST; - -#endif // _METHOD_DEF_H_ diff --git a/src/method/method_invoke.hpp b/src/method/method_invoke.hpp deleted file mode 100644 index 91f409ec05..0000000000 --- a/src/method/method_invoke.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#ifndef _METHOD_INVOKE_HPP_ -#define _METHOD_INVOKE_HPP_ - -#ident "$Id$" - -#if !defined (SERVER_MODE) && !defined (SA_MODE) -#error Belongs to server module -#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ - -#include -#include -#include - -#include "dbtype.h" /* db_value_* */ -#include "method_def.hpp" /* method_sig_node */ -#include "method_query_cursor.hpp" -#include "method_struct_invoke.hpp" /* cubmethod::header */ -#include "mem_block.hpp" /* cubmem::block, cubmem::extensible_block */ -#include "porting.h" /* SOCKET */ - -#if defined (SA_MODE) -#include "query_method.hpp" -#endif - -// thread_entry.hpp -namespace cubthread -{ - class entry; -} - -namespace cubmethod -{ - // forward declarations - class method_invoke_group; - - class method_invoke - { - public: - method_invoke () = delete; // Not DefaultConstructible - method_invoke (method_invoke_group *group, method_sig_node *sig) : m_group (group), m_method_sig (sig) {} - virtual ~method_invoke () {}; - - method_invoke (method_invoke &&other) = delete; // Not MoveConstructible - method_invoke (const method_invoke ©) = delete; // Not CopyConstructible - - method_invoke &operator= (method_invoke &&other) = delete; // Not MoveAssignable - method_invoke &operator= (const method_invoke ©) = delete; // Not CopyAssignable - - virtual int invoke (cubthread::entry *thread_p, std::vector> &arg_base) = 0; - virtual int get_return (cubthread::entry *thread_p, std::vector> &arg_base, - DB_VALUE &result) = 0; - - uint64_t get_id () - { - return (uint64_t) this; - } - - protected: - method_invoke_group *m_group; - method_sig_node *m_method_sig; - }; - - class method_invoke_builtin : public method_invoke - { - public: - method_invoke_builtin () = delete; - method_invoke_builtin (method_invoke_group *group, method_sig_node *method_sig); - - int invoke (cubthread::entry *thread_p, std::vector> &arg_base) override; - int get_return (cubthread::entry *thread_p, std::vector> &arg_base, - DB_VALUE &result) override; - }; - - class method_invoke_java : public method_invoke - { - public: - method_invoke_java () = delete; - method_invoke_java (method_invoke_group *group, method_sig_node *method_sig, bool transaction_control); - ~method_invoke_java (); - - int invoke (cubthread::entry *thread_p, std::vector> &arg_base) override; - int get_return (cubthread::entry *thread_p, std::vector> &arg_base, - DB_VALUE &result) override; - - private: - int receive_result (std::vector> &arg_base, - DB_VALUE &returnval); - int receive_error (); - - int callback_dispatch (cubthread::entry &thread_ref); - - int callback_get_db_parameter (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_prepare (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_execute (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_fetch (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_oid_get (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_oid_put (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_oid_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_collection_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_make_outresult (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_get_generated_keys (cubthread::entry &thread_ref, packing_unpacker &unpacker); - int callback_end_transaction (cubthread::entry &thread_ref, packing_unpacker &unpacker); - - void erase_query_cursor (const std::uint64_t query_id); - - const cubmethod::header &get_next_java_header (cubmethod::header &header); - - cubmethod::header m_client_header; // header sending to cubridcs - cubmethod::header m_java_header; // header sending to cub_javasp - - bool m_transaction_control; - }; - -} // namespace cubmethod - -#endif /* _METHOD_INVOKE_HPP_ */ diff --git a/src/method/method_invoke_builtin.cpp b/src/method/method_invoke_builtin.cpp deleted file mode 100644 index 13d07f1dae..0000000000 --- a/src/method/method_invoke_builtin.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_invoke.hpp" - -#include - -#include "method_struct_invoke.hpp" -#include "method_invoke_group.hpp" -#include "packer.hpp" -#include "method_connection_sr.hpp" - -#if defined (SERVER_MODE) -#include "method_struct_query.hpp" -#else -#include "query_method.hpp" -#endif -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ - method_invoke_builtin::method_invoke_builtin (method_invoke_group *group, method_sig_node *method_sig) - : method_invoke (group, method_sig) - { - // - } - - int method_invoke_builtin::invoke (cubthread::entry *thread_p, std::vector> &arg_base) - { - int error = NO_ERROR; - cubmethod::header header (m_group->get_session_id(), METHOD_REQUEST_INVOKE /* default */, 0); - cubmethod::invoke_builtin arg (m_group->get_id (), m_method_sig); - error = method_send_data_to_client (thread_p, header, arg); - return error; - } - - int - method_invoke_builtin::get_return (cubthread::entry *thread_p, std::vector> &arg_base, - DB_VALUE &result) - { - int error = NO_ERROR; - db_value_clear (&result); - - auto get_method_result = [&] (cubmem::block & b) - { - int e = NO_ERROR; - packing_unpacker unpacker (b); - int status; - unpacker.unpack_int (status); - if (status == METHOD_SUCCESS) - { - unpacker.unpack_db_value (result); - } - else - { - unpacker.unpack_int (e); /* er_errid */ - } - return e; - }; - - error = xs_receive (thread_p, get_method_result); - return error; - } -} // namespace cubmethod diff --git a/src/method/method_invoke_group.cpp b/src/method/method_invoke_group.cpp deleted file mode 100644 index 90135d5da2..0000000000 --- a/src/method/method_invoke_group.cpp +++ /dev/null @@ -1,493 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_invoke_group.hpp" - -#include "boot_sr.h" -#include "dbtype.h" /* db_value_* */ -#include "db_value_printer.hpp" -#include "jsp_comm.h" /* common communcation functions for javasp */ -#include "mem_block.hpp" /* cubmem::extensible_block */ -#include "method_invoke.hpp" -#include "method_struct_invoke.hpp" -#include "object_primitive.h" -#include "object_representation.h" /* OR_ */ -#include "packer.hpp" -#include "method_connection_sr.hpp" -#include "method_connection_java.hpp" -#include "method_connection_pool.hpp" -#include "session.h" -#include "string_buffer.hpp" - -#if defined (SA_MODE) -#include "query_method.hpp" -#endif -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ -////////////////////////////////////////////////////////////////////////// -// Method Group to invoke together -////////////////////////////////////////////////////////////////////////// - method_invoke_group::method_invoke_group (cubthread::entry *thread_p, const method_sig_list &sig_list, - bool is_for_scan = false) - : m_id ((std::uint64_t) this) - , m_thread_p (thread_p) - , m_connection (nullptr) - , m_cursor_set () - , m_handler_set () - { - assert (sig_list.num_methods > 0); - - // init runtime context - session_get_method_runtime_context (thread_p, m_rctx); - session_get_session_id (thread_p, &m_sid); - - m_tid = logtb_find_current_tranid (thread_p); - - method_sig_node *sig = sig_list.method_sig; - while (sig) - { - method_invoke *mi = nullptr; - - METHOD_TYPE type = sig->method_type; - switch (type) - { - case METHOD_TYPE_INSTANCE_METHOD: - case METHOD_TYPE_CLASS_METHOD: - mi = new method_invoke_builtin (this, sig); - break; - case METHOD_TYPE_JAVA_SP: - { - bool use_tcl = prm_get_bool_value (PRM_ID_PL_TRANSACTION_CONTROL); - mi = new method_invoke_java (this, sig, use_tcl); - } - break; - default: - assert (false); // not implemented yet - break; - } - - m_kind_type.insert (type); - m_method_vector.push_back (mi); - - sig = sig->next; - } - - DB_VALUE v; - db_make_null (&v); - m_result_vector.resize (sig_list.num_methods, v); - m_is_running = false; - m_parameter_info = nullptr; - m_is_for_scan = is_for_scan; - } - - method_invoke_group::~method_invoke_group () - { - for (method_invoke *method: m_method_vector) - { - delete method; - } - m_method_vector.clear (); - if (m_parameter_info) - { - delete m_parameter_info; - } - } - - DB_VALUE & - method_invoke_group::get_return_value (int index) - { - assert (index >= 0 && index < (int) get_num_methods ()); - return m_result_vector[index]; - } - - int - method_invoke_group::get_num_methods () const - { - return m_method_vector.size (); - } - - METHOD_GROUP_ID - method_invoke_group::get_id () const - { - return m_id; - } - - TRANID - method_invoke_group::get_tran_id () - { - m_tid = logtb_find_current_tranid (m_thread_p); - return m_tid; - } - - SOCKET - method_invoke_group::get_socket () const - { - return m_connection ? m_connection->get_socket () : INVALID_SOCKET; - } - - cubthread::entry * - method_invoke_group::get_thread_entry () const - { - return m_thread_p; - } - - std::queue & - method_invoke_group::get_data_queue () - { - return m_data_queue; - } - - cubmethod::runtime_context * - method_invoke_group::get_runtime_context () - { - return m_rctx; - } - - connection_pool & - method_invoke_group::get_connection_pool () - { - return get_runtime_context ()->get_connection_pool (); - } - - bool - method_invoke_group::is_running () const - { - return m_is_running; - } - - bool - method_invoke_group::is_for_scan () const - { - return m_is_for_scan; - } - - db_parameter_info * - method_invoke_group::get_db_parameter_info () const - { - return m_parameter_info; - } - - void - method_invoke_group::set_db_parameter_info (db_parameter_info *param_info) - { - m_parameter_info = param_info; - } - - bool - method_invoke_group::is_supported_dbtype (const DB_VALUE &value) - { - bool res = false; - switch (DB_VALUE_TYPE (&value)) - { - case DB_TYPE_INTEGER: - case DB_TYPE_SHORT: - case DB_TYPE_BIGINT: - case DB_TYPE_FLOAT: - case DB_TYPE_DOUBLE: - case DB_TYPE_MONETARY: - case DB_TYPE_NUMERIC: - case DB_TYPE_CHAR: - case DB_TYPE_NCHAR: - case DB_TYPE_VARNCHAR: - case DB_TYPE_STRING: - - case DB_TYPE_DATE: - case DB_TYPE_TIME: - case DB_TYPE_TIMESTAMP: - case DB_TYPE_DATETIME: - - case DB_TYPE_SET: - case DB_TYPE_MULTISET: - case DB_TYPE_SEQUENCE: - case DB_TYPE_OID: - case DB_TYPE_OBJECT: - - case DB_TYPE_RESULTSET: - case DB_TYPE_NULL: - res = true; - break; - - // unsupported types - case DB_TYPE_BIT: - case DB_TYPE_VARBIT: - case DB_TYPE_TABLE: - case DB_TYPE_BLOB: - case DB_TYPE_CLOB: - case DB_TYPE_TIMESTAMPTZ: - case DB_TYPE_TIMESTAMPLTZ: - case DB_TYPE_DATETIMETZ: - case DB_TYPE_DATETIMELTZ: - case DB_TYPE_JSON: - case DB_TYPE_ENUMERATION: - res = false; - break; - - // obsolete, internal, unused type - case DB_TYPE_ELO: - case DB_TYPE_VARIABLE: - case DB_TYPE_SUB: - case DB_TYPE_POINTER: - case DB_TYPE_ERROR: - case DB_TYPE_VOBJ: - case DB_TYPE_DB_VALUE: - case DB_TYPE_MIDXKEY: - default: - assert (false); - break; - } - - return res; - } - - int - method_invoke_group::prepare (std::vector> &arg_base, - const std::vector &arg_use_vec) - { - int error = NO_ERROR; - - /* send base arguments */ - for (const auto &elem : m_kind_type) - { - switch (elem) - { - case METHOD_TYPE_INSTANCE_METHOD: - case METHOD_TYPE_CLASS_METHOD: - { - cubmethod::header header (get_session_id(), METHOD_REQUEST_ARG_PREPARE, get_and_increment_request_id ()); - cubmethod::prepare_args arg (m_id, get_tran_id (), elem, arg_base); - error = method_send_data_to_client (m_thread_p, header, arg); - break; - } - case METHOD_TYPE_JAVA_SP: - { - /* optimize arguments only for java sp not to send redundant values */ - DB_VALUE null_val; - db_make_null (&null_val); - std::vector> optimized_arg_base (arg_base.begin (), - arg_base.end ()); /* bind null value for the unused columns */ - for (int i = 0; i < arg_use_vec.size (); i++) - { - bool is_used = arg_use_vec [i]; - optimized_arg_base[i] = (!is_used) ? std::ref (null_val) : optimized_arg_base[i]; - } - - /* check unsupported types */ - for (const DB_VALUE &value : optimized_arg_base) - { - if (is_supported_dbtype (value) == false) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, - pr_type_name ((DB_TYPE) value.domain.general_info.type)); - set_error_msg (er_msg ()); - return er_errid (); - } - } - - // send to Java SP Servers - cubmethod::header header (get_session_id(), SP_CODE_PREPARE_ARGS, get_and_increment_request_id ()); - cubmethod::prepare_args arg (m_id, get_tran_id (), elem, optimized_arg_base); - - error = mcon_send_data_to_java (get_socket (), header, arg); - break; - } - default: - assert (false); - break; - } - } - - return error; - } - - int method_invoke_group::execute (std::vector> &arg_base) - { - int error = NO_ERROR; - - for (int i = 0; i < get_num_methods (); i++) - { - error = m_method_vector[i]->invoke (m_thread_p, arg_base); - if (error != NO_ERROR) - { - break; - } - - error = m_method_vector[i]->get_return (m_thread_p, arg_base, m_result_vector[i]); - if (m_rctx->is_interrupted ()) - { - error = m_rctx->get_interrupt_id (); - } - - if (error != NO_ERROR) - { - // if error is not interrupt reason, interrupt is not set - m_rctx->set_interrupt (error, (er_has_error () && er_msg ()) ? er_msg () : ""); - break; - } - } - - return error; - } - - void - method_invoke_group::begin () - { - if (m_is_running == true) - { - return; - } - - // push to stack - m_rctx->push_stack (m_thread_p, this); - - // connect socket for java sp - bool is_in = m_kind_type.find (METHOD_TYPE_JAVA_SP) != m_kind_type.end (); - if (is_in) - { - if (m_connection == nullptr) - { - m_connection = get_connection_pool ().claim(); - } - - // check javasp server's status - if (m_connection->get_socket () == INVALID_SOCKET) - { - if (m_connection->is_jvm_running ()) - { - m_rctx->set_interrupt (ER_SP_CANNOT_CONNECT_JVM, "connect ()"); - } - else - { - m_rctx->set_interrupt (ER_SP_NOT_RUNNING_JVM); - } - } - } - - m_is_running = true; - } - - int method_invoke_group::reset (bool is_end_query) - { - int error = NO_ERROR; - - if (!is_end_query) - { - cubmethod::header header (get_session_id(), METHOD_REQUEST_END, get_and_increment_request_id ()); - std::vector handler_vec (m_handler_set.begin (), m_handler_set.end ()); - error = method_send_data_to_client (m_thread_p, header, handler_vec); - m_handler_set.clear (); - } - - destroy_resources (); - - return error; - } - - void - method_invoke_group::register_client_handler (int handler_id) - { - m_handler_set.insert (handler_id); - } - - void - method_invoke_group::end () - { - if (m_is_running == false) - { - return; - } - - // FIXME: The connection is closed to prevent Java thread from entering an unexpected state. - if (m_connection) - { - bool kill = (m_rctx->is_interrupted() || er_has_error ()); - get_connection_pool ().retire (m_connection, kill); - m_connection = nullptr; - } - - // FIXME - // m_rctx->pop_stack (m_thread_p, this); - - m_is_running = false; - } - - void - method_invoke_group::destroy_resources () - { - pr_clear_value_vector (m_result_vector); - - // destroy cursors used in this group - destory_all_cursors (); - } - - query_cursor * - method_invoke_group::create_cursor (QUERY_ID query_id, bool oid_included) - { - if (query_id == NULL_QUERY_ID || query_id >= SHRT_MAX) - { - // false query e.g) SELECT * FROM db_class WHERE 0 <> 0 - assert (query_id == NULL_QUERY_ID); - return nullptr; - } - - m_cursor_set.insert (query_id); - return m_rctx->create_cursor (m_thread_p, query_id, oid_included); - } - - void - method_invoke_group::register_returning_cursor (QUERY_ID query_id) - { - m_rctx->register_returning_cursor (m_thread_p, query_id); - m_cursor_set.erase (query_id); - } - - query_cursor * - method_invoke_group::get_cursor (QUERY_ID query_id) - { - return m_rctx->get_cursor (m_thread_p, query_id); - } - - void - method_invoke_group::destory_all_cursors () - { - for (auto &cursor_it : m_cursor_set) - { - // If the cursor is received from the child function and is not returned to the parent function, the cursor remains in m_cursor_set. - // So here trying to find the cursor Id in the global returning cursor storage and remove it if exists. - m_rctx->deregister_returning_cursor (m_thread_p, cursor_it); - - m_rctx->destroy_cursor (m_thread_p, cursor_it); - } - - m_cursor_set.clear (); - } - - std::string - method_invoke_group::get_error_msg () - { - return m_err_msg; - } - - void - method_invoke_group::set_error_msg (const std::string &msg) - { - m_err_msg = msg; - } -} // namespace cubmethod diff --git a/src/method/method_invoke_java.cpp b/src/method/method_invoke_java.cpp deleted file mode 100644 index a5d146cc37..0000000000 --- a/src/method/method_invoke_java.cpp +++ /dev/null @@ -1,703 +0,0 @@ -/* - * - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -#include "method_invoke.hpp" - -#include - -#include "jsp_comm.h" /* common communcation functions for javasp */ -#include "object_representation.h" /* OR_ */ - -#include "connection_support.h" -#include "dbtype_def.h" - -#include "method_connection_sr.hpp" -#include "method_connection_java.hpp" -#include "method_struct_parameter_info.hpp" -#include "method_struct_invoke.hpp" -#include "method_struct_value.hpp" -#include "method_struct_oid_info.hpp" -#include "method_invoke_group.hpp" -#include "method_struct_query.hpp" -#include "method_query_util.hpp" -#include "method_runtime_context.hpp" - -#include "log_impl.h" - -#if !defined (SERVER_MODE) -#include "method_callback.hpp" -#endif -// XXX: SHOULD BE THE LAST INCLUDE HEADER -#include "memory_wrapper.hpp" - -namespace cubmethod -{ - method_invoke_java::method_invoke_java (method_invoke_group *group, method_sig_node *method_sig, - bool transaction_control) - : method_invoke (group, method_sig) - , m_client_header (group->get_session_id (), METHOD_REQUEST_CALLBACK /* default */, 0) - , m_java_header (group->get_session_id (), SP_CODE_INTERNAL_JDBC /* default */, 0) - , m_transaction_control (transaction_control) - { - // - } - - method_invoke_java::~method_invoke_java () - { - // - } - - const cubmethod::header & - method_invoke_java::get_next_java_header (cubmethod::header &header) - { - header.req_id = m_group->get_and_increment_request_id (); - return header; - } - - int method_invoke_java::invoke (cubthread::entry *thread_p, std::vector> &arg_base) - { - int error = NO_ERROR; - - cubmethod::header header (m_group->get_session_id (), SP_CODE_INVOKE, m_group->get_and_increment_request_id ()); - cubmethod::invoke_java arg (m_group->get_id (), m_group->get_tran_id (), m_method_sig, m_transaction_control); - - error = mcon_send_data_to_java (m_group->get_socket (), header, arg); - return error; - } - - static int - method_interrupt_handler (cubthread::entry *thread_p) - { - cubmethod::runtime_context *rctx = cubmethod::get_rctx (thread_p); - if (rctx && rctx->is_interrupted ()) - { - return rctx->get_interrupt_id (); - } - return NO_ERROR; - } - - int - method_invoke_java::get_return (cubthread::entry *thread_p, std::vector> &arg_base, - DB_VALUE &returnval) - { - int start_code, error_code = NO_ERROR; - - do - { - /* read request code */ - cubmem::block response_blk; - int nbytes = -1; - auto interrupt_f = std::bind (method_interrupt_handler, thread_p); - error_code = mcon_read_data_from_java (m_group->get_socket(), response_blk, interrupt_f); - if (error_code == NO_ERROR) - { - packing_unpacker unpacker (response_blk); - unpacker.unpack_int (start_code); - - char *aligned_ptr = PTR_ALIGN (unpacker.get_curr_ptr(), MAX_ALIGNMENT); - cubmem::block payload_blk ((size_t) (unpacker.get_buffer_end() - aligned_ptr), - aligned_ptr); - m_group->get_data_queue().emplace (std::move (payload_blk)); - - /* processing */ - if (start_code == SP_CODE_INTERNAL_JDBC) - { - error_code = callback_dispatch (*thread_p); - } - else if (start_code == SP_CODE_RESULT) - { - error_code = receive_result (arg_base, returnval); - } - else if (start_code == SP_CODE_ERROR) - { - error_code = receive_error (); - db_make_null (&returnval); - } - else - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, - start_code); - error_code = ER_SP_NETWORK_ERROR; - } - - if (m_group->get_data_queue().empty() == false) - { - m_group->get_data_queue().pop (); - } - } - - // free phase - if (response_blk.is_valid ()) - { - delete [] response_blk.ptr; - response_blk.ptr = NULL; - response_blk.dim = 0; - } - - if (error_code != NO_ERROR) - { - break; - } - } - while (error_code == NO_ERROR && start_code == SP_CODE_INTERNAL_JDBC); - - return error_code; - } - - int - method_invoke_java::receive_result (std::vector> &arg_base, - DB_VALUE &returnval) - { - int error_code = NO_ERROR; - - // check queue - if (m_group->get_data_queue().empty() == true) - { - return ER_FAILED; - } - - cubmem::block &blk = m_group->get_data_queue().front (); - packing_unpacker unpacker (blk); - - dbvalue_java value_unpacker; - db_make_null (&returnval); - value_unpacker.value = &returnval; - value_unpacker.unpack (unpacker); - - if (db_value_type (&returnval) == DB_TYPE_RESULTSET) - { - std::uint64_t query_id = db_get_resultset (&returnval); - m_group->register_returning_cursor (query_id); - } - - /* out arguments */ - DB_VALUE temp; - int num_args = m_method_sig->num_method_args; - for (int i = 0; i < num_args; i++) - { - if (m_method_sig->arg_info.arg_mode[i] == METHOD_ARG_MODE_IN) - { - continue; - } - - value_unpacker.value = &temp; - value_unpacker.unpack (unpacker); - - if (db_value_type (&temp) == DB_TYPE_RESULTSET) - { - // out argument CURSOR is not supported yet - // it is implmented for the future - std::uint64_t query_id = db_get_resultset (&temp); - m_group->register_returning_cursor (query_id); - } - - int pos = m_method_sig->method_arg_pos[i]; - DB_VALUE &arg_ref = arg_base[pos].get(); - db_value_clear (&arg_ref); - db_value_clone (&temp, &arg_ref); - db_value_clear (&temp); - } - - return error_code; - } - - int - method_invoke_java::receive_error () - { - // check queue - if (m_group->get_data_queue().empty() == true) - { - return ER_FAILED; - } - - cubmem::block &blk = m_group->get_data_queue().front (); - - packing_unpacker unpacker (blk); - - std::string error_msg; - unpacker.unpack_string (error_msg); - - m_group->set_error_msg (error_msg); - return ER_FAILED; - } - - int - method_invoke_java::callback_dispatch (cubthread::entry &thread_ref) - { - int error = NO_ERROR; - - // check queue - if (m_group->get_data_queue().empty() == true) - { - return ER_FAILED; - } - - cubmem::block &blk = m_group->get_data_queue().front (); - packing_unpacker unpacker (blk); - - int code; - unpacker.unpack_int (code); - - switch (code) - { - /* NOTE: we don't need to implement it - case METHOD_CALLBACK_GET_DB_VERSION: - break; - */ - - case METHOD_CALLBACK_GET_DB_PARAMETER: - error = callback_get_db_parameter (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_QUERY_PREPARE: - error = callback_prepare (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_QUERY_EXECUTE: - error = callback_execute (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_FETCH: - error = callback_fetch (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_OID_GET: - error = callback_oid_get (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_OID_PUT: - error = callback_oid_put (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_OID_CMD: - error = callback_oid_cmd (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_COLLECTION: - error = callback_collection_cmd (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_MAKE_OUT_RS: - error = callback_make_outresult (thread_ref, unpacker); - break; - - case METHOD_CALLBACK_GET_GENERATED_KEYS: - error = callback_get_generated_keys (thread_ref, unpacker); - break; - case METHOD_CALLBACK_END_TRANSACTION: - error = callback_end_transaction (thread_ref, unpacker); - break; - default: - // TODO: not implemented yet, do we need error handling? - assert (false); - error = ER_FAILED; - break; - } - - return error; - } - - int - method_invoke_java::callback_get_db_parameter (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_GET_DB_PARAMETER; - - if (m_group->get_db_parameter_info () == nullptr) - { - int tran_index = LOG_FIND_THREAD_TRAN_INDEX (m_group->get_thread_entry()); - db_parameter_info *parameter_info = new db_parameter_info (); - - parameter_info->tran_isolation = logtb_find_isolation (tran_index); - parameter_info->wait_msec = logtb_find_wait_msecs (tran_index); - logtb_get_client_ids (tran_index, ¶meter_info->client_ids); - - m_group->set_db_parameter_info (parameter_info); - } - - db_parameter_info *parameter_info = m_group->get_db_parameter_info (); - if (parameter_info) - { - cubmem::block blk = std::move (mcon_pack_data_block (METHOD_RESPONSE_SUCCESS, *parameter_info)); - error = mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), blk); - delete[] blk.ptr; - } - else - { - cubmem::block blk = std::move (mcon_pack_data_block (METHOD_RESPONSE_ERROR, ER_FAILED, "unknown error", - ARG_FILE_LINE)); - error = mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), blk); - delete[] blk.ptr; - } - return error; - } - - int - method_invoke_java::callback_prepare (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_QUERY_PREPARE; - std::string sql; - int flag; - - unpacker.unpack_all (sql, flag); - - error = method_send_data_to_client (&thread_ref, m_client_header, code, sql, flag); - if (error != NO_ERROR) - { - return error; - } - - auto get_prepare_info = [&] (const cubmem::block & b) - { - packing_unpacker unpacker (b.ptr, (size_t) b.dim); - - int res_code; - unpacker.unpack_int (res_code); - - if (res_code == METHOD_RESPONSE_SUCCESS) - { - prepare_info info; - info.unpack (unpacker); - - m_group->register_client_handler (info.handle_id); - } - - error = mcon_send_data_to_java (m_group->get_socket (), get_next_java_header (m_java_header), b); - return error; - }; - - error = xs_receive (&thread_ref, get_prepare_info); - return error; - } - - int - method_invoke_java::callback_execute (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_QUERY_EXECUTE; - execute_request request; - - unpacker.unpack_all (request); - request.has_parameter = 1; - - error = method_send_data_to_client (&thread_ref, m_client_header, code, request); - - request.clear (); - - auto get_execute_info = [&] (const cubmem::block & b) - { - packing_unpacker unpacker (b.ptr, (size_t) b.dim); - - int res_code; - unpacker.unpack_int (res_code); - - if (res_code == METHOD_RESPONSE_SUCCESS) - { - execute_info info; - info.unpack (unpacker); - - query_result_info ¤t_result_info = info.qresult_info; - int stmt_type = current_result_info.stmt_type; - if (stmt_type == CUBRID_STMT_SELECT) - { - std::uint64_t qid = current_result_info.query_id; - bool is_oid_included = current_result_info.include_oid; - (void) m_group->create_cursor (qid, is_oid_included); - } - } - - error = mcon_send_data_to_java (m_group->get_socket (), get_next_java_header (m_java_header), b); - return error; - }; - - if (error == NO_ERROR) - { - error = xs_receive (&thread_ref, get_execute_info); - } - return error; - } - - int - method_invoke_java::callback_fetch (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_FETCH; - std::uint64_t qid; - int pos; - int fetch_count; - int fetch_flag; - - unpacker.unpack_all (qid, pos, fetch_count, fetch_flag); - - /* find query cursor */ - query_cursor *cursor = m_group->get_cursor (qid); - if (cursor == nullptr) - { - assert (false); - error = mcon_send_data_to_java (m_group->get_socket (), METHOD_RESPONSE_ERROR, ER_FAILED, "unknown error", - ARG_FILE_LINE); - return error; - } - - if (cursor->get_is_opened () == false) - { - cursor->open (); - } - - cursor->set_fetch_count (fetch_count); - - fetch_info info; - - SCAN_CODE s_code = S_SUCCESS; - - /* Most cases, fetch_count will be the same value - * To handle an invalid value of fetch_count is set at `cursor->set_fetch_count (fetch_count);` - * Here, I'm going to get the fetch_count from the getter again. - */ - fetch_count = cursor->get_fetch_count (); - - int start_index = cursor->get_current_index (); - while (s_code == S_SUCCESS) - { - s_code = cursor->next_row (); - int tuple_index = cursor->get_current_index (); - if (s_code == S_END) - { - break; - } - - std::vector tuple_values = cursor->get_current_tuple (); - - if (cursor->get_is_oid_included()) - { - /* FIXME!!: For more optimized way, refactoring method_query_cursor is needed */ - OID *oid = cursor->get_current_oid (); - std::vector sub_vector = {tuple_values.begin() + 1, tuple_values.end ()}; - info.tuples.emplace_back (tuple_index, sub_vector, *oid); - } - else - { - info.tuples.emplace_back (tuple_index, tuple_values); - } - - if (tuple_index - start_index >= fetch_count - 1) - { - break; - } - } - - cubmem::block blk = std::move (mcon_pack_data_block (METHOD_RESPONSE_SUCCESS, info)); - error = mcon_send_data_to_java (m_group->get_socket (), get_next_java_header (m_java_header), std::move (blk)); - if (blk.is_valid ()) - { - delete [] blk.ptr; - blk.ptr = NULL; - blk.dim = 0; - } - return error; - } - - int - method_invoke_java::callback_oid_get (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_OID_GET; - oid_get_request request; - request.unpack (unpacker); - - error = method_send_data_to_client (&thread_ref, m_client_header, code, request); - if (error != NO_ERROR) - { - return error; - } - - auto java_lambda = [&] (const cubmem::block & b) - { - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - }; - - error = xs_receive (&thread_ref, java_lambda); - return error; - } - - int - method_invoke_java::callback_oid_put (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_OID_PUT; - oid_put_request request; - request.is_compatible_java = true; - request.unpack (unpacker); - request.is_compatible_java = false; - - error = method_send_data_to_client (&thread_ref, m_client_header, code, request); - if (error != NO_ERROR) - { - return error; - } - - auto java_lambda = [&] (const cubmem::block & b) - { - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - }; - - error = xs_receive (&thread_ref, java_lambda); - return error; - } - - int - method_invoke_java::callback_oid_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_OID_CMD; - int command; - OID oid; - unpacker.unpack_all (command, oid); - - error = method_send_data_to_client (&thread_ref, m_client_header, code, command, oid); - if (error != NO_ERROR) - { - return error; - } - - auto java_lambda = [&] (const cubmem::block & b) - { - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - }; - - error = xs_receive (&thread_ref, java_lambda); - return error; - } - - int - method_invoke_java::callback_collection_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - - int code = METHOD_CALLBACK_COLLECTION; - collection_cmd_request request; - request.is_compatible_java = true; - request.unpack (unpacker); - - - request.is_compatible_java = false; - - error = method_send_data_to_client (&thread_ref, m_client_header, code, request); - if (error != NO_ERROR) - { - return error; - } - - auto java_lambda = [&] (const cubmem::block & b) - { - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - }; - - error = xs_receive (&thread_ref, java_lambda); - return error; - } - - int - method_invoke_java::callback_make_outresult (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - - int code = METHOD_CALLBACK_MAKE_OUT_RS; - uint64_t query_id; - unpacker.unpack_all (query_id); - - error = method_send_data_to_client (&thread_ref, m_client_header, code, query_id); - if (error != NO_ERROR) - { - return error; - } - - auto get_make_outresult_info = [&] (const cubmem::block & b) - { - packing_unpacker unpacker (b.ptr, (size_t) b.dim); - - int res_code; - make_outresult_info info; - unpacker.unpack_all (res_code, info); - - const query_result_info ¤t_result_info = info.qresult_info; - query_cursor *cursor = m_group->get_cursor (current_result_info.query_id); - if (cursor) - { - cursor->change_owner (m_group->get_thread_entry ()); - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - } - else - { - assert (false); - return ER_FAILED; - } - }; - - error = xs_receive (&thread_ref, get_make_outresult_info); - return error; - } - - int - method_invoke_java::callback_get_generated_keys (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_GET_GENERATED_KEYS; - int handler_id; - unpacker.unpack_all (handler_id); - - error = method_send_data_to_client (&thread_ref, m_client_header, code, handler_id); - if (error != NO_ERROR) - { - return error; - } - - auto java_lambda = [&] (const cubmem::block & b) - { - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - }; - - error = xs_receive (&thread_ref, java_lambda); - return error; - } - - int - method_invoke_java::callback_end_transaction (cubthread::entry &thread_ref, packing_unpacker &unpacker) - { - int error = NO_ERROR; - int code = METHOD_CALLBACK_END_TRANSACTION; - int command; // commit or abort - - unpacker.unpack_all (command); - error = method_send_data_to_client (&thread_ref, m_client_header, code, command); - if (error != NO_ERROR) - { - return error; - } - - auto java_lambda = [&] (const cubmem::block & b) - { - return mcon_send_data_to_java (m_group->get_socket(), get_next_java_header (m_java_header), b); - }; - - error = xs_receive (&thread_ref, java_lambda); - return error; - } - -} // namespace cubmethod diff --git a/src/method/method_query_handler.cpp b/src/method/method_query_handler.cpp index 02ffb5cd29..64764edd69 100644 --- a/src/method/method_query_handler.cpp +++ b/src/method/method_query_handler.cpp @@ -36,6 +36,7 @@ namespace cubmethod { query_handler::query_handler (error_context &ctx, int id) : m_id (id) + , m_tid (NULL_TRANID) , m_error_ctx (ctx) , m_sql_stmt () , m_stmt_type (CUBRID_STMT_NONE) @@ -67,6 +68,7 @@ namespace cubmethod { end_qresult (); m_is_occupied = false; + } query_result::query_result () @@ -132,6 +134,18 @@ namespace cubmethod m_is_occupied = flag; } + TRANID + query_handler::get_tran_id () + { + return m_tid; + } + + void + query_handler::set_tran_id (TRANID tid) + { + m_tid = tid; + } + prepare_info & query_handler::get_prepare_info () { diff --git a/src/method/method_query_handler.hpp b/src/method/method_query_handler.hpp index 6981f7e073..a941a796f8 100644 --- a/src/method/method_query_handler.hpp +++ b/src/method/method_query_handler.hpp @@ -100,6 +100,10 @@ namespace cubmethod int get_num_markers (); bool get_is_occupied (); void set_is_occupied (bool flag); + + TRANID get_tran_id (); + void set_tran_id (TRANID tid); + DB_SESSION *get_db_session (); DB_QUERY_TYPE *get_column_info (); @@ -148,6 +152,7 @@ namespace cubmethod private: int m_id; + TRANID m_tid; /* error */ error_context &m_error_ctx; diff --git a/src/method/method_scan.cpp b/src/method/method_scan.cpp index 80c516bc50..965d90983c 100644 --- a/src/method/method_scan.cpp +++ b/src/method/method_scan.cpp @@ -21,7 +21,10 @@ #include "dbtype.h" /* db_value_* */ #include "list_file.h" /* qfile_ */ #include "object_representation.h" /* OR_ */ -#include "method_runtime_context.hpp" + +#include "pl_session.hpp" +#include "pl_signature.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" @@ -39,7 +42,7 @@ namespace cubscan } int - scanner::init (cubthread::entry *thread_p, METHOD_SIG_LIST *sig_list, qfile_list_id *list_id) + scanner::init (cubthread::entry *thread_p, PL_SIGNATURE_ARRAY_TYPE *sig_array, qfile_list_id *list_id) { // check initialized if (m_thread_p != thread_p) @@ -49,7 +52,7 @@ namespace cubscan if (m_method_group == nullptr) // signature is not initialized { - m_method_group = cubmethod::get_rctx (thread_p)->create_invoke_group (thread_p, *sig_list, true); + m_method_group = new cubmethod::method_invoke_group (*sig_array); if (!m_method_group) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, @@ -63,7 +66,6 @@ namespace cubscan m_list_id = list_id; int arg_count = m_list_id->type_list.type_cnt; m_arg_vector.resize (arg_count); - m_arg_use_vector.resize (arg_count, false); m_arg_dom_vector.resize (arg_count); for (int i = 0; i < arg_count; i++) @@ -77,16 +79,17 @@ namespace cubscan } } - method_sig_node *sig = sig_list->method_sig; - while (sig) +#if 0 // TODO + for (int i = 0; i < sig_array->num_sigs; i++) { - for (int i = 0; i < sig->num_method_args; i++) + cubpl::pl_signature &sig = sig_array->sigs[i]; + for (int j = 0; j < sig.arg.arg_size; j++) { - int idx = sig->method_arg_pos [i]; + int idx = sig.ext.method.arg_pos[i]; m_arg_use_vector [idx] = true; } - sig = sig->next; } +#endif if (m_dbval_list == nullptr) { @@ -113,8 +116,11 @@ namespace cubscan m_method_group->reset (true); m_method_group->end (); +// TODO +#if 0 cubmethod::runtime_context *rctx = m_method_group->get_runtime_context (); rctx->pop_stack (m_thread_p, m_method_group); +#endif m_method_group = nullptr; // will be destroyed by cubmethod::runtime_context } @@ -155,11 +161,6 @@ namespace cubscan std::vector> arg_wrapper (m_arg_vector.begin (), m_arg_vector.end ()); - if (scan_code == S_SUCCESS && (error = m_method_group->prepare (arg_wrapper, m_arg_use_vector)) != NO_ERROR) - { - scan_code = S_ERROR; - } - if (scan_code == S_SUCCESS && (error = m_method_group->execute (arg_wrapper)) != NO_ERROR) { scan_code = S_ERROR; @@ -188,15 +189,17 @@ namespace cubscan m_method_group->reset (false); } + if (scan_code == S_ERROR) { - cubmethod::runtime_context *rctx = m_method_group->get_runtime_context (); - if (rctx->is_interrupted ()) - { - rctx->set_local_error_for_interrupt (); - } - else if (error != - ER_SM_INVALID_METHOD_ENV) /* FIXME: error possibly occured in builtin method, It should be handled at CAS */ +// PL_SESSION *session = m_method_group->get_session (); +// if (session->is_interrupted ()) +// { +// session->set_local_error_for_interrupt (); +// } +// else + if (error != + ER_SM_INVALID_METHOD_ENV) /* FIXME: error possibly occured in builtin method, It should be handled at CAS */ { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_EXECUTE_ERROR, 1, m_method_group->get_error_msg ().c_str ()); } diff --git a/src/method/method_scan.hpp b/src/method/method_scan.hpp index 347bf379ea..fd3c7a1803 100644 --- a/src/method/method_scan.hpp +++ b/src/method/method_scan.hpp @@ -29,7 +29,7 @@ #include #include "dbtype_def.h" /* DB_VALUE */ -#include "method_def.hpp" /* method_sig_list */ + #include "method_invoke_group.hpp" /* cubmethod::method_invoke_group */ #include "object_domain.h" /* TP_DOMAIN */ #include "query_list.h" /* qfile_list_id, qfile_list_scan_id */ @@ -58,7 +58,7 @@ namespace cubscan scanner (); - int init (cubthread::entry *thread_p, method_sig_list *sig_list, qfile_list_id *list_id); + int init (cubthread::entry *thread_p, PL_SIGNATURE_ARRAY_TYPE *sig_array, qfile_list_id *list_id); void clear (bool is_final); ////////////////////////////////////////////////////////////////////////// diff --git a/src/method/method_struct_invoke.cpp b/src/method/method_struct_invoke.cpp index 23ed6c7c35..efea0d3410 100644 --- a/src/method/method_struct_invoke.cpp +++ b/src/method/method_struct_invoke.cpp @@ -80,7 +80,7 @@ namespace cubmethod ////////////////////////////////////////////////////////////////////////// // Common structure implementation ////////////////////////////////////////////////////////////////////////// - prepare_args::prepare_args (METHOD_GROUP_ID id, int tid, METHOD_TYPE type, + prepare_args::prepare_args (uint64_t id, int tid, METHOD_TYPE type, std::vector> &vec) : group_id (id), tran_id (tid), type (type), args (vec) { @@ -100,6 +100,7 @@ namespace cubmethod break; } case METHOD_TYPE_JAVA_SP: + case METHOD_TYPE_PLCSQL: { serializator.pack_int (tran_id); serializator.pack_int (args.size ()); @@ -142,6 +143,7 @@ namespace cubmethod break; } case METHOD_TYPE_JAVA_SP: + case METHOD_TYPE_PLCSQL: { size += serializator.get_packed_int_size (size); // tran_id size += serializator.get_packed_int_size (size); // arg count @@ -160,108 +162,4 @@ namespace cubmethod } return size; } - -////////////////////////////////////////////////////////////////////////// -// Method Builtin (C Language Method) -////////////////////////////////////////////////////////////////////////// - invoke_builtin::invoke_builtin (METHOD_GROUP_ID g_id, method_sig_node *sig) - : group_id (g_id) - , sig (sig) - { - // - } - - void - invoke_builtin::pack (cubpacking::packer &serializator) const - { - serializator.pack_bigint (group_id); - sig->pack (serializator); - } - - void - invoke_builtin::unpack (cubpacking::unpacker &deserializator) - { - deserializator.unpack_bigint (group_id); - sig = new METHOD_SIG (); - sig->unpack (deserializator); - } - - size_t - invoke_builtin::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const - { - size_t size = serializator.get_packed_bigint_size (start_offset); //group id - size += sig->get_packed_size (serializator, size); // sig - return size; - } - -////////////////////////////////////////////////////////////////////////// -// Method Java -////////////////////////////////////////////////////////////////////////// - invoke_java::invoke_java (METHOD_GROUP_ID id, int tid, method_sig_node *sig, bool tc) - : group_id (id) - , tran_id (tid) - { - signature.assign (sig->method_name); - num_args = sig->num_method_args; - - arg_pos.resize (num_args); - arg_mode.resize (num_args); - arg_type.resize (num_args); - - for (int i = 0; i < num_args; i++) - { - arg_pos[i] = sig->method_arg_pos[i]; - arg_mode[i] = sig->arg_info.arg_mode[i]; - arg_type[i] = sig->arg_info.arg_type[i]; - } - - result_type = sig->arg_info.result_type; - transaction_control = tc; - } - - void - invoke_java::pack (cubpacking::packer &serializator) const - { - serializator.pack_bigint (group_id); - serializator.pack_int (tran_id); - serializator.pack_string (signature); - serializator.pack_int (num_args); - - for (int i = 0; i < num_args; i++) - { - serializator.pack_int (arg_pos[i]); - serializator.pack_int (arg_mode[i]); - serializator.pack_int (arg_type[i]); - } - - serializator.pack_int (result_type); - serializator.pack_bool (transaction_control); - } - - void - invoke_java::unpack (cubpacking::unpacker &deserializator) - { - // TODO: unpacking is not necessary - assert (false); - } - - size_t - invoke_java::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const - { - size_t size = serializator.get_packed_bigint_size (start_offset); // group_id - size += serializator.get_packed_int_size (size); // tran_id - size += serializator.get_packed_string_size (signature, size); // signature - size += serializator.get_packed_int_size (size); // num_args - - for (int i = 0; i < num_args; i++) - { - size += serializator.get_packed_int_size (size); // arg_pos - size += serializator.get_packed_int_size (size); // arg_mode - size += serializator.get_packed_int_size (size); // arg_type - } - - size += serializator.get_packed_int_size (size); // return_type - size += serializator.get_packed_bool_size (size); // transaction_control - return size; - } } diff --git a/src/method/method_struct_invoke.hpp b/src/method/method_struct_invoke.hpp index 2bdd5a13d4..5e5c17dc49 100644 --- a/src/method/method_struct_invoke.hpp +++ b/src/method/method_struct_invoke.hpp @@ -22,9 +22,10 @@ #include #include "porting.h" -#include "method_def.hpp" + #include "mem_block.hpp" #include "packable_object.hpp" +#include "sp_constants.hpp" /* * method_struct_invoke.hpp @@ -45,7 +46,7 @@ namespace cubmethod { header () = delete; explicit header (cubpacking::unpacker &unpacker); - header (uint64_t id, int command, METHOD_REQ_ID req_id); + header (uint64_t id, int command, int req_id); void pack (cubpacking::packer &serializator) const override; void unpack (cubpacking::unpacker &deserializator) override; @@ -53,7 +54,7 @@ namespace cubmethod uint64_t id; int command; - METHOD_REQ_ID req_id; + int req_id; }; /* @@ -62,63 +63,18 @@ namespace cubmethod struct prepare_args : public cubpacking::packable_object { prepare_args () = delete; - prepare_args (METHOD_GROUP_ID id, int tran_id, METHOD_TYPE type, std::vector> &args); + prepare_args (uint64_t id, int tran_id, METHOD_TYPE type, std::vector> &args); ~prepare_args () = default; void pack (cubpacking::packer &serializator) const override; void unpack (cubpacking::unpacker &deserializator) override; size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; - METHOD_GROUP_ID group_id; + uint64_t group_id; int tran_id; METHOD_TYPE type; std::vector> &args; }; - - /* - * request data to invoke builtin(C) method - */ - struct invoke_builtin : public cubpacking::packable_object - { - invoke_builtin () = delete; - explicit invoke_builtin (cubpacking::unpacker &deserializator) - { - this->unpack (deserializator); - }; - invoke_builtin (METHOD_GROUP_ID g_id, method_sig_node *sig); - - void pack (cubpacking::packer &serializator) const override; - void unpack (cubpacking::unpacker &deserializator) override; - size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; - - METHOD_GROUP_ID group_id; - method_sig_node *sig; - }; - - /* - * request data to invoke java method - */ - struct invoke_java : public cubpacking::packable_object - { - invoke_java () = delete; - invoke_java (METHOD_GROUP_ID group_id, int tran_id, method_sig_node *sig, bool tc); - - void pack (cubpacking::packer &serializator) const override; - void unpack (cubpacking::unpacker &deserializator) override; - size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; - - METHOD_GROUP_ID group_id; - int tran_id; - - std::string signature; - int num_args; - std::vector arg_pos; - std::vector arg_mode; - std::vector arg_type; - int result_type; - - bool transaction_control; // TODO: wrap it with proper structs - }; } // namespace cubmethod #endif diff --git a/src/method/method_struct_value.cpp b/src/method/method_struct_value.cpp index 250cc7be15..97f218d2cd 100644 --- a/src/method/method_struct_value.cpp +++ b/src/method/method_struct_value.cpp @@ -117,6 +117,7 @@ namespace cubmethod case DB_TYPE_STRING: // TODO: support unicode decomposed string { + serializator.pack_int (db_get_string_codeset (&v)); serializator.pack_c_string (db_get_string (&v), db_get_string_size (&v)); } break; @@ -330,6 +331,7 @@ namespace cubmethod case DB_TYPE_VARNCHAR: case DB_TYPE_STRING: { + size += serializator.get_packed_int_size (size); /* codeset */ size += serializator.get_packed_int_size (size); /* dummy size */ size += serializator.get_packed_c_string_size (db_get_string (value), db_get_string_size (value), size); } @@ -519,11 +521,12 @@ namespace cubmethod case DB_TYPE_VARNCHAR: case DB_TYPE_STRING: { + int codeset; cubmem::extensible_block blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; + deserializator.unpack_int (codeset); deserializator.unpack_string_to_memblock (blk); // TODO: unicode compose hanlding - #if 0 char *invalid_pos = NULL; int len = strlen (blk.get_ptr ()); @@ -559,17 +562,7 @@ namespace cubmethod } #endif db_make_string (v, blk.release_ptr ()); - - INTL_CODESET codeset; - int collation; -#if !defined (SERVER_MODE) - codeset = lang_get_client_charset (); - collation = lang_get_client_collation (); -#else - codeset = LANG_SYS_CODESET; - collation = LANG_SYS_COLLATION; -#endif - db_string_put_cs_and_collation (v, codeset, collation); + db_string_put_cs_and_collation (v, codeset, LANG_GET_BINARY_COLLATION (codeset)); v->need_clear = true; } break; diff --git a/src/method/query_method.cpp b/src/method/query_method.cpp index fb92904547..729aa84eba 100644 --- a/src/method/query_method.cpp +++ b/src/method/query_method.cpp @@ -43,11 +43,12 @@ #include "mem_block.hpp" /* cubmem::extensible_block */ #include "method_callback.hpp" -#include "method_def.hpp" /* method_sig_list, method_sig_node */ + #include "method_query_handler.hpp" #include "transaction_cl.h" #include "packer.hpp" /* packing_packer */ +#include "network_callback_cl.hpp" #endif #if defined (SERVER_MODE) || defined (SA_MODE) @@ -88,7 +89,7 @@ static void method_set_runtime_arguments (UINT64 id, std::vector &args static int method_prepare_arguments (packing_unpacker &unpacker); static int method_invoke_builtin (packing_unpacker &unpacker, DB_VALUE &result); -static int method_invoke_builtin_internal (DB_VALUE &result, std::vector &args, method_sig_node *meth_sig_p); +static int method_invoke_builtin_internal (DB_VALUE &result, std::vector &args, cubpl::pl_signature &sig); static int method_dispatch_internal (packing_unpacker &unpacker); @@ -124,7 +125,7 @@ method_dispatch (unsigned int rc, char *methoddata, int methoddata_size) if (error == NO_ERROR) { - cubmethod::mcon_set_connection_info (depth - 1, rc); + xs_set_conn_info (depth - 1, rc); error = method_dispatch_internal (unpacker); } @@ -146,8 +147,8 @@ method_error (unsigned int rc, int error_id) int error = NO_ERROR; tran_begin_libcas_function(); int depth = tran_get_libcas_depth (); - cubmethod::mcon_set_connection_info (depth - 1, rc); - error = cubmethod::mcon_send_data_to_server (METHOD_ERROR, error_id); + xs_set_conn_info (depth - 1, rc); + error = xs_send_queue (METHOD_ERROR, error_id); tran_end_libcas_function(); return error; } @@ -252,17 +253,19 @@ static int method_invoke_builtin (packing_unpacker &unpacker, DB_VALUE &result) { int error = NO_ERROR; + uint64_t group_id; + cubpl::pl_signature ib; + unpacker.unpack_all (group_id, ib); - cubmethod::invoke_builtin ib (unpacker); - auto search = runtime_args.find (ib.group_id); + auto search = runtime_args.find (group_id); if (search != runtime_args.end()) { std::vector &args = search->second; - error = method_invoke_builtin_internal (result, args, ib.sig); + error = method_invoke_builtin_internal (result, args, ib); if (error == NO_ERROR) { /* send a result value to server */ - error = cubmethod::mcon_send_data_to_server (METHOD_SUCCESS, result); + error = xs_send_queue (METHOD_SUCCESS, result); } } else @@ -270,7 +273,6 @@ method_invoke_builtin (packing_unpacker &unpacker, DB_VALUE &result) error = ER_GENERIC_ERROR; } - delete ib.sig; return error; } @@ -336,60 +338,49 @@ method_set_runtime_arguments (UINT64 id, std::vector &args) */ // *INDENT-OFF* int -method_invoke_builtin_internal (DB_VALUE & result, std::vector &args, method_sig_node * meth_sig_p) +method_invoke_builtin_internal (DB_VALUE & result, std::vector &args, cubpl::pl_signature &sig) // *INDENT-ON* { int error = NO_ERROR; int turn_on_auth = 1; - assert (meth_sig_p != NULL); - assert (meth_sig_p->method_type == METHOD_TYPE_CLASS_METHOD || meth_sig_p->method_type == METHOD_TYPE_INSTANCE_METHOD); - /* The first position # is for the object ID */ - int num_args = meth_sig_p->num_method_args + 1; + int num_args = sig.arg.arg_size + 1; // *INDENT-OFF* - std::vector arg_val_p (num_args + 1, NULL); /* + 1 for C method */ + std::vector arg_val_p (num_args + 1, NULL); // *INDENT-ON* for (int i = 0; i < num_args; ++i) { - int pos = meth_sig_p->method_arg_pos[i]; + int pos = sig.ext.method.arg_pos[i]; arg_val_p[i] = &args[pos]; } db_make_null (&result); - if (meth_sig_p->method_type == METHOD_TYPE_INSTANCE_METHOD || meth_sig_p->method_type == METHOD_TYPE_CLASS_METHOD) + + /* Don't call the method if the object is NULL or it has been deleted. A method call on a NULL object is + * NULL. */ + if (!DB_IS_NULL (arg_val_p[0])) { - /* Don't call the method if the object is NULL or it has been deleted. A method call on a NULL object is - * NULL. */ - if (!DB_IS_NULL (arg_val_p[0])) - { - error = db_is_any_class (db_get_object (arg_val_p[0])); - if (error == 0) - { - error = db_is_instance (db_get_object (arg_val_p[0])); - } - } - if (error == ER_HEAP_UNKNOWN_OBJECT) - { - error = NO_ERROR; - } - else if (error > 0) + error = db_is_any_class (db_get_object (arg_val_p[0])); + if (error == 0) { - /* methods must run with authorization turned on and database modifications turned off. */ - turn_on_auth = 0; - AU_ENABLE (turn_on_auth); - db_disable_modification (); - error = obj_send_array (db_get_object (arg_val_p[0]), meth_sig_p->method_name, &result, &arg_val_p[1]); - db_enable_modification (); - AU_DISABLE (turn_on_auth); + error = db_is_instance (db_get_object (arg_val_p[0])); } } - else + if (error == ER_HEAP_UNKNOWN_OBJECT) { - /* java stored procedure is not handled here anymore */ - assert (false); - error = ER_GENERIC_ERROR; + error = NO_ERROR; + } + else if (error > 0) + { + /* methods must run with authorization turned on and database modifications turned off. */ + turn_on_auth = 0; + AU_ENABLE (turn_on_auth); + db_disable_modification (); + error = obj_send_array (db_get_object (arg_val_p[0]), sig.name, &result, &arg_val_p[1]); + db_enable_modification (); + AU_DISABLE (turn_on_auth); } /* error handling */ @@ -592,6 +583,8 @@ method_fixup_vobjs (DB_VALUE *value_p) #endif #if defined (SERVER_MODE) || defined (SA_MODE) + +#if 0 /* * xmethod_invoke_fold_constants () - perform constant folding for method * return : error code @@ -626,3 +619,5 @@ int xmethod_invoke_fold_constants (THREAD_ENTRY *thread_p, const method_sig_list return error_code; } #endif + +#endif diff --git a/src/method/query_method.hpp b/src/method/query_method.hpp index 30fc2a4753..7821fd5303 100644 --- a/src/method/query_method.hpp +++ b/src/method/query_method.hpp @@ -34,7 +34,7 @@ // forward def struct method_sig_list; struct qfile_list_id; -struct method_sig_node; + #if defined(CS_MODE) extern int method_dispatch (unsigned int rc, char *methoddata, int methoddata_size); diff --git a/src/object/authenticate.c b/src/object/authenticate.c index 868fbb80f3..c84c356ba8 100644 --- a/src/object/authenticate.c +++ b/src/object/authenticate.c @@ -38,6 +38,8 @@ #include #include +#include + #include "porting.h" #include "misc_string.h" #include "memory_alloc.h" diff --git a/src/object/authenticate.h b/src/object/authenticate.h index fc38d5602b..f318db60fa 100644 --- a/src/object/authenticate.h +++ b/src/object/authenticate.h @@ -91,6 +91,10 @@ class print_output; #define au_check_user au_ctx ()->check_user #define au_has_user_name au_ctx ()->has_user_name +// execution rights +#define au_perform_push_user au_ctx ()->push_user +#define au_perform_pop_user au_ctx ()->pop_user + #define AU_SET_USER au_set_user // FIXME: To migrate legacy @@ -139,8 +143,8 @@ extern int au_login (const char *name, const char *password, bool ignore_dba_pri * GRANT/REVOKE OPERATIONS (authenticate_grant.cpp) */ -extern int au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option); -extern int au_revoke (MOP user, MOP class_mop, DB_AUTH type); +extern int au_grant (DB_OBJECT_TYPE obj_type, MOP user, MOP class_mop, DB_AUTH type, bool grant_option); +extern int au_revoke (DB_OBJECT_TYPE obj_type, MOP user, MOP class_mop, DB_AUTH type, MOP drop_user); #if defined (SA_MODE) extern int au_force_write_new_auth (void); @@ -208,6 +212,7 @@ extern bool au_is_server_authorized_user (DB_VALUE * owner_val); do \ { \ Au_cache.reset_authorization_caches (); \ + Au_cache.reset_user_cache (); \ } \ while (0) // @@ -216,7 +221,7 @@ extern bool au_is_server_authorized_user (DB_VALUE * owner_val); * MIGRATION OPERATIONS (authenticate_migration.cpp) */ extern int au_export_users (extract_context & ctxt, print_output & output_ctx); -extern int au_export_grants (extract_context & ctxt, print_output & output_ctx, MOP class_mop); +extern int au_export_grants (extract_context & ctxt, print_output & output_ctx, MOP class_mop, DB_OBJECT_TYPE obj_type); // /* @@ -242,6 +247,7 @@ extern void au_dump_auth (FILE * fp); // /* + * Etc * SET TYPE OPERATIONS */ extern int au_get_set (MOP obj, const char *attname, DB_SET ** set); diff --git a/src/object/authenticate_access_auth.cpp b/src/object/authenticate_access_auth.cpp index e64a38b14e..2d104958d6 100644 --- a/src/object/authenticate_access_auth.cpp +++ b/src/object/authenticate_access_auth.cpp @@ -32,6 +32,8 @@ #include "schema_manager.h" #include "schema_system_catalog_constants.h" +#include "jsp_cl.h" + const char *AU_TYPE_SET[] = { "SELECT", /* DB_AUTH_SELECT */ @@ -54,25 +56,24 @@ const int AU_TYPE_SET_LEN[] = strlen ("EXECUTE") /* DB_AUTH_EXECUTE */ }; -MOP au_auth_accessor::au_class_mop = nullptr; - au_auth_accessor::au_auth_accessor () : m_au_obj (nullptr) + , m_au_class_mop (nullptr) {} int au_auth_accessor::create_new_auth () { - if (au_class_mop == nullptr) + if (m_au_class_mop == nullptr) { - au_class_mop = sm_find_class (CT_CLASSAUTH_NAME); - if (au_class_mop == NULL) + m_au_class_mop = sm_find_class (CT_CLASSAUTH_NAME); + if (m_au_class_mop == nullptr) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_MISSING_CLASS, 1, CT_CLASSAUTH_NAME); } } - m_au_obj = db_create_internal (au_class_mop); + m_au_obj = db_create_internal (m_au_class_mop); if (m_au_obj == NULL) { assert (er_errid () != NO_ERROR); @@ -81,13 +82,16 @@ au_auth_accessor::create_new_auth () } int -au_auth_accessor::set_new_auth (MOP au_obj, MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type, bool grant_option) +au_auth_accessor::set_new_auth (DB_OBJECT_TYPE obj_type, MOP au_obj, MOP grantor, MOP user, MOP obj_mop, + DB_AUTH auth_type, bool grant_option) { - DB_VALUE value, class_name_val; - MOP db_class = nullptr, db_class_inst = nullptr; + DB_VALUE value; + MOP db_class = nullptr, inst_mop = nullptr; DB_AUTH type; int i; int error = NO_ERROR; + char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1]; + unique_name[0] = '\0'; m_au_obj = au_obj; if (m_au_obj == nullptr) @@ -101,24 +105,34 @@ au_auth_accessor::set_new_auth (MOP au_obj, MOP grantor, MOP user, MOP class_mop db_make_object (&value, user); obj_set (m_au_obj, AU_AUTH_ATTR_GRANTEE, &value); - db_class = sm_find_class (CT_CLASS_NAME); - if (db_class == NULL) + if (obj_type == DB_OBJECT_CLASS) { - assert (er_errid () != NO_ERROR); - return er_errid (); + inst_mop = obj_mop; } - - db_make_string (&class_name_val, sm_get_ch_name (class_mop)); - db_class_inst = obj_find_unique (db_class, "unique_name", &class_name_val, AU_FETCH_READ); - if (db_class_inst == NULL) + else { - assert (er_errid () != NO_ERROR); - pr_clear_value (&class_name_val); - return er_errid (); + // TODO: CBRD-24912 + if (jsp_get_unique_name (obj_mop, unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL) + { + assert (er_errid () != NO_ERROR); + pr_clear_value (&value); + return er_errid (); + } + + inst_mop = jsp_find_stored_procedure (unique_name, DB_AUTH_NONE); + if (inst_mop == NULL) + { + assert (er_errid () != NO_ERROR); + pr_clear_value (&value); + return er_errid (); + } } - db_make_object (&value, db_class_inst); - obj_set (m_au_obj, "class_of", &value); + db_make_int (&value, (int) obj_type); + obj_set (m_au_obj, "object_type", &value); + + db_make_object (&value, inst_mop); + obj_set (m_au_obj, "object_of", &value); for (type = DB_AUTH_SELECT, i = 0; type != auth_type; type = (DB_AUTH) (type << 1), i++); @@ -128,12 +142,12 @@ au_auth_accessor::set_new_auth (MOP au_obj, MOP grantor, MOP user, MOP class_mop db_make_int (&value, (int) grant_option); obj_set (m_au_obj, "is_grantable", &value); - pr_clear_value (&class_name_val); + pr_clear_value (&value); return NO_ERROR; } int -au_auth_accessor::get_new_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type) +au_auth_accessor::get_new_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type) { int error = NO_ERROR, save, i = 0; DB_VALUE val[COUNT_FOR_VARIABLES]; @@ -141,11 +155,15 @@ au_auth_accessor::get_new_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH au DB_QUERY_RESULT *result = NULL; DB_SESSION *session = NULL; STATEMENT_ID stmt_id; - const char *class_name; + const char *name; const char *sql_query = "SELECT [au].object FROM [" CT_CLASSAUTH_NAME "] [au]" " WHERE [au].[grantee].[name] = ? AND [au].[grantor].[name] = ?" - " AND [au].[class_of].[unique_name] = ? AND [au].[auth_type] = ?"; // TODO: static + " AND [au].[object_of] = (%s) AND [au].[auth_type] = ?"; + char obj_fetch_query[256]; + const char *class_unique_name = NULL; + char sp_unique_name[DB_MAX_IDENTIFIER_LENGTH + 1]; + char error_msg[ERR_MSG_SIZE]; for (i = 0; i < COUNT_FOR_VARIABLES; i++) { @@ -157,54 +175,107 @@ au_auth_accessor::get_new_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH au /* Disable the checking for internal authorization object access */ AU_DISABLE (save); + switch (obj_type) + { + case DB_OBJECT_CLASS: + class_unique_name = sm_get_ch_name (obj_mop); + if (class_unique_name == NULL) + { + assert (false); + error = ER_UNEXPECTED; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Cannot get class name of mop."); + goto exit; + } + + sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?"); + break; + case DB_OBJECT_PROCEDURE: + sp_unique_name[0] = '\0'; + if (jsp_get_unique_name (obj_mop, sp_unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL) + { + assert (false); + error = ER_UNEXPECTED; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Cannot get stored procedure name of mop."); + goto exit; + } + + sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?"); + break; + default: + assert (false); + error = ER_UNEXPECTED; + error_msg[0] = '\0'; + snprintf (error_msg, sizeof (error_msg) - 1, "unknown database object id: %d.", obj_type); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_msg); + goto exit; + } + + session = db_open_buffer_local (obj_fetch_query); + if (session == NULL) + { + assert (er_errid () != NO_ERROR); + goto exit; + } + + error = db_set_system_generated_statement (session); + if (error != NO_ERROR) + { + goto release; + } + + stmt_id = db_compile_statement_local (session); + if (stmt_id != 1) + { + assert (er_errid () != NO_ERROR); + goto release; + } + /* Prepare DB_VALUEs for host variables */ error = obj_get (user, "name", &val[INDEX_FOR_GRANTEE_NAME]); if (error != NO_ERROR) { - goto exit; + goto release; } else if (!DB_IS_STRING (&val[INDEX_FOR_GRANTEE_NAME]) || DB_IS_NULL (&val[INDEX_FOR_GRANTEE_NAME]) || db_get_string (&val[INDEX_FOR_GRANTEE_NAME]) == NULL) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_MISSING_OR_INVALID_USER, 0); - goto exit; + goto release; } error = obj_get (grantor, "name", &val[INDEX_FOR_GRANTOR_NAME]); if (error != NO_ERROR) { - goto exit; + goto release; } else if (!DB_IS_STRING (&val[INDEX_FOR_GRANTOR_NAME]) || DB_IS_NULL (&val[INDEX_FOR_GRANTOR_NAME]) || db_get_string (&val[INDEX_FOR_GRANTOR_NAME]) == NULL) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_MISSING_OR_INVALID_USER, 0); - goto exit; + goto release; } - class_name = db_get_class_name (class_mop); - if (class_name == NULL) + switch (obj_type) { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_CLASS, 0); - goto exit; + case DB_OBJECT_CLASS: + db_make_string (&val[INDEX_FOR_OBJECT_NAME], class_unique_name); + break; + case DB_OBJECT_PROCEDURE: + db_make_string (&val[INDEX_FOR_OBJECT_NAME], sp_unique_name); + break; + default: + assert (false); + error = ER_FAILED; + goto release; } - db_make_string (&val[INDEX_FOR_CLASS_NAME], class_name); i = 0; for (DB_AUTH type = DB_AUTH_SELECT; type != auth_type; type = (DB_AUTH) (type << 1)) { i++; } - db_make_string (&val[INDEX_FOR_AUTH_TYPE], AU_TYPE_SET[i]); - session = db_open_buffer (sql_query); - if (session == NULL) - { - assert (er_errid () != NO_ERROR); - goto release; - } - error = db_push_values (session, COUNT_FOR_VARIABLES, val); if (error != NO_ERROR) { @@ -212,13 +283,6 @@ au_auth_accessor::get_new_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH au goto release; } - stmt_id = db_compile_statement (session); - if (stmt_id != 1) - { - assert (er_errid () != NO_ERROR); - goto release; - } - error = db_execute_statement_local (session, stmt_id, &result); /* The error value is row count if it's not negative value. */ @@ -282,14 +346,15 @@ au_auth_accessor::get_new_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH au } int -au_auth_accessor::insert_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type, int grant_option) +au_auth_accessor::insert_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type, + int grant_option) { int error = NO_ERROR; for (int index = DB_AUTH_EXECUTE; index; index >>= 1) { if (auth_type & index) { - error = set_new_auth (NULL, grantor, user, class_mop, (DB_AUTH) index, + error = set_new_auth (obj_type, NULL, grantor, user, obj_mop, (DB_AUTH) index, ((grant_option & index) ? true : false)); if (error != NO_ERROR) { @@ -302,14 +367,15 @@ au_auth_accessor::insert_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH aut } int -au_auth_accessor::update_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type, int grant_option) +au_auth_accessor::update_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type, + int grant_option) { int error = NO_ERROR; for (int index = DB_AUTH_EXECUTE; index; index >>= 1) { if (auth_type & index) { - error = get_new_auth (grantor, user, class_mop, (DB_AUTH) index); + error = get_new_auth (obj_type, grantor, user, obj_mop, (DB_AUTH) index); if (error != NO_ERROR) { return error; @@ -323,7 +389,7 @@ au_auth_accessor::update_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH aut return error; } - error = set_new_auth (m_au_obj, grantor, user, class_mop, (DB_AUTH) index, + error = set_new_auth (obj_type, m_au_obj, grantor, user, obj_mop, (DB_AUTH) index, ((grant_option & index) ? true : false)); if (error != NO_ERROR) { @@ -336,14 +402,14 @@ au_auth_accessor::update_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH aut } int -au_auth_accessor::delete_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type) +au_auth_accessor::delete_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type) { int error = NO_ERROR; for (int index = DB_AUTH_EXECUTE; index; index >>= 1) { if (auth_type & index) { - error = get_new_auth (grantor, user, class_mop, (DB_AUTH) index); + error = get_new_auth (obj_type, grantor, user, obj_mop, (DB_AUTH) index); if (error != NO_ERROR) { return error; @@ -440,32 +506,45 @@ au_delete_auth_of_dropping_user (MOP user) return error; } - /* - * au_delete_auth_of_dropping_table - delete _db_auth records refers to the given table. + * au_delete_auth_of_dropping_database_object - delete _db_auth records refers to the given database object. * return: error code - * class_name(in): the class name to be dropped + * obj_type(in): the object type + * name(in): the object name to be dropped */ int -au_delete_auth_of_dropping_table (const char *class_name) +au_delete_auth_of_dropping_database_object (DB_OBJECT_TYPE obj_type, const char *name) { int error = NO_ERROR, save; - const char *sql_query = - "DELETE FROM [" CT_CLASSAUTH_NAME "] [au]" " WHERE [au].[class_of] IN" " (SELECT [cl] FROM " CT_CLASS_NAME - " [cl] WHERE [unique_name] = ?);"; + const char *sql_query = "DELETE FROM [" CT_CLASSAUTH_NAME "] [au]" " WHERE [au].[object_of] IN (%s);"; DB_VALUE val; DB_QUERY_RESULT *result = NULL; DB_SESSION *session = NULL; int stmt_id; + char obj_fetch_query[256]; db_make_null (&val); /* Disable the checking for internal authorization object access */ AU_DISABLE (save); - assert (class_name != NULL); + assert (name != NULL); - session = db_open_buffer_local (sql_query); + switch (obj_type) + { + case DB_OBJECT_CLASS: + sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?"); + break; + case DB_OBJECT_PROCEDURE: + sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?"); + break; + default: + assert (false); + error = ER_FAILED; + goto exit; + } + + session = db_open_buffer_local (obj_fetch_query); if (session == NULL) { ASSERT_ERROR_AND_SET (error); @@ -485,7 +564,7 @@ au_delete_auth_of_dropping_table (const char *class_name) goto release; } - db_make_string (&val, class_name); + db_make_string (&val, name); error = db_push_values (session, 1, &val); if (error != NO_ERROR) { @@ -584,3 +663,485 @@ au_delete_authorizartion_of_dropping_user (MOP user) return error; } + +/* + * au_object_revoke_all_privileges - drop a class, virtual class and procedure, or when changing the owner, all privileges are revoked. + * return: error code + * obj_mop(in): a class/stored procedure object + * grantor_mop(in): a class/stored procedure owner + */ +int +au_object_revoke_all_privileges (DB_OBJECT_TYPE obj_type, MOP grantor_mop, const char *unique_name) +{ + int error = NO_ERROR, save, len, i = 0; + const char *auth; + DB_AUTH db_auth; + MOP grantee_mop, object_of_mop; + DB_VALUE val[2]; + DB_VALUE grantee_value, object_of_value, auth_type_value; + DB_QUERY_RESULT *result = NULL; + DB_SESSION *session = NULL; + int stmt_id; + int row_count = -1; + char obj_fetch_query[256]; + const char *sql_query = + "SELECT [au].grantee, [au].object_of, [au].auth_type FROM [" CT_CLASSAUTH_NAME "] [au]" + " WHERE [au].[grantor].[name] = ? AND [au].[object_of] = (%s);"; + + assert (grantor_mop != NULL && unique_name != NULL); + + for (i = 0; i < 2; i++) + { + db_make_null (&val[i]); + } + + db_make_null (&grantee_value); + db_make_null (&object_of_value); + db_make_null (&auth_type_value); + + /* Disable the checking for internal authorization object access */ + AU_DISABLE (save); + + switch (obj_type) + { + case DB_OBJECT_CLASS: + sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?"); + break; + case DB_OBJECT_PROCEDURE: + sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?"); + break; + default: + assert (false); + error = ER_FAILED; + goto exit; + } + + session = db_open_buffer_local (obj_fetch_query); + if (session == NULL) + { + ASSERT_ERROR_AND_SET (error); + goto exit; + } + + error = db_set_system_generated_statement (session); + if (error != NO_ERROR) + { + goto release; + } + + stmt_id = db_compile_statement_local (session); + if (stmt_id < 0) + { + ASSERT_ERROR_AND_SET (error); + goto release; + } + + /* Prepare DB_VALUEs for host variables */ + error = obj_get (grantor_mop, "name", &val[0]); + if (error != NO_ERROR) + { + goto release; + } + else if (!DB_IS_STRING (&val[0]) || DB_IS_NULL (&val[0]) + || db_get_string (&val[0]) == NULL) + { + error = ER_AU_MISSING_OR_INVALID_USER; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto release; + } + + db_make_string (&val[1], unique_name); + + error = db_push_values (session, 2, val); + if (error != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + goto release; + } + + error = db_execute_statement_local (session, stmt_id, &result); + + /* The error value is row count if it's not negative value. */ + if (error == 0) + { + row_count = error; + goto release; + } + else if (error < 0) + { + assert (er_errid () != NO_ERROR); + goto release; + } + + row_count = error; + error = NO_ERROR; + + while (db_query_next_tuple (result) == DB_CURSOR_SUCCESS) + { + if (db_query_get_tuple_value (result, 0, &grantee_value) == NO_ERROR) + { + grantee_mop = NULL; + if (!DB_IS_NULL (&grantee_value)) + { + grantee_mop = db_get_object (&grantee_value); + } + else + { + goto release; + } + } + + if (db_query_get_tuple_value (result, 1, &object_of_value) == NO_ERROR) + { + object_of_mop = NULL; + if (!DB_IS_NULL (&object_of_value)) + { + object_of_mop = db_get_object (&object_of_value); + } + else + { + goto release; + } + } + + if (db_query_get_tuple_value (result, 2, &auth_type_value) == NO_ERROR) + { + auth = NULL; + if (!DB_IS_NULL (&auth_type_value)) + { + auth = db_get_char (&auth_type_value, &len); + + switch (auth[0]) + { + case 'A': + db_auth = DB_AUTH_ALTER; + break; + + case 'D': + db_auth = DB_AUTH_DELETE; + break; + + case 'E': + db_auth = DB_AUTH_EXECUTE; + break; + + case 'I': + if (auth[2] == 'D') + { + db_auth = DB_AUTH_INDEX; + } + else if (auth[2] == 'S') + { + db_auth = DB_AUTH_INSERT; + } + else + { + db_auth = DB_AUTH_NONE; + } + break; + + case 'S': + db_auth = DB_AUTH_SELECT; + break; + + case 'U': + db_auth = DB_AUTH_UPDATE; + break; + + default: + db_auth = DB_AUTH_NONE; + break; + } + } + else + { + goto release; + } + } + + assert (grantee_mop != NULL); + assert (object_of_mop != NULL); + assert (db_auth != DB_AUTH_NONE); + + error = au_revoke (obj_type, grantee_mop, object_of_mop, db_auth, NULL); + if (error != NO_ERROR) + { + goto release; + } + } + +release: + if (result != NULL) + { + db_query_end (result); + } + if (session != NULL) + { + db_close_session (session); + } + +exit: + AU_ENABLE (save); + + db_value_clear (&grantee_value); + db_value_clear (&object_of_value); + db_value_clear (&auth_type_value); + + for (i = 0; i < 2; i++) + { + db_value_clear (&val[i]); + } + + if (row_count < 0 && er_errid () == NO_ERROR && (grantee_mop == NULL || object_of_mop == NULL + || auth == NULL || db_auth == DB_AUTH_NONE)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0); + error = ER_GENERIC_ERROR; + } + + return (error); +} + +/* + * au_user_revoke_all_privileges - when a user is deleted, all of their privileges are revoked. + * return: error code + * user_mop(in): a user object + */ +int +au_user_revoke_all_privileges (MOP user_mop) +{ + int error = NO_ERROR, save, len; + int object_type; + DB_OBJECT_TYPE obj_type; + const char *auth; + DB_AUTH db_auth; + MOP grantee_mop, obj_mop; + DB_VALUE name; + DB_VALUE grantee_value, object_type_value, object_of_value, auth_type_value; + DB_QUERY_RESULT *result = NULL; + DB_SESSION *session = NULL; + int stmt_id; + int row_count = -1; + const char *sql_query = + "SELECT [au].grantee, [au].object_type, [au].object_of, [au].auth_type FROM [" CT_CLASSAUTH_NAME "] [au]" + " WHERE [au].[grantor].[name] = ?"; + + assert (user_mop != NULL); + + + db_make_null (&name); + db_make_null (&grantee_value); + db_make_null (&object_type_value); + db_make_null (&object_of_value); + db_make_null (&auth_type_value); + + /* Disable the checking for internal authorization object access */ + AU_DISABLE (save); + + session = db_open_buffer_local (sql_query); + if (session == NULL) + { + ASSERT_ERROR_AND_SET (error); + goto exit; + } + + error = db_set_system_generated_statement (session); + if (error != NO_ERROR) + { + goto release; + } + + stmt_id = db_compile_statement_local (session); + if (stmt_id < 0) + { + ASSERT_ERROR_AND_SET (error); + goto release; + } + + /* Prepare DB_VALUEs for host variables */ + error = obj_get (user_mop, "name", &name); + if (error != NO_ERROR) + { + goto release; + } + else if (!DB_IS_STRING (&name) || DB_IS_NULL (&name) + || db_get_string (&name) == NULL) + { + error = ER_AU_MISSING_OR_INVALID_USER; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto release; + } + + error = db_push_values (session, 1, &name); + if (error != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + goto release; + } + + error = db_execute_statement_local (session, stmt_id, &result); + + /* The error value is row count if it's not negative value. */ + if (error == 0) + { + row_count = error; + goto release; + } + else if (error < 0) + { + assert (er_errid () != NO_ERROR); + goto release; + } + + row_count = error; + error = NO_ERROR; + + while (db_query_next_tuple (result) == DB_CURSOR_SUCCESS) + { + if (db_query_get_tuple_value (result, 0, &grantee_value) == NO_ERROR) + { + grantee_mop = NULL; + if (!DB_IS_NULL (&grantee_value)) + { + grantee_mop = db_get_object (&grantee_value); + } + else + { + goto release; + } + } + + if (db_query_get_tuple_value (result, 1, &object_type_value) == NO_ERROR) + { + object_type = 0; + if (!DB_IS_NULL (&object_type_value)) + { + object_type = db_get_int (&object_type_value); + switch (object_type) + { + case 0: + obj_type = DB_OBJECT_CLASS; + break; + + case 5: + obj_type = DB_OBJECT_PROCEDURE; + break; + + default: + assert (object_type == 0 || object_type == 5); + goto release; + } + } + else + { + goto release; + } + } + + if (db_query_get_tuple_value (result, 2, &object_of_value) == NO_ERROR) + { + obj_mop = NULL; + if (!DB_IS_NULL (&object_of_value)) + { + obj_mop = db_get_object (&object_of_value); + } + else + { + goto release; + } + } + + if (db_query_get_tuple_value (result, 3, &auth_type_value) == NO_ERROR) + { + auth = NULL; + if (!DB_IS_NULL (&auth_type_value)) + { + auth = db_get_char (&auth_type_value, &len); + + switch (auth[0]) + { + case 'A': + db_auth = DB_AUTH_ALTER; + break; + + case 'D': + db_auth = DB_AUTH_DELETE; + break; + + case 'E': + db_auth = DB_AUTH_EXECUTE; + break; + + case 'I': + if (auth[2] == 'D') + { + db_auth = DB_AUTH_INDEX; + } + else if (auth[2] == 'S') + { + db_auth = DB_AUTH_INSERT; + } + else + { + db_auth = DB_AUTH_NONE; + } + break; + + case 'S': + db_auth = DB_AUTH_SELECT; + break; + + case 'U': + db_auth = DB_AUTH_UPDATE; + break; + + default: + db_auth = DB_AUTH_NONE; + break; + } + } + else + { + goto release; + } + } + + assert (grantee_mop != NULL); + assert (obj_mop != NULL); + assert (db_auth != DB_AUTH_NONE); + + error = au_revoke (obj_type, grantee_mop, obj_mop, db_auth, user_mop); + if (error != NO_ERROR) + { + goto release; + } + } + +release: + if (result != NULL) + { + db_query_end (result); + } + if (session != NULL) + { + db_close_session (session); + } + +exit: + AU_ENABLE (save); + + db_value_clear (&grantee_value); + db_value_clear (&object_type_value); + db_value_clear (&object_of_value); + db_value_clear (&auth_type_value); + db_value_clear (&name); + + if (row_count < 0 && er_errid () == NO_ERROR && (grantee_mop == NULL || obj_mop == NULL || auth == NULL + || db_auth == DB_AUTH_NONE || (object_type != 0 && object_type != 5))) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0); + error = ER_GENERIC_ERROR; + } + + return (error); +} \ No newline at end of file diff --git a/src/object/authenticate_access_auth.hpp b/src/object/authenticate_access_auth.hpp index 8be9573b84..297e2483be 100644 --- a/src/object/authenticate_access_auth.hpp +++ b/src/object/authenticate_access_auth.hpp @@ -46,7 +46,7 @@ class au_auth_accessor { private: // TODO: thread safe? - static MOP au_class_mop; + MOP m_au_class_mop; MOP m_au_obj; @@ -54,26 +54,27 @@ class au_auth_accessor { INDEX_FOR_GRANTEE_NAME = 0, INDEX_FOR_GRANTOR_NAME = 1, - INDEX_FOR_CLASS_NAME = 2, + INDEX_FOR_OBJECT_NAME = 2, INDEX_FOR_AUTH_TYPE = 3, /* Total count for the above */ COUNT_FOR_VARIABLES }; int create_new_auth (); - int set_new_auth (MOP au_object, MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type, bool grant_option); - int get_new_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type); + int set_new_auth (DB_OBJECT_TYPE obj_type, MOP au_object, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type, + bool grant_option); + int get_new_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type); public: explicit au_auth_accessor (); - int insert_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type, int grant_option); - int update_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type, int grant_option); - int delete_auth (MOP grantor, MOP user, MOP class_mop, DB_AUTH auth_type); + int insert_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type, int grant_option); + int update_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type, int grant_option); + int delete_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type); - static MOP get_auth_class_mop () + MOP get_auth_class_mop () { - return au_class_mop; + return m_au_class_mop; } MOP get_auth_object () @@ -93,6 +94,16 @@ extern int au_delete_auth_of_dropping_user (MOP user); extern int au_delete_authorizartion_of_dropping_user (MOP user); // delete _db_auth records refers to the given table -extern int au_delete_auth_of_dropping_table (const char *class_name); +extern int au_delete_auth_of_dropping_database_object (DB_OBJECT_TYPE obj_type, const char *name); + +/* +* drop a class, virtual class and procedure, or when changing the owner, all privileges are revoked. +*/ +extern int au_object_revoke_all_privileges (DB_OBJECT_TYPE obj_type, MOP grantor_mop, const char *unique_name); + +/* +* when a user is deleted, all of their privileges are revoked. +*/ +extern int au_user_revoke_all_privileges (MOP user_mop); #endif // _authenticate_access_auth_HPP_ \ No newline at end of file diff --git a/src/object/authenticate_access_user.cpp b/src/object/authenticate_access_user.cpp index 0cf0740d67..22d838b4d1 100644 --- a/src/object/authenticate_access_user.cpp +++ b/src/object/authenticate_access_user.cpp @@ -73,6 +73,7 @@ au_find_user (const char *user_name) char *upper_case_name; size_t upper_case_name_size; DB_VALUE user_name_string; + AU_USER_CACHE *user_cache = nullptr; if (user_name == NULL) { @@ -96,9 +97,6 @@ au_find_user (const char *user_name) } } - /* disable checking of internal authorization object access */ - AU_DISABLE (save); - user = NULL; upper_case_name_size = intl_identifier_upper_string_size (user_name); @@ -110,6 +108,17 @@ au_find_user (const char *user_name) } intl_identifier_upper (user_name, upper_case_name); + user_cache = Au_cache.find_user_cache_by_name (upper_case_name); + if (user_cache) + { + user = user_cache->user; + assert (user != NULL); + return user; + } + + /* disable checking of internal authorization object access */ + AU_DISABLE (save); + /* * first try to find the user id by index. This is faster than * a query, and will not get blocked out as a server request @@ -174,6 +183,11 @@ au_find_user (const char *user_name) } } + if (user) + { + (void) Au_cache.make_user_cache (user_name, user, false); + } + exit: AU_ENABLE (save); @@ -636,6 +650,12 @@ au_add_user (const char *name, int *exists) } AU_ENABLE (save); } + + if (user != NULL) + { + (void) Au_cache.make_user_cache (name, user, false); + } + return (user); } @@ -1350,6 +1370,13 @@ au_drop_user (MOP user) } } + /* before deleting an user, all permissions are revoked. */ + error = au_user_revoke_all_privileges (user); + if (error != NO_ERROR) + { + goto error; + } + error = au_delete_auth_of_dropping_user (user); if (error != NO_ERROR) { @@ -1370,7 +1397,7 @@ au_drop_user (MOP user) error = obj_delete (user); if (error == NO_ERROR) { - Au_cache.remove_user_cache_references (user); + Au_cache.remove_user_cache (user); } error: diff --git a/src/object/authenticate_cache.cpp b/src/object/authenticate_cache.cpp index dcbb614808..8369626bec 100644 --- a/src/object/authenticate_cache.cpp +++ b/src/object/authenticate_cache.cpp @@ -28,7 +28,22 @@ #include "schema_manager.h" #include "set_object.h" -static void free_user_cache (AU_USER_CACHE *u); +au_class_cache::au_class_cache (int depth) +{ + next = NULL; + class_ = NULL; + data = new unsigned int[depth]; + std::fill_n (data, depth, AU_CACHE_INVALID); +} + +au_class_cache::~au_class_cache () +{ + if (data) + { + delete [] data; + data = nullptr; + } +} authenticate_cache::authenticate_cache () { @@ -51,7 +66,6 @@ authenticate_cache::init (void) cache_index = -1; } - /* * flush_caches - Called during au_final(). Free the authorization cache * structures and initialize the global variables @@ -75,6 +89,7 @@ authenticate_cache::flush (void) nextu = u->next; free_user_cache (u); } + user_name_cache.clear (); /* clear the associated globals */ init (); @@ -281,6 +296,7 @@ authenticate_cache::free_authorization_cache (void *cache) { AU_CLASS_CACHE *c, *prev; + prev = NULL; if (cache != NULL) { for (c = class_caches, prev = NULL; c != NULL && c != cache; c = c->next) @@ -297,12 +313,11 @@ authenticate_cache::free_authorization_cache (void *cache) { prev->next = c->next; } + free_class_cache ((AU_CLASS_CACHE *) cache); } - free_class_cache ((AU_CLASS_CACHE *) cache); } } - /* * AUTHORIZATION CACHES */ @@ -325,20 +340,12 @@ authenticate_cache::make_class_cache (int depth) } else { - size = sizeof (AU_CLASS_CACHE) + ((depth - 1) * sizeof (unsigned int)); - new_class_cache = (AU_CLASS_CACHE *) malloc (size); + new_class_cache = new (std::nothrow) AU_CLASS_CACHE (depth); if (new_class_cache == NULL) { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, size); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (AU_CLASS_CACHE)); return NULL; } - - new_class_cache->next = NULL; - new_class_cache->class_ = NULL; - for (i = 0; i < depth; i++) - { - new_class_cache->data[i] = AU_CACHE_INVALID; - } } return new_class_cache; @@ -354,7 +361,7 @@ authenticate_cache::free_class_cache (AU_CLASS_CACHE *cache) { if (cache != NULL) { - free_and_init (cache); + delete cache; } } @@ -472,72 +479,122 @@ authenticate_cache::extend_class_caches (int *index) } /* - * au_find_user_cache_index - This determines the cache index for the given - * user. - * return: error code - * user(in): user object - * index(out): returned user index - * check_it(in): + * make_user_cache - This creates a new user cache and appends it to the user cache list + * return: user cache + * name(in): user name + * user(in): user MOP * - * Note: If the user has never been added to the authorization cache, - * we reserve a new index for the user. Reserving the user index may - * result in growing all the existing class caches. - * This is the primary work function for AU_SET_USER() and it should - * be fast. */ -int -authenticate_cache::find_user_cache_index (DB_OBJECT *user, int *index, int check_it) +AU_USER_CACHE * +authenticate_cache::make_user_cache (const char *name, DB_OBJECT *user, bool sanity_check) { - int error = NO_ERROR; - AU_USER_CACHE *u, *new_user_cache; - DB_OBJECT *class_mop; + AU_USER_CACHE *new_user_cache = nullptr; + assert (name != nullptr); + assert (user != nullptr); - for (u = user_cache; u != NULL && !ws_is_same_object (u->user, user); u = u->next) - ; - - if (u != NULL) - { - *index = u->index; - } - else + if (sanity_check) { /* - * User wasn't in the cache, add it and extend the existing class - * caches. First do a little sanity check just to make sure this - * is a user object. - */ - if (check_it) + * User wasn't in the cache, add it and extend the existing class + * caches. First do a little sanity check just to make sure this + * is a user object. + */ + DB_OBJECT *class_mop = sm_get_class (user); + if (class_mop == NULL) { - class_mop = sm_get_class (user); - if (class_mop == NULL) - { - assert (er_errid () != NO_ERROR); - return er_errid (); - } - else if (class_mop != Au_user_class) - { - error = ER_AU_CORRUPTED; /* need a better error */ - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); - return er_errid (); - } + assert (er_errid () != NO_ERROR); + return NULL; } + else if (class_mop != Au_user_class) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_CORRUPTED, 0); /* need a better error */ + return NULL; + } + } + + std::string upper_case_name (name); + std::transform (upper_case_name.begin(), upper_case_name.end(), upper_case_name.begin(), ::toupper); + + if ((new_user_cache = find_user_cache_by_name (upper_case_name.c_str ())) != nullptr) + { + return new_user_cache; + } + + new_user_cache = new AU_USER_CACHE; + if (new_user_cache != nullptr) + { + new_user_cache->next = user_cache; + user_cache = new_user_cache; + + new_user_cache->name = upper_case_name; + new_user_cache->user = user; + new_user_cache->index = -1; + + user_name_cache.insert (std::pair (upper_case_name, new_user_cache)); + } + + return new_user_cache; +} + +/* + * find_user_cache_by_name - This determines the cache for the given user name. + * return: user cache + * name(in): user name + * + */ +AU_USER_CACHE * +authenticate_cache::find_user_cache_by_name (const char *name) +{ + if (name == nullptr) + { + return nullptr; + } + + AU_USER_CACHE *user_cache = nullptr; + + const auto &it = user_name_cache.find (name); + if (it != user_name_cache.end()) + { + user_cache = it->second; + } + + return user_cache; +} + +/* + * find_user_cache_by_mop - This determines the cache for the given user MOP. + * return: user cache + * user(in): user mop + * + */ +AU_USER_CACHE * +authenticate_cache::find_user_cache_by_mop (DB_OBJECT *user) +{ + AU_USER_CACHE *u; + + for (u = user_cache; u != NULL && !ws_is_same_object (u->user, user); u = u->next) + ; + + return u; +} - new_user_cache = (AU_USER_CACHE *) malloc (sizeof (AU_USER_CACHE)); - if (new_user_cache != NULL) +int +authenticate_cache::get_user_cache_index (AU_USER_CACHE *cache, int *index) +{ + int error = NO_ERROR; + + if (cache->index == -1) + { + error = extend_class_caches (index); + if (error == NO_ERROR) { - if ((error = extend_class_caches (index))) - { - free_and_init (new_user_cache); - } - else - { - new_user_cache->next = user_cache; - user_cache = new_user_cache; - new_user_cache->user = user; - new_user_cache->index = *index; - } + cache->index = *index; } } + else + { + *index = cache->index; + } return error; } @@ -552,12 +609,18 @@ authenticate_cache::free_user_cache (AU_USER_CACHE *u) { if (u != NULL) { + u->next = NULL; u->user = NULL; /* clear GC roots */ - free_and_init (u); + + if (!u->name.empty ()) + { + user_name_cache.erase (u->name); + } + + delete u; } } - /* * reset_cache_for_user_and_class - This is called whenever a grant or revoke * operation is performed. It resets the @@ -590,7 +653,14 @@ authenticate_cache::reset_cache_for_user_and_class (SM_CLASS *sm_class) */ for (u = user_cache; u != NULL; u = u->next) { - c->data[u->index] = AU_CACHE_INVALID; + // NOTE: u->index is initalized as -1 + // This means that the user is cached in a context that is independent of the class, + // for example, obtaining the user object in the execution context of another database object, + // such as the owner's right of procedure or a user management method. + if (u->index >= 0) + { + c->data[u->index] = AU_CACHE_INVALID; + } } } } @@ -626,30 +696,57 @@ authenticate_cache::reset_authorization_caches (void) } /* - * remove_user_cache_reference - This is called when a user object is deleted. + * remove_user_cache - This is called when a user object is deleted. * return: none * user(in): user object * - * Note: If there is an authorization cache entry for this user, we NULL - * the user pointer so it will no longer be used. We could to in - * and restructure all the caches to remove the deleted user but user - * deletion isn't that common. Just leave an unused entry in the - * cache array. */ void -authenticate_cache::remove_user_cache_references (MOP user) +authenticate_cache::remove_user_cache (MOP user) { - AU_USER_CACHE *u; + AU_USER_CACHE *u, *prevu, *nextu; - for (u = user_cache; u != NULL; u = u->next) + prevu = NULL; + for (u = user_cache; u != NULL; u = nextu) { + nextu = u->next; if (ws_is_same_object (u->user, user)) { - u->user = NULL; + if (prevu == NULL) + { + user_cache = nextu; + } + else + { + prevu->next = nextu; + } + free_user_cache (u); + break; + } + else + { + prevu = u; } } } +/* + * reset_user_cache - This is called when a user object is invalidated. + * return: none + */ +void +authenticate_cache::reset_user_cache (void) +{ + AU_USER_CACHE *u = user_cache; + while (u != NULL) + { + AU_USER_CACHE *nextu = u->next; + free_user_cache (u); + u = nextu; + } + user_cache = NULL; +} + /* * au_print_cache() - * return: none diff --git a/src/object/authenticate_cache.hpp b/src/object/authenticate_cache.hpp index a0900b5339..17405217b2 100644 --- a/src/object/authenticate_cache.hpp +++ b/src/object/authenticate_cache.hpp @@ -26,6 +26,9 @@ #include "class_object.h" /* SM_CLASS */ +#include +#include + /* Invalid cache is identified when the high bit is on. */ #define AU_CACHE_INVALID 0x80000000 @@ -49,7 +52,11 @@ struct au_class_cache struct au_class_cache *next; SM_CLASS *class_; - unsigned int data[1]; + unsigned int *data; + + au_class_cache () = delete; + au_class_cache (int depth); + ~au_class_cache (); }; /* @@ -65,8 +72,11 @@ struct au_user_cache { struct au_user_cache *next; + std::string name; DB_OBJECT *user; int index; + + au_user_cache() = default; }; /* @@ -84,6 +94,15 @@ class authenticate_cache */ AU_USER_CACHE *user_cache; + /* + * Au_user_name_cache + * + * The map of user name to user cache + */ + using user_name_cache_t = std::unordered_map; + + user_name_cache_t user_name_cache; + /* * Au_class_caches * @@ -132,12 +151,18 @@ class authenticate_cache unsigned int *get_cache_bits (SM_CLASS *sm_class); void free_authorization_cache (void *cache); - int find_user_cache_index (DB_OBJECT *user, int *index, int check_it); + + AU_USER_CACHE *make_user_cache (const char *name, DB_OBJECT *user, bool sanity_check); + AU_USER_CACHE *find_user_cache_by_name (const char *name); + AU_USER_CACHE *find_user_cache_by_mop (DB_OBJECT *user); + + int get_user_cache_index (AU_USER_CACHE *cache, int *index); void reset_cache_for_user_and_class (SM_CLASS *sm_class); void reset_authorization_caches (void); - void remove_user_cache_references (MOP user); + void remove_user_cache (MOP user); + void reset_user_cache (void); void print_cache (int cache, FILE *fp); // for debugging @@ -147,6 +172,7 @@ class authenticate_cache void free_class_cache (AU_CLASS_CACHE *cache); AU_CLASS_CACHE *install_class_cache (SM_CLASS *sm_class); int extend_class_caches (int *index); + void free_user_cache (AU_USER_CACHE *u); }; diff --git a/src/object/authenticate_constants.h b/src/object/authenticate_constants.h index 21bb4029b5..a65d2204a0 100644 --- a/src/object/authenticate_constants.h +++ b/src/object/authenticate_constants.h @@ -71,16 +71,7 @@ #define MSGCAT_AUTH_AUTH_TITLE 15 #define MSGCAT_AUTH_USER_DIRECT_GROUPS 16 -enum AU_OBJECT -{ - AU_OBJECT_CLASS, /* TABLE, VIEW (_db_class) */ - AU_OBJECT_TRIGGER, /* TRIGGER (_db_trigger) */ - AU_OBJECT_SERIAL, /* SERIAL (db_serial) */ - AU_OBJECT_SERVER, /* SERVER (db_server) */ - AU_OBJECT_SYNONYM, /* SYNONYM (_db_synonym) */ - AU_OBJECT_PROCEDURE /* PROCEDURE, FUNCTION (_db_stored_procedure) */ -}; - +typedef DB_OBJECT_TYPE AU_OBJECT; /* * Mask to extract only the authorization bits from a cache. This can also diff --git a/src/object/authenticate_context.cpp b/src/object/authenticate_context.cpp index 95bcb2be32..de5a986820 100644 --- a/src/object/authenticate_context.cpp +++ b/src/object/authenticate_context.cpp @@ -293,6 +293,7 @@ authenticate_context::install (void) { MOP root_cls = NULL, user_cls = NULL, pass_cls = NULL, auth_cls = NULL, old_cls = NULL; SM_TEMPLATE *def; + AU_USER_CACHE *user_cache; int exists, save, index; AU_DISABLE (save); @@ -490,10 +491,17 @@ authenticate_context::install (void) } /* establish the DBA as the current user */ - if (caches.find_user_cache_index (dba_user, &index, 0) != NO_ERROR) + user_cache = caches.find_user_cache_by_mop (dba_user); + if (user_cache == NULL) + { + user_cache = caches.make_user_cache (AU_DBA_USER_NAME, dba_user, false); + } + + if (caches.get_user_cache_index (user_cache, &index) != NO_ERROR) { goto exit_on_error; } + current_user = dba_user; Au_cache.set_cache_index (index); @@ -516,11 +524,11 @@ authenticate_context::install (void) * grant browser access to the authorization objects * note that the password class cannot be read by anyone except the DBA */ - au_grant (public_user, root_cls, (DB_AUTH) (AU_SELECT | AU_EXECUTE), false); - au_grant (public_user, old_cls, (DB_AUTH) (AU_SELECT | AU_EXECUTE), false); - au_grant (public_user, user_cls, AU_SELECT, false); - au_grant (public_user, user_cls, (DB_AUTH) (AU_SELECT | AU_EXECUTE), false); - au_grant (public_user, auth_cls, AU_SELECT, false); + au_grant (DB_OBJECT_CLASS, public_user, root_cls, (DB_AUTH) (AU_SELECT | AU_EXECUTE), false); + au_grant (DB_OBJECT_CLASS, public_user, old_cls, (DB_AUTH) (AU_SELECT | AU_EXECUTE), false); + au_grant (DB_OBJECT_CLASS, public_user, user_cls, AU_SELECT, false); + au_grant (DB_OBJECT_CLASS, public_user, user_cls, (DB_AUTH) (AU_SELECT | AU_EXECUTE), false); + au_grant (DB_OBJECT_CLASS, public_user, auth_cls, AU_SELECT, false); au_add_method_check_authorization (); @@ -711,26 +719,41 @@ authenticate_context::set_user (MOP newuser) { int error = NO_ERROR; int index; + AU_USER_CACHE *user_cache; if (newuser != NULL && !ws_is_same_object (newuser, current_user)) { - if (! (error = caches.find_user_cache_index (newuser, &index, 1))) + user_cache = caches.find_user_cache_by_mop (newuser); + if (!user_cache) { + const char *user_name = au_get_user_name (newuser); + user_cache = caches.make_user_cache (user_name, newuser, false); + } - current_user = newuser; - caches.set_cache_index (index); + if (user_cache) + { + if (caches.get_user_cache_index (user_cache, &index) == NO_ERROR) + { + current_user = newuser; + caches.set_cache_index (index); - /* - * it is important that we don't call sm_bump_local_schema_version() here - * because this function is called during the compilation of vclasses - */ + /* + * it is important that we don't call sm_bump_local_schema_version() here + * because this function is called during the compilation of vclasses + */ - /* - * Entry-level SQL specifies that the schema name is the same as - * the current user authorization name. In any case, this is - * the place to set the current schema since the user just changed. - */ - error = sc_set_current_schema (current_user); + /* + * Entry-level SQL specifies that the schema name is the same as + * the current user authorization name. In any case, this is + * the place to set the current schema since the user just changed. + */ + error = sc_set_current_schema (current_user); + } + } + else + { + // you can guarantee that user cache is already created in au_find_user () + assert (false); } } return (error); @@ -914,6 +937,40 @@ authenticate_context::get_user_class_name (void) return AU_USER_CLASS_NAME; } +int +authenticate_context::push_user (MOP user) +{ + MOP save_user = Au_user; + if (AU_SET_USER (user) == NO_ERROR) + { + user_stack.push (save_user); + return NO_ERROR; + } + else + { + return ER_FAILED; + } +} + +int +authenticate_context::pop_user (void) +{ + if (user_stack.size () == 0) + { + return ER_FAILED; + } + + if (AU_SET_USER (user_stack.top ()) == NO_ERROR) + { + user_stack.pop (); + return NO_ERROR; + } + else + { + return ER_FAILED; + } +} + // // STATIC FUNCTIONS // @@ -949,7 +1006,7 @@ au_add_method_check_authorization (void) smt_assign_argument_domain (def, "check_authorization", true, NULL, 2, "integer", (DB_DOMAIN *) 0); sm_update_class (def, NULL); - au_grant (Au_public_user, auth, AU_EXECUTE, false); + au_grant (DB_OBJECT_CLASS, Au_public_user, auth, AU_EXECUTE, false); AU_ENABLE (save); return NO_ERROR; diff --git a/src/object/authenticate_context.hpp b/src/object/authenticate_context.hpp index 8c77dd8a55..f3d0791cd7 100644 --- a/src/object/authenticate_context.hpp +++ b/src/object/authenticate_context.hpp @@ -24,6 +24,8 @@ #ifndef _AUTHENTICATE_CONTEXT_HPP_ #define _AUTHENTICATE_CONTEXT_HPP_ +#include + #include "porting.h" #include "dbtype_def.h" @@ -113,6 +115,14 @@ class EXPORT_IMPORT authenticate_context * system authorizations. */ MOP current_user; + + /* + * Au_user_stack + * + * This manages the MOP stack to track execution rights of stored procedures. + */ + std::stack user_stack; + /* * Au_user_name, Au_user_password * @@ -161,6 +171,10 @@ class EXPORT_IMPORT authenticate_context int check_user (void); bool has_user_name (void); + // execution rights + int push_user (MOP user); + int pop_user (); + // getters MOP get_public_user (void); MOP get_dba_user (void); diff --git a/src/object/authenticate_grant.cpp b/src/object/authenticate_grant.cpp index e961370c7b..99f6e46922 100644 --- a/src/object/authenticate_grant.cpp +++ b/src/object/authenticate_grant.cpp @@ -37,16 +37,28 @@ #include "object_accessor.h" /* obj_inst_lock () */ #include "object_primitive.h" +#include "msgcat_glossary.hpp" + +#include "jsp_cl.h" #if defined(SA_MODE) extern bool catcls_Enable; #endif /* SA_MODE */ +static int au_grant_class (MOP user, MOP class_mop, DB_AUTH type, bool grant_option); +static int au_grant_procedure (MOP user, MOP obj_mop, DB_AUTH type, bool grant_option); + +static int au_revoke_class (MOP user, MOP class_mop, DB_AUTH type, MOP drop_user); +static int au_revoke_procedure (MOP user, MOP obj_mop, DB_AUTH type, MOP drop_user); + static int check_grant_option (MOP classop, SM_CLASS *sm_class, DB_AUTH type); static int collect_class_grants (MOP class_mop, DB_AUTH type, MOP revoked_auth, int revoked_grant_index, AU_GRANT **return_grants); -static int propagate_revoke (AU_GRANT *grant_list, MOP owner, DB_AUTH mask); -static int au_propagate_del_new_auth (AU_GRANT *glist, DB_AUTH mask); +static int propagate_revoke (DB_OBJECT_TYPE obj_type, AU_GRANT *grant_list, MOP owner, DB_AUTH mask); +static int au_propagate_del_new_auth (DB_OBJECT_TYPE obj_type, AU_GRANT *glist, DB_AUTH mask); + +static int au_compare_grantor_and_return (MOP *grantor, MOP obj_mop, DB_AUTH type, MOP login_user, MOP class_owner, + MOP drop_user); /* * GRANT STRUCTURE OPERATION @@ -55,7 +67,7 @@ static void free_grant_list (AU_GRANT *grants); static void map_grant_list (AU_GRANT *grants, MOP grantor); static int find_grant_entry (DB_SET *grants, MOP class_mop, MOP grantor); -static int add_grant_entry (DB_SET *grants, MOP class_mop, MOP grantor); +static int add_grant_entry (DB_SET *grants, DB_OBJECT_TYPE obj_type, MOP obj_mop, MOP grantor); static void drop_grant_entry (DB_SET *grants, int index); static void print_grant_entry (DB_SET *grants, int grant_index, FILE *fp); @@ -65,15 +77,46 @@ static void print_grant_entry (DB_SET *grants, int grant_index, FILE *fp); /* * au_grant - This is the primary interface function for granting authorization - * on classes. + * on database objects. * return: error code + * obj_type(in): database object type to be granted * user(in): user receiving the grant * class_mop(in): class being authorized * type(in): type of authorization * grant_option(in): non-zero if grant option is also being given */ int -au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) +au_grant (DB_OBJECT_TYPE obj_type, MOP user, MOP class_mop, DB_AUTH type, bool grant_option) +{ + int error = NO_ERROR; + switch (obj_type) + { + case DB_OBJECT_CLASS: + error = au_grant_class (user, class_mop, type, grant_option); + break; + + case DB_OBJECT_PROCEDURE: + error = au_grant_procedure (user, class_mop, type, grant_option); + break; + default: + error = ER_FAILED; + assert (false); + break; + } + return error; +} + +/* + * au_grant_class - This is the primary interface function for granting authorization + * on classes. + * return: error code + * user(in): user receiving the grant + * class_mop(in): class being authorized + * type(in): type of authorization + * grant_option(in): non-zero if grant option is also being given + */ +static int +au_grant_class (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) { int error = NO_ERROR; MOP auth; @@ -83,6 +126,7 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) SM_CLASS *classobj; int is_partition = DB_NOT_PARTITIONED_CLASS, i, savepoint_grant = 0; MOP *sub_partitions = NULL; + MOP grantor = NULL; error = sm_partitioned_class_type (class_mop, &is_partition, NULL, &sub_partitions); if (error != NO_ERROR) @@ -101,7 +145,7 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) savepoint_grant = 1; for (i = 0; sub_partitions[i]; i++) { - error = au_grant (user, sub_partitions[i], type, grant_option); + error = au_grant_class (user, sub_partitions[i], type, grant_option); if (error != NO_ERROR) { break; @@ -116,24 +160,50 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) } AU_DISABLE (save); - if (ws_is_same_object (user, Au_user)) - { - /* - * Treat grant to self condition as a success only. Although this - * statement is a no-op, it is not an indication of no-success. - * The "privileges" are indeed already granted to self. - * Note: Revoke from self is an error, because this cannot be done. - */ - } - else if ((error = au_fetch_class_force (class_mop, &classobj, AU_FETCH_READ)) == NO_ERROR) + if ((error = au_fetch_class_force (class_mop, &classobj, AU_FETCH_READ)) == NO_ERROR) { - if (ws_is_same_object (classobj->owner, user)) + if (ws_is_same_object (user, Au_user)) + { + /* + * Treat grant to self condition as a success only. Although this + * statement is a no-op, it is not an indication of no-success. + * The "privileges" are indeed already granted to self. + * Note: Revoke from self is an error, because this cannot be done. + * Additionally, two conditions have been added: + * 1) No-op is disabled if the user does not have access to the CLASS (excluding the owner) + * Example : + * CALL LOGIN('u1', '') ON CLASS db_user; + * GRANT SELECT ON dba.tbl TO u1; + * Result : ERROR: SELECT authorization failure + * 2) No-op is disabled if the user has access to the CLASS but does not have the WITH GRANT OPTION (excluding the owner). + * Example : + * CALL LOGIN(class db_user, 'dba', ''); + * GRANT SELECT ON dba.tbl TO u1; + * CALL LOGIN('u1', '') ON CLASS db_user; + * GRANT SELECT ON dba.tbl TO u1; + * Result : ERROR: No GRANT option. + */ + + error = check_grant_option (class_mop, classobj, type); + if (error != NO_ERROR) + { + return (error); + } + } + else if (ws_is_same_object (classobj->owner, user)) { error = ER_AU_CANT_GRANT_OWNER; - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_CLASS)); } - else if ((error = check_grant_option (class_mop, classobj, type)) == NO_ERROR) + else if ((error = au_compare_grantor_and_return (&grantor, class_mop, type, Au_user, classobj->owner, + NULL)) != NO_ERROR) { + return (error); + } + else + { + assert (grantor != NULL); + if (au_get_object (user, "authorization", &auth) != NO_ERROR) { error = ER_AU_ACCESS_ERROR; @@ -147,7 +217,7 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) } else if ((error = obj_inst_lock (auth, 1)) == NO_ERROR && (error = get_grants (auth, &grants, 1)) == NO_ERROR) { - gindex = find_grant_entry (grants, class_mop, Au_user); + gindex = find_grant_entry (grants, class_mop, grantor); if (gindex == -1) { current = AU_NO_AUTHORIZATION; @@ -180,15 +250,15 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) if (ins_bits) { error = - accessor.insert_auth (Au_user, user, class_mop, ins_bits, + accessor.insert_auth (DB_OBJECT_CLASS, grantor, user, class_mop, ins_bits, (grant_option) ? ins_bits : DB_AUTH_NONE); } upd_bits = (DB_AUTH) (~ins_bits & (int) type); if ((error == NO_ERROR) && upd_bits) { error = - accessor.update_auth (Au_user, user, class_mop, upd_bits, - (grant_option) ? upd_bits : DB_AUTH_NONE); + accessor.update_auth (DB_OBJECT_CLASS, grantor, user, class_mop, upd_bits, + (grant_option || (current & (type << AU_GRANT_SHIFT))) ? upd_bits : DB_AUTH_NONE); } } @@ -209,7 +279,7 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) if (gindex == -1) { /* There is no grant entry, add a new one. */ - gindex = add_grant_entry (grants, class_mop, Au_user); + gindex = add_grant_entry (grants, DB_OBJECT_CLASS, class_mop, grantor); } set_put_element (grants, GRANT_ENTRY_CACHE (gindex), &value); set_free (grants); @@ -242,6 +312,161 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) return (error); } +static int +au_grant_procedure (MOP user, MOP obj_mop, DB_AUTH type, bool grant_option) +{ + int error = NO_ERROR; + DB_VALUE value; + MOP auth; + DB_SET *grants; + int current, save = 0, gindex; + MOP grantor = NULL; + + assert (type == AU_EXECUTE); + + AU_DISABLE (save); + MOP sp_owner = jsp_get_owner (obj_mop); + + /* + * The WITH GRANT OPTION is not yet supported for stored procedures. + * Therefore, only the DBA, member of the DBA group, and the owner can grant privileges. + */ + if (!au_is_dba_group_member (Au_user) && !au_is_user_group_member (sp_owner, Au_user)) + { + error = ER_AU_OWNER_ONLY_GRANT_PRIVILEGE; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, "EXECUTE"); + return (error); + } + + if (ws_is_same_object (user, Au_user)) + { + /* + * Treat grant to self condition as a success only. Although this + * statement is a no-op, it is not an indication of no-success. + * The "privileges" are indeed already granted to self. + * Note: Revoke from self is an error, because this cannot be done. + */ + } + else + { + if (ws_is_same_object (sp_owner, user)) + { + error = ER_AU_CANT_GRANT_OWNER; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_PROCEDURE)); + } + else if ((error = au_compare_grantor_and_return (&grantor, obj_mop, type, Au_user, sp_owner, NULL)) != NO_ERROR) + { + return (error); + } + else + { + assert (grantor != NULL); + + if (au_get_object (user, "authorization", &auth) != NO_ERROR) + { + error = ER_AU_ACCESS_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, AU_USER_CLASS_NAME, "authorization"); + } + /* lock authorization for write & mark dirty */ + else if (au_fetch_instance (auth, NULL, AU_FETCH_UPDATE, LC_FETCH_MVCC_VERSION, AU_UPDATE) != NO_ERROR) + { + error = ER_AU_CANT_UPDATE; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + } + else if ((error = obj_inst_lock (auth, 1)) == NO_ERROR && (error = get_grants (auth, &grants, 1)) == NO_ERROR) + { + gindex = find_grant_entry (grants, obj_mop, grantor); + if (gindex == -1) + { + current = AU_NO_AUTHORIZATION; + } + else + { + /* already granted, get current cache */ + error = set_get_element (grants, GRANT_ENTRY_CACHE (gindex), &value); + if (error != NO_ERROR) + { + set_free (grants); + AU_ENABLE (save); + return (error); + } + current = db_get_int (&value); + } + +#if defined(SA_MODE) + if (catcls_Enable == true) +#endif /* SA_MODE */ + { + au_auth_accessor accessor; + DB_AUTH ins_bits, upd_bits; + + ins_bits = (DB_AUTH) ((~current & AU_TYPE_MASK) & (int) type); + if (ins_bits) + { + error = + accessor.insert_auth (DB_OBJECT_PROCEDURE, grantor, user, obj_mop, AU_EXECUTE, DB_AUTH_NONE); + } + + upd_bits = (DB_AUTH) (~ins_bits & (int) type); + if ((error == NO_ERROR) && upd_bits) + { + error = + accessor.update_auth (DB_OBJECT_PROCEDURE, grantor, user, obj_mop, AU_EXECUTE, DB_AUTH_NONE); + } + } + + /* Fail to insert/update, never change the grant entry set. */ + if (error != NO_ERROR) + { + set_free (grants); + goto end; + } + + current |= (int) type; + /* TODO: no grant option for procedure */ + /* + if (grant_option) + { + current |= ((int) type << AU_GRANT_SHIFT); + } + */ + + db_make_int (&value, current); + if (gindex == -1) + { + /* There is no grant entry, add a new one. */ + gindex = add_grant_entry (grants, DB_OBJECT_PROCEDURE, obj_mop, grantor); + } + set_put_element (grants, GRANT_ENTRY_CACHE (gindex), &value); + set_free (grants); + + /* Fail to insert/update, never change the grant entry set. */ + if (error != NO_ERROR) + { + set_free (grants); + goto end; + } + + /* + * clear the cache for this user/class pair to make sure we + * recalculate it the next time it is referenced + */ + //reset_cache_for_user_and_class (classobj); + + /* + * Make sure any cached parse trees are rebuild. This proabably + * isn't necessary for GRANT, only REVOKE. + */ + sm_bump_local_schema_version (); + } + } + } + +end: + AU_ENABLE (save); + return (error); +} + /* * au_revoke - This is the primary interface function for * revoking authorization @@ -249,6 +474,7 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) * user(in): user being revoked * class_mop(in): class being revoked * type(in): type of authorization being revoked + * drop_user(in) : used when executing the drop user statement * * Note: The authorization of the given type on the given class is removed * from the authorization info stored with the given user. If this @@ -259,7 +485,45 @@ au_grant (MOP user, MOP class_mop, DB_AUTH type, bool grant_option) * TODO : LP64 */ int -au_revoke (MOP user, MOP class_mop, DB_AUTH type) +au_revoke (DB_OBJECT_TYPE obj_type, MOP user, MOP obj_mop, DB_AUTH type, MOP drop_user) +{ + int error = NO_ERROR; + switch (obj_type) + { + case DB_OBJECT_CLASS: + error = au_revoke_class (user, obj_mop, type, drop_user); + break; + + case DB_OBJECT_PROCEDURE: + error = au_revoke_procedure (user, obj_mop, type, drop_user); + break; + default: + error = ER_FAILED; + assert (false); + break; + } + return error; +} + +/* + * au_revoke_class - This is the primary interface function for + * revoking authorization + * return: error code + * user(in): user being revoked + * class_mop(in): class being revoked + * type(in): type of authorization being revoked + * drop_user(in) : used when executing the drop user statement + * + * Note: The authorization of the given type on the given class is removed + * from the authorization info stored with the given user. If this + * user has the grant option for this type and has granted authorization + * to other users, the revoke will be recursively propagated to all + * affected users. + * + * TODO : LP64 + */ +static int +au_revoke_class (MOP user, MOP class_mop, DB_AUTH type, MOP drop_user) { int error; MOP auth; @@ -270,6 +534,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) SM_CLASS *classobj; int is_partition = DB_NOT_PARTITIONED_CLASS, i = 0, savepoint_revoke = 0; MOP *sub_partitions = NULL; + MOP grantor = NULL; error = sm_partitioned_class_type (class_mop, &is_partition, NULL, &sub_partitions); if (error != NO_ERROR) @@ -288,7 +553,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) for (i = 0; sub_partitions[i]; i++) { - error = au_revoke (user, sub_partitions[i], type); + error = au_revoke_class (user, sub_partitions[i], type, drop_user); if (error != NO_ERROR) { break; @@ -316,11 +581,11 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) if (ws_is_same_object (classobj->owner, user)) { error = ER_AU_CANT_REVOKE_OWNER; - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_CLASS)); goto fail_end; } - error = check_grant_option (class_mop, classobj, type); + error = au_compare_grantor_and_return (&grantor, class_mop, type, Au_user, classobj->owner, drop_user); if (error != NO_ERROR) { goto fail_end; @@ -340,7 +605,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) } else if ((error = obj_inst_lock (auth, 1)) == NO_ERROR && (error = get_grants (auth, &grants, 1)) == NO_ERROR) { - gindex = find_grant_entry (grants, class_mop, Au_user); + gindex = find_grant_entry (grants, class_mop, grantor); if (gindex == -1) { error = ER_AU_GRANT_NOT_FOUND; @@ -350,7 +615,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) else { /* get current cache bits */ - error = set_get_element (grants, gindex + 2, &cache_element); + error = set_get_element (grants, GRANT_ENTRY_CACHE (gindex), &cache_element); if (error != NO_ERROR) { set_free (grants); @@ -394,7 +659,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) mask = (int) ~ (type | (type << AU_GRANT_SHIFT)); /* propagate the revoke to the affected classes */ - if ((error = propagate_revoke (grant_list, classobj->owner, (DB_AUTH) mask)) == NO_ERROR) + if ((error = propagate_revoke (DB_OBJECT_CLASS, grant_list, classobj->owner, (DB_AUTH) mask)) == NO_ERROR) { /* @@ -405,7 +670,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) if (current) { db_make_int (&cache_element, current); - set_put_element (grants, gindex + 2, &cache_element); + set_put_element (grants, GRANT_ENTRY_CACHE (gindex), &cache_element); } else { @@ -424,7 +689,7 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) { #endif /* SA_MODE */ au_auth_accessor accessor; - error = accessor.delete_auth (Au_user, user, class_mop, type); + error = accessor.delete_auth (DB_OBJECT_CLASS, grantor, user, class_mop, type); #if defined(SA_MODE) } #endif /* SA_MODE */ @@ -458,6 +723,193 @@ au_revoke (MOP user, MOP class_mop, DB_AUTH type) return (error); } +static int +au_revoke_procedure (MOP user, MOP obj_mop, DB_AUTH type, MOP drop_user) +{ + int error = NO_ERROR; + DB_SET *grants = NULL; + MOP auth; + int save = 0, current = 0, gindex, mask, savepoint_revoke = 0; + AU_GRANT *grant_list; + DB_VALUE cache_element; + MOP sp_owner; + MOP grantor = NULL; + + AU_DISABLE (save); + if (ws_is_same_object (user, Au_user)) + { + error = ER_AU_CANT_REVOKE_SELF; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + goto fail_end; + } + + sp_owner = jsp_get_owner (obj_mop); + if (sp_owner == NULL) + { + error = ER_FAILED; + goto fail_end; + } + + if (error == NO_ERROR) + { + if (ws_is_same_object (sp_owner, user)) + { + error = ER_AU_CANT_REVOKE_OWNER; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_PROCEDURE)); + goto fail_end; + } + + /* GRANT OPTION is not supported yet for stored procedure + error = check_grant_option (class_mop, obj_mop, type); + if (error != NO_ERROR) + { + goto fail_end; + } + */ + /* + * The WITH GRANT OPTION is not yet supported for stored procedures. + * Therefore, if the user is not the dba group or owner, the same error as grant/revoke_class is output. + * example: + * call login(class db_user,'public',''); + * REVOKE EXECUTE ON PROCEDURE u1.hello FROM u2; + */ + if (!au_is_dba_group_member (Au_user) && !au_is_user_group_member (sp_owner, Au_user)) + { + error = ER_AU_EXECUTE_FAILURE; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + goto fail_end; + } + + error = au_compare_grantor_and_return (&grantor, obj_mop, type, Au_user, sp_owner, drop_user); + if (error != NO_ERROR) + { + goto fail_end; + } + + if (au_get_object (user, "authorization", &auth) != NO_ERROR) + { + error = ER_AU_ACCESS_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, AU_USER_CLASS_NAME, "authorization"); + goto fail_end; + } + else if (au_fetch_instance (auth, NULL, AU_FETCH_UPDATE, LC_FETCH_MVCC_VERSION, AU_UPDATE) != NO_ERROR) + { + error = ER_AU_CANT_UPDATE; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0); + goto fail_end; + } + else if ((error = obj_inst_lock (auth, 1)) == NO_ERROR && (error = get_grants (auth, &grants, 1)) == NO_ERROR) + { + gindex = find_grant_entry (grants, obj_mop, grantor); + if (gindex == -1) + { + error = ER_AU_GRANT_NOT_FOUND; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + goto fail_end; + } + else + { + /* get current cache bits */ + error = set_get_element (grants, GRANT_ENTRY_CACHE (gindex), &cache_element); + if (error != NO_ERROR) + { + set_free (grants); + AU_ENABLE (save); + return (error); + } + current = db_get_int (&cache_element); + + /* + * If all the bits are set, assume we wan't to + * revoke everything previously granted, makes it a bit + * easier but muddies the semantics too much ? + */ + if (type == DB_AUTH_ALL) + { + type = (DB_AUTH) (current & AU_TYPE_MASK); + } + + /* + * this test could be more sophisticated, right now, + * if there are any valid grants that fit in + * the specified bit mask, the operation will proceed, + * we could make sure that every bit in the supplied + * mask is also present in the cache and if not abort + * the whole thing + */ + + if ((current & (int) type) == 0) + { + error = ER_AU_GRANT_NOT_FOUND; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + } + else if ((error = collect_class_grants (obj_mop, type, auth, gindex, &grant_list)) == NO_ERROR) + { + /* calculate the mask to turn off the grant */ + mask = (int) ~ (type | (type << AU_GRANT_SHIFT)); + + /* propagate the revoke to the affected classes */ + if ((error = propagate_revoke (DB_OBJECT_PROCEDURE, grant_list, sp_owner, (DB_AUTH) mask)) == NO_ERROR) + { + + /* + * finally, update the local grant for the + * original object + */ + current &= mask; + if (current) + { + db_make_int (&cache_element, current); + set_put_element (grants, GRANT_ENTRY_CACHE (gindex), &cache_element); + } + else + { + /* no remaining grants, remove it from the grant set */ + drop_grant_entry (grants, gindex); + } + /* + * clear the cache for this user/class pair + * to make sure we recalculate it the next time + * it is referenced + */ + // TODO: CBRD-24912 + // reset_cache_for_user_and_procedure (obj_mop); + +#if defined(SA_MODE) + if (catcls_Enable == true) + { +#endif /* SA_MODE */ + au_auth_accessor accessor; + error = accessor.delete_auth (DB_OBJECT_PROCEDURE, grantor, user, obj_mop, type); +#if defined(SA_MODE) + } +#endif /* SA_MODE */ + /* + * Make sure that we don't keep any parse trees + * around that rely on obsolete authorization. + * This may not be necessary. + */ + sm_bump_local_schema_version (); + } + free_grant_list (grant_list); + } + } + } + } + +fail_end: + if (grants != NULL) + { + set_free (grants); + } + if (savepoint_revoke && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED) + { + (void) tran_abort_upto_system_savepoint (UNIQUE_PARTITION_SAVEPOINT_REVOKE); + } + AU_ENABLE (save); + return (error); +} + /* * check_grant_option - Checks to see if a class has the grant option for * a particular authorization type. @@ -701,23 +1153,27 @@ map_grant_list (AU_GRANT *grants, MOP grantor) } /* - * add_grant_entry - This adds a grant on a class from a particular user to + * add_grant_entry - This adds a grant on a database object from a particular user to * a sequence of grant elemetns. * It returns the index of the new grant element. * return: sequence index to new grant entry * grants(in): grant sequence to extend - * class_mop(in): class being granted + * db_obj_type(in): database object type + * obj_mop(in): database object being granted * grantor(in): user doing the granting */ static int -add_grant_entry (DB_SET *grants, MOP class_mop, MOP grantor) +add_grant_entry (DB_SET *grants, DB_OBJECT_TYPE obj_type, MOP obj_mop, MOP grantor) { DB_VALUE value; int index; index = set_size (grants); - db_make_object (&value, class_mop); + db_make_int (&value, (int) obj_type); + set_put_element (grants, GRANT_ENTRY_TYPE (index), &value); + + db_make_object (&value, obj_mop); set_put_element (grants, GRANT_ENTRY_CLASS (index), &value); db_make_object (&value, grantor); @@ -754,17 +1210,17 @@ drop_grant_entry (DB_SET *grants, int index) /* * find_grant_entry - This searches a sequence of grant elements looking for - * a grant from a particular user on a particular class. + * a grant from a particular user on a particular database object. * return: sequence index to grant entry * grants(in): sequence of grant information - * class_mop(in): class to look for + * obj_mop(in): database object to look for * grantor(in): user who made the grant * * Note: It returns the index into the sequence where the grant information * is found. If the grant was not found it returns -1. */ static int -find_grant_entry (DB_SET *grants, MOP class_mop, MOP grantor) +find_grant_entry (DB_SET *grants, MOP obj_mop, MOP grantor) { DB_VALUE element; int i, gsize, position; @@ -774,7 +1230,7 @@ find_grant_entry (DB_SET *grants, MOP class_mop, MOP grantor) for (i = 0; i < gsize && position == -1; i += GRANT_ENTRY_LENGTH) { set_get_element (grants, GRANT_ENTRY_CLASS (i), &element); - if (db_get_object (&element) == class_mop) + if (db_get_object (&element) == obj_mop) { set_get_element (grants, GRANT_ENTRY_SOURCE (i), &element); if (ws_is_same_object (db_get_object (&element), grantor)) @@ -798,10 +1254,29 @@ static void print_grant_entry (DB_SET *grants, int grant_index, FILE *fp) { DB_VALUE value; + char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1]; + unique_name[0] = '\0'; + + int type; + set_get_element (grants, GRANT_ENTRY_TYPE (grant_index), &value); + type = db_get_int (&value); set_get_element (grants, GRANT_ENTRY_CLASS (grant_index), &value); - fprintf (fp, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_AUTHORIZATION, MSGCAT_AUTH_CLASS_NAME), - sm_get_ch_name (db_get_object (&value))); + + if (type == DB_OBJECT_CLASS) + { + fprintf (fp, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_AUTHORIZATION, MSGCAT_AUTH_CLASS_NAME), + sm_get_ch_name (db_get_object (&value))); + } + else + { + if (jsp_get_unique_name (db_get_object (&value), unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL) + { + assert (er_errid () != NO_ERROR); + } + + fprintf (fp, msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_AUTHORIZATION, MSGCAT_AUTH_CLASS_NAME), unique_name); + } fprintf (fp, " "); set_get_element (grants, GRANT_ENTRY_SOURCE (grant_index), &value); @@ -831,8 +1306,8 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) int error = NO_ERROR; DB_VALUE value; DB_SET *grants = NULL; - MOP grantor, gowner, class_; - int gsize, i, j, existing, cache; + MOP grantor, gowner, gtype, obj_; + int gsize, i, j, existing, cache, obj_type; bool need_pop_er_stack = false; assert (grant_ptr != NULL); @@ -857,14 +1332,14 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) goto end; } + grants = db_get_set (&value); + gsize = set_size (grants); + if (!filter) { goto end; } - grants = db_get_set (&value); - gsize = set_size (grants); - /* there might be errors */ error = er_errid (); if (error != NO_ERROR) @@ -874,6 +1349,13 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) for (i = 0; i < gsize; i += GRANT_ENTRY_LENGTH) { + error = set_get_element (grants, GRANT_ENTRY_TYPE (i), &value); + if (error != NO_ERROR) + { + goto end; + } + obj_type = db_get_int (&value); + error = set_get_element (grants, GRANT_ENTRY_SOURCE (i), &value); if (error != NO_ERROR) { @@ -892,7 +1374,7 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) if (grantor == NULL) { - class_ = NULL; + obj_ = NULL; error = set_get_element (grants, GRANT_ENTRY_CLASS (i), &value); if (error != NO_ERROR) { @@ -901,14 +1383,14 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) if (DB_VALUE_TYPE (&value) == DB_TYPE_OBJECT && !DB_IS_NULL (&value)) { - class_ = db_get_object (&value); - if (WS_IS_DELETED (class_)) + obj_ = db_get_object (&value); + if (WS_IS_DELETED (obj_)) { - class_ = NULL; + obj_ = NULL; } } - if (class_ == NULL) + if (obj_ == NULL) { /* class is bad too, remove this entry */ drop_grant_entry (grants, i); @@ -917,7 +1399,14 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) else { /* this will at least be DBA */ - gowner = au_get_class_owner (class_); + if (obj_type == DB_OBJECT_CLASS) + { + gowner = au_get_class_owner (obj_); + } + else + { + gowner = jsp_get_owner (obj_); + } /* see if there's already an entry for this */ existing = -1; @@ -937,6 +1426,13 @@ get_grants (MOP auth, DB_SET **grant_ptr, int filter) if (existing == -1) { + db_make_int (&value, obj_type); + error = set_put_element (grants, GRANT_ENTRY_TYPE (i), &value); + if (error != NO_ERROR) + { + goto end; + } + /* * no previous entry for the owner, * use the current one @@ -1082,6 +1578,7 @@ collect_class_grants (MOP class_mop, DB_AUTH type, MOP revoked_auth, int revoked DB_QUERY_ERROR query_error; DB_VALUE user_val; const char *qp1 = "select [%s] from [%s];"; + int saved_opt_level; *return_grants = NULL; @@ -1094,7 +1591,14 @@ collect_class_grants (MOP class_mop, DB_AUTH type, MOP revoked_auth, int revoked } sprintf (query, qp1, AU_USER_CLASS_NAME, AU_USER_CLASS_NAME); + + saved_opt_level = prm_get_integer_value (PRM_ID_OPTIMIZATION_LEVEL); + prm_set_integer_value (PRM_ID_OPTIMIZATION_LEVEL, 1); + error = db_compile_and_execute_local (query, &query_result, &query_error); + + prm_set_integer_value (PRM_ID_OPTIMIZATION_LEVEL, saved_opt_level); + if (error < 0) /* error is row count if not negative. */ { @@ -1218,16 +1722,16 @@ collect_class_grants (MOP class_mop, DB_AUTH type, MOP revoked_auth, int revoked return (error); } - /* * propagate_revoke - Propagates a revoke operation to all affected users. * return: error code + * obj_type(in): type of the database object * grant_list(in): list of grant nodes - * owner(in): owner of the class + * owner(in): owner of the database object * mask(in): authorization type mask */ static int -propagate_revoke (AU_GRANT *grant_list, MOP owner, DB_AUTH mask) +propagate_revoke (DB_OBJECT_TYPE obj_type, AU_GRANT *grant_list, MOP owner, DB_AUTH mask) { int error = NO_ERROR; DB_VALUE element; @@ -1242,7 +1746,7 @@ propagate_revoke (AU_GRANT *grant_list, MOP owner, DB_AUTH mask) if (catcls_Enable == true) #endif /* SA_MODE */ { - error = au_propagate_del_new_auth (grant_list, mask); + error = au_propagate_del_new_auth (obj_type, grant_list, mask); if (error != NO_ERROR) { return error; @@ -1336,11 +1840,11 @@ propagate_revoke (AU_GRANT *grant_list, MOP owner, DB_AUTH mask) * mask(in): */ static int -au_propagate_del_new_auth (AU_GRANT *glist, DB_AUTH mask) +au_propagate_del_new_auth (DB_OBJECT_TYPE obj_type, AU_GRANT *glist, DB_AUTH mask) { AU_GRANT *g; DB_SET *grants; - DB_VALUE class_, type; + DB_VALUE obj_, type; int error = NO_ERROR; au_auth_accessor accessor; @@ -1354,7 +1858,7 @@ au_propagate_del_new_auth (AU_GRANT *glist, DB_AUTH mask) break; } - error = set_get_element (grants, GRANT_ENTRY_CLASS (g->grant_index), &class_); + error = set_get_element (grants, GRANT_ENTRY_CLASS (g->grant_index), &obj_); if (error != NO_ERROR) { break; @@ -1366,8 +1870,10 @@ au_propagate_del_new_auth (AU_GRANT *glist, DB_AUTH mask) break; } + // NOTE: Only DB_OBJECT_CLASS error = - accessor.delete_auth (g->grantor, g->user, db_get_object (&class_), (DB_AUTH) (db_get_int (&type) & ~mask)); + accessor.delete_auth (obj_type, g->grantor, g->user, db_get_object (&obj_), + (DB_AUTH) (db_get_int (&type) & ~mask)); if (error != NO_ERROR) { break; @@ -1378,6 +1884,120 @@ au_propagate_del_new_auth (AU_GRANT *glist, DB_AUTH mask) return error; } +/* + * au_compare_grantor_and_return - + * return: error code + * grantor(out): return the class_owner or login_user + * obj_mop(in): mop of the object + * type(in) : authorization type + * login_user(in) : current login_user (Au_user) + * class_owner(in) : owner of the object + * drop_user(in) : used when executing the drop user statement + */ +static int +au_compare_grantor_and_return (MOP *grantor, MOP obj_mop, DB_AUTH type, MOP login_user, MOP class_owner, MOP drop_user) +{ + int error = NO_ERROR; + unsigned int cache, mask; + MOP auth; + DB_VALUE element; + DB_SET *grants; + int j, gsize; + + assert ((grantor != NULL && obj_mop != NULL && login_user != NULL && class_owner != NULL) || drop_user != NULL); + + *grantor = NULL; + + if (drop_user != NULL) + { + /* + * used when executing the drop user statement. + */ + *grantor = drop_user; + } + else if (au_is_dba_group_member (login_user) || au_is_user_group_member (class_owner, login_user)) + { + /* + * DBA, DBA Member, Owner, Owner Memeber + */ + *grantor = class_owner; + } + else + { + /* + * Check grantable user + */ + if (au_get_object (login_user, "authorization", &auth) != NO_ERROR) + { + error = ER_AU_ACCESS_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, AU_USER_CLASS_NAME, "authorization"); + } + else if ((error = get_grants (auth, &grants, 1)) == NO_ERROR) + { + gsize = set_size (grants); + if (gsize) + { + for (j = 0; j < gsize && error == NO_ERROR; j += GRANT_ENTRY_LENGTH) + { + cache = AU_NO_AUTHORIZATION; + if (set_get_element (grants, GRANT_ENTRY_CLASS (j), &element)) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + break; + } + + if (db_get_object (&element) == obj_mop) + { + cache = AU_NO_AUTHORIZATION; + if (set_get_element (grants, GRANT_ENTRY_CACHE (j), &element)) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + break; + } + + cache = db_get_int (&element); + mask = (unsigned int) (type | (type << AU_GRANT_SHIFT)); + if ((cache & mask) != mask) + { + error = appropriate_error (cache, mask); + if (error) + { + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + break; + } + } + else + { + *grantor = login_user; + break; + } + } + } + } + set_free (grants); + + /* + * This error condition occurs in the following two cases, both of which are considered as lacking authorization: + * 1. gsize == 0: Indicates no prior authorization + * When the grants column in the db_authorization catalog is empty. + * 2. db_get_object(&element) != obj_mop: Indicates that permissions exist for other objects but not for the current one + * When the grants column in the db_authorization catalog contains permissions for other objects (such as classes or procedures), but lacks permissions for the obj_mop object. + */ + if (error == NO_ERROR && *grantor == NULL) + { + cache = 0; + mask = (unsigned int) type; + error = appropriate_error (cache, mask); + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + } + } + } + + return error; +} + /* * au_print_grants() - * return: none @@ -1439,8 +2059,9 @@ au_force_write_new_auth (void) MOP au_class, au_obj; DB_VALUE grants_val; DB_SET *grants; - DB_VALUE grantor_val, grantee_val, class_val, auth_val; - MOP grantor, grantee, class_; + DB_VALUE grantor_val, grantee_val, obj_val, auth_val, type_val; + MOP grantor, grantee, obj_; + DB_OBJECT_TYPE obj_type; DB_AUTH auth; int gindex, gsize; int save; @@ -1489,12 +2110,19 @@ au_force_write_new_auth (void) au_auth_accessor accessor; for (gindex = 0; gindex < gsize; gindex += GRANT_ENTRY_LENGTH) { - error = set_get_element (grants, GRANT_ENTRY_CLASS (gindex), &class_val); + error = set_get_element (grants, GRANT_ENTRY_TYPE (gindex), &type_val); if (error != NO_ERROR) { goto end; } - class_ = db_get_object (&class_val); + obj_type = (DB_OBJECT_TYPE) db_get_int (&type_val); + + error = set_get_element (grants, GRANT_ENTRY_CLASS (gindex), &obj_val); + if (error != NO_ERROR) + { + goto end; + } + obj_ = db_get_object (&obj_val); error = set_get_element (grants, GRANT_ENTRY_SOURCE (gindex), &grantor_val); if (error != NO_ERROR) @@ -1510,7 +2138,8 @@ au_force_write_new_auth (void) } auth = (DB_AUTH) db_get_int (&auth_val); - error = accessor.insert_auth (grantor, grantee, class_, (DB_AUTH) (auth & AU_TYPE_MASK), (auth & AU_GRANT_MASK)); + error = accessor.insert_auth (obj_type, grantor, grantee, obj_, (DB_AUTH) (auth & AU_TYPE_MASK), + (auth & AU_GRANT_MASK)); if (error != NO_ERROR) { goto end; @@ -1528,4 +2157,5 @@ au_force_write_new_auth (void) return error; } + #endif // SA_MODE diff --git a/src/object/authenticate_grant.hpp b/src/object/authenticate_grant.hpp index 1fe30fe7a1..59e05e2ab7 100644 --- a/src/object/authenticate_grant.hpp +++ b/src/object/authenticate_grant.hpp @@ -63,10 +63,12 @@ struct au_grant * */ -#define GRANT_ENTRY_LENGTH 3 -#define GRANT_ENTRY_CLASS(index) (index) -#define GRANT_ENTRY_SOURCE(index) ((index) + 1) -#define GRANT_ENTRY_CACHE(index) ((index) + 2) +#define GRANT_ENTRY_LENGTH 4 + +#define GRANT_ENTRY_TYPE(index) ((index)) +#define GRANT_ENTRY_CLASS(index) ((index) + 1) +#define GRANT_ENTRY_SOURCE(index) ((index) + 2) +#define GRANT_ENTRY_CACHE(index) ((index) + 3) extern int apply_grants (MOP auth, MOP class_mop, unsigned int *bits); extern int get_grants (MOP auth, DB_SET **grant_ptr, int filter); diff --git a/src/object/authenticate_migration.cpp b/src/object/authenticate_migration.cpp index ab5671aee5..15e4f40051 100644 --- a/src/object/authenticate_migration.cpp +++ b/src/object/authenticate_migration.cpp @@ -32,6 +32,7 @@ #include "schema_manager.h" /* sm_get_ch_name () */ #include "extract_schema.hpp" /* extract_context */ #include "printer.hpp" /* print_output */ +#include "jsp_cl.h" /* jsp_get_owner () */ /* * CLASS_GRANT @@ -86,8 +87,9 @@ static int add_class_grant (CLASS_AUTH *auth, MOP source, MOP user, int cache); static int build_class_grant_list (CLASS_AUTH *cl_auth, MOP class_mop); static void issue_grant_statement (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *auth, - CLASS_GRANT *grant, int authbits); -static int class_grant_loop (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *auth); + CLASS_GRANT *grant, int authbits, DB_OBJECT_TYPE obj_type); +static int class_grant_loop (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *auth, + DB_OBJECT_TYPE obj_type); /* * MIGRATION SUPPORT @@ -576,7 +578,7 @@ au_export_users (extract_context &ctxt, print_output &output_ctx) * quoted_id_flag(in): */ int -au_export_grants (extract_context &ctxt, print_output &output_ctx, MOP class_mop) +au_export_grants (extract_context &ctxt, print_output &output_ctx, MOP class_mop, DB_OBJECT_TYPE obj_type) { int error = NO_ERROR; CLASS_AUTH cl_auth; @@ -584,9 +586,23 @@ au_export_grants (extract_context &ctxt, print_output &output_ctx, MOP class_mop int statements, ecount; char *uname; - cl_auth.class_mop = class_mop; - cl_auth.owner = au_get_class_owner (class_mop); - cl_auth.users = NULL; + switch (obj_type) + { + case DB_OBJECT_CLASS: + cl_auth.class_mop = class_mop; + cl_auth.owner = au_get_class_owner (class_mop); + cl_auth.users = NULL; + break; + case DB_OBJECT_PROCEDURE: + cl_auth.class_mop = class_mop; + cl_auth.owner = jsp_get_owner (class_mop); + cl_auth.users = NULL; + break; + default: + assert (false); + error = ER_FAILED; + return (error); + } /* make an entry for the owner with complete authorization */ u = find_or_add_user (&cl_auth, cl_auth.owner); @@ -597,7 +613,7 @@ au_export_grants (extract_context &ctxt, print_output &output_ctx, MOP class_mop if (error == NO_ERROR) { /* loop through the grant list, issuing grant statements */ - while ((statements = class_grant_loop (ctxt, output_ctx, &cl_auth))) + while ((statements = class_grant_loop (ctxt, output_ctx, &cl_auth, obj_type))) ; for (u = cl_auth.users, ecount = 0; u != NULL; u = u->next) @@ -941,10 +957,11 @@ build_class_grant_list (CLASS_AUTH *cl_auth, MOP class_mop) */ static void issue_grant_statement (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *auth, CLASS_GRANT *grant, - int authbits) + int authbits, DB_OBJECT_TYPE obj_type) { const char *gtype; char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' }; + char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1]; char *class_name = NULL; char *username; int typebit; @@ -977,10 +994,29 @@ issue_grant_statement (extract_context &ctxt, print_output &output_ctx, CLASS_AU gtype = "???"; break; } - SPLIT_USER_SPECIFIED_NAME (sm_get_ch_name (auth->class_mop), owner_name, class_name); - username = au_get_user_name (grant->user->obj); - output_ctx ("GRANT %s ON ", gtype); + output_ctx ("\n"); + + switch (obj_type) + { + case DB_OBJECT_CLASS: + SPLIT_USER_SPECIFIED_NAME (sm_get_ch_name (auth->class_mop), owner_name, class_name); + username = au_get_user_name (grant->user->obj); + + output_ctx ("GRANT %s ON ", gtype); + break; + case DB_OBJECT_PROCEDURE: + unique_name[0] = '\0'; + jsp_get_unique_name (auth->class_mop, unique_name, DB_MAX_IDENTIFIER_LENGTH + 1); + SPLIT_USER_SPECIFIED_NAME (unique_name, owner_name, class_name); + username = au_get_user_name (grant->user->obj); + + output_ctx ("GRANT %s ON PROCEDURE ", gtype); + break; + default: + output_ctx ("GRANT %s ON ", gtype); + break; + } if (ctxt.is_dba_user || ctxt.is_dba_group_member) { @@ -1036,7 +1072,7 @@ issue_grant_statement (extract_context &ctxt, print_output &output_ctx, CLASS_AU * TODO : LP64 */ static int -class_grant_loop (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *auth) +class_grant_loop (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *auth, DB_OBJECT_TYPE obj_type) { #define AU_MIN_BIT 1 /* AU_SELECT */ #define AU_MAX_BIT 0x40 /* AU_EXECUTE */ @@ -1066,7 +1102,7 @@ class_grant_loop (extract_context &ctxt, print_output &output_ctx, CLASS_AUTH *a { if (!ws_is_same_object (auth->users->obj, grant->user->obj)) { - issue_grant_statement (ctxt, output_ctx, auth, grant, authbits); + issue_grant_statement (ctxt, output_ctx, auth, grant, authbits, obj_type); } /* turn on grant bits in the granted user */ diff --git a/src/object/authenticate_owner.cpp b/src/object/authenticate_owner.cpp index 46f97e0f14..365720ee8f 100644 --- a/src/object/authenticate_owner.cpp +++ b/src/object/authenticate_owner.cpp @@ -478,7 +478,16 @@ au_change_sp_owner (MOP sp, MOP owner) { int error = NO_ERROR; int save; - DB_VALUE value; + const char *name_str = NULL, *owner_str = NULL; + char new_name_str[DB_MAX_IDENTIFIER_LENGTH]; + new_name_str[0]= '\0'; + char downcase_owner_name[DB_MAX_USER_LENGTH]; + downcase_owner_name[0] = '\0'; + DB_VALUE value, name_value, owner_value; + + db_make_null (&value); + db_make_null (&name_value); + db_make_null (&owner_value); AU_DISABLE (save); if (!au_is_dba_group_member (Au_user)) @@ -488,6 +497,31 @@ au_change_sp_owner (MOP sp, MOP owner) } else { + error = obj_get (sp, "sp_name", &name_value); + if (error != NO_ERROR) + { + goto end; + } + error = obj_get (owner, "name", &owner_value); + if (error != NO_ERROR) + { + goto end; + } + + name_str = db_get_string (&name_value); + owner_str = db_get_string (&owner_value); + + sm_downcase_name (owner_str, downcase_owner_name, DB_MAX_USER_LENGTH); + sprintf (new_name_str, "%s.%s", downcase_owner_name, name_str); + + /* change the unique_name */ + db_make_string (&value, new_name_str); + error = obj_set (sp, SP_ATTR_UNIQUE_NAME, &value); + if (error < 0) + { + goto end; + } + db_make_object (&value, owner); error = obj_set (sp, SP_ATTR_OWNER, &value); if (error < 0) diff --git a/src/object/object_representation.c b/src/object/object_representation.c index be1723f63c..56b9083350 100644 --- a/src/object/object_representation.c +++ b/src/object/object_representation.c @@ -37,7 +37,7 @@ #include "error_manager.h" #include "file_io.h" #include "log_lsa.hpp" -#include "method_def.hpp" + #include "object_primitive.h" #include "object_representation.h" #include "oid.h" @@ -78,8 +78,6 @@ int mvcc_header_size_lookup[8] = { }; static TP_DOMAIN *unpack_domain (OR_BUF * buf, int *is_null); -static char *or_pack_method_sig (char *ptr, void *method_sig_ptr); -static char *or_unpack_method_sig (char *ptr, void **method_sig_ptr, int n); #if defined(ENABLE_UNUSED_FUNCTION) static char *unpack_str_array (char *buffer, char ***string_array, int count); #endif @@ -5649,37 +5647,6 @@ or_listid_length (void *listid_ptr) return length; } -/* - * or_pack_method_sig - packs a METHOD_SIG descriptor. - * return: advanced buffer pointer - * ptr(out): starting pointer - * method_sig_ptr(in): opaque pointer to METHOD_SIG structure - */ -static char * -or_pack_method_sig (char *ptr, void *method_sig_ptr) -{ - METHOD_SIG *method_sig = (METHOD_SIG *) method_sig_ptr; - int n; - - if (method_sig == (METHOD_SIG *) 0) - { - return ptr; - } - - ptr = or_pack_method_sig (ptr, method_sig->next); - ptr = or_pack_string (ptr, method_sig->method_name); - ptr = or_pack_string (ptr, method_sig->class_name); - ptr = or_pack_int (ptr, method_sig->method_type); - ptr = or_pack_int (ptr, method_sig->num_method_args); - - for (n = 0; n < method_sig->num_method_args + 1; n++) - { - ptr = or_pack_int (ptr, method_sig->method_arg_pos[n]); - } - - return ptr; -} - /* * or_pack_key_val_range - packs a KEY VALUE RANGE. * return: advanced buffer pointer @@ -5730,153 +5697,6 @@ or_unpack_key_val_range (char *ptr, void *key_val_range_ptr) return ptr; } -/* - * or_unpack_method_sig - unpacks a METHOD_SIG descriptor from a buffer. - * return: advanced buffer pointer - * ptr(in): starting pointer - * method_sig_ptr(out): method_sig descriptor - * n(in): - */ -static char * -or_unpack_method_sig (char *ptr, void **method_sig_ptr, int n) -{ - METHOD_SIG *method_sig; - - if (n == 0) - { - *(METHOD_SIG **) method_sig_ptr = (METHOD_SIG *) 0; - return ptr; - } - method_sig = (METHOD_SIG *) db_private_alloc (NULL, sizeof (METHOD_SIG)); - - if (method_sig == (METHOD_SIG *) 0) - { - return NULL; - } - ptr = or_unpack_method_sig (ptr, (void **) &method_sig->next, n - 1); - ptr = or_unpack_string (ptr, &method_sig->method_name); - ptr = or_unpack_string (ptr, &method_sig->class_name); - ptr = or_unpack_int (ptr, (int *) &method_sig->method_type); - ptr = or_unpack_int (ptr, &method_sig->num_method_args); - - method_sig->method_arg_pos = (int *) db_private_alloc (NULL, sizeof (int) * (method_sig->num_method_args + 1)); - if (method_sig->method_arg_pos == (int *) 0) - { - db_private_free_and_init (NULL, method_sig); - return NULL; - } - - for (n = 0; n < method_sig->num_method_args + 1; n++) - { - ptr = or_unpack_int (ptr, &method_sig->method_arg_pos[n]); - } - - *(METHOD_SIG **) method_sig_ptr = method_sig; - - return ptr; -} - -/* - * or_pack_method_sig_list - write a method signature list - * return: advanced buffer pointer - * ptr(out): starting pointer - * method_sig_list_ptr(in): method_sig_list descriptor - * Note: - * This packs a METHOD_SIG_LIST descriptor. - */ -char * -or_pack_method_sig_list (char *ptr, void *method_sig_list_ptr) -{ - METHOD_SIG_LIST *method_sig_list = (METHOD_SIG_LIST *) method_sig_list_ptr; - - ptr = or_pack_int (ptr, method_sig_list->num_methods); - -#if !defined(NDEBUG) - { - int i = 0; - METHOD_SIG *sig; - - for (sig = method_sig_list->method_sig; sig; sig = sig->next) - { - i++; - } - assert (method_sig_list->num_methods == i); - } -#endif - - ptr = or_pack_method_sig (ptr, method_sig_list->method_sig); - return ptr; -} - -/* - * or_unpack_method_sig_list - read a method signature list - * return: advanced buffer pointer - * ptr(in): starting pointer - * method_sig_list_ptr(out): method_sig_list descriptor - * Note: - * This unpacks a METHOD_SIG_LIST descriptor from a buffer. - */ -char * -or_unpack_method_sig_list (char *ptr, void **method_sig_list_ptr) -{ - METHOD_SIG_LIST *method_sig_list; - - method_sig_list = (METHOD_SIG_LIST *) db_private_alloc (NULL, sizeof (METHOD_SIG_LIST)); - if (method_sig_list == (METHOD_SIG_LIST *) 0) - { - return NULL; - } - - ptr = or_unpack_int (ptr, &method_sig_list->num_methods); - ptr = or_unpack_method_sig (ptr, (void **) &method_sig_list->method_sig, method_sig_list->num_methods); - -#if !defined(NDEBUG) - { - int i = 0; - METHOD_SIG *sig; - - for (sig = method_sig_list->method_sig; sig; sig = sig->next) - { - i++; - } - assert (method_sig_list->num_methods == i); - } -#endif - - *(METHOD_SIG_LIST **) method_sig_list_ptr = method_sig_list; - - return ptr; -} - -/* - * or_method_sig_list_length - get the length of method signature list - * return: length of METHOD_SIG_LIST in bytes. - * method_sig_list_ptr(in): method_sig_list descriptor - * Note: - * Calculates the number of bytes required to store the disk/comm - * representation of a METHOD_SIG_LIST structure. - */ -int -or_method_sig_list_length (void *method_sig_list_ptr) -{ - METHOD_SIG_LIST *method_sig_list = (METHOD_SIG_LIST *) method_sig_list_ptr; - METHOD_SIG *method_sig; - int length = OR_INT_SIZE; /* num_methods */ - int n; - - for (n = 0, method_sig = method_sig_list->method_sig; n < method_sig_list->num_methods; - ++n, method_sig = method_sig->next) - { - length += or_packed_string_length (method_sig->method_name, NULL); - length += or_packed_string_length (method_sig->class_name, NULL); - length += OR_INT_SIZE * 2; /* method_type & num_method_args */ - /* + object ptr */ - length += OR_INT_SIZE * (method_sig->num_method_args + 1); - /* method_arg_pos */ - } - return length; -} - /* * GENERIC DB_VALUE PACKING */ diff --git a/src/object/schema_class_truncator.cpp b/src/object/schema_class_truncator.cpp index 46aa153334..a1a977177f 100644 --- a/src/object/schema_class_truncator.cpp +++ b/src/object/schema_class_truncator.cpp @@ -528,7 +528,7 @@ namespace cubschema STATEMENT_ID stmt_id; DB_VALUE value; char select_query[DB_MAX_IDENTIFIER_LENGTH + 256] = { 0 }; - constexpr int CNT_CATCLS_OBJECTS = 5; + constexpr int CNT_CATCLS_OBJECTS = 6; DB_BIGINT cnt_refers = CNT_CATCLS_OBJECTS + 1; int au_save; @@ -544,13 +544,13 @@ namespace cubschema * To do this, we use an walkaround in which we count the number of general object domains in existing system catalogs * and if the SELECT result is over this, we asuume that there are some general object domain in some user class. * - * The number is now 5 and hard-coded, so we MUST consider it when add or remove a general object domain in a system class. + * The number is now 6 and hard-coded, so we MUST consider it when add or remove a general object domain in a system class. * If it is changed, we MUST also change the value of CNT_CATCLS_OBJECTS. * - * We add a QA test case to confirm there are only 5 general object domains in system classes, which will help notice this constraint + * We add a QA test case to confirm there are only 6 general object domains in system classes, which will help notice this constraint * and this test case also has to be changed along if CNT_CATCLS_OBJECTS is changed. * - * See CBRD-23983 for the details. + * See CBRD-23983 and CBRD-25697 for the details. */ AU_DISABLE (au_save); diff --git a/src/object/schema_manager.c b/src/object/schema_manager.c index 42e1a8bcf8..50ae23eddd 100644 --- a/src/object/schema_manager.c +++ b/src/object/schema_manager.c @@ -13568,6 +13568,7 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) SM_CLASS_CONSTRAINT *pk; char *fk_name = NULL; const char *table_name; + MOP save_user, owner; if (op == NULL) { @@ -13826,8 +13827,30 @@ sm_delete_class_mop (MOP op, bool is_cascade_constraints) goto end; } + /* before deleting an object, all permissions are revoked. */ + owner = au_get_class_owner (op); + if (owner == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + save_user = Au_user; + if (AU_SET_USER (owner) == NO_ERROR) + { + error = au_object_revoke_all_privileges (DB_OBJECT_CLASS, owner, table_name); + if (error != NO_ERROR) + { + AU_SET_USER (save_user); + goto end; + } + } + + AU_SET_USER (save_user); + /* now delete _db_auth tuples refers to the table */ - error = au_delete_auth_of_dropping_table (table_name); + error = au_delete_auth_of_dropping_database_object (DB_OBJECT_CLASS, table_name); if (error != NO_ERROR) { goto end; diff --git a/src/object/schema_system_catalog.cpp b/src/object/schema_system_catalog.cpp index 1ae1e40674..4a560c8cbb 100644 --- a/src/object/schema_system_catalog.cpp +++ b/src/object/schema_system_catalog.cpp @@ -72,6 +72,7 @@ namespace cubschema CT_PARTITION_NAME, // "_db_partition" CT_STORED_PROC_NAME, // "_db_stored_procedure" CT_STORED_PROC_ARGS_NAME, // "_db_stored_procedure_args" + CT_STORED_PROC_CODE_NAME, // "_db_stored_procedure_code" CT_SERIAL_NAME, // "db_serial" CT_HA_APPLY_INFO_NAME, // "db_ha_apply_info" CT_COLLATION_NAME, // "_db_collation" diff --git a/src/object/schema_system_catalog_builder.cpp b/src/object/schema_system_catalog_builder.cpp index 3062006e35..bd60631ed1 100644 --- a/src/object/schema_system_catalog_builder.cpp +++ b/src/object/schema_system_catalog_builder.cpp @@ -179,7 +179,7 @@ namespace cubschema for (const grant &g : auth.grants) { - error_code = au_grant (g.target_user, class_mop, g.auth, g.with_grant_option); + error_code = au_grant (DB_OBJECT_CLASS, g.target_user, class_mop, g.auth, g.with_grant_option); if (error_code != NO_ERROR) { assert (false); @@ -253,7 +253,7 @@ namespace cubschema for (const grant &g : auth.grants) { assert (g.target_user != nullptr); - error_code = au_grant (g.target_user, class_mop, g.auth, g.with_grant_option); + error_code = au_grant (DB_OBJECT_CLASS, g.target_user, class_mop, g.auth, g.with_grant_option); if (error_code != NO_ERROR) { return error_code; diff --git a/src/object/schema_system_catalog_constants.h b/src/object/schema_system_catalog_constants.h index 8838ac4ab7..909dcb98db 100644 --- a/src/object/schema_system_catalog_constants.h +++ b/src/object/schema_system_catalog_constants.h @@ -40,6 +40,7 @@ #define CT_DATATYPE_NAME "_db_data_type" #define CT_STORED_PROC_NAME "_db_stored_procedure" #define CT_STORED_PROC_ARGS_NAME "_db_stored_procedure_args" +#define CT_STORED_PROC_CODE_NAME "_db_stored_procedure_code" #define CT_PARTITION_NAME "_db_partition" #define CT_SERIAL_NAME "db_serial" #define CT_HA_APPLY_INFO_NAME "db_ha_apply_info" diff --git a/src/object/schema_system_catalog_definition.hpp b/src/object/schema_system_catalog_definition.hpp index d5b3bc850f..ed8d583363 100644 --- a/src/object/schema_system_catalog_definition.hpp +++ b/src/object/schema_system_catalog_definition.hpp @@ -33,7 +33,6 @@ namespace cubschema { - enum class attribute_kind { COLUMN, diff --git a/src/object/schema_system_catalog_install.cpp b/src/object/schema_system_catalog_install.cpp index 6a073daaf2..8f4220b2a5 100644 --- a/src/object/schema_system_catalog_install.cpp +++ b/src/object/schema_system_catalog_install.cpp @@ -224,6 +224,7 @@ catcls_init (void) ADD_TABLE_DEFINITION (CT_DATATYPE_NAME, system_catalog_initializer::get_data_type()); ADD_TABLE_DEFINITION (CT_STORED_PROC_NAME, system_catalog_initializer::get_stored_procedure()); ADD_TABLE_DEFINITION (CT_STORED_PROC_ARGS_NAME, system_catalog_initializer::get_stored_procedure_arguments()); + ADD_TABLE_DEFINITION (CT_STORED_PROC_CODE_NAME, system_catalog_initializer::get_stored_procedure_code()); ADD_TABLE_DEFINITION (CT_SERIAL_NAME, system_catalog_initializer::get_serial()); ADD_TABLE_DEFINITION (CT_HA_APPLY_INFO_NAME, system_catalog_initializer::get_ha_apply_info()); ADD_TABLE_DEFINITION (CT_COLLATION_NAME, system_catalog_initializer::get_collations()); @@ -743,7 +744,8 @@ namespace cubschema { {"grantor", AU_USER_CLASS_NAME}, {"grantee", AU_USER_CLASS_NAME}, - {"class_of", CT_CLASS_NAME}, + {"object_type", "integer"}, + {"object_of", "object"}, {"auth_type", format_varchar (7)}, {"is_grantable", "integer"} }, @@ -756,7 +758,7 @@ namespace cubschema // owner, grants Au_dba_user, {} }, -// initializer +// initializers nullptr ); @@ -831,19 +833,24 @@ namespace cubschema CT_STORED_PROC_NAME, // columns { + {"unique_name", format_varchar (255)}, {"sp_name", format_varchar (255)}, {"sp_type", "integer"}, {"return_type", "integer"}, {"arg_count", "integer"}, {"args", format_sequence (CT_STORED_PROC_ARGS_NAME)}, {"lang", "integer"}, - {"target", format_varchar (4096)}, + {"pkg_name", format_varchar (255)}, + {"is_system_generated", "integer"}, + {"directive", "integer"}, + {"target_class", format_varchar (1024)}, + {"target_method", format_varchar (1024)}, {"owner", AU_USER_CLASS_NAME}, {"comment", format_varchar (1024)} }, // constraints { - {DB_CONSTRAINT_UNIQUE, "", {"sp_name", nullptr}, false}, + {DB_CONSTRAINT_PRIMARY_KEY, "pk_db_stored_procedure_unique_name", {"unique_name", nullptr}, false} }, // authorization { @@ -853,8 +860,6 @@ namespace cubschema // initializer nullptr ); - - } system_catalog_definition @@ -866,16 +871,20 @@ namespace cubschema CT_STORED_PROC_ARGS_NAME, // columns { - {"sp_name", format_varchar (255)}, + {"sp_of", CT_STORED_PROC_NAME}, + {"pkg_name", format_varchar (255)}, {"index_of", "integer"}, + {"is_system_generated", "integer"}, {"arg_name", format_varchar (255)}, {"data_type", "integer"}, {"mode", "integer"}, + {"default_value", format_varchar (255)}, // TODO: CBRD-25261 + {"is_optional", "integer"}, // default_value is used only when is_optional is 1 {"comment", format_varchar (1024)}, }, // constraints { - {DB_CONSTRAINT_INDEX, "", {"sp_name", nullptr}, false}, + {DB_CONSTRAINT_INDEX, "", {"sp_of", nullptr}, false}, }, // authorization { @@ -885,8 +894,40 @@ namespace cubschema // initializer nullptr ); + } + system_catalog_definition + system_catalog_initializer::get_stored_procedure_code () + { + + return system_catalog_definition ( + // name + CT_STORED_PROC_CODE_NAME, + // columns + { + {"name", format_varchar (1024)}, // same with [_db_stored_procedure].[target_class] + {"created_time", format_varchar (16)}, + {"owner", AU_USER_CLASS_NAME}, + {"is_static", "integer"}, + {"is_system_generated", "integer"}, + {"stype", "integer"}, + {"scode", format_varchar (1073741823)}, + {"otype", "integer"}, + {"ocode", format_varchar (1073741823)} + }, +// constraints + { + {DB_CONSTRAINT_PRIMARY_KEY, "", {"name", nullptr}, false} + }, +// authorization + { + // owner, grants + Au_dba_user, {} + }, +// initializer + nullptr + ); } system_catalog_definition @@ -1658,7 +1699,8 @@ namespace cubschema { {"grantor_name", "varchar(255)"}, {"grantee_name", "varchar(255)"}, - {"class_name", "varchar(255)"}, + {"object_type", "varchar(16)"}, + {"object_name", "varchar(255)"}, {"owner_name", "varchar(255)"}, {"auth_type", "varchar(7)"}, {"is_grantable", "varchar(3)"}, @@ -1767,12 +1809,15 @@ namespace cubschema // columns { {"sp_name", "varchar(255)"}, + {"pkg_name", "varchar (255)"}, {"sp_type", "varchar(16)"}, {"return_type", "varchar(16)"}, {"arg_count", "integer"}, {"lang", "varchar(16)"}, + {"authid", "varchar(16)"}, {"target", "varchar(4096)"}, {"owner", "varchar(256)"}, + {"code", format_varchar (1073741823)}, {"comment", "varchar(1024)"}, // query specs {attribute_kind::QUERY_SPEC, sm_define_view_stored_procedure_spec ()} @@ -1804,6 +1849,8 @@ namespace cubschema // columns { {"sp_name", "varchar(255)"}, + {"owner_name", "varchar(255)"}, + {"pkg_name", "varchar (255)"}, {"index_of", "integer"}, {"arg_name", "varchar(255)"}, {"data_type", "varchar(16)"}, diff --git a/src/object/schema_system_catalog_install.hpp b/src/object/schema_system_catalog_install.hpp index 7dd89dc710..98133d956e 100644 --- a/src/object/schema_system_catalog_install.hpp +++ b/src/object/schema_system_catalog_install.hpp @@ -47,6 +47,7 @@ namespace cubschema static system_catalog_definition get_partition (); static system_catalog_definition get_data_type (); static system_catalog_definition get_stored_procedure (); + static system_catalog_definition get_stored_procedure_code (); static system_catalog_definition get_stored_procedure_arguments (); static system_catalog_definition get_serial (); diff --git a/src/object/schema_system_catalog_install_query_spec.cpp b/src/object/schema_system_catalog_install_query_spec.cpp index 1f67e84d48..42b7aa3a29 100644 --- a/src/object/schema_system_catalog_install_query_spec.cpp +++ b/src/object/schema_system_catalog_install_query_spec.cpp @@ -68,7 +68,7 @@ sm_define_view_class_spec (void) "SELECT " "[c].[class_name] AS [class_name], " "CAST ([c].[owner].[name] AS VARCHAR(255)) AS [owner_name], " /* string -> varchar(255) */ - "CASE [c].[class_type] WHEN 0 THEN 'CLASS' WHEN 1 THEN 'VCLASS' ELSE 'UNKNOW' END AS [class_type], " + "CASE [c].[class_type] WHEN 0 THEN 'CLASS' WHEN 1 THEN 'VCLASS' ELSE 'UNKNOWN' END AS [class_type], " "CASE WHEN MOD ([c].[is_system_class], 2) = 1 THEN 'YES' ELSE 'NO' END AS [is_system_class], " "CASE [c].[tde_algorithm] WHEN 0 THEN 'NONE' WHEN 1 THEN 'AES' WHEN 2 THEN 'ARIA' END AS [tde_algorithm], " "CASE " @@ -105,9 +105,9 @@ sm_define_view_class_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[c]} SUBSETEQ (" + "OR {[c].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -170,9 +170,9 @@ sm_define_view_super_class_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[c]} SUBSETEQ (" + "OR {[c].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -236,9 +236,9 @@ sm_define_view_vclass_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[q].[class_of]} SUBSETEQ (" + "OR {[q].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -334,9 +334,9 @@ sm_define_view_attribute_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[c]} SUBSETEQ (" + "OR {[c].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -418,9 +418,9 @@ sm_define_view_attribute_set_domain_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[c]} SUBSETEQ (" + "OR {[c].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -492,9 +492,9 @@ sm_define_view_method_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[m].[class_of]} SUBSETEQ (" + "OR {[m].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -573,9 +573,9 @@ sm_define_view_method_argument_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[s].[meth_of].[class_of]} SUBSETEQ (" + "OR {[s].[meth_of].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -656,9 +656,9 @@ sm_define_view_method_argument_set_domain_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[s].[meth_of].[class_of]} SUBSETEQ (" + "OR {[s].[meth_of].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -723,9 +723,9 @@ sm_define_view_method_file_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[f].[class_of]} SUBSETEQ (" + "OR {[f].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -837,9 +837,9 @@ sm_define_view_index_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[i].[class_of]} SUBSETEQ (" + "OR {[i].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -914,9 +914,9 @@ sm_define_view_index_key_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[k].[index_of].[class_of]} SUBSETEQ (" + "OR {[k].[index_of].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -946,21 +946,25 @@ sm_define_view_index_key_spec (void) const char * sm_define_view_authorization_spec (void) { - static char stmt [2048]; + static char stmt [4096]; // *INDENT-OFF* sprintf (stmt, "SELECT " "CAST ([a].[grantor].[name] AS VARCHAR(255)) AS [grantor_name], " /* string -> varchar(255) */ "CAST ([a].[grantee].[name] AS VARCHAR(255)) AS [grantee_name], " /* string -> varchar(255) */ - "[a].[class_of].[class_name] AS [class_name], " - "CAST ([a].[class_of].[owner].[name] AS VARCHAR(255)) AS [owner_name], " /* string -> varchar(255) */ + "CASE [c].[class_type] WHEN 0 THEN 'CLASS' WHEN 1 THEN 'VCLASS' ELSE 'UNKNOWN' END AS [object_type], " + "[c].[class_name] AS [object_name], " + "CAST ([c].[owner].[name] AS VARCHAR(255)) AS [owner_name], " /* string -> varchar(255) */ "[a].[auth_type] AS [auth_type], " "CASE [a].[is_grantable] WHEN 0 THEN 'NO' ELSE 'YES' END AS [is_grantable] " "FROM " - /* CT_CLASSAUTH_NAME */ - "[%s] AS [a] " + /* CT_CLASSAUTH_NAME, CT_CLASS_NAME */ + "[%s] AS [a], [%s] AS [c] " "WHERE " + "[a].[object_of] = [c].[class_of] " + "AND [a].[object_type] = 0 " + "AND ( " "{'DBA'} SUBSETEQ (" "SELECT " "SET {CURRENT_USER} + COALESCE (SUM (SET {[t].[g].[name]}), SET {}) " @@ -970,7 +974,7 @@ sm_define_view_authorization_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[a].[class_of].[owner].[name]} SUBSETEQ (" + "OR {[c].[owner].[name]} SUBSETEQ (" "SELECT " "SET {CURRENT_USER} + COALESCE (SUM (SET {[t].[g].[name]}), SET {}) " "FROM " @@ -979,9 +983,9 @@ sm_define_view_authorization_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[a].[class_of]} SUBSETEQ (" + "OR {[c].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -996,12 +1000,73 @@ sm_define_view_authorization_spec (void) "[u].[name] = CURRENT_USER" ") " "AND [au].[auth_type] = 'SELECT'" - ")", + ") ) " + "UNION ALL " + "SELECT " + "CAST ([a].[grantor].[name] AS VARCHAR(255)) AS [grantor_name], " /* string -> varchar(255) */ + "CAST ([a].[grantee].[name] AS VARCHAR(255)) AS [grantee_name], " /* string -> varchar(255) */ + "CASE [s].[sp_type] WHEN 1 THEN 'PROCEDURE' ELSE 'FUNCTION' END AS [object_type], " + "[s].[sp_name] AS [object_name], " + "CAST ([s].[owner].[name] AS VARCHAR(255)) AS [owner_name], " + "[a].[auth_type] AS [auth_type], " + "CASE [a].[is_grantable] WHEN 0 THEN 'NO' ELSE 'YES' END AS [is_grantable] " + "FROM " + /* CT_CLASSAUTH_NAME, CT_STORED_PROC_NAME */ + "[%s] AS [a], [%s] AS [s] " + "WHERE " + "[a].[object_of] = [s] " + "AND [a].[object_type] = 5 " + "AND ( " + "{'DBA'} SUBSETEQ (" + "SELECT " + "SET {CURRENT_USER} + COALESCE (SUM (SET {[t].[g].[name]}), SET {}) " + "FROM " + /* AU_USER_CLASS_NAME */ + "[%s] AS [u], TABLE ([u].[groups]) AS [t] ([g]) " + "WHERE " + "[u].[name] = CURRENT_USER" + ") " + "OR {[s].[owner].[name]} SUBSETEQ (" + "SELECT " + "SET {CURRENT_USER} + COALESCE (SUM (SET {[t].[g].[name]}), SET {}) " + "FROM " + /* AU_USER_CLASS_NAME */ + "[%s] AS [u], TABLE ([u].[groups]) AS [t] ([g]) " + "WHERE " + "[u].[name] = CURRENT_USER" + ") " + "OR {[s]} SUBSETEQ (" + "SELECT " + "SUM (SET {[au].[object_of]}) " + "FROM " + /* CT_CLASSAUTH_NAME */ + "[%s] AS [au] " + "WHERE " + "{[au].[grantee].[name]} SUBSETEQ (" + "SELECT " + "SET {CURRENT_USER} + COALESCE (SUM (SET {[t].[g].[name]}), SET {}) " + "FROM " + /* AU_USER_CLASS_NAME */ + "[%s] AS [u], TABLE ([u].[groups]) AS [t] ([g]) " + "WHERE " + "[u].[name] = CURRENT_USER" + ") " + "AND [au].[auth_type] = 'EXECUTE'" + ") ) ", CT_CLASSAUTH_NAME, + CT_CLASS_NAME, AU_USER_CLASS_NAME, AU_USER_CLASS_NAME, CT_CLASSAUTH_NAME, - AU_USER_CLASS_NAME); + AU_USER_CLASS_NAME, + + CT_CLASSAUTH_NAME, + CT_STORED_PROC_NAME, + AU_USER_CLASS_NAME, + AU_USER_CLASS_NAME, + CT_CLASSAUTH_NAME, + AU_USER_CLASS_NAME + ); // *INDENT-ON* return stmt; @@ -1048,9 +1113,9 @@ sm_define_view_trigger_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[c]} SUBSETEQ (" /* Why [c] and not [t].[target_class]? */ + "OR {[c].[class_of]} SUBSETEQ (" /* Why [c] and not [t].[target_class]? */ "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -1122,9 +1187,9 @@ sm_define_view_partition_spec (void) "WHERE " "[u].[name] = CURRENT_USER" ") " - "OR {[p].[class_of]} SUBSETEQ (" + "OR {[p].[class_of].[class_of]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " @@ -1162,6 +1227,7 @@ sm_define_view_stored_procedure_spec (void) sprintf (stmt, "SELECT " "[sp].[sp_name] AS [sp_name], " + "[sp].[pkg_name] AS [pkg_name], " "CASE [sp].[sp_type] WHEN 1 THEN 'PROCEDURE' ELSE 'FUNCTION' END AS [sp_type], " "CASE [sp].[return_type] " "WHEN 0 THEN 'void' " @@ -1170,15 +1236,22 @@ sm_define_view_stored_procedure_spec (void) "ELSE (SELECT [t].[type_name] FROM [%s] AS [t] WHERE [sp].[return_type] = [t].[type_id]) " "END AS [return_type], " "[sp].[arg_count] AS [arg_count], " - "CASE [sp].[lang] WHEN 1 THEN 'JAVA' ELSE '' END AS [lang], " - "[sp].[target] AS [target], " + "CASE [sp].[lang] WHEN 0 THEN 'PLCSQL' WHEN 1 THEN 'JAVA' ELSE 'UNKNOWN' END AS [lang], " + "CASE [sp].[directive] & 1 WHEN 0 THEN 'DEFINER' ELSE 'CURRENT_USER' END AS [authid], " + "CONCAT ([sp].[target_class], '.', [sp].[target_method]) AS [target], " "CAST ([sp].[owner].[name] AS VARCHAR(255)) AS [owner], " /* string -> varchar(255) */ + "[sp_code].[scode] AS [code], " "[sp].[comment] AS [comment] " "FROM " /* CT_STORED_PROC_NAME */ - "[%s] AS [sp]", + "[%s] AS [sp] " + /* CT_STORED_PROC_CODE_NAME */ + "LEFT OUTER JOIN [%s] AS [sp_code] ON [sp].[target_class] = [sp_code].[name] " + "WHERE " + "[sp].[is_system_generated] = 0", CT_DATATYPE_NAME, - CT_STORED_PROC_NAME); + CT_STORED_PROC_NAME, + CT_STORED_PROC_CODE_NAME); // *INDENT-ON* return stmt; @@ -1192,7 +1265,9 @@ sm_define_view_stored_procedure_arguments_spec (void) // *INDENT-OFF* sprintf (stmt, "SELECT " - "[sp].[sp_name] AS [sp_name], " + "[sp].[sp_of].[sp_name] AS [sp_name], " + "CAST ([sp].[sp_of].[owner].[name] AS VARCHAR(255)) AS [sp_owner_name], " /* string -> varchar(255) */ + "[sp].[pkg_name] AS [pkg_name], " "[sp].[index_of] AS [index_of], " "[sp].[arg_name] AS [arg_name], " "CASE [sp].[data_type] " @@ -1205,8 +1280,9 @@ sm_define_view_stored_procedure_arguments_spec (void) "FROM " /* CT_STORED_PROC_ARGS_NAME */ "[%s] AS [sp] " + "WHERE [sp].[is_system_generated] = 0 " "ORDER BY " /* Is it possible to remove ORDER BY? */ - "[sp].[sp_name], " + "[sp].[sp_of].[sp_name], " "[sp].[index_of]", CT_DATATYPE_NAME, CT_STORED_PROC_ARGS_NAME); @@ -1368,7 +1444,7 @@ sm_define_view_db_server_spec (void) ") " "OR {[ds]} SUBSETEQ (" "SELECT " - "SUM (SET {[au].[class_of]}) " + "SUM (SET {[au].[object_of]}) " "FROM " /* CT_CLASSAUTH_NAME */ "[%s] AS [au] " diff --git a/src/object/trigger_manager.c b/src/object/trigger_manager.c index e4b76016d6..2bd5460431 100644 --- a/src/object/trigger_manager.c +++ b/src/object/trigger_manager.c @@ -5099,7 +5099,7 @@ execute_activity (TR_TRIGGER * trigger, DB_TRIGGER_TIME tr_time, DB_OBJECT * cur { if (AU_SET_USER (save_user)) { - /* what can this mean ? */ + // what can this mean ? rstatus = TR_RETURN_ERROR; } } diff --git a/src/optimizer/query_graph.c b/src/optimizer/query_graph.c index c4ef557878..dd6583c74c 100644 --- a/src/optimizer/query_graph.c +++ b/src/optimizer/query_graph.c @@ -3749,13 +3749,6 @@ pt_is_pseudo_const (PT_NODE * expr) */ return true; - case PT_METHOD_CALL: - /* - * Even if there are columns(PT_NAME) in the parameter of the Java Stored Procedure(METHOD_CALL), - * it can be guaranteed to be evaluated by the time it is referenced. - */ - return true; - case PT_DOT_: /* * It would be nice if we could use expressions that are @@ -4034,6 +4027,21 @@ pt_is_pseudo_const (PT_NODE * expr) return false; } + case PT_METHOD_CALL: + PT_NODE * p; + /* + * Even if there are columns(PT_NAME) in the parameter of the Java Stored Procedure(METHOD_CALL), + * it can be guaranteed to be evaluated by the time it is referenced. + */ + for (p = expr->info.method_call.arg_list; p; p = p->next) + { + if (!pt_is_pseudo_const (p)) + { + return false; + } + } + return true; + case PT_FUNCTION: { /* diff --git a/src/parser/csql_grammar.y b/src/parser/csql_grammar.y index b7522b7c32..d60cd82076 100644 --- a/src/parser/csql_grammar.y +++ b/src/parser/csql_grammar.y @@ -166,7 +166,7 @@ static void pt_fill_conn_info_container(PARSER_CONTEXT *parser, int buffer_pos, #include "memory_alloc.h" #include "db_elo.h" #include "storage_common.h" -#include "jsp_cl.h" +#include "sp_constants.hpp" #include "db_function.hpp" #if defined (SUPPRESS_STRLEN_WARNING) @@ -490,7 +490,8 @@ char *g_query_string; int g_query_string_len; int g_original_buffer_len; -static char *g_plcsql_text; +static int pt_set_plcsql_body_impl(PT_NODE* node, PT_NODE* body, int start, int spec_start, int spec_end, int end); +static int g_plcsql_text_pos; /* * The behavior of location propagation when a rule is matched must @@ -554,7 +555,6 @@ static char *g_plcsql_text; %} -%initial-action {yybuffer_pos = 0;} %locations %glr-parser %define parse.error verbose @@ -661,6 +661,7 @@ static char *g_plcsql_text; %type opt_access_modifier %type deduplicate_key_mod_level %type opt_index_with_clause_no_online +%type opt_authid /*}}}*/ /* define rule type (node) */ @@ -710,6 +711,9 @@ static char *g_plcsql_text; %type serial_name %type synonym_name_without_dot %type synonym_name +%type procedure_or_function_name_without_dot +%type procedure_or_function_name +%type procedure_or_function_name_list %type opt_alter_synonym %type opt_identifier %type normal_or_class_attr_list_with_commas @@ -750,6 +754,7 @@ static char *g_plcsql_text; %type delete_stmt %type author_cmd_list %type authorized_cmd +%type authorized_execute_procedure_cmd %type opt_password %type opt_groups %type opt_members @@ -953,6 +958,8 @@ static char *g_plcsql_text; %type grant_head %type grant_cmd %type revoke_cmd +%type grant_proc_cmd +%type revoke_proc_cmd %type opt_from_table_spec_list %type method_file_list %type incr_arg_name_list__inc @@ -1031,6 +1038,7 @@ static char *g_plcsql_text; %type dblink_column_definition %type pl_language_spec +%type opt_sp_default_value %type table_column /*}}}*/ @@ -1348,7 +1356,6 @@ static char *g_plcsql_text; %token PROMOTE %token QUERY %token READ -%token REBUILD %token RECURSIVE %token REF %token REFERENCES @@ -1516,12 +1523,14 @@ static char *g_plcsql_text; %token ANALYZE %token ARCHIVE %token ARIA +%token AUTHID %token AUTO_INCREMENT %token BENCHMARK %token BIT_AND %token BIT_OR %token BIT_XOR %token BUFFER +%token CALLER %token CACHE %token CAPACITY %token CHARACTER_SET_ @@ -1533,6 +1542,7 @@ static char *g_plcsql_text; %token COLUMNS %token COMMENT %token COMMITTED +%token COMPILE %token COST %token CRITICAL %token CUME_DIST @@ -1541,6 +1551,7 @@ static char *g_plcsql_text; %token DBLINK %token DBNAME %token DECREMENT +%token DEFINER %token DENSE_RANK %token DONT_REUSE_OID %token ELT @@ -1653,6 +1664,7 @@ static char *g_plcsql_text; %token QUEUES %token RANGE_ %token RANK +%token REBUILD %token REGEXP_COUNT %token REGEXP_INSTR %token REGEXP_LIKE @@ -1669,6 +1681,7 @@ static char *g_plcsql_text; %token DISK_SIZE %token ROW_NUMBER %token SECTIONS +%token SEMICOLON %token SEPARATOR %token SERIAL %token SERVER @@ -1739,9 +1752,9 @@ stmt_done ; stmt_list - : stmt_list ';' %dprec 1 + : stmt_list SEMICOLON %dprec 1 {{ /* empty line*/ }} - | stmt_list ';' stmt %dprec 2 + | stmt_list SEMICOLON stmt %dprec 2 {{ if ($3 != NULL) @@ -1785,7 +1798,7 @@ stmt_list } DBG_PRINT}} - | ';' + | SEMICOLON {{ /* empty line*/ }} ; @@ -1863,7 +1876,7 @@ stmt allow_attribute_ordering = false; parser_hidden_incr_list = NULL; - g_plcsql_text = NULL; + g_plcsql_text_pos = -1; is_in_sp_func_type = false; assert(expecting_pl_lang_spec == 0); // initialized in parser_main() or parse_one_statement() DBG_PRINT}} @@ -3058,22 +3071,45 @@ create_stmt push_msg(MSGCAT_SYNTAX_INVALID_CREATE_PROCEDURE); expecting_pl_lang_spec = 1; } - identifier opt_sp_param_list /* 5, 6 */ - is_or_as pl_language_spec /* 7, 8 */ - opt_comment_spec /* 9 */ + procedure_or_function_name_without_dot /* 5 */ + opt_sp_param_list /* 6 */ + opt_authid /* 7 */ + is_or_as pl_language_spec /* 8, 9 */ + opt_comment_spec /* 10 */ { pop_msg(); } {{ DBG_TRACE_GRAMMAR(create_stmt, | CREATE opt_or_replace PROCEDURE~); PT_NODE *node = parser_pop_hint_node (); if (node) { + PT_NODE* body = $9; + if (body->info.sp_body.lang == SP_LANG_PLCSQL && body->info.sp_body.impl == NULL) + { + // In particular, this happens for two cases: + // . cubrid loaddb -s ... (loading a schema file with loaddb utility) + // . csql -i --no-single-line ... (running csql with -i and --no-single-line) + // in which case parser->original_buffer is NULL. + // Without the original buffer, We need to get the SQL user text from the file. + assert(this_parser->original_buffer == NULL); + assert(this_parser->file); + + int start = @1.buffer_pos - 6; // 6 : length of "create" + int spec_start = @8.buffer_pos; // right after is_or_as + int spec_end = @9.buffer_pos; + int end = @$.buffer_pos; + if (pt_set_plcsql_body_impl(node, body, start, spec_start, spec_end, end) < 0) { + PT_ERROR (this_parser, node, "failed to get the user SQL from the input file"); + } + } + node->info.sp.or_replace = $2; node->info.sp.name = $5; node->info.sp.type = PT_SP_PROCEDURE; + node->info.sp.auth_id = $7; node->info.sp.param_list = $6; node->info.sp.ret_type = PT_TYPE_NONE; node->info.sp.ret_data_type = NULL; - node->info.sp.body = $8; - node->info.sp.comment = $9; + node->info.sp.body = $9; + node->info.sp.comment = $10; } $$ = node; @@ -3089,23 +3125,46 @@ create_stmt push_msg(MSGCAT_SYNTAX_INVALID_CREATE_FUNCTION); expecting_pl_lang_spec = 1; } - identifier opt_sp_param_list /* 5, 6 */ + procedure_or_function_name_without_dot /* 5 */ + opt_sp_param_list /* 6 */ RETURN sp_return_type /* 7, 8 */ - is_or_as pl_language_spec /* 9, 10 */ - opt_comment_spec /* 11 */ + opt_authid /* 9 */ + is_or_as pl_language_spec /* 10, 11 */ + opt_comment_spec /* 12 */ { pop_msg(); } {{ DBG_TRACE_GRAMMAR(create_stmt, | CREATE opt_or_replace FUNCTION~); PT_NODE *node = parser_pop_hint_node (); if (node) { + PT_NODE* body = $11; + if (body->info.sp_body.lang == SP_LANG_PLCSQL && body->info.sp_body.impl == NULL) + { + // In particular, this happens for two cases: + // . cubrid loaddb -s ... (loading a schema file with loaddb utility) + // . csql -i --no-single-line ... (running csql with -i and --no-single-line) + // in which case parser->original_buffer is NULL. + // Without the original buffer, We need to get the SQL user text from the file. + assert(this_parser->original_buffer == NULL); + assert(this_parser->file); + + int start = @1.buffer_pos - 6; // 6 : length of "create" + int spec_start = @10.buffer_pos; // right after is_or_as + int spec_end = @11.buffer_pos; + int end = @$.buffer_pos; + if (pt_set_plcsql_body_impl(node, body, start, spec_start, spec_end, end) < 0) { + PT_ERROR (this_parser, node, "failed to get the user SQL from the input file"); + } + } + node->info.sp.or_replace = $2; node->info.sp.name = $5; node->info.sp.type = PT_SP_FUNCTION; + node->info.sp.auth_id = $9; node->info.sp.param_list = $6; node->info.sp.ret_type = (int) TO_NUMBER(CONTAINER_AT_0($8)); node->info.sp.ret_data_type = CONTAINER_AT_1($8); - node->info.sp.body = $10; - node->info.sp.comment = $11; + node->info.sp.body = $11; + node->info.sp.comment = $12; } $$ = node; @@ -4083,10 +4142,10 @@ alter_stmt DBG_PRINT}} | ALTER /* 1 */ procedure_or_function /* 2 */ - identifier /* 3 */ - opt_owner_clause /* 4 */ - opt_comment_spec /* 5 */ - {{ DBG_TRACE_GRAMMAR(alter_stmt, | ALTER procedure_or_function identifier opt_owner_clause opt_comment_spec); + procedure_or_function_name /* 3 */ + opt_owner_clause /* 4 */ + opt_comment_spec /* 5 */ + {{ DBG_TRACE_GRAMMAR(alter_stmt, | ALTER procedure_or_function procedure_or_function_name opt_owner_clause opt_comment_spec); PT_NODE *node = parser_new_node (this_parser, PT_ALTER_STORED_PROCEDURE); @@ -4096,6 +4155,7 @@ alter_stmt node->info.sp.type = ($2 == 1) ? PT_SP_PROCEDURE : PT_SP_FUNCTION; node->info.sp.ret_type = PT_TYPE_NONE; node->info.sp.owner = $4; + node->info.sp.recompile = 0; node->info.sp.comment = $5; if ($4 == NULL && $5 == NULL) { @@ -4108,6 +4168,26 @@ alter_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | ALTER /* 1 */ + procedure_or_function /* 2 */ + procedure_or_function_name /* 3 */ + COMPILE /* 4 */ + {{ DBG_TRACE_GRAMMAR(alter_stmt, | ALTER procedure_or_function procedure_or_function_name COMPILE); + + PT_NODE *node = parser_new_node (this_parser, PT_ALTER_STORED_PROCEDURE); + + if (node != NULL) + { + node->info.sp.name = $3; + node->info.sp.type = ($2 == 1) ? PT_SP_PROCEDURE : PT_SP_FUNCTION; + node->info.sp.ret_type = PT_TYPE_NONE; + node->info.sp.recompile = 1; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} | ALTER SERVER dblink_server_name alter_server_list {{ DBG_TRACE_GRAMMAR(alter_stmt, | ALTER SERVER dblink_server_name alter_server_list); @@ -4662,8 +4742,8 @@ drop_stmt PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) DBG_PRINT}} - | DROP PROCEDURE identifier_list - {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP PROCEDURE identifier_list); + | DROP PROCEDURE procedure_or_function_name_list + {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP PROCEDURE procedure_or_function_name_list); PT_NODE *node = parser_new_node (this_parser, PT_DROP_STORED_PROCEDURE); @@ -4678,8 +4758,8 @@ drop_stmt PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) DBG_PRINT}} - | DROP FUNCTION identifier_list - {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP FUNCTION identifier_list); + | DROP FUNCTION procedure_or_function_name_list + {{ DBG_TRACE_GRAMMAR(drop_stmt, | DROP FUNCTION procedure_or_function_name_list); PT_NODE *node = parser_new_node (this_parser, PT_DROP_STORED_PROCEDURE); @@ -5873,6 +5953,37 @@ synonym_name } ; +procedure_or_function_name_without_dot + : user_specified_name_without_dot + { DBG_TRACE_GRAMMAR(procedure_or_function_name_without_dot, : user_specified_name_without_dot); + $$ = $1; + } + ; + +procedure_or_function_name + : user_specified_name + { DBG_TRACE_GRAMMAR(procedure_or_function_name, : user_specified_name); + $$ = $1; + } + ; + +procedure_or_function_name_list + : procedure_or_function_name_list ',' procedure_or_function_name + {{ DBG_TRACE_GRAMMAR(procedure_or_function_name_list, : procedure_or_function_name_list ',' procedure_or_function_name); + + $$ = parser_make_link($1, $3); + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + + DBG_PRINT}} + | procedure_or_function_name + {{ DBG_TRACE_GRAMMAR(procedure_or_function_name_list, : procedure_or_function_name); + + $$ = $1; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + + DBG_PRINT}} + ; + opt_partition_spec : /* empty */ {{ DBG_TRACE_GRAMMAR(opt_partition_spec, : ); @@ -8866,6 +8977,22 @@ auth_stmt $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | revoke_proc_cmd procedure_or_function_name_list from_id_list + {{ DBG_TRACE_GRAMMAR(auth_stmt, | revoke_proc_cmd procedure_or_function_name_list from_id_list); + + PT_NODE *node = parser_new_node (this_parser, PT_REVOKE); + + if (node) + { + node->info.revoke.user_list = $3; + node->info.revoke.spec_list = $2; + node->info.revoke.auth_cmd_list = $1; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} ; @@ -8885,6 +9012,23 @@ grant_cmd { pop_msg(); } { DBG_TRACE_GRAMMAR(grant_cmd, : GRANT author_cmd_list); $$ = $3; } + +grant_proc_cmd + : GRANT + { push_msg(MSGCAT_SYNTAX_MISSING_AUTH_COMMAND_LIST); } + authorized_execute_procedure_cmd + { pop_msg(); } + { DBG_TRACE_GRAMMAR(grant_proc_cmd, : GRANT authorized_execute_procedure_cmd); + $$ = $3; } + ; + +revoke_proc_cmd + : REVOKE + { push_msg(MSGCAT_SYNTAX_MISSING_AUTH_COMMAND_LIST); } + authorized_execute_procedure_cmd + { pop_msg(); } + { DBG_TRACE_GRAMMAR(revoke_proc_cmd, : REVOKE authorized_execute_procedure_cmd); + $$ = $3; } ; grant_head @@ -8919,6 +9063,38 @@ grant_head $$ = node; PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} + | grant_cmd to_id_list + {{ DBG_TRACE_GRAMMAR(grant_head, | grant_cmd to_id_list); + + PT_NODE *node = parser_new_node (this_parser, PT_GRANT); + + if (node) + { + node->info.grant.user_list = $2; + node->info.grant.spec_list = NULL; + node->info.grant.auth_cmd_list = $1; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + + DBG_PRINT}} + | grant_proc_cmd procedure_or_function_name_list to_id_list + {{ DBG_TRACE_GRAMMAR(grant_head, | grant_proc_cmd procedure_or_function_name_list to_id_list); + + PT_NODE *node = parser_new_node (this_parser, PT_GRANT); + + if (node) + { + node->info.grant.user_list = $3; + node->info.grant.spec_list = $2; + node->info.grant.auth_cmd_list = $1; + } + + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT}} ; @@ -8981,6 +9157,20 @@ author_cmd_list DBG_PRINT}} ; +authorized_execute_procedure_cmd + : EXECUTE ON_ PROCEDURE + {{ + PT_NODE *node = parser_new_node (this_parser, PT_AUTH_CMD); + if (node) + { + node->info.auth_cmd.auth_cmd = PT_EXECUTE_PROCEDURE_PRIV; + node->info.auth_cmd.attr_mthd_list = NULL; + } + $$ = node; + PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) + DBG_PRINT }} + ; + authorized_cmd : SELECT {{ DBG_TRACE_GRAMMAR(authorized_cmd, : SELECT); @@ -9116,6 +9306,7 @@ authorized_cmd PARSER_SAVE_ERR_CONTEXT ($$, @$.buffer_pos) DBG_PRINT}} + | EXECUTE {{ DBG_TRACE_GRAMMAR(authorized_cmd, | EXECUTE); @@ -12640,6 +12831,19 @@ sp_return_type DBG_PRINT}} ; +opt_authid + : /* empty */ + {{ $$ = PT_AUTHID_OWNER; }} + | AUTHID DEFINER + {{ $$ = PT_AUTHID_OWNER; }} + | AUTHID OWNER + {{ $$ = PT_AUTHID_OWNER; }} + | AUTHID CALLER + {{ $$ = PT_AUTHID_CALLER; }} + | AUTHID CURRENT_USER + {{ $$ = PT_AUTHID_CALLER; }} + ; + is_or_as : IS | AS @@ -12651,26 +12855,20 @@ opt_lang_plcsql ; pl_language_spec - : opt_lang_plcsql plcsql_text opt_identifier + : opt_lang_plcsql plcsql_text {{ DBG_TRACE_GRAMMAR(pl_language_spec, : opt_lang_plcsql plcsql_text); PT_NODE *node = parser_new_node (this_parser, PT_SP_BODY); if (node) { - int len; - - assert(g_plcsql_text != NULL); - - if ($3) { - len = $2 + strlen($3->info.name.original); - parser_free_tree(this_parser, $3); + node->info.sp_body.lang = SP_LANG_PLCSQL; + if (g_query_string) { + node->info.sp_body.impl = pt_create_string_literal_node_w_charset_coll( + g_query_string + g_plcsql_text_pos, $2); } else { - len = $2; + node->info.sp_body.impl = NULL; // set later } - - node->info.sp_body.lang = SP_LANG_PLCSQL; - node->info.sp_body.impl = pt_create_string_literal_node_w_charset_coll(g_plcsql_text, len); node->info.sp_body.direct = 1; } @@ -12707,9 +12905,9 @@ plcsql_text | plcsql_text_part {{ DBG_TRACE_GRAMMAR(plcsql_text, | plcsql_text_part); - assert(g_plcsql_text == NULL); + assert(g_plcsql_text_pos == -1); $$ = strlen($1); - g_plcsql_text = g_query_string + @$.buffer_pos - $$; + g_plcsql_text_pos = @$.buffer_pos - $$; DBG_PRINT}} ; @@ -12792,6 +12990,7 @@ sp_param_def : identifier opt_sp_in_out sp_param_type + opt_sp_default_value opt_comment_spec {{ DBG_TRACE_GRAMMAR(sp_param_def, : identifier opt_sp_in_out sp_param_type opt_comment_spec); @@ -12803,7 +13002,8 @@ sp_param_def node->data_type = CONTAINER_AT_1 ($3); node->info.sp_param.name = $1; node->info.sp_param.mode = $2; - node->info.sp_param.comment = $4; + node->info.sp_param.default_value = $4; + node->info.sp_param.comment = $5; } $$ = node; @@ -12883,6 +13083,26 @@ opt_sp_in_out DBG_PRINT}} ; +opt_sp_default_value + : /* empty */ + {{ + $$ = NULL; + DBG_PRINT}} + | DEFAULT + expression_ + {{ + PT_NODE *node = pt_make_data_default_expr_node (this_parser, $2); + PARSER_SAVE_ERR_CONTEXT (node, @2.buffer_pos) + $$ = node; + DBG_PRINT}} + | VAR_ASSIGN + expression_ + {{ + PT_NODE *node = pt_make_data_default_expr_node (this_parser, $2); + PARSER_SAVE_ERR_CONTEXT (node, @2.buffer_pos) + $$ = node; + DBG_PRINT}} + esql_query_stmt : { parser_select_level++; } csql_query_select_has_no_with_clause @@ -19286,7 +19506,7 @@ generic_function ; generic_function_for_call - : identifier + : procedure_or_function_name { if(pwd_info.parser_call_check) { @@ -19301,8 +19521,7 @@ generic_function_for_call } } '(' opt_expression_list_for_call ')' opt_on_target - {{ DBG_TRACE_GRAMMAR(generic_function_for_call, : identifier '(' opt_expression_list ')' opt_on_target ); - + {{ DBG_TRACE_GRAMMAR(generic_function_for_call, : procedure_or_function_name '(' opt_expression_list_for_call ')' opt_on_target ); PT_NODE *node = NULL; if ($6 == NULL) @@ -19319,6 +19538,17 @@ generic_function_for_call node->info.method_call.method_name = $1; node->info.method_call.arg_list = $4; node->info.method_call.on_call_target = $6; + if (node->info.method_call.on_call_target != NULL) + { + PT_NAME_INFO_CLEAR_FLAG (node->info.method_call.method_name, PT_NAME_INFO_USER_SPECIFIED); + } + else + { + if (node->info.method_call.arg_list != NULL && node->info.method_call.arg_list->node_type == PT_NAME && node->info.method_call.arg_list->info.name.meta_class == PT_META_CLASS) + { + PT_NAME_INFO_CLEAR_FLAG (node->info.method_call.method_name, PT_NAME_INFO_USER_SPECIFIED); + } + } node->info.method_call.call_or_expr = PT_IS_MTHD_EXPR; } @@ -22956,12 +23186,14 @@ identifier | ANALYZE {{ DBG_TRACE_GRAMMAR(identifier, | ANALYZE ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | ARCHIVE {{ DBG_TRACE_GRAMMAR(identifier, | ARCHIVE ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | ARIA {{ DBG_TRACE_GRAMMAR(identifier, | ARIA ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} + | AUTHID {{ DBG_TRACE_GRAMMAR(identifier, | AUTHID ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | AUTO_INCREMENT {{ DBG_TRACE_GRAMMAR(identifier, | AUTO_INCREMENT ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} - | BENCHMARK {{ DBG_TRACE_GRAMMAR(identifier, | BENCHMARK ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} + | BENCHMARK {{ DBG_TRACE_GRAMMAR(identifier, | BENCHMARK ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | BIT_AND {{ DBG_TRACE_GRAMMAR(identifier, | BIT_AND ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | BIT_OR {{ DBG_TRACE_GRAMMAR(identifier, | BIT_OR ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | BIT_XOR {{ DBG_TRACE_GRAMMAR(identifier, | BIT_XOR ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | BUFFER {{ DBG_TRACE_GRAMMAR(identifier, | BUFFER ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} + | CALLER {{ DBG_TRACE_GRAMMAR(identifier, | CALLER ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | CACHE {{ DBG_TRACE_GRAMMAR(identifier, | CACHE ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | CAPACITY {{ DBG_TRACE_GRAMMAR(identifier, | CAPACITY ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | CHARACTER_SET_ {{ DBG_TRACE_GRAMMAR(identifier, | CHARACTER_SET_ ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} @@ -22973,6 +23205,7 @@ identifier | COLUMNS {{ DBG_TRACE_GRAMMAR(identifier, | COLUMNS ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | COMMENT {{ DBG_TRACE_GRAMMAR(identifier, | COMMENT ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | COMMITTED {{ DBG_TRACE_GRAMMAR(identifier, | COMMITTED ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} + | COMPILE {{ DBG_TRACE_GRAMMAR(identifier, | COMPILE ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | COST {{ DBG_TRACE_GRAMMAR(identifier, | COST ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | CRITICAL {{ DBG_TRACE_GRAMMAR(identifier, | CRITICAL ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | CUME_DIST {{ DBG_TRACE_GRAMMAR(identifier, | CUME_DIST ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} @@ -22981,6 +23214,7 @@ identifier | DBLINK {{ DBG_TRACE_GRAMMAR(identifier, | DBLINK ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | DBNAME {{ DBG_TRACE_GRAMMAR(identifier, | DBNAME ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | DECREMENT {{ DBG_TRACE_GRAMMAR(identifier, | DECREMENT ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} + | DEFINER {{ DBG_TRACE_GRAMMAR(identifier, | DEFINER ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | DEDUPLICATE_ {{ DBG_TRACE_GRAMMAR(identifier, | DEDUPLICATE_ ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | DENSE_RANK {{ DBG_TRACE_GRAMMAR(identifier, | DENSE_RANK ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | DISK_SIZE {{ DBG_TRACE_GRAMMAR(identifier, | DISK_SIZE ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} @@ -23090,6 +23324,7 @@ identifier | QUEUES {{ DBG_TRACE_GRAMMAR(identifier, | QUEUES ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | RANGE_ {{ DBG_TRACE_GRAMMAR(identifier, | RANGE_ ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | RANK {{ DBG_TRACE_GRAMMAR(identifier, | RANK ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} + | REBUILD {{ DBG_TRACE_GRAMMAR(identifier, | REBUILD ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | REGEXP_COUNT {{ DBG_TRACE_GRAMMAR(identifier, | REGEXP_COUNT ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | REGEXP_INSTR {{ DBG_TRACE_GRAMMAR(identifier, | REGEXP_INSTR ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} | REGEXP_LIKE {{ DBG_TRACE_GRAMMAR(identifier, | REGEXP_LIKE ); SET_CPTR_2_PTNAME($$, $1, @$.buffer_pos); }} @@ -26255,7 +26490,7 @@ parser_main (PARSER_CONTEXT * parser) { long desc_index = 0; long i, top; - int rv; + int rv, yybuffer_pos_save; PARSER_CONTEXT *this_parser_saved; @@ -26271,6 +26506,7 @@ parser_main (PARSER_CONTEXT * parser) dbcs_start_input (); yycolumn = yycolumn_end = 1; + yybuffer_pos_save = yybuffer_pos; yybuffer_pos=0; is_dblink_query_string = 0; expecting_pl_lang_spec = 0; @@ -26282,6 +26518,11 @@ parser_main (PARSER_CONTEXT * parser) pt_initialize_hint(parser, parser_hint_table); rv = yyparse (); + + // parser_main can be reentered while executing statements loaded by loaddb -s. + // During the loaddb -s, the yybuffer_pos must not be currupted. + yybuffer_pos = yybuffer_pos_save; + pt_cleanup_hint (parser, parser_hint_table); if (pt_has_error (parser) || parser->stack_top <= 0 || !parser->node_stack) @@ -26365,6 +26606,9 @@ parse_one_statement (int state) csql_yyset_lineno (1); yycolumn = yycolumn_end = 1; + // init only for the first time in order to make csql_yylloc.buffer_pos identical to the file pos + yybuffer_pos=0; + return 0; } @@ -26372,7 +26616,6 @@ parse_one_statement (int state) parser_yyinput_single_mode = 1; - yybuffer_pos=0; is_dblink_query_string = 0; expecting_pl_lang_spec = 0; csql_yylloc.buffer_pos=0; @@ -26390,8 +26633,7 @@ parse_one_statement (int state) else parser_statement_OK = 1; - if (!parser_yyinput_single_mode) /* eof */ - return 1; + parser_yyinput_single_mode = 0; return 0; } @@ -28446,3 +28688,50 @@ pt_add_password_offset (int start, int end, bool is_add_comma, EN_ADD_PWD_STRING password_add_offset (&this_parser->hide_pwd_info, start, end, is_add_comma, en_add_pwd_string); } + +static int +pt_set_plcsql_body_impl(PT_NODE* node, PT_NODE* body, int start, int spec_start, int spec_end, int end) +{ + // In (at least) following two cases, the control reaches here. + // . csql -i --no-single-line ... + // . cubrid loaddb -s ... + + // In these cases, parser->original_buffer is null and + // node->sql_user_text must be got from this_parser->file. + // The arguments start, spec_start, spec_end, and end are got from the tokens' buffer_pos + // but they are also actual positions in the file in these two cases. + + int r, read_sz = end - start; // texts from pos start to pos (end - 1) + char* buff = (char*) parser_alloc(this_parser, read_sz + 1); + + int file_pos = ftell(this_parser->file); + + r = fseek(this_parser->file, start, SEEK_SET); + if (r != 0) { + return -1; + } + + r = (int) fread(buff, 1, read_sz, this_parser->file); + if (r != read_sz) { + return -1; + } + + r = fseek(this_parser->file, file_pos, SEEK_SET); // restore it to the original position + if (r != 0){ + return -1; + } + + if (strncasecmp("create", buff, 6) != 0) { + return -1; + } + + buff[read_sz] = '\0'; + char* impl = buff + (spec_start - start); + + node->sql_user_text = buff; + node->sql_user_text_len = read_sz; + + body->info.sp_body.impl = pt_create_string_literal_node_w_charset_coll(impl, (spec_end - spec_start)); + + return 0; +} diff --git a/src/parser/csql_lexer.l b/src/parser/csql_lexer.l index 350e7e3f35..55c0b4505d 100644 --- a/src/parser/csql_lexer.l +++ b/src/parser/csql_lexer.l @@ -38,8 +38,8 @@ #define CSQL_MAXNAME 256 -static int parser_yyinput_single_line (char *buff, int max_size); -static int parser_yyinput_multi_line (char *buff, int max_size); +int parser_yyinput_single_mode = 0; + static int parser_yyinput (char *buff, int max_size); static char *parser_c_hint (void); static char *parser_line_hint (void); @@ -94,6 +94,7 @@ int expecting_pl_lang_spec = 0; %x POST_DOT_OR_RIGHT_ARROW_STRING %x PL_LANG_SPEC %x PLCSQL_TEXT +%x POST_PLCSQL_TEXT /* id letter */ IDL [a-zA-Z0-9_] @@ -155,6 +156,7 @@ IDL [a-zA-Z0-9_] csql_yylval.cptr = pt_makename(yytext); return AUTO_INCREMENT; } [aA][vV][gG] { begin_token(yytext); return AVG; } +[aA][uU][tT][hH][iI][dD] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); return AUTHID; } [bB][eE][fF][oO][rR][eE] { begin_token(yytext); return BEFORE; } [bB][eE][gG][iI][nN] { begin_token(yytext); return BEGIN_; } [bB][eE][nN][cC][hH][mM][aA][rR][kK] { begin_token(yytext); @@ -183,6 +185,7 @@ IDL [a-zA-Z0-9_] csql_yylval.cptr = pt_makename(yytext); return BUFFER; } [cC][aA][lL][lL] { begin_token(yytext); return CALL; } +[cC][aA][lL][lL][eE][rR] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); return CALLER; } [cC][aA][cC][hH][eE] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); return CACHE; } @@ -230,7 +233,10 @@ IDL [a-zA-Z0-9_] [cC][oO][mM][mM][iI][tT] { begin_token(yytext); return COMMIT; } [cC][oO][mM][mM][iI][tT][tT][eE][dD] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); - return COMMITTED; } + return COMMITTED; } +[cC][oO][mM][pP][iI][lL][eE] { begin_token(yytext); + csql_yylval.cptr = pt_makename(yytext); + return COMPILE; } [cC][oO][nN][nN][eE][cC][tT] { begin_token(yytext); return CONNECT; } [cC][oO][nN][nN][eE][cC][tT][_][bB][yY][_][iI][sS][cC][yY][cC][lL][eE] { begin_token(yytext); return CONNECT_BY_ISCYCLE; } [cC][oO][nN][nN][eE][cC][tT][_][bB][yY][_][iI][sS][lL][eE][aA][fF] { begin_token(yytext); return CONNECT_BY_ISLEAF; } @@ -300,6 +306,7 @@ IDL [a-zA-Z0-9_] [dD][eE][fF][aA][uU][lL][tT] { begin_token(yytext); return DEFAULT; } [dD][eE][fF][eE][rR][rR][aA][bB][lL][eE] { begin_token(yytext); return DEFERRABLE; } [dD][eE][fF][eE][rR][rR][eE][dD] { begin_token(yytext); return DEFERRED; } +[dD][eE][fF][iI][nN][eE][rR] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); return DEFINER; } [dD][eE][lL][eE][tT][eE] { begin_token(yytext); return DELETE_; } [dD][eE][nN][sS][eE]_[rR][aA][nN][kK] { begin_token(yytext); csql_yylval.cptr = pt_makename(yytext); @@ -795,7 +802,9 @@ IDL [a-zA-Z0-9_] return RANGE_; } [rR][eE][aA][dD] { begin_token(yytext); return READ; } [rR][eE][aA][lL] { begin_token(yytext); return FLOAT_; } -[rR][eE][bB][uU][iI][lL][dD] { begin_token(yytext); return REBUILD; } +[rR][eE][bB][uU][iI][lL][dD] { begin_token(yytext); + csql_yylval.cptr = pt_makename(yytext); + return REBUILD; } [rR][eE][cC][uU][rR][sS][iI][vV][eE] { begin_token(yytext); return RECURSIVE; } [rR][eE][fF] { begin_token(yytext); return REF; } [rR][eE][fF][eE][rR][eE][nN][cC][eE][sS] { begin_token(yytext); return REFERENCES; } @@ -1086,6 +1095,19 @@ IDL [a-zA-Z0-9_] \\N { begin_token(yytext); return Null; } +";" { begin_token(yytext); + if (parser_yyinput_single_mode) { + // Pretend to be an EOF + // to make yyparse() return. + // (parse a single statement at a time) + // NOTE: at the next call to yylex(), + // the work starts at the last state of + // the lexer. + return 0; + } else { + return SEMICOLON; + } + } "->" { begin_token(yytext); return RIGHT_ARROW; } "." { begin_token(yytext); return DOT; } "->>" { begin_token(yytext); return DOUBLE_RIGHT_ARROW; } @@ -1667,9 +1689,9 @@ _[uU][tT][fF]8['] { plcsql_begin_end_balance++; csql_yylval.cptr = pt_makename(yytext); return PLCSQL_TEXT_SOME; } -[eE][nN][dD][ \t\r\n]+[iI][fF] | -[eE][nN][dD][ \t\r\n]+[cC][aA][sS][eE] | -[eE][nN][dD][ \t\r\n]+[lL][oO][oO][pP] | +[eE][nN][dD][ \t\r\n]+[iI][fF][ \t\r\n]* | +[eE][nN][dD][ \t\r\n]+[cC][aA][sS][eE][ \t\r\n]* | +[eE][nN][dD][ \t\r\n]+[lL][oO][oO][pP][ \t\r\n]* | [eE][nN][dD][ \t\r\n]* { begin_token(yytext); plcsql_begin_end_balance--; if (plcsql_begin_end_balance < 0) { @@ -1680,7 +1702,7 @@ _[uU][tT][fF]8['] { if (plcsql_begin_end_balance == 0) { plcsql_nest_level--; if (plcsql_nest_level < 0) { - BEGIN(INITIAL); + BEGIN(POST_PLCSQL_TEXT); } } csql_yylval.cptr = pt_makename(yytext); @@ -1709,10 +1731,25 @@ _[uU][tT][fF]8['] { csql_yylval.cptr = pt_makename(yytext); return PLCSQL_TEXT_SOME; } + /* mode POST_PLCSQL_TEXT */ -%% +[cC][oO][mM][mM][eE][nN][tT] { BEGIN(INITIAL); + yybuffer_pos -= csql_yyleng; + yyless(0); } -int parser_yyinput_single_mode = 0; +{IDL}+ { BEGIN(INITIAL); + begin_token(yytext); + csql_yylval.cptr = pt_makename(yytext); + return PLCSQL_TEXT_SOME; } + +(.) { BEGIN(INITIAL); + yybuffer_pos -= csql_yyleng; + yyless(0); } + +<> { BEGIN(INITIAL); + return 0; } + +%% void csql_yyerror_explicit (int line, int column) @@ -1964,9 +2001,9 @@ yywrap () static void init_plcsql_lexing() { - plcsql_begin_end_balance = 0; - plcsql_nest_level = 0; - from_plcsql_text = 0; + plcsql_begin_end_balance = 0; + plcsql_nest_level = 0; + from_plcsql_text = 0; } static int @@ -2030,24 +2067,25 @@ parser_yyinput_single_line (char *buff, int max_size) while (c != -1); } + buff[i++] = c; + if (c == ';') { - buff[i++] = -1; - buff[i] = 0; + buff[i] = '\0'; /* not required but to ease debugging */ + /* stop filling the buffer. see PR 5403 */ return i; } - buff[i++] = c; if (i >= max_size) { + buff[i] = '\0'; /* not required but to ease debugging */ return i; } } while (c != -1); - buff[i] = 0; - parser_yyinput_single_mode = 0; /* all done */ + buff[i] = '\0'; /* not required but to ease debugging */ /* end of file */ str_identifier = '\0'; diff --git a/src/parser/keyword.c b/src/parser/keyword.c index 8771d4a421..9ec4b880df 100644 --- a/src/parser/keyword.c +++ b/src/parser/keyword.c @@ -63,6 +63,7 @@ static KEYWORD_RECORD keywords[] = { {AT, "AT", 0}, {ATTACH, "ATTACH", 0}, {ATTRIBUTE, "ATTRIBUTE", 0}, + {AUTHID, "AUTHID", 1}, {AUTO_INCREMENT, "AUTO_INCREMENT", 1}, {AVG, "AVG", 0}, {BEFORE, "BEFORE", 0}, @@ -82,6 +83,7 @@ static KEYWORD_RECORD keywords[] = { {BY, "BY", 0}, {BUFFER, "BUFFER", 1}, {CALL, "CALL", 0}, + {CALLER, "CALLER", 1}, {CACHE, "CACHE", 1}, {CAPACITY, "CAPACITY", 1}, {CASCADE, "CASCADE", 0}, @@ -145,6 +147,7 @@ static KEYWORD_RECORD keywords[] = { {DAY_SECOND, "DAY_SECOND", 0}, {DBLINK, "DBLINK", 0}, {DEALLOCATE, "DEALLOCATE", 0}, + {DEFINER, "DEFINER", 1}, {NUMERIC, "DEC", 0}, {NUMERIC, "DECIMAL", 0}, {DECLARE, "DECLARE", 0}, diff --git a/src/parser/method_transform.c b/src/parser/method_transform.c index 8d40ea3e95..ee7b7f4bf7 100644 --- a/src/parser/method_transform.c +++ b/src/parser/method_transform.c @@ -184,7 +184,7 @@ meth_have_methods (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *cont int *have_method = (int *) arg; *continue_walk = PT_CONTINUE_WALK; - if (node->node_type == PT_METHOD_CALL) + if (PT_IS_METHOD (node)) { *have_method = 1; *continue_walk = PT_STOP_WALK; @@ -465,14 +465,14 @@ meth_create_method_list (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg *continue_walk = PT_LIST_WALK; } - if (node->node_type == PT_DOT_ && (arg1 = node->info.dot.arg1) && arg1->node_type == PT_METHOD_CALL + if (node->node_type == PT_DOT_ && (arg1 = node->info.dot.arg1) && PT_IS_METHOD (arg1) && arg1->info.method_call.call_or_expr == PT_PARAMETER && node->info.dot.arg2) { /* this is a path expression rooted in a constant method call. We need to tag it as such for xasl generation */ node->info.dot.arg2->info.name.meta_class = PT_PARAMETER; } - if ((node->node_type != PT_METHOD_CALL) || (node->info.method_call.method_name->info.name.spec_id == 0)) + if (!PT_IS_METHOD (node) || (node->info.method_call.method_name->info.name.spec_id == 0)) { return node; } @@ -1083,7 +1083,7 @@ meth_get_method_params (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE * meth for (method = method_list; method != NULL; method = method->next) { - if (method->node_type != PT_METHOD_CALL) + if (!PT_IS_METHOD (method)) { PT_INTERNAL_ERROR (parser, "translate"); return NULL; @@ -1199,7 +1199,7 @@ meth_replace_method_params (PARSER_CONTEXT * parser, UINTPTR spec_id, PT_NODE * attr_list = as_attr_list; for (method = method_list; method != NULL; method = method->next) { - if (method->node_type != PT_METHOD_CALL) + if (!PT_IS_METHOD (method)) { PT_INTERNAL_ERROR (parser, "translate"); return; @@ -1285,7 +1285,7 @@ meth_replace_method_calls (PARSER_CONTEXT * parser, PT_NODE * root, PT_NODE * me attr_list = as_attr_list; for (method = method_list; method != NULL; method = method->next) { - if (method->node_type != PT_METHOD_CALL) + if (!PT_IS_METHOD (method)) { PT_INTERNAL_ERROR (parser, "translate"); return; @@ -1314,7 +1314,7 @@ meth_replace_call (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int PT_NODE *new_node; METH_INFO1 info; - if (node->node_type != PT_METHOD_CALL) + if (!PT_IS_METHOD (node)) { return node; } @@ -1421,8 +1421,7 @@ meth_find_last_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, } /* don't walk into the method you're checking with */ - if (node->node_type == PT_METHOD_CALL - && (node->info.method_call.method_id == info->method->info.method_call.method_id)) + if (PT_IS_METHOD (node) && (node->info.method_call.method_id == info->method->info.method_call.method_id)) { *continue_walk = PT_LIST_WALK; } @@ -1501,7 +1500,7 @@ meth_match_entity (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int /* check to see if we want to dive into nested method calls. don't dive into data type nodes */ - if ((!info7->check_method_calls && (node->node_type == PT_METHOD_CALL)) || (node->node_type == PT_DATA_TYPE)) + if (!info7->check_method_calls && (PT_IS_METHOD (node) || (node->node_type == PT_DATA_TYPE))) { *continue_walk = PT_LIST_WALK; return node; @@ -1817,7 +1816,7 @@ meth_is_method (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *co *continue_walk = PT_CONTINUE_WALK; - if (node->node_type == PT_METHOD_CALL && node->info.method_call.call_or_expr != PT_PARAMETER) + if (PT_IS_METHOD (node) && node->info.method_call.call_or_expr != PT_PARAMETER) { *is_a_method = 1; } @@ -1931,7 +1930,7 @@ meth_find_method (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int * *continue_walk = PT_CONTINUE_WALK; - if (node->node_type == PT_METHOD_CALL && (info->id == 0 || node->info.method_call.method_id == info->id)) + if (PT_IS_METHOD (node) && (info->id == 0 || node->info.method_call.method_id == info->id)) { info->found = 1; } @@ -2279,7 +2278,7 @@ meth_replace_id_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void * { METH_INFO6 *info6 = (METH_INFO6 *) void_arg; - if (node->node_type == PT_METHOD_CALL && (node->info.method_call.method_name->info.name.spec_id == info6->old_id)) + if (PT_IS_METHOD (node) && (node->info.method_call.method_name->info.name.spec_id == info6->old_id)) { node->info.method_call.method_name->info.name.spec_id = info6->new_id; } @@ -2362,7 +2361,7 @@ meth_find_hierarchical_in_method_list (PARSER_CONTEXT * parser, PT_NODE * method for (node = method_list; node != NULL && !(*has_hierarchical_expr); node = node->next) { - if (node->node_type == PT_METHOD_CALL) + if (PT_IS_METHOD (node)) { for (arg = node->info.method_call.arg_list; arg != NULL && !(*has_hierarchical_expr); arg = arg->next) { diff --git a/src/parser/name_resolution.c b/src/parser/name_resolution.c index 5eca711393..6944d1eda6 100644 --- a/src/parser/name_resolution.c +++ b/src/parser/name_resolution.c @@ -530,6 +530,10 @@ pt_resolved (const PT_NODE * expr) return (expr->info.name.spec_id != 0); case PT_DOT_: return (pt_resolved (expr->info.dot.arg1) && pt_resolved (expr->info.dot.arg2)); + case PT_FUNCTION: + // Resolved as a function node. + // If it's actually a user-defined function, this node will be resolved in the next phase (function resolution). + return (expr->info.function.function_type == PT_GENERIC); default: break; } @@ -941,8 +945,9 @@ pt_bind_name_or_path_in_scope (PARSER_CONTEXT * parser, PT_BIND_NAMES_ARG * bind /* If pt_name in group by/ having, maybe it's alias. We will try to resolve it later. */ if (!is_pt_name_in_group_having (in_node)) { - - if (parser->flag.is_parsing_static_sql == 1) + if (parser->flag.is_parsing_static_sql == 1 + && ((in_node->node_type == PT_DOT_ && !pt_resolved (in_node->info.dot.arg2)) + || in_node->node_type == PT_NAME)) { // clear unknown attribute error, the unknown symbol will be converted (paramterized) to host variable pt_reset_error (parser); @@ -1980,6 +1985,8 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue short i, k, lhs_location, rhs_location, level; PT_JOIN_TYPE join_type; void *save_etc = NULL; + PT_NODE *method_name_node = NULL; + const char *method_name; *continue_walk = PT_CONTINUE_WALK; @@ -3288,13 +3295,16 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue * first parameter to the on_call_target. If there is no parameter, * it will be caught in pt_semantic_check_local() */ - if (!node->info.method_call.on_call_target - && jsp_is_exist_stored_procedure (node->info.method_call.method_name->info.name.original)) - { - PT_NODE *method_name = node->info.method_call.method_name; - node->info.method_call.method_name->info.name.spec_id = (UINTPTR) method_name; - node->info.method_call.method_type = (PT_MISC_TYPE) jsp_get_sp_type (method_name->info.name.original); - node->info.method_call.method_name->info.name.meta_class = PT_METHOD; + method_name_node = node->info.method_call.method_name; + // parser_print_tree is for built-in package names such as DBMS_OUTPUT + method_name = PT_NAME_RESOLVED (method_name_node) ? parser_print_tree (parser, + method_name_node) : + PT_NAME_ORIGINAL (method_name_node); + if (!node->info.method_call.on_call_target && jsp_is_exist_stored_procedure (method_name)) + { + method_name_node->info.name.spec_id = (UINTPTR) method_name_node; + node->info.method_call.method_type = (PT_MISC_TYPE) jsp_get_sp_type (method_name); + method_name_node->info.name.meta_class = PT_METHOD; parser_walk_leaves (parser, node, pt_bind_names, bind_arg, pt_bind_names_post, bind_arg); /* don't revisit leaves */ *continue_walk = PT_LIST_WALK; @@ -3306,6 +3316,19 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue node->info.method_call.on_call_target = node->info.method_call.arg_list; node->info.method_call.arg_list = node->info.method_call.arg_list->next; node->info.method_call.on_call_target->next = NULL; + + /* + * When using a session variable in the first arg_list, + * It is unknown whether the session variable contains a class, object, or constant value. + * So, if it's not a Java stored procedure and there is an on_call_target, then it's considered a method and [user_schema] is removed. + * + * ex) create class x (xint int, xstr string, class cint int) method add_int(int, int) int function add_int file '$METHOD_FILE'; + * insert into x values (4, 'string 4'); + * select x into p1 from x where xint = 4; + * call add_int(p1, 1, 2); + */ + node->info.method_call.method_name->info.name.original = + sm_remove_qualifier_name (node->info.method_call.method_name->info.name.original); } /* make method name look resolved */ @@ -3347,9 +3370,7 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue node->info.method_call.method_name->info.name.spec_id = entity->info.spec.id; } } - } - break; case PT_DATA_TYPE: @@ -3406,6 +3427,44 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue { node = temp; } + else if (PT_CHECK_USER_SCHEMA_PROCEDURE_OR_FUNCTION (node)) + { + /* + * when (dot.arg1->node_type == PT_NAME) && (dot.arg2->node_type == PT_FUNCTION), + * pt_bind_name_or_path_in_scope() always returns NULL and sets the value PT_ERRORmf(.. MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_IS_NOT_DEFINED ..). + */ + pt_reset_error (parser); + + /* + * jsp_is_exist_stored_procedure() could not be checked in pt_set_user_specified_name(), so it was checked in pt_bind_names(). + * Created a temporary node in name.original to join user_schema(dot.arg1) and sp_name(dot.arg2). + */ + char downcase_owner_name[DB_MAX_USER_LENGTH]; + downcase_owner_name[0] = '\0'; + char *generic_name = NULL; + + sm_downcase_name (node->info.dot.arg1->info.name.original, downcase_owner_name, DB_MAX_USER_LENGTH); + generic_name = pt_append_string (parser, downcase_owner_name, "."); + generic_name = pt_append_string (parser, generic_name, node->info.dot.arg2->info.function.generic_name); + node->info.dot.arg2->info.function.generic_name = generic_name; + node->info.dot.arg1->info.name.original = generic_name; + + if (jsp_is_exist_stored_procedure (node->info.dot.arg2->info.function.generic_name)) + { + node1 = pt_resolve_stored_procedure (parser, node->info.dot.arg2, bind_arg); + if (node1 == NULL) + { + break; // FIXME: something wrong + } + PT_NODE_COPY_NUMBER_OUTERLINK (node1, node); + + PT_NODE_INIT_OUTERLINK (node); + parser_free_tree (parser, node); + node = node1; /* return the new node */ + /* don't revisit leaves */ + *continue_walk = PT_LIST_WALK; + } + } else if (pt_has_error (parser)) { return NULL; @@ -3440,18 +3499,38 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue case PT_FUNCTION: if (node->info.function.function_type == PT_GENERIC) { - const char *generic_name = node->info.function.generic_name; + MOP sp_mop = NULL; + char sp_unique_name[SM_MAX_IDENTIFIER_LENGTH + 1]; node->info.function.function_type = pt_find_function_type (node->info.function.generic_name); if (node->info.function.function_type == PT_GENERIC) { + if (strchr (node->info.function.generic_name, '.')) + { + /* + * when checking for a PROCEDURE in a PT_DOT_ type, if the PROCEDURE does not exist, the check moves on to the PT_FUNCTION. + * along the way, it will go through the pt_bind_name_or_path_in_scope() function of PT_NAME, + * which will always return NULL and set the value of + * PT_ERRORmf(.. MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_IS_NOT_DEFINED ..). + */ + pt_reset_error (parser); + } + /* * It may be a method call since they are parsed as * nodes PT_FUNCTION. If so, pt_make_stored_procedure() and pt_make_method_call() will * translate it into a method_call. */ - if (jsp_is_exist_stored_procedure (generic_name)) + sp_mop = jsp_find_stored_procedure (node->info.function.generic_name, DB_AUTH_NONE); + if (sp_mop != NULL) { + sp_unique_name[0] = '\0'; + jsp_get_unique_name (sp_mop, sp_unique_name, DB_MAX_IDENTIFIER_LENGTH + 1); + if (sp_unique_name[0] != '\0') + { + node->info.function.generic_name = pt_append_string (parser, NULL, sp_unique_name); + } + node1 = pt_resolve_stored_procedure (parser, node, bind_arg); } else @@ -3505,17 +3584,24 @@ pt_bind_names (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue PT_ERRORm (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_PREFIX_IN_FUNC_INDX_NOT_ALLOWED); } - else if (parser_function_code != PT_EMPTY) - { - PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, - MSGCAT_SEMANTIC_INVALID_INTERNAL_FUNCTION, node->info.function.generic_name); - } else { - PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_UNKNOWN_FUNCTION, - node->info.function.generic_name); - } + char downcase_generic_name[DB_MAX_IDENTIFIER_LENGTH]; + downcase_generic_name[0] = '\0'; + sm_downcase_name (node->info.function.generic_name, downcase_generic_name, + DB_MAX_IDENTIFIER_LENGTH); + if (parser_function_code != PT_EMPTY) + { + PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, + MSGCAT_SEMANTIC_INVALID_INTERNAL_FUNCTION, downcase_generic_name); + } + else + { + PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_UNKNOWN_FUNCTION, + downcase_generic_name); + } + } } } } @@ -10163,6 +10249,8 @@ pt_make_method_call (PARSER_CONTEXT * parser, PT_NODE * f_node, PT_BIND_NAMES_AR new_node->info.method_call.arg_list = parser_copy_tree_list (parser, f_node->info.function.arg_list); new_node->info.method_call.call_or_expr = PT_IS_MTHD_EXPR; new_node->info.method_call.on_call_target = NULL; + new_node->info.method_call.auth_name = NULL; + PT_METHOD_CALL_AUTH_NAME (new_node) = ws_copy_string (au_get_user_name (Au_user)); // default return new_node; } /* pt_make_method_call */ @@ -10257,6 +10345,10 @@ pt_resolve_method (PARSER_CONTEXT * parser, PT_NODE * node, PT_BIND_NAMES_ARG * static PT_NODE * pt_resolve_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * node, PT_BIND_NAMES_ARG * bind_arg) { + char owner[DB_MAX_USER_LENGTH + 1]; + owner[0] = '\0'; + char *current_user_owner; + PT_NODE *new_node = pt_make_method_call (parser, node, bind_arg); if (new_node == NULL) { @@ -10274,6 +10366,12 @@ pt_resolve_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * node, PT_BIND_NA return NULL; } + if (jsp_get_owner_name (sp_name, owner, DB_MAX_USER_LENGTH) == NULL) + { + PT_INTERNAL_ERROR (parser, "jsp_get_owner_name"); + return NULL; + } + new_node->type_enum = pt_db_to_type_enum ((DB_TYPE) return_type); TP_DOMAIN *d = pt_type_enum_to_db_domain (new_node->type_enum); d = tp_domain_cache (d); @@ -10284,6 +10382,18 @@ pt_resolve_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * node, PT_BIND_NA int sp_type_misc = jsp_get_sp_type (sp_name); new_node->info.method_call.method_type = (PT_MISC_TYPE) sp_type_misc; + PT_METHOD_CALL_AUTH_ID (new_node) = PT_AUTHID_OWNER; // TODO + if (PT_METHOD_CALL_AUTH_ID (new_node) == PT_AUTHID_OWNER) + { + PT_METHOD_CALL_AUTH_NAME (new_node) = pt_append_string (parser, NULL, owner); + } + else + { + current_user_owner = au_get_user_name (Au_user); + PT_METHOD_CALL_AUTH_NAME (new_node) = pt_append_string (parser, NULL, current_user_owner); + ws_free_string_and_init (current_user_owner); + } + return new_node; } /* pt_resolve_stored_procedure */ diff --git a/src/parser/parse_dbi.c b/src/parser/parse_dbi.c index dba3874b8a..36a1c5802a 100644 --- a/src/parser/parse_dbi.c +++ b/src/parser/parse_dbi.c @@ -2577,6 +2577,10 @@ pt_auth_to_db_auth (const PT_NODE * auth) db_auth = DB_AUTH_UPDATE; break; + case PT_EXECUTE_PROCEDURE_PRIV: + db_auth = DB_AUTH_EXECUTE; + break; + default: db_auth = DB_AUTH_NONE; break; diff --git a/src/parser/parse_evaluate.c b/src/parser/parse_evaluate.c index 4488b5efe7..de661ee47b 100644 --- a/src/parser/parse_evaluate.c +++ b/src/parser/parse_evaluate.c @@ -1369,6 +1369,14 @@ pt_evaluate_tree_internal (PARSER_CONTEXT * parser, PT_NODE * tree, DB_VALUE * d break; case PT_METHOD_CALL: + + if (!PT_IS_METHOD (tree) + && !(tree->info.method_call.call_or_expr == PT_IS_CALL_STMT) && do_Trigger_involved == false) + { + // do not perform constant folding + break; + } + if (qo_need_skip_execution ()) { // It is for the get_query_info. diff --git a/src/parser/parse_tree.c b/src/parser/parse_tree.c index b9f4ec2641..190c738697 100644 --- a/src/parser/parse_tree.c +++ b/src/parser/parse_tree.c @@ -1232,6 +1232,7 @@ parser_create_parser (void) parser->max_print_len = 0; parser->flag.is_auto_commit = 0; parser->flag.is_parsing_static_sql = 0; + parser->flag.is_parsing_unload_schema = 0; parser->external_into_label = NULL; parser->external_into_label_cnt = 0; diff --git a/src/parser/parse_tree.h b/src/parser/parse_tree.h index 57e22cc789..bdc1e739ce 100644 --- a/src/parser/parse_tree.h +++ b/src/parser/parse_tree.h @@ -114,6 +114,11 @@ struct json_t; #define PT_INTERNAL_ERROR(parser, what) \ pt_internal_error((parser), __FILE__, __LINE__, (what)) +// macros for PARSER_CONTEXT +#define PT_IS_FOR_PL_COMPILE(parser) \ + ((parser)->flag.is_parsing_static_sql == 1) + +// macros for PT_NODE */ #define PT_IS_QUERY_NODE_TYPE(x) \ ( (x) == PT_SELECT || (x) == PT_UNION \ || (x) == PT_DIFFERENCE || (x) == PT_INTERSECTION) @@ -262,6 +267,7 @@ struct json_t; #define pt_is_dot_node(n) PT_IS_DOT_NODE(n) #define pt_is_expr_node(n) PT_IS_EXPR_NODE(n) #define pt_is_function(n) PT_IS_FUNCTION(n) +#define pt_is_sp(n) PT_IS_SP(n) #define pt_is_multi_col_term(n) PT_IS_MULTI_COL_TERM(n) #define pt_is_name_node(n) PT_IS_NAME_NODE(n) #define pt_is_oid_name(n) PT_IS_OID_NAME(n) @@ -540,6 +546,12 @@ struct json_t; || (n->node_type == PT_UPDATE && n->info.update.spec->info.spec.remote_server_name) \ || (n->node_type == PT_MERGE && n->info.merge.into->info.spec.remote_server_name)) +#define PT_CHECK_USER_SCHEMA_PROCEDURE_OR_FUNCTION(n) \ + ((n->info.dot.arg1->node_type == PT_NAME) \ + && (n->info.dot.arg2->node_type == PT_FUNCTION) \ + && (n->info.dot.arg2->info.function.function_type == PT_GENERIC) \ + && (strchr (n->info.dot.arg2->info.function.generic_name, '.') == NULL)) + #if !defined (SERVER_MODE) /* the following defines support host variable binding for internal statements. internal statements can be generated on TEXT handling, and these statements @@ -751,7 +763,7 @@ struct json_t; ( (n) && (n)->node_type == PT_METHOD_CALL && \ (n)->info.method_call.method_type == PT_IS_INST_MTHD ) -#define PT_IS_JAVA_SP(n) \ +#define PT_IS_SP(n) \ ( (n) && (n)->node_type == PT_METHOD_CALL && \ ( (n)->info.method_call.method_type == PT_SP_PROCEDURE || \ (n)->info.method_call.method_type == PT_SP_FUNCTION) ) @@ -778,6 +790,7 @@ struct json_t; #define PT_NAME_ORIGINAL(n) (PT_NAME_ASSERT ((n)), (n)->info.name.original) #define PT_NAME_RESOLVED(n) (PT_NAME_ASSERT ((n)), (n)->info.name.resolved) #define PT_NAME_DB_OBJECT(n) (PT_NAME_ASSERT ((n)), (n)->info.name.db_object) +#define PT_NAME_ORIGINAL(n) (PT_NAME_ASSERT ((n)), (n)->info.name.original) /* PT_CREATE_ENTITY */ #define PT_CREATE_ENTITY_ASSERT(n) (PT_ASSERT_NODE_TYPE ((n), PT_CREATE_ENTITY)) @@ -820,6 +833,12 @@ struct json_t; #define PT_SYNONYM_IF_EXISTS(n) ((n)->info.synonym.if_exists) #define PT_SYNONYM_IS_DBLINKED(n) ((n)->info.synonym.is_dblinked) /* for user.table@server */ +/* PT_METHOD_CALL_INFO */ +#define PT_METHOD_CALL_NAME(n) ((n)->info.method_call.method_name) +#define PT_METHOD_ARG_LIST(n) ((n)->info.method_call.arg_list) +#define PT_METHOD_CALL_AUTH_ID(n) ((n)->info.method_call.auth_id) +#define PT_METHOD_CALL_AUTH_NAME(n) ((n)->info.method_call.auth_name) + /* Check node_type of PT_NODE */ #define PT_NODE_IS_EXPR(n) (PT_ASSERT_NOT_NULL ((n)), (n)->node_type == PT_EXPR) #define PT_NODE_IS_NAME(n) (PT_ASSERT_NOT_NULL ((n)), (n)->node_type == PT_NAME) @@ -1157,7 +1176,8 @@ typedef enum PT_INSERT_PRIV, PT_REFERENCES_PRIV, /* for ANSI compatibility */ PT_SELECT_PRIV, - PT_UPDATE_PRIV + PT_UPDATE_PRIV, + PT_EXECUTE_PROCEDURE_PRIV } PT_PRIV_TYPE; /* Enumerated Misc Types */ @@ -1327,7 +1347,10 @@ typedef enum PT_PRIVATE, PT_PUBLIC, - PT_SYNONYM + PT_SYNONYM, + + PT_AUTHID_OWNER, + PT_AUTHID_CALLER // todo: separate into relevant enumerations } PT_MISC_TYPE; @@ -2511,7 +2534,7 @@ struct pt_grant_info { PT_NODE *auth_cmd_list; /* PT_AUTH_CMD(list) */ PT_NODE *user_list; /* PT_NAME */ - PT_NODE *spec_list; /* PT_SPEC */ + PT_NODE *spec_list; /* PT_SPEC (class) or PT_NAME (procedure) */ PT_MISC_TYPE grant_option; /* = PT_GRANT_OPTION or PT_NO_GRANT_OPTION */ }; @@ -2576,6 +2599,8 @@ struct pt_method_call_info PT_NODE *to_return_var; /* PT_NAME */ PT_MISC_TYPE call_or_expr; /* PT_IS_CALL_STMT or PT_IS_MTHD_EXPR */ PT_MISC_TYPE method_type; /* PT_IS_CLASS_MTHD, PT_IS_INST_MTHD, PT_SP_PROCEDURE, PT_SP_FUNCTION */ + char *auth_name; /* owner or current user name */ + PT_MISC_TYPE auth_id; /* PT_AUTHID_OWNER, PT_AUTHID_CALLER */ UINTPTR method_id; /* unique identifier so when copying we know if two methods are copies of the same * original method call. */ }; @@ -3376,11 +3401,12 @@ struct pt_stored_proc_info PT_NODE *body; PT_NODE *comment; PT_NODE *owner; /* for ALTER PROCEDURE/FUNCTION name OWNER TO new_owner */ + PT_MISC_TYPE auth_id; /* PT_AUTHID_OWNER, PT_AUTHID_CALLER */ PT_MISC_TYPE type; unsigned or_replace:1; /* OR REPLACE clause */ PT_TYPE_ENUM ret_type; PT_NODE *ret_data_type; - + int recompile; }; struct pt_prepare_info @@ -3406,8 +3432,9 @@ struct pt_execute_info struct pt_stored_proc_param_info { - PT_NODE *name; - PT_MISC_TYPE mode; + PT_NODE *name; /* PT_NAME */ + PT_MISC_TYPE mode; /* PT_INPUT, PT_OUTPUT, PT_INPUTOUTPUT */ + PT_NODE *default_value; /* PT_DATA_DEFAULT */ PT_NODE *comment; }; @@ -3992,6 +4019,7 @@ struct parser_context unsigned is_system_generated_stmt:1; unsigned is_auto_commit:1; /* set to true, if auto commit. */ unsigned is_parsing_static_sql:1; /* For PL/CSQL's static SQL: parameterize PL/CSQL variable symbols (to host variable) */ + unsigned is_parsing_unload_schema:1; /* Parsing in unload: used to parse the scode (original query) of PL/CSQL to remove the owner. */ } flag; }; diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index 412d43d2c7..38bf91c5fd 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -4043,6 +4043,8 @@ pt_show_priv (PT_PRIV_TYPE t) return "drop"; case PT_EXECUTE_PRIV: return "execute"; + case PT_EXECUTE_PROCEDURE_PRIV: + return "execute on procedure"; case PT_INDEX_PRIV: return "index"; case PT_INSERT_PRIV: @@ -7564,6 +7566,7 @@ pt_print_create_trigger (PARSER_CONTEXT * parser, PT_NODE * p) static PT_NODE * pt_apply_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) { + PT_APPLY_WALK (parser, p->info.sp.name, arg); PT_APPLY_WALK (parser, p->info.sp.param_list, arg); PT_APPLY_WALK (parser, p->info.sp.ret_data_type, arg); return p; @@ -7580,6 +7583,7 @@ pt_apply_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p, void *ar static PT_NODE * pt_apply_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) { + PT_APPLY_WALK (parser, p->info.sp.name, arg); return p; } @@ -7595,14 +7599,26 @@ pt_print_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p) PARSER_VARCHAR *q = NULL, *r1, *r2, *r3; r1 = pt_print_bytes (parser, p->info.sp.name); - q = pt_append_nulstring (parser, q, "create "); - if (p->info.sp.or_replace) + + q = pt_append_nulstring (parser, q, parser->flag.is_parsing_unload_schema ? "CREATE OR REPLACE " : "create "); + if (p->info.sp.or_replace && !parser->flag.is_parsing_unload_schema) { q = pt_append_nulstring (parser, q, "or replace "); } - q = pt_append_nulstring (parser, q, pt_show_misc_type (p->info.sp.type)); + q = + pt_append_nulstring (parser, q, + parser->flag.is_parsing_unload_schema ? strcmp (pt_show_misc_type (p->info.sp.type), + "procedure") == + 0 ? "PROCEDURE" : "FUNCTION" : pt_show_misc_type (p->info.sp.type)); q = pt_append_nulstring (parser, q, " "); - q = pt_append_varchar (parser, q, r1); + if (parser->custom_print & (PT_PRINT_NO_SPECIFIED_USER_NAME | PT_PRINT_NO_CURRENT_USER_NAME)) + { + q = pt_append_name (parser, q, p->info.sp.name->info.name.original); + } + else + { + q = pt_append_varchar (parser, q, r1); + } r2 = pt_print_bytes_l (parser, p->info.sp.param_list); q = pt_append_nulstring (parser, q, "("); @@ -7611,7 +7627,7 @@ pt_print_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p) if (p->info.sp.type == PT_SP_FUNCTION) { - q = pt_append_nulstring (parser, q, " return "); + q = pt_append_nulstring (parser, q, parser->flag.is_parsing_unload_schema ? " RETURN " : " return "); if (p->info.sp.ret_data_type) { q = pt_append_varchar (parser, q, pt_print_bytes (parser, p->info.sp.ret_data_type)); @@ -7622,10 +7638,22 @@ pt_print_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p) } } + if (parser->flag.is_parsing_unload_schema) + { + if (p->info.sp.auth_id == PT_AUTHID_OWNER) + { + q = pt_append_nulstring (parser, q, " AUTHID OWNER"); + } + else + { + q = pt_append_nulstring (parser, q, " AUTHID CALLER"); + } + } + r3 = pt_print_bytes (parser, p->info.sp.body); q = pt_append_varchar (parser, q, r3); - if (p->info.sp.comment != NULL) + if (p->info.sp.comment != NULL && !parser->flag.is_parsing_unload_schema) { r1 = pt_print_bytes (parser, p->info.sp.comment); q = pt_append_nulstring (parser, q, " comment "); @@ -7879,7 +7907,10 @@ pt_print_sp_parameter (PARSER_CONTEXT * parser, PT_NODE * p) r1 = pt_print_bytes (parser, p->info.sp_param.name); q = pt_append_varchar (parser, q, r1); q = pt_append_nulstring (parser, q, " "); - q = pt_append_nulstring (parser, q, pt_show_misc_type (p->info.sp_param.mode)); + q = pt_append_nulstring (parser, q, parser->flag.is_parsing_unload_schema ? + (p->info.sp_param.mode == PT_INPUT || p->info.sp_param.mode == PT_NOPUT) ? + "IN" : p->info.sp_param.mode == PT_OUTPUT ? + "OUT" : "INOUT" : pt_show_misc_type (p->info.sp_param.mode)); q = pt_append_nulstring (parser, q, " "); if (p->data_type) { @@ -7890,6 +7921,12 @@ pt_print_sp_parameter (PARSER_CONTEXT * parser, PT_NODE * p) q = pt_append_nulstring (parser, q, pt_show_type_enum (p->type_enum)); } + if (p->info.sp_param.default_value != NULL) + { + r1 = pt_print_bytes (parser, p->info.sp_param.default_value); + q = pt_append_varchar (parser, q, r1); + } + if (p->info.sp_param.comment != NULL) { r1 = pt_print_bytes (parser, p->info.sp_param.comment); @@ -7924,8 +7961,7 @@ static PARSER_VARCHAR * pt_print_sp_body (PARSER_CONTEXT * parser, PT_NODE * p) { PARSER_VARCHAR *q = NULL, *r1 = NULL; - - q = pt_append_nulstring (parser, q, " as "); + q = pt_append_nulstring (parser, q, parser->flag.is_parsing_unload_schema ? " AS\n" : " as "); if (p->info.sp_body.lang == SP_LANG_PLCSQL) { // TODO: PL/CSQL compiler should permit it. @@ -7963,8 +7999,13 @@ pt_print_sp_body (PARSER_CONTEXT * parser, PT_NODE * p) } */ } + q = pt_append_varchar (parser, q, r1); - q = pt_append_nulstring (parser, q, ";"); + + if (!parser->flag.is_parsing_unload_schema) + { + q = pt_append_nulstring (parser, q, ";"); + } return q; } @@ -8333,6 +8374,11 @@ pt_print_alter_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * p) q = pt_append_varchar (parser, q, r1); } + if (sp_info->recompile == 1) + { + q = pt_append_nulstring (parser, q, " recompile "); + } + if (sp_info->comment != NULL) { r1 = pt_print_bytes (parser, sp_info->comment); @@ -8553,11 +8599,34 @@ pt_print_datatype (PARSER_CONTEXT * parser, PT_NODE * p) } break; case PT_TYPE_NCHAR: + if (parser->flag.is_parsing_unload_schema) + { + q = pt_append_nulstring (parser, q, "national character"); + break; + } case PT_TYPE_VARNCHAR: + if (parser->flag.is_parsing_unload_schema) + { + q = pt_append_nulstring (parser, q, "national character varying"); + break; + } case PT_TYPE_CHAR: + if (parser->flag.is_parsing_unload_schema) + { + q = pt_append_nulstring (parser, q, "character"); + break; + } case PT_TYPE_VARCHAR: - show_collation = true; - /* FALLTHRU */ + if (!parser->flag.is_parsing_unload_schema) + { + show_collation = true; + /* FALLTHRU */ + } + else + { + q = pt_append_nulstring (parser, q, "character varying"); + break; + } case PT_TYPE_BIT: case PT_TYPE_VARBIT: case PT_TYPE_FLOAT: @@ -13336,7 +13405,10 @@ pt_print_isolation_lvl (PARSER_CONTEXT * parser, PT_NODE * p) static PT_NODE * pt_apply_method_call (PARSER_CONTEXT * parser, PT_NODE * p, void *arg) { - PT_APPLY_WALK (parser, p->info.method_call.method_name, arg); + if (PT_IS_METHOD (p)) + { + PT_APPLY_WALK (parser, p->info.method_call.method_name, arg); + } PT_APPLY_WALK (parser, p->info.method_call.arg_list, arg); PT_APPLY_WALK (parser, p->info.method_call.on_call_target, arg); PT_APPLY_WALK (parser, p->info.method_call.to_return_var, arg); @@ -18901,7 +18973,8 @@ pt_json_table_column_behavior_to_string (const json_table_column_behavior_type & // column_behavior (in) : column behavior // static PARSER_VARCHAR * -pt_print_json_table_column_error_or_empty_behavior (PARSER_CONTEXT * parser, PARSER_VARCHAR * pstr, +pt_print_json_table_column_error_or_empty_behavior (PARSER_CONTEXT * parser, + PARSER_VARCHAR * pstr, const struct json_table_column_behavior &column_behavior) { PARSER_VARCHAR *substr = NULL; diff --git a/src/parser/parser.h b/src/parser/parser.h index 62f68890ec..446024d7bf 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -178,7 +178,10 @@ extern "C" extern PT_NODE *pt_get_node_from_list (PT_NODE * list, int index); extern PT_NODE *pt_get_select_list (PARSER_CONTEXT * parser, PT_NODE * query); + + extern PT_NODE *pt_make_data_default_expr_node (PARSER_CONTEXT * parser, PT_NODE * expr); extern PT_OP_TYPE pt_op_type_from_default_expr_type (DB_DEFAULT_EXPR_TYPE expr_type); + extern int pt_associate_label_with_value_check_reference (const char *label, DB_VALUE * val); extern DB_VALUE *pt_find_value_of_label (const char *label); #if defined(ENABLE_UNUSED_FUNCTION) @@ -674,6 +677,8 @@ extern "C" int *continue_walk); extern void pt_get_default_expression_from_data_default_node (PARSER_CONTEXT * parser, PT_NODE * data_default_node, DB_DEFAULT_EXPR * default_expr); + extern void pt_get_default_expression_from_string (PARSER_CONTEXT * parser, const char *str, const int str_size, + DB_DEFAULT_EXPR * default_expr); extern PT_NODE *pt_has_name_oid (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk); extern int pt_check_dblink_password (PARSER_CONTEXT * parser, const char *passwd, char *cipher, int ciper_size); diff --git a/src/parser/parser_message.h b/src/parser/parser_message.h index efe01b11c3..db177a312c 100644 --- a/src/parser/parser_message.h +++ b/src/parser/parser_message.h @@ -504,6 +504,14 @@ #define MSGCAT_SEMANTIC_SP_INTO_FIELD_EXPR_IN_NON_STATIC_SQL MSGCAT_SEMANTIC_NO(324) #define MSGCAT_SEMANTIC_NOT_SUPPORT_TYPE_TO_DATE_LANG MSGCAT_SEMANTIC_NO(325) +#define MSGCAT_SEMANTIC_NOT_SUPPORT_TYPE_TO_DATE_LANG MSGCAT_SEMANTIC_NO(325) +#define MSTCAT_SEMANTIC_SP_NOT_EXIST MSGCAT_SEMANTIC_NO(326) +#define MSGCAT_SEMANTIC_SP_OUT_DEFAULT_ARG_NOT_ALLOWED MSGCAT_SEMANTIC_NO(327) +#define MSGCAT_SEMANTIC_SP_NON_TRAILING_OPTIONAL_PARAMS MSGCAT_SEMANTIC_NO(328) +#define MSGCAT_SEMATNIC_AU_GRANT_OPTION_NOT_ALLOWED MSGCAT_SEMANTIC_NO(329) + + + /* Message id in the set MSGCAT_SET_PARSER_RUNTIME */ #define MSGCAT_RUNTIME_NO(n) n #define MSGCAT_RUNTIME_OUT_OF_MEMORY MSGCAT_RUNTIME_NO(1) diff --git a/src/parser/parser_support.c b/src/parser/parser_support.c index d0727f285d..eb6aaf6fb9 100644 --- a/src/parser/parser_support.c +++ b/src/parser/parser_support.c @@ -1522,7 +1522,7 @@ pt_is_method_call (PT_NODE * node) } node = pt_get_end_path_node (node); - return (node->node_type == PT_METHOD_CALL); + return (PT_IS_METHOD (node)); } /* @@ -7769,33 +7769,26 @@ pt_make_query_show_grants_curr_usr (PARSER_CONTEXT * parser) return node; } +static PT_NODE * +pt_set_auth_bypass_mask_for_show (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, int *continue_walk) +{ + DB_AUTH *auth_bypass; + + assert (arg != NULL); + + if (node && node->node_type == PT_SPEC) + { + auth_bypass = (DB_AUTH *) arg; + node->info.spec.auth_bypass_mask = *auth_bypass; + } + + return node; +} + /* * pt_make_query_show_grants() - builds the query used for SHOW GRANTS for a * given user * - * SELECT CONCAT ( 'GRANT ', - * GROUP_CONCAT(AU.auth_type ORDER BY 1 SEPARATOR ', '), - * ' ON ' , - * AU.class_of.class_name, - * ' TO ', - * AU.grantee.name , - * IF (AU.is_grantable=1, - * ' WITH GRANT OPTION', - * '') - * ) AS GRANTS - * FROM db_class C, _db_auth AU - * WHERE AU.class_of.unique_name = C.unique_name AND - * AU.class_of.owner.name = C.owner_name AND - * C.is_system_class='NO' AND - * ( AU.grantee.name= OR - * SET{ AU.grantee.name} SUBSETEQ ( - * SELECT SUM(SET{t.g.name}) - * FROM db_user U, TABLE(groups) AS t(g) - * WHERE U.name=) - * ) - * GROUP BY AU.grantee, AU.class_of, AU.is_grantable - * ORDER BY 1; - * * Note : The purpose of GROUP BY is to group all the privilege by user, * table and the presence of 'WITH GRANT OPTION' flag. We output the * privileges for the user but also for all groups to which the user @@ -7808,218 +7801,131 @@ pt_make_query_show_grants_curr_usr (PARSER_CONTEXT * parser) * parser(in): Parser context * user_name(in): DB user name */ + PT_NODE * pt_make_query_show_grants (PARSER_CONTEXT * parser, const char *original_user_name) { - PT_NODE *node = NULL; - PT_NODE *from_item = NULL; - PT_NODE *where_expr = NULL; - PT_NODE *concat_node = NULL; - PT_NODE *group_by_item = NULL; + PT_NODE **node = NULL; + PT_NODE *show_node = NULL; char user_name[SM_MAX_IDENTIFIER_LENGTH]; - assert (original_user_name != NULL); - assert (strlen (original_user_name) < SM_MAX_IDENTIFIER_LENGTH); + // *INDENT-OFF* + const static char *query = + "SELECT " + "CONCAT ('GRANT ', " + "GROUP_CONCAT([auth_type] ORDER BY 1 SEPARATOR ', '), " + "' ON '," + "IF ([object_type]=5, 'PROCEDURE ', ''), " + "[owner_name] || '.' || [object_name], " + "' TO '," + "[grantee_name]," + "IF ([is_grantable]=1, ' WITH GRANT OPTION', '')" + ") AS GRANTS " + "FROM (" + "SELECT " + "CAST ([a].[grantor].[name] AS VARCHAR(255)) AS [grantor_name], " /* string -> varchar(255) */ + "CAST ([a].[grantee].[name] AS VARCHAR(255)) AS [grantee_name], " /* string -> varchar(255) */ + "[a].[object_type] AS [object_type], " + "[c].[class_name] AS [object_name], " + "CAST ([c].[owner].[name] AS VARCHAR(255)) AS [owner_name], " /* string -> varchar(255) */ + "[a].[auth_type] AS [auth_type], " + "[a].[is_grantable] AS [is_grantable] " + "FROM " + "[_db_auth] AS [a], [_db_class] AS [c] " + "WHERE " + "[a].[object_of] = [c].[class_of] " + "AND [a].[object_type] = 0 " + "AND MOD ([c].[is_system_class], 2) = 0 " + "AND ( " + "[a].[grantee].[name] = '%1$s' " + "OR " + "SET {[a].[grantee].[name]} SUBSETEQ (" + "SELECT " + "SUM (SET {[t].[g].[name]}) " + "FROM " + /* AU_USER_CLASS_NAME */ + "[db_user] AS [u], TABLE ([u].[groups]) AS [t] ([g]) " + "WHERE " + "[u].[name] = '%1$s'" + ") " + ") " + "UNION ALL " + "SELECT " + "CAST ([a].[grantor].[name] AS VARCHAR(255)) AS [grantor_name], " /* string -> varchar(255) */ + "CAST ([a].[grantee].[name] AS VARCHAR(255)) AS [grantee_name], " /* string -> varchar(255) */ + "[a].[object_type] AS [object_type], " + "[s].[sp_name] AS [object_name], " + "CAST ([s].[owner].[name] AS VARCHAR(255)) AS [owner_name], " /* string -> varchar(255) */ + "[a].[auth_type] AS [auth_type], " + "[a].[is_grantable] AS [is_grantable] " + "FROM " + "[_db_auth] AS [a], [_db_stored_procedure] AS [s] " + "WHERE " + "[a].[object_of] = [s] " + "AND [a].[object_type] = 5 " + "AND [s].[is_system_generated] = 0 " + "AND ( " + "[a].[grantee].[name] = '%1$s' " + "OR " + "SET {[a].[grantee].[name]} SUBSETEQ (" + "SELECT " + "SUM (SET {[t].[g].[name]}) " + "FROM " + /* AU_USER_CLASS_NAME */ + "[db_user] AS [u], TABLE ([u].[groups]) AS [t] ([g]) " + "WHERE " + "[u].[name] = '%1$s'" + ") " + ") " + ") " + "GROUP BY " + "[grantee_name], [owner_name], [object_name], [is_grantable] ASC " + "ORDER BY 1;"; + // *INDENT-ON* + + const int buffer_size = 4096; // length of query (1303) + identifier (255) * 4 < 1024 + char buffer[buffer_size]; + memset (buffer, 0, buffer_size); /* conversion to uppercase can cause to double size, if internationalization is used : size * accordingly */ intl_identifier_upper (original_user_name, user_name); - node = parser_new_node (parser, PT_SELECT); - if (node == NULL) - { - return NULL; - } - - PT_SELECT_INFO_SET_FLAG (node, PT_SELECT_INFO_READ_ONLY); - - /* ------ SELECT list ------- */ - /* - * CONCAT ( 'GRANT ', - * GROUP_CONCAT(AU.auth_type ORDER BY 1 SEPARATOR ', '), - * ' ON ' , - * AU.class_of.unique_name, - * ' TO ', - * AU.grantee.name , - * IF (AU.is_grantable=1, - * ' WITH GRANT OPTION', - * '') - * ) AS GRANTS - */ - { - PT_NODE *concat_arg_list = NULL; - PT_NODE *concat_arg = NULL; + snprintf (buffer, buffer_size, query, user_name); - concat_arg = pt_make_string_value (parser, "GRANT "); - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); + /* parser ';' will empty and reset the stack of parser, this make the status machine be right for the next statement, + * and avoid nested parser statement. */ + parser_parse_string (parser, ";"); + node = parser_parse_string_use_sys_charset (parser, buffer); + if (node == NULL) { - /* GROUP_CONCAT(AU.auth_type ORDER BY 1 SEPARATOR ', ') */ - PT_NODE *group_concat_field = NULL; - PT_NODE *group_concat_sep = NULL; - PT_NODE *order_by_item = NULL; - - concat_arg = parser_new_node (parser, PT_FUNCTION); - if (concat_arg == NULL) - { - return NULL; - } - - concat_arg->info.function.function_type = PT_GROUP_CONCAT; - concat_arg->info.function.all_or_distinct = PT_ALL; - - group_concat_field = pt_make_dotted_identifier (parser, "AU.auth_type"); - group_concat_sep = pt_make_string_value (parser, ", "); - concat_arg->info.function.arg_list = parser_append_node (group_concat_sep, group_concat_field); - - /* add ORDER BY */ - assert (concat_arg->info.function.order_by == NULL); - - /* By 1 */ - order_by_item = pt_make_sort_spec_with_number (parser, 1, PT_ASC); - concat_arg->info.function.order_by = order_by_item; + return NULL; } - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); - concat_arg = pt_make_string_value (parser, " ON "); - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); - - concat_arg = pt_make_dotted_identifier (parser, "AU.class_of.unique_name"); - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); - - concat_arg = pt_make_string_value (parser, " TO "); - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); + parser->flag.dont_collect_exec_stats = 1; - concat_arg = pt_make_dotted_identifier (parser, "AU.grantee.name"); - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); + show_node = pt_pop (parser); + assert (show_node == node[0]); - /* IF (AU.is_grantable=1, ' WITH GRANT OPTION','') */ + if (show_node) { - PT_NODE *pred_for_if = NULL; - - pred_for_if = pt_make_pred_name_int_val (parser, PT_EQ, "AU.is_grantable", 1); - concat_arg = pt_make_if_with_strings (parser, pred_for_if, " WITH GRANT OPTION", "", NULL); - } - concat_arg_list = parser_append_node (concat_arg, concat_arg_list); - - concat_node = parser_keyword_func ("concat", concat_arg_list); - if (concat_node == NULL) - { - return NULL; - } + DB_AUTH bypass_auth = DB_AUTH_SELECT; + show_node = parser_walk_tree (parser, show_node, pt_set_auth_bypass_mask_for_show, &bypass_auth, NULL, NULL); - { + // for backward compatibiltiy char col_alias[SM_MAX_IDENTIFIER_LENGTH] = { 0 }; const char *const col_header = "Grants for "; strcpy (col_alias, col_header); strncat (col_alias, user_name, SM_MAX_IDENTIFIER_LENGTH - strlen (col_header) - 1); col_alias[SM_MAX_IDENTIFIER_LENGTH - 1] = '\0'; - concat_node->alias_print = pt_append_string (parser, NULL, col_alias); - } - } - node->info.query.q.select.list = parser_append_node (concat_node, node->info.query.q.select.list); - - /* ------ SELECT ... FROM ------- */ - from_item = pt_add_table_name_to_from_list (parser, node, "db_class", "C", DB_AUTH_SELECT); - - from_item = pt_add_table_name_to_from_list (parser, node, "_db_auth", "AU", DB_AUTH_SELECT); - - /* ------ SELECT ... WHERE ------- */ - /* - * WHERE AU.class_of.class_name = C.class_name AND - * AU.class_of.owner.name = C.owner_name AND - * C.is_system_class='NO' AND - * ( AU.grantee.name= OR - * SET{ AU.grantee.name} SUBSETEQ ( ) - * ) - */ - { - /* AU.class_of.class_name = C.class_name */ - PT_NODE *where_item = NULL; - - where_item = pt_make_pred_with_identifiers (parser, PT_EQ, "AU.class_of.class_name", "C.class_name"); - where_expr = where_item; - } - { - /* AU.class_of.owner.name = C.owner_name */ - PT_NODE *where_item = NULL; - where_item = pt_make_pred_with_identifiers (parser, PT_EQ, "AU.class_of.owner.name", "C.owner_name"); - /* = AND */ - where_expr = parser_make_expression (parser, PT_AND, where_expr, where_item, NULL); - } - { - /* C.is_system_class = 'NO' */ - PT_NODE *where_item = NULL; - - where_item = pt_make_pred_name_string_val (parser, PT_EQ, "C.is_system_class", "NO"); - /* = AND */ - where_expr = parser_make_expression (parser, PT_AND, where_expr, where_item, NULL); - } - { - PT_NODE *user_cond = NULL; - PT_NODE *group_cond = NULL; - /* AU.grantee.name = */ - user_cond = pt_make_pred_name_string_val (parser, PT_EQ, "AU.grantee.name", user_name); - - /* SET{ AU.grantee.name} SUBSETEQ ( */ - { - /* query to get a SET of user's groups */ - PT_NODE *query_user_groups = NULL; - PT_NODE *set_of_grantee_name = NULL; - - { - /* SET{ AU.grantee.name} */ - PT_NODE *grantee_name_identifier = NULL; - - grantee_name_identifier = pt_make_dotted_identifier (parser, "AU.grantee.name"); - set_of_grantee_name = parser_new_node (parser, PT_VALUE); - if (set_of_grantee_name == NULL) - { - return NULL; - } - set_of_grantee_name->info.value.data_value.set = grantee_name_identifier; - set_of_grantee_name->type_enum = PT_TYPE_SET; - } - - query_user_groups = pt_make_query_user_groups (parser, user_name); - - group_cond = parser_make_expression (parser, PT_SUBSETEQ, set_of_grantee_name, query_user_groups, NULL); + PT_NODE *concat_node = show_node->info.query.q.select.list; + concat_node->alias_print = pt_append_string (parser, NULL, col_alias); } - user_cond = parser_make_expression (parser, PT_OR, user_cond, group_cond, NULL); - - where_expr = parser_make_expression (parser, PT_AND, where_expr, user_cond, NULL); - } - - - - /* WHERE list should be empty */ - assert (node->info.query.q.select.where == NULL); - node->info.query.q.select.where = parser_append_node (where_expr, node->info.query.q.select.where); - - /* GROUP BY : AU.grantee, AU.class_of, AU.is_grantable */ - assert (node->info.query.q.select.group_by == NULL); - group_by_item = pt_make_sort_spec_with_identifier (parser, "AU.grantee", PT_ASC); - node->info.query.q.select.group_by = parser_append_node (group_by_item, node->info.query.q.select.group_by); - - group_by_item = pt_make_sort_spec_with_identifier (parser, "AU.class_of", PT_ASC); - node->info.query.q.select.group_by = parser_append_node (group_by_item, node->info.query.q.select.group_by); - - group_by_item = pt_make_sort_spec_with_identifier (parser, "AU.is_grantable", PT_ASC); - node->info.query.q.select.group_by = parser_append_node (group_by_item, node->info.query.q.select.group_by); - group_by_item = NULL; - - { - PT_NODE *order_by_item = NULL; - assert (node->info.query.order_by == NULL); - - /* By GROUPS */ - order_by_item = pt_make_sort_spec_with_number (parser, 1, PT_ASC); - node->info.query.order_by = parser_append_node (order_by_item, node->info.query.order_by); - } - return node; + return show_node; } /* @@ -10397,6 +10303,144 @@ pt_has_non_groupby_column_node (PARSER_CONTEXT * parser, PT_NODE * node, void *a return node; } +static DB_DEFAULT_EXPR_TYPE +parse_default_expr_type (const char *str, const int str_size, int *next_len) +{ + if (str_size < 4) + { + *next_len = 0; + return DB_DEFAULT_NONE; + } + + switch (str[0]) + { + case 'S': + if (str_size >= 8) + { + if (strncmp (str, "SYS_DATE", 8) == 0) + { + *next_len = 8; + return DB_DEFAULT_SYSDATE; + } + if (strncmp (str, "SYS_TIME", 8) == 0) + { + *next_len = 8; + return DB_DEFAULT_SYSTIME; + } + } + if (str_size >= 12 && strncmp (str, "SYS_DATETIME", 12) == 0) + { + *next_len = 12; + return DB_DEFAULT_SYSDATETIME; + } + if (str_size >= 13 && strncmp (str, "SYS_TIMESTAMP", 13) == 0) + { + *next_len = 13; + return DB_DEFAULT_SYSTIMESTAMP; + } + break; + + case 'C': + if (str_size >= 12) + { + if (strncmp (str, "CURRENT_DATE", 12) == 0) + { + *next_len = 12; + return DB_DEFAULT_CURRENTDATE; + } + if (strncmp (str, "CURRENT_TIME", 12) == 0) + { + *next_len = 12; + return DB_DEFAULT_CURRENTTIME; + } + if (strncmp (str, "CURRENT_USER", 12) == 0) + { + *next_len = 12; + return DB_DEFAULT_CURR_USER; + } + } + if (str_size >= 16 && strncmp (str, "CURRENT_DATETIME", 16) == 0) + { + *next_len = 16; + return DB_DEFAULT_CURRENTDATETIME; + } + if (str_size >= 17 && strncmp (str, "CURRENT_TIMESTAMP", 17) == 0) + { + *next_len = 17; + return DB_DEFAULT_CURRENTTIMESTAMP; + } + break; + + case 'U': + if (str_size >= 16 && strncmp (str, "UNIX_TIMESTAMP()", 16) == 0) + { + *next_len = 16; + return DB_DEFAULT_UNIX_TIMESTAMP; + } + if (str_size >= 6 && strncmp (str, "USER()", 6) == 0) + { + *next_len = 6; + return DB_DEFAULT_USER; + } + if (str_size >= 4 && strncmp (str, "USER", 4) == 0) + { + *next_len = 4; + return DB_DEFAULT_CURR_USER; + } + break; + } + + *next_len = 0; + return DB_DEFAULT_NONE; +} + +/* + * pt_get_default_expression_from_string () - get default value from string + * return : error code or NO_ERROR + * + * parser (in) : parser context + * str (in) : default expression string + * str_size (in) : default expression string size + * default_expr (out) : default expression + */ +void +pt_get_default_expression_from_string (PARSER_CONTEXT * parser, const char *str, const int str_size, + DB_DEFAULT_EXPR * default_expr) +{ + assert (parser != NULL && default_expr != NULL); + assert (str != NULL && str_size > 0); + + classobj_initialize_default_expr (default_expr); + + std::string expr_str (str, str_size); + + int curr_idx = 0; + int curr_len = str_size; + + const int to_char_size = sizeof ("TO_CHAR(") - 1; + if (str_size > to_char_size && strncmp (str, "TO_CHAR(", to_char_size) == 0) + { + curr_idx += to_char_size; + curr_len -= to_char_size; + default_expr->default_expr_op = T_TO_CHAR; + } + + int parsed_len; + default_expr->default_expr_type = parse_default_expr_type (&str[curr_idx], curr_len, &parsed_len); + curr_idx += parsed_len; + curr_len -= parsed_len; + + if (default_expr->default_expr_op == T_TO_CHAR) + { + // find next ',' + const char *formatted_string = strchr (&str[curr_idx], ',') + 1; + + // get remaining length before the last ')' + int remaining_len = str_size - (formatted_string - &str[curr_idx]); + default_expr->default_expr_format = strndup (formatted_string, remaining_len - 1); + } +} + /* * pt_get_default_value_from_attrnode () - get default value from data default node * return : error code or NO_ERROR @@ -10501,7 +10545,7 @@ pt_set_user_specified_name (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, switch (node->node_type) { case PT_NAME: - if (PT_NAME_INFO_IS_FLAGED (node, PT_NAME_INFO_USER_SPECIFIED)) + if (PT_NAME_INFO_IS_FLAGED (node, PT_NAME_INFO_USER_SPECIFIED) || node->info.name.meta_class == PT_META_CLASS) { original_name = node->info.name.original; resolved_name = node->info.name.resolved; @@ -10680,7 +10724,7 @@ pt_set_user_specified_name (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, } // *INDENT-OFF* - assert ((node->node_type == PT_NAME && PT_NAME_INFO_IS_FLAGED (node, PT_NAME_INFO_USER_SPECIFIED)) + assert ((node->node_type == PT_NAME && (PT_NAME_INFO_IS_FLAGED (node, PT_NAME_INFO_USER_SPECIFIED) || node->info.name.meta_class == PT_META_CLASS)) || (node->node_type == PT_EXPR && PT_IS_SERIAL (node->info.expr.op))); // *INDENT-ON* assert (original_name && original_name[0] != '\0'); @@ -10695,7 +10739,7 @@ pt_set_user_specified_name (PARSER_CONTEXT * parser, PT_NODE * node, void *arg, { PT_ERRORf2 (parser, node, "Object name [%s] not allowed. It cannot exceed %d bytes.", - pt_short_print (parser, node), DB_MAX_IDENTIFIER_LENGTH - DB_MAX_USER_LENGTH); + pt_short_print (parser, node), (DB_MAX_IDENTIFIER_LENGTH - DB_MAX_USER_LENGTH) - 1); *continue_walk = PT_STOP_WALK; return node; } @@ -12062,3 +12106,87 @@ pt_rewrite_for_dblink (PARSER_CONTEXT * parser, PT_NODE * stmt) return; } + +extern PT_NODE * +pt_make_data_default_expr_node (PARSER_CONTEXT * parser, PT_NODE * expr) +{ + PT_NODE *node = parser_new_node (parser, PT_DATA_DEFAULT); + if (node) + { + PT_NODE *def; + node->info.data_default.default_value = expr; + node->info.data_default.shared = PT_DEFAULT; + + def = node->info.data_default.default_value; + if (def && def->node_type == PT_EXPR) + { + if (def->info.expr.op == PT_TO_CHAR) + { + if (def->info.expr.arg3) + { + bool has_user_lang = false; + bool dummy; + + assert (def->info.expr.arg3->node_type == PT_VALUE); + (void) lang_get_lang_id_from_flag (def->info.expr.arg3->info.value.data_value.i, &dummy, + &has_user_lang); + if (has_user_lang) + { + PT_ERROR (parser, def->info.expr.arg3, "do not allow lang format in default to_char"); + } + } + + if (def->info.expr.arg1 && def->info.expr.arg1->node_type == PT_EXPR) + { + def = def->info.expr.arg1; + } + } + + switch (def->info.expr.op) + { + case PT_SYS_TIME: + node->info.data_default.default_expr_type = DB_DEFAULT_SYSTIME; + break; + case PT_SYS_DATE: + node->info.data_default.default_expr_type = DB_DEFAULT_SYSDATE; + break; + case PT_SYS_DATETIME: + node->info.data_default.default_expr_type = DB_DEFAULT_SYSDATETIME; + break; + case PT_SYS_TIMESTAMP: + node->info.data_default.default_expr_type = DB_DEFAULT_SYSTIMESTAMP; + break; + case PT_CURRENT_TIME: + node->info.data_default.default_expr_type = DB_DEFAULT_CURRENTTIME; + break; + case PT_CURRENT_DATE: + node->info.data_default.default_expr_type = DB_DEFAULT_CURRENTDATE; + break; + case PT_CURRENT_DATETIME: + node->info.data_default.default_expr_type = DB_DEFAULT_CURRENTDATETIME; + break; + case PT_CURRENT_TIMESTAMP: + node->info.data_default.default_expr_type = DB_DEFAULT_CURRENTTIMESTAMP; + break; + case PT_USER: + node->info.data_default.default_expr_type = DB_DEFAULT_USER; + break; + case PT_CURRENT_USER: + node->info.data_default.default_expr_type = DB_DEFAULT_CURR_USER; + break; + case PT_UNIX_TIMESTAMP: + node->info.data_default.default_expr_type = DB_DEFAULT_UNIX_TIMESTAMP; + break; + default: + node->info.data_default.default_expr_type = DB_DEFAULT_NONE; + break; + } + } + else + { + node->info.data_default.default_expr_type = DB_DEFAULT_NONE; + } + } + + return node; +} diff --git a/src/parser/semantic_check.c b/src/parser/semantic_check.c index 06fc33ae84..520a7e8c68 100644 --- a/src/parser/semantic_check.c +++ b/src/parser/semantic_check.c @@ -46,6 +46,7 @@ #include "db_json.hpp" #include "object_primitive.h" #include "db_client_type.hpp" +#include "msgcat_glossary.hpp" #include "dbtype.h" #define PT_CHAIN_LENGTH 10 @@ -273,6 +274,7 @@ static PT_NODE *pt_check_where (PARSER_CONTEXT * parser, PT_NODE * node); static int pt_check_range_partition_strict_increasing (PARSER_CONTEXT * parser, PT_NODE * stmt, PT_NODE * part, PT_NODE * part_next, PT_NODE * column_dt); static int pt_coerce_partition_value_with_data_type (PARSER_CONTEXT * parser, PT_NODE * value, PT_NODE * data_type); +static int pt_check_default_value_param_for_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * param); /* pt_combine_compatible_info () - combine two cinfo into cinfo1 * return: true if compatible, else false @@ -9504,6 +9506,67 @@ pt_get_type_name (PT_TYPE_ENUM type_enum, PT_NODE * data_type) return pt_show_type_enum (type_enum); } +/* + * pt_check_default_value_param_for_stored_procedure () - do semantic checks for default value params' invalid form: Out parameter, system expressions, incoercible type + * return: none + * parser(in): the parser context used to derive the statement + * node(in): a statement + */ +static int +pt_check_default_value_param_for_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * param) +{ + int error = NO_ERROR; + PT_NODE *node_ptr = NULL; + PT_NODE *default_value_node = NULL; + PT_NODE *default_value = NULL; + const char *default_value_print = NULL; + + default_value_node = param->info.sp_param.default_value = + pt_check_data_default (parser, param->info.sp_param.default_value); + if (pt_has_error (parser)) + { + return error; + } + + assert (default_value_node != NULL && default_value_node->info.data_default.shared == PT_DEFAULT); + + default_value = default_value_node->info.data_default.default_value; + default_value_print = pt_short_print (parser, default_value); + + if (param->info.sp_param.mode != PT_INPUT && param->info.sp_param.mode != PT_NOPUT) + { + PT_ERRORmf (parser, + param, + MSGCAT_SET_PARSER_SEMANTIC, + MSGCAT_SEMANTIC_SP_OUT_DEFAULT_ARG_NOT_ALLOWED, pt_short_print (parser, param->info.sp_param.name)); + return error; + } + + if (default_value_node->info.data_default.default_expr_type != DB_DEFAULT_NONE) + { + PT_ERRORmf (parser, + default_value_node->info.data_default.default_value, + MSGCAT_SET_PARSER_SEMANTIC, + MSGCAT_SEMANTIC_DEFAULT_EXPR_NOT_ALLOWED, + pt_short_print (parser, default_value_node->info.data_default.default_value)); + } + else + { + error = + pt_coerce_value_for_default_value (parser, default_value, default_value, param->type_enum, + param->data_type, default_value_node->info.data_default.default_expr_type); + if (error != NO_ERROR) + { + error = + (error == ER_IT_DATA_OVERFLOW) ? MSGCAT_SEMANTIC_OVERFLOW_COERCING_TO : MSGCAT_SEMANTIC_CANT_COERCE_TO; + PT_ERRORmf2 (parser, default_value, MSGCAT_SET_PARSER_SEMANTIC, error, + default_value_print, pt_get_type_name (param->type_enum, param->data_type)); + } + } + + return error; +} + /* * pt_check_create_stored_procedure () - do semantic checks on the create procedure/function statement * return: none @@ -9513,10 +9576,39 @@ pt_get_type_name (PT_TYPE_ENUM type_enum, PT_NODE * data_type) static void pt_check_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * node) { - PT_NODE *param; - + int error = NO_ERROR; + PT_NODE *param = NULL; + PT_NODE *default_value_node = NULL; + PT_NODE *default_value = NULL; + PT_NODE *initial_def_val = NULL; + int param_count = 0; + bool has_default_value = false; bool is_plcsql = (node->info.sp.body->info.sp_body.lang == SP_LANG_PLCSQL); + DB_OBJECT *owner = NULL; + PT_NODE *name = node->info.sp.name; + const char *owner_name = pt_get_qualifier_name (parser, name); + if (owner_name) + { + owner = db_find_user (owner_name); + if (owner == NULL) + { + ASSERT_ERROR_AND_SET (error); + + if (er_errid () == ER_AU_INVALID_USER) + { + PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_USER_IS_NOT_IN_DB, owner_name); + } + return; + } + else if (au_is_dba_group_member (Au_user) == false && ws_is_same_object (owner, Au_user) == false) + { + PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_SYNONYM_NOT_OWNER, + "CREATE PROCEDURE/FUNCTION"); + return; + } + } + for (param = node->info.sp.param_list; param; param = param->next) { if (param->type_enum == PT_TYPE_NONE) @@ -9543,7 +9635,32 @@ pt_check_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * node) PT_ERRORmf (parser, param, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_NOT_SUPPORTED_SP_ARG_TYPE, pt_get_type_name (param->type_enum, param->data_type)); } - return; + goto end; + } + + /* check trailing arguments */ + if (param->info.sp_param.default_value != NULL) + { + has_default_value = true; + // check default value + error = pt_check_default_value_param_for_stored_procedure (parser, param); + if (error != NO_ERROR) + { + goto end; + } + } + else + { + // error for non-trailing arguments + if (has_default_value) + { + PT_ERRORmf (parser, + param, + MSGCAT_SET_PARSER_SEMANTIC, + MSGCAT_SEMANTIC_SP_NON_TRAILING_OPTIONAL_PARAMS, + pt_short_print (parser, param->info.sp_param.name)); + goto end; + } } } @@ -9575,9 +9692,12 @@ pt_check_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * node) MSGCAT_SEMANTIC_NOT_SUPPORTED_SP_RET_TYPE, pt_get_type_name (node->info.sp.ret_type, node->info.sp.ret_data_type)); } - return; + goto end; } } + +end: + return; } /* @@ -9850,10 +9970,48 @@ pt_check_grant_revoke (PARSER_CONTEXT * parser, PT_NODE * node) const char *username; PT_FLAT_SPEC_INFO info; - /* Replace each Entity Spec with an Equivalent flat list */ - info.spec_parent = NULL; - info.for_update = false; - parser_walk_tree (parser, node, pt_flat_spec_pre, &info, pt_continue_walk, NULL); + bool is_for_spec = true; + PT_NODE *auth_cmd_list = node->info.grant.auth_cmd_list; + while (auth_cmd_list) + { + PT_PRIV_TYPE pt_auth = auth_cmd_list->info.auth_cmd.auth_cmd; + if (pt_auth == PT_EXECUTE_PROCEDURE_PRIV) + { + is_for_spec = false; + break; + } + + auth_cmd_list = auth_cmd_list->next; + } + + if (is_for_spec == true) + { + /* Replace each Entity Spec with an Equivalent flat list */ + info.spec_parent = NULL; + info.for_update = false; + parser_walk_tree (parser, node, pt_flat_spec_pre, &info, pt_continue_walk, NULL); + } + else + { + /* check grant option */ + if (node->info.grant.grant_option == PT_GRANT_OPTION) + { + PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMATNIC_AU_GRANT_OPTION_NOT_ALLOWED, + MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_PROCEDURE)); + } + + /* check spec_list (procedures/functions) exists */ + for (PT_NODE * procs = node->info.grant.spec_list; procs != NULL; procs = procs->next) + { + // [TODO] Resovle user schema name, built-in package name + const char *proc_name = procs->info.name.original; + if (jsp_is_exist_stored_procedure (proc_name) == false) + { + PT_ERRORmf (parser, procs, MSGCAT_SET_PARSER_SEMANTIC, MSTCAT_SEMANTIC_SP_NOT_EXIST, proc_name); + break; + } + } + } /* make sure the grantees/revokees exist */ for ((user = (node->node_type == PT_GRANT ? node->info.grant.user_list : node->info.revoke.user_list)); user; @@ -14485,6 +14643,15 @@ pt_coerce_insert_values (PARSER_CONTEXT * parser, PT_NODE * stmt) /* test assignment compatibility. This sets parser->error_msgs */ PT_NODE *new_node; + if (parser->flag.is_parsing_static_sql == 1 && a->node_type != PT_NAME) + { + assert (a->node_type == PT_HOST_VAR); + PT_ERRORmf2 (parser, stmt, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CLASS_HAS_NO_ATTR, + pt_short_print (parser, stmt->info.insert.spec->info.spec.entity_name), + a->info.host_var.label); + continue; + } + new_node = pt_assignment_compatible (parser, a, v); if (new_node == NULL) { diff --git a/src/parser/view_transform.c b/src/parser/view_transform.c index bcf1d2882d..80eb3575ed 100644 --- a/src/parser/view_transform.c +++ b/src/parser/view_transform.c @@ -1632,7 +1632,7 @@ mq_substitute_spec_in_method_and_hints (PARSER_CONTEXT * parser, PT_NODE * node, switch (node->node_type) { case PT_METHOD_CALL: - if ((node->info.method_call.method_name) + if (PT_IS_METHOD (node) && (node->info.method_call.method_name) && (node->info.method_call.method_name->info.name.spec_id == info->old_id)) { node->info.method_call.method_name->info.name.spec_id = info->new_id; @@ -3222,6 +3222,11 @@ mq_translate_tree (PARSER_CONTEXT * parser, PT_NODE * tree, PT_NODE * spec_list, return NULL; } + if (PT_IS_FOR_PL_COMPILE (parser) && sm_is_system_vclass (entity->info.name.original)) + { + continue; + } + if (!fetch_for_update) { subquery = mq_fetch_subqueries (parser, entity); @@ -3394,13 +3399,10 @@ mq_class_meth_corr_subq_pre (PARSER_CONTEXT * parser, PT_NODE * node, void *void *continue_walk = PT_CONTINUE_WALK; - if (node->node_type == PT_METHOD_CALL) + if (PT_IS_CLASS_METHOD (node)) { /* found class method */ - if (node->info.method_call.method_type == PT_IS_CLASS_MTHD) - { - *found = true; - } + *found = true; } else if (pt_is_query (node)) { @@ -8364,7 +8366,7 @@ mq_reset_spec_ids (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int static PT_NODE * mq_reset_spec_in_method_names (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg, int *continue_walk) { - if (node->node_type == PT_METHOD_CALL) + if (PT_IS_METHOD (node)) { PT_NODE *method_name; method_name = node->info.method_call.method_name; diff --git a/src/parser/xasl_generation.c b/src/parser/xasl_generation.c index b0e65d751d..0fb03e6de8 100644 --- a/src/parser/xasl_generation.c +++ b/src/parser/xasl_generation.c @@ -66,6 +66,7 @@ #include "db_json.hpp" #include "jsp_cl.h" #include "subquery_cache.h" +#include "pl_signature.hpp" #if defined(WINDOWS) #include "wintcp.h" @@ -224,9 +225,6 @@ static void pt_fill_in_attrid_array (REGU_VARIABLE_LIST attr_list, ATTR_ID * att static SORT_LIST *pt_to_sort_list (PARSER_CONTEXT * parser, PT_NODE * node_list, PT_NODE * col_list, SORT_LIST_MODE sort_mode); -static int *pt_to_method_arglist (PARSER_CONTEXT * parser, PT_NODE * target, PT_NODE * node_list, - PT_NODE * subquery_as_attr_list); - static int regu_make_constant_vid (DB_VALUE * val, DB_VALUE ** dbvalptr); static int set_has_objs (DB_SET * seq); static int setof_mop_to_setof_vobj (PARSER_CONTEXT * parser, DB_SET * seq, DB_VALUE * new_val); @@ -237,6 +235,8 @@ static REGU_VARIABLE *pt_make_regu_constant (PARSER_CONTEXT * parser, DB_VALUE * static REGU_VARIABLE *pt_make_regu_pred (const PRED_EXPR * pred); static REGU_VARIABLE *pt_make_function (PARSER_CONTEXT * parser, int function_code, const REGU_VARIABLE_LIST arg_list, const DB_TYPE result_type, const PT_NODE * node); + +static REGU_VARIABLE *pt_stored_procedure_to_regu (PARSER_CONTEXT * parser, PT_NODE * node); static REGU_VARIABLE *pt_function_to_regu (PARSER_CONTEXT * parser, PT_NODE * function); static REGU_VARIABLE *pt_make_regu_subquery (PARSER_CONTEXT * parser, XASL_NODE * xasl, const UNBOX unbox, const PT_NODE * node); @@ -334,7 +334,7 @@ static int pt_fix_buildlist_aggregate_cume_dist_percent_rank (PARSER_CONTEXT * p ((r)->type == TYPE_CONSTANT || (r)->type == TYPE_DBVAL || (r)->type == TYPE_POS_VALUE || (r)->type == TYPE_INARITH) #define VALIDATE_REGU_KEY(r) \ - ((r)->type == TYPE_CONSTANT || (r)->type == TYPE_DBVAL || (r)->type == TYPE_POS_VALUE \ + ((r)->type == TYPE_CONSTANT || (r)->type == TYPE_DBVAL || (r)->type == TYPE_POS_VALUE || (r)->type == TYPE_SP \ || ((r)->type == TYPE_INARITH && validate_regu_key_function_index ((r)))) typedef struct xasl_supp_info @@ -552,7 +552,7 @@ static ACCESS_SPEC_TYPE *pt_make_showstmt_access_spec (PRED_EXPR * where_pred, S static ACCESS_SPEC_TYPE *pt_make_set_access_spec (REGU_VARIABLE * set_expr, ACCESS_METHOD access, INDX_INFO * indexptr, PRED_EXPR * where_pred, REGU_VARIABLE_LIST attr_list); -static ACCESS_SPEC_TYPE *pt_make_cselect_access_spec (XASL_NODE * xasl, METHOD_SIG_LIST * method_sig_list, +static ACCESS_SPEC_TYPE *pt_make_cselect_access_spec (XASL_NODE * xasl, PL_SIGNATURE_ARRAY_TYPE * sig_array, ACCESS_METHOD access, INDX_INFO * indexptr, PRED_EXPR * where_pred, REGU_VARIABLE_LIST attr_list); @@ -568,9 +568,6 @@ static PT_NODE *pt_build_do_stmt_aptr_list_pre (PARSER_CONTEXT * parser, PT_NODE static XASL_NODE *pt_build_do_stmt_aptr_list (PARSER_CONTEXT * parser, PT_NODE * node); -static METHOD_SIG_LIST *pt_to_method_sig_list (PARSER_CONTEXT * parser, PT_NODE * node_list, - PT_NODE * subquery_as_attr_list); - static int pt_is_subquery (PT_NODE * node); static int *pt_make_identity_offsets (PT_NODE * attr_list); @@ -3753,220 +3750,6 @@ pt_filter_pseudo_specs (PARSER_CONTEXT * parser, PT_NODE * spec) return spec; } -/* - * pt_to_method_arglist () - converts a parse expression tree list of - * method call arguments to method argument array - * return: A NULL on error occurred - * parser(in): - * target(in): - * node_list(in): should be parse name nodes - * subquery_as_attr_list(in): - */ -static int * -pt_to_method_arglist (PARSER_CONTEXT * parser, PT_NODE * target, PT_NODE * node_list, PT_NODE * subquery_as_attr_list) -{ - int *arg_list = NULL; - int i = 1; - int num_args = pt_length_of_list (node_list) + 1; - PT_NODE *node; - - arg_list = regu_int_array_alloc (num_args); - if (!arg_list) - { - return NULL; - } - - if (target != NULL) - { - /* the method call target is the first element in the array */ - arg_list[0] = pt_find_attribute (parser, target, subquery_as_attr_list); - if (arg_list[0] == -1) - { - return NULL; - } - } - else - { - i = 0; - } - - for (node = node_list; node != NULL; node = node->next) - { - arg_list[i] = pt_find_attribute (parser, node, subquery_as_attr_list); - if (arg_list[i] == -1) - { - return NULL; - } - i++; - } - - return arg_list; -} - - -/* - * pt_to_method_sig_list () - converts a parse expression tree list of - * method calls to method signature list - * return: A NULL return indicates a (memory) error occurred - * parser(in): - * node_list(in): should be parse method nodes - * subquery_as_attr_list(in): - */ -static METHOD_SIG_LIST * -pt_to_method_sig_list (PARSER_CONTEXT * parser, PT_NODE * node_list, PT_NODE * subquery_as_attr_list) -{ - METHOD_SIG_LIST *sig_list = NULL; - METHOD_SIG **tail = NULL; - PT_NODE *node; - - regu_alloc (sig_list); - if (!sig_list) - { - return NULL; - } - - tail = &(sig_list->method_sig); - - for (node = node_list; node != NULL; node = node->next) - { - regu_alloc (*tail); - - if (*tail) - { - (sig_list->num_methods)++; - - (*tail)->method_name = (char *) node->info.method_call.method_name->info.name.original; - - /* num_method_args does not include the target by convention */ - (*tail)->num_method_args = pt_length_of_list (node->info.method_call.arg_list); - (*tail)->method_arg_pos = - pt_to_method_arglist (parser, node->info.method_call.on_call_target, node->info.method_call.arg_list, - subquery_as_attr_list); - - if (PT_IS_METHOD (node)) - { - PT_NODE *dt = node->info.method_call.on_call_target->data_type; - /* beware of virtual classes */ - if (dt->info.data_type.virt_object) - { - (*tail)->class_name = (char *) db_get_class_name (dt->info.data_type.virt_object); - } - else - { - (*tail)->class_name = (char *) dt->info.data_type.entity->info.name.original; - } - - (*tail)->method_type = PT_IS_CLASS_METHOD (node) ? METHOD_TYPE_CLASS_METHOD : METHOD_TYPE_INSTANCE_METHOD; - } - else if (PT_IS_JAVA_SP (node)) - { - (*tail)->class_name = NULL; - (*tail)->method_type = METHOD_TYPE_JAVA_SP; - - int num_args = (*tail)->num_method_args; - (*tail)->arg_info.arg_mode = regu_int_array_alloc (num_args); - (*tail)->arg_info.arg_type = regu_int_array_alloc (num_args); - - DB_OBJECT *mop_p = jsp_find_stored_procedure ((*tail)->method_name); - if (mop_p) - { - /* java stored procedure signature */ - DB_VALUE method; - if (db_get (mop_p, SP_ATTR_TARGET, &method) == NO_ERROR) - { - (*tail)->method_name = (char *) db_get_string (&method); - } - else - { - break; - } - - DB_VALUE args; - /* arg_mode, arg_type */ - if (db_get (mop_p, SP_ATTR_ARGS, &args) == NO_ERROR) - { - DB_SET *param_set = db_get_set (&args); - DB_VALUE mode, type, temp; - int i, arg_mode, arg_type; - for (i = 0; i < num_args; i++) - { - set_get_element (param_set, i, &temp); - DB_OBJECT *arg_mop_p = db_get_object (&temp); - if (arg_mop_p) - { - if (db_get (arg_mop_p, SP_ATTR_MODE, &mode) == NO_ERROR) - { - arg_mode = db_get_int (&mode); - } - - if (db_get (arg_mop_p, SP_ATTR_DATA_TYPE, &type) == NO_ERROR) - { - arg_type = db_get_int (&type); - } - - (*tail)->arg_info.arg_mode[i] = arg_mode; - (*tail)->arg_info.arg_type[i] = arg_type; - - pr_clear_value (&mode); - pr_clear_value (&type); - pr_clear_value (&temp); - } - else - { - break; - } - - - if (jsp_check_out_param_in_query (parser, node, arg_mode) != NO_ERROR) - { - pr_clear_value (&args); - return NULL; - } - } - pr_clear_value (&args); - } - else - { - break; - } - - /* result type */ - DB_VALUE result_type; - if (db_get (mop_p, SP_ATTR_RETURN_TYPE, &result_type) == NO_ERROR) - { - (*tail)->arg_info.result_type = db_get_int (&result_type); - pr_clear_value (&result_type); - } - else - { - break; - } - } - else - { - break; - } - } - else - { - /* should be never happened */ - assert (false); - break; - } - tail = &(*tail)->next; - } - else - { - /* something failed */ - sig_list = NULL; - assert (false); - break; - } - } - - return sig_list; -} - /* * pt_make_val_list () - Makes a val list with a DB_VALUE place holder * for every attribute on an attribute list @@ -4560,7 +4343,7 @@ pt_to_aggregate_node (PARSER_CONTEXT * parser, PT_NODE * tree, void *arg, int *c /* Do not proceed down the leaves. */ *continue_walk = PT_LIST_WALK; } - else if (tree->node_type == PT_METHOD_CALL) + else if (PT_IS_METHOD (tree)) { /* Do not proceed down the leaves */ *continue_walk = PT_LIST_WALK; @@ -5019,6 +4802,10 @@ pt_cnt_attrs (const REGU_VARIABLE_LIST attr_list) /* need to check all the operands for the function */ cnt += pt_cnt_attrs (tmp->value.value.funcp->operand); } + else if (tmp->value.type == TYPE_SP) + { + cnt += pt_cnt_attrs (tmp->value.value.sp_ptr->args); + } } return cnt; @@ -5052,6 +4839,10 @@ pt_fill_in_attrid_array (REGU_VARIABLE_LIST attr_list, ATTR_ID * attr_array, int /* need to check all the operands for the function */ pt_fill_in_attrid_array (tmp->value.value.funcp->operand, attr_array, next_pos); } + else if (tmp->value.type == TYPE_SP) + { + pt_fill_in_attrid_array (tmp->value.value.sp_ptr->args, attr_array, next_pos); + } } } @@ -5420,14 +5211,14 @@ pt_make_set_access_spec (REGU_VARIABLE * set_expr, ACCESS_METHOD access, INDX_IN * ACCESS_SPEC_TYPE TARGET_METHOD structure * return: * xasl(in): - * method_sig_list(in): + * sig_array(in): * access(in): * indexptr(in): * where_pred(in): * attr_list(in): */ static ACCESS_SPEC_TYPE * -pt_make_cselect_access_spec (XASL_NODE * xasl, METHOD_SIG_LIST * method_sig_list, ACCESS_METHOD access, +pt_make_cselect_access_spec (XASL_NODE * xasl, PL_SIGNATURE_ARRAY_TYPE * sig_array, ACCESS_METHOD access, INDX_INFO * indexptr, PRED_EXPR * where_pred, REGU_VARIABLE_LIST attr_list) { ACCESS_SPEC_TYPE *spec; @@ -5443,7 +5234,7 @@ pt_make_cselect_access_spec (XASL_NODE * xasl, METHOD_SIG_LIST * method_sig_list { spec->s.method_node.method_regu_list = attr_list; spec->s.method_node.xasl_node = xasl; - spec->s.method_node.method_sig_list = method_sig_list; + spec->s.method_node.sig_array = sig_array; } return spec; @@ -6846,6 +6637,58 @@ pt_make_function (PARSER_CONTEXT * parser, int function_code, const REGU_VARIABL } +/* + * pt_stored_procedure_to_regu () - takes a PT_METHOD_CALL and converts to a regu_variable + * return: A NULL return indicates an error occurred + * parser(in): + * function(in/out): + * + */ +static REGU_VARIABLE * +pt_stored_procedure_to_regu (PARSER_CONTEXT * parser, PT_NODE * node) +{ + int error = NO_ERROR; + REGU_VARIABLE *regu = NULL; + REGU_VARIABLE_LIST args; + SP_TYPE *sp = NULL; + + regu_alloc (regu); + if (!regu) + { + return NULL; + } + + regu_alloc (regu->value.sp_ptr); + + sp = regu->value.sp_ptr; + if (sp) + { + error = jsp_make_pl_signature (parser, node, NULL, *(sp->sig)); + if (error != NO_ERROR) + { + return NULL; + } + + PT_NODE *default_next_node_list = jsp_get_default_expr_node_list (parser, *(sp->sig)); + node->info.method_call.arg_list = parser_append_node (default_next_node_list, node->info.method_call.arg_list); + + DB_TYPE result_type = (DB_TYPE) sp->sig->result_type; + if (result_type == DB_TYPE_RESULTSET) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0); + return NULL; + } + + regu_dbval_type_init (sp->value, result_type); + sp->args = pt_to_regu_variable_list (parser, node->info.method_call.arg_list, UNBOX_AS_VALUE, NULL, NULL); + } + + regu->type = TYPE_SP; + regu->domain = pt_xasl_node_to_domain (parser, node); + + return regu; +} + /* * pt_function_to_regu () - takes a PT_FUNCTION and converts to a regu_variable * return: A NULL return indicates an error occurred @@ -7729,11 +7572,24 @@ pt_to_regu_variable (PARSER_CONTEXT * parser, PT_NODE * node, UNBOX unbox) */ /* a method call that can be evaluated as a constant expression. */ - regu_alloc (val); - pt_evaluate_tree (parser, node, val, 1); - if (!pt_has_error (parser)) + if (PT_IS_METHOD (node)) { - regu = pt_make_regu_constant (parser, val, pt_node_to_db_type (node), node); + /* a method call that can be evaluated as a constant expression. */ + regu_alloc (val); + pt_evaluate_tree (parser, node, val, 1); + if (!pt_has_error (parser)) + { + regu = pt_make_regu_constant (parser, val, pt_node_to_db_type (node), node); + } + } + else + { + regu = pt_stored_procedure_to_regu (parser, node); + if (regu == NULL) + { + PT_ERRORc (parser, node, er_msg ()); + } + return regu; } break; @@ -10874,11 +10730,12 @@ pt_to_list_key (PARSER_CONTEXT * parser, PT_NODE ** term_exprs, int nterms, bool { /* PT_IS_IN or PT_EQ_SOME */ - if (rhs->node_type == PT_FUNCTION) + if (rhs->node_type == PT_FUNCTION || rhs->node_type == PT_METHOD_CALL) { /* PT_FUNCTION */ + elem = (rhs->node_type == PT_FUNCTION) ? rhs->info.function.arg_list : rhs->info.method_call.arg_list; - for (j = 0, elem = rhs->info.function.arg_list; j < n_elem && elem; j++, elem = elem->next) + for (j = 0; j < n_elem && elem; j++, elem = elem->next) { regu_var_list[j] = pt_to_regu_variable (parser, elem, UNBOX_AS_VALUE); @@ -12907,30 +12764,42 @@ pt_to_cselect_table_spec_list (PARSER_CONTEXT * parser, PT_NODE * spec, PT_NODE XASL_NODE *subquery_proc; REGU_VARIABLE_LIST regu_attributes; ACCESS_SPEC_TYPE *access; - METHOD_SIG_LIST *method_sig_list; + PL_SIGNATURE_ARRAY_TYPE *sig_array; + int idx = 0; /* every cselect must have a subquery for its source list file, this is pointed to by the methods of the cselect */ - if (!cselect || !(cselect->node_type == PT_METHOD_CALL) || !src_derived_tbl || !PT_SPEC_IS_DERIVED (src_derived_tbl)) + if (!cselect || !(PT_IS_METHOD (cselect)) || !src_derived_tbl || !PT_SPEC_IS_DERIVED (src_derived_tbl)) { return NULL; } subquery_proc = (XASL_NODE *) src_derived_tbl->info.spec.derived_table->info.query.xasl; - method_sig_list = pt_to_method_sig_list (parser, cselect, src_derived_tbl->info.spec.as_attr_list); - if (method_sig_list == NULL) + regu_new (sig_array, pt_length_of_list (cselect)); + if (sig_array == NULL) { return NULL; } + + for (PT_NODE * node = cselect; node != NULL; node = node->next) + { + int error = jsp_make_pl_signature (parser, node, src_derived_tbl->info.spec.as_attr_list, sig_array->sigs[idx]); + if (error != NO_ERROR) + { + regu_delete (sig_array); + return NULL; + } + idx++; + } + /* This generates a list of TYPE_POSITION regu_variables There information is stored in a QFILE_TUPLE_VALUE_POSITION, * which describes a type and index into a list file. */ - regu_attributes = pt_to_position_regu_variable_list (parser, spec->info.spec.as_attr_list, NULL, NULL); access = - pt_make_cselect_access_spec (subquery_proc, method_sig_list, ACCESS_METHOD_SEQUENTIAL, NULL, NULL, regu_attributes); + pt_make_cselect_access_spec (subquery_proc, sig_array, ACCESS_METHOD_SEQUENTIAL, NULL, NULL, regu_attributes); - if (access && subquery_proc && method_sig_list && (regu_attributes || !spec->info.spec.as_attr_list)) + if (access && subquery_proc && sig_array && (regu_attributes || !spec->info.spec.as_attr_list)) { return access; } @@ -23197,6 +23066,32 @@ pt_get_var_regu_variable_p_list (const REGU_VARIABLE * regu, bool is_prior, int } break; + case TYPE_SP: + { + REGU_VARIABLE_LIST r = regu->value.sp_ptr->args; + while (r) + { + list1 = pt_get_var_regu_variable_p_list (&r->value, is_prior, err); + + if (!list) + { + list = list1; + } + else + { + list2 = list; + while (list2->next) + { + list2 = list2->next; + } + list2->next = list1; + } + + r = r->next; + } + } + break; + default: break; } @@ -27749,6 +27644,8 @@ pt_make_sq_cache_key_struct (QPROC_DB_VALUE_LIST key_struct, void *p, int type) case TYPE_CLASSOID: case TYPE_REGUVAL_LIST: case TYPE_REGU_VAR_LIST: + + case TYPE_SP: /* Result Cache not supported */ return ER_FAILED; break; diff --git a/src/parser/xasl_regu_alloc.cpp b/src/parser/xasl_regu_alloc.cpp index b5dc2f6d81..607f6a8316 100644 --- a/src/parser/xasl_regu_alloc.cpp +++ b/src/parser/xasl_regu_alloc.cpp @@ -194,7 +194,7 @@ regu_spec_target_init (access_spec_node &spec, TARGET_TYPE type) case TARGET_METHOD: ACCESS_SPEC_METHOD_REGU_LIST (&spec) = NULL; ACCESS_SPEC_XASL_NODE (&spec) = NULL; - ACCESS_SPEC_METHOD_SIG_LIST (&spec) = NULL; + ACCESS_SPEC_METHOD_SIG_ARRAY (&spec) = NULL; break; case TARGET_JSON_TABLE: ACCESS_SPEC_JSON_TABLE_REGU_VAR (&spec) = NULL; @@ -280,6 +280,21 @@ regu_init (arith_list_node &arith) regu_alloc (arith.value); } +void +regu_init (cubxasl::sp_node &sp) +{ + sp.args = NULL; + sp.sig = NULL; + + regu_alloc (sp.value); + + regu_alloc (sp.sig); + if (sp.sig) + { + new (sp.sig) PL_SIGNATURE_TYPE (); + } +} + void regu_init (function_node &fnode) { diff --git a/src/parser/xasl_regu_alloc.hpp b/src/parser/xasl_regu_alloc.hpp index 1cdd07a551..22a566c3df 100644 --- a/src/parser/xasl_regu_alloc.hpp +++ b/src/parser/xasl_regu_alloc.hpp @@ -72,6 +72,7 @@ void regu_init (upddel_class_info &upddel); void regu_init (update_assignment &assign); void regu_init (arith_list_node &arith); void regu_init (function_node &fnode); +void regu_init (cubxasl::sp_node &sp); void regu_init (cubxasl::aggregate_list_node &agg); void regu_init (cubxasl::analytic_list_node &ana); void regu_init (xasl_node &node); @@ -85,6 +86,12 @@ void regu_alloc (T *&ptr); template void regu_array_alloc (T **ptr, size_t size); +template +void regu_new (T *&ptr, Args &&... args); + +template +void regu_delete (T *&ptr); + /* for regu_machead_array () */ int *regu_int_array_alloc (int size); OID *regu_oid_array_alloc (int size); @@ -120,6 +127,26 @@ regu_alloc (T *&ptr) regu_init (*ptr); } +template +void +regu_new (T *&ptr, Args &&... args) +{ + ptr = reinterpret_cast (pt_alloc_packing_buf ((int) sizeof (T))); + if (ptr == NULL) + { + regu_set_error_with_zero_args (ER_REGU_NO_SPACE); + return; + } + new (ptr) T (std::forward (args)...); +} + +template +void +regu_delete (T *&ptr) +{ + ptr->~T (); // call destructor, placement new in regu_new () +} + template void regu_array_alloc (T **ptr, size_t size) diff --git a/src/query/execute_schema.c b/src/query/execute_schema.c index c4e312eef3..df268c651c 100644 --- a/src/query/execute_schema.c +++ b/src/query/execute_schema.c @@ -59,6 +59,9 @@ #include "xasl_to_stream.h" #include "parser_support.h" #include "dbtype.h" +#include "jsp_cl.h" +#include "msgcat_glossary.hpp" +#include "authenticate_access_auth.hpp" #if defined (SUPPRESS_STRLEN_WARNING) #define strlen(s1) ((int) strlen(s1)) @@ -1749,7 +1752,7 @@ do_grant (const PARSER_CONTEXT * parser, const PT_NODE * statement) DB_OBJECT *user_obj, *class_mop; PT_NODE *auth_cmd_list, *auth_list, *auth; DB_AUTH db_auth; - PT_NODE *spec_list, *s_list, *spec; + PT_NODE *spec_list; PT_NODE *entity_list, *entity; int grant_option; bool set_savepoint = false; @@ -1791,27 +1794,55 @@ do_grant (const PARSER_CONTEXT * parser, const PT_NODE * statement) { db_auth = pt_auth_to_db_auth (auth); - s_list = spec_list; - for (spec = s_list; spec != NULL; spec = spec->next) + if (auth->info.auth_cmd.auth_cmd == PT_EXECUTE_PROCEDURE_PRIV) { - entity_list = spec->info.spec.flat_entity_list; - for (entity = entity_list; entity != NULL; entity = entity->next) + // NOTE: db_auth is always DB_AUTH_EXECUTE + assert (db_auth == DB_AUTH_EXECUTE); + + PT_NODE *p_list = spec_list; + for (PT_NODE * procs = p_list; procs != NULL; procs = procs->next) { - class_mop = db_find_class (entity->info.name.original); - if (class_mop == NULL) + // [TODO] Resovle user schema name, built-in package name + const char *proc_name = procs->info.name.original; + + MOP proc_mop = jsp_find_stored_procedure (proc_name, DB_AUTH_NONE); + if (proc_mop == NULL) { assert (er_errid () != NO_ERROR); error = er_errid (); goto end; } - error = db_grant (user_obj, class_mop, db_auth, grant_option); + error = db_grant_object (DB_OBJECT_PROCEDURE, user_obj, proc_mop, db_auth, grant_option); if (error != NO_ERROR) { goto end; } } } + else + { + for (PT_NODE * spec = spec_list; spec != NULL; spec = spec->next) + { + entity_list = spec->info.spec.flat_entity_list; + for (entity = entity_list; entity != NULL; entity = entity->next) + { + class_mop = db_find_class (entity->info.name.original); + if (class_mop == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + error = db_grant_object (DB_OBJECT_CLASS, user_obj, class_mop, db_auth, grant_option); + if (error != NO_ERROR) + { + goto end; + } + } + } + } } } @@ -1871,27 +1902,56 @@ do_revoke (const PARSER_CONTEXT * parser, const PT_NODE * statement) { db_auth = pt_auth_to_db_auth (auth); - s_list = spec_list; - for (spec = s_list; spec != NULL; spec = spec->next) + if (auth->info.auth_cmd.auth_cmd == PT_EXECUTE_PROCEDURE_PRIV) { - entity_list = spec->info.spec.flat_entity_list; - for (entity = entity_list; entity != NULL; entity = entity->next) + // NOTE: db_auth is always DB_AUTH_EXECUTE + assert (db_auth == DB_AUTH_EXECUTE); + + PT_NODE *p_list = spec_list; + for (PT_NODE * procs = p_list; procs != NULL; procs = procs->next) { - class_mop = db_find_class (entity->info.name.original); - if (class_mop == NULL) + // [TODO] Resovle user schema name, built-in package name + const char *proc_name = procs->info.name.original; + + MOP proc_mop = jsp_find_stored_procedure (proc_name, DB_AUTH_NONE); + if (proc_mop == NULL) { assert (er_errid () != NO_ERROR); error = er_errid (); goto end; } - error = db_revoke (user_obj, class_mop, db_auth); + // TODO: In CBRD-24912, GRANT/REVOKE for stored procedure is implemented, the following will be processed properly + error = db_revoke_object (DB_OBJECT_PROCEDURE, user_obj, proc_mop, db_auth); if (error != NO_ERROR) { goto end; } } } + else + { + for (PT_NODE * spec = spec_list; spec != NULL; spec = spec->next) + { + entity_list = spec->info.spec.flat_entity_list; + for (entity = entity_list; entity != NULL; entity = entity->next) + { + class_mop = db_find_class (entity->info.name.original); + if (class_mop == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + goto end; + } + + error = db_revoke_object (DB_OBJECT_CLASS, user_obj, class_mop, db_auth); + if (error != NO_ERROR) + { + goto end; + } + } + } + } } } @@ -2258,7 +2318,7 @@ do_alter_user (const PARSER_CONTEXT * parser, const PT_NODE * statement) if (!ws_is_same_object (user, Au_user) && !au_is_dba_group_member (Au_user)) { error = ER_AU_NOT_OWNER; - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, MSGCAT_GET_GLOSSARY_MSG (MSGCAT_GLOSSARY_CLASS)); goto end; } @@ -10115,9 +10175,10 @@ do_alter_change_owner (PARSER_CONTEXT * const parser, PT_NODE * const alter) { int error = NO_ERROR; DB_OBJECT *obj = NULL; - MOP class_mop, user_mop; + MOP class_mop, user_mop, save_user, owner; PT_NODE *class_, *user; SM_CLASS *sm_class = NULL; + const char *table_name; assert (alter != NULL); @@ -10141,6 +10202,13 @@ do_alter_change_owner (PARSER_CONTEXT * const parser, PT_NODE * const alter) return error; } + table_name = sm_get_ch_name (class_mop); + if (table_name == NULL) + { + ASSERT_ERROR_AND_SET (error); + return error; + } + /* To change the owner of a system class is not allowed. */ if (sm_issystem (sm_class)) { @@ -10148,6 +10216,28 @@ do_alter_change_owner (PARSER_CONTEXT * const parser, PT_NODE * const alter) return error; } + /* when changing the owner, all privileges are revoked */ + owner = au_get_class_owner (class_mop); + if (owner == NULL) + { + assert (er_errid () != NO_ERROR); + error = er_errid (); + return error; + } + + save_user = Au_user; + if (AU_SET_USER (owner) == NO_ERROR) + { + error = au_object_revoke_all_privileges (DB_OBJECT_CLASS, owner, table_name); + if (error != NO_ERROR) + { + AU_SET_USER (save_user); + return error; + } + } + + AU_SET_USER (save_user); + user_mop = au_find_user (user->info.name.original); if (user_mop == NULL) { diff --git a/src/query/execute_statement.c b/src/query/execute_statement.c index a554d8eaf2..e533f0d00b 100644 --- a/src/query/execute_statement.c +++ b/src/query/execute_statement.c @@ -20250,6 +20250,98 @@ do_find_synonym_by_query (const char *name, char *buf, int buf_size) #undef QUERY_BUF_SIZE } +int +do_find_stored_procedure_by_query (const char *name, char *buf, int buf_size) +{ +#define QUERY_BUF_SIZE 2048 + DB_QUERY_RESULT *query_result = NULL; + DB_QUERY_ERROR query_error; + DB_VALUE value; + const char *query = NULL; + char query_buf[QUERY_BUF_SIZE] = { '\0' }; + const char *current_schema_name = NULL; + const char *sp_name = NULL; + int error = NO_ERROR; + + db_make_null (&value); + query_error.err_lineno = 0; + query_error.err_posno = 0; + + if (name == NULL || name[0] == '\0') + { + ERROR_SET_WARNING (error, ER_OBJ_INVALID_ARGUMENTS); + return error; + } + + assert (buf != NULL); + + current_schema_name = sc_current_schema_name (); + + sp_name = sm_remove_qualifier_name (name); + query = "SELECT [unique_name] FROM [%s] WHERE [sp_name] = '%s' AND [owner].[name] != UPPER ('%s')"; + assert (QUERY_BUF_SIZE > snprintf (NULL, 0, query, CT_STORED_PROC_NAME, sp_name, current_schema_name)); + snprintf (query_buf, QUERY_BUF_SIZE, query, CT_STORED_PROC_NAME, sp_name, current_schema_name); + assert (query_buf[0] != '\0'); + + error = db_compile_and_execute_local (query_buf, &query_result, &query_error); + if (error < NO_ERROR) + { + ASSERT_ERROR (); + goto end; + } + + error = db_query_first_tuple (query_result); + if (error != DB_CURSOR_SUCCESS) + { + if (error == DB_CURSOR_END) + { + ERROR_SET_WARNING_1ARG (error, ER_SP_NOT_EXIST, name); + } + else + { + ASSERT_ERROR (); + } + + goto end; + } + + error = db_query_get_tuple_value (query_result, 0, &value); + if (error != NO_ERROR) + { + ASSERT_ERROR (); + goto end; + } + + if (!DB_IS_NULL (&value)) + { + assert (strlen (db_get_string (&value)) < buf_size); + strcpy (buf, db_get_string (&value)); + } + else + { + /* unique_name must not be null. */ + ASSERT_ERROR_AND_SET (error); + goto end; + } + + error = db_query_next_tuple (query_result); + if (error != DB_CURSOR_END) + { + /* No result can be returned because unique_name is not unique. */ + buf[0] = '\0'; + } + +end: + if (query_result) + { + db_query_end (query_result); + query_result = NULL; + } + + return error; +#undef QUERY_BUF_SIZE +} + /* * do_set_trace_to_query_flag() - * return: void diff --git a/src/query/execute_statement.h b/src/query/execute_statement.h index d7d2863f17..31c14f4de2 100644 --- a/src/query/execute_statement.h +++ b/src/query/execute_statement.h @@ -207,4 +207,5 @@ extern int do_find_class_by_query (const char *name, char *buf, int buf_size); extern int do_find_serial_by_query (const char *name, char *buf, int buf_size); extern int do_find_trigger_by_query (const char *name, char *buf, int buf_size); extern int do_find_synonym_by_query (const char *name, char *buf, int buf_size); +extern int do_find_stored_procedure_by_query (const char *name, char *buf, int buf_size); #endif /* _EXECUTE_STATEMENT_H_ */ diff --git a/src/query/fetch.c b/src/query/fetch.c index d78d38d411..0d6ee6914f 100644 --- a/src/query/fetch.c +++ b/src/query/fetch.c @@ -54,6 +54,7 @@ #include "query_executor.h" #include "thread_entry.hpp" #include "subquery_cache.h" +#include "pl_executor.hpp" #include "dbtype.h" // XXX: SHOULD BE THE LAST INCLUDE HEADER @@ -4023,6 +4024,30 @@ fetch_peek_dbval (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var, val_descr * || REGU_VARIABLE_IS_FLAGED (regu_var, REGU_VARIABLE_FETCH_NOT_CONST)); break; + case TYPE_SP: /* fetch stored procedure value */ + { + /* clear any value from a previous iteration */ + pr_clear_value (regu_var->value.sp_ptr->value); + fetch_force_not_const_recursive (*regu_var); + + cubpl::executor executor (*regu_var->value.sp_ptr->sig); + + error = executor.fetch_args_peek (regu_var->value.sp_ptr->args, vd, obj_oid, tpl); + if (error != NO_ERROR) + { + goto exit_on_error; + } + + error = executor.execute (*regu_var->value.sp_ptr->value); + if (error != NO_ERROR) + { + goto exit_on_error; + } + + *peek_dbval = regu_var->value.sp_ptr->value; + } + break; + case TYPE_FUNC: /* fetch function value */ if (REGU_VARIABLE_IS_FLAGED (regu_var, REGU_VARIABLE_FETCH_ALL_CONST)) { @@ -4957,6 +4982,7 @@ fetch_force_not_const_recursive (REGU_VARIABLE & reguvar) case TYPE_INARITH: case TYPE_OUTARITH: case TYPE_FUNC: + case TYPE_SP: REGU_VARIABLE_SET_FLAG (®u, REGU_VARIABLE_FETCH_NOT_CONST); break; default: diff --git a/src/query/query_dump.c b/src/query/query_dump.c index 64b3d873a3..e982654655 100644 --- a/src/query/query_dump.c +++ b/src/query/query_dump.c @@ -1145,6 +1145,8 @@ qdump_regu_type_string (REGU_DATATYPE type) return "TYPE_REGUVAL_LIST"; case TYPE_REGU_VAR_LIST: return "TYPE_REGU_VAR_LIST"; + case TYPE_SP: + return "TYPE_SP"; default: return "undefined"; } @@ -1357,6 +1359,13 @@ qdump_print_value (REGU_VARIABLE * value_p) qdump_print_function_value (value_p); return true; + case TYPE_SP: + fprintf (foutput, "[TYPE_SP]"); + fprintf (foutput, "[%s]", value_p->value.sp_ptr->sig->name); + fprintf (foutput, "args-->"); + qdump_print_regu_variable_list (value_p->value.sp_ptr->args); + return true; + default: return true; } diff --git a/src/query/query_executor.c b/src/query/query_executor.c index 3e91c06943..b2200099d3 100644 --- a/src/query/query_executor.c +++ b/src/query/query_executor.c @@ -1590,6 +1590,15 @@ qexec_clear_regu_var (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, REGU_VARIABLE case TYPE_OUTARITH: pg_cnt += qexec_clear_arith_list (thread_p, xasl_p, regu_var->value.arithptr, is_final); break; + case TYPE_SP: + pr_clear_value (regu_var->value.sp_ptr->value); + pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, regu_var->value.sp_ptr->args, is_final); + if (is_final) + { + delete regu_var->value.sp_ptr->sig; + regu_var->value.sp_ptr->sig = nullptr; + } + break; case TYPE_FUNC: pr_clear_value (regu_var->value.funcp->value); pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, regu_var->value.funcp->operand, is_final); @@ -2101,6 +2110,11 @@ qexec_clear_access_spec_list (THREAD_ENTRY * thread_p, XASL_NODE * xasl_p, ACCES break; case TARGET_METHOD: pg_cnt += qexec_clear_regu_list (thread_p, xasl_p, p->s.method_node.method_regu_list, is_final); + if (is_final) + { + delete p->s.method_node.sig_array; + p->s.method_node.sig_array = NULL; + } break; case TARGET_REGUVAL_LIST: break; @@ -9326,7 +9340,7 @@ qexec_open_scan (THREAD_ENTRY * thread_p, ACCESS_SPEC_TYPE * curr_spec, VAL_LIST case TARGET_METHOD: error_code = scan_open_method_scan (thread_p, s_id, grouped, curr_spec->single_fetch, curr_spec->s_dbval, val_list, vd, - ACCESS_SPEC_METHOD_LIST_ID (curr_spec), ACCESS_SPEC_METHOD_SIG_LIST (curr_spec)); + ACCESS_SPEC_METHOD_LIST_ID (curr_spec), ACCESS_SPEC_METHOD_SIG_ARRAY (curr_spec)); if (error_code != NO_ERROR) { ASSERT_ERROR (); @@ -10155,6 +10169,10 @@ qexec_reset_regu_variable (REGU_VARIABLE * var) qexec_reset_regu_variable (var->value.arithptr->thirdptr); /* use arithptr */ break; + case TYPE_SP: + /* use sp_ptr */ + qexec_reset_regu_variable_list (var->value.sp_ptr->args); + break; case TYPE_FUNC: /* use funcp */ qexec_reset_regu_variable_list (var->value.funcp->operand); @@ -18854,6 +18872,17 @@ qexec_replace_prior_regu_vars_prior_expr (THREAD_ENTRY * thread_p, regu_variable qexec_replace_prior_regu_vars_prior_expr (thread_p, regu->value.arithptr->thirdptr, xasl, connect_by_ptr); break; + case TYPE_SP: + { + REGU_VARIABLE_LIST r = regu->value.sp_ptr->args; + while (r) + { + qexec_replace_prior_regu_vars_prior_expr (thread_p, &r->value, xasl, connect_by_ptr); + r = r->next; + } + } + break; + case TYPE_FUNC: { REGU_VARIABLE_LIST r = regu->value.funcp->operand; @@ -18901,6 +18930,17 @@ qexec_replace_prior_regu_vars (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu, XA } break; + case TYPE_SP: + { + REGU_VARIABLE_LIST r = regu->value.sp_ptr->args; + while (r) + { + qexec_replace_prior_regu_vars (thread_p, &r->value, xasl); + r = r->next; + } + } + break; + case TYPE_FUNC: { REGU_VARIABLE_LIST r = regu->value.funcp->operand; diff --git a/src/query/regu_var.cpp b/src/query/regu_var.cpp index 9103a55a8b..13e5f91433 100644 --- a/src/query/regu_var.cpp +++ b/src/query/regu_var.cpp @@ -65,6 +65,19 @@ regu_variable_node::map_regu (const map_regu_func_type &func, bool &stop) map_regu_not_null_and_check_stop (value.arithptr->rightptr); break; + case TYPE_SP: + if (value.sp_ptr == NULL) + { + assert (false); + return; + } + + for (regu_variable_list_node *arg = value.sp_ptr->args; arg != NULL; arg = arg->next) + { + map_regu_and_check_stop (&arg->value); + } + break; + case TYPE_FUNC: if (value.funcp == NULL) { @@ -143,6 +156,11 @@ regu_variable_node::clear_xasl_local () } break; + case TYPE_SP: + assert (value.sp_ptr != NULL); + pr_clear_value (value.sp_ptr->value); + break; + case TYPE_FUNC: assert (value.funcp != NULL); pr_clear_value (value.funcp->value); diff --git a/src/query/regu_var.hpp b/src/query/regu_var.hpp index 7311335fba..537138d03e 100644 --- a/src/query/regu_var.hpp +++ b/src/query/regu_var.hpp @@ -29,6 +29,7 @@ #include "string_opfunc.h" #include "object_primitive.h" #include "db_function.hpp" +#include "xasl_sp.hpp" #include @@ -58,7 +59,8 @@ typedef enum TYPE_CLASSOID, /* does not have corresponding field use current class identifier value */ TYPE_FUNC, /* use funcp */ TYPE_REGUVAL_LIST, /* use reguval_list */ - TYPE_REGU_VAR_LIST /* use regu_variable_list for 'CUME_DIST' and 'PERCENT_RANK' */ + TYPE_REGU_VAR_LIST, /* use regu_variable_list for 'CUME_DIST' and 'PERCENT_RANK' */ + TYPE_SP /* use sp_ptr */ } REGU_DATATYPE; /* declare ahead REGU_VARIABLE */ @@ -192,6 +194,7 @@ class regu_variable_node struct function_node *funcp; /* function */ REGU_VALUE_LIST *reguval_list; /* for "values" query */ REGU_VARIABLE_LIST regu_var_list; /* for CUME_DIST and PERCENT_RANK */ + cubxasl::sp_node *sp_ptr; /* stored procedure */ } value; regu_variable_node () = default; diff --git a/src/query/scan_manager.c b/src/query/scan_manager.c index 51400b0fb2..59825007c3 100644 --- a/src/query/scan_manager.c +++ b/src/query/scan_manager.c @@ -4022,7 +4022,7 @@ scan_open_method_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list, VAL_DESCR * vd, /* */ - QFILE_LIST_ID * list_id, method_sig_list * meth_sig_list) + QFILE_LIST_ID * list_id, PL_SIGNATURE_ARRAY_TYPE * sig_array) { /* scan type is METHOD SCAN */ scan_id->type = S_METHOD_SCAN; @@ -4031,7 +4031,7 @@ scan_open_method_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, /* mvcc_select_lock_needed = false, fixed = true */ scan_init_scan_id (scan_id, false, S_SELECT, true, grouped, single_fetch, join_dbval, val_list, vd); - int error = scan_id->s.msid.init (thread_p, meth_sig_list, list_id); + int error = scan_id->s.msid.init (thread_p, sig_array, list_id); if (error == NO_ERROR) { error = scan_id->s.msid.open (); @@ -5216,6 +5216,8 @@ scan_next_heap_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id) regu_variable_list_node *p; hsidp = &scan_id->s.hsid; + p_current_oid = &hsidp->curr_oid; + if (scan_id->mvcc_select_lock_needed) { COPY_OID (¤t_oid, &hsidp->curr_oid); diff --git a/src/query/scan_manager.h b/src/query/scan_manager.h index a5e930600d..2835399521 100644 --- a/src/query/scan_manager.h +++ b/src/query/scan_manager.h @@ -52,7 +52,6 @@ struct indx_info; typedef struct indx_info INDX_INFO; struct key_range; struct key_val_range; -struct method_sig_list; struct regu_variable_list_node; struct val_descr; @@ -475,7 +474,7 @@ extern int scan_open_method_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, int grouped, QPROC_SINGLE_FETCH single_fetch, DB_VALUE * join_dbval, val_list_node * val_list, val_descr * vd, /* */ - QFILE_LIST_ID * list_id, method_sig_list * meth_sig_list); + QFILE_LIST_ID * list_id, PL_SIGNATURE_ARRAY_TYPE * meth_sig_list); extern int scan_open_dblink_scan (THREAD_ENTRY * thread_p, SCAN_ID * scan_id, struct access_spec_node *spec, diff --git a/src/query/stream_to_xasl.c b/src/query/stream_to_xasl.c index 8227b1a2c1..cbe98f4c96 100644 --- a/src/query/stream_to_xasl.c +++ b/src/query/stream_to_xasl.c @@ -42,11 +42,14 @@ #include "xasl_predicate.hpp" #include "xasl_stream.hpp" #include "xasl_unpack_info.hpp" +#include "pl_signature.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" static ACCESS_SPEC_TYPE *stx_restore_access_spec_type (THREAD_ENTRY * thread_p, char **ptr, void *arg); static AGGREGATE_TYPE *stx_restore_aggregate_type (THREAD_ENTRY * thread_p, char *ptr); +static SP_TYPE *stx_restore_sp_type (THREAD_ENTRY * thread_p, char *ptr); static FUNCTION_TYPE *stx_restore_function_type (THREAD_ENTRY * thread_p, char *ptr); static ANALYTIC_TYPE *stx_restore_analytic_type (THREAD_ENTRY * thread_p, char *ptr); static ANALYTIC_EVAL_TYPE *stx_restore_analytic_eval_type (THREAD_ENTRY * thread_p, char *ptr); @@ -76,8 +79,10 @@ static HEAP_CACHE_ATTRINFO *stx_restore_cache_attrinfo (THREAD_ENTRY * thread_p, static DB_VALUE **stx_restore_db_value_array_extra (THREAD_ENTRY * thread_p, char *ptr, int size, int total_size); static int *stx_restore_int_array (THREAD_ENTRY * thread_p, char *ptr, int size); static OID *stx_restore_OID_array (THREAD_ENTRY * thread_p, char *ptr, int size); -static METHOD_SIG_LIST *stx_restore_method_sig_list (THREAD_ENTRY * thread_p, char *ptr); -static METHOD_SIG *stx_restore_method_sig (THREAD_ENTRY * thread_p, char *ptr, int size); + +static PL_SIGNATURE_ARRAY_TYPE *stx_restore_pl_sig_array (THREAD_ENTRY * thread_p, char *ptr); +static PL_SIGNATURE_TYPE *stx_restore_pl_sig (THREAD_ENTRY * thread_p, char *ptr); + static KEY_RANGE *stx_restore_key_range_array (THREAD_ENTRY * thread_p, char *ptr, int size); static char *stx_build_xasl_node (THREAD_ENTRY * thread_p, char *tmp, XASL_NODE * ptr); @@ -87,8 +92,10 @@ static char *stx_build_func_pred (THREAD_ENTRY * thread_p, char *tmp, FUNC_PRED static char *stx_build_cache_attrinfo (char *tmp); static char *stx_build_list_id (THREAD_ENTRY * thread_p, char *tmp, QFILE_LIST_ID * ptr); static char *stx_build_sub_xasl_id (THREAD_ENTRY * thread_p, char *tmp, XASL_ID * ptr); -static char *stx_build_method_sig_list (THREAD_ENTRY * thread_p, char *tmp, METHOD_SIG_LIST * ptr); -static char *stx_build_method_sig (THREAD_ENTRY * thread_p, char *tmp, METHOD_SIG * ptr, int size); + +static char *stx_build_pl_sig (THREAD_ENTRY * thread_p, char *ptr, PL_SIGNATURE_TYPE * sig); +static char *stx_build_pl_sig_array (THREAD_ENTRY * thread_p, char *ptr, PL_SIGNATURE_ARRAY_TYPE * sig_array); + static char *stx_build_union_proc (THREAD_ENTRY * thread_p, char *tmp, UNION_PROC_NODE * ptr); static char *stx_build_fetch_proc (THREAD_ENTRY * thread_p, char *tmp, FETCH_PROC_NODE * ptr); static char *stx_build_buildlist_proc (THREAD_ENTRY * thread_p, char *tmp, BUILDLIST_PROC_NODE * ptr); @@ -140,6 +147,7 @@ static char *stx_build_srlist_id (THREAD_ENTRY * thread_p, char *tmp, QFILE_SORT static char *stx_build_sort_list (THREAD_ENTRY * thread_p, char *tmp, SORT_LIST * ptr); static char *stx_build_connectby_proc (THREAD_ENTRY * thread_p, char *tmp, CONNECTBY_PROC_NODE * ptr); static char *stx_build_sq_cache (THREAD_ENTRY * thread_p, char *ptr, SQ_CACHE ** sq_cache_p); +static char *stx_build_sp_type (THREAD_ENTRY * thread_p, char *tmp, SP_TYPE * ptr); static REGU_VALUE_LIST *stx_regu_value_list_alloc_and_init (THREAD_ENTRY * thread_p); static REGU_VALUE_ITEM *stx_regu_value_item_alloc_and_init (THREAD_ENTRY * thread_p); @@ -424,6 +432,37 @@ stx_restore_aggregate_type (THREAD_ENTRY * thread_p, char *ptr) return aggregate; } +static SP_TYPE * +stx_restore_sp_type (THREAD_ENTRY * thread_p, char *ptr) +{ + SP_TYPE *sp; + + if (ptr == NULL) + { + return NULL; + } + + sp = (SP_TYPE *) stx_get_struct_visited_ptr (thread_p, ptr); + if (sp != NULL) + { + return sp; + } + + sp = (SP_TYPE *) stx_alloc_struct (thread_p, sizeof (*sp)); + if (sp == NULL) + { + stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); + return NULL; + } + + if (stx_mark_struct_visited (thread_p, ptr, sp) == ER_FAILED || stx_build_sp_type (thread_p, ptr, sp) == NULL) + { + return NULL; + } + + return sp; +} + static FUNCTION_TYPE * stx_restore_function_type (THREAD_ENTRY * thread_p, char *ptr) { @@ -1198,74 +1237,82 @@ stx_restore_list_id (THREAD_ENTRY * thread_p, char *ptr) } /* - * stx_restore_method_sig_list () - + * stx_restore_pl_sig () - * - * Note: do not use or_unpack_method_sig_list () */ -static METHOD_SIG_LIST * -stx_restore_method_sig_list (THREAD_ENTRY * thread_p, char *ptr) +static PL_SIGNATURE_TYPE * +stx_restore_pl_sig (THREAD_ENTRY * thread_p, char *ptr) { - METHOD_SIG_LIST *method_sig_list; + PL_SIGNATURE_TYPE *sig = NULL; if (ptr == NULL) { return NULL; } - method_sig_list = (METHOD_SIG_LIST *) stx_get_struct_visited_ptr (thread_p, ptr); - if (method_sig_list != NULL) + sig = (PL_SIGNATURE_TYPE *) stx_get_struct_visited_ptr (thread_p, ptr); + if (sig != NULL) { - return method_sig_list; + return sig; } - method_sig_list = (METHOD_SIG_LIST *) stx_alloc_struct (thread_p, sizeof (METHOD_SIG_LIST)); - if (method_sig_list == NULL) - { - stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); - return NULL; - } - if (stx_mark_struct_visited (thread_p, ptr, method_sig_list) == ER_FAILED - || stx_build_method_sig_list (thread_p, ptr, method_sig_list) == NULL) + //sig_array = (PL_SIGNATURE_ARRAY_TYPE *) stx_alloc_struct (thread_p, sizeof (PL_SIGNATURE_ARRAY_TYPE)); + //if (sig_array == NULL) + // { + // stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); + // return NULL; + // } + sig = new PL_SIGNATURE_TYPE; + + // new (sig_array) PL_SIGNATURE_ARRAY_TYPE; + + if (stx_mark_struct_visited (thread_p, ptr, sig) == ER_FAILED || stx_build_pl_sig (thread_p, ptr, sig) == NULL) { return NULL; } - return method_sig_list; + return sig; } -static METHOD_SIG * -stx_restore_method_sig (THREAD_ENTRY * thread_p, char *ptr, int count) +/* + * stx_restore_pl_sig_array () - + * + */ +static PL_SIGNATURE_ARRAY_TYPE * +stx_restore_pl_sig_array (THREAD_ENTRY * thread_p, char *ptr) { - METHOD_SIG *method_sig; + PL_SIGNATURE_ARRAY_TYPE *sig_array = NULL; if (ptr == NULL) { - assert (count == 0); return NULL; } - assert (count > 0); - - method_sig = (METHOD_SIG *) stx_get_struct_visited_ptr (thread_p, ptr); - if (method_sig != NULL) + sig_array = (PL_SIGNATURE_ARRAY_TYPE *) stx_get_struct_visited_ptr (thread_p, ptr); + if (sig_array != NULL) { - return method_sig; + return sig_array; } - method_sig = (METHOD_SIG *) stx_alloc_struct (thread_p, sizeof (METHOD_SIG)); - if (method_sig == NULL) +#if 0 + sig_array = (PL_SIGNATURE_ARRAY_TYPE *) stx_alloc_struct (thread_p, sizeof (PL_SIGNATURE_ARRAY_TYPE)); + if (sig_array == NULL) { stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); return NULL; } + new (sig_array) PL_SIGNATURE_ARRAY_TYPE; +#endif + + sig_array = new PL_SIGNATURE_ARRAY_TYPE; - if (stx_mark_struct_visited (thread_p, ptr, method_sig) == ER_FAILED - || stx_build_method_sig (thread_p, ptr, method_sig, count) == NULL) + if (stx_mark_struct_visited (thread_p, ptr, sig_array) == ER_FAILED || + stx_build_pl_sig_array (thread_p, ptr, sig_array) == NULL) { return NULL; } - return method_sig; + return sig_array; } static DB_VALUE ** @@ -2521,129 +2568,30 @@ stx_build_list_id (THREAD_ENTRY * thread_p, char *ptr, QFILE_LIST_ID * listid) return NULL; } +// FIXME: use template static char * -stx_build_method_sig_list (THREAD_ENTRY * thread_p, char *ptr, METHOD_SIG_LIST * method_sig_list) +stx_build_pl_sig (THREAD_ENTRY * thread_p, char *ptr, PL_SIGNATURE_TYPE * sig) { - int offset; - XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p); + int size, offset; - ptr = or_unpack_int (ptr, (int *) &method_sig_list->num_methods); + ptr = or_unpack_int (ptr, (int *) &size); + packing_unpacker unpacker (ptr, size); + unpacker.unpack_all (*sig); - ptr = or_unpack_int (ptr, &offset); - if (offset == 0) - { - method_sig_list->method_sig = NULL; - } - else - { - method_sig_list->method_sig = - stx_restore_method_sig (thread_p, &xasl_unpack_info->packed_xasl[offset], method_sig_list->num_methods); - if (method_sig_list->method_sig == NULL) - { - goto error; - } - } - -#if !defined(NDEBUG) - { - int i = 0; - METHOD_SIG *sig; - - for (sig = method_sig_list->method_sig; sig; sig = sig->next) - { - i++; - } - assert (method_sig_list->num_methods == i); - } -#endif - - return ptr; - -error: - stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); - return NULL; + return (char *) unpacker.get_curr_ptr (); } +// FIXME: use template static char * -stx_build_method_sig (THREAD_ENTRY * thread_p, char *ptr, METHOD_SIG * method_sig, int count) +stx_build_pl_sig_array (THREAD_ENTRY * thread_p, char *ptr, PL_SIGNATURE_ARRAY_TYPE * sig_array) { - int offset; - int num_args, n; - XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p); + int size, offset; - method_sig->method_name = stx_restore_string (thread_p, ptr); - if (method_sig->method_name == NULL) - { - assert (false); - goto error; - } - - ptr = or_unpack_int (ptr, (int *) &method_sig->method_type); - ptr = or_unpack_int (ptr, &method_sig->num_method_args); - - num_args = method_sig->num_method_args + 1; - - method_sig->method_arg_pos = (int *) stx_alloc_struct (thread_p, sizeof (int) * num_args); - if (method_sig->method_arg_pos == NULL) - { - goto error; - } - - for (n = 0; n < num_args; n++) - { - ptr = or_unpack_int (ptr, &(method_sig->method_arg_pos[n])); - } - - if (method_sig->method_type == METHOD_TYPE_JAVA_SP) - { - method_sig->arg_info.arg_mode = (int *) stx_alloc_struct (thread_p, sizeof (int) * method_sig->num_method_args); - if (method_sig->arg_info.arg_mode == NULL) - { - goto error; - } - - method_sig->arg_info.arg_type = (int *) stx_alloc_struct (thread_p, sizeof (int) * method_sig->num_method_args); - if (method_sig->arg_info.arg_type == NULL) - { - goto error; - } + ptr = or_unpack_int (ptr, (int *) &size); + packing_unpacker unpacker (ptr, size); + unpacker.unpack_all (*sig_array); - for (n = 0; n < method_sig->num_method_args; n++) - { - ptr = or_unpack_int (ptr, &method_sig->arg_info.arg_mode[n]); - } - for (n = 0; n < method_sig->num_method_args; n++) - { - ptr = or_unpack_int (ptr, &method_sig->arg_info.arg_type[n]); - } - - ptr = or_unpack_int (ptr, &method_sig->arg_info.result_type); - } - else /* method */ - { - /* is can be null */ - method_sig->class_name = stx_restore_string (thread_p, ptr); - } - - ptr = or_unpack_int (ptr, &offset); - if (offset == 0) - { - method_sig->next = NULL; - } - else - { - method_sig->next = stx_restore_method_sig (thread_p, &xasl_unpack_info->packed_xasl[offset], count - 1); - if (method_sig->next == NULL) - { - goto error; - } - } - - return ptr; - -error: - stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); - return NULL; + return (char *) unpacker.get_curr_ptr (); } static char * @@ -5384,12 +5332,12 @@ stx_build_method_spec_type (THREAD_ENTRY * thread_p, char *ptr, METHOD_SPEC_TYPE ptr = or_unpack_int (ptr, &offset); if (offset == 0) { - method_spec->method_sig_list = NULL; + method_spec->sig_array = NULL; } else { - method_spec->method_sig_list = stx_restore_method_sig_list (thread_p, &xasl_unpack_info->packed_xasl[offset]); - if (method_spec->method_sig_list == NULL) + method_spec->sig_array = stx_restore_pl_sig_array (thread_p, &xasl_unpack_info->packed_xasl[offset]); + if (method_spec->sig_array == NULL) { stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); return NULL; @@ -5709,6 +5657,22 @@ stx_unpack_regu_variable_value (THREAD_ENTRY * thread_p, char *ptr, REGU_VARIABL } break; + case TYPE_SP: + ptr = or_unpack_int (ptr, &offset); + if (offset == 0) + { + regu_var->value.sp_ptr = NULL; + } + else + { + regu_var->value.sp_ptr = stx_restore_sp_type (thread_p, &xasl_unpack_info_p->packed_xasl[offset]); + if (regu_var->value.sp_ptr == NULL) + { + goto error; + } + } + break; + case TYPE_ATTR_ID: case TYPE_SHARED_ATTR_ID: case TYPE_CLASS_ATTR_ID: @@ -6068,6 +6032,62 @@ stx_build_aggregate_type (THREAD_ENTRY * thread_p, char *ptr, AGGREGATE_TYPE * a return NULL; } + +static char * +stx_build_sp_type (THREAD_ENTRY * thread_p, char *ptr, SP_TYPE * sp) +{ + int tmp, offset; + XASL_UNPACK_INFO *xasl_unpack_info = get_xasl_unpack_info_ptr (thread_p); + + ptr = or_unpack_int (ptr, &offset); + if (offset == 0) + { + sp->value = NULL; + } + else + { + sp->value = stx_restore_db_value (thread_p, &xasl_unpack_info->packed_xasl[offset]); + if (sp->value == NULL) + { + stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); + return NULL; + } + assert (sp->value->need_clear == false); + } + + ptr = or_unpack_int (ptr, &offset); + if (offset == 0) + { + sp->args = NULL; + } + else + { + sp->args = stx_restore_regu_variable_list (thread_p, &xasl_unpack_info->packed_xasl[offset]); + if (sp->args == NULL) + { + stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); + return NULL; + } + } + + ptr = or_unpack_int (ptr, &offset); + if (offset == 0) + { + sp->sig = NULL; + } + else + { + sp->sig = stx_restore_pl_sig (thread_p, &xasl_unpack_info->packed_xasl[offset]); + if (sp->sig == NULL) + { + stx_set_xasl_errcode (thread_p, ER_OUT_OF_VIRTUAL_MEMORY); + return NULL; + } + } + + return ptr; +} + static char * stx_build_function_type (THREAD_ENTRY * thread_p, char *ptr, FUNCTION_TYPE * function) { diff --git a/src/query/xasl.h b/src/query/xasl.h index a5738aa709..4a70a2471f 100644 --- a/src/query/xasl.h +++ b/src/query/xasl.h @@ -30,13 +30,14 @@ #include "access_json_table.hpp" #include "access_spec.hpp" #include "memory_hash.h" -#include "method_def.hpp" + #include "query_hash_scan.h" #include "query_list.h" #include "regu_var.hpp" #include "storage_common.h" #include "string_opfunc.h" #include "subquery_cache.h" +#include "pl_signature.hpp" #if defined (SERVER_MODE) || defined (SA_MODE) #include "external_sort.h" @@ -891,7 +892,7 @@ struct method_spec_node XASL_NODE *xasl_node; /* the XASL node that contains the */ /* list file ID for the method */ /* arguments */ - METHOD_SIG_LIST *method_sig_list; /* method signature list */ + PL_SIGNATURE_ARRAY_TYPE *sig_array; /* method signature array */ }; struct dblink_spec_node @@ -984,8 +985,8 @@ union hybrid_node #define ACCESS_SPEC_METHOD_REGU_LIST(ptr) \ ((ptr)->s.method_node.method_regu_list) -#define ACCESS_SPEC_METHOD_SIG_LIST(ptr) \ - ((ptr)->s.method_node.method_sig_list) +#define ACCESS_SPEC_METHOD_SIG_ARRAY(ptr) \ + ((ptr)->s.method_node.sig_array) #define ACCESS_SPEC_METHOD_LIST_ID(ptr) \ (ACCESS_SPEC_METHOD_XASL_NODE(ptr)->list_id) diff --git a/src/query/xasl_to_stream.c b/src/query/xasl_to_stream.c index 56d23b4ed2..bc335f24ad 100644 --- a/src/query/xasl_to_stream.c +++ b/src/query/xasl_to_stream.c @@ -78,6 +78,7 @@ static int xts_save_aggregate_type (const AGGREGATE_TYPE * aggregate); static int xts_save_function_type (const FUNCTION_TYPE * function); static int xts_save_analytic_type (const ANALYTIC_TYPE * analytic); static int xts_save_analytic_eval_type (const ANALYTIC_EVAL_TYPE * analytic); +static int xts_save_sp_type (const SP_TYPE * sp); static int xts_save_srlist_id (const QFILE_SORTED_LIST_ID * sort_list_id); static int xts_save_list_id (const QFILE_LIST_ID * list_id); static int xts_save_arith_type (const ARITH_TYPE * arithmetic); @@ -121,12 +122,11 @@ static int xts_save_db_value_array (DB_VALUE ** ptr, int size); static int xts_save_int_array (int *ptr, int size); static int xts_save_hfid_array (HFID * ptr, int size); static int xts_save_oid_array (OID * ptr, int size); -static int xts_save_method_sig_list (const METHOD_SIG_LIST * ptr); -static int xts_save_method_sig (const METHOD_SIG * ptr, int size); static int xts_save_key_range_array (const KEY_RANGE * ptr, int size); static int xts_save_upddel_class_info_array (const UPDDEL_CLASS_INFO * classes, int nelements); static int xts_save_update_assignment_array (const UPDATE_ASSIGNMENT * assigns, int nelements); static int xts_save_odku_info (const ODKU_INFO * odku_info); +static int xts_save_packable_object (const cubpacking::packable_object & po); static char *xts_process (char *ptr, const json_table_column & json_table_col); static char *xts_process (char *ptr, const json_table_node & json_table_node); @@ -183,10 +183,9 @@ static char *xts_process_aggregate_type (char *ptr, const AGGREGATE_TYPE * aggre static char *xts_process_analytic_type (char *ptr, const ANALYTIC_TYPE * analytic); static char *xts_process_analytic_eval_type (char *ptr, const ANALYTIC_EVAL_TYPE * analytic); static char *xts_process_function_type (char *ptr, const FUNCTION_TYPE * function); +static char *xts_process_sp_type (char *ptr, const SP_TYPE * sp); static char *xts_process_srlist_id (char *ptr, const QFILE_SORTED_LIST_ID * sort_list_id); static char *xts_process_sort_list (char *ptr, const SORT_LIST * sort_list); -static char *xts_process_method_sig_list (char *ptr, const METHOD_SIG_LIST * method_sig_list); -static char *xts_process_method_sig (char *ptr, const METHOD_SIG * method_sig, int size); static char *xts_process_connectby_proc (char *ptr, const CONNECTBY_PROC_NODE * connectby_proc); static char *xts_process_regu_value_list (char *ptr, const REGU_VALUE_LIST * regu_value_list); static char *xts_process_sq_cache (char *ptr, const SQ_CACHE * sq_cache); @@ -245,11 +244,10 @@ static int xts_sizeof_analytic_type (const ANALYTIC_TYPE * ptr); static int xts_sizeof_analytic_eval_type (const ANALYTIC_EVAL_TYPE * ptr); static int xts_sizeof_srlist_id (const QFILE_SORTED_LIST_ID * ptr); static int xts_sizeof_sort_list (const SORT_LIST * ptr); -static int xts_sizeof_method_sig_list (const METHOD_SIG_LIST * ptr); -static int xts_sizeof_method_sig (const METHOD_SIG * ptr); static int xts_sizeof_connectby_proc (const CONNECTBY_PROC_NODE * ptr); static int xts_sizeof_regu_value_list (const REGU_VALUE_LIST * regu_value_list); static int xts_sizeof_cte_proc (const CTE_PROC_NODE * ptr); +static int xts_sizeof_sp_type (const SP_TYPE * sp); static int xts_mark_ptr_visited (const void *ptr, int offset); static int xts_get_offset_visited_ptr (const void *ptr); @@ -561,6 +559,74 @@ xts_save_aggregate_type (const AGGREGATE_TYPE * aggregate) return offset; } +static int +xts_save_sp_type (const SP_TYPE * sp) +{ + int offset; + int size; + OR_ALIGNED_BUF (sizeof (*sp) * 2) a_buf; + char *buf = OR_ALIGNED_BUF_START (a_buf); + char *buf_p = NULL; + bool is_buf_alloced = false; + + if (sp == NULL) + { + return NO_ERROR; + } + + offset = xts_get_offset_visited_ptr (sp); + if (offset != ER_FAILED) + { + return offset; + } + + size = xts_sizeof_sp_type (sp); + if (size == ER_FAILED) + { + return ER_FAILED; + } + + offset = xts_reserve_location_in_stream (size); + if (offset == ER_FAILED || xts_mark_ptr_visited (sp, offset) == ER_FAILED) + { + return ER_FAILED; + } + + if (size <= (int) OR_ALIGNED_BUF_SIZE (a_buf)) + { + buf_p = buf; + } + else + { + buf_p = (char *) malloc (size); + if (buf_p == NULL) + { + xts_Xasl_errcode = ER_OUT_OF_VIRTUAL_MEMORY; + return ER_FAILED; + } + + is_buf_alloced = true; + } + + buf = xts_process_sp_type (buf_p, sp); + if (buf == NULL) + { + offset = ER_FAILED; + goto end; + } + assert (buf <= buf_p + size); + + memcpy (&xts_Stream_buffer[offset], buf_p, size); + +end: + if (is_buf_alloced) + { + free_and_init (buf_p); + } + + return offset; +} + static int xts_save_function_type (const FUNCTION_TYPE * function) { @@ -2235,145 +2301,6 @@ xts_save_insert_info (const INSERT_PROC_NODE * insert_proc) } #endif -static int -xts_save_method_sig_list (const METHOD_SIG_LIST * method_sig_list) -{ - int offset; - int size; - OR_ALIGNED_BUF (sizeof (*method_sig_list) * 2) a_buf; - char *buf = OR_ALIGNED_BUF_START (a_buf); - char *buf_p = NULL; - bool is_buf_alloced = false; - - if (method_sig_list == NULL) - { - return NO_ERROR; - } - - offset = xts_get_offset_visited_ptr (method_sig_list); - if (offset != ER_FAILED) - { - return offset; - } - - size = xts_sizeof_method_sig_list (method_sig_list); - if (size == ER_FAILED) - { - return ER_FAILED; - } - - offset = xts_reserve_location_in_stream (size); - if (offset == ER_FAILED || xts_mark_ptr_visited (method_sig_list, offset) == ER_FAILED) - { - return ER_FAILED; - } - - if (size <= (int) OR_ALIGNED_BUF_SIZE (a_buf)) - { - buf_p = buf; - } - else - { - buf_p = (char *) malloc (size); - if (buf_p == NULL) - { - xts_Xasl_errcode = ER_OUT_OF_VIRTUAL_MEMORY; - return ER_FAILED; - } - - is_buf_alloced = true; - } - - buf = xts_process_method_sig_list (buf_p, method_sig_list); - if (buf == NULL) - { - offset = ER_FAILED; - goto end; - } - assert (buf <= buf_p + size); - - memcpy (&xts_Stream_buffer[offset], buf_p, size); - -end: - if (is_buf_alloced) - { - free_and_init (buf_p); - } - - return offset; -} - -static int -xts_save_method_sig (const METHOD_SIG * method_sig, int count) -{ - int offset; - int size; - OR_ALIGNED_BUF (sizeof (*method_sig) * 2) a_buf; - char *buf = OR_ALIGNED_BUF_START (a_buf); - char *buf_p = NULL; - bool is_buf_alloced = false; - - if (method_sig == NULL) - { - assert (count == 0); - return NO_ERROR; - } - - assert (count > 0); - - offset = xts_get_offset_visited_ptr (method_sig); - if (offset != ER_FAILED) - { - return offset; - } - - size = xts_sizeof_method_sig (method_sig); - if (size == ER_FAILED) - { - return ER_FAILED; - } - - offset = xts_reserve_location_in_stream (size); - if (offset == ER_FAILED || xts_mark_ptr_visited (method_sig, offset) == ER_FAILED) - { - return ER_FAILED; - } - - if (size <= (int) OR_ALIGNED_BUF_SIZE (a_buf)) - { - buf_p = buf; - } - else - { - buf_p = (char *) malloc (size); - if (buf_p == NULL) - { - xts_Xasl_errcode = ER_OUT_OF_VIRTUAL_MEMORY; - return ER_FAILED; - } - - is_buf_alloced = true; - } - - buf = xts_process_method_sig (buf_p, method_sig, count); - if (buf == NULL) - { - offset = ER_FAILED; - goto end; - } - assert (buf <= buf_p + size); - - memcpy (&xts_Stream_buffer[offset], buf_p, size); - -end: - if (is_buf_alloced) - { - free_and_init (buf_p); - } - - return offset; -} - static int xts_save_string (const char *string) { @@ -4047,6 +3974,37 @@ xts_save_update_assignment_array (const UPDATE_ASSIGNMENT * assigns, int nelemen return offset; } +static int +xts_save_packable_object (const cubpacking::packable_object & po) +{ + int offset, size, packed_length; + char *ptr; + + offset = xts_get_offset_visited_ptr (&po); + if (offset != ER_FAILED) + { + return offset; + } + + packing_packer packer; + cubmem::extensible_block eb; + packer.set_buffer_and_pack_all (eb, po); + + size = packer.get_current_size () + OR_INT_SIZE; + + offset = xts_reserve_location_in_stream (size); + if (offset == ER_FAILED || xts_mark_ptr_visited (&po, offset) == ER_FAILED) + { + return ER_FAILED; + } + + ptr = &xts_Stream_buffer[offset]; + ptr = or_pack_int (ptr, size); + memcpy (ptr, eb.get_ptr (), size); + + return offset; +} + static int xts_save_odku_info (const ODKU_INFO * odku_info) { @@ -5213,7 +5171,7 @@ xts_process_method_spec_type (char *ptr, const METHOD_SPEC_TYPE * method_spec) } ptr = or_pack_int (ptr, offset); - offset = xts_save_method_sig_list (method_spec->method_sig_list); + offset = xts_save_packable_object (*(method_spec->sig_array)); if (offset == ER_FAILED) { return NULL; @@ -5403,6 +5361,15 @@ xts_pack_regu_variable_value (char *ptr, const REGU_VARIABLE * regu_var) ptr = or_pack_int (ptr, offset); break; + case TYPE_SP: + offset = xts_save_sp_type (regu_var->value.sp_ptr); + if (offset == ER_FAILED) + { + return NULL; + } + ptr = or_pack_int (ptr, offset); + break; + case TYPE_FUNC: offset = xts_save_function_type (regu_var->value.funcp); if (offset == ER_FAILED) @@ -5745,25 +5712,25 @@ xts_process_analytic_type (char *ptr, const ANALYTIC_TYPE * analytic) } static char * -xts_process_analytic_eval_type (char *ptr, const ANALYTIC_EVAL_TYPE * analytic_eval) +xts_process_sp_type (char *ptr, const SP_TYPE * sp) { int offset; - offset = xts_save_analytic_type (analytic_eval->head); + offset = xts_save_db_value (sp->value); if (offset == ER_FAILED) { return NULL; } ptr = or_pack_int (ptr, offset); - offset = xts_save_sort_list (analytic_eval->sort_list); + offset = xts_save_regu_variable_list (sp->args); if (offset == ER_FAILED) { return NULL; } ptr = or_pack_int (ptr, offset); - offset = xts_save_analytic_eval_type (analytic_eval->next); + offset = xts_save_packable_object (*sp->sig); if (offset == ER_FAILED) { return NULL; @@ -5774,74 +5741,42 @@ xts_process_analytic_eval_type (char *ptr, const ANALYTIC_EVAL_TYPE * analytic_e } static char * -xts_process_srlist_id (char *ptr, const QFILE_SORTED_LIST_ID * sort_list_id) +xts_process_analytic_eval_type (char *ptr, const ANALYTIC_EVAL_TYPE * analytic_eval) { int offset; - ptr = or_pack_int (ptr, sort_list_id->sorted); - - offset = xts_save_list_id (sort_list_id->list_id); + offset = xts_save_analytic_type (analytic_eval->head); if (offset == ER_FAILED) { return NULL; } ptr = or_pack_int (ptr, offset); - return ptr; -} - -static char * -xts_process_sort_list (char *ptr, const SORT_LIST * sort_list) -{ - int offset; - - offset = xts_save_sort_list (sort_list->next); + offset = xts_save_sort_list (analytic_eval->sort_list); if (offset == ER_FAILED) { return NULL; } ptr = or_pack_int (ptr, offset); - ptr = xts_process_pos_descr (ptr, &sort_list->pos_descr); - if (ptr == NULL) + offset = xts_save_analytic_eval_type (analytic_eval->next); + if (offset == ER_FAILED) { return NULL; } - - ptr = or_pack_int (ptr, sort_list->s_order); - ptr = or_pack_int (ptr, sort_list->s_nulls); - - /* others (not sent to server) */ + ptr = or_pack_int (ptr, offset); return ptr; } -/* - * xts_process_method_sig_list ( ) - - * - * Note: do not use or_pack_method_sig_list - */ static char * -xts_process_method_sig_list (char *ptr, const METHOD_SIG_LIST * method_sig_list) +xts_process_srlist_id (char *ptr, const QFILE_SORTED_LIST_ID * sort_list_id) { int offset; -#if !defined(NDEBUG) - { - int i = 0; - METHOD_SIG *sig; - - for (sig = method_sig_list->method_sig; sig; sig = sig->next) - { - i++; - } - assert (method_sig_list->num_methods == i); - } -#endif - - ptr = or_pack_int (ptr, method_sig_list->num_methods); + ptr = or_pack_int (ptr, sort_list_id->sorted); - offset = xts_save_method_sig (method_sig_list->method_sig, method_sig_list->num_methods); + offset = xts_save_list_id (sort_list_id->list_id); if (offset == ER_FAILED) { return NULL; @@ -5852,57 +5787,27 @@ xts_process_method_sig_list (char *ptr, const METHOD_SIG_LIST * method_sig_list) } static char * -xts_process_method_sig (char *ptr, const METHOD_SIG * method_sig, int count) +xts_process_sort_list (char *ptr, const SORT_LIST * sort_list) { int offset; - int n; - - assert (method_sig->method_name != NULL); - offset = xts_save_string (method_sig->method_name); + offset = xts_save_sort_list (sort_list->next); if (offset == ER_FAILED) { return NULL; } ptr = or_pack_int (ptr, offset); - ptr = or_pack_int (ptr, method_sig->method_type); - ptr = or_pack_int (ptr, method_sig->num_method_args); - - for (n = 0; n < method_sig->num_method_args + 1; n++) + ptr = xts_process_pos_descr (ptr, &sort_list->pos_descr); + if (ptr == NULL) { - ptr = or_pack_int (ptr, method_sig->method_arg_pos[n]); + return NULL; } - if (method_sig->method_type == METHOD_TYPE_JAVA_SP) - { - for (n = 0; n < method_sig->num_method_args; n++) - { - ptr = or_pack_int (ptr, method_sig->arg_info.arg_mode[n]); - } - for (n = 0; n < method_sig->num_method_args; n++) - { - ptr = or_pack_int (ptr, method_sig->arg_info.arg_type[n]); - } - - ptr = or_pack_int (ptr, method_sig->arg_info.result_type); - } - else - { - offset = xts_save_string (method_sig->class_name); /* is can be null */ - if (offset == ER_FAILED) - { - return NULL; - } - ptr = or_pack_int (ptr, offset); - } + ptr = or_pack_int (ptr, sort_list->s_order); + ptr = or_pack_int (ptr, sort_list->s_nulls); - offset = xts_save_method_sig (method_sig->next, count - 1); - if (offset == ER_FAILED) - { - return NULL; - } - ptr = or_pack_int (ptr, offset); + /* others (not sent to server) */ return ptr; } @@ -7167,7 +7072,7 @@ xts_sizeof_method_spec_type (const METHOD_SPEC_TYPE * method_spec) size += (PTR_SIZE /* method_regu_list */ + PTR_SIZE /* xasl_node */ - + PTR_SIZE); /* method_sig_list */ + + PTR_SIZE); /* sig_array */ return size; } @@ -7387,6 +7292,10 @@ xts_get_regu_variable_value_size (const REGU_VARIABLE * regu_var) size = PTR_SIZE; /* arithptr */ break; + case TYPE_SP: + size = PTR_SIZE; /* sp_ptr */ + break; + case TYPE_FUNC: size = PTR_SIZE; /* funcp */ break; @@ -7543,6 +7452,23 @@ xts_sizeof_aggregate_type (const AGGREGATE_TYPE * aggregate) return size; } +/* + * xts_sizeof_function_type () - + * return: + * ptr(in) : + */ +static int +xts_sizeof_sp_type (const SP_TYPE * sp) +{ + int size = 0; + + size += (PTR_SIZE /* value */ + + PTR_SIZE /* sig */ + + PTR_SIZE); /* args */ + + return size; +} + /* * xts_sizeof_function_type () - * return: @@ -7674,47 +7600,6 @@ xts_sizeof_sort_list (const SORT_LIST * sort_lis) return size; } -/* - * xts_sizeof_method_sig_list () - - * return: - * ptr(in) : - */ -static int -xts_sizeof_method_sig_list (const METHOD_SIG_LIST * method_sig_list) -{ - int size = 0; - - size += (OR_INT_SIZE /* num_methods */ - + PTR_SIZE); /* method_sig */ - - return size; -} - -static int -xts_sizeof_method_sig (const METHOD_SIG * method_sig) -{ - int size = 0; - - size += (PTR_SIZE /* method_name */ - + OR_INT_SIZE /* method_type */ - + OR_INT_SIZE /* num_method_args */ - + (OR_INT_SIZE * (method_sig->num_method_args + 1)) /* method_arg_pos */ - + PTR_SIZE); /* next */ - - if (method_sig->method_type == METHOD_TYPE_JAVA_SP) - { - size += ((method_sig->num_method_args * OR_INT_SIZE) /* arg_mode */ - + (method_sig->num_method_args * OR_INT_SIZE) /* arg_type */ - + (OR_INT_SIZE)); /* result type */ - } - else - { - size += PTR_SIZE; /* class_name */ - } - - return size; -} - /* * xts_sizeof_connectby_proc () - * return: diff --git a/src/session/session.c b/src/session/session.c index 6d1f54234f..fab62a4997 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -53,6 +53,8 @@ #include "thread_lockfree_hash_map.hpp" #include "thread_manager.hpp" #include "xasl_cache.h" +#include "pl_session.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" @@ -135,7 +137,7 @@ struct session_state int private_lru_index; load_session *load_session_p; - method_runtime_context *method_rctx_p; + PL_SESSION *pl_session_p; // *INDENT-OFF* session_state (); @@ -314,7 +316,7 @@ session_state_init (void *st) session_p->private_lru_index = -1; session_p->auto_commit = false; session_p->load_session_p = NULL; - session_p->method_rctx_p = NULL; + session_p->pl_session_p = NULL; return NO_ERROR; } @@ -3182,8 +3184,7 @@ session_get_load_session (THREAD_ENTRY * thread_p, REFPTR (load_session, load_se } int -session_get_method_runtime_context (THREAD_ENTRY * thread_p, - REFPTR (method_runtime_context, method_runtime_context_ref_ptr)) +session_get_pl_session (THREAD_ENTRY * thread_p, REFPTR (PL_SESSION, pl_session_ref_ptr)) { SESSION_STATE *state_p = NULL; @@ -3193,12 +3194,12 @@ session_get_method_runtime_context (THREAD_ENTRY * thread_p, return ER_FAILED; } - if (state_p->method_rctx_p == NULL) + if (state_p->pl_session_p == NULL) { - state_p->method_rctx_p = new method_runtime_context (); + state_p->pl_session_p = new PL_SESSION (); } - method_runtime_context_ref_ptr = state_p->method_rctx_p; + pl_session_ref_ptr = state_p->pl_session_p; return NO_ERROR; } @@ -3226,13 +3227,13 @@ session_stop_attached_threads (void *session_arg) session->load_session_p = NULL; } - if (session->method_rctx_p != NULL) + if (session->pl_session_p != NULL) { - session->method_rctx_p->set_interrupt (er_errid ()); - session->method_rctx_p->wait_for_interrupt (); + session->pl_session_p->set_interrupt (er_errid ()); + session->pl_session_p->wait_for_interrupt (); - delete session->method_rctx_p; - session->method_rctx_p = NULL; + delete session->pl_session_p; + session->pl_session_p = NULL; } #endif } diff --git a/src/session/session.h b/src/session/session.h index c5da4146b5..6b55c12afe 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -33,7 +33,7 @@ #include "system_parameter.h" #include "thread_compat.hpp" #include "tz_support.h" -#include "method_runtime_context.hpp" +#include "pl_session.hpp" // forward definitions struct xasl_cache_ent; @@ -89,7 +89,6 @@ extern int session_set_tran_auto_commit (THREAD_ENTRY * thread_p, bool auto_comm extern int session_set_load_session (THREAD_ENTRY * thread_p, load_session * load_session_p); extern int session_get_load_session (THREAD_ENTRY * thread_p, REFPTR (load_session, load_session_ref_ptr)); -extern int session_get_method_runtime_context (THREAD_ENTRY * thread_p, - REFPTR (method_runtime_context, method_runtime_context_ref_ptr)); +extern int session_get_pl_session (THREAD_ENTRY * thread_p, REFPTR (PL_SESSION, pl_session_ref_ptr)); extern void session_stop_attached_threads (void *session); #endif /* _SESSION_H_ */ diff --git a/src/sp/Makefile_jspserver b/src/sp/Makefile_jspserver deleted file mode 100644 index b00bc09391..0000000000 --- a/src/sp/Makefile_jspserver +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright 2008 Search Solution Corporation -# Copyright 2016 CUBRID Corporation -# -# Licensed 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. -# -# - -JDBC_SRC_DIR = . - -BIN_DIR = bin -SRC_DIR = src - -JDBC_BUILD_NUMBER := $(shell cat ../../BUILD_NUMBER) - -JDBC_DRIVER = jspserver.jar - -all: $(JDBC_DRIVER) - -clean: - ant -buildfile ../../java/build.xml -Dbasedir=. -Dversion=$(JDBC_BUILD_NUMBER) clean - -$(JDBC_DRIVER): - ant -buildfile ../../java/build.xml -Dbasedir=. -Dsrc=$(JDBC_SRC_DIR) -Dversion=$(JDBC_BUILD_NUMBER) dist diff --git a/src/sp/jsp_cl.c b/src/sp/jsp_cl.c deleted file mode 100644 index 5bf60d2c00..0000000000 --- a/src/sp/jsp_cl.c +++ /dev/null @@ -1,1647 +0,0 @@ -/* - * Copyright 2008 Search Solution Corporation - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - -/* - * jsp_cl.c - Java Stored Procedure Client Module Source - */ - -#ident "$Id$" - -#include "config.h" - -#include -#if !defined(WINDOWS) -#include -#else /* not WINDOWS */ -#include -#endif /* not WINDOWS */ - -#include -#include - -#include "authenticate.h" -#include "error_manager.h" -#include "memory_alloc.h" -#include "dbtype.h" -#include "parser.h" -#include "object_domain.h" -#include "object_primitive.h" -#include "object_representation.h" -#include "db.h" -#include "object_accessor.h" -#include "set_object.h" -#include "locator_cl.h" -#include "transaction_cl.h" -#include "schema_manager.h" -#include "numeric_opfunc.h" -#include "jsp_cl.h" -#include "system_parameter.h" -#include "network_interface_cl.h" -#include "unicode_support.h" -#include "dbtype.h" -#include "jsp_comm.h" -#include "method_compile_def.hpp" -#include "parser_message.h" - -#define PT_NODE_SP_NAME(node) \ - ((node)->info.sp.name->info.name.original) - -#define PT_NODE_SP_TYPE(node) \ - ((node)->info.sp.type) - -#define PT_NODE_SP_RETURN_TYPE(node) \ - ((node)->info.sp.ret_type->info.name.original) - -#define PT_NODE_SP_BODY(node) \ - ((node)->info.sp.body) - -#define PT_NODE_SP_LANG(node) \ - ((node)->info.sp.body->info.sp_body.lang) - -#define PT_NODE_SP_DIRECT(node) \ - ((node)->info.sp.body->info.sp_body.direct) - -#define PT_NODE_SP_IMPL(node) \ - ((node)->info.sp.body->info.sp_body.impl->info.value.data_value.str->bytes) - -#define PT_NODE_SP_JAVA_METHOD(node) \ - ((node)->info.sp.body->info.sp_body.decl->info.value.data_value.str->bytes) - -#define PT_NODE_SP_COMMENT(node) \ - (((node)->info.sp.comment == NULL) ? NULL : \ - (node)->info.sp.comment->info.value.data_value.str->bytes) - -#define PT_NODE_SP_ARG_COMMENT(node) \ - (((node)->info.sp_param.comment == NULL) ? NULL : \ - (node)->info.sp_param.comment->info.value.data_value.str->bytes) - -#define MAX_CALL_COUNT 16 -#define SAVEPOINT_ADD_STORED_PROC "ADDSTOREDPROC" -#define SAVEPOINT_CREATE_STORED_PROC "CREATESTOREDPROC" - -#define MAX_ARG_COUNT 64 - -static int server_port = -1; -static int call_cnt = 0; -static bool is_prepare_call[MAX_CALL_COUNT] = { false, }; - -static SP_TYPE_ENUM jsp_map_pt_misc_to_sp_type (PT_MISC_TYPE pt_enum); -static int jsp_map_pt_misc_to_sp_mode (PT_MISC_TYPE pt_enum); -static PT_MISC_TYPE jsp_map_sp_type_to_pt_misc (SP_TYPE_ENUM sp_type); - -static int jsp_add_stored_procedure_argument (MOP * mop_p, const char *sp_name, const char *arg_name, int index, - PT_TYPE_ENUM data_type, PT_MISC_TYPE mode, const char *arg_comment); -static char *jsp_check_stored_procedure_name (const char *str); -static int jsp_add_stored_procedure (const char *name, const PT_MISC_TYPE type, const PT_TYPE_ENUM ret_type, - PT_NODE * param_list, const char *java_method, const char *comment); -static int drop_stored_procedure (const char *name, PT_MISC_TYPE expected_type); - -static int jsp_make_method_sig_list (PARSER_CONTEXT * parser, PT_NODE * node_list, method_sig_list & sig_list); -static int *jsp_make_method_arglist (PARSER_CONTEXT * parser, PT_NODE * node_list); - -extern bool ssl_client; - -/* - * jsp_find_stored_procedure - * return: MOP - * name(in): find java stored procedure name - * - * Note: - */ - -MOP -jsp_find_stored_procedure (const char *name) -{ - MOP mop = NULL; - DB_VALUE value; - int save; - char *checked_name; - - if (!name) - { - return NULL; - } - - AU_DISABLE (save); - - checked_name = jsp_check_stored_procedure_name (name); - db_make_string (&value, checked_name); - mop = db_find_unique (db_find_class (SP_CLASS_NAME), SP_ATTR_NAME, &value); - - if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND) - { - er_clear (); - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_EXIST, 1, name); - } - - free_and_init (checked_name); - AU_ENABLE (save); - - return mop; -} - -/* - * jsp_is_exist_stored_procedure - * return: name is exist then return true - * else return false - * name(in): find java stored procedure name - * - * Note: - */ - -int -jsp_is_exist_stored_procedure (const char *name) -{ - MOP mop = NULL; - - mop = jsp_find_stored_procedure (name); - er_clear (); - - return mop != NULL; -} - -int -jsp_check_out_param_in_query (PARSER_CONTEXT * parser, PT_NODE * node, int arg_mode) -{ - int error = NO_ERROR; - - assert ((node) && (node)->node_type == PT_METHOD_CALL); - - if (node->info.method_call.call_or_expr != PT_IS_CALL_STMT) - { - // check out parameters - if (arg_mode != SP_MODE_IN) - { - PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_SP_OUT_ARGS_EXISTS_IN_QUERY, - node->info.method_call.method_name->info.name.original); - error = ER_PT_SEMANTIC; - } - } - - return error; -} - -/* - * jsp_check_param_type_supported - * - * Note: - */ - -int -jsp_check_param_type_supported (PT_NODE * node) -{ - assert (node && node->node_type == PT_SP_PARAMETERS); - - PT_TYPE_ENUM pt_type = node->type_enum; - DB_TYPE domain_type = pt_type_enum_to_db (pt_type); - - switch (domain_type) - { - case DB_TYPE_INTEGER: - case DB_TYPE_FLOAT: - case DB_TYPE_DOUBLE: - case DB_TYPE_STRING: - case DB_TYPE_OBJECT: - case DB_TYPE_SET: - case DB_TYPE_MULTISET: - case DB_TYPE_SEQUENCE: - case DB_TYPE_TIME: - case DB_TYPE_TIMESTAMP: - case DB_TYPE_DATE: - case DB_TYPE_MONETARY: - case DB_TYPE_SHORT: - case DB_TYPE_NUMERIC: - case DB_TYPE_CHAR: - case DB_TYPE_BIGINT: - case DB_TYPE_DATETIME: - return NO_ERROR; - break; - - case DB_TYPE_RESULTSET: - if (node->info.sp_param.mode != PT_OUTPUT) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_INPUT_RESULTSET, 0); - } - break; - - default: - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, pr_type_name (domain_type)); - break; - } - - return er_errid (); -} - - -/* - * jsp_check_return_type_supported - * - * Note: - */ - -int -jsp_check_return_type_supported (DB_TYPE type) -{ - switch (type) - { - case DB_TYPE_NULL: - case DB_TYPE_INTEGER: - case DB_TYPE_FLOAT: - case DB_TYPE_DOUBLE: - case DB_TYPE_STRING: - case DB_TYPE_OBJECT: - case DB_TYPE_SET: - case DB_TYPE_MULTISET: - case DB_TYPE_SEQUENCE: - case DB_TYPE_TIME: - case DB_TYPE_TIMESTAMP: - case DB_TYPE_DATE: - case DB_TYPE_MONETARY: - case DB_TYPE_SHORT: - case DB_TYPE_NUMERIC: - case DB_TYPE_CHAR: - case DB_TYPE_BIGINT: - case DB_TYPE_DATETIME: - case DB_TYPE_RESULTSET: - return NO_ERROR; - break; - - default: - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_RETURN_TYPE, 1, pr_type_name (type)); - break; - } - - return er_errid (); -} - -/* - * jsp_get_return_type - Return Java Stored Procedure Type - * return: if fail return error code - * else return Java Stored Procedure Type - * name(in): java stored procedure name - * - * Note: - */ - -int -jsp_get_return_type (const char *name) -{ - DB_OBJECT *mop_p; - DB_VALUE return_type; - int err; - int save; - - AU_DISABLE (save); - - mop_p = jsp_find_stored_procedure (name); - if (mop_p == NULL) - { - AU_ENABLE (save); - - assert (er_errid () != NO_ERROR); - return er_errid (); - } - - err = db_get (mop_p, SP_ATTR_RETURN_TYPE, &return_type); - if (err != NO_ERROR) - { - AU_ENABLE (save); - return err; - } - - AU_ENABLE (save); - return db_get_int (&return_type); -} - -/* - * jsp_get_sp_type - Return Java Stored Procedure Type - * return: if fail return error code - * else return Java Stored Procedure Type - * name(in): java stored procedure name - * - * Note: - */ - -int -jsp_get_sp_type (const char *name) -{ - DB_OBJECT *mop_p; - DB_VALUE sp_type_val; - int err; - int save; - - AU_DISABLE (save); - - mop_p = jsp_find_stored_procedure (name); - if (mop_p == NULL) - { - AU_ENABLE (save); - - assert (er_errid () != NO_ERROR); - return er_errid (); - } - - /* check type */ - err = db_get (mop_p, SP_ATTR_SP_TYPE, &sp_type_val); - if (err != NO_ERROR) - { - AU_ENABLE (save); - return err; - } - - AU_ENABLE (save); - return jsp_map_sp_type_to_pt_misc ((SP_TYPE_ENUM) db_get_int (&sp_type_val)); -} - -static PT_MISC_TYPE -jsp_map_sp_type_to_pt_misc (SP_TYPE_ENUM sp_type) -{ - if (sp_type == SP_TYPE_PROCEDURE) - { - return PT_SP_PROCEDURE; - } - else - { - return PT_SP_FUNCTION; - } -} - -/* - * jsp_call_stored_procedure - call java stored procedure in constant folding - * return: call jsp failed return error code - * parser(in/out): parser environment - * statement(in): a statement node - * - * Note: - */ - -int -jsp_call_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement) -{ - int error = NO_ERROR; - PT_NODE *method; - const char *method_name; - if (!statement || !(method = statement->info.method_call.method_name) || method->node_type != PT_NAME - || !(method_name = method->info.name.original)) - { - er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0); - return er_errid (); - } - - DB_VALUE ret_value; - db_make_null (&ret_value); - - // *INDENT-OFF* - std::vector > args; - // *INDENT-ON* - - PT_NODE *vc = statement->info.method_call.arg_list; - while (vc) - { - DB_VALUE *db_value; - bool to_break = false; - - /* - * Don't clone host vars; they may actually be acting as output variables (e.g., a character array that is - * intended to receive bytes from the method), and cloning will ensure that the results never make it to the - * expected area. Since pt_evaluate_tree() always clones its db_values we must not use pt_evaluate_tree() to - * extract the db_value from a host variable; instead extract it ourselves. */ - if (PT_IS_CONST (vc)) - { - db_value = pt_value_to_db (parser, vc); - } - else - { - db_value = (DB_VALUE *) malloc (sizeof (DB_VALUE)); - if (db_value == NULL) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (DB_VALUE)); - return er_errid (); - } - - /* must call pt_evaluate_tree */ - pt_evaluate_tree (parser, vc, db_value, 1); - if (pt_has_error (parser)) - { - /* to maintain the list to free all the allocated */ - to_break = true; - } - } - - args.push_back (std::ref (*db_value)); - vc = vc->next; - - if (to_break) - { - break; - } - } - - if (pt_has_error (parser)) - { - pt_report_to_ersys (parser, PT_SEMANTIC); - error = er_errid (); - } - else - { - /* call sp */ - method_sig_list sig_list; - - sig_list.method_sig = nullptr; - sig_list.num_methods = 0; - - error = jsp_make_method_sig_list (parser, statement, sig_list); - if (error == NO_ERROR && locator_get_sig_interrupt () == 0) - { - error = method_invoke_fold_constants (sig_list, args, ret_value); - } - sig_list.freemem (); - } - - if (error == NO_ERROR) - { - vc = statement->info.method_call.arg_list; - for (int i = 0; i < (int) args.size () && vc; i++) - { - if (!PT_IS_CONST (vc)) - { - DB_VALUE & arg = args[i]; - db_value_clear (&arg); - free (&arg); - } - vc = vc->next; - } - } - - if (error == NO_ERROR) - { - /* Save the method result and its domain */ - statement->etc = (void *) db_value_copy (&ret_value); - statement = pt_bind_type_from_dbval (parser, statement, &ret_value); - - PT_NODE *into = statement->info.method_call.to_return_var; - - const char *into_label; - if (into != NULL && into->node_type == PT_NAME && (into_label = into->info.name.original) != NULL) - { - /* create another DB_VALUE of the new instance for the label_table */ - DB_VALUE *ins_value = db_value_copy (&ret_value); - error = pt_associate_label_with_value_check_reference (into_label, ins_value); - } - } - -#if defined (CS_MODE) - db_value_clear (&ret_value); -#endif - - return error; -} - -/* - * jsp_drop_stored_procedure - drop java stored procedure - * return: Error code - * parser(in/out): parser environment - * statement(in): a statement node - * - * Note: - */ - -int -jsp_drop_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement) -{ - const char *name; - PT_MISC_TYPE type; - PT_NODE *name_list, *p; - int i; - int err = NO_ERROR; - - CHECK_MODIFICATION_ERROR (); - - if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT)) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0); - return ER_BLOCK_DDL_STMT; - } - - name_list = statement->info.sp.name; - type = PT_NODE_SP_TYPE (statement); - - for (p = name_list, i = 0; p != NULL; p = p->next) - { - name = (char *) p->info.name.original; - if (name == NULL || name[0] == '\0') - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0); - return er_errid (); - } - - err = drop_stored_procedure (name, type); - if (err != NO_ERROR) - { - break; - } - } - - return err; -} - -/* - * jsp_create_stored_procedure - * return: if failed return error code else execute jsp_add_stored_procedure - * function - * parser(in/out): parser environment - * statement(in): a statement node - * - * Note: - */ - -int -jsp_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement) -{ - const char *name, *decl, *comment = NULL; - - PT_MISC_TYPE type; - PT_NODE *param_list, *p; - PT_TYPE_ENUM ret_type = PT_TYPE_NONE; - int param_count; - int lang; - int err = NO_ERROR; - bool has_savepoint = false; - PLCSQL_COMPILE_INFO compile_info; - - CHECK_MODIFICATION_ERROR (); - - if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT)) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0); - return ER_BLOCK_DDL_STMT; - } - - name = (char *) PT_NODE_SP_NAME (statement); - if (name == NULL || name[0] == '\0') - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0); - return er_errid (); - } - - type = PT_NODE_SP_TYPE (statement); - if (type == PT_SP_FUNCTION) - { - ret_type = statement->info.sp.ret_type; - } - - param_list = statement->info.sp.param_list; - for (p = param_list, param_count = 0; p != NULL; p = p->next, param_count++) - { - ; - } - - if (param_count > MAX_ARG_COUNT) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_TOO_MANY_ARG_COUNT, 1, name); - goto error_exit; - } - - lang = PT_NODE_SP_LANG (statement); - if (lang == SP_LANG_PLCSQL) - { - std::string pl_code (statement->sql_user_text, statement->sql_user_text_len); - err = plcsql_transfer_file (pl_code, false, compile_info); - if (err == NO_ERROR && compile_info.err_code == NO_ERROR) - { - decl = compile_info.java_signature.c_str (); - } - else - { - // TODO: error handling needs to be improved - err = ER_SP_COMPILE_ERROR; - - std::string err_msg; - if (compile_info.err_msg.empty ()) - { - err_msg = "unknown"; - } - else - { - err_msg.assign (compile_info.err_msg); - } - - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_COMPILE_ERROR, 3, compile_info.err_line, - compile_info.err_column, err_msg.c_str ()); - pt_record_error (parser, parser->statement_number, compile_info.err_line, compile_info.err_column, er_msg (), - NULL); - } - } - else /* SP_LANG_JAVA */ - { - bool is_direct = PT_NODE_SP_DIRECT (statement); - if (is_direct) - { - // TODO: CBRD-24641 - assert (false); - } - else - { - decl = (const char *) PT_NODE_SP_JAVA_METHOD (statement); - } - } - - if (err != NO_ERROR) - { - goto error_exit; - } - - /* check already exists */ - if (jsp_is_exist_stored_procedure (name)) - { - if (statement->info.sp.or_replace) - { - /* drop existing stored procedure */ - err = tran_system_savepoint (SAVEPOINT_CREATE_STORED_PROC); - if (err != NO_ERROR) - { - return err; - } - has_savepoint = true; - - err = drop_stored_procedure (name, type); - if (err != NO_ERROR) - { - goto error_exit; - } - } - else - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_ALREADY_EXIST, 1, name); - return er_errid (); - } - } - - comment = (char *) PT_NODE_SP_COMMENT (statement); - - err = jsp_add_stored_procedure (name, type, ret_type, param_list, decl, comment); - if (err != NO_ERROR) - { - goto error_exit; - } - return NO_ERROR; - -error_exit: - if (has_savepoint) - { - tran_abort_upto_system_savepoint (SAVEPOINT_CREATE_STORED_PROC); - } - return (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED; -} - -/* - * jsp_alter_stored_procedure - * return: if failed return error code else NO_ERROR - * parser(in/out): parser environment - * statement(in): a statement node - * - * Note: - */ - -int -jsp_alter_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement) -{ - int err = NO_ERROR; - PT_NODE *sp_name = NULL, *sp_owner = NULL, *sp_comment = NULL; - const char *name_str = NULL, *owner_str = NULL, *comment_str = NULL; - PT_MISC_TYPE type; - SP_TYPE_ENUM real_type; - MOP sp_mop = NULL, new_owner = NULL; - DB_VALUE user_val, sp_type_val; - int save; - - assert (statement != NULL); - - CHECK_MODIFICATION_ERROR (); - - if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT)) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0); - return ER_BLOCK_DDL_STMT; - } - - db_make_null (&user_val); - - type = PT_NODE_SP_TYPE (statement); - sp_name = statement->info.sp.name; - assert (sp_name != NULL); - - sp_owner = statement->info.sp.owner; - sp_comment = statement->info.sp.comment; - assert (sp_owner != NULL || sp_comment != NULL); - - name_str = sp_name->info.name.original; - assert (name_str != NULL); - - if (sp_owner != NULL) - { - owner_str = sp_owner->info.name.original; - assert (owner_str != NULL); - } - - comment_str = (char *) PT_NODE_SP_COMMENT (statement); - - AU_DISABLE (save); - - /* authentication */ - if (!au_is_dba_group_member (Au_user)) - { - err = ER_AU_DBA_ONLY; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, "change stored procedure owner"); - goto error; - } - - /* existence of sp */ - sp_mop = jsp_find_stored_procedure (name_str); - if (sp_mop == NULL) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - /* existence of new owner */ - if (sp_owner != NULL) - { - new_owner = db_find_user (owner_str); - if (new_owner == NULL) - { - err = ER_OBJ_OBJECT_NOT_FOUND; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, owner_str); - goto error; - } - } - - /* check type */ - err = db_get (sp_mop, SP_ATTR_SP_TYPE, &sp_type_val); - if (err != NO_ERROR) - { - goto error; - } - - real_type = (SP_TYPE_ENUM) db_get_int (&sp_type_val); - if (real_type != jsp_map_pt_misc_to_sp_type (type)) - { - err = ER_SP_INVALID_TYPE; - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, name_str, - real_type == SP_TYPE_FUNCTION ? "FUNCTION" : "PROCEDURE"); - goto error; - } - - /* change the owner */ - if (sp_owner != NULL) - { - db_make_object (&user_val, new_owner); - err = obj_set (sp_mop, SP_ATTR_OWNER, &user_val); - if (err < 0) - { - goto error; - } - pr_clear_value (&user_val); - } - - /* change the comment */ - if (sp_comment != NULL) - { - db_make_string (&user_val, comment_str); - err = obj_set (sp_mop, SP_ATTR_COMMENT, &user_val); - if (err < 0) - { - goto error; - } - pr_clear_value (&user_val); - } - -error: - - pr_clear_value (&user_val); - AU_ENABLE (save); - - return err; -} - -/* - * jsp_map_pt_misc_to_sp_type - * return : stored procedure type ( Procedure or Function ) - * pt_enum(in): Misc Types - * - * Note: - */ - -static SP_TYPE_ENUM -jsp_map_pt_misc_to_sp_type (PT_MISC_TYPE pt_enum) -{ - if (pt_enum == PT_SP_PROCEDURE) - { - return SP_TYPE_PROCEDURE; - } - else - { - return SP_TYPE_FUNCTION; - } -} - -/* - * jsp_map_pt_misc_to_sp_mode - * return : stored procedure mode ( input or output or inout ) - * pt_enum(in) : Misc Types - * - * Note: - */ - -static int -jsp_map_pt_misc_to_sp_mode (PT_MISC_TYPE pt_enum) -{ - if (pt_enum == PT_INPUT || pt_enum == PT_NOPUT) - { - return SP_MODE_IN; - } - else if (pt_enum == PT_OUTPUT) - { - return SP_MODE_OUT; - } - else - { - return SP_MODE_INOUT; - } -} - -/* - * jsp_add_stored_procedure_argument - * return: Error Code - * mop_p(in/out) : - * sp_name(in) : - * arg_name(in) : - * index(in) : - * data_type(in) : - * mode(in) : - * arg_comment(in): - * - * Note: - */ - -static int -jsp_add_stored_procedure_argument (MOP * mop_p, const char *sp_name, const char *arg_name, int index, - PT_TYPE_ENUM data_type, PT_MISC_TYPE mode, const char *arg_comment) -{ - DB_OBJECT *classobj_p, *object_p; - DB_OTMPL *obt_p = NULL; - DB_VALUE value; - int save; - int err; - - AU_DISABLE (save); - - classobj_p = db_find_class (SP_ARG_CLASS_NAME); - if (classobj_p == NULL) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - obt_p = dbt_create_object_internal (classobj_p); - if (obt_p == NULL) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - db_make_string (&value, sp_name); - err = dbt_put_internal (obt_p, SP_ATTR_NAME, &value); - pr_clear_value (&value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_string (&value, arg_name); - err = dbt_put_internal (obt_p, SP_ATTR_ARG_NAME, &value); - pr_clear_value (&value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_int (&value, index); - err = dbt_put_internal (obt_p, SP_ATTR_INDEX_OF_NAME, &value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_int (&value, pt_type_enum_to_db (data_type)); - err = dbt_put_internal (obt_p, SP_ATTR_DATA_TYPE, &value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_int (&value, jsp_map_pt_misc_to_sp_mode (mode)); - err = dbt_put_internal (obt_p, SP_ATTR_MODE, &value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_string (&value, arg_comment); - err = dbt_put_internal (obt_p, SP_ATTR_ARG_COMMENT, &value); - pr_clear_value (&value); - if (err != NO_ERROR) - { - goto error; - } - - object_p = dbt_finish_object (obt_p); - if (!object_p) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - obt_p = NULL; - - err = locator_flush_instance (object_p); - if (err != NO_ERROR) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - obj_delete (object_p); - goto error; - } - - *mop_p = object_p; - - AU_ENABLE (save); - return NO_ERROR; - -error: - if (obt_p) - { - dbt_abort_object (obt_p); - } - - AU_ENABLE (save); - return err; -} - -/* - * jsp_check_stored_procedure_name - - * return: java stored procedure name - * str(in) : - * - * Note: convert lowercase - */ - -static char * -jsp_check_stored_procedure_name (const char *str) -{ - char buffer[SM_MAX_IDENTIFIER_LENGTH + 2]; - char *name = NULL; - - sm_downcase_name (str, buffer, SM_MAX_IDENTIFIER_LENGTH); - name = strdup (buffer); - - return name; -} - -/* - * jsp_add_stored_procedure - - * return: Error ID - * name(in): jsp name - * type(in): type - * ret_type(in): return type - * param_list(in): parameter list - * java_method(in): - * comment(in): - * - * Note: - */ - -static int -jsp_add_stored_procedure (const char *name, const PT_MISC_TYPE type, const PT_TYPE_ENUM return_type, - PT_NODE * param_list, const char *java_method, const char *comment) -{ - DB_OBJECT *classobj_p, *object_p; - DB_OTMPL *obt_p = NULL; - DB_VALUE value, v; - DB_SET *param = NULL; - int i, save; - int err; - PT_NODE *node_p; - PT_NAME_INFO name_info; - bool has_savepoint = false; - char *checked_name; - const char *arg_comment; - DB_TYPE return_type_value; - - if (java_method == NULL) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVAILD_JAVA_METHOD, 0); - return er_errid (); - } - - AU_DISABLE (save); - - checked_name = jsp_check_stored_procedure_name (name); - - classobj_p = db_find_class (SP_CLASS_NAME); - - if (classobj_p == NULL) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - err = tran_system_savepoint (SAVEPOINT_ADD_STORED_PROC); - if (err != NO_ERROR) - { - goto error; - } - has_savepoint = true; - - obt_p = dbt_create_object_internal (classobj_p); - if (!obt_p) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - db_make_string (&value, checked_name); - err = dbt_put_internal (obt_p, SP_ATTR_NAME, &value); - pr_clear_value (&value); - - if (err != NO_ERROR) - { - goto error; - } - - db_make_int (&value, jsp_map_pt_misc_to_sp_type (type)); - err = dbt_put_internal (obt_p, SP_ATTR_SP_TYPE, &value); - if (err != NO_ERROR) - { - goto error; - } - - return_type_value = pt_type_enum_to_db (return_type); - if (jsp_check_return_type_supported (return_type_value) != NO_ERROR) - { - err = er_errid (); - goto error; - } - - db_make_int (&value, (int) return_type_value); - err = dbt_put_internal (obt_p, SP_ATTR_RETURN_TYPE, &value); - if (err != NO_ERROR) - { - goto error; - } - - param = set_create_sequence (0); - if (param == NULL) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - for (node_p = param_list, i = 0; node_p != NULL; node_p = node_p->next) - { - MOP mop = NULL; - - if (jsp_check_param_type_supported (node_p) != NO_ERROR) - { - err = er_errid (); - goto error; - } - - name_info = node_p->info.sp_param.name->info.name; - - arg_comment = (char *) PT_NODE_SP_ARG_COMMENT (node_p); - - err = - jsp_add_stored_procedure_argument (&mop, checked_name, name_info.original, i, node_p->type_enum, - node_p->info.sp_param.mode, arg_comment); - if (err != NO_ERROR) - { - goto error; - } - - db_make_object (&v, mop); - err = set_put_element (param, i++, &v); - pr_clear_value (&v); - - if (err != NO_ERROR) - { - goto error; - } - } - - db_make_sequence (&value, param); - err = dbt_put_internal (obt_p, SP_ATTR_ARGS, &value); - pr_clear_value (&value); - param = NULL; - if (err != NO_ERROR) - { - goto error; - } - - db_make_int (&value, i); - err = dbt_put_internal (obt_p, SP_ATTR_ARG_COUNT, &value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_int (&value, SP_LANG_JAVA); - err = dbt_put_internal (obt_p, SP_ATTR_LANG, &value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_string (&value, java_method); - err = dbt_put_internal (obt_p, SP_ATTR_TARGET, &value); - pr_clear_value (&value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_object (&value, Au_user); - err = dbt_put_internal (obt_p, SP_ATTR_OWNER, &value); - pr_clear_value (&value); - if (err != NO_ERROR) - { - goto error; - } - - db_make_string (&value, comment); - err = dbt_put_internal (obt_p, SP_ATTR_COMMENT, &value); - pr_clear_value (&value); - if (err != NO_ERROR) - { - goto error; - } - - object_p = dbt_finish_object (obt_p); - if (!object_p) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - obt_p = NULL; - - err = locator_flush_instance (object_p); - if (err != NO_ERROR) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - obj_delete (object_p); - goto error; - } - - free_and_init (checked_name); - AU_ENABLE (save); - return NO_ERROR; - -error: - if (param) - set_free (param); - - if (obt_p) - { - dbt_abort_object (obt_p); - } - - if (has_savepoint) - { - tran_abort_upto_system_savepoint (SAVEPOINT_ADD_STORED_PROC); - } - - free_and_init (checked_name); - AU_ENABLE (save); - - return err; -} - -/* - * drop_stored_procedure - - * return: Error code - * name(in): jsp name - * expected_type(in): - * - * Note: - */ - -static int -drop_stored_procedure (const char *name, PT_MISC_TYPE expected_type) -{ - MOP sp_mop, arg_mop, owner; - DB_VALUE sp_type_val, arg_cnt_val, args_val, owner_val, temp; - SP_TYPE_ENUM real_type; - DB_SET *arg_set_p; - int save, i, arg_cnt; - int err; - - AU_DISABLE (save); - - db_make_null (&args_val); - db_make_null (&owner_val); - - sp_mop = jsp_find_stored_procedure (name); - if (sp_mop == NULL) - { - assert (er_errid () != NO_ERROR); - err = er_errid (); - goto error; - } - - err = db_get (sp_mop, SP_ATTR_OWNER, &owner_val); - if (err != NO_ERROR) - { - goto error; - } - owner = db_get_object (&owner_val); - - if (!ws_is_same_object (owner, Au_user) && !au_is_dba_group_member (Au_user)) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED, 0); - err = er_errid (); - goto error; - } - - err = db_get (sp_mop, SP_ATTR_SP_TYPE, &sp_type_val); - if (err != NO_ERROR) - { - goto error; - } - - real_type = (SP_TYPE_ENUM) db_get_int (&sp_type_val); - if (real_type != jsp_map_pt_misc_to_sp_type (expected_type)) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_TYPE, 2, name, - real_type == SP_TYPE_FUNCTION ? "FUNCTION" : "PROCEDURE"); - - err = er_errid (); - goto error; - } - - err = db_get (sp_mop, SP_ATTR_ARG_COUNT, &arg_cnt_val); - if (err != NO_ERROR) - { - goto error; - } - - arg_cnt = db_get_int (&arg_cnt_val); - - err = db_get (sp_mop, SP_ATTR_ARGS, &args_val); - if (err != NO_ERROR) - { - goto error; - } - - arg_set_p = db_get_set (&args_val); - - for (i = 0; i < arg_cnt; i++) - { - set_get_element (arg_set_p, i, &temp); - arg_mop = db_get_object (&temp); - err = obj_delete (arg_mop); - pr_clear_value (&temp); - if (err != NO_ERROR) - { - goto error; - } - } - - err = obj_delete (sp_mop); - -error: - AU_ENABLE (save); - - pr_clear_value (&args_val); - pr_clear_value (&owner_val); - - return err; -} - -/* - * jsp_set_prepare_call - - * return: none - * - * Note: - */ - -void -jsp_set_prepare_call (void) -{ - int depth = tran_get_libcas_depth (); - is_prepare_call[depth] = true; -} - -/* - * jsp_unset_prepare_call - - * return: none - * - * Note: - */ - -void -jsp_unset_prepare_call (void) -{ - int depth = tran_get_libcas_depth (); - is_prepare_call[depth] = false; -} - -/* - * jsp_is_prepare_call - - * return: bool - * - * Note: - */ - -bool -jsp_is_prepare_call () -{ - int depth = tran_get_libcas_depth (); - return is_prepare_call[depth]; -} - -/* - * jsp_make_method_sig_list () - converts a parse expression tree list of - * method calls to method signature list - * return: A NULL return indicates a (memory) error occurred - * parser(in): - * node_list(in): should be parse method nodes - * subquery_as_attr_list(in): - */ -static int -jsp_make_method_sig_list (PARSER_CONTEXT * parser, PT_NODE * node, method_sig_list & sig_list) -{ - int error = NO_ERROR; - int save; - DB_VALUE method, param_cnt_val, mode, arg_type, temp, result_type; - - int sig_num_args = pt_length_of_list (node->info.method_call.arg_list); - std::vector < int >sig_arg_mode; - std::vector < int >sig_arg_type; - int sig_result_type; - - METHOD_SIG *sig = nullptr; - - db_make_null (&method); - db_make_null (¶m_cnt_val); - db_make_null (&mode); - db_make_null (&arg_type); - db_make_null (&temp); - db_make_null (&result_type); - - { - char *parsed_method_name = (char *) node->info.method_call.method_name->info.name.original; - DB_OBJECT *mop_p = jsp_find_stored_procedure (parsed_method_name); - AU_DISABLE (save); - if (mop_p) - { - /* check java stored prcedure target */ - error = db_get (mop_p, SP_ATTR_TARGET, &method); - if (error != NO_ERROR) - { - goto end; - } - - /* check arg count */ - error = db_get (mop_p, SP_ATTR_ARG_COUNT, ¶m_cnt_val); - if (error != NO_ERROR) - { - goto end; - } - - int param_cnt = db_get_int (¶m_cnt_val); - if (sig_num_args != param_cnt) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_PARAM_COUNT, 2, param_cnt, sig_num_args); - error = er_errid (); - goto end; - } - - DB_VALUE args; - /* arg_mode, arg_type */ - error = db_get (mop_p, SP_ATTR_ARGS, &args); - if (error != NO_ERROR) - { - goto end; - } - - DB_SET *param_set = db_get_set (&args); - for (int i = 0; i < sig_num_args; i++) - { - set_get_element (param_set, i, &temp); - DB_OBJECT *arg_mop_p = db_get_object (&temp); - if (arg_mop_p) - { - error = db_get (arg_mop_p, SP_ATTR_MODE, &mode); - int arg_mode = db_get_int (&mode); - - error = jsp_check_out_param_in_query (parser, node, arg_mode); - - if (error == NO_ERROR) - { - sig_arg_mode.push_back (arg_mode); - } - else - { - goto end; - } - - error = db_get (arg_mop_p, SP_ATTR_DATA_TYPE, &arg_type); - if (error == NO_ERROR) - { - int type_val = db_get_int (&arg_type); - if (type_val == DB_TYPE_RESULTSET && !jsp_is_prepare_call ()) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0); - error = er_errid (); - goto end; - } - sig_arg_type.push_back (type_val); - } - else - { - goto end; - } - - pr_clear_value (&mode); - pr_clear_value (&arg_type); - pr_clear_value (&temp); - } - } - pr_clear_value (&args); - - /* result type */ - error = db_get (mop_p, SP_ATTR_RETURN_TYPE, &result_type); - if (error != NO_ERROR) - { - goto end; - } - sig_result_type = db_get_int (&result_type); - if (sig_result_type == DB_TYPE_RESULTSET && !jsp_is_prepare_call ()) - { - er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0); - error = er_errid (); - goto end; - } - } - else - { - error = er_errid (); - goto end; - } - - sig = sig_list.method_sig = (METHOD_SIG *) db_private_alloc (NULL, sizeof (METHOD_SIG)); - if (sig) - { - sig->next = nullptr; - sig->num_method_args = sig_num_args; - sig->method_type = METHOD_TYPE_JAVA_SP; - - const char *method_name = db_get_string (&method); - int method_name_len = db_get_string_size (&method); - - sig->method_name = (char *) db_private_alloc (NULL, method_name_len + 1); - if (!sig->method_name) - { - error = ER_OUT_OF_VIRTUAL_MEMORY; - goto end; - } - - memcpy (sig->method_name, method_name, method_name_len); - sig->method_name[method_name_len] = 0; - - - sig->method_arg_pos = (int *) db_private_alloc (NULL, (sig_num_args + 1) * sizeof (int)); - if (!sig->method_arg_pos) - { - error = ER_OUT_OF_VIRTUAL_MEMORY; - goto end; - } - - for (int i = 0; i < sig_num_args + 1; i++) - { - sig->method_arg_pos[i] = i; - } - - - sig->arg_info.arg_mode = (int *) db_private_alloc (NULL, (sig_num_args + 1) * sizeof (int)); - if (!sig->arg_info.arg_mode) - { - error = ER_OUT_OF_VIRTUAL_MEMORY; - goto end; - } - - sig->arg_info.arg_type = (int *) db_private_alloc (NULL, (sig_num_args + 1) * sizeof (int)); - if (!sig->arg_info.arg_type) - { - error = ER_OUT_OF_VIRTUAL_MEMORY; - goto end; - } - - for (int i = 0; i < sig_num_args; i++) - { - sig->arg_info.arg_mode[i] = sig_arg_mode[i]; - sig->arg_info.arg_type[i] = sig_arg_type[i]; - } - - sig->arg_info.result_type = sig_result_type; - - sig_list.num_methods = 1; - } - else - { - error = ER_OUT_OF_VIRTUAL_MEMORY; - goto end; - } - } - -end: - AU_ENABLE (save); - if (error != NO_ERROR) - { - if (sig) - { - sig->freemem (); - } - sig_list.method_sig = nullptr; - sig_list.num_methods = 0; - } - - pr_clear_value (&method); - pr_clear_value (¶m_cnt_val); - pr_clear_value (&result_type); - - return error; -} - -/* - * pt_to_method_arglist () - converts a parse expression tree list of - * method call arguments to method argument array - * return: A NULL on error occurred - * parser(in): - * target(in): - * node_list(in): should be parse name nodes - * subquery_as_attr_list(in): - */ -static int * -jsp_make_method_arglist (PARSER_CONTEXT * parser, PT_NODE * node_list) -{ - int *arg_list = NULL; - int i = 0; - int num_args = pt_length_of_list (node_list); - PT_NODE *node; - - arg_list = (int *) db_private_alloc (NULL, num_args * sizeof (int)); - if (!arg_list) - { - return NULL; - } - - for (node = node_list; node != NULL; node = node->next) - { - arg_list[i] = i; - i++; - /* - arg_list[i] = pt_find_attribute (parser, node, subquery_as_attr_list); - if (arg_list[i] == -1) - { - return NULL; - } - i++; - */ - } - - return arg_list; -} diff --git a/src/sp/jsp_cl.cpp b/src/sp/jsp_cl.cpp new file mode 100644 index 0000000000..873446a8d6 --- /dev/null +++ b/src/sp/jsp_cl.cpp @@ -0,0 +1,2438 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * jsp_cl.cpp - Java Stored Procedure Client Module Source + */ + +#ident "$Id$" + +#include "config.h" + +#include +#if !defined(WINDOWS) +#include +#else /* not WINDOWS */ +#include +#endif /* not WINDOWS */ + +#include +#include +#include +#include +#include +#include + +#include "authenticate.h" +#include "error_manager.h" +#include "memory_alloc.h" +#include "dbtype.h" +#include "parser.h" +#include "parser_message.h" +#include "object_domain.h" +#include "object_primitive.h" +#include "object_representation.h" +#include "db.h" +#include "object_accessor.h" +#include "set_object.h" +#include "locator_cl.h" +#include "transaction_cl.h" +#include "schema_manager.h" +#include "numeric_opfunc.h" +#include "jsp_cl.h" +#include "system_parameter.h" +#include "network_interface_cl.h" +#include "unicode_support.h" +#include "dbtype.h" +#include "pl_comm.h" +#include "pl_struct_compile.hpp" +#include "sp_catalog.hpp" +#include "authenticate_access_auth.hpp" +#include "pl_signature.hpp" +#include "oid.h" +#include "string_buffer.hpp" +#include "db_value_printer.hpp" +#include "execute_statement.h" + +#define PT_NODE_SP_NAME(node) \ + (((node)->info.sp.name == NULL) ? "" : \ + (node)->info.sp.name->info.name.original) + +#define PT_NODE_SP_TYPE(node) \ + ((node)->info.sp.type) + +#define PT_NODE_SP_RETURN_TYPE(node) \ + ((node)->info.sp.ret_type->info.name.original) + +#define PT_NODE_SP_BODY(node) \ + ((node)->info.sp.body) + +#define PT_NODE_SP_LANG(node) \ + ((node)->info.sp.body->info.sp_body.lang) + +#define PT_NODE_SP_ARGS(node) \ + ((node)->info.sp.param_list) + +#define PT_NODE_SP_DIRECT(node) \ + ((node)->info.sp.body->info.sp_body.direct) + +#define PT_NODE_SP_IMPL(node) \ + ((node)->info.sp.body->info.sp_body.impl->info.value.data_value.str->bytes) + +#define PT_NODE_SP_JAVA_METHOD(node) \ + ((node)->info.sp.body->info.sp_body.decl->info.value.data_value.str->bytes) + +#define PT_NODE_SP_AUTHID(node) \ + ((node)->info.sp.auth_id) + +#define PT_NODE_SP_COMMENT(node) \ + (((node)->info.sp.comment == NULL) ? "" : \ + (char *) (node)->info.sp.comment->info.value.data_value.str->bytes) + +#define PT_NODE_SP_ARG_NAME(node) \ + (((node)->info.sp_param.name == NULL) ? "" : \ + (node)->info.sp_param.name->info.name.original) + +#define PT_NODE_SP_ARG_COMMENT(node) \ + (((node)->info.sp_param.comment == NULL) ? "" : \ + (char *) (node)->info.sp_param.comment->info.value.data_value.str->bytes) + +#define MAX_CALL_COUNT 16 + +#define MAX_ARG_COUNT 64 + +static int server_port = -1; +static int call_cnt = 0; +static bool is_prepare_call[MAX_CALL_COUNT] = { false, }; + +static SP_TYPE_ENUM jsp_map_pt_misc_to_sp_type (PT_MISC_TYPE pt_enum); +static SP_MODE_ENUM jsp_map_pt_misc_to_sp_mode (PT_MISC_TYPE pt_enum); +static PT_MISC_TYPE jsp_map_sp_type_to_pt_misc (SP_TYPE_ENUM sp_type); +static SP_DIRECTIVE_ENUM jsp_map_pt_to_sp_authid (PT_MISC_TYPE pt_authid); + +static char *jsp_check_stored_procedure_name (const char *str); +static int jsp_check_overflow_args (PARSER_CONTEXT *parser, PT_NODE *node, int num_params, int num_args); +static int jsp_check_out_param_in_query (PARSER_CONTEXT *parser, PT_NODE *node, int arg_mode); +static int jsp_check_param_type_supported (DB_TYPE type, int mode); + +static int drop_stored_procedure (const char *name, SP_TYPE_ENUM expected_type); +static int drop_stored_procedure_code (const char *name); +static int alter_stored_procedure_code (PARSER_CONTEXT *parser, MOP sp_mop, const char *name, const char *owner_str, + int sp_recompile); + +static int jsp_default_value_string (PARSER_CONTEXT *parser, PT_NODE *node, std::string &out); +static int check_execute_authorization (const MOP sp_obj, const DB_AUTH au_type); + +extern bool ssl_client; + +/* + * jsp_is_exist_stored_procedure + * return: name is exist then return true + * else return false + * name(in): find java stored procedure name + * + * Note: + */ + +int +jsp_is_exist_stored_procedure (const char *name) +{ + MOP mop = NULL; + + mop = jsp_find_stored_procedure (name, DB_AUTH_NONE); + er_clear (); + + return mop != NULL; +} + +/* + * jsp_find_stored_procedure + * return: MOP + * name(in): find java stored procedure name + * purpose(in): DB_AUTH_NONE or DB_AUTH_SELECT + * + * Note: + */ + +MOP +jsp_find_stored_procedure (const char *name, DB_AUTH purpose) +{ + MOP mop = NULL; + DB_VALUE value; + int save, err = NO_ERROR; + char *checked_name; + + if (!name) + { + return NULL; + } + + AU_DISABLE (save); + + checked_name = jsp_check_stored_procedure_name (name); + db_make_string (&value, checked_name); + mop = db_find_unique (db_find_class (SP_CLASS_NAME), SP_ATTR_UNIQUE_NAME, &value); + + if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND) + { + er_clear (); + + /* This is the case when the loaddb utility is executed with the --no-user-specified-name option as the dba user. */ + if (db_get_client_type () == DB_CLIENT_TYPE_ADMIN_LOADDB_COMPAT) + { + err = jsp_find_sp_of_another_owner (name, &mop); + } + else + { + err = ER_SP_NOT_EXIST; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, err, 1, checked_name); + } + } + + if (mop) + { + err = check_execute_authorization (mop, purpose); + } + + if (err != NO_ERROR) + { + mop = NULL; + } + + free_and_init (checked_name); + AU_ENABLE (save); + + return mop; +} + +/* + * jsp_find_stored_procedure_code + * return: MOP + * name(in): find java stored procedure name + * + * Note: + */ + +MOP +jsp_find_stored_procedure_code (const char *name) +{ + MOP mop = NULL; + DB_VALUE value; + int save; + + if (!name) + { + return NULL; + } + + AU_DISABLE (save); + + db_make_string (&value, name); + mop = db_find_unique (db_find_class (SP_CODE_CLASS_NAME), SP_ATTR_CLS_NAME, &value); + + if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND) + { + er_clear (); + } + + AU_ENABLE (save); + + return mop; +} + +/* + * jsp_find_sp_of_another_owner + * return: if fail return error code + * name(in): find java stored procedure name + * return_mop(in): retrieves the name of a java stored procedure and returns its MOP value. + * + * Note: This is a function for finding the unique_name of an SP when running the loaddb utility with the --no-user-specified-name option as a dba user. + */ + +int +jsp_find_sp_of_another_owner (const char *name, MOP *return_mop) +{ + int error = NO_ERROR; + DB_VALUE value; + char other_class_name[DB_MAX_IDENTIFIER_LENGTH]; + other_class_name[0] = '\0'; + *return_mop = NULL; + + error = do_find_stored_procedure_by_query (name, other_class_name, DB_MAX_IDENTIFIER_LENGTH); + if (other_class_name[0] != '\0') + { + db_make_string (&value, other_class_name); + *return_mop = db_find_unique (db_find_class (SP_CLASS_NAME), SP_ATTR_UNIQUE_NAME, &value); + if (er_errid () == ER_OBJ_OBJECT_NOT_FOUND) + { + error = ER_SP_NOT_EXIST; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, other_class_name); + } + } + + return error; +} + +/* + * jsp_check_out_param_in_query + * + * Note: + */ + +static int +jsp_check_out_param_in_query (PARSER_CONTEXT *parser, PT_NODE *node, int arg_mode) +{ + int error = NO_ERROR; + + assert ((node) && (node)->node_type == PT_METHOD_CALL); + + if (node->info.method_call.call_or_expr != PT_IS_CALL_STMT) + { + // check out parameters + if (arg_mode != SP_MODE_IN) + { + PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_SP_OUT_ARGS_EXISTS_IN_QUERY, + node->info.method_call.method_name->info.name.original); + error = ER_PT_SEMANTIC; + } + } + + return error; +} + +/* + * jsp_check_param_type_supported + * + * Note: + */ + +static int +jsp_check_param_type_supported (DB_TYPE type, int mode) +{ + switch (type) + { + case DB_TYPE_INTEGER: + case DB_TYPE_FLOAT: + case DB_TYPE_DOUBLE: + case DB_TYPE_STRING: + case DB_TYPE_OBJECT: + case DB_TYPE_SET: + case DB_TYPE_MULTISET: + case DB_TYPE_SEQUENCE: + case DB_TYPE_TIME: + case DB_TYPE_TIMESTAMP: + case DB_TYPE_DATE: + case DB_TYPE_MONETARY: + case DB_TYPE_SHORT: + case DB_TYPE_NUMERIC: + case DB_TYPE_CHAR: + case DB_TYPE_BIGINT: + case DB_TYPE_DATETIME: + return NO_ERROR; + break; + + case DB_TYPE_RESULTSET: + if (mode != SP_MODE_OUT) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_INPUT_RESULTSET, 0); + } + else if (!jsp_is_prepare_call ()) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0); + } + else + { + return NO_ERROR; + } + break; + + default: + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, pr_type_name (type)); + break; + } + + return er_errid (); +} + +/* + * jsp_check_return_type_supported + * + * Note: + */ + +int +jsp_check_return_type_supported (DB_TYPE type) +{ + switch (type) + { + case DB_TYPE_NULL: + case DB_TYPE_INTEGER: + case DB_TYPE_FLOAT: + case DB_TYPE_DOUBLE: + case DB_TYPE_STRING: + case DB_TYPE_OBJECT: + case DB_TYPE_SET: + case DB_TYPE_MULTISET: + case DB_TYPE_SEQUENCE: + case DB_TYPE_TIME: + case DB_TYPE_TIMESTAMP: + case DB_TYPE_DATE: + case DB_TYPE_MONETARY: + case DB_TYPE_SHORT: + case DB_TYPE_NUMERIC: + case DB_TYPE_CHAR: + case DB_TYPE_BIGINT: + case DB_TYPE_DATETIME: + return NO_ERROR; + case DB_TYPE_RESULTSET: + if (!jsp_is_prepare_call ()) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_RETURN_RESULTSET, 0); + } + break; + + default: + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_RETURN_TYPE, 1, pr_type_name (type)); + break; + } + + return er_errid (); +} + +/* + * jsp_get_return_type - Return Java Stored Procedure Type + * return: if fail return error code + * else return Java Stored Procedure Type + * name(in): java stored procedure name + * + * Note: + */ + +int +jsp_get_return_type (const char *name) +{ + DB_OBJECT *mop_p; + DB_VALUE return_type; + int err; + int save; + + AU_DISABLE (save); + + mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE); + if (mop_p == NULL) + { + AU_ENABLE (save); + + assert (er_errid () != NO_ERROR); + return er_errid (); + } + + err = db_get (mop_p, SP_ATTR_RETURN_TYPE, &return_type); + if (err != NO_ERROR) + { + AU_ENABLE (save); + return err; + } + + AU_ENABLE (save); + return db_get_int (&return_type); +} + +/* + * jsp_get_sp_type - Return Java Stored Procedure Type + * return: if fail return error code + * else return Java Stored Procedure Type + * name(in): java stored procedure name + * + * Note: + */ + +int +jsp_get_sp_type (const char *name) +{ + DB_OBJECT *mop_p; + DB_VALUE sp_type_val; + int err; + int save; + + AU_DISABLE (save); + + mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE); + if (mop_p == NULL) + { + AU_ENABLE (save); + + assert (er_errid () != NO_ERROR); + return er_errid (); + } + + /* check type */ + err = db_get (mop_p, SP_ATTR_SP_TYPE, &sp_type_val); + if (err != NO_ERROR) + { + AU_ENABLE (save); + return err; + } + + AU_ENABLE (save); + return jsp_map_sp_type_to_pt_misc ((SP_TYPE_ENUM) db_get_int (&sp_type_val)); +} + +MOP +jsp_get_owner (MOP mop_p) +{ + int save; + DB_VALUE value; + + AU_DISABLE (save); + + /* check type */ + int err = db_get (mop_p, SP_ATTR_OWNER, &value); + if (err != NO_ERROR) + { + AU_ENABLE (save); + return NULL; + } + + MOP owner = db_get_object (&value); + + AU_ENABLE (save); + return owner; +} + +char * +jsp_get_name (MOP mop_p) +{ + int save; + DB_VALUE value; + char *res = NULL; + + AU_DISABLE (save); + + /* check type */ + int err = db_get (mop_p, SP_ATTR_NAME, &value); + if (err != NO_ERROR) + { + AU_ENABLE (save); + return NULL; + } + + res = ws_copy_string (db_get_string (&value)); + pr_clear_value (&value); + + AU_ENABLE (save); + return res; +} + +char * +jsp_get_unique_name (MOP mop_p, char *buf, int buf_size) +{ + int save; + DB_VALUE value; + int err = NO_ERROR; + + assert (buf != NULL); + assert (buf_size > 0); + + if (mop_p == NULL) + { + ERROR_SET_WARNING (err, ER_SM_INVALID_ARGUMENTS); + buf[0] = '\0'; + return NULL; + } + + AU_DISABLE (save); + + /* check type */ + err = db_get (mop_p, SP_ATTR_UNIQUE_NAME, &value); + if (err != NO_ERROR) + { + AU_ENABLE (save); + return NULL; + } + + strncpy (buf, db_get_string (&value), buf_size); + pr_clear_value (&value); + + AU_ENABLE (save); + return buf; +} + +/* + * jsp_get_owner_name - Return Java Stored Procedure'S Owner nmae + * return: if fail return MULL + * else return Java Stored Procedure Type + * name(in): java stored procedure name + * + * Note: + */ + +char * +jsp_get_owner_name (const char *name, char *buf, int buf_size) +{ + DB_OBJECT *mop_p; + DB_VALUE value; + int err; + int save; + + assert (buf != NULL); + assert (buf_size > 0); + + if (name == NULL || name[0] == '\0') + { + ERROR_SET_WARNING (err, ER_SM_INVALID_ARGUMENTS); + buf[0] = '\0'; + return NULL; + } + + AU_DISABLE (save); + + mop_p = jsp_find_stored_procedure (name, DB_AUTH_NONE); + if (mop_p == NULL) + { + AU_ENABLE (save); + + assert (er_errid () != NO_ERROR); + return NULL; + } + + /* check type */ + err = db_get (mop_p, SP_ATTR_OWNER, &value); + if (err != NO_ERROR) + { + AU_ENABLE (save); + return NULL; + } + + MOP owner = db_get_object (&value); + if (owner != NULL) + { + DB_VALUE value2; + err = db_get (owner, "name", &value2); + if (err == NO_ERROR) + { + strncpy (buf, db_get_string (&value2), buf_size); + } + pr_clear_value (&value2); + } + pr_clear_value (&value); + + AU_ENABLE (save); + return buf; +} + + + +static PT_MISC_TYPE +jsp_map_sp_type_to_pt_misc (SP_TYPE_ENUM sp_type) +{ + if (sp_type == SP_TYPE_PROCEDURE) + { + return PT_SP_PROCEDURE; + } + else + { + return PT_SP_FUNCTION; + } +} + +static int +jsp_evaluate_arguments (PARSER_CONTEXT *parser, PT_NODE *statement, + std::vector > &args) +{ + assert (statement); + assert (statement->node_type == PT_METHOD_CALL); + + PT_NODE *vc = statement->info.method_call.arg_list; + while (vc) + { + DB_VALUE *db_value; + + /* + * Don't clone host vars; they may actually be acting as output variables (e.g., a character array that is + * intended to receive bytes from the method), and cloning will ensure that the results never make it to the + * expected area. Since pt_evaluate_tree() always clones its db_values we must not use pt_evaluate_tree() to + * extract the db_value from a host variable; instead extract it ourselves. */ + if (PT_IS_CONST (vc)) + { + db_value = pt_value_to_db (parser, vc); + } + else + { + db_value = (DB_VALUE *) malloc (sizeof (DB_VALUE)); + if (db_value == NULL) + { + goto exit_on_error; + } + + db_make_null (db_value); + + /* must call pt_evaluate_tree */ + pt_evaluate_tree_having_serial (parser, vc, db_value, 1); + if (pt_has_error (parser)) + { + /* to maintain the list to free all the allocated */ + db_value_clear (db_value); + goto exit_on_error; + } + } + + args.emplace_back (std::ref (*db_value)); + vc = vc->next; + } + + return NO_ERROR; + +exit_on_error: + + for (DB_VALUE &val : args) + { + db_value_clear (&val); + } + args.clear (); + + return ER_FAILED; +} + +/* + * jsp_call_stored_procedure - call java stored procedure in constant folding + * return: call jsp failed return error code + * parser(in/out): parser environment + * statement(in): a statement node + * + * Note: + */ + +int +jsp_call_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement) +{ + int error = NO_ERROR; + PT_NODE *method; + const char *method_name; + if (!statement || ! (method = statement->info.method_call.method_name) || method->node_type != PT_NAME) + { + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0); + return er_errid (); + } + + DB_VALUE ret_value; + db_make_null (&ret_value); + + /* call sp */ + std::vector > args; + cubpl::pl_signature sig; + error = jsp_make_pl_signature (parser, statement, NULL, sig); + if (error == NO_ERROR) + { + PT_NODE *default_next_node_list = jsp_get_default_expr_node_list (parser, sig); + if (default_next_node_list != NULL) + { + error = qp_get_server_info (parser, SI_SYS_DATETIME); + } + statement->info.method_call.arg_list = parser_append_node (default_next_node_list, + statement->info.method_call.arg_list); + error = jsp_evaluate_arguments (parser, statement, args); + if (pt_has_error (parser)) + { + pt_report_to_ersys (parser, PT_SEMANTIC); + error = er_errid (); + } + } + + if (error == NO_ERROR && locator_get_sig_interrupt () == 0) + { + std::vector out_args; + error = pl_call (sig, args, out_args, ret_value); + if (error == NO_ERROR) + { + for (int i = 0, j = 0; i < sig.arg.arg_size; i++) + { + if (sig.arg.arg_mode[i] == SP_MODE_IN) + { + continue; + } + + DB_VALUE &arg = args[i]; + DB_VALUE &out_arg = out_args[j++]; + + db_value_clear (&arg); + db_value_clone (&out_arg, &arg); + db_value_clear (&out_arg); + } + } + } + + PT_NODE *vc = statement->info.method_call.arg_list; + for (int i = 0; i < (int) args.size () && vc; i++) + { + if (!PT_IS_CONST (vc)) + { + DB_VALUE &arg = args[i]; + db_value_clear (&arg); + free (&arg); + } + vc = vc->next; + } + + if (error == NO_ERROR) + { + /* Save the method result and its domain */ + statement->etc = (void *) db_value_copy (&ret_value); + statement = pt_bind_type_from_dbval (parser, statement, &ret_value); + + PT_NODE *into = statement->info.method_call.to_return_var; + + const char *into_label; + if (into != NULL && into->node_type == PT_NAME && (into_label = into->info.name.original) != NULL) + { + /* create another DB_VALUE of the new instance for the label_table */ + DB_VALUE *ins_value = db_value_copy (&ret_value); + error = pt_associate_label_with_value_check_reference (into_label, ins_value); + } + } + +#if defined (CS_MODE) + db_value_clear (&ret_value); +#endif + + return error; +} + +/* + * jsp_drop_stored_procedure - drop java stored procedure + * return: Error code + * parser(in/out): parser environment + * statement(in): a statement node + * + * Note: + */ + +int +jsp_drop_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement) +{ + const char *name; + PT_MISC_TYPE type; + PT_NODE *name_list, *p; + int i; + int err = NO_ERROR; + + CHECK_MODIFICATION_ERROR (); + + if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0); + return ER_BLOCK_DDL_STMT; + } + + name_list = statement->info.sp.name; + type = PT_NODE_SP_TYPE (statement); + + for (p = name_list, i = 0; p != NULL; p = p->next) + { + name = (char *) p->info.name.original; + if (name == NULL || name[0] == '\0') + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0); + return er_errid (); + } + + err = drop_stored_procedure (name, jsp_map_pt_misc_to_sp_type (type)); + if (err != NO_ERROR) + { + break; + } + } + + return err; +} + +/* + * jsp_default_value_string + * return: + * parser(in/out): parser environment + * statement(in): a default_value node + * + * Note: + */ +static int +jsp_default_value_string (PARSER_CONTEXT *parser, PT_NODE *node, std::string &out) +{ + int error = NO_ERROR; + + DB_DEFAULT_EXPR default_expr; + pt_get_default_expression_from_data_default_node (parser, node, &default_expr); + + out.clear (); + if (default_expr.default_expr_type != DB_DEFAULT_NONE) + { + if (default_expr.default_expr_type == NULL_DEFAULT_EXPRESSION_OPERATOR) + { + DB_VALUE *value = pt_value_to_db (parser, node->info.data_default.default_value); + if (!DB_IS_NULL (value)) + { + string_buffer sb; + sb.clear (); + db_sprint_value (value, sb); + + out.append (sb.get_buffer ()); + } + else + { + // empty out consider as NULL + } + } + else + { + if (default_expr.default_expr_op == T_TO_CHAR) + { + out.append ("TO_CHAR("); + } + + const char *default_value_expr_type_string = db_default_expression_string (default_expr.default_expr_type); + if (default_value_expr_type_string != NULL) + { + out.append (default_value_expr_type_string); + } + else + { + out.append (parser_print_tree (parser, node)); + } + + if (default_expr.default_expr_op == T_TO_CHAR) + { + if (default_expr.default_expr_format != NULL) + { + out.append (", \'"); + out.append (default_expr.default_expr_format); + out.append ("\'"); + } + + out.append (")"); + } + } + } + else + { + DB_VALUE *value = pt_value_to_db (parser, node->info.data_default.default_value); + if (!DB_IS_NULL (value)) + { + string_buffer sb; + sb.clear (); + db_sprint_value (value, sb); + + out.append (sb.get_buffer ()); + } + else + { + // empty out consider as NULL + } + } + + return error; +} + +/* + * jsp_create_stored_procedure + * return: if failed return error code else execute jsp_add_stored_procedure + * function + * parser(in/out): parser environment + * statement(in): a statement node + * + * Note: + */ + +int +jsp_create_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement) +{ + const char *decl = NULL, *comment = NULL; + char owner_name[DB_MAX_USER_LENGTH]; + owner_name[0] = '\0'; + + PT_NODE *param_list, *p; + PT_TYPE_ENUM ret_type = PT_TYPE_NONE; + int lang; + int err = NO_ERROR; + bool has_savepoint = false; + + PLCSQL_COMPILE_REQUEST compile_request; + PLCSQL_COMPILE_RESPONSE compile_response; + + SP_INFO sp_info; + char *temp; + + CHECK_MODIFICATION_ERROR (); + + if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0); + return ER_BLOCK_DDL_STMT; + } + + // check PL/CSQL's AUTHID with CURRENT_USER + sp_info.directive = jsp_map_pt_to_sp_authid (PT_NODE_SP_AUTHID (statement)); + sp_info.lang = (SP_LANG_ENUM) PT_NODE_SP_LANG (statement); + if (sp_info.directive == SP_DIRECTIVE_RIGHTS_CALLER && sp_info.lang == SP_LANG_PLCSQL) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVOKERS_RIGHTS_NOT_SUPPORTED, 0); + return er_errid (); + } + + temp = jsp_check_stored_procedure_name (PT_NODE_SP_NAME (statement)); + sp_info.unique_name = temp; + free (temp); + if (sp_info.unique_name.empty ()) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0); + return er_errid (); + } + + sp_info.sp_name = sm_remove_qualifier_name (sp_info.unique_name.data ()); + if (sp_info.sp_name.empty ()) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_NAME, 0); + return er_errid (); + } + + sp_info.sp_type = jsp_map_pt_misc_to_sp_type (PT_NODE_SP_TYPE (statement)); + if (sp_info.sp_type == SP_TYPE_FUNCTION) + { + sp_info.return_type = pt_type_enum_to_db (statement->info.sp.ret_type); + } + else + { + sp_info.return_type = DB_TYPE_NULL; + } + + // set rows for _db_stored_procedure_args + int param_count = 0; + param_list = PT_NODE_SP_ARGS (statement); + for (p = param_list; p != NULL; p = p->next) + { + SP_ARG_INFO arg_info (sp_info.unique_name, sp_info.pkg_name); + + arg_info.index_of = param_count++; + arg_info.arg_name = PT_NODE_SP_ARG_NAME (p); + arg_info.data_type = pt_type_enum_to_db (p->type_enum); + arg_info.mode = jsp_map_pt_misc_to_sp_mode (p->info.sp_param.mode); + + // default value + // coerciable is already checked in semantic_check + PT_NODE *default_value = p->info.sp_param.default_value; + if (default_value) + { + std::string default_value_str; + if (jsp_default_value_string (parser, default_value, default_value_str) == NO_ERROR) + { + if (!default_value_str.empty ()) + { + db_make_string (&arg_info.default_value, ws_copy_string (default_value_str.c_str ())); + } + else + { + db_make_null (&arg_info.default_value); + } + + arg_info.is_optional = true; + } + else + { + ASSERT_ERROR (); + goto error_exit; + } + } + else + { + db_make_null (&arg_info.default_value); + arg_info.is_optional = false; // explicitly + } + + arg_info.comment = (char *) PT_NODE_SP_ARG_COMMENT (p); + + // check # of args constraint + if (param_count > MAX_ARG_COUNT) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_TOO_MANY_ARG_COUNT, 1, sp_info.unique_name.data ()); + goto error_exit; + } + + sp_info.args.push_back (arg_info); + } + + if (sm_qualifier_name (sp_info.unique_name.data (), owner_name, DB_MAX_USER_LENGTH) == NULL) + { + ASSERT_ERROR (); + goto error_exit; + } + + sp_info.owner = owner_name[0] == '\0' ? Au_user : db_find_user (owner_name); + if (sp_info.owner == NULL) + { + // for safeguard: it is already checked in pt_check_create_stored_procedure () + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_INVALID_USER_NAME, 1, owner_name); + goto error_exit; + } + + if (sp_info.lang == SP_LANG_PLCSQL) + { + assert (statement->sql_user_text && statement->sql_user_text_len); + compile_request.code.assign (statement->sql_user_text, statement->sql_user_text_len); + compile_request.owner.assign ((owner_name[0] == '\0') ? au_get_current_user_name () : owner_name); + + // TODO: Only the owner's rights is supported for PL/CSQL + au_perform_push_user (sp_info.owner); + err = plcsql_transfer_file (compile_request, compile_response); + au_perform_pop_user (); + + if (err == NO_ERROR && compile_response.err_code == NO_ERROR) + { + decl = compile_response.java_signature.c_str (); + } + else + { + err = ER_SP_COMPILE_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_COMPILE_ERROR, 3, compile_response.err_line, + compile_response.err_column, compile_response.err_msg.c_str ()); + pt_record_error (parser, parser->statement_number, compile_response.err_line, compile_response.err_column, er_msg (), + NULL); + goto error_exit; + } + } + else /* SP_LANG_JAVA */ + { + bool is_direct = PT_NODE_SP_DIRECT (statement); + if (is_direct) + { + // TODO: CBRD-24641 + assert (false); + } + else + { + decl = (const char *) PT_NODE_SP_JAVA_METHOD (statement); + } + } + + if (decl) + { + std::string target = decl; + sp_split_target_signature (target, sp_info.target_class, sp_info.target_method); + } + + sp_info.comment = (char *) PT_NODE_SP_COMMENT (statement); + + if (err != NO_ERROR) + { + goto error_exit; + } + + /* check already exists */ + if (jsp_is_exist_stored_procedure (sp_info.unique_name.data ())) + { + if (statement->info.sp.or_replace) + { + /* drop existing stored procedure */ + err = tran_system_savepoint (SAVEPOINT_CREATE_STORED_PROC); + if (err != NO_ERROR) + { + return err; + } + has_savepoint = true; + + err = drop_stored_procedure (sp_info.unique_name.data (), sp_info.sp_type); + if (err != NO_ERROR) + { + goto error_exit; + } + } + else + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_ALREADY_EXIST, 1, sp_info.unique_name.data ()); + goto error_exit; + } + } + + err = sp_add_stored_procedure (sp_info); + if (err != NO_ERROR) + { + goto error_exit; + } + + if (!compile_request.code.empty ()) + { + SP_CODE_INFO code_info; + + auto now = std::chrono::system_clock::now(); + auto converted_timep = std::chrono::system_clock::to_time_t (now); + std::stringstream stm; + stm << std::put_time (localtime (&converted_timep), "%Y%m%d%H%M%S"); + + code_info.name = sp_info.target_class; + code_info.created_time = stm.str (); + code_info.stype = (sp_info.lang == SP_LANG_PLCSQL) ? SPSC_PLCSQL : SPSC_JAVA; + code_info.scode = compile_request.code; + code_info.otype = compile_response.compiled_type; + code_info.ocode = compile_response.compiled_code; + code_info.owner = sp_info.owner; + + err = sp_add_stored_procedure_code (code_info); + if (err != NO_ERROR) + { + goto error_exit; + } + } + + return NO_ERROR; + +error_exit: + if (has_savepoint) + { + tran_abort_upto_system_savepoint (SAVEPOINT_CREATE_STORED_PROC); + } + + return (err == NO_ERROR) ? er_errid () : err; +} + +/* + * jsp_alter_stored_procedure + * return: if failed return error code else NO_ERROR + * parser(in/out): parser environment + * statement(in): a statement node + * + * Note: + */ + +int +jsp_alter_stored_procedure (PARSER_CONTEXT *parser, PT_NODE *statement) +{ + int err = NO_ERROR, sp_recompile, save, lang; + PT_NODE *sp_name = NULL, *sp_owner = NULL, *sp_comment = NULL; + const char *name_str = NULL, *owner_str = NULL, *comment_str = NULL, *target_cls = NULL; + char new_name_str[DB_MAX_IDENTIFIER_LENGTH]; + new_name_str[0] = '\0'; + char downcase_owner_name[DB_MAX_USER_LENGTH]; + downcase_owner_name[0] = '\0'; + char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1]; + unique_name[0] = '\0'; + PT_MISC_TYPE type; + SP_TYPE_ENUM real_type; + MOP sp_mop = NULL, new_owner = NULL, owner = NULL, save_user = NULL; + DB_VALUE user_val, sp_type_val, sp_lang_val, target_cls_val; + + assert (statement != NULL); + + CHECK_MODIFICATION_ERROR (); + + if (prm_get_bool_value (PRM_ID_BLOCK_DDL_STATEMENT)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_BLOCK_DDL_STMT, 0); + return ER_BLOCK_DDL_STMT; + } + + db_make_null (&user_val); + db_make_null (&sp_type_val); + db_make_null (&sp_lang_val); + db_make_null (&target_cls_val); + + type = PT_NODE_SP_TYPE (statement); + sp_name = statement->info.sp.name; + assert (sp_name != NULL); + + sp_owner = statement->info.sp.owner; + sp_recompile = statement->info.sp.recompile; + sp_comment = statement->info.sp.comment; + + assert (sp_owner != NULL || sp_comment != NULL || sp_recompile); + + name_str = sp_name->info.name.original; + assert (name_str != NULL); + + if (sp_owner != NULL) + { + owner_str = sp_owner->info.name.original; + assert (owner_str != NULL); + } + + comment_str = (char *) PT_NODE_SP_COMMENT (statement); + + AU_DISABLE (save); + + /* authentication */ + if (!au_is_dba_group_member (Au_user)) + { + err = ER_AU_DBA_ONLY; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, "change stored procedure owner"); + goto error; + } + + /* existence of sp */ + sp_mop = jsp_find_stored_procedure (name_str, DB_AUTH_SELECT); + if (sp_mop == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + /* when changing the owner, all privileges are revoked */ + if (jsp_get_unique_name (sp_mop, unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL) + { + assert (er_errid () != NO_ERROR); + } + + owner = jsp_get_owner (sp_mop); + if (owner == NULL) + { + err = ER_FAILED; + goto error; + } + + save_user = Au_user; + if (AU_SET_USER (owner) == NO_ERROR) + { + err = au_object_revoke_all_privileges (DB_OBJECT_PROCEDURE, owner, unique_name); + if (err != NO_ERROR) + { + AU_SET_USER (save_user); + goto error; + } + } + + AU_SET_USER (save_user); + + /* existence of new owner */ + if (sp_owner != NULL) + { + new_owner = db_find_user (owner_str); + if (new_owner == NULL) + { + err = ER_OBJ_OBJECT_NOT_FOUND; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 1, owner_str); + goto error; + } + } + + /* check type */ + err = db_get (sp_mop, SP_ATTR_SP_TYPE, &sp_type_val); + if (err != NO_ERROR) + { + goto error; + } + + real_type = (SP_TYPE_ENUM) db_get_int (&sp_type_val); + if (real_type != jsp_map_pt_misc_to_sp_type (type)) + { + err = ER_SP_INVALID_TYPE; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err, 2, name_str, + real_type == SP_TYPE_FUNCTION ? "FUNCTION" : "PROCEDURE"); + goto error; + } + + /* change _db_stored_procedure */ + if (sp_owner != NULL) + { + /* change the unique_name */ + sm_downcase_name (owner_str, downcase_owner_name, DB_MAX_USER_LENGTH); + sprintf (new_name_str, "%s.%s", downcase_owner_name, sm_remove_qualifier_name (name_str)); + + db_make_string (&user_val, new_name_str); + err = obj_set (sp_mop, SP_ATTR_UNIQUE_NAME, &user_val); + if (err < 0) + { + goto error; + } + pr_clear_value (&user_val); + + /* change the owner */ + db_make_object (&user_val, new_owner); + err = obj_set (sp_mop, SP_ATTR_OWNER, &user_val); + if (err < 0) + { + goto error; + } + pr_clear_value (&user_val); + } + + /* check lang */ + err = db_get (sp_mop, SP_ATTR_LANG, &sp_lang_val); + if (err != NO_ERROR) + { + goto error; + } + + lang = db_get_int (&sp_lang_val); + if (lang == SP_LANG_PLCSQL) + { + if (sp_owner != NULL || sp_recompile == 1) + { + err = db_get (sp_mop, SP_ATTR_TARGET_CLASS, &target_cls_val); + if (err != NO_ERROR) + { + goto error; + } + target_cls = db_get_string (&target_cls_val); + + if (sp_recompile == 1) + { + owner_str = sm_qualifier_name (name_str, downcase_owner_name, DB_MAX_USER_LENGTH); + } + + err = alter_stored_procedure_code (parser, sp_mop, target_cls, owner_str, sp_recompile); + if (err != NO_ERROR) + { + goto error; + } + pr_clear_value (&target_cls_val); + } + pr_clear_value (&sp_lang_val); + } + + /* change the comment */ + if (sp_comment != NULL) + { + db_make_string (&user_val, comment_str); + err = obj_set (sp_mop, SP_ATTR_COMMENT, &user_val); + if (err < 0) + { + goto error; + } + pr_clear_value (&user_val); + } + +error: + + pr_clear_value (&user_val); + pr_clear_value (&sp_type_val); + pr_clear_value (&sp_lang_val); + pr_clear_value (&target_cls_val); + AU_ENABLE (save); + + return err; +} + +/* + * jsp_map_pt_misc_to_sp_type + * return : stored procedure type ( Procedure or Function ) + * pt_enum(in): Misc Types + * + * Note: + */ + +static SP_TYPE_ENUM +jsp_map_pt_misc_to_sp_type (PT_MISC_TYPE pt_enum) +{ + if (pt_enum == PT_SP_PROCEDURE) + { + return SP_TYPE_PROCEDURE; + } + else + { + return SP_TYPE_FUNCTION; + } +} + +/* + * jsp_map_pt_misc_to_sp_mode + * return : stored procedure mode ( input or output or inout ) + * pt_enum(in) : Misc Types + * + * Note: + */ + +static SP_MODE_ENUM +jsp_map_pt_misc_to_sp_mode (PT_MISC_TYPE pt_enum) +{ + if (pt_enum == PT_INPUT || pt_enum == PT_NOPUT) + { + return SP_MODE_IN; + } + else if (pt_enum == PT_OUTPUT) + { + return SP_MODE_OUT; + } + else + { + return SP_MODE_INOUT; + } +} + +static SP_DIRECTIVE_ENUM +jsp_map_pt_to_sp_authid (PT_MISC_TYPE pt_authid) +{ + assert (pt_authid == PT_AUTHID_OWNER || pt_authid == PT_AUTHID_CALLER); + return (pt_authid == PT_AUTHID_OWNER ? SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_OWNER : + SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_CALLER); +} + +/* + * jsp_check_stored_procedure_name - + * return: java stored procedure name + * str(in) : + * + * Note: convert lowercase + */ + +static char * +jsp_check_stored_procedure_name (const char *str) +{ + char buffer[SM_MAX_IDENTIFIER_LENGTH + 2]; + char tmp[SM_MAX_IDENTIFIER_LENGTH + 2]; + char *name = NULL; + static int dbms_output_len = strlen ("dbms_output."); + + + if (strncasecmp (str, "dbms_output.", dbms_output_len) == 0) + { + sprintf (buffer, "public.dbms_output.%s", + sm_downcase_name (str + dbms_output_len, tmp, strlen (str + dbms_output_len) + 1)); + } + else + { + sm_user_specified_name (str, buffer, SM_MAX_IDENTIFIER_LENGTH); + } + + name = strdup (buffer); + + return name; +} + +/* + * drop_stored_procedure - + * return: Error code + * name(in): jsp name + * expected_type(in): + * + * Note: + */ + +static int +drop_stored_procedure (const char *name, SP_TYPE_ENUM expected_type) +{ + MOP sp_mop, arg_mop, owner, save_user; + DB_VALUE sp_type_val, arg_cnt_val, args_val, owner_val, generated_val, target_cls_val, lang_val, temp; + SP_TYPE_ENUM real_type; + std::string class_name; + const char *target_cls; + DB_SET *arg_set_p; + int save, i, arg_cnt, lang; + int err; + char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1]; + unique_name[0] = '\0'; + + AU_DISABLE (save); + + db_make_null (&args_val); + db_make_null (&owner_val); + + sp_mop = jsp_find_stored_procedure (name, DB_AUTH_SELECT); + if (sp_mop == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + err = db_get (sp_mop, SP_ATTR_OWNER, &owner_val); + if (err != NO_ERROR) + { + goto error; + } + owner = db_get_object (&owner_val); + + if (!ws_is_same_object (owner, Au_user) && !au_is_dba_group_member (Au_user)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED_PRIVILEGES, 0); + err = er_errid (); + goto error; + } + + err = db_get (sp_mop, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val); + if (err != NO_ERROR) + { + goto error; + } + + if (1 == db_get_int (&generated_val)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED_SYSTEM_GENERATED, 0); + err = er_errid (); + goto error; + } + + err = db_get (sp_mop, SP_ATTR_SP_TYPE, &sp_type_val); + if (err != NO_ERROR) + { + goto error; + } + + real_type = (SP_TYPE_ENUM) db_get_int (&sp_type_val); + if (real_type != expected_type) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_TYPE, 2, name, + real_type == SP_TYPE_FUNCTION ? "FUNCTION" : "PROCEDURE"); + + err = er_errid (); + goto error; + } + + // delete _db_stored_procedure_code + + err = db_get (sp_mop, SP_ATTR_LANG, &lang_val); + if (err != NO_ERROR) + { + goto error; + } + + lang = db_get_int (&lang_val); + if (lang == SP_LANG_PLCSQL) + { + err = db_get (sp_mop, SP_ATTR_TARGET_CLASS, &target_cls_val); + if (err != NO_ERROR) + { + goto error; + } + + target_cls = db_get_string (&target_cls_val); + err = drop_stored_procedure_code (target_cls); + if (err != NO_ERROR) + { + goto error; + } + } + + err = db_get (sp_mop, SP_ATTR_ARG_COUNT, &arg_cnt_val); + if (err != NO_ERROR) + { + goto error; + } + + arg_cnt = db_get_int (&arg_cnt_val); + + err = db_get (sp_mop, SP_ATTR_ARGS, &args_val); + if (err != NO_ERROR) + { + goto error; + } + + arg_set_p = db_get_set (&args_val); + + for (i = 0; i < arg_cnt; i++) + { + set_get_element (arg_set_p, i, &temp); + arg_mop = db_get_object (&temp); + err = obj_delete (arg_mop); + pr_clear_value (&temp); + if (err != NO_ERROR) + { + goto error; + } + } + + /* before deleting an object, all permissions are revoked. */ + if (jsp_get_unique_name (sp_mop, unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL) + { + assert (er_errid () != NO_ERROR); + } + + save_user = Au_user; + if (AU_SET_USER (owner) == NO_ERROR) + { + err = au_object_revoke_all_privileges (DB_OBJECT_PROCEDURE, owner, unique_name); + if (err != NO_ERROR) + { + AU_SET_USER (save_user); + goto error; + } + } + + AU_SET_USER (save_user); + + err = au_delete_auth_of_dropping_database_object (DB_OBJECT_PROCEDURE, name); + if (err != NO_ERROR) + { + goto error; + } + + err = obj_delete (sp_mop); + +error: + AU_ENABLE (save); + + pr_clear_value (&args_val); + pr_clear_value (&owner_val); + + return err; +} + +/* + * drop_stored_procedure_code - + * return: Error code + * name(in): jsp name + * + * Note: + */ + +static int +drop_stored_procedure_code (const char *name) +{ + MOP code_mop, owner; + DB_VALUE owner_val, generated_val; + int save; + int err; + + AU_DISABLE (save); + + db_make_null (&owner_val); + + code_mop = jsp_find_stored_procedure_code (name); + if (code_mop == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + err = db_get (code_mop, SP_ATTR_OWNER, &owner_val); + if (err != NO_ERROR) + { + goto error; + } + owner = db_get_object (&owner_val); + + if (!ws_is_same_object (owner, Au_user) && !au_is_dba_group_member (Au_user)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED_PRIVILEGES, 0); + err = er_errid (); + goto error; + } + + err = db_get (code_mop, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val); + if (err != NO_ERROR) + { + goto error; + } + + if (!DB_IS_NULL (&generated_val) && 1 == db_get_int (&generated_val)) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_DROP_NOT_ALLOWED_SYSTEM_GENERATED, 0); + err = er_errid (); + goto error; + } + + // TODO: If a unreloadable SP is deleted, mark a flag in PL server to block calling the deleted SP + err = obj_delete (code_mop); + +error: + AU_ENABLE (save); + + pr_clear_value (&owner_val); + + return err; +} + +/* + * alter_stored_procedure_code - + * return: Error code + * name(in): jsp name + * + * Note: + */ + +static int +alter_stored_procedure_code (PARSER_CONTEXT *parser, MOP sp_mop, const char *name, const char *owner_str, + int sp_recompile) +{ + const char *scode = NULL, *decl = NULL; + int scode_len, save, err; + MOP code_mop; + DB_VALUE scode_val, value; + PLCSQL_COMPILE_REQUEST compile_request; + PLCSQL_COMPILE_RESPONSE compile_response; + SP_INFO sp_info; + SP_CODE_INFO code_info; + DB_OBJECT *object_p; + DB_OTMPL *obt_p = NULL; + + AU_DISABLE (save); + + db_make_null (&scode_val); + db_make_null (&value); + + code_mop = jsp_find_stored_procedure_code (name); + if (code_mop == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + err = db_get (code_mop, SP_ATTR_SOURCE_CODE, &scode_val); + if (err != NO_ERROR) + { + goto error; + } + + scode = db_get_string (&scode_val); + scode_len = db_get_string_size (&scode_val); + + sp_info.owner = db_find_user (owner_str); + + assert (scode && scode_len); + compile_request.code.assign (scode, scode_len); + compile_request.owner.assign (owner_str); + pr_clear_value (&scode_val); + + // TODO: Only the owner's rights is supported for PL/CSQL + au_perform_push_user (sp_info.owner); + err = plcsql_transfer_file (compile_request, compile_response); + au_perform_pop_user (); + + if (err == NO_ERROR && compile_response.err_code == NO_ERROR) + { + decl = compile_response.java_signature.c_str (); + } + else + { + if (err == NO_ERROR && compile_response.err_code == NO_ERROR) + { + decl = compile_response.java_signature.c_str (); + } + else + { + err = ER_SP_COMPILE_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_COMPILE_ERROR, 3, compile_response.err_line, + compile_response.err_column, compile_response.err_msg.c_str ()); + pt_record_error (parser, parser->statement_number, compile_response.err_line, compile_response.err_column, er_msg (), + NULL); + goto error; + } + } + + if (decl) + { + std::string target = decl; + sp_split_target_signature (target, sp_info.target_class, sp_info.target_method); + } + + code_info.name = sp_info.target_class; + code_info.ocode = compile_response.compiled_code; + + if (sp_recompile == 1) + { + /* recompile */ + code_info.owner = NULL; + } + else + { + /* owner to */ + code_info.owner = sp_info.owner; + } + + err = sp_edit_stored_procedure_code (code_mop, code_info); + if (err != NO_ERROR) + { + goto error; + } + + /* Update the target_class column in the _db_stored_procedure catalog. */ + obt_p = dbt_edit_object (sp_mop); + if (obt_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + db_make_string (&value, code_info.name.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_TARGET_CLASS, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + object_p = dbt_finish_object (obt_p); + if (!object_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + obt_p = NULL; + + err = locator_flush_instance (object_p); + if (err != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + obj_delete (object_p); + goto error; + } + +error: + AU_ENABLE (save); + + pr_clear_value (&scode_val); + pr_clear_value (&value); + + return err; +} + +/* + * jsp_set_prepare_call - + * return: none + * + * Note: + */ + +void +jsp_set_prepare_call (void) +{ + int depth = tran_get_libcas_depth (); + is_prepare_call[depth] = true; +} + +/* + * jsp_unset_prepare_call - + * return: none + * + * Note: + */ + +void +jsp_unset_prepare_call (void) +{ + int depth = tran_get_libcas_depth (); + is_prepare_call[depth] = false; +} + +/* + * jsp_is_prepare_call - + * return: bool + * + * Note: + */ + +bool +jsp_is_prepare_call () +{ + int depth = tran_get_libcas_depth (); + return is_prepare_call[depth]; +} + +static int +jsp_check_overflow_args (PARSER_CONTEXT *parser, PT_NODE *node, int num_params, int num_args) +{ + if (num_args > num_params) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_PARAM_COUNT, 2, num_params, num_args); + return er_errid (); + } + else if (num_args < num_params) + { + // there are trailing default arguments + return num_params - num_args; + } + return 0; +} + +/* + * pt_to_method_arglist () - converts a parse expression tree list of + * method call arguments to method argument array + * return: A NULL on error occurred + * parser(in): + * target(in): + * node_list(in): should be parse name nodes + * subquery_as_attr_list(in): + */ +static int * +pt_to_method_arglist (PARSER_CONTEXT *parser, PT_NODE *target, PT_NODE *node_list, PT_NODE *subquery_as_attr_list) +{ + int *arg_list = NULL; + int i = 1; + int num_args = pt_length_of_list (node_list) + 1; + PT_NODE *node; + + arg_list = (int *) db_private_alloc (NULL, num_args); + if (!arg_list) + { + return NULL; + } + + if (subquery_as_attr_list != NULL) + { + if (target != NULL) + { + /* the method call target is the first element in the array */ + arg_list[0] = pt_find_attribute (parser, target, subquery_as_attr_list); + if (arg_list[0] == -1) + { + return NULL; + } + } + else + { + i = 0; + } + + for (node = node_list; node != NULL; node = node->next) + { + arg_list[i] = pt_find_attribute (parser, node, subquery_as_attr_list); + if (arg_list[i] == -1) + { + return NULL; + } + i++; + } + } + else + { + for (node = node_list; node != NULL; node = node->next) + { + arg_list[i] = i; + i++; + } + } + + return arg_list; +} + +/* + * jsp_make_pl_signature () - converts a parse expression tree list of pl calls to pl_signature struct + * return: error_code + * parser(in): + * node_list(in): should be parse pl nodes + * subquery_as_attr_list(in): + * sig(out): pl_signature struct + */ +int +jsp_make_pl_signature (PARSER_CONTEXT *parser, PT_NODE *node, PT_NODE *subquery_as_attr_list, cubpl::pl_signature &sig) +{ + int save; + int error = NO_ERROR; + char user_name_buffer [DB_MAX_USER_LENGTH + 1]; + + assert (node); + + sp_entry entry (SP_ATTR_INDEX_LAST); + + { + PT_NODE *method_name_node = node->info.method_call.method_name; + const char *name = PT_NAME_RESOLVED (method_name_node) ? parser_print_tree (parser, + method_name_node) : PT_NAME_ORIGINAL (method_name_node); + + sig.name = db_private_strdup (NULL, name); + if (PT_IS_METHOD (node)) + { + sig.type = PT_IS_CLASS_METHOD (node) ? PL_TYPE_CLASS_METHOD : PL_TYPE_INSTANCE_METHOD; + } + else + { + DB_OBJECT *mop_p = jsp_find_stored_procedure (name, DB_AUTH_EXECUTE); + if (mop_p == NULL) + { + error = er_errid (); + assert (error != NO_ERROR); + goto exit; + } + + AU_DISABLE (save); + entry.oid = *WS_OID (mop_p); + + for (int i = 0; i < SP_ATTR_INDEX_LAST; i++) + { + error = obj_get (mop_p, sp_get_entry_name (i).data (), &entry.vals[i]); + if (error != NO_ERROR) + { + goto exit; + } + } + + int lang = db_get_int (&entry.vals[SP_ATTR_INDEX_LANG]); + sig.type = (lang == SP_LANG_PLCSQL) ? PL_TYPE_PLCSQL : PL_TYPE_JAVA_SP; + + /* semantic check */ + int directive = db_get_int (&entry.vals[SP_ATTR_INDEX_DIRECTIVE]); + const char *auth_name = (directive == SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_OWNER ? jsp_get_owner_name ( + name, user_name_buffer, DB_MAX_USER_LENGTH) : au_get_current_user_name ()); + + int result_type = db_get_int (&entry.vals[SP_ATTR_INDEX_RETURN_TYPE]); + error = jsp_check_return_type_supported ((DB_TYPE) result_type); + if (error != NO_ERROR) + { + goto exit; + } + + // args + int num_params = db_get_int (&entry.vals[SP_ATTR_INDEX_ARG_COUNT]); + DB_SET *param_set = db_get_set (&entry.vals[SP_ATTR_INDEX_ARGS]); + error = jsp_make_pl_args (parser, node, num_params, param_set, sig); + if (error != NO_ERROR) + { + goto exit; + } + + sig.auth = db_private_strdup (NULL, auth_name); + sig.result_type = result_type; + if (directive == SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_OWNER) + { + jsp_get_owner_name (name, user_name_buffer, DB_MAX_USER_LENGTH); + sig.auth = db_private_strndup (NULL, user_name_buffer, DB_MAX_USER_LENGTH); + } + else + { + sig.auth = db_private_strdup (NULL, au_get_current_user_name ()); + } + } + + // make pl_ext + if (PT_IS_METHOD (node)) + { + PT_NODE *dt = node->info.method_call.on_call_target->data_type; + /* beware of virtual classes */ + + sig.ext.method.class_name = (dt->info.data_type.virt_object) ? (char *) db_get_class_name ( + dt->info.data_type.virt_object) : (char *) dt->info.data_type.entity->info.name.original; + sig.arg.set_arg_size (pt_length_of_list (node->info.method_call.arg_list) + 1); + sig.ext.method.arg_pos = pt_to_method_arglist (parser, node->info.method_call.on_call_target, + node->info.method_call.arg_list, subquery_as_attr_list); + } + else + { + sig.ext.sp.target_class_name = db_private_strdup (NULL, db_get_string (&entry.vals[SP_ATTR_INDEX_TARGET_CLASS])); + sig.ext.sp.target_method_name = db_private_strdup (NULL, db_get_string (&entry.vals[SP_ATTR_INDEX_TARGET_METHOD])); + if (sig.ext.sp.target_class_name != NULL) + { + MOP code_mop = jsp_find_stored_procedure_code (sig.ext.sp.target_class_name); + if (code_mop) + { + sig.ext.sp.code_oid = *WS_OID (code_mop); + } + else + { + // Java SP + sig.ext.sp.code_oid = OID_INITIALIZER; + } + } + } + } + +exit: + AU_ENABLE (save); + return error; +} + +int +jsp_make_pl_args (PARSER_CONTEXT *parser, PT_NODE *node, int num_params, DB_SET *param_set, cubpl::pl_signature &sig) +{ + int error = NO_ERROR; + + DB_VALUE temp; + db_make_null (&temp); + + { + sig.arg.set_arg_size (num_params); + + // check default arguments + int num_args = pt_length_of_list (node->info.method_call.arg_list); + int num_trailing_default_args = jsp_check_overflow_args (parser, node, num_params, num_args); + if (num_trailing_default_args < 0) + { + error = er_errid (); + goto exit_on_error; + } + + sp_entry entry (SP_ARGS_ATTR_INDEX_LAST); + + for (int i = 0; i < num_params; i++) + { + set_get_element (param_set, i, &temp); + + MOP arg_mop_p = db_get_object (&temp); + if (arg_mop_p == NULL) + { + error = er_errid (); + assert (error != NO_ERROR); + goto exit_on_error; + } + + for (int i = 0; i < SP_ARGS_ATTR_INDEX_LAST; i++) + { + error = obj_get (arg_mop_p, sp_args_get_entry_name (i).data (), &entry.vals[i]); + if (error != NO_ERROR) + { + goto exit_on_error; + } + } + + int arg_mode = db_get_int (&entry.vals[SP_ARGS_ATTR_INDEX_MODE]); + error = jsp_check_out_param_in_query (parser, node, arg_mode); + if (error != NO_ERROR) + { + goto exit_on_error; + } + + int arg_type = db_get_int (&entry.vals[SP_ARGS_ATTR_INDEX_DATA_TYPE]); + error = jsp_check_param_type_supported ((DB_TYPE) arg_type, arg_mode); + if (error != NO_ERROR) + { + goto exit_on_error; + } + + const char *default_value_str = NULL; + int default_value_size = PL_ARG_DEFAULT_NONE; + + int num_required_args = num_params - num_trailing_default_args; + + if (i >= num_required_args) + { + int is_optional = db_get_int (&entry.vals[SP_ARGS_ATTR_INDEX_IS_OPTIONAL]); + if (is_optional == 1) + { + const DB_VALUE &default_val = entry.vals[SP_ARGS_ATTR_INDEX_DEFAULT_VALUE]; + if (!DB_IS_NULL (&default_val)) + { + default_value_size = db_get_string_size (&default_val); // null character + if (default_value_size > 0) + { + default_value_str = db_get_string (&default_val); + } + } + else + { + default_value_size = PL_ARG_DEFAULT_NULL; // special value when default value is *NULL* + } + } + else + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_INVALID_PARAM_COUNT, 2, num_params, num_args); + error = er_errid (); + goto exit_on_error; + } + } + + sig.arg.arg_mode[i] = arg_mode; + sig.arg.arg_type[i] = arg_type; + + sig.arg.arg_default_value_size[i] = default_value_size; + if (default_value_str) + { + sig.arg.arg_default_value[i] = db_private_strndup (NULL, default_value_str, default_value_size); + } + } + } + +exit_on_error: + return error; +} + +static int +check_execute_authorization_by_query (const MOP sp_obj) +{ + int error = NO_ERROR, save; + const char *query = "SELECT [au] FROM " CT_CLASSAUTH_NAME + " [au] WHERE [object_type] = ? and [auth_type] = 'EXECUTE' and [object_of] = ? and [grantee] = ?"; + DB_QUERY_RESULT *result = NULL; + DB_SESSION *session = NULL; + DB_VALUE val[3]; + int stmt_id; + int cnt = 0; + + db_make_null (&val[0]); + db_make_null (&val[1]); + db_make_null (&val[2]); + + /* Disable the checking for internal authorization object access */ + AU_DISABLE (save); + + session = db_open_buffer_local (query); + if (session == NULL) + { + ASSERT_ERROR_AND_SET (error); + goto release; + } + + error = db_set_system_generated_statement (session); + if (error != NO_ERROR) + { + goto release; + } + + stmt_id = db_compile_statement_local (session); + if (stmt_id < 0) + { + ASSERT_ERROR_AND_SET (error); + goto release; + } + + db_make_int (&val[0], (int) DB_OBJECT_PROCEDURE); + db_make_object (&val[1], sp_obj); + db_make_object (&val[2], Au_user); + + error = db_push_values (session, 3, val); + if (error != NO_ERROR) + { + goto release; + } + + cnt = error = db_execute_statement_local (session, stmt_id, &result); + if (error < 0) + { + goto release; + } + + error = db_query_end (result); + +release: + if (session != NULL) + { + db_close_session (session); + } + pr_clear_value (&val[0]); + pr_clear_value (&val[1]); + pr_clear_value (&val[2]); + + AU_ENABLE (save); + + return cnt; +} + +static int +check_execute_authorization (const MOP sp_obj, const DB_AUTH au_type) +{ + int error = NO_ERROR; + MOP owner_mop = NULL; + DB_VALUE owner; + + if (au_type != DB_AUTH_EXECUTE) + { + return NO_ERROR; + } + + if (au_is_dba_group_member (Au_user)) + { + return NO_ERROR; + } + + error = db_get (sp_obj, SP_ATTR_OWNER, &owner); + if (error == NO_ERROR) + { + // check sp's owner is current user + owner_mop = db_get_object (&owner); + if (ws_is_same_object (owner_mop, Au_user) || ws_is_same_object (owner_mop, Au_public_user)) + { + return NO_ERROR; + } + else if (check_execute_authorization_by_query (sp_obj) == 0) + { + error = ER_AU_EXECUTE_FAILURE; + er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0); + } + else + { + error = er_errid (); + } + } + + return error; +} + +PT_NODE * +jsp_get_default_expr_node_list (PARSER_CONTEXT *parser, cubpl::pl_signature &sig) +{ + PT_NODE *default_next_node_list = NULL; + PT_NODE *default_next_node = NULL; + for (int i = 0; i < sig.arg.arg_size; i++) + { + if (sig.arg.arg_default_value_size[i] == 0) + { + default_next_node = pt_make_string_value (parser, NULL); + } + else if (sig.arg.arg_default_value_size[i] > 0) + { + DB_DEFAULT_EXPR default_expr; + pt_get_default_expression_from_string (parser, sig.arg.arg_default_value[i], sig.arg.arg_default_value_size[i], + &default_expr); + + // from pt_resolve_default_value + if (default_expr.default_expr_type != DB_DEFAULT_NONE) + { + PT_OP_TYPE op = pt_op_type_from_default_expr_type (default_expr.default_expr_type); + PT_NODE *default_op_value_node = pt_expression_0 (parser, op); + + if (default_expr.default_expr_op == NULL_DEFAULT_EXPRESSION_OPERATOR) + { + default_next_node = default_op_value_node; + } + else + { + PT_NODE *arg1, *arg2, *arg3; + arg1 = default_op_value_node; + bool has_user_format = default_expr.default_expr_format ? true : false; + arg2 = pt_make_string_value (parser, default_expr.default_expr_format); + + if (arg2 == NULL) + { + parser_free_tree (parser, default_op_value_node); + return NULL; + } + + arg3 = parser_new_node (parser, PT_VALUE); + if (arg3 == NULL) + { + parser_free_tree (parser, default_op_value_node); + parser_free_tree (parser, arg2); + return NULL; + } + + arg3->type_enum = PT_TYPE_INTEGER; + const char *lang_str = prm_get_string_value (PRM_ID_INTL_DATE_LANG); + int flag = 0; + lang_set_flag_from_lang (lang_str, has_user_format, 0, &flag); + arg3->info.value.data_value.i = (long) flag; + + default_next_node = parser_make_expression (parser, PT_TO_CHAR, arg1, arg2, arg3); + if (default_next_node == NULL) + { + parser_free_tree (parser, default_op_value_node); + parser_free_tree (parser, arg2); + parser_free_tree (parser, arg3); + return NULL; + } + } + } + else + { + default_next_node = pt_make_string_value (parser, sig.arg.arg_default_value[i]); + default_next_node = pt_wrap_with_cast_op (parser, default_next_node, pt_db_to_type_enum ((DB_TYPE) sig.arg.arg_type[i]), + TP_FLOATING_PRECISION_VALUE, 0, NULL); + } + } + + if (default_next_node != NULL) + { + default_next_node = pt_semantic_type (parser, default_next_node, NULL); + if (default_next_node == NULL) + { + return NULL; + } + + default_next_node_list = parser_append_node (default_next_node, default_next_node_list); + } + } + + return default_next_node_list; +} diff --git a/src/sp/jsp_cl.h b/src/sp/jsp_cl.h index 9a2a8b4373..dbf2af8edf 100644 --- a/src/sp/jsp_cl.h +++ b/src/sp/jsp_cl.h @@ -32,62 +32,43 @@ #error Does not belong to server module. #endif /* SERVER_MODE */ -#include "parse_tree.h" - -#define SP_CLASS_NAME "_db_stored_procedure" -#define SP_ARG_CLASS_NAME "_db_stored_procedure_args" - -#define SP_ATTR_NAME "sp_name" -#define SP_ATTR_SP_TYPE "sp_type" -#define SP_ATTR_RETURN_TYPE "return_type" -#define SP_ATTR_ARGS "args" -#define SP_ATTR_ARG_COUNT "arg_count" -#define SP_ATTR_LANG "lang" -#define SP_ATTR_TARGET "target" -#define SP_ATTR_OWNER "owner" -#define SP_ATTR_COMMENT "comment" - -#define SP_ATTR_ARG_NAME "arg_name" -#define SP_ATTR_INDEX_OF_NAME "index_of" -#define SP_ATTR_DATA_TYPE "data_type" -#define SP_ATTR_MODE "mode" -#define SP_ATTR_ARG_COMMENT "comment" - -typedef enum -{ - SP_TYPE_PROCEDURE = 1, - SP_TYPE_FUNCTION -} SP_TYPE_ENUM; +#ifdef __cplusplus +#include +#include +#endif -typedef enum -{ - SP_MODE_IN = 1, - SP_MODE_OUT, - SP_MODE_INOUT -} SP_MODE_ENUM; - -typedef enum -{ - SP_LANG_PLCSQL = 0, - SP_LANG_JAVA = 1 -} SP_LANG_ENUM; +#include "parse_tree.h" +#include "sp_constants.hpp" +#include "pl_signature.hpp" extern int jsp_create_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement); extern int jsp_alter_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement); extern int jsp_drop_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement); extern int jsp_call_stored_procedure (PARSER_CONTEXT * parser, PT_NODE * statement); -extern int jsp_check_out_param_in_query (PARSER_CONTEXT * parser, PT_NODE * node, int arg_mode); -extern int jsp_check_param_type_supported (PT_NODE * node); extern int jsp_check_return_type_supported (DB_TYPE type); +extern int jsp_make_pl_signature (PARSER_CONTEXT * parser, PT_NODE * statement, PT_NODE * subquery_as_attr_list, + cubpl::pl_signature & signature); +extern int jsp_make_pl_args (PARSER_CONTEXT * parser, PT_NODE * node, int num_params, DB_SET * param_set, + cubpl::pl_signature & signature); + extern int jsp_is_exist_stored_procedure (const char *name); + +extern char *jsp_get_owner_name (const char *name, char *buf, int buf_size); extern int jsp_get_return_type (const char *name); extern int jsp_get_sp_type (const char *name); -extern MOP jsp_find_stored_procedure (const char *name); +extern MOP jsp_find_stored_procedure (const char *name, DB_AUTH purpose); +extern MOP jsp_find_stored_procedure_code (const char *name); +extern int jsp_find_sp_of_another_owner (const char *name, MOP * return_mop); + +extern MOP jsp_get_owner (MOP mop_p); +extern char *jsp_get_name (MOP mop_p); +extern char *jsp_get_unique_name (MOP mop_p, char *buf, int buf_size); extern void jsp_set_prepare_call (void); extern void jsp_unset_prepare_call (void); extern bool jsp_is_prepare_call (void); +extern PT_NODE *jsp_get_default_expr_node_list (PARSER_CONTEXT * parser, cubpl::pl_signature & sig); #endif /* _JSP_CL_H_ */ diff --git a/src/sp/jsp_file.h b/src/sp/jsp_file.h deleted file mode 100644 index 883c050ada..0000000000 --- a/src/sp/jsp_file.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2008 Search Solution Corporation - * Copyright 2016 CUBRID Corporation - * - * Licensed 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. - * - */ - - -/* - * jsp_file.h - Functions to manage files related to Java Stored Procedure Server - * - * Note: - */ - -#ifndef _JSP_FILE_H_ -#define _JSP_FILE_H_ - -#ident "$Id$" - -#include "porting.h" -#include - -typedef struct javasp_server_info JAVASP_SERVER_INFO; -struct javasp_server_info -{ - int pid; - int port; -}; - -#define JAVASP_PID_DISABLED -1 -#define JAVASP_PORT_DISABLED -2 -#define JAVASP_PORT_UDS_MODE -1 - -#define JAVASP_SERVER_INFO_INITIALIZER \ - {JAVASP_PID_DISABLED, JAVASP_PORT_DISABLED} - -#ifdef __cplusplus -extern "C" -{ -#endif - - extern bool javasp_open_info_dir (); - extern FILE *javasp_open_info (const char *db_name, const char *mode); - extern void javasp_unlink_info (const char *db_name); - - extern bool javasp_read_info (const char *db_name, JAVASP_SERVER_INFO & info); - extern bool javasp_write_info (const char *db_name, JAVASP_SERVER_INFO info); - extern bool javasp_reset_info (const char *db_name); - - extern bool javasp_get_info_file (char *buf, size_t len, const char *db_name); - extern bool javasp_get_error_file (char *buf, size_t len, const char *db_name); - extern bool javasp_get_log_file (char *buf, size_t len, const char *db_name); - -#ifdef __cplusplus -} -#endif - -#endif /* _JSP_FILE_H_ */ diff --git a/src/sp/method_invoke_group.cpp b/src/sp/method_invoke_group.cpp new file mode 100644 index 0000000000..1c6ebe71e8 --- /dev/null +++ b/src/sp/method_invoke_group.cpp @@ -0,0 +1,253 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "method_invoke_group.hpp" + +#include "boot_sr.h" +#include "dbtype.h" /* db_value_* */ +#include "db_value_printer.hpp" +#include "pl_comm.h" /* common communcation functions for javasp */ +#include "mem_block.hpp" /* cubmem::extensible_block */ + +#include "method_struct_invoke.hpp" +#include "object_primitive.h" +#include "object_representation.h" /* OR_ */ +#include "packer.hpp" +#include "pl_connection.hpp" +#include "session.h" +#include "string_buffer.hpp" +#include "pl_session.hpp" +#include "network_callback_sr.hpp" + +#if defined (SA_MODE) +#include "query_method.hpp" +#endif +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +namespace cubmethod +{ +////////////////////////////////////////////////////////////////////////// +// Method Group to invoke together +////////////////////////////////////////////////////////////////////////// + method_invoke_group::method_invoke_group (cubpl::pl_signature_array &sig_array) + : m_id ((std::uint64_t) this) + , m_stack (nullptr) + , m_sig_array (sig_array) + { + assert (sig_array.num_sigs > 0); + + // assert +#if !defined (NDEBUG) + for (int i = 0; i < sig_array.num_sigs; i++) + { + assert (PL_TYPE_IS_METHOD (sig_array.sigs[i].type)); + } +#endif + + DB_VALUE v; + db_make_null (&v); + m_result_vector.resize (sig_array.num_sigs, v); + } + + method_invoke_group::~method_invoke_group () + { + destroy_resources (); + } + + DB_VALUE & + method_invoke_group::get_return_value (int index) + { + assert (index >= 0 && index < (int) m_sig_array.num_sigs); + return m_result_vector[index]; + } + + METHOD_GROUP_ID + method_invoke_group::get_id () const + { + return m_id; + } + + bool + method_invoke_group::is_running () const + { + return m_is_running; + } + + int + method_invoke_group::prepare (std::vector> &arg_base) + { + int error = NO_ERROR; + + SESSION_ID s_id = cubpl::get_session ()->get_id (); + int req_id = m_stack->get_and_increment_request_id (); + TRANID t_id = m_stack->get_tran_id (); + + cubmethod::header header (s_id, METHOD_REQUEST_ARG_PREPARE, req_id); + cubmethod::prepare_args arg (m_id, t_id, METHOD_TYPE_CLASS_METHOD, arg_base); // TOD + + error = xs_callback_send_args (m_stack->get_thread_entry (), header, arg); + return error; + } + + int method_invoke_group::execute (std::vector> &arg_base) + { + int error = NO_ERROR; + SESSION_ID s_id; + TRANID t_id; + + m_stack = cubpl::get_session ()->create_and_push_stack (nullptr); + s_id = cubpl::get_session ()->get_id (); + t_id = m_stack->get_tran_id (); + + // prepare args + error = prepare (arg_base); + if (error != NO_ERROR) + { + goto exit; + } + + for (int i = 0; i < m_sig_array.num_sigs; i++) + { + int req_id = m_stack->get_and_increment_request_id (); + // invoke + cubmethod::header header (s_id, METHOD_REQUEST_INVOKE /* default */, 0); + error = xs_callback_send_args (m_stack->get_thread_entry (), header, m_id, m_sig_array.sigs[i]); + if (error != NO_ERROR) + { + break; + } + + DB_VALUE &result = m_result_vector[i]; + db_value_clear (&result); + + auto get_method_result = [&] (cubmem::block & b) + { + int e = NO_ERROR; + packing_unpacker unpacker (b); + int status; + unpacker.unpack_int (status); + if (status == METHOD_SUCCESS) + { + unpacker.unpack_db_value (result); + } + else + { + unpacker.unpack_int (e); /* er_errid */ + } + return e; + }; + + // get_return + error = xs_callback_receive (m_stack->get_thread_entry (), get_method_result); + if (error != NO_ERROR) + { + break; + } + +#if 0 // TODO + if (m_session->is_interrupted ()) + { + error = m_session->get_interrupt_id (); + } + + if (error != NO_ERROR) + { + // if error is not interrupt reason, interrupt is not set + m_session->set_interrupt (error, (er_has_error () && er_msg ()) ? er_msg () : ""); + break; + } +#endif + } + + if (m_stack) + { + delete m_stack; + } +exit: + return error; + } + + void + method_invoke_group::begin () + { + if (m_is_running == true) + { + return; + } + + m_is_running = true; + } + + int method_invoke_group::reset (bool is_end_query) + { + int error = NO_ERROR; + +// TODO +#if 0 + if (!is_end_query) + { + cubmethod::header header (get_session_id(), METHOD_REQUEST_END, get_and_increment_request_id ()); + std::vector handler_vec (m_handler_set.begin (), m_handler_set.end ()); + error = xs_callback_send_args (m_thread_p, header, handler_vec); + m_handler_set.clear (); + } + +#endif + + return error; + } + + void + method_invoke_group::destroy_resources () + { + pr_clear_value_vector (m_result_vector); + } + + void + method_invoke_group::end () + { + if (m_is_running == false) + { + return; + } + + // FIXME + // m_rctx->pop_stack (m_thread_p, this); + + m_is_running = false; + } + + int + method_invoke_group::get_num_methods () + { + return m_sig_array.num_sigs; + } + + std::string + method_invoke_group::get_error_msg () + { + return m_err_msg; + } + + void + method_invoke_group::set_error_msg (const std::string &msg) + { + m_err_msg = msg; + } +} // namespace cubmethod diff --git a/src/method/method_invoke_group.hpp b/src/sp/method_invoke_group.hpp similarity index 60% rename from src/method/method_invoke_group.hpp rename to src/sp/method_invoke_group.hpp index e9c59cbf3b..d8dde32650 100644 --- a/src/method/method_invoke_group.hpp +++ b/src/sp/method_invoke_group.hpp @@ -37,14 +37,17 @@ #include #include -#include "method_connection_pool.hpp" /* cubmethod::connection */ -#include "method_def.hpp" /* method_sig_node */ -#include "method_runtime_context.hpp" /* cubmethod::runtime_context */ +#include "pl_connection.hpp" /* cubpl::connection */ + #include "method_struct_parameter_info.hpp" /* db_parameter_info */ #include "mem_block.hpp" /* cubmem::block, cubmem::extensible_block */ #include "porting.h" /* SOCKET */ #include "storage_common.h" +#include "pl_execution_stack_context.hpp" +#include "pl_signature.hpp" +#include "pl_session.hpp" + // thread_entry.hpp namespace cubthread { @@ -56,6 +59,7 @@ namespace cubmethod ////////////////////////////////////////////////////////////////////////// // Method Group to invoke together ////////////////////////////////////////////////////////////////////////// + // forward declarations class method_invoke; @@ -63,7 +67,7 @@ namespace cubmethod { public: method_invoke_group () = delete; // Not DefaultConstructible - method_invoke_group (cubthread::entry *thread_p, const method_sig_list &sigs, bool is_for_scan); + method_invoke_group (cubpl::pl_signature_array &sig); method_invoke_group (method_invoke_group &&other) = delete; // Not MoveConstructible method_invoke_group (const method_invoke_group ©) = delete; // Not CopyConstructible @@ -74,76 +78,33 @@ namespace cubmethod ~method_invoke_group (); void begin (); - int prepare (std::vector> &arg_base, const std::vector &arg_use_vec); + int prepare (std::vector> &arg_base); int execute (std::vector> &arg_base); int reset (bool is_end_query); - void destroy_resources (); void end (); + int get_num_methods (); DB_VALUE &get_return_value (int index); - int get_num_methods () const; METHOD_GROUP_ID get_id () const; - SOCKET get_socket () const; - cubthread::entry *get_thread_entry () const; std::queue &get_data_queue (); - cubmethod::runtime_context *get_runtime_context (); - connection_pool &get_connection_pool (); - SESSION_ID get_session_id () const - { - return m_sid; - } - TRANID get_tran_id (); bool is_running () const; - bool is_for_scan () const; - - // cursor interface for method_invoke - query_cursor *create_cursor (QUERY_ID query_id, bool oid_included); - query_cursor *get_cursor (QUERY_ID query_id); - void register_returning_cursor (QUERY_ID query_id); - void deregister_returning_cursor (QUERY_ID query_id); - - // client handelr - void register_client_handler (int handler_id); // error std::string get_error_msg (); void set_error_msg (const std::string &msg); - db_parameter_info *get_db_parameter_info () const; - - void set_db_parameter_info (db_parameter_info *param_info); - inline METHOD_REQ_ID get_and_increment_request_id () - { - return m_rctx->get_and_increment_request_id(); - } + void destroy_resources (); private: - void destory_all_cursors (); - - bool is_supported_dbtype (const DB_VALUE &value); - - runtime_context *m_rctx; bool m_is_running; - bool m_is_for_scan; - - connection *m_connection; - std::queue m_data_queue; - - std::unordered_set m_cursor_set; - std::unordered_set m_handler_set; std::string m_err_msg; - SESSION_ID m_sid; METHOD_GROUP_ID m_id; - TRANID m_tid; - - db_parameter_info *m_parameter_info; - cubthread::entry *m_thread_p; - std::set m_kind_type; - std::vector m_method_vector; + cubpl::execution_stack *m_stack; + cubpl::pl_signature_array &m_sig_array; std::vector m_result_vector; /* placeholder for result value */ }; diff --git a/src/sp/jsp_comm.c b/src/sp/pl_comm.c similarity index 88% rename from src/sp/jsp_comm.c rename to src/sp/pl_comm.c index bf89b126fe..c3661954de 100644 --- a/src/sp/jsp_comm.c +++ b/src/sp/pl_comm.c @@ -18,12 +18,12 @@ /* - * jsp_comm.c - Functions to communicate with Java Stored Procedure Server + * pl_comm.c - Functions to communicate with Java Stored Procedure Server * * Note: */ -#include "jsp_comm.h" +#include "pl_comm.h" #include "config.h" @@ -45,7 +45,7 @@ #include #endif /* not WINDOWS */ -#include "jsp_file.h" +#include "pl_file.h" #include "connection_support.h" #include "porting.h" #include "error_manager.h" @@ -63,12 +63,12 @@ // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" -static SOCKET jsp_connect_server_tcp (int server_port); +static SOCKET pl_connect_server_tcp (int server_port); #if !defined (WINDOWS) -static SOCKET jsp_connect_server_uds (const char *db_name); +static SOCKET pl_connect_server_uds (const char *db_name); #endif /* - * jsp_connect_server + * pl_connect_server * return: connect fail - return Error Code * connection success - return socket fd * @@ -76,26 +76,26 @@ static SOCKET jsp_connect_server_uds (const char *db_name); */ SOCKET -jsp_connect_server (const char *db_name, int server_port) +pl_connect_server (const char *db_name, int server_port) { SOCKET socket = INVALID_SOCKET; #if defined (WINDOWS) - socket = jsp_connect_server_tcp (server_port); + socket = pl_connect_server_tcp (server_port); #else - if (server_port == JAVASP_PORT_UDS_MODE) + if (server_port == PL_PORT_UDS_MODE) { - socket = jsp_connect_server_uds (db_name); + socket = pl_connect_server_uds (db_name); } else { - socket = jsp_connect_server_tcp (server_port); + socket = pl_connect_server_tcp (server_port); } #endif return socket; } /* - * jsp_disconnect_server - + * pl_disconnect_server - * return: none * sockfd(in) : close connection * @@ -103,7 +103,7 @@ jsp_connect_server (const char *db_name, int server_port) */ void -jsp_disconnect_server (SOCKET & sockfd) +pl_disconnect_server (SOCKET & sockfd) { if (!IS_INVALID_SOCKET (sockfd)) { @@ -122,7 +122,7 @@ jsp_disconnect_server (SOCKET & sockfd) } /* - * jsp_writen + * pl_writen * return: fail return -1, * fd(in): Specifies the socket file descriptor. * vptr(in): Points to the buffer containing the message to send. @@ -132,7 +132,7 @@ jsp_disconnect_server (SOCKET & sockfd) */ int -jsp_writen (SOCKET fd, const void *vptr, int n) +pl_writen (SOCKET fd, const void *vptr, int n) { int nwritten; int nleft = n; @@ -170,7 +170,7 @@ jsp_writen (SOCKET fd, const void *vptr, int n) } /* - * jsp_readn + * pl_readn * return: read size * fd(in): Specifies the socket file descriptor. * vptr(in/out): Points to a buffer where the message should be stored. @@ -181,20 +181,20 @@ jsp_writen (SOCKET fd, const void *vptr, int n) */ int -jsp_readn (SOCKET fd, void *vptr, int n) +pl_readn (SOCKET fd, void *vptr, int n) { const static int PING_TIMEOUT = 5000; return css_readn (fd, (char *) vptr, n, PING_TIMEOUT); } int -jsp_readn_with_timeout (SOCKET fd, void *vptr, int n, int timeout) +pl_readn_with_timeout (SOCKET fd, void *vptr, int n, int timeout) { return css_readn (fd, (char *) vptr, n, timeout); } int -jsp_ping (SOCKET fd) +pl_ping (SOCKET fd) { char buffer[DB_MAX_IDENTIFIER_LENGTH]; @@ -203,21 +203,21 @@ jsp_ping (SOCKET fd) char *ptr = or_pack_int (request, OR_INT_SIZE); ptr = or_pack_int (ptr, SP_CODE_UTIL_PING); - int nbytes = jsp_writen (fd, request, OR_INT_SIZE * 2); + int nbytes = pl_writen (fd, request, OR_INT_SIZE * 2); if (nbytes != OR_INT_SIZE * 2) { return ER_SP_NETWORK_ERROR; } int res_size = 0; - nbytes = jsp_readn (fd, (char *) &res_size, OR_INT_SIZE); + nbytes = pl_readn (fd, (char *) &res_size, OR_INT_SIZE); if (nbytes != OR_INT_SIZE) { return ER_SP_NETWORK_ERROR; } res_size = ntohl (res_size); - nbytes = jsp_readn (fd, buffer, res_size); + nbytes = pl_readn (fd, buffer, res_size); if (nbytes != res_size) { return ER_SP_NETWORK_ERROR; @@ -227,7 +227,7 @@ jsp_ping (SOCKET fd) } char * -jsp_get_socket_file_path (const char *db_name) +pl_get_socket_file_path (const char *db_name) { static char path[PATH_MAX]; static bool need_init = true; @@ -255,7 +255,7 @@ jsp_get_socket_file_path (const char *db_name) #if !defined (WINDOWS) static SOCKET -jsp_connect_server_uds (const char *db_name) +pl_connect_server_uds (const char *db_name) { struct sockaddr_un sock_addr; SOCKET sockfd = INVALID_SOCKET; @@ -269,7 +269,7 @@ jsp_connect_server_uds (const char *db_name) int slen = sizeof (sock_addr); memset (&sock_addr, 0, slen); sock_addr.sun_family = AF_UNIX; - snprintf (sock_addr.sun_path, sizeof (sock_addr.sun_path), "%s", jsp_get_socket_file_path (db_name)); + snprintf (sock_addr.sun_path, sizeof (sock_addr.sun_path), "%s", pl_get_socket_file_path (db_name)); int success = connect (sockfd, (struct sockaddr *) &sock_addr, slen); if (success < 0) @@ -285,7 +285,7 @@ jsp_connect_server_uds (const char *db_name) #endif static SOCKET -jsp_connect_server_tcp (int server_port) +pl_connect_server_tcp (int server_port) { struct sockaddr_in tcp_srv_addr; diff --git a/src/sp/jsp_comm.h b/src/sp/pl_comm.h similarity index 71% rename from src/sp/jsp_comm.h rename to src/sp/pl_comm.h index 91f50a5ed2..730825a21b 100644 --- a/src/sp/jsp_comm.h +++ b/src/sp/pl_comm.h @@ -18,13 +18,13 @@ /* - * jsp_comm.h - Functions to communicate with Java Stored Procedure Server + * pl_comm.h - Functions to communicate with Java Stored Procedure Server * * Note: */ -#ifndef _JSP_COMM_H_ -#define _JSP_COMM_H_ +#ifndef _PL_COMM_H_ +#define _PL_COMM_H_ #ident "$Id$" @@ -52,14 +52,15 @@ typedef enum SP_CODE_COMPILE = 0x80, + SP_CODE_UTIL_BOOTSTRAP = 0xDD, SP_CODE_UTIL_PING = 0xDE, SP_CODE_UTIL_STATUS = 0xEE, SP_CODE_UTIL_TERMINATE_THREAD = 0xFE, SP_CODE_UTIL_TERMINATE_SERVER = 0xFF } SP_CODE; -typedef struct javasp_status_info JAVASP_STATUS_INFO; -struct javasp_status_info +typedef struct pl_status_info PL_STATUS_INFO; +struct pl_status_info { int pid; int port; @@ -73,14 +74,14 @@ struct javasp_status_info extern "C" { #endif - EXPORT_IMPORT SOCKET jsp_connect_server (const char *db_name, int server_port); - EXPORT_IMPORT void jsp_disconnect_server (SOCKET & sockfd); - EXPORT_IMPORT int jsp_writen (SOCKET fd, const void *vptr, int n); - EXPORT_IMPORT int jsp_readn (SOCKET fd, void *vptr, int n); - EXPORT_IMPORT int jsp_readn_with_timeout (SOCKET fd, void *vptr, int n, int timeout); + EXPORT_IMPORT SOCKET pl_connect_server (const char *db_name, int server_port); + EXPORT_IMPORT void pl_disconnect_server (SOCKET & sockfd); + EXPORT_IMPORT int pl_writen (SOCKET fd, const void *vptr, int n); + EXPORT_IMPORT int pl_readn (SOCKET fd, void *vptr, int n); + EXPORT_IMPORT int pl_readn_with_timeout (SOCKET fd, void *vptr, int n, int timeout); - int jsp_ping (SOCKET fd); - char *jsp_get_socket_file_path (const char *db_name); + int pl_ping (SOCKET fd); + char *pl_get_socket_file_path (const char *db_name); #if defined(WINDOWS) extern int windows_socket_startup (FARPROC hook); @@ -91,4 +92,4 @@ extern "C" } #endif -#endif /* _JSP_COMM_H_ */ +#endif /* _pl_COMM_H_ */ diff --git a/src/sp/pl_compile_handler.cpp b/src/sp/pl_compile_handler.cpp new file mode 100644 index 0000000000..f250963b18 --- /dev/null +++ b/src/sp/pl_compile_handler.cpp @@ -0,0 +1,162 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "pl_compile_handler.hpp" + +#include + +#include "pl_comm.h" +#include "pl_execution_stack_context.hpp" + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +namespace cubpl +{ + compile_handler::compile_handler () + { + m_stack = get_session ()->create_and_push_stack (nullptr); + } + + compile_handler::~compile_handler () + { + // exit stack + if (m_stack != nullptr) + { + delete m_stack; + } + } + + int + compile_handler::read_request (cubmem::block &response_blk, int &code) + { + int error_code = m_stack->read_data_from_java (response_blk); + if (error_code != NO_ERROR || response_blk.dim == 0) + { + return ER_FAILED; + } + + cubpacking::unpacker unpacker (response_blk); + if (!response_blk.is_valid ()) + { + error_code = ER_SP_NETWORK_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sizeof (int)); + } + else + { + unpacker.unpack_int (code); + (void) m_stack->read_payload_block (unpacker); + } + + return error_code; + } + + void + compile_handler::create_error_response (cubmem::extensible_block &res, int error_code) + { + compile_response compile_response; + compile_response.err_code = (er_errid () != NO_ERROR) ? er_errid () : error_code; + compile_response.err_msg = er_msg ()? er_msg () : "unknown error"; + compile_response.err_line = -1; + compile_response.err_column = -1; + + packing_packer packer; + cubmem::extensible_block eb; + packer.set_buffer_and_pack_all (res, compile_response); + } + + int + compile_handler::compile (const compile_request &req, cubmem::extensible_block &out_blk) + { + int error_code = NO_ERROR; + SESSION_ID sid = get_session ()->get_id (); + + m_stack->set_command (SP_CODE_COMPILE); + error_code = m_stack->send_data_to_java (req); + if (error_code != NO_ERROR) + { + return error_code; + } + + auto bypass_block = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + int code; + cubmem::block response_blk; + do + { + error_code = read_request (response_blk, code); + + cubmem::block &payload_blk = m_stack->get_data_queue().front (); + + if (code == METHOD_REQUEST_COMPILE) + { + if (payload_blk.dim > 0) + { + out_blk.extend_to (payload_blk.dim); + std::memcpy (out_blk.get_ptr (), payload_blk.ptr, payload_blk.dim); + } + else + { + create_error_response (out_blk, error_code); + } + } + else if (code == METHOD_REQUEST_SQL_SEMANTICS) + { + packing_unpacker respone_unpacker (payload_blk); + sql_semantics_request request; + respone_unpacker.unpack_all (request); + + error_code = m_stack->send_data_to_client (bypass_block, request); + } + else if (code == METHOD_REQUEST_GLOBAL_SEMANTICS) + { + packing_unpacker respone_unpacker (payload_blk); + global_semantics_request request; + respone_unpacker.unpack_all (request); + + error_code = m_stack->send_data_to_client (bypass_block, request); + } + else + { + error_code = ER_FAILED; + assert (false); + } + + if (m_stack->get_data_queue ().empty() == false) + { + m_stack->get_data_queue ().pop (); + } + + // free phase + if (response_blk.is_valid ()) + { + delete [] response_blk.ptr; + response_blk.ptr = NULL; + response_blk.dim = 0; + } + } + while (error_code == NO_ERROR && code != METHOD_REQUEST_COMPILE); + +exit: + + return error_code; + } +} \ No newline at end of file diff --git a/src/sp/pl_compile_handler.hpp b/src/sp/pl_compile_handler.hpp new file mode 100644 index 0000000000..d5850833c9 --- /dev/null +++ b/src/sp/pl_compile_handler.hpp @@ -0,0 +1,58 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * pl_compile_handler.hpp + */ + +#ifndef _PL_COMPILE_HANDLER_HPP_ +#define _PL_COMPILE_HANDLER_HPP_ + +#if !defined (SERVER_MODE) && !defined (SA_MODE) +#error Belongs to server module +#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ + +#include "pl_execution_stack_context.hpp" +#include "pl_signature.hpp" +#include "pl_session.hpp" + +#include "pl_struct_compile.hpp" + +// forward definitions +struct regu_variable_list_node; + +namespace cubpl +{ + class EXPORT_IMPORT compile_handler + { + public: + compile_handler (); + ~compile_handler (); + + int compile (const compile_request &req, cubmem::extensible_block &out_blk); + + private: + int read_request (cubmem::block &response_blk, int &code); + + void create_error_response (cubmem::extensible_block &res, int error_code); + + execution_stack *m_stack; + }; +} + +#endif // _PL_COMPILE_HANDLER_HPP_ \ No newline at end of file diff --git a/src/sp/pl_connection.cpp b/src/sp/pl_connection.cpp new file mode 100644 index 0000000000..d3bace1c85 --- /dev/null +++ b/src/sp/pl_connection.cpp @@ -0,0 +1,405 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "pl_connection.hpp" + +#include /* std::count_if */ +#include /* std::unique_ptr */ + +#include "boot_sr.h" +#include "pl_sr.h" /* pl_server_port(), pl_connect_server() */ +#include "pl_comm.h" /* pl_disconnect_server (), pl_ping () */ +#include "object_representation.h" /* OR_ */ + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +namespace cubpl +{ + ////////////////////////////////////////////////////////////////////////// + // Definitions + ////////////////////////////////////////////////////////////////////////// + + /********************************************************************* + * connection_pool - definition + *********************************************************************/ + + constexpr int SYSTEM_REVISION = -1; + constexpr int INITIAL_REVISION = 0; + + connection_pool::connection_pool (int pool_size) + : m_pool (pool_size, nullptr) + , m_epoch (INITIAL_REVISION) + , m_queue () + , m_mutex () + { + assert (pool_size > 0); + // TODO: make it configurable + m_min_conn_size = 3; + m_inc_conn_size = 5; + + initialize_pool (); + } + + connection_pool::connection_pool (int pool_size, const std::string &db_name, int pl_port, bool is_for_sys) + : connection_pool (pool_size) + { + m_db_name = db_name; + m_db_port = pl_port; + if (is_for_sys) + { + m_epoch = SYSTEM_REVISION; + } + } + + connection_pool::~connection_pool () + { + cleanup_pool (); + } + + connection_view + connection_pool::claim () + { + if (!is_system_pool ()) + { + pl_server_wait_for_ready (); + } + if (m_db_port == PL_PORT_DISABLED) + { + m_db_port = pl_server_port_from_info (); + } + + std::lock_guard lock (m_mutex); + + // Check if a connection is available in the queue + if (!m_queue.empty()) + { + int index = m_queue.front(); + m_queue.pop(); + + if (m_pool[index] == nullptr) + { + create_new_connection (index); + } + + return get_connection_view (index); + } + + // If no connections are available, find a slot for a new connection + for (size_t i = 0; i < m_pool.size(); ++i) + { + if (m_pool[i] == nullptr) + { + create_new_connection (i); + return get_connection_view (i); + } + } + + return nullptr; + } + + void + connection_pool::increment_epoch () + { + if (!is_system_pool ()) + { + m_epoch++; + } + } + + int + connection_pool::get_pool_size () const + { + return m_pool.size (); + } + + int + connection_pool::get_epoch () const + { + return m_epoch; + } + + const char * + connection_pool::get_db_name () const + { + return m_db_name.c_str(); + } + + int + connection_pool::get_db_port () const + { + return m_db_port; + } + + bool + connection_pool::is_system_pool () const + { + return (m_epoch.load (std::memory_order::memory_order_relaxed) == SYSTEM_REVISION); + } + + // private + void + connection_pool::retire (connection *conn) + { + std::lock_guard lock (m_mutex); + + m_queue.push (conn->get_index ()); + } + + void + connection_pool::initialize_pool() + { + for (int i = 0; i < m_min_conn_size && i < m_pool.size (); ++i) + { + m_queue.push (i); // Pre-fill the queue with indices + } + } + + void + connection_pool::cleanup_pool() + { + std::lock_guard lock (m_mutex); + + for (connection *&conn : m_pool) + { + if (conn) + { + delete conn; + conn = nullptr; + } + } + + m_pool.clear(); + while (!m_queue.empty()) + { + m_queue.pop(); + } + } + + void + connection_pool::create_new_connection (int index) + { + connection *conn = new connection (this, index); + m_pool[index] = conn; + } + + connection_view + connection_pool::get_connection_view (int index) + { + connection *conn = m_pool[index]; + return connection_view (conn, [this] (connection *c) + { + if (c) + { + this->retire (c); // Automatically return connection to the pool + } + }); + } + + /********************************************************************* + * connection - definition + *********************************************************************/ + connection::connection (connection_pool *pool, int index) + : m_pool (pool) + , m_index (index) + , m_socket (INVALID_SOCKET) + , m_epoch (pool->get_epoch ()) + { + // + do_reconnect (); + } + + connection::~connection () + { + if (m_socket != INVALID_SOCKET) + { + pl_disconnect_server (m_socket); + } + } + + bool + connection::is_connected () const + { + return m_socket != INVALID_SOCKET; + } + + bool + connection::is_valid () const + { + return (m_socket != INVALID_SOCKET) && (m_pool->get_epoch () == m_epoch || m_pool->get_epoch () == SYSTEM_REVISION); + } + + int + connection::get_index () const + { + return m_index; + } + + SOCKET + connection::get_socket () const + { + return m_socket; + } + + int + connection::send_buffer (const cubmem::block &blk) + { + if (!is_valid ()) + { + do_reconnect (); + } + + OR_ALIGNED_BUF (OR_INT_SIZE) a_request; + char *request = OR_ALIGNED_BUF_START (a_request); + + int request_size = static_cast (blk.dim); + or_pack_int (request, request_size); + + int nbytes = pl_writen (m_socket, request, OR_INT_SIZE); + if (nbytes != OR_INT_SIZE) + { + return do_handle_network_error (nbytes); + } + + nbytes = pl_writen (m_socket, blk.ptr, blk.dim); + if (nbytes != static_cast (blk.dim)) + { + return do_handle_network_error (nbytes); + } + + return NO_ERROR; + } + + int + connection::receive_buffer (cubmem::block &b) + { + return receive_buffer (b, nullptr, -1); + } + + int + connection::receive_buffer (cubmem::block &b, const pl_callback_func *interrupt_func, int timeout_ms) + { + if (!is_valid ()) + { + return do_handle_network_error (-1); + } + + int res_size = 0; + int nbytes; + int elapsed = 0; + + /* read data length */ + while (true) + { + nbytes = pl_readn_with_timeout (m_socket, (char *)&res_size, OR_INT_SIZE, timeout_ms); + if (nbytes < 0) + { + if (errno == ETIMEDOUT) + { + if (interrupt_func && (*interrupt_func)() != NO_ERROR) + { + return er_errid (); + } + continue; + } + return do_handle_network_error (-1); + } + if (nbytes != sizeof (int)) + { + return do_handle_network_error (nbytes); + } + else + { + break; + } + } + + res_size = ntohl (res_size); + + // To avoid invalid res_size is returned by PL server, and to prevent memory exhaustion of cub_server + constexpr int MAX_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB max size + if (res_size > MAX_BUFFER_SIZE || res_size < 0) + { + return do_handle_network_error (nbytes); + } + + if (res_size == 0) + { + // No payload to read + return NO_ERROR; + } + + // Step 3: Extend block to fit the incoming data + cubmem::extensible_block ext_blk; + ext_blk.extend_to (res_size); + + // Step 4: Read the actual data with optional interrupt handling + int total_read = 0; + while (total_read < res_size) + { + nbytes = pl_readn_with_timeout (m_socket, ext_blk.get_ptr() + total_read, res_size - total_read, timeout_ms); + if (errno == ETIMEDOUT && interrupt_func && (*interrupt_func)() != NO_ERROR) + { + return er_errid (); + } + if (nbytes < 0) + { + return do_handle_network_error (nbytes); + } + + total_read += nbytes; + } + + // Step 5: Move the data into the block + cubmem::block blk (res_size, ext_blk.release_ptr()); + b = std::move (blk); + + return NO_ERROR; // Successfully received the buffer + } + + void + connection::invalidate () + { + pl_disconnect_server (m_socket); + } + + // private + void + connection::do_reconnect () + { + if (m_socket != INVALID_SOCKET) + { + pl_disconnect_server (m_socket); + } + + m_socket = pl_connect_server (m_pool->get_db_name (), m_pool->get_db_port ()); + if (m_socket != INVALID_SOCKET) + { + m_epoch = m_pool->get_epoch (); + } + } + + int + connection::do_handle_network_error (int nbytes) + { + (void) invalidate (); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, nbytes); + return er_errid (); + } + +} // namespace cubpl diff --git a/src/sp/pl_connection.hpp b/src/sp/pl_connection.hpp new file mode 100644 index 0000000000..43358a8805 --- /dev/null +++ b/src/sp/pl_connection.hpp @@ -0,0 +1,176 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * pl_connection.hpp + */ + +#ifndef _PL_CONNECTION_POOL_HPP_ +#define _PL_CONNECTION_POOL_HPP_ + +#if !defined (SERVER_MODE) && !defined (SA_MODE) && !defined (PL_MODE) +#error Belongs to server module +#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ + +#include +#include +#include +#include + +#include "porting.h" // SOCKET + +#include "error_code.h" +#include "mem_block.hpp" +#include "packer.hpp" +#include "pl_file.h" /* pl_read_info() */ +#include "network_callback_sr.hpp" + +namespace cubthread +{ + class entry; +} + +using pl_callback_func = std::function ; +using pl_callback_func_with_sock = std::function ; + +namespace cubpl +{ + ////////////////////////////////////////////////////////////////////////// + // Declarations + ////////////////////////////////////////////////////////////////////////// + // forward declaration + class connection; + + using connection_view = std::unique_ptr>; + + /********************************************************************* + * connection_pool - declaration + *********************************************************************/ + class EXPORT_IMPORT connection_pool + { + public: + connection_pool () = delete; + explicit connection_pool (int pool_size, const std::string &db_name, int pl_port = PL_PORT_DISABLED, + bool is_for_sys = false); + ~connection_pool (); + + connection_pool (connection_pool &&other) = delete; // Not MoveConstructible + connection_pool (const connection_pool ©) = delete; // Not CopyConstructible + + connection_pool &operator= (connection_pool &&other) = delete; // Not MoveAssignable + connection_pool &operator= (const connection_pool ©) = delete; // Not CopyAssignable + + connection_view claim (); + void retire (connection *claimed); + + void increment_epoch (); + + int get_pool_size () const; + int get_epoch () const; + + const char *get_db_name () const; + int get_db_port () const; + + bool is_system_pool () const; + + private: + explicit connection_pool (int pool_size); + void create_new_connection (int index); + connection_view get_connection_view (int index); + + + void initialize_pool (); + void cleanup_pool (); + + std::vector m_pool; + std::atomic m_epoch; // Whenever PL server is restarted, server_manager increments this value + + int m_min_conn_size; // minimum connection size + int m_inc_conn_size; // increment connection size for lazy initialization + + // for connection + std::string m_db_name; + int m_db_port; + + // blocking queue + std::queue m_queue; + std::mutex m_mutex; + }; + + /********************************************************************* + * connection - declaration + *********************************************************************/ + class EXPORT_IMPORT connection + { + friend connection_pool; + + public: + connection () = delete; + ~connection (); + + connection (const connection ©) = delete; // Not CopyConstructible + connection &operator= (const connection ©) = delete; // Not CopyAssignable + + connection (connection &&c) = delete; + connection &operator= (connection &&other) = delete; + + bool is_connected () const; + bool is_valid () const; + int get_index () const; + + int send_buffer (const cubmem::block &mem); + + int receive_buffer (cubmem::block &b); // simplified version + int receive_buffer (cubmem::block &b, const pl_callback_func *interrupt_func, int timeout_ms); + + template + int send_buffer_args (Args &&... args) + { + cubmem::block b = pack_data_block (std::forward (args)...); + int status = send_buffer (b); + if (b.is_valid ()) + { + delete [] b.ptr; + b.ptr = NULL; + b.dim = 0; + } + return status; + } + + void invalidate (); + + private: + explicit connection (connection_pool *pool, int index); + + void do_reconnect (); + int do_handle_network_error (int nbytes); + + SOCKET get_socket () const; + + connection_pool *m_pool; + int m_index; + SOCKET m_socket; + int m_epoch; // see connection_pool::m_epoch + }; +}; // namespace cubpl + +using PL_CONNECTION_POOL = cubpl::connection_pool; +using PL_CONNECTION_VIEW = cubpl::connection_view; +using PL_CONNECTION = cubpl::connection; + +#endif // _PL_CONNECTION_POOL_HPP_ diff --git a/src/sp/pl_execution_stack_context.cpp b/src/sp/pl_execution_stack_context.cpp new file mode 100644 index 0000000000..122faa0435 --- /dev/null +++ b/src/sp/pl_execution_stack_context.cpp @@ -0,0 +1,228 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "pl_execution_stack_context.hpp" + +#include "session.h" +#include "pl_sr.h" +#include "pl_comm.h" +#include "pl_connection.hpp" +#include "pl_query_cursor.hpp" + +#include "log_impl.h" + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" +namespace cubpl +{ + execution_stack::execution_stack (cubthread::entry *thread_p) + : m_id ((std::uint64_t) this) + , m_thread_p (thread_p) + , m_session {get_session ()} + , m_client_header (-1, METHOD_REQUEST_CALLBACK /* default */, 0) + , m_java_header (-1, SP_CODE_INTERNAL_JDBC /* default */, 0) + , m_connection {nullptr} + , m_req_id {0} + { + m_tid = logtb_find_current_tranid (thread_p); + m_is_running = false; + + if (m_session) + { + m_client_header.id = m_session->get_id (); + } + } + + execution_stack::~execution_stack () + { + if (m_session) + { + // retire connection + if (m_connection) + { + m_connection.reset (); + } + } + + destory_all_cursors (); + + m_session->pop_and_destroy_stack (get_id ()); + } + + void + execution_stack::add_query_handler (int handler_id) + { + m_stack_handler_id.insert (handler_id); + } + + void + execution_stack::remove_query_handler (int handler_id) + { + m_stack_handler_id.erase (handler_id); + } + + int + execution_stack::add_cursor (QUERY_ID query_id, bool oid_included) + { + if (query_id == NULL_QUERY_ID || query_id >= SHRT_MAX) + { + // false query e.g) SELECT * FROM db_class WHERE 0 <> 0 + return ER_FAILED; + } + + m_stack_cursor_id.insert (query_id); + + query_cursor *cursor = m_session->create_cursor (m_thread_p, query_id, oid_included); + return cursor ? NO_ERROR : ER_FAILED; + } + + query_cursor * + execution_stack::get_cursor (QUERY_ID query_id) + { + query_cursor *cursor = nullptr; + + if (query_id == NULL_QUERY_ID || query_id >= SHRT_MAX) + { + // false query e.g) SELECT * FROM db_class WHERE 0 <> 0 + return cursor; + } + + cursor = m_session->get_cursor (m_thread_p, query_id); + + /* + if (cursor == nullptr) + { + if (m_session->is_session_cursor (query_id)) + { + cursor = m_session->create_cursor (m_thread_p, query_id, false); + if (cursor) + { + // add to the clearing list at the end of stack + m_stack_cursor_id.insert (query_id); + } + } + } + */ + + return cursor; + } + + void + execution_stack::promote_to_session_cursor (QUERY_ID query_id) + { + m_session->add_session_cursor (m_thread_p, query_id); + + query_cursor *cursor = m_session->get_cursor (m_thread_p, query_id); + if (cursor) + { + cursor->change_owner (nullptr); + } + + m_stack_cursor_id.erase (query_id); + } + + void + execution_stack::destory_all_cursors () + { + for (auto &cursor_it : m_stack_cursor_id) + { + // If the cursor is received from the child function and is not returned to the parent function, the cursor remains in m_cursor_set. + // So here trying to find the cursor Id in the global returning cursor storage and remove it if exists. + m_session->remove_session_cursor (m_thread_p, cursor_it); + + m_session->destroy_cursor (m_thread_p, cursor_it); + } + + m_stack_cursor_id.clear (); + } + + connection_view & + execution_stack::get_connection () + { + if (m_connection == nullptr) + { + connection_pool *pool = get_connection_pool (); + if (pool) + { + m_connection = pool->claim (); + } + } + + return m_connection; + } + + PL_STACK_ID + execution_stack::get_id () const + { + return m_id; + } + + TRANID + execution_stack::get_tran_id () + { + m_tid = logtb_find_current_tranid (m_thread_p); + return m_tid; + } + + cubthread::entry * + execution_stack::get_thread_entry () const + { + return m_thread_p; + } + + + const std::unordered_set * + execution_stack::get_stack_query_handler () const + { + return &m_stack_handler_id; + } + + const std::unordered_set * + execution_stack::get_stack_cursor () const + { + return &m_stack_cursor_id; + } + + void + execution_stack::read_payload_block (cubpacking::unpacker &unpacker) + { + char *aligned_ptr = PTR_ALIGN (unpacker.get_curr_ptr(), MAX_ALIGNMENT); + size_t payload_size = (size_t) (unpacker.get_buffer_end() - aligned_ptr); + cubmem::block payload_blk (payload_size, aligned_ptr); + m_data_queue.emplace (std::move (payload_blk)); + } + + std::queue & + execution_stack::get_data_queue () + { + return m_data_queue; + } + + int + execution_stack::interrupt_handler () + { + bool dummy_continue; + if (logtb_is_interrupted (m_thread_p, true, &dummy_continue)) + { + m_session->set_local_error_for_interrupt (); + m_connection->invalidate (); + return m_session->get_interrupt_id (); + } + return NO_ERROR; + } +} diff --git a/src/sp/pl_execution_stack_context.hpp b/src/sp/pl_execution_stack_context.hpp new file mode 100644 index 0000000000..a9e5d2c9e0 --- /dev/null +++ b/src/sp/pl_execution_stack_context.hpp @@ -0,0 +1,188 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * pl_execution_stack_context.hpp: managing subprograms of a server task + */ + +#ifndef _PL_EXECUTION_STACK_HPP_ +#define _PL_EXECUTION_STACK_HPP_ + +#if !defined (SERVER_MODE) && !defined (SA_MODE) +#error Belongs to server module +#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ + +#include + +#include "dbtype_def.h" +#include "error_manager.h" +#include "query_list.h" +#include "query_executor.h" +#include "mem_block.hpp" +#include "packer.hpp" + +#include "network_callback_sr.hpp" +#include "method_struct_invoke.hpp" +#include "pl_connection.hpp" + +// thread_entry.hpp +namespace cubthread +{ + class entry; +} + +using PL_STACK_ID = uint64_t; + +namespace cubpl +{ + class session; + class query_cursor; + + class execution_stack + { + protected: + PL_STACK_ID m_id; + TRANID m_tid; + + cubthread::entry *m_thread_p; + session *m_session; + + /* resources */ + std::unordered_set m_stack_handler_id; + std::unordered_set m_stack_cursor_id; + connection_view m_connection; + + /* error */ + std::string m_error_message; + + bool m_is_running; + + int interrupt_handler (); + + public: + execution_stack () = delete; // Not DefaultConstructible + execution_stack (cubthread::entry *thread_p); + + execution_stack (execution_stack &&other) = delete; // Not MoveConstructible + execution_stack (const execution_stack ©) = delete; // Not CopyConstructible + + execution_stack &operator= (execution_stack &&other) = delete; // Not MoveAssignable + execution_stack &operator= (const execution_stack ©) = delete; // Not CopyAssignable + + ~execution_stack (); + + /* getters */ + PL_STACK_ID get_id () const; + TRANID get_tran_id (); + + /* session and thread */ + cubthread::entry *get_thread_entry () const; + + /* connection */ + connection_view &get_connection (); + std::queue &get_data_queue (); + + /* resource management */ + int add_cursor (QUERY_ID query_id, bool oid_included); + void remove_cursor (QUERY_ID query_id); + query_cursor *get_cursor (QUERY_ID query_id); + void promote_to_session_cursor (QUERY_ID query_id); + void destory_all_cursors (); + + /* query handler */ + void add_query_handler (int handler_id); + void remove_query_handler (int handler_id); + + const std::unordered_set *get_stack_query_handler () const; + const std::unordered_set *get_stack_cursor () const; + + // runtime (temporary) + std::queue m_data_queue; + + cubmethod::header m_client_header; // header sending to cubridcs + cubmethod::header m_java_header; // header sending to cub_javasp + bool m_transaction_control; + + template + int send_data_to_client (const xs_callback_func &func, Args &&... args) + { + return xs_callback_send_and_receive (m_thread_p, func, m_client_header, std::forward (args)...); + } + + template + int send_data_to_java (Args &&... args) + { + m_java_header.req_id = get_and_increment_request_id (); + connection_view &conn = get_connection(); + if (!conn) + { + assert (er_errid () != NO_ERROR); + return er_errid (); // Handle the case where connection is unavailable + } + + return conn->send_buffer_args (m_java_header, std::forward (args)...); + } + + int + read_data_from_java (cubmem::block &b) + { + connection_view &conn = get_connection(); + if (!conn) + { + assert (er_errid () != NO_ERROR); + return er_errid (); // Handle the case where connection is unavailable + } + + pl_callback_func interrupt_func = [this]() + { + return interrupt_handler (); + }; + + return conn->receive_buffer (b, &interrupt_func, 500); + } + + void + set_command (int command) + { + m_java_header.command = command; + } + + int m_req_id; + inline int get_and_increment_request_id () + { + return m_req_id++; + } + + std::string m_error_msg; + void set_error_message (std::string error_msg) + { + m_error_message = error_msg; + } + + std::string get_error_message () + { + return m_error_message; + } + + void read_payload_block (cubpacking::unpacker &unpacker); + }; +} + +using PL_EXECUTION_STACK = cubpl::execution_stack; + +#endif //_PL_EXECUTION_STACK_HPP_ diff --git a/src/sp/pl_executor.cpp b/src/sp/pl_executor.cpp new file mode 100644 index 0000000000..86f113f6f6 --- /dev/null +++ b/src/sp/pl_executor.cpp @@ -0,0 +1,972 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "pl_executor.hpp" + +#include "regu_var.hpp" +#include "fetch.h" +#include "memory_alloc.h" + +// runtime +#include "dbtype.h" + +#include "method_struct_invoke.hpp" +#include "method_struct_query.hpp" +#include "method_struct_value.hpp" +#include "method_struct_oid_info.hpp" +#include "method_struct_parameter_info.hpp" + +#include "pl_comm.h" +#include "pl_query_cursor.hpp" +#include "sp_code.hpp" + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" +namespace cubpl +{ + using namespace cubmethod; + + invoke_java::invoke_java (uint64_t id, int tid, pl_signature *sig, bool tc) + : g_id (id) + , tran_id (tid) + { + signature.assign (sig->ext.sp.target_class_name).append (".").append (sig->ext.sp.target_method_name); + auth.assign (sig->auth); + lang = sig->type; + result_type = sig->result_type; + + pl_arg &arg = sig->arg; + num_args = arg.arg_size; + arg_mode.resize (num_args); + arg_type.resize (num_args); + + for (int i = 0; i < num_args; i++) + { + arg_mode[i] = arg.arg_mode[i]; + arg_type[i] = arg.arg_type[i]; + } + + transaction_control = (lang == SP_LANG_PLCSQL) ? true : tc; + } + + void + invoke_java::pack (cubpacking::packer &serializator) const + { + serializator.pack_bigint (g_id); + serializator.pack_int (tran_id); + serializator.pack_string (signature); + serializator.pack_string (auth); + serializator.pack_int (lang); + serializator.pack_int (num_args); + + for (int i = 0; i < num_args; i++) + { + serializator.pack_int (arg_mode[i]); + serializator.pack_int (arg_type[i]); + } + + serializator.pack_int (result_type); + serializator.pack_bool (transaction_control); + } + + void + invoke_java::unpack (cubpacking::unpacker &deserializator) + { + // TODO: unpacking is not necessary + assert (false); + } + + size_t + invoke_java::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + { + size_t size = serializator.get_packed_bigint_size (start_offset); // group_id + size += serializator.get_packed_int_size (size); // tran_id + size += serializator.get_packed_string_size (signature, size); // signature + size += serializator.get_packed_string_size (auth, size); // auth + size += serializator.get_packed_int_size (size); // lang + size += serializator.get_packed_int_size (size); // num_args + + for (int i = 0; i < num_args; i++) + { + size += serializator.get_packed_int_size (size); // arg_mode + size += serializator.get_packed_int_size (size); // arg_type + } + + size += serializator.get_packed_int_size (size); // return_type + size += serializator.get_packed_bool_size (size); // transaction_control + return size; + } + + +////////////////////////////////////////////////// + executor::executor (pl_signature &sig) + : m_sig (sig) + { + m_stack = get_session ()->create_and_push_stack (nullptr); + } + + executor::~executor () + { + // destory local resources + pr_clear_value_vector (m_out_args); + + // exit stack + if (m_stack != nullptr) + { + delete m_stack; + } + } + + int + executor::fetch_args_peek (regu_variable_list_node *val_list_p, VAL_DESCR *val_desc_p, OID *obj_oid_p, + QFILE_TUPLE tuple) + { + int error = NO_ERROR; + int index = 0; + REGU_VARIABLE_LIST operand; + + if (m_stack == NULL) + { + return ER_FAILED; + } + + cubthread::entry *m_thread_p = m_stack->get_thread_entry (); + + if (m_sig.has_args ()) + { + DB_VALUE *value = NULL; + + operand = val_list_p; + while (operand != NULL) + { + error = fetch_peek_dbval (m_thread_p, &operand->value, val_desc_p, NULL, obj_oid_p, tuple, &value); + if (error != NO_ERROR) + { + m_args.clear (); + break; + } + + if (is_supported_dbtype (*value) == false) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, + pr_type_name ((DB_TYPE) value->domain.general_info.type)); + m_stack->set_error_message (std::string (er_msg ())); + error = er_errid (); + break; + } + + m_args.emplace_back (std::ref (*value)); + + operand = operand->next; + } + } + + return error; + } + + int + executor::fetch_args_peek (std::vector > args) + { + assert (m_args.empty ()); + m_args = args; + for (const DB_VALUE &val : m_args) + { + if (is_supported_dbtype (val) == false) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, + pr_type_name ((DB_TYPE) val.domain.general_info.type)); + m_stack->set_error_message (std::string (er_msg ())); + return er_errid (); + } + } + + return NO_ERROR; + } + + bool + executor::is_supported_dbtype (const DB_VALUE &value) + { + bool res = false; + switch (DB_VALUE_TYPE (&value)) + { + case DB_TYPE_INTEGER: + case DB_TYPE_SHORT: + case DB_TYPE_BIGINT: + case DB_TYPE_FLOAT: + case DB_TYPE_DOUBLE: + case DB_TYPE_MONETARY: + case DB_TYPE_NUMERIC: + case DB_TYPE_CHAR: + case DB_TYPE_NCHAR: + case DB_TYPE_VARNCHAR: + case DB_TYPE_STRING: + case DB_TYPE_DATE: + case DB_TYPE_TIME: + case DB_TYPE_TIMESTAMP: + case DB_TYPE_DATETIME: + case DB_TYPE_SET: + case DB_TYPE_MULTISET: + case DB_TYPE_SEQUENCE: + case DB_TYPE_OID: + case DB_TYPE_OBJECT: + case DB_TYPE_RESULTSET: + case DB_TYPE_NULL: + res = true; + break; + // unsupported types + case DB_TYPE_BIT: + case DB_TYPE_VARBIT: + case DB_TYPE_TABLE: + case DB_TYPE_BLOB: + case DB_TYPE_CLOB: + case DB_TYPE_TIMESTAMPTZ: + case DB_TYPE_TIMESTAMPLTZ: + case DB_TYPE_DATETIMETZ: + case DB_TYPE_DATETIMELTZ: + case DB_TYPE_JSON: + case DB_TYPE_ENUMERATION: + res = false; + break; + + // obsolete, internal, unused type + case DB_TYPE_ELO: + case DB_TYPE_VARIABLE: + case DB_TYPE_SUB: + case DB_TYPE_POINTER: + case DB_TYPE_ERROR: + case DB_TYPE_VOBJ: + case DB_TYPE_DB_VALUE: + case DB_TYPE_MIDXKEY: + default: + assert (false); + break; + } + return res; + } + + int + executor::execute (DB_VALUE &value) + { + int error = NO_ERROR; + + if (m_stack == NULL) + { + return ER_FAILED; + } + + // execution rights + assert (m_sig.auth != NULL); + error = change_exec_rights (m_sig.auth); + if (error != NO_ERROR) + { + goto exit; + } + + error = request_invoke_command (); + if (error != NO_ERROR) + { + goto exit; + } + + error = response_invoke_command (value); + if (error != NO_ERROR) + { + goto exit; + } + +exit: + // restore execution rights + change_exec_rights (NULL); + + return error; + } + + // runtime + int + executor::change_exec_rights (const char *auth_name) + { + int error = NO_ERROR; + int is_restore = (auth_name == NULL) ? 1 : 0; + + auto dummy = [&] (const cubmem::block & b) + { + return NO_ERROR; + }; + + if (is_restore == 0) + { + error = m_stack->send_data_to_client (dummy, METHOD_CALLBACK_CHANGE_RIGHTS, is_restore, std::string (auth_name)); + } + else + { + error = m_stack->send_data_to_client (dummy, METHOD_CALLBACK_CHANGE_RIGHTS, is_restore); + + } + + return error; + } + + int + executor::request_invoke_command () + { + int error = NO_ERROR; + + SESSION_ID sid = get_session ()->get_id (); + TRANID tid = m_stack->get_tran_id (); + + m_stack->set_command (SP_CODE_INVOKE); + prepare_args prepare_arg ((std::uint64_t) this, tid, METHOD_TYPE_PLCSQL, m_args); + invoke_java invoke_arg ((std::uint64_t) this, tid, &m_sig, prm_get_bool_value (PRM_ID_PL_TRANSACTION_CONTROL)); + + error = m_stack->send_data_to_java (prepare_arg, invoke_arg); + + return error; + } + + int + executor::response_invoke_command (DB_VALUE &value) + { + int error_code = NO_ERROR; + int start_code = -1; + + // response loop + do + { + cubmem::block response_blk; + error_code = m_stack->read_data_from_java (response_blk); + if (error_code != NO_ERROR) + { + break; + } + + cubpacking::unpacker unpacker (response_blk); + if (!response_blk.is_valid ()) + { + error_code = ER_SP_NETWORK_ERROR; + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error_code, 1, sizeof (int)); + break; + } + + unpacker.unpack_int (start_code); + + (void) m_stack->read_payload_block (unpacker); + + /* processing */ + if (start_code == SP_CODE_INTERNAL_JDBC) + { + error_code = response_callback_command (); + } + else if (start_code == SP_CODE_RESULT || start_code == SP_CODE_ERROR) + { + error_code = response_result (start_code, value); + } + else + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NETWORK_ERROR, 1, + start_code); + error_code = ER_SP_NETWORK_ERROR; + } + + if (m_stack->get_data_queue ().empty() == false) + { + m_stack->get_data_queue ().pop (); + } + + // free phase + if (response_blk.is_valid ()) + { + delete [] response_blk.ptr; + response_blk.ptr = NULL; + response_blk.dim = 0; + } + } + while (error_code == NO_ERROR && start_code == SP_CODE_INTERNAL_JDBC); + + return error_code; + } + + int + executor::response_result (int code, DB_VALUE &returnval) + { + // check queue + if (m_stack->get_data_queue().empty() == true) + { + return ER_FAILED; + } + + cubmem::block &blk = m_stack->get_data_queue().front (); + packing_unpacker unpacker (blk); + + if (code == SP_CODE_RESULT) + { + dbvalue_java value_unpacker; + db_make_null (&returnval); + value_unpacker.value = &returnval; + value_unpacker.unpack (unpacker); + + if (db_value_type (&returnval) == DB_TYPE_RESULTSET) + { + std::uint64_t query_id = db_get_resultset (&returnval); + if (query_id != NULL_QUERY_ID) + { + // qfile_update_qlist_count (thread_p, m_list_id, -1); + m_stack->promote_to_session_cursor (query_id); + } + } + + for (int i = 0; i < m_sig.arg.arg_size; i++) + { + DB_VALUE out_val; + db_make_null (&out_val); + if (m_sig.arg.arg_mode[i] != SP_MODE_IN) + { + value_unpacker.value = &out_val; + value_unpacker.unpack (unpacker); + m_out_args.emplace_back (out_val); + } + } + return NO_ERROR; + } + else if (code == SP_CODE_ERROR) + { + std::string error_msg; + unpacker.unpack_string (error_msg); + m_stack->set_error_message (error_msg); + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_EXECUTE_ERROR, 1, error_msg.c_str ()); + return ER_SP_EXECUTE_ERROR; + } + else + { + // it is handled in response_invoke_command + assert (false); + return ER_FAILED; + } + + return NO_ERROR; + } + + int + executor::response_callback_command () + { + int error_code = NO_ERROR; + // check queue + if (m_stack->get_data_queue().empty() == true) + { + return ER_FAILED; + } + + cubmem::block &blk = m_stack->get_data_queue().front (); + packing_unpacker unpacker (blk); + cubthread::entry &thread_ref = *m_stack->get_thread_entry (); + + int code; + unpacker.unpack_int (code); + + switch (code) + { + /* NOTE: we don't need to implement it + case METHOD_CALLBACK_GET_DB_VERSION: + break; + */ + + case METHOD_CALLBACK_GET_DB_PARAMETER: + error_code = callback_get_db_parameter (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_QUERY_PREPARE: + error_code = callback_prepare (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_QUERY_EXECUTE: + error_code = callback_execute (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_FETCH: + error_code = callback_fetch (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_OID_GET: + error_code = callback_oid_get (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_OID_PUT: + error_code = callback_oid_put (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_OID_CMD: + error_code = callback_oid_cmd (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_COLLECTION: + error_code = callback_collection_cmd (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_MAKE_OUT_RS: + error_code = callback_make_outresult (thread_ref, unpacker); + break; + + case METHOD_CALLBACK_GET_GENERATED_KEYS: + error_code = callback_get_generated_keys (thread_ref, unpacker); + break; + case METHOD_CALLBACK_END_TRANSACTION: + error_code = callback_end_transaction (thread_ref, unpacker); + break; + case METHOD_CALLBACK_CHANGE_RIGHTS: + error_code = callback_change_auth_rights (thread_ref, unpacker); + break; + case METHOD_CALLBACK_GET_CODE_ATTR: + error_code = callback_get_code_attr (thread_ref, unpacker); + break; + default: + // TODO: not implemented yet, do we need error handling? + assert (false); + error_code = ER_FAILED; + break; + } + + return error_code; + } + + std::vector & + executor::get_out_args () + { + return m_out_args; + } + + execution_stack * + executor::get_stack () + { + return m_stack; + } + + int + executor::callback_get_db_parameter (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_GET_DB_PARAMETER; + + db_parameter_info *parameter_info = get_session()->get_db_parameter_info (); + if (parameter_info == nullptr) + { + int tran_index = LOG_FIND_THREAD_TRAN_INDEX (m_stack->get_thread_entry()); + parameter_info = new db_parameter_info (); + + parameter_info->tran_isolation = logtb_find_isolation (tran_index); + parameter_info->wait_msec = logtb_find_wait_msecs (tran_index); + logtb_get_client_ids (tran_index, ¶meter_info->client_ids); + + get_session()->set_db_parameter_info (parameter_info); + } + + cubmem::block blk; + if (parameter_info) + { + blk = std::move (pack_data_block (METHOD_RESPONSE_SUCCESS, *parameter_info)); + } + else + { + blk = std::move (pack_data_block (METHOD_RESPONSE_ERROR, ER_FAILED, "unknown error", + ARG_FILE_LINE)); + } + + if (blk.is_valid ()) + { + m_stack->send_data_to_java (blk); + delete[] blk.ptr; + } + + return error; + } + + int + executor::callback_prepare (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_QUERY_PREPARE; + std::string sql; + int flag; + + unpacker.unpack_all (sql, flag); + + auto get_prepare_info = [&] (const cubmem::block & b) + { + packing_unpacker unpacker (b.ptr, (size_t) b.dim); + + int res_code; + unpacker.unpack_int (res_code); + + if (res_code == METHOD_RESPONSE_SUCCESS) + { + prepare_info info; + info.unpack (unpacker); + + m_stack->add_query_handler (info.handle_id); + } + + m_stack->send_data_to_java (b); + + return error; + }; + + error = m_stack->send_data_to_client (get_prepare_info, code, sql, flag, m_stack->get_tran_id ()); + return error; + } + + int + executor::callback_execute (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_QUERY_EXECUTE; + execute_request request; + + unpacker.unpack_all (request); + request.has_parameter = 1; + + auto get_execute_info = [&] (const cubmem::block & b) + { + packing_unpacker unpacker (b.ptr, (size_t) b.dim); + + int res_code; + unpacker.unpack_int (res_code); + + if (res_code == METHOD_RESPONSE_SUCCESS) + { + execute_info info; + info.unpack (unpacker); + + query_result_info ¤t_result_info = info.qresult_info; + int stmt_type = current_result_info.stmt_type; + if (stmt_type == CUBRID_STMT_SELECT) + { + std::uint64_t qid = current_result_info.query_id; + bool is_oid_included = current_result_info.include_oid; + (void) m_stack->add_cursor (qid, is_oid_included); + } + } + + error = m_stack->send_data_to_java (b); + return error; + }; + + error = m_stack->send_data_to_client (get_execute_info, code, request); + request.clear (); + + return error; + } + + int + executor::callback_fetch (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_FETCH; + std::uint64_t qid; + int pos; + int fetch_count; + int fetch_flag; + + unpacker.unpack_all (qid, pos, fetch_count, fetch_flag); + + /* find query cursor */ + query_cursor *cursor = m_stack->get_cursor (qid); + if (cursor == nullptr) + { + assert (false); + cubmem::block b = std::move (pack_data_block (METHOD_RESPONSE_ERROR, ER_FAILED, "unknown error", + ARG_FILE_LINE)); + error = m_stack->send_data_to_java (b); + return error; + } + + if (cursor->get_is_opened () == false) + { + cursor->open (); + } + + cursor->set_fetch_count (fetch_count); + + fetch_info info; + + SCAN_CODE s_code = S_SUCCESS; + + /* Most cases, fetch_count will be the same value + * To handle an invalid value of fetch_count is set at `cursor->set_fetch_count (fetch_count);` + * Here, I'm going to get the fetch_count from the getter again. + */ + fetch_count = cursor->get_fetch_count (); + + int start_index = cursor->get_current_index (); + while (s_code == S_SUCCESS) + { + s_code = cursor->next_row (); + int tuple_index = cursor->get_current_index (); + if (s_code == S_END || tuple_index - start_index >= fetch_count) + { + break; + } + + std::vector tuple_values = cursor->get_current_tuple (); + + if (cursor->get_is_oid_included()) + { + /* FIXME!!: For more optimized way, refactoring method_query_cursor is needed */ + OID *oid = cursor->get_current_oid (); + std::vector sub_vector = {tuple_values.begin() + 1, tuple_values.end ()}; + info.tuples.emplace_back (tuple_index, sub_vector, *oid); + } + else + { + info.tuples.emplace_back (tuple_index, tuple_values); + } + } + + cubmem::block blk; + if (s_code != S_ERROR) + { + blk = std::move (pack_data_block (METHOD_RESPONSE_SUCCESS, info)); + } + else + { + blk = std::move (pack_data_block (METHOD_RESPONSE_ERROR, ER_FAILED, "unknown error", + ARG_FILE_LINE)); + } + + error = m_stack->send_data_to_java (blk); + if (blk.is_valid ()) + { + delete [] blk.ptr; + blk.ptr = NULL; + blk.dim = 0; + } + + return error; + } + + int + executor::callback_oid_get (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_OID_GET; + oid_get_request request; + request.unpack (unpacker); + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, request); + return error; + } + + int + executor::callback_oid_put (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_OID_PUT; + oid_put_request request; + request.is_compatible_java = true; + request.unpack (unpacker); + request.is_compatible_java = false; + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, request); + return error; + } + + int + executor::callback_oid_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_OID_CMD; + int command; + OID oid; + unpacker.unpack_all (command, oid); + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, command, oid); + return error; + } + + int + executor::callback_collection_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + + int code = METHOD_CALLBACK_COLLECTION; + collection_cmd_request request; + request.is_compatible_java = true; + request.unpack (unpacker); + + request.is_compatible_java = false; + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, request); + return error; + } + + int + executor::callback_make_outresult (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + + int code = METHOD_CALLBACK_MAKE_OUT_RS; + uint64_t query_id; + unpacker.unpack_all (query_id); + + auto get_make_outresult_info = [&] (const cubmem::block & b) + { + packing_unpacker unpacker (b.ptr, (size_t) b.dim); + + int res_code; + make_outresult_info info; + unpacker.unpack_all (res_code, info); + + const query_result_info ¤t_result_info = info.qresult_info; + query_cursor *cursor = m_stack->get_cursor (current_result_info.query_id); + if (cursor) + { + cursor->change_owner (&thread_ref); + return m_stack->send_data_to_java (b); + } + else + { + assert (false); + return ER_FAILED; + } + }; + + error = m_stack->send_data_to_client (get_make_outresult_info, code, query_id); + + return error; + } + + int + executor::callback_get_generated_keys (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_GET_GENERATED_KEYS; + int handler_id; + unpacker.unpack_all (handler_id); + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, handler_id); + return error; + } + + int + executor::callback_end_transaction (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_END_TRANSACTION; + int command; // commit or abort + + unpacker.unpack_all (command); + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, command); + return error; + } + + int + executor::callback_change_auth_rights (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_CHANGE_RIGHTS; + + int command; + std::string auth_name; + + unpacker.unpack_all (command, auth_name); + + auto java_lambda = [&] (const cubmem::block & b) + { + return m_stack->send_data_to_java (b); + }; + + error = m_stack->send_data_to_client (java_lambda, code, command, auth_name); + return error; + } + + int + executor::callback_get_code_attr (cubthread::entry &thread_ref, packing_unpacker &unpacker) + { + int error = NO_ERROR; + int code = METHOD_CALLBACK_GET_CODE_ATTR; + + std::string attr_name; + + DB_VALUE res; + db_make_null (&res); + unpacker.unpack_all (attr_name); + + OID *code_oid = &m_sig.ext.sp.code_oid; + if (OID_ISNULL (code_oid)) + { + error = ER_FAILED; + } + + if (error == NO_ERROR) + { + error = sp_get_code_attr (&thread_ref, attr_name, code_oid, &res); + } + + cubmem::block blk; + if (error == NO_ERROR) + { + dbvalue_java java_packer; + java_packer.value = &res; + + blk = std::move (pack_data_block (error, java_packer)); + } + else + { + blk = std::move (pack_data_block (error)); + } + + db_value_clear (&res); + + error = m_stack->send_data_to_java (blk); + + if (blk.is_valid ()) + { + delete[] blk.ptr; + } + + return error; + } +} diff --git a/src/sp/pl_executor.hpp b/src/sp/pl_executor.hpp new file mode 100644 index 0000000000..8a84814997 --- /dev/null +++ b/src/sp/pl_executor.hpp @@ -0,0 +1,124 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * pl_executor.hpp + */ + +#ifndef _PL_EXECUTOR_HPP_ +#define _PL_EXECUTOR_HPP_ + +#if !defined (SERVER_MODE) && !defined (SA_MODE) +#error Belongs to server module +#endif /* !defined (SERVER_MODE) && !defined (SA_MODE) */ + +#include "pl_execution_stack_context.hpp" +#include "pl_signature.hpp" +#include "pl_session.hpp" + +// forward definitions +struct regu_variable_list_node; + +namespace cubpl +{ + struct invoke_java : public cubpacking::packable_object + { + invoke_java () = delete; + invoke_java (uint64_t g_id, int tran_id, pl_signature *sig, bool tc); + + void pack (cubpacking::packer &serializator) const override; + void unpack (cubpacking::unpacker &deserializator) override; + size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; + + uint64_t g_id; + int tran_id; + + std::string signature; + std::string auth; + int lang; + int num_args; + std::vector arg_mode; + std::vector arg_type; + int result_type; + + bool transaction_control; // TODO: wrap it with proper structs + }; + + class executor + { + public: + executor () = delete; // Not DefaultConstructible + executor (pl_signature &sig); + + executor (executor &&other) = delete; // Not MoveConstructible + executor (const executor ©) = delete; // Not CopyConstructible + + executor &operator= (executor &&other) = delete; // Not MoveAssignable + executor &operator= (const executor ©) = delete; // Not CopyAssignable + + ~executor (); + + // args + int fetch_args_peek (regu_variable_list_node *val_list_p, VAL_DESCR *val_desc_p, OID *obj_oid_p, + QFILE_TUPLE tuple); // QUERY + int fetch_args_peek (std::vector > args); // CALL + + // execute + int execute (DB_VALUE &value); + + // getter + std::vector &get_out_args (); + execution_stack *get_stack (); + + private: + execution_stack *m_stack; + pl_signature &m_sig; + + std::vector > m_args; + std::vector m_out_args; + + // check + int check_unsupported_dbtype (); + bool is_supported_dbtype (const DB_VALUE &val); + + int change_exec_rights (const char *auth_name); + + // command handling + int request_invoke_command (); + int response_invoke_command (DB_VALUE &value); + + int response_result (int code, DB_VALUE &returnval); + int response_callback_command (); + + int callback_get_db_parameter (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_prepare (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_execute (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_fetch (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_oid_get (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_oid_put (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_oid_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_collection_cmd (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_make_outresult (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_get_generated_keys (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_end_transaction (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_change_auth_rights (cubthread::entry &thread_ref, packing_unpacker &unpacker); + int callback_get_code_attr (cubthread::entry &thread_ref, packing_unpacker &unpacker); + }; +} + +#endif \ No newline at end of file diff --git a/src/sp/jsp_file.c b/src/sp/pl_file.c similarity index 54% rename from src/sp/jsp_file.c rename to src/sp/pl_file.c index 5723cd01bd..f5ded88f9f 100644 --- a/src/sp/jsp_file.c +++ b/src/sp/pl_file.c @@ -18,7 +18,7 @@ /* - * jsp_file.c - Functions to manage files related to Java Stored Procedure Server + * pl_file.c - Functions to manage files related to Java Stored Procedure Server * * Note: */ @@ -27,7 +27,7 @@ #include #endif -#include "jsp_file.h" +#include "pl_file.h" #include "porting.h" #include "environment_variable.h" @@ -40,28 +40,28 @@ #include "memory_wrapper.hpp" bool -javasp_open_info_dir () +pl_open_info_dir () { - char javasp_dir[PATH_MAX]; - envvar_vardir_file (javasp_dir, sizeof (javasp_dir), "javasp"); + char pl_dir[PATH_MAX]; + envvar_vardir_file (pl_dir, sizeof (pl_dir), "pl"); - if (access (javasp_dir, F_OK) < 0) + if (access (pl_dir, F_OK) < 0) { /* create directory if not exist */ - if (mkdir (javasp_dir, 0777) < 0 && errno == ENOENT) + if (mkdir (pl_dir, 0777) < 0 && errno == ENOENT) { char pdir[PATH_MAX]; - if (cub_dirname_r (javasp_dir, pdir, PATH_MAX) > 0 && access (pdir, F_OK) < 0) + if (cub_dirname_r (pl_dir, pdir, PATH_MAX) > 0 && access (pdir, F_OK) < 0) { mkdir (pdir, 0777); } } } - if (access (javasp_dir, F_OK) < 0) + if (access (pl_dir, F_OK) < 0) { - if (mkdir (javasp_dir, 0777) < 0) + if (mkdir (pl_dir, 0777) < 0) { return false; } @@ -71,13 +71,13 @@ javasp_open_info_dir () } FILE * -javasp_open_info (const char *db_name, const char *mode) +pl_open_info (const char *db_name, const char *mode) { FILE *fp = NULL; char file_name[PATH_MAX] = { 0 }; char file_path[PATH_MAX] = { 0 }; - snprintf (file_name, PATH_MAX, "javasp/javasp_%s.info", db_name); + snprintf (file_name, PATH_MAX, "pl/pl_%s.info", db_name); envvar_vardir_file (file_path, PATH_MAX, file_name); fp = fopen (file_path, mode); @@ -86,24 +86,24 @@ javasp_open_info (const char *db_name, const char *mode) } void -javasp_unlink_info (const char *db_name) +pl_unlink_info (const char *db_name) { char file_name[PATH_MAX] = { 0 }; char file_path[PATH_MAX] = { 0 }; - snprintf (file_name, PATH_MAX, "javasp/javasp_%s.info", db_name); + snprintf (file_name, PATH_MAX, "pl/pl_%s.info", db_name); envvar_vardir_file (file_path, PATH_MAX, file_name); unlink (file_path); } bool -javasp_get_info_file (char *buf, size_t len, const char *db_name) +pl_get_info_file (char *buf, size_t len, const char *db_name) { - char javasp_vardir[PATH_MAX]; - envvar_vardir_file (javasp_vardir, PATH_MAX, "javasp"); + char pl_vardir[PATH_MAX]; + envvar_vardir_file (pl_vardir, PATH_MAX, "pl"); - if (snprintf (buf, len, "%s/javasp_%s.info", javasp_vardir, db_name) < 0) + if (snprintf (buf, len, "%s/pl_%s.info", pl_vardir, db_name) < 0) { assert (false); buf[0] = '\0'; @@ -113,12 +113,12 @@ javasp_get_info_file (char *buf, size_t len, const char *db_name) } bool -javasp_get_error_file (char *buf, size_t len, const char *db_name) +pl_get_error_file (char *buf, size_t len, const char *db_name) { - char javasp_logdir[PATH_MAX]; - envvar_logdir_file (javasp_logdir, sizeof (javasp_logdir), ""); + char pl_logdir[PATH_MAX]; + envvar_logdir_file (pl_logdir, sizeof (pl_logdir), ""); - if (snprintf (buf, len, "%s/%s_java.err", javasp_logdir, db_name) < 0) + if (snprintf (buf, len, "%s/%s_java.err", pl_logdir, db_name) < 0) { assert (false); buf[0] = '\0'; @@ -128,12 +128,12 @@ javasp_get_error_file (char *buf, size_t len, const char *db_name) } bool -javasp_get_log_file (char *buf, size_t len, const char *db_name) +pl_get_log_file (char *buf, size_t len, const char *db_name) { - char javasp_logdir[PATH_MAX]; - envvar_logdir_file (javasp_logdir, sizeof (javasp_logdir), ""); + char pl_logdir[PATH_MAX]; + envvar_logdir_file (pl_logdir, sizeof (pl_logdir), ""); - if (snprintf (buf, len, "%s/%s_java.log", javasp_logdir, db_name) < 0) + if (snprintf (buf, len, "%s/%s_java.log", pl_logdir, db_name) < 0) { assert (false); buf[0] = '\0'; @@ -143,11 +143,11 @@ javasp_get_log_file (char *buf, size_t len, const char *db_name) } bool -javasp_read_info (const char *db_name, JAVASP_SERVER_INFO & info) +pl_read_info (const char *db_name, PL_SERVER_INFO & info) { FILE *fp = NULL; - fp = javasp_open_info (db_name, "r"); + fp = pl_open_info (db_name, "r"); if (fp) { fscanf (fp, "%d %d", &info.pid, &info.port); @@ -159,12 +159,12 @@ javasp_read_info (const char *db_name, JAVASP_SERVER_INFO & info) } bool -javasp_write_info (const char *db_name, JAVASP_SERVER_INFO info) +pl_write_info (const char *db_name, PL_SERVER_INFO info) { bool result = false; FILE *fp = NULL; - fp = javasp_open_info (db_name, "w+"); + fp = pl_open_info (db_name, "w+"); if (fp) { fprintf (fp, "%d %d", info.pid, info.port); @@ -175,8 +175,8 @@ javasp_write_info (const char *db_name, JAVASP_SERVER_INFO info) } bool -javasp_reset_info (const char *db_name) +pl_reset_info (const char *db_name) { - JAVASP_SERVER_INFO reset_info = JAVASP_SERVER_INFO_INITIALIZER; - return javasp_write_info (db_name, reset_info); + PL_SERVER_INFO reset_info = PL_SERVER_INFO_INITIALIZER; + return pl_write_info (db_name, reset_info); } diff --git a/src/sp/pl_file.h b/src/sp/pl_file.h new file mode 100644 index 0000000000..5817e326f1 --- /dev/null +++ b/src/sp/pl_file.h @@ -0,0 +1,69 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + + +/* + * pl_file.h - Functions to manage files related to Java Stored Procedure Server + * + * Note: + */ + +#ifndef _PL_FILE_H_ +#define _PL_FILE_H_ + +#ident "$Id$" + +#include "porting.h" +#include + +typedef struct pl_server_info PL_SERVER_INFO; +struct pl_server_info +{ + int pid; + int port; +}; + +#define PL_PID_DISABLED -1 +#define PL_PORT_DISABLED -2 +#define PL_PORT_UDS_MODE -1 + +#define PL_SERVER_INFO_INITIALIZER \ + {PL_PID_DISABLED, PL_PORT_DISABLED} + +#ifdef __cplusplus +extern "C" +{ +#endif + + extern EXPORT_IMPORT bool pl_open_info_dir (); + extern EXPORT_IMPORT FILE *pl_open_info (const char *db_name, const char *mode); + extern EXPORT_IMPORT void pl_unlink_info (const char *db_name); + + extern EXPORT_IMPORT bool pl_read_info (const char *db_name, PL_SERVER_INFO & info); + extern EXPORT_IMPORT bool pl_write_info (const char *db_name, PL_SERVER_INFO info); + extern EXPORT_IMPORT bool pl_reset_info (const char *db_name); + + extern EXPORT_IMPORT bool pl_get_info_file (char *buf, size_t len, const char *db_name); + extern EXPORT_IMPORT bool pl_get_error_file (char *buf, size_t len, const char *db_name); + extern EXPORT_IMPORT bool pl_get_log_file (char *buf, size_t len, const char *db_name); + +#ifdef __cplusplus +} +#endif + +#endif /* _PL_FILE_H_ */ diff --git a/src/method/method_query_cursor.cpp b/src/sp/pl_query_cursor.cpp similarity index 89% rename from src/method/method_query_cursor.cpp rename to src/sp/pl_query_cursor.cpp index 5d88a20d89..fe45842899 100644 --- a/src/method/method_query_cursor.cpp +++ b/src/sp/pl_query_cursor.cpp @@ -16,27 +16,34 @@ * */ -#include "method_query_cursor.hpp" +#include "pl_query_cursor.hpp" #include "dbtype.h" #include "dbtype_def.h" #include "list_file.h" #include "log_impl.h" #include "object_representation.h" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" -namespace cubmethod +namespace cubpl { query_cursor::query_cursor (cubthread::entry *thread_p, QMGR_QUERY_ENTRY *query_entry_p, bool oid_included) : m_thread (thread_p) , m_is_oid_included (oid_included) , m_is_opened (false) , m_fetch_count (1000) // FIXME: change the fixed value, 1000 + , m_query_id (0) { reset (query_entry_p); } + query_cursor::~query_cursor () + { + close (); + } + int query_cursor::reset (QMGR_QUERY_ENTRY *query_entry_p) { @@ -127,6 +134,10 @@ namespace cubmethod } } } + else if (scan_code == S_END) + { + close (); + } return scan_code; } @@ -174,6 +185,10 @@ namespace cubmethod } } } + else if (scan_code == S_END) + { + close (); + } return scan_code; } @@ -181,7 +196,15 @@ namespace cubmethod void query_cursor::change_owner (cubthread::entry *thread_p) { - if (m_thread->get_id () == thread_p->get_id ()) + if (thread_p == nullptr) + { + close (); + // qfile_update_qlist_count (m_thread, m_list_id, -1); + m_thread = nullptr; + return; + } + + if (m_thread != nullptr && m_thread->get_id () == thread_p->get_id ()) { return; } @@ -192,7 +215,13 @@ namespace cubmethod m_thread = thread_p; // m_list_id is going to be destoryed on server-side, so that qlist_count has to be updated - qfile_update_qlist_count (thread_p, m_list_id, 1); + // qfile_update_qlist_count (thread_p, m_list_id, 1); + } + + cubthread::entry * + query_cursor::get_owner () const + { + return m_thread; } std::vector @@ -201,8 +230,6 @@ namespace cubmethod return m_current_tuple; } - void clear (); - int query_cursor::get_current_index () { @@ -257,4 +284,5 @@ namespace cubmethod m_fetch_count = cnt; } } + } diff --git a/src/method/method_query_cursor.hpp b/src/sp/pl_query_cursor.hpp similarity index 87% rename from src/method/method_query_cursor.hpp rename to src/sp/pl_query_cursor.hpp index dd63d62e90..b2351a2ff8 100644 --- a/src/method/method_query_cursor.hpp +++ b/src/sp/pl_query_cursor.hpp @@ -17,11 +17,11 @@ */ // -// method_query_cursor.hpp +// pl_query_cursor.hpp // -#ifndef _METHOD_QUERY_CURSOR_HPP_ -#define _METHOD_QUERY_CURSOR_HPP_ +#ifndef _PL_QUERY_CURSOR_HPP_ +#define _PL_QUERY_CURSOR_HPP_ #ident "$Id$" @@ -29,7 +29,7 @@ #include "dbtype_def.h" #include "query_list.h" /* QUERY_ID, QFILE_LIST_ID */ -#include "query_manager.h" +#include "query_manager.h" /* QMGR_QUERY_ENTRY */ // thread_entry.hpp namespace cubthread @@ -37,12 +37,13 @@ namespace cubthread class entry; } -namespace cubmethod +namespace cubpl { class query_cursor { public: query_cursor (cubthread::entry *thread_p, QMGR_QUERY_ENTRY *query_entry_p, bool is_oid_included = false); + ~query_cursor (); int open (); void close (); @@ -68,10 +69,11 @@ namespace cubmethod int get_tuple_value (int index, DB_VALUE &result); bool get_is_oid_included (); bool get_is_opened (); - int get_fetch_count (); void set_fetch_count (int cnt); + cubthread::entry *get_owner () const; + private: cubthread::entry *m_thread; /* which thread owns this cursor */ @@ -90,4 +92,6 @@ namespace cubmethod }; } // namespace cubmethod -#endif /* _METHOD_QUERY_CURSOR_HPP_ */ +using PL_QUERY_CURSOR = cubpl::query_cursor; + +#endif /* _PL_QUERY_CURSOR_HPP_ */ diff --git a/src/method/method_runtime_context.cpp b/src/sp/pl_session.cpp similarity index 55% rename from src/method/method_runtime_context.cpp rename to src/sp/pl_session.cpp index 1bac853326..331c81a432 100644 --- a/src/method/method_runtime_context.cpp +++ b/src/sp/pl_session.cpp @@ -16,139 +16,171 @@ * */ -#include "method_runtime_context.hpp" +#include "pl_session.hpp" -#include "method_query_cursor.hpp" +#include "pl_query_cursor.hpp" #include "query_manager.h" #include "session.h" #include "xserver_interface.h" #include "thread_manager.hpp" #include "method_error.hpp" + +#include "method_struct_parameter_info.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" -namespace cubmethod +namespace cubpl { ////////////////////////////////////////////////////////////////////////// // Global interface ////////////////////////////////////////////////////////////////////////// - runtime_context *get_rctx (cubthread::entry *thread_p) + session *get_session () { - method_runtime_context *rctx = nullptr; - session_get_method_runtime_context (thread_p, rctx); - return rctx; + session *s = nullptr; + cubthread::entry *thread_p = thread_get_thread_entry_info (); + session_get_pl_session (thread_p, s); + return s; } ////////////////////////////////////////////////////////////////////////// // Runtime Context ////////////////////////////////////////////////////////////////////////// - runtime_context::runtime_context () + session::session () : m_mutex () - , m_group_stack {} - , m_returning_cursors {} - , m_group_map {} + , m_exec_stack {} + , m_stack_idx {-1} + , m_session_cursors {} + , m_stack_map {} , m_cursor_map {} , m_is_interrupted (false) , m_interrupt_id (NO_ERROR) , m_is_running (false) - , m_conn_pool (METHOD_MAX_RECURSION_DEPTH + 1) , m_req_id {0} + , m_param_info {nullptr} { - // + m_exec_stack.reserve (METHOD_MAX_RECURSION_DEPTH + 1); } - runtime_context::~runtime_context () + session::~session () { - destroy_all_groups (); + } - method_invoke_group * - runtime_context::create_invoke_group (cubthread::entry *thread_p, const method_sig_list &sig_list, bool is_scan) + execution_stack * + session::create_and_push_stack (cubthread::entry *thread_p) { - std::unique_lock ulock (m_mutex); + if (thread_p == nullptr) + { + thread_p = thread_get_thread_entry_info (); + } - method_invoke_group *group = new cubmethod::method_invoke_group (thread_p, sig_list, is_scan); - if (group) + // check interrupt + if (is_interrupted () && m_stack_idx > -1) { - m_group_map [group->get_id ()] = group; + // block creating a new stack + set_local_error_for_interrupt (); + m_cond_var.notify_all (); + return nullptr; } - return group; - } - void - runtime_context::push_stack (cubthread::entry *thread_p, method_invoke_group *group) - { std::unique_lock ulock (m_mutex); - m_is_running = true; - m_group_stack.push_back (group->get_id ()); + execution_stack *stack = new execution_stack (thread_p); + if (stack) + { + m_stack_map [stack->get_id ()] = stack; + + // update stack index + m_stack_idx++; + + // push to exec_stack + int stack_size = (int) m_exec_stack.size (); + PL_STACK_ID stack_id = stack->get_id (); + if (m_stack_idx < stack_size) + { + m_exec_stack [m_stack_idx] = stack_id; + } + else + { + m_exec_stack.emplace_back (stack_id); + } + + m_is_running = true; + } + else + { + set_interrupt (ER_OUT_OF_VIRTUAL_MEMORY); + } + + return stack; } void - runtime_context::pop_stack (cubthread::entry *thread_p, method_invoke_group *claimed) + session::pop_and_destroy_stack (const PL_STACK_ID sid) { - std::unique_lock ulock (m_mutex); - - if (claimed->is_for_scan () && m_group_stack.back() != claimed->get_id ()) + if (m_stack_idx == -1) { - // push deferred - // When beginning method_invoke_group with method scan, method_invoke_group belonging to child node in XASL is pushed first (postorder) - // When method_invoke_group is ended while clearing XASL by qexec_clear_xasl(), method_invoke_group belonging to the parent node in XASL is poped first (preorder) - // Because of these differences, I've introduced the m_deferred_free_stack structure to follow the order of clearing according to the XASL structure when clearing method_invoke_groups from the m_group_stack. - m_deferred_free_stack.push_back (claimed->get_id ()); + // interrupted return; } auto pred = [&] () -> bool { // condition to check - return m_group_stack.back() == claimed->get_id (); + return m_exec_stack[m_stack_idx] == sid; }; // Guaranteed to be removed from the topmost element + std::unique_lock ulock (m_mutex); m_cond_var.wait (ulock, pred); if (pred ()) { - destroy_group (m_group_stack.back ()); - m_group_stack.pop_back (); - } + if (m_stack_idx > -1) + { + m_exec_stack[m_stack_idx] = -1; + m_stack_idx--; + } - // should be freed for all XASL structure - while (m_deferred_free_stack.empty () == false && m_deferred_free_stack.back () == m_group_stack.back()) - { - destroy_group (m_group_stack.back ()); - m_group_stack.pop_back (); - m_deferred_free_stack.pop_back (); + m_stack_map.erase (sid); } - if (m_group_stack.empty()) + if (m_stack_idx < 0) { - // reset interrupt state - m_is_interrupted = false; - m_interrupt_id = NO_ERROR; m_is_running = false; - // notify m_group_stack becomes empty (); - ulock.unlock (); - m_cond_var.notify_all (); + // clear interrupt + m_is_interrupted = false; + m_interrupt_id = NO_ERROR; + m_interrupt_msg.clear (); } + + ulock.unlock (); + m_cond_var.notify_all (); } - method_invoke_group * - runtime_context::top_stack () + execution_stack * + session::top_stack () { std::unique_lock ulock (m_mutex); - if (m_group_stack.empty()) + + return top_stack_internal (); + } + + execution_stack * + session::top_stack_internal () + { + if (m_exec_stack.empty()) { return nullptr; } - METHOD_GROUP_ID top = m_group_stack.back (); - const auto &it = m_group_map.find (top); - if (it == m_group_map.end ()) + PL_STACK_ID top = m_exec_stack[m_stack_idx]; + const auto &it = m_stack_map.find (top); + if (it == m_stack_map.end ()) { // should not happended assert (false); @@ -158,8 +190,25 @@ namespace cubmethod return it->second; } + bool + session::is_thread_involved (thread_id_t id) + { + std::unique_lock ulock (m_mutex); + + for (const auto &it : m_stack_map) + { + execution_stack *stack = it.second; + if (stack->get_thread_entry () && id == stack->get_thread_entry ()->get_id ()) + { + return true; + } + } + + return false; + } + void - runtime_context::set_interrupt (int reason, std::string msg) + session::set_interrupt (int reason, std::string msg) { switch (reason) { @@ -189,36 +238,36 @@ namespace cubmethod } void - runtime_context::set_local_error_for_interrupt () + session::set_local_error_for_interrupt () { - handle_method_error (get_interrupt_id (), get_interrupt_msg ()); + cubmethod::handle_method_error (get_interrupt_id (), get_interrupt_msg ()); } bool - runtime_context::is_interrupted () + session::is_interrupted () { return m_is_interrupted; } int - runtime_context::get_interrupt_id () + session::get_interrupt_id () { return m_interrupt_id; } std::string - runtime_context::get_interrupt_msg () + session::get_interrupt_msg () { return m_interrupt_msg; } void - runtime_context::wait_for_interrupt () + session::wait_for_interrupt () { auto pred = [this] () -> bool { // condition of finish - return m_group_stack.empty () && is_running () == false; + return is_running () == false; }; if (pred ()) @@ -226,24 +275,32 @@ namespace cubmethod return; } + m_cond_var.notify_all (); + std::unique_lock ulock (m_mutex); m_cond_var.wait (ulock, pred); } int - runtime_context::get_depth () + session::get_depth () + { + return m_stack_map.size () - m_deferred_free_stack.size (); + } + + SESSION_ID + session::get_id () { - return m_group_map.size () - m_deferred_free_stack.size (); + return m_id; } bool - runtime_context::is_running () + session::is_running () { return m_is_running; } query_cursor * - runtime_context::get_cursor (cubthread::entry *thread_p, QUERY_ID query_id) + session::get_cursor (cubthread::entry *thread_p, QUERY_ID query_id) { if (query_id == NULL_QUERY_ID) { @@ -264,7 +321,7 @@ namespace cubmethod } query_cursor * - runtime_context::create_cursor (cubthread::entry *thread_p, QUERY_ID query_id, bool is_oid_included) + session::create_cursor (cubthread::entry *thread_p, QUERY_ID query_id, bool is_oid_included) { if (query_id == NULL_QUERY_ID || query_id >= SHRT_MAX) { @@ -308,7 +365,7 @@ namespace cubmethod } void - runtime_context::destroy_cursor (cubthread::entry *thread_p, QUERY_ID query_id) + session::destroy_cursor (cubthread::entry *thread_p, QUERY_ID query_id) { if (query_id == NULL_QUERY_ID) { @@ -316,7 +373,11 @@ namespace cubmethod return; } - std::unique_lock ulock (m_mutex); + // TODo + // std::unique_lock ulock (m_mutex); + + // remove from session cursor map + // m_session_cursors.erase (query_id); // safe guard // find in map auto search = m_cursor_map.find (query_id); @@ -338,7 +399,7 @@ namespace cubmethod } void - runtime_context::register_returning_cursor (cubthread::entry *thread_p, QUERY_ID query_id) + session::add_session_cursor (cubthread::entry *thread_p, QUERY_ID query_id) { if (query_id == NULL_QUERY_ID) { @@ -346,14 +407,13 @@ namespace cubmethod return; } - std::unique_lock ulock (m_mutex); + // std::unique_lock ulock (m_mutex); - m_returning_cursors.insert (query_id); - // m_cursor_map.erase (query_id); + m_session_cursors.insert (query_id); } void - runtime_context::deregister_returning_cursor (cubthread::entry *thread_p, QUERY_ID query_id) + session::remove_session_cursor (cubthread::entry *thread_p, QUERY_ID query_id) { if (query_id == NULL_QUERY_ID) { @@ -361,69 +421,51 @@ namespace cubmethod return; } - std::unique_lock ulock (m_mutex); + // std::unique_lock ulock (m_mutex); - m_returning_cursors.erase (query_id); + m_session_cursors.erase (query_id); } - void - runtime_context::destroy_group (METHOD_GROUP_ID id) + bool + session::is_session_cursor (QUERY_ID query_id) { - // assume that lock is already acquired - // std::unique_lock ulock (m_mutex); - - // find in map - auto search = m_group_map.find (id); - if (search != m_group_map.end ()) + if (m_session_cursors.find (query_id) != m_session_cursors.end ()) { - method_invoke_group *group = search->second; - if (group) - { - delete group; - } - m_group_map.erase (search); + return true; } - } - - void - runtime_context::destroy_all_groups () - { - std::unique_lock ulock (m_mutex); - for (auto &it : m_group_map) + else { - if (it.second) - { - delete it.second; - } + return false; } - m_group_map.clear (); } void - runtime_context::destroy_all_cursors () + session::destroy_all_cursors () { std::unique_lock ulock (m_mutex); for (auto &it : m_cursor_map) { - /* - if (cubthread::get_manager () != NULL) - { - destroy_cursor (&cubthread::get_entry (), it.first); - } - */ - if (it.second) + query_cursor *cursor = it.second; + if (cursor) { + destroy_cursor (cursor->get_owner (), it.first /* QUERY_ID */); delete it.second; } } m_cursor_map.clear (); - m_returning_cursors.clear (); + m_session_cursors.clear (); } - connection_pool & - runtime_context::get_connection_pool () + cubmethod::db_parameter_info * + session::get_db_parameter_info () const + { + return m_param_info; + } + + void + session::set_db_parameter_info (cubmethod::db_parameter_info *param_info) { - return m_conn_pool; + m_param_info = param_info; } } // cubmethod diff --git a/src/method/method_runtime_context.hpp b/src/sp/pl_session.hpp similarity index 62% rename from src/method/method_runtime_context.hpp rename to src/sp/pl_session.hpp index c4aae4427a..b8282958bf 100644 --- a/src/method/method_runtime_context.hpp +++ b/src/sp/pl_session.hpp @@ -17,11 +17,11 @@ */ // -// method_runtime_context.hpp +// pl_session.hpp // -#ifndef _METHOD_RUNTIME_CONTEXT_HPP_ -#define _METHOD_RUNTIME_CONTEXT_HPP_ +#ifndef _PL_SESSION_HPP_ +#define _PL_SESSION_HPP_ #if !defined (SERVER_MODE) && !defined (SA_MODE) #error Belongs to server module @@ -34,8 +34,10 @@ #include #include -#include "method_connection_pool.hpp" -#include "method_def.hpp" +#include "pl_connection.hpp" + +#include "pl_execution_stack_context.hpp" +#include "pl_signature.hpp" // thread_entry.hpp namespace cubthread @@ -45,41 +47,53 @@ namespace cubthread namespace cubmethod { - // forward declarations class method_invoke_group; + class db_parameter_info; +} + +namespace cubpl +{ + // forward declarations class query_cursor; - class connection_pool; + class execution_stack; using THREAD_ENTRY_IDX = int; using QUERY_ID = std::uint64_t; - class runtime_context + class session { public: - runtime_context (); - ~runtime_context (); + session (); + ~session (); - using invoke_group_map_type = std::unordered_map ; - using invoke_group_stack_type = std::deque ; - using invoke_group_iter = std::unordered_map ::iterator; + using exec_stack_map_type = std::unordered_map ; + using exec_stack_id_type = std::vector ; + using exec_stack_iter = std::unordered_map ::iterator; using cursor_map_type = std::unordered_map ; using cursor_iter = std::unordered_map ::iterator; + /* cursor management */ query_cursor *create_cursor (cubthread::entry *thread_p, QUERY_ID query_id, bool oid_included = false); query_cursor *get_cursor (cubthread::entry *thread_p, QUERY_ID query_id); void destroy_cursor (cubthread::entry *thread_p, QUERY_ID query_id); - void register_returning_cursor (cubthread::entry *thread_p, QUERY_ID query_id); - void deregister_returning_cursor (cubthread::entry *thread_p, QUERY_ID query_id); - - method_invoke_group *create_invoke_group (cubthread::entry *thread_p, const method_sig_list &siglist, bool is_scan); + void add_session_cursor (cubthread::entry *thread_p, QUERY_ID query_id); + void remove_session_cursor (cubthread::entry *thread_p, QUERY_ID query_id); + bool is_session_cursor (QUERY_ID query_id); + /* stack management */ // Currently these functions are used for debugging purpose. // In the recursive call situation, each time the function is called, a new worker from the thread pool is assigned. With this code, you can easily know the current state. // In the future, these functions will resolve some cases when it is necessary to set an error for all threads participating in a recursive call e.g. interrupt - void push_stack (cubthread::entry *thread_p, method_invoke_group *group); - void pop_stack (cubthread::entry *thread_p, method_invoke_group *claimed); - method_invoke_group *top_stack (); + execution_stack *create_and_push_stack (cubthread::entry *thread_p); + void pop_and_destroy_stack (const PL_STACK_ID sid); + execution_stack *top_stack (); + + /* thread */ + bool is_thread_involved (thread_id_t id); + + /* getter */ + SESSION_ID get_id (); void set_interrupt (int reason, std::string msg = ""); bool is_interrupted (); @@ -98,41 +112,45 @@ namespace cubmethod return m_req_id++; } - connection_pool &get_connection_pool (); + cubmethod::db_parameter_info *get_db_parameter_info () const; + void set_db_parameter_info (cubmethod::db_parameter_info *param_info); private: - void destroy_group (METHOD_GROUP_ID id); - - void destroy_all_groups (); + execution_stack *top_stack_internal (); void destroy_all_cursors (); std::mutex m_mutex; std::condition_variable m_cond_var; - invoke_group_stack_type m_group_stack; // runtime stack - std::unordered_set m_returning_cursors; + std::unordered_set m_session_cursors; - invoke_group_map_type m_group_map; // method executor storage - cursor_map_type m_cursor_map; // server-side cursor storage + exec_stack_map_type m_stack_map; // method executor storage + exec_stack_id_type m_exec_stack; // runtime stack (implemented using vector) + int m_stack_idx; - invoke_group_stack_type m_deferred_free_stack; - connection_pool m_conn_pool; + cursor_map_type m_cursor_map; // server-side cursor storage + + exec_stack_id_type m_deferred_free_stack; std::atomic m_req_id; + cubmethod::db_parameter_info *m_param_info; + bool m_is_interrupted; int m_interrupt_id; std::string m_interrupt_msg; bool m_is_running; + + SESSION_ID m_id; }; /* global interface */ - runtime_context *get_rctx (cubthread::entry *thread_p); + session *get_session (); } // cubmethod // alias declaration for legacy C files -using method_runtime_context = cubmethod::runtime_context; +using PL_SESSION = cubpl::session; -#endif // _METHOD_RUNTIME_CONTEXT_HPP_ \ No newline at end of file +#endif // _PL_SESSION_HPP_ diff --git a/src/sp/pl_signature.cpp b/src/sp/pl_signature.cpp new file mode 100644 index 0000000000..2978426ec2 --- /dev/null +++ b/src/sp/pl_signature.cpp @@ -0,0 +1,429 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#include "pl_signature.hpp" + +#include +#include "memory_alloc.h" +#include "memory_private_allocator.hpp" +#include "sp_constants.hpp" + +#if defined (SERVER_MODE) +#include "thread_manager.hpp" +#endif + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +#define CHECK_NULL_AND_FREE(owner, val) \ + do { \ + if (val != nullptr) \ + { \ + db_private_free_and_init (owner, val); \ + } \ + } while(0) + +namespace cubpl +{ + static const char *EMPTY_STRING = ""; + + pl_arg::pl_arg () + : pl_arg (0) + {} + + pl_arg::pl_arg (int num_args) + : arg_size {num_args} + { +#if defined (SERVER_MODE) + owner = thread_get_thread_entry_info (); +#else + owner = NULL; +#endif + set_arg_size (num_args); + } + + pl_arg::~pl_arg () + { + clear (); + } + + void + pl_arg::clear () + { + if (arg_size > 0) + { + CHECK_NULL_AND_FREE (owner, arg_mode); + CHECK_NULL_AND_FREE (owner, arg_type); + for (int i = 0; i < arg_size; i++) + { + if (arg_default_value_size && arg_default_value_size[i] > 0) + { + CHECK_NULL_AND_FREE (owner, arg_default_value[i]); + } + } + CHECK_NULL_AND_FREE (owner, arg_default_value_size); + CHECK_NULL_AND_FREE (owner, arg_default_value); + } + } + + void + pl_arg::pack (cubpacking::packer &serializator) const + { + serializator.pack_int (arg_size); + + if (arg_size > 0) + { + serializator.pack_int_array (arg_mode, arg_size); + serializator.pack_int_array (arg_type, arg_size); + } + } + + void + pl_arg::unpack (cubpacking::unpacker &deserializator) + { + deserializator.unpack_int (arg_size); + + if (arg_size > 0) + { + set_arg_size (arg_size); + + int cnt; + deserializator.unpack_int_array (arg_mode, cnt); + assert (arg_size == cnt); + + deserializator.unpack_int_array (arg_type, cnt); + assert (arg_size == cnt); + } + } + + size_t + pl_arg::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + { + size_t size = serializator.get_packed_int_size (start_offset); // arg_size + if (arg_size > 0) + { + size += serializator.get_packed_int_vector_size (size, arg_size); // arg_mode + size += serializator.get_packed_int_vector_size (size, arg_size); // arg_type + } + return size; + } + + void + pl_arg::set_arg_size (int num_args) + { + clear (); + if (num_args > 0) + { + arg_size = num_args; + arg_mode = (int *) db_private_alloc (NULL, (num_args) * sizeof (int)); + arg_type = (int *) db_private_alloc (NULL, (num_args) * sizeof (int)); + arg_default_value_size = (int *) db_private_alloc (NULL, (num_args) * sizeof (int)); + arg_default_value = (char **) db_private_alloc (NULL, (num_args) * sizeof (char *)); + for (int i = 0; i < num_args; i++) + { + arg_mode[i] = 0; + arg_type[i] = 0; + arg_default_value_size[i] = 0; + arg_default_value[i] = nullptr; + } + } + else + { + arg_size = 0; + arg_mode = nullptr; + arg_type = nullptr; + arg_default_value_size = nullptr; + arg_default_value = nullptr; + } + } + + pl_signature::pl_signature () + : name {nullptr} + , auth {nullptr} + , type {0} + , result_type {0} + { +#if defined (SERVER_MODE) + owner = thread_get_thread_entry_info (); +#else + owner = NULL; +#endif + memset (&ext, 0, sizeof (pl_ext)); + } + + pl_signature::~pl_signature () + { + CHECK_NULL_AND_FREE (owner, name); + CHECK_NULL_AND_FREE (owner, auth); + + if (PL_TYPE_IS_METHOD (type)) + { + CHECK_NULL_AND_FREE (owner, ext.method.class_name); + CHECK_NULL_AND_FREE (owner, ext.method.arg_pos); + } + else + { + CHECK_NULL_AND_FREE (owner, ext.sp.target_class_name); + CHECK_NULL_AND_FREE (owner, ext.sp.target_method_name); + } + } + + void + pl_signature::pack (cubpacking::packer &serializator) const + { + serializator.pack_int (type); + serializator.pack_c_string (name, strlen (name)); + + serializator.pack_bool (auth != nullptr); + if (auth) + { + serializator.pack_c_string (auth, strlen (auth)); + } + + serializator.pack_int (result_type); + + // arg + arg.pack (serializator); + + // ext + if (PL_TYPE_IS_METHOD (type)) + { + serializator.pack_bool (ext.method.class_name != nullptr); + if (ext.method.class_name) + { + serializator.pack_c_string (ext.method.class_name, strlen (ext.method.class_name)); + } + if (arg.arg_size > 0) + { + serializator.pack_int_array (ext.method.arg_pos, arg.arg_size); + } + } + else + { + serializator.pack_bool (ext.sp.target_class_name != nullptr); + if (ext.sp.target_class_name) + { + serializator.pack_c_string (ext.sp.target_class_name, strlen (ext.sp.target_class_name)); + } + serializator.pack_bool (ext.sp.target_method_name != nullptr); + if (ext.sp.target_method_name) + { + serializator.pack_c_string (ext.sp.target_method_name, strlen (ext.sp.target_method_name)); + } + serializator.pack_oid (ext.sp.code_oid); + } + } + + void + pl_signature::unpack (cubpacking::unpacker &deserializator) + { + deserializator.unpack_int (type); + + cubmem::extensible_block name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; + deserializator.unpack_string_to_memblock (name_blk); + name = name_blk.release_ptr (); + + bool has_auth = false; + deserializator.unpack_bool (has_auth); + if (has_auth) + { + cubmem::extensible_block auth_name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; + deserializator.unpack_string_to_memblock (auth_name_blk); + auth = auth_name_blk.release_ptr (); + } + else + { + auth = nullptr; + } + + deserializator.unpack_int (result_type); + + arg.unpack (deserializator); + + // ext + if (PL_TYPE_IS_METHOD (type)) + { + bool has_cn = false; + deserializator.unpack_bool (has_cn); + if (has_cn) + { + cubmem::extensible_block class_name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; + deserializator.unpack_string_to_memblock (class_name_blk); + ext.method.class_name = class_name_blk.release_ptr (); + } + else + { + ext.method.class_name = nullptr; + } + + if (arg.arg_size > 0) + { + ext.method.arg_pos = (int *) db_private_alloc (NULL, sizeof (int) * arg.arg_size); + int cnt; + deserializator.unpack_int_array (ext.method.arg_pos, cnt); + assert (cnt == arg.arg_size); + } + else + { + ext.method.arg_pos = nullptr; + } + } + else + { + bool has_n = false; + deserializator.unpack_bool (has_n); + if (has_n) + { + cubmem::extensible_block class_name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; + deserializator.unpack_string_to_memblock (class_name_blk); + ext.sp.target_class_name = class_name_blk.release_ptr (); + } + else + { + ext.sp.target_class_name = nullptr; + } + + deserializator.unpack_bool (has_n); + if (has_n) + { + cubmem::extensible_block class_name_blk { cubmem::PRIVATE_BLOCK_ALLOCATOR }; + deserializator.unpack_string_to_memblock (class_name_blk); + ext.sp.target_method_name = class_name_blk.release_ptr (); + } + else + { + ext.sp.target_method_name = nullptr; + } + + deserializator.unpack_oid (ext.sp.code_oid); + } + } + + size_t + pl_signature::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + { + size_t size = serializator.get_packed_int_size (start_offset); /* type */ + + size += serializator.get_packed_c_string_size (name, strlen (name), size); // name + size += serializator.get_packed_bool_size (size); // has auth + if (auth) + { + size += serializator.get_packed_c_string_size (auth, strlen (auth), size); + } + + size += serializator.get_packed_int_size (size); /* result_type */ + + size += arg.get_packed_size (serializator, size); // arg + + if (PL_TYPE_IS_METHOD (type)) + { + size += serializator.get_packed_bool_size (size); // has class_name + if (ext.method.class_name) + { + size += serializator.get_packed_c_string_size (ext.method.class_name, strlen (ext.method.class_name), size); + } + + if (arg.arg_size > 0) + { + size += serializator.get_packed_int_vector_size (size, arg.arg_size); // arg_pos + } + } + else + { + size += serializator.get_packed_bool_size (size); // has target_class_name + if (ext.sp.target_class_name) + { + size += serializator.get_packed_c_string_size (ext.sp.target_class_name, strlen (ext.sp.target_class_name), size); + } + size += serializator.get_packed_bool_size (size); // has target_method_name + if (ext.sp.target_method_name) + { + size += serializator.get_packed_c_string_size (ext.sp.target_method_name, strlen (ext.sp.target_method_name), size); + } + + size += serializator.get_packed_oid_size (size); // code_oid + } + + return size; + } + + bool + pl_signature::has_args () + { + return arg.arg_size > 0; + } + + pl_signature_array::pl_signature_array () + :pl_signature_array (0) + {} + + pl_signature_array::pl_signature_array (int num) + : num_sigs {num} + { +#if defined (SERVER_MODE) + owner = thread_get_thread_entry_info (); +#else + owner = NULL; +#endif + sigs = (num > 0) ? new pl_signature[num] : nullptr; + } + + pl_signature_array::~pl_signature_array () + { + if (sigs) + { + delete [] sigs; + sigs = nullptr; + } + } + + void + pl_signature_array::pack (cubpacking::packer &serializator) const + { + serializator.pack_int (num_sigs); + for (int i = 0; i < num_sigs; i++) + { + sigs[i].pack (serializator); + } + } + + void + pl_signature_array::unpack (cubpacking::unpacker &deserializator) + { + deserializator.unpack_int (num_sigs); + if (num_sigs > 0) + { + sigs = new pl_signature [num_sigs]; + for (int i = 0; i < num_sigs; i++) + { + sigs[i].unpack (deserializator); + } + } + } + + size_t + pl_signature_array::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + { + size_t size = serializator.get_packed_int_size (start_offset); /* num_sigs */ + for (int i = 0; i < num_sigs; i++) + { + size += sigs[i].get_packed_size (serializator, size); + } + return size; + } +} diff --git a/src/sp/pl_signature.hpp b/src/sp/pl_signature.hpp new file mode 100644 index 0000000000..9cb8e7a6b3 --- /dev/null +++ b/src/sp/pl_signature.hpp @@ -0,0 +1,131 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +// +// pl_signature.hpp +// + +#ifndef _PL_SIGNATURE_HPP_ +#define _PL_SIGNATURE_HPP_ + +#include "packable_object.hpp" +#include "thread_compat.hpp" + +enum PL_TYPE +{ + PL_TYPE_NONE = 0, + PL_TYPE_INSTANCE_METHOD, + PL_TYPE_CLASS_METHOD, + PL_TYPE_JAVA_SP, + PL_TYPE_PLCSQL +}; + +enum PL_ARG_DEFAULT +{ + PL_ARG_DEFAULT_NONE = -1, + PL_ARG_DEFAULT_NULL = 0 +}; + +namespace cubpl +{ +#define PL_TYPE_IS_METHOD(type) \ + ((type) == PL_TYPE_INSTANCE_METHOD || (type) == PL_TYPE_CLASS_METHOD) + + struct pl_arg : public cubpacking::packable_object + { + THREAD_ENTRY *owner; + + int arg_size; + int *arg_mode; // array of (IN|OUT|IN/OUT) + int *arg_type; // array of DB_TYPE + + // Only used in runtime + int *arg_default_value_size; + char **arg_default_value; + + void pack (cubpacking::packer &serializator) const override; + void unpack (cubpacking::unpacker &deserializator) override; + size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; + + pl_arg (); + pl_arg (int num_args); + ~pl_arg () override; + + void set_arg_size (int num_args); + void clear (); + }; + + union pl_ext + { + struct pl_sp_info + { + char *target_class_name; + char *target_method_name; + OID code_oid; // PL/CSQL + } sp; + struct pl_method_info + { + char *class_name; + int *arg_pos; + } method; + }; + + struct pl_signature : public cubpacking::packable_object + { + THREAD_ENTRY *owner; + + int type; // PL_TYPE + char *name; + char *auth; + int result_type; // DB_TYPE + + pl_arg arg; + pl_ext ext; + + void pack (cubpacking::packer &serializator) const override; + void unpack (cubpacking::unpacker &deserializator) override; + size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; + + bool has_args (); + + pl_signature (); + ~pl_signature () override; + }; + + struct pl_signature_array : public cubpacking::packable_object + { + THREAD_ENTRY *owner; + + int num_sigs; + pl_signature *sigs; + + void pack (cubpacking::packer &serializator) const override; + void unpack (cubpacking::unpacker &deserializator) override; + size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; + + pl_signature_array (); + pl_signature_array (int num); + ~pl_signature_array () override; + }; +} + +using PL_SIGNATURE_TYPE = cubpl::pl_signature; +using PL_SIGNATURE_ARG_TYPE = cubpl::pl_arg; +using PL_SIGNATURE_ARRAY_TYPE = cubpl::pl_signature_array; + +#endif // _PL_SIGNATURE_HPP_ diff --git a/src/sp/jsp_sr.h b/src/sp/pl_signature_packing_helper.hpp similarity index 55% rename from src/sp/jsp_sr.h rename to src/sp/pl_signature_packing_helper.hpp index afab1c06af..8c3abcf302 100644 --- a/src/sp/jsp_sr.h +++ b/src/sp/pl_signature_packing_helper.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Search Solution Corporation + * * Copyright 2016 CUBRID Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,30 +16,15 @@ * */ +// +// pl_signature_packing_helper.hpp +// -/* - * jsp_sr.h - Java Stored Procedure Server Module Header - * - * Note: - */ - -#ifndef _JSP_SR_H_ -#define _JSP_SR_H_ - -#ident "$Id$" +#ifndef _PL_SIGNATURE_PACKING_HELPER_HPP_ +#define _PL_SIGNATURE_PACKING_HELPER_HPP_ -#if defined(__cplusplus) -extern "C" -{ -#endif +#include "pl_signature.hpp" - extern int jsp_start_server (const char *server_name, const char *path, int port_number); - extern int jsp_server_port (void); - extern int jsp_server_port_from_info (void); - extern int jsp_jvm_is_loaded (void); -#if defined(__cplusplus) -} -#endif -#endif /* _JSP_SR_H_ */ +#endif \ No newline at end of file diff --git a/src/sp/pl_sr.cpp b/src/sp/pl_sr.cpp new file mode 100644 index 0000000000..b567cf5e7e --- /dev/null +++ b/src/sp/pl_sr.cpp @@ -0,0 +1,621 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * pl_sr.cpp - PL Server Module Source + */ + +#include "pl_sr.h" + +#if defined (SERVER_MODE) || defined (SA_MODE) +#include "boot_sr.h" +#endif + +#if !defined(WINDOWS) +#include +#include +#endif + +#include "thread_manager.hpp" +#include "thread_task.hpp" +#if defined (SERVER_MODE) +#include "thread_entry.hpp" +#include "thread_looper.hpp" +#include "thread_daemon.hpp" +#else +#include "dbi.h" +#include "boot.h" +#endif + +#include "dbtype.h" +#include "pl_comm.h" +#include "pl_connection.hpp" +#include "process_util.h" +#include "environment_variable.h" +#include "system_parameter.h" +#include "release_string.h" +#include "memory_alloc.h" +#include "error_manager.h" +#include "method_struct_invoke.hpp" +#include "method_struct_value.hpp" + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" +namespace cubpl +{ +////////////////////////////////////////////////////////////////////////// +// Declarations +////////////////////////////////////////////////////////////////////////// + + class server_monitor_task; + + /********************************************************************* + * server_manager - declaration + *********************************************************************/ + class server_manager final + { + public: + static constexpr std::size_t CONNECTION_POOL_SIZE = 100; + + explicit server_manager (const char *db_name); + + ~server_manager (); + + server_manager (const server_manager ©) = delete; // Not CopyConstructible + server_manager &operator= (const server_manager ©) = delete; // Not CopyAssignable + + server_manager (server_manager &&other) = delete; // Not MoveConstructible + server_manager &operator= (server_manager &&other) = delete; // Not MoveAssignable + + /* + * start () - start the PL server through monitoring task + */ + void start (); + + /* + * wait_for_server_ready() - check if the server is ready to accept connection + */ + void wait_for_server_ready (); + + /* + * get_connection_pool() - get the connection pool + */ + connection_pool *get_connection_pool (); + + private: + + server_monitor_task *m_server_monitor_task; + connection_pool *m_connection_pool; + +#if defined (SERVER_MODE) + cubthread::daemon *m_monitor_helper_daemon = nullptr; +#endif + }; + + /********************************************************************* + * server_monitor_task - declaration + *********************************************************************/ + +#if defined (SERVER_MODE) + class server_monitor_task : public cubthread::entry_task +#else + class server_monitor_task +#endif + { + public: + enum server_monitor_state + { + SERVER_MONITOR_STATE_INIT, + SERVER_MONITOR_STATE_RUNNING, + SERVER_MONITOR_STATE_STOPPED, + SERVER_MONITOR_STATE_HANG, + SERVER_MONITOR_STATE_UNKNOWN + }; + + server_monitor_task (server_manager *manager, const char *db_name); + ~server_monitor_task (); + + server_monitor_task (const server_monitor_task ©) = delete; // Not CopyConstructible + server_monitor_task &operator= (const server_monitor_task ©) = delete; // Not CopyAssignable + + server_monitor_task (server_monitor_task &&other) = delete; // Not MoveConstructible + server_monitor_task &operator= (server_monitor_task &&other) = delete; // Not MoveAssignable + +#if defined (SERVER_MODE) + // called by daemon thread + void execute (context_type &thread_ref) override; +#endif + + // internal main routine + // This function is called by daemon thread (SERVER_MODE) or main thread (SA_MODE) + void do_monitor (); + + // wait until PL server is initialized + void wait_for_ready (); + + private: + void do_initialize (); + + // check functions for PL server state + void do_check_state (bool hang_check); + int do_check_connection (); + + /* + * do_bootstrap_request() - send a bootstrap request to PL server + */ + int do_bootstrap_request (); + + server_manager *m_manager; + + int m_pid; + server_monitor_state m_state; + std::string m_db_name; + std::string m_binary_name; + std::string m_executable_path; + const char *m_argv[3]; + + connection_pool *m_sys_conn_pool; + + std::mutex m_monitor_mutex; + std::condition_variable m_monitor_cv; + }; + + struct pl_ctx_params + { + int param_id; + DB_VALUE param_value; + }; + + struct bootstrap_request : public cubpacking::packable_object + { + std::vector static_params; + + bootstrap_request (SYSPRM_ASSIGN_VALUE *pl_ctx_values); + ~bootstrap_request (); + + void pack (cubpacking::packer &serializator) const override; + void unpack (cubpacking::unpacker &deserializator) override; + size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; + }; + +////////////////////////////////////////////////////////////////////////// +// Definitions +////////////////////////////////////////////////////////////////////////// + + /********************************************************************* + * server_manager - definition + *********************************************************************/ + server_manager::server_manager (const char *db_name) + { + m_server_monitor_task = new server_monitor_task (this, db_name); +#if defined (SERVER_MODE) + m_monitor_helper_daemon = nullptr; +#endif + m_connection_pool = new connection_pool (server_manager::CONNECTION_POOL_SIZE, db_name); + } + + server_manager::~server_manager () + { +#if defined (SERVER_MODE) + if (m_monitor_helper_daemon) + { + cubthread::get_manager ()->destroy_daemon (m_monitor_helper_daemon); + } + + if (m_connection_pool) + { + delete m_connection_pool; + m_connection_pool = nullptr; + } +#endif + } + + void + server_manager::start () + { +#if defined (SERVER_MODE) + cubthread::looper looper = cubthread::looper (std::chrono::milliseconds (1000)); + m_monitor_helper_daemon = cubthread::get_manager ()->create_daemon (looper, m_server_monitor_task, "pl_monitor"); +#else + m_server_monitor_task->do_monitor (); +#endif + } + + void + server_manager::wait_for_server_ready () + { + m_server_monitor_task->wait_for_ready (); + } + + connection_pool * + server_manager::get_connection_pool () + { + return m_connection_pool; + } + + /********************************************************************* + * server_monitor_task - definition + *********************************************************************/ + server_monitor_task::server_monitor_task (server_manager *manager, const char *db_name) + : m_manager (manager) + , m_pid (-1) + , m_state (SERVER_MONITOR_STATE_INIT) + , m_db_name (db_name) + , m_binary_name ("cub_pl") + , m_argv {m_binary_name.c_str (), m_db_name.c_str (), 0} + , m_sys_conn_pool {nullptr} + , m_monitor_mutex {} + , m_monitor_cv {} + { + char executable_path[PATH_MAX]; + (void) envvar_bindir_file (executable_path, PATH_MAX, m_binary_name.c_str ()); + m_executable_path.assign (executable_path, PATH_MAX); + } + + server_monitor_task::~server_monitor_task () + { + // do nothing + } + +#if defined (SERVER_MODE) + void + server_monitor_task::execute (context_type &thread_ref) + { + if (!BO_IS_SERVER_RESTARTED ()) + { + // wait for boot to finish + return; + } + + do_monitor (); + } +#endif + + void + server_monitor_task::do_monitor () + { + (void) do_check_state (false); + + if (m_state == SERVER_MONITOR_STATE_HANG) + { + terminate_process (m_pid); + } + + if (m_state != SERVER_MONITOR_STATE_RUNNING) + { + int status; + int pid = create_child_process (m_executable_path.c_str (), m_argv, 0 /* do not wait */, nullptr, nullptr, nullptr, + &status); + if (pid <= 0) + { + // do nothing + } + else // parent + { + m_pid = pid; + do_initialize (); + } + } + } + + void + server_monitor_task::wait_for_ready () + { + auto pred = [this] () -> bool { return m_state == SERVER_MONITOR_STATE_RUNNING; }; + + std::unique_lock ulock (m_monitor_mutex); + m_monitor_cv.wait (ulock, pred); + } + + void + server_monitor_task::do_initialize () + { + int error = ER_FAILED; + std::lock_guard lock (m_monitor_mutex); + // wait PL server is ready to accept connection (polling) + + constexpr int MAX_FAIL_COUNT = 10; + int fail_count = 0; + while (fail_count < MAX_FAIL_COUNT) + { + error = do_check_connection (); + if (error != NO_ERROR) + { + fail_count++; + (void) sleep (1); + } + else + { + break; + } + } + + if (error == NO_ERROR) + { + error = do_bootstrap_request (); + } + + if (error != NO_ERROR) + { + m_state = SERVER_MONITOR_STATE_UNKNOWN; + terminate_process (m_pid); + } + else + { + // re-initialize connection pool + m_manager->get_connection_pool ()->increment_epoch (); + + // notify server is ready + m_state = SERVER_MONITOR_STATE_RUNNING; + } + + m_monitor_cv.notify_all(); + } + + void + server_monitor_task::do_check_state (bool hang_check) + { + if (m_pid > 0) + { + if (!is_terminated_process (m_pid)) + { + // If process is running but ping command through UDS (TCP) does not respond, then it is considered as hang + if (hang_check && do_check_connection () != NO_ERROR) + { + m_state = SERVER_MONITOR_STATE_HANG; + } + else + { + m_state = SERVER_MONITOR_STATE_RUNNING; + } + } + else + { + m_state = SERVER_MONITOR_STATE_STOPPED; + } + } + } + + int + server_monitor_task::do_check_connection () + { + int error = NO_ERROR; + + if (m_sys_conn_pool == nullptr) + { + m_sys_conn_pool = new connection_pool (5, m_db_name, pl_server_port_from_info (), true); + } + + cubmem::block ping_response; + connection_view cv = m_sys_conn_pool->claim (); + cubmethod::header header (DB_EMPTY_SESSION, SP_CODE_UTIL_PING, 0); + + auto ping = [&] () + { + int error = cv->send_buffer_args (header); + if (error == NO_ERROR) + { + error = cv->receive_buffer (ping_response); + } + return error; + }; + + error = ping (); + if (error != NO_ERROR) + { + // retry + error = ping (); + } + +exit: + if (ping_response.is_valid ()) + { + delete [] ping_response.ptr; + ping_response.ptr = NULL; + ping_response.dim = 0; + } + + cv.reset (); + + return (error); + } + + int + server_monitor_task::do_bootstrap_request () + { + cubmem::block bootstrap_response; + cubmethod::header header (DB_EMPTY_SESSION, SP_CODE_UTIL_BOOTSTRAP, 0); + connection_view cv = m_sys_conn_pool->claim (); + + int error = NO_ERROR; + + SYSPRM_ASSIGN_VALUE *pl_ctx_params_assignments = xsysprm_get_pl_context_parameters (); + bootstrap_request bootstrap_request (pl_ctx_params_assignments); + error = cv->send_buffer_args (header, bootstrap_request); + if (error == NO_ERROR) + { + error = cv->receive_buffer (bootstrap_response); + } + + if (error == NO_ERROR && bootstrap_response.is_valid ()) + { + packing_unpacker deserializator (bootstrap_response); + deserializator.unpack_int (error); + } + + sysprm_free_assign_values (&pl_ctx_params_assignments); + + return error; + } + + /********************************************************************* + * bootstrap_request - definition + *********************************************************************/ + bootstrap_request::bootstrap_request (SYSPRM_ASSIGN_VALUE *pl_ctx_values) + : static_params () + { + int idx = 0; + while (pl_ctx_values != nullptr) + { + PARAM_ID param_id = pl_ctx_values->prm_id; + + pl_ctx_params param_obj; + param_obj.param_id = (int) param_id; + + if (PRM_IS_BOOLEAN (GET_PRM (param_id))) + { + int val = prm_get_bool_value (param_id) ? 1 : 0; + db_make_int (¶m_obj.param_value, val); + } + else if (PRM_IS_STRING (GET_PRM (param_id))) + { + const char *val = prm_get_string_value (param_id); + if (val == NULL) + { + switch (param_id) + { + case PRM_ID_INTL_COLLATION: + val = lang_get_collation_name (LANG_GET_BINARY_COLLATION (LANG_SYS_CODESET)); + break; + case PRM_ID_INTL_DATE_LANG: + case PRM_ID_INTL_NUMBER_LANG: + val = lang_get_Lang_name (); + break; + case PRM_ID_TIMEZONE: + val = prm_get_string_value (PRM_ID_SERVER_TIMEZONE); + break; + default: + /* do nothing */ + break; + } + } + db_make_string (¶m_obj.param_value, val); + } + else + { + // not implemented yet + assert (false); + } + static_params.push_back (param_obj); + + idx++; + pl_ctx_values = pl_ctx_values->next; + } + } + + bootstrap_request::~bootstrap_request () + { + for (pl_ctx_params ¶m : static_params) + { + db_value_clear (¶m.param_value); + } + } + + void + bootstrap_request::pack (cubpacking::packer &serializator) const + { + serializator.pack_int (static_params.size ()); + cubmethod::dbvalue_java sp_val; + for (const pl_ctx_params ¶m : static_params) + { + serializator.pack_int (param.param_id); + sp_val.value = (DB_VALUE *) ¶m.param_value; + sp_val.pack (serializator); + } + } + + void + bootstrap_request::unpack (cubpacking::unpacker &deserializator) + { + // do nothing + } + + size_t + bootstrap_request::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + { + size_t size = serializator.get_packed_int_size (start_offset); // static_params.size () + + cubmethod::dbvalue_java sp_val; + for (const pl_ctx_params ¶m : static_params) + { + size += serializator.get_packed_int_size (size); // param.param_id + sp_val.value = (DB_VALUE *) ¶m.param_value; + size += sp_val.get_packed_size (serializator, size); + } + + return size; + } + +} // namespace cubpl + +////////////////////////////////////////////////////////////////////////// +// High Level API for PL server module +////////////////////////////////////////////////////////////////////////// + +static cubpl::server_manager *pl_server_manager = nullptr; + +void +pl_server_init (const char *db_name) +{ + if (pl_server_manager != nullptr || prm_get_bool_value (PRM_ID_STORED_PROCEDURE) == false) + { + return; + } + +#if defined (SA_MODE) + if (!BOOT_NORMAL_CLIENT_TYPE (db_get_client_type ())) + { + return; + } +#endif + + pl_server_manager = new cubpl::server_manager (db_name); + pl_server_manager->start (); +} + +void +pl_server_destroy () +{ + if (pl_server_manager != nullptr) + { + delete pl_server_manager; + pl_server_manager = nullptr; + } +} + +void +pl_server_wait_for_ready () +{ + if (pl_server_manager) + { + pl_server_manager->wait_for_server_ready (); + } +} + +PL_CONNECTION_POOL *get_connection_pool () +{ + if (pl_server_manager) + { + return pl_server_manager->get_connection_pool (); + } + else + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_RUNNING_JVM, 0); + return nullptr; + } +} diff --git a/src/sp/pl_sr.h b/src/sp/pl_sr.h new file mode 100644 index 0000000000..a2f2153054 --- /dev/null +++ b/src/sp/pl_sr.h @@ -0,0 +1,47 @@ +/* + * Copyright 2008 Search Solution Corporation + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + + +/* + * pl_sr.h - PL Server Module Header + * + * Note: + */ + +#ifndef _PL_SR_H_ +#define _PL_SR_H_ + +#include +#include + +#include "porting.h" +#include "thread_compat.hpp" +#include "pl_connection.hpp" + +extern EXPORT_IMPORT void pl_server_init (const char *db_name); +extern EXPORT_IMPORT void pl_server_destroy (); +extern EXPORT_IMPORT void pl_server_wait_for_ready (); + +extern EXPORT_IMPORT PL_CONNECTION_POOL *get_connection_pool (); + +extern EXPORT_IMPORT int pl_start_jvm_server (const char *server_name, const char *path, int port_number); +extern EXPORT_IMPORT int pl_server_port (void); +extern EXPORT_IMPORT int pl_server_port_from_info (void); +extern EXPORT_IMPORT int pl_jvm_is_loaded (void); + +#endif /* _PL_SR_H_ */ diff --git a/src/sp/jsp_sr.c b/src/sp/pl_sr_jvm.cpp similarity index 68% rename from src/sp/jsp_sr.c rename to src/sp/pl_sr_jvm.cpp index 5082ae703d..4ead4ef03c 100644 --- a/src/sp/jsp_sr.c +++ b/src/sp/pl_sr_jvm.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008 Search Solution Corporation + * * Copyright 2016 CUBRID Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,11 +17,9 @@ */ /* - * jsp_sr.c - Java Stored Procedure Server Module Source + * pl_sr_jvm.cpp - PL Server Module Source related to setup JVM */ -#ident "$Id$" - #include "config.h" #if defined(WINDOWS) @@ -42,9 +40,9 @@ #include #include -#include "jsp_sr.h" -#include "jsp_file.h" -#include "jsp_comm.h" +#include "pl_sr.h" +#include "pl_file.h" +#include "pl_comm.h" #include "boot_sr.h" #include "environment_variable.h" @@ -52,13 +50,11 @@ #include "release_string.h" #include "memory_alloc.h" #include "error_manager.h" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" -#if defined(sparc) -#define JVM_LIB_PATH "jre/lib/sparc/client" -#define JVM_LIB_PATH_JDK11 "lib/server" -#elif defined(WINDOWS) +#if defined(WINDOWS) #if __WORDSIZE == 32 #define JVM_LIB_PATH_JDK "jre\\bin\\client" #define JVM_LIB_PATH_JRE "bin\\client" @@ -68,42 +64,16 @@ #define JVM_LIB_PATH_JRE "bin\\server" #define JVM_LIB_PATH_JDK11 "bin\\server" #endif -#elif defined(HPUX) && defined(IA64) -#define JVM_LIB_PATH "jre/lib/IA64N/hotspot" -#define JVM_LIB_PATH_JDK11 "lib/IA64N/server" -#elif defined(HPUX) && !defined(IA64) -#define JVM_LIB_PATH "jre/lib/PA_RISC2.0/hotspot" -#define JVM_LIB_PATH_JDK11 "lib/PA_RISC2.0/server" -#elif defined(AIX) -#if __WORDSIZE == 32 -#define JVM_LIB_PATH "jre/bin/classic" -#define JVM_LIB_PATH_JDK11 "lib/server" -#elif __WORDSIZE == 64 -#define JVM_LIB_PATH "jre/lib/ppc64/classic" -#define JVM_LIB_PATH_JDK11 "lib/server" -#endif -#elif defined(__i386) || defined(__x86_64) -#if __WORDSIZE == 32 -#define JVM_LIB_PATH "jre/lib/i386/client" -#define JVM_LIB_PATH_JDK11 "lib/server" #else #define JVM_LIB_PATH "jre/lib/amd64/server" #define JVM_LIB_PATH_JDK11 "lib/server" #endif -#else /* ETC */ -#define JVM_LIB_PATH "" -#define JVM_LIB_PATH_JDK11 "" -#endif /* ETC */ -#if !defined(WINDOWS) -#if defined(AIX) -#define JVM_LIB_FILE "libjvm.so" -#elif defined(HPUX) && !defined(IA64) -#define JVM_LIB_FILE "libjvm.sl" -#else /* not AIX , not ( HPUX && (not IA64)) */ +#if defined(WINDOWS) +#define JVM_LIB_FILE "libjvm.dll" +#else #define JVM_LIB_FILE "libjvm.so" -#endif /* not AIX , not ( HPUX && (not IA64)) */ -#endif /* !WINDOWS */ +#endif #if defined(WINDOWS) #define REGKEY_JAVA "Software\\JavaSoft\\Java Runtime Environment" @@ -145,9 +115,7 @@ typedef jint (*CREATE_VM_FUNC) (JavaVM **, void **, void *); static JavaVM *jvm = NULL; static jint sp_port = -1; -// *INDENT-OFF* static std::string err_msgs; -// *INDENT-ON* #if defined(WINDOWS) int get_java_root_path (char *path); @@ -158,9 +126,10 @@ extern PfnDliHook __pfnDliNotifyHook2 = delay_load_hook; extern PfnDliHook __pfnDliFailureHook2 = delay_load_hook; #else /* WINDOWS */ -static void *jsp_get_create_java_vm_function_ptr (void); +static void *pl_get_create_java_vm_function_ptr (void); #endif /* !WINDOWS */ + #if defined(WINDOWS) /* @@ -249,86 +218,86 @@ delay_load_hook (unsigned dliNotify, PDelayLoadInfo pdli) switch (dliNotify) { case dliFailLoadLib: - { - char *java_home = NULL, *jvm_path = NULL, *tmp = NULL, *tail; - void *libVM = NULL; + { + char *java_home = NULL, *jvm_path = NULL, *tmp = NULL, *tail; + void *libVM = NULL; - jvm_path = getenv ("JVM_PATH"); - java_home = getenv ("JAVA_HOME"); + jvm_path = getenv ("JVM_PATH"); + java_home = getenv ("JAVA_HOME"); - if (jvm_path) - { - err_msgs.append ("\n\tFailed to load libjvm from 'JVM_PATH' environment variable: "); - err_msgs.append ("\n\t\t"); - err_msgs.append (jvm_path); - - libVM = LoadLibrary (jvm_path); - if (libVM) - { - fp = (FARPROC) (HMODULE) libVM; - return fp; - } - } - else - { - err_msgs.append ("\n\tFailed to get 'JVM_PATH' environment variable"); - } + if (jvm_path) + { + err_msgs.append ("\n\tFailed to load libjvm from 'JVM_PATH' environment variable: "); + err_msgs.append ("\n\t\t"); + err_msgs.append (jvm_path); + + libVM = LoadLibrary (jvm_path); + if (libVM) + { + fp = (FARPROC) (HMODULE) libVM; + return fp; + } + } + else + { + err_msgs.append ("\n\tFailed to get 'JVM_PATH' environment variable"); + } - tail = JVM_LIB_PATH_JDK; - if (java_home == NULL) - { - tmp = (char *) malloc (BUF_SIZE); - if (tmp) - { - if (get_java_root_path (tmp)) - { - java_home = tmp; - tail = JVM_LIB_PATH_JRE; - } - } - } + tail = JVM_LIB_PATH_JDK; + if (java_home == NULL) + { + tmp = (char *) malloc (BUF_SIZE); + if (tmp) + { + if (get_java_root_path (tmp)) + { + java_home = tmp; + tail = JVM_LIB_PATH_JRE; + } + } + } - if (java_home) - { - err_msgs.append ("\n\tFailed to load libjvm from 'JAVA_HOME' environment variable: "); + if (java_home) + { + err_msgs.append ("\n\tFailed to load libjvm from 'JAVA_HOME' environment variable: "); - char jvm_lib_path[BUF_SIZE]; - sprintf (jvm_lib_path, "%s\\%s\\jvm.dll", java_home, tail); + char jvm_lib_path[BUF_SIZE]; + sprintf (jvm_lib_path, "%s\\%s\\jvm.dll", java_home, tail); - err_msgs.append ("\n\t\t"); - err_msgs.append (jvm_lib_path); + err_msgs.append ("\n\t\t"); + err_msgs.append (jvm_lib_path); - libVM = LoadLibrary (jvm_lib_path); + libVM = LoadLibrary (jvm_lib_path); - if (libVM) - { - fp = (FARPROC) (HMODULE) libVM; - } - else - { - tail = JVM_LIB_PATH_JDK11; + if (libVM) + { + fp = (FARPROC) (HMODULE) libVM; + } + else + { + tail = JVM_LIB_PATH_JDK11; - memset (jvm_lib_path, BUF_SIZE, 0); - sprintf (jvm_lib_path, "%s\\%s\\jvm.dll", java_home, tail); + memset (jvm_lib_path, BUF_SIZE, 0); + sprintf (jvm_lib_path, "%s\\%s\\jvm.dll", java_home, tail); - err_msgs.append ("\n\t\t"); - err_msgs.append (jvm_lib_path); + err_msgs.append ("\n\t\t"); + err_msgs.append (jvm_lib_path); - libVM = LoadLibrary (jvm_lib_path); - fp = (FARPROC) (HMODULE) libVM; - } - } - else - { - err_msgs.append ("\n\tFailed to get 'JAVA_HOME' environment variable"); - } + libVM = LoadLibrary (jvm_lib_path); + fp = (FARPROC) (HMODULE) libVM; + } + } + else + { + err_msgs.append ("\n\tFailed to get 'JAVA_HOME' environment variable"); + } - if (tmp) - { - free_and_init (tmp); - } - } - break; + if (tmp) + { + free_and_init (tmp); + } + } + break; default: break; @@ -365,14 +334,14 @@ delay_load_dll_exception_filter (PEXCEPTION_POINTERS pep) #else /* WINDOWS */ /* - * jsp_get_create_java_vm_func_ptr + * pl_get_create_java_vm_func_ptr * return: return java vm function pointer * * Note: */ static void * -jsp_get_create_java_vm_function_ptr () +pl_get_create_java_vm_function_ptr () { void *libVM_p = NULL; @@ -440,26 +409,26 @@ jsp_get_create_java_vm_function_ptr () /* - * jsp_create_java_vm + * pl_create_java_vm * return: create java vm * * Note: */ static int -jsp_create_java_vm (JNIEnv ** env_p, JavaVMInitArgs * vm_arguments) +pl_create_java_vm (JNIEnv **env_p, JavaVMInitArgs *vm_arguments) { int res; #if defined(WINDOWS) __try - { - res = JNI_CreateJavaVM (&jvm, (void **) env_p, vm_arguments); - } + { + res = JNI_CreateJavaVM (&jvm, (void **) env_p, vm_arguments); + } __except (delay_load_dll_exception_filter (GetExceptionInformation ())) - { - res = -1; - } + { + res = -1; + } #else /* WINDOWS */ - CREATE_VM_FUNC create_vm_func = (CREATE_VM_FUNC) jsp_get_create_java_vm_function_ptr (); + CREATE_VM_FUNC create_vm_func = (CREATE_VM_FUNC) pl_get_create_java_vm_function_ptr (); if (create_vm_func) { res = (*create_vm_func) (&jvm, (void **) env_p, (void *) vm_arguments); @@ -475,14 +444,12 @@ jsp_create_java_vm (JNIEnv ** env_p, JavaVMInitArgs * vm_arguments) } /* - * jsp_tokenize_jvm_options + * pl_tokenize_jvm_options * return: tokenized array of string * */ - -// *INDENT-OFF* static std::vector -jsp_tokenize_jvm_options (char *opt_str) +pl_tokenize_jvm_options (char *opt_str) { std::string str (opt_str); std::istringstream iss (str); @@ -491,10 +458,58 @@ jsp_tokenize_jvm_options (char *opt_str) std::istream_iterator (), std::back_inserter (options)); return options; } -// *INDENT-ON* /* - * jsp_start_server - + * pl_jvm_options + * return: jvm options + * + */ +static std::vector +pl_jvm_options () +{ + char buffer[PATH_MAX]; + + envvar_javadir_file (buffer, PATH_MAX, ""); + std::string pl_file_path (buffer); + + std::vector options; + +#ifndef NDEBUG + // enable assertions in PL Server + options.push_back ("-ea"); // must be the first option in order not to override ones specified by the user +#endif // !NDEBUG + + // defaults + options.push_back ("-Djava.awt.headless=true"); + options.push_back ("-Dfile.encoding=UTF-8"); + + // CBRD-25364: Prevent JVM crash caused by libzip + // Added the following option as a default until the minimum JDK version is upgraded + options.push_back ("-Dsun.zip.disableMemoryMapping=true"); + + // + options.push_back ("-Djava.class.path=" + pl_file_path + "pl_server.jar"); + options.push_back ("-Djava.util.logging.config.file=" + pl_file_path + "logging.properties"); + + int debug_port = prm_get_integer_value (PRM_ID_JAVA_STORED_PROCEDURE_DEBUG); + if (debug_port != -1) + { + options.push_back ("-Xdebug"); + options.push_back ("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=" + std::to_string (debug_port)); + } + + char *jvm_opt_sysprm = (char *) prm_get_string_value (PRM_ID_JAVA_STORED_PROCEDURE_JVM_OPTIONS); + if (jvm_opt_sysprm != NULL) + { + std::vector ext_opts = pl_tokenize_jvm_options (jvm_opt_sysprm); + options.insert (options.end(), ext_opts.begin(), ext_opts.end()); + } + + return options; +} + +/* + * pl_start_jvm_server - * return: Error Code * db_name(in): db name * path(in): path @@ -503,7 +518,7 @@ jsp_tokenize_jvm_options (char *opt_str) */ int -jsp_start_server (const char *db_name, const char *path, int port) +pl_start_jvm_server (const char *db_name, const char *path, int port) { jint res; jclass cls, string_cls; @@ -513,21 +528,11 @@ jsp_start_server (const char *db_name, const char *path, int port) jobjectArray args; JavaVMInitArgs vm_arguments; JavaVMOption *options; - int vm_n_default_options = 2; - int vm_n_ext_options = 0; - char classpath[PATH_MAX + 32] = { 0 }; - char logging_prop[PATH_MAX + 32] = { 0 }; - char option_debug[70]; - char debug_flag[] = "-Xdebug"; - char debug_jdwp[] = "-agentlib:jdwp=transport=dt_socket,server=y,address=%d,suspend=n"; + int vm_n_options = 0; const char *envroot; const char *uds_path; - char jsp_file_path[PATH_MAX]; - char port_str[6] = { 0 }; char *loc_p, *locale; - char *jvm_opt_sysprm = NULL; - int debug_port = -1; - const bool is_uds_mode = (port == JAVASP_PORT_UDS_MODE); + const bool is_uds_mode = (port == PL_PORT_UDS_MODE); { if (jvm != NULL) { @@ -535,63 +540,26 @@ jsp_start_server (const char *db_name, const char *path, int port) } envroot = envvar_root (); + uds_path = (is_uds_mode) ? pl_get_socket_file_path (db_name) : ""; - if (is_uds_mode) - { - uds_path = jsp_get_socket_file_path (db_name); - } - else - { - uds_path = ""; - } - - snprintf (classpath, sizeof (classpath) - 1, "-Djava.class.path=%s", - envvar_javadir_file (jsp_file_path, PATH_MAX, "pl_server.jar")); - - snprintf (logging_prop, sizeof (logging_prop) - 1, "-Djava.util.logging.config.file=%s", - envvar_javadir_file (jsp_file_path, PATH_MAX, "logging.properties")); - - debug_port = prm_get_integer_value (PRM_ID_JAVA_STORED_PROCEDURE_DEBUG); - if (debug_port != -1) - { - vm_n_default_options += 2; /* set debug flag and debugging port */ - } + std::vector opts = pl_jvm_options (); - jvm_opt_sysprm = (char *) prm_get_string_value (PRM_ID_JAVA_STORED_PROCEDURE_JVM_OPTIONS); - // *INDENT-OFF* - std::vector opts = jsp_tokenize_jvm_options (jvm_opt_sysprm); -#ifndef NDEBUG - // enable assertions in PL Server - opts.insert(opts.begin(), "-ea"); // must be the first option in order not to override ones specified by the user -#endif // !NDEBUG - // *INDENT-ON* - vm_n_ext_options += (int) opts.size (); - options = new JavaVMOption[vm_n_default_options + vm_n_ext_options]; + vm_n_options = (int) opts.size (); + options = new JavaVMOption[vm_n_options]; if (options == NULL) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 0); goto exit; } - int ext_idx = vm_n_default_options; - options[0].optionString = classpath; - options[1].optionString = logging_prop; - if (debug_port != -1) - { - snprintf (option_debug, sizeof (option_debug) - 1, debug_jdwp, debug_port); - options[2].optionString = debug_flag; - options[3].optionString = option_debug; - } - + int idx = 0; for (auto it = opts.begin (); it != opts.end (); ++it) { - // *INDENT-OFF* - options[ext_idx++].optionString = const_cast (it->c_str ()); - // *INDENT-ON* + options[idx++].optionString = const_cast (it->c_str ()); } vm_arguments.version = JNI_VERSION_1_6; - vm_arguments.nOptions = vm_n_default_options + vm_n_ext_options; + vm_arguments.nOptions = vm_n_options; vm_arguments.options = options; vm_arguments.ignoreUnrecognized = JNI_TRUE; @@ -602,10 +570,8 @@ jsp_start_server (const char *db_name, const char *path, int port) locale = strdup (loc_p); } - res = jsp_create_java_vm (&env_p, &vm_arguments); - // *INDENT-OFF* - delete[] options; - // *INDENT-ON* + res = pl_create_java_vm (&env_p, &vm_arguments); + delete[] options; #if !defined(WINDOWS) if (er_has_error ()) @@ -685,6 +651,7 @@ jsp_start_server (const char *db_name, const char *path, int port) goto exit; } + char port_str[6] = { 0 }; sprintf (port_str, "%d", port); jstr_port = JVM_NewStringUTF (env_p, port_str); if (jstr_port == NULL) @@ -737,8 +704,8 @@ jsp_start_server (const char *db_name, const char *path, int port) } /* - * jsp_server_port - * return: if jsp is disabled return -2 (JAVASP_PORT_DISABLED) + * pl_server_port + * return: if jsp is disabled return -2 (PL_PORT_DISABLED) * else if jsp is UDS mode return -1 * else return a port (TCP mode) * @@ -746,38 +713,38 @@ jsp_start_server (const char *db_name, const char *path, int port) */ int -jsp_server_port (void) +pl_server_port (void) { return sp_port; } /* - * jsp_server_port_from_info - * return: if jsp is disabled return -2 (JAVASP_PORT_DISABLED) + * pl_server_port_from_info + * return: if jsp is disabled return -2 (PL_PORT_DISABLED) * else if jsp is UDS mode return -1 * else return a port (TCP mode) - * + * * * Note: */ int -jsp_server_port_from_info (void) +pl_server_port_from_info (void) { -#if defined (SA_MODE) - return sp_port; -#else - // check $CUBRID/var/javasp_.info -// *INDENT-OFF* - JAVASP_SERVER_INFO jsp_info {-1, -1}; -// *INDENT-ON* - javasp_read_info (boot_db_name (), jsp_info); - return sp_port = jsp_info.port; +#if defined (SERVER_MODE) + // check $CUBRID/var/pl_.info + if (sp_port != PL_PORT_DISABLED) + { + PL_SERVER_INFO pl_info {-1, -1}; + pl_read_info (boot_db_name (), pl_info); + sp_port = pl_info.port; + } #endif + return sp_port; } /* - * jsp_jvm_is_loaded + * pl_jvm_is_loaded * return: if disable jsp function and return false * enable jsp function and return not false * @@ -785,7 +752,7 @@ jsp_server_port_from_info (void) */ int -jsp_jvm_is_loaded (void) +pl_jvm_is_loaded (void) { return jvm != NULL; } diff --git a/src/method/method_compile_def.cpp b/src/sp/pl_struct_compile.cpp similarity index 90% rename from src/method/method_compile_def.cpp rename to src/sp/pl_struct_compile.cpp index 66c0cd0572..d6f6ecdb5e 100644 --- a/src/method/method_compile_def.cpp +++ b/src/sp/pl_struct_compile.cpp @@ -16,22 +16,57 @@ * */ -#include "method_compile_def.hpp" +#include "pl_struct_compile.hpp" #include "byte_order.h" #include "connection_support.h" #include "dbtype.h" /* db_value_* */ -#include "method_def.hpp" + #include "method_struct_value.hpp" +#include "sp_constants.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" -namespace cubmethod +namespace cubpl { ////////////////////////////////////////////////////////////////////////// // compile info ////////////////////////////////////////////////////////////////////////// - compile_info::compile_info () + +#define COMPILE_REQUEST_PACKER_ARGS() \ + code, owner, mode + + compile_request::compile_request () + : code {} + , owner {} + , mode {} + { + // + } + + void + compile_request::pack (cubpacking::packer &serializator) const + { + serializator.pack_all (COMPILE_REQUEST_PACKER_ARGS ()); + } + + size_t + compile_request::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + { + return serializator.get_all_packed_size_starting_offset (start_offset, + COMPILE_REQUEST_PACKER_ARGS ()); + } + + void + compile_request::unpack (cubpacking::unpacker &deserializator) + { + deserializator.unpack_all (COMPILE_REQUEST_PACKER_ARGS ()); + } + +// + + compile_response::compile_response () : err_code (-1) , err_line (0) , err_column (0) @@ -40,7 +75,7 @@ namespace cubmethod } void - compile_info::pack (cubpacking::packer &serializator) const + compile_response::pack (cubpacking::packer &serializator) const { serializator.pack_int (err_code); if (err_code < 0) @@ -55,11 +90,17 @@ namespace cubmethod serializator.pack_string (register_stmt); serializator.pack_string (class_name); serializator.pack_string (java_signature); + + serializator.pack_int (compiled_type); + if (compiled_type >= 0) + { + serializator.pack_string (compiled_code); + } } } size_t - compile_info::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const + compile_response::get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const { size_t size = serializator.get_packed_int_size (start_offset); // err_code @@ -75,13 +116,19 @@ namespace cubmethod size += serializator.get_packed_string_size (register_stmt, size); // register_stmt size += serializator.get_packed_string_size (class_name, size); // class_name size += serializator.get_packed_string_size (java_signature, size); // java_signature + + size += serializator.get_packed_int_size (size); // compiled_type + if (compiled_type >= 0) + { + size += serializator.get_packed_string_size (compiled_code, size); // compiled_code + } } return size; } void - compile_info::unpack (cubpacking::unpacker &deserializator) + compile_response::unpack (cubpacking::unpacker &deserializator) { deserializator.unpack_int (err_code); if (err_code < 0) @@ -96,6 +143,12 @@ namespace cubmethod deserializator.unpack_string (register_stmt); deserializator.unpack_string (class_name); deserializator.unpack_string (java_signature); + + deserializator.unpack_int (compiled_type); + if (compiled_type >= 0) + { + deserializator.unpack_string (compiled_code); + } } } @@ -322,7 +375,7 @@ namespace cubmethod if (!DB_IS_NULL (&value)) { - dbvalue_java sp_val; + cubmethod::dbvalue_java sp_val; serializator.pack_int (1); sp_val.value = (DB_VALUE *) &value; sp_val.pack (serializator); @@ -348,7 +401,7 @@ namespace cubmethod size += serializator.get_packed_int_size (size); // value is null if (!DB_IS_NULL (&value)) { - dbvalue_java sp_val; + cubmethod::dbvalue_java sp_val; sp_val.value = (DB_VALUE *) &value; size += sp_val.get_packed_size (serializator, size); } @@ -373,7 +426,7 @@ namespace cubmethod if (value_is_null == 1) { - dbvalue_java value_unpacker; + cubmethod::dbvalue_java value_unpacker; value_unpacker.value = &value; value_unpacker.unpack (deserializator); } diff --git a/src/method/method_compile_def.hpp b/src/sp/pl_struct_compile.hpp similarity index 85% rename from src/method/method_compile_def.hpp rename to src/sp/pl_struct_compile.hpp index a5703364f1..3d3d0b36ab 100644 --- a/src/method/method_compile_def.hpp +++ b/src/sp/pl_struct_compile.hpp @@ -17,11 +17,11 @@ */ // -// method_compile_def.hpp - define structures used by method feature +// pl_struct_compile.hpp - define structures used by method feature // -#ifndef _METHOD_COMPILE_DEF_HPP_ -#define _METHOD_COMPILE_DEF_HPP_ +#ifndef _PL_STRUCT_COMPILE_HPP_ +#define _PL_STRUCT_COMPILE_HPP_ #include "mem_block.hpp" #include "packer.hpp" @@ -33,13 +33,26 @@ #include #include -namespace cubmethod +namespace cubpl { struct pl_parameter_info; - struct EXPORT_IMPORT compile_info : public cubpacking::packable_object + struct EXPORT_IMPORT compile_request : public cubpacking::packable_object { - compile_info (); + compile_request (); + + std::string code; + std::string owner; + std::string mode; /* for debugging : compile configs such as verbose */ + + void pack (cubpacking::packer &serializator) const override; + void unpack (cubpacking::unpacker &deserializator) override; + size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; + }; + + struct EXPORT_IMPORT compile_response : public cubpacking::packable_object + { + compile_response (); void pack (cubpacking::packer &serializator) const override; void unpack (cubpacking::unpacker &deserializator) override; @@ -54,6 +67,9 @@ namespace cubmethod std::string register_stmt; std::string class_name; std::string java_signature; + + int compiled_type; + std::string compiled_code; }; struct EXPORT_IMPORT sql_semantics : public cubpacking::packable_object @@ -68,7 +84,7 @@ namespace cubmethod int sql_type; std::string rewritten_query; - std::vector columns; + std::vector columns; std::vector hvs; std::vector into_vars; }; @@ -180,7 +196,7 @@ namespace cubmethod void unpack (cubpacking::unpacker &deserializator) override; size_t get_packed_size (cubpacking::packer &serializator, std::size_t start_offset) const override; - column_info c_info; + cubmethod::column_info c_info; }; struct EXPORT_IMPORT global_semantics_response : public cubpacking::packable_object @@ -193,6 +209,7 @@ namespace cubmethod }; } -using PLCSQL_COMPILE_INFO = cubmethod::compile_info; +using PLCSQL_COMPILE_REQUEST = cubpl::compile_request; +using PLCSQL_COMPILE_RESPONSE = cubpl::compile_response; -#endif //_METHOD_COMPILE_DEF_HPP_ +#endif //_PL_STRUCT_COMPILE_HPP_ diff --git a/src/sp/sp_catalog.cpp b/src/sp/sp_catalog.cpp new file mode 100644 index 0000000000..4caaad9537 --- /dev/null +++ b/src/sp/sp_catalog.cpp @@ -0,0 +1,1023 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +/* + * sp_catalog.cpp - Implement stored procedure related system catalog's row sturcture and initializer +*/ + +#include "sp_catalog.hpp" + +#include + +#include "jsp_cl.h" +#include "authenticate.h" +#include "object_domain.h" +#include "object_primitive.h" +#include "object_representation.h" +#include "db.h" +#include "object_accessor.h" +#include "set_object.h" +#include "locator_cl.h" +#include "transaction_cl.h" +#include "schema_manager.h" +#include "dbtype.h" + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +// memory representation of built-in stored procedures +static std::vector sp_builtin_definition; + +static const std::vector sp_entry_names +{ + SP_ATTR_UNIQUE_NAME, + SP_ATTR_NAME, + SP_ATTR_SP_TYPE, + SP_ATTR_RETURN_TYPE, + SP_ATTR_ARG_COUNT, + SP_ATTR_ARGS, + SP_ATTR_LANG, + SP_ATTR_PKG, + SP_ATTR_IS_SYSTEM_GENERATED, + SP_ATTR_TARGET_CLASS, + SP_ATTR_TARGET_METHOD, + SP_ATTR_DIRECTIVE, + SP_ATTR_OWNER, + SP_ATTR_COMMENT +}; + +static const std::vector sp_args_entry_names +{ + SP_ATTR_SP_OF, + SP_ATTR_PKG, + SP_ATTR_INDEX_OF_NAME, + SP_ATTR_IS_SYSTEM_GENERATED, + SP_ATTR_ARG_NAME, + SP_ATTR_DATA_TYPE, + SP_ATTR_MODE, + SP_ATTR_DEFAULT_VALUE, + SP_ATTR_IS_OPTIONAL, + SP_ATTR_COMMENT +}; + +static int sp_add_stored_procedure_internal (SP_INFO &info, bool has_savepoint); +static int sp_builtin_init (); + +// TODO +static int sp_builtin_init () +{ + if (sp_builtin_definition.size () > 0) + { + // already initialized + return 0; + } + + sp_info v; + sp_arg_info a; + + // common + v.is_system_generated = true; + v.lang = SP_LANG_PLCSQL; + v.owner = Au_public_user; + v.comment = ""; + v.directive = SP_DIRECTIVE_RIGHTS_OWNER; + v.target_class = "com.cubrid.plcsql.builtin.DBMS_OUTPUT"; + + a.is_system_generated = true; + + // DBMS_OUTPUT.enable + v.unique_name = "public.dbms_output.enable"; + v.sp_name = "enable"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "enable(int)"; + + // arg(0) of enable + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 0; + a.arg_name = "s"; + a.data_type = DB_TYPE_INTEGER; + a.mode = SP_MODE_IN; + a.comment = ""; + + v.args.push_back (a); + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + // DBMS_OUTPUT.disable + v.unique_name = "public.dbms_output.disable"; + v.sp_name = "disable"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "disable()"; + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + // DBMS_OUTPUT.put + v.unique_name = "public.dbms_output.put"; + v.sp_name = "put"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "put(java.lang.String)"; + + // arg(0) of put + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 0; + a.arg_name = "str"; + a.data_type = DB_TYPE_STRING; + a.mode = SP_MODE_IN; + a.comment = ""; + + v.args.push_back (a); + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + // DBMS_OUTPUT.put_line + v.unique_name = "public.dbms_output.put_line"; + v.sp_name = "put_line"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "putLine(java.lang.String)"; + + // arg(0) of put_line + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 0; + a.arg_name = "str"; + a.data_type = DB_TYPE_STRING; + a.mode = SP_MODE_IN; + a.comment = ""; + + v.args.push_back (a); + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + // DBMS_OUTPUT.new_line + v.unique_name = "public.dbms_output.new_line"; + v.sp_name = "new_line"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "newLine()"; + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + // DBMS_OUTPUT.get_line + v.unique_name = "public.dbms_output.get_line"; + v.sp_name = "get_line"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "getLine(java.lang.String[], int[])"; + + // arg(0) of get_line + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 0; + a.arg_name = "line"; + a.data_type = DB_TYPE_STRING; + a.mode = SP_MODE_OUT; + a.comment = ""; + + v.args.push_back (a); + + // arg(1) of get_line + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 1; + a.arg_name = "status"; + a.data_type = DB_TYPE_INTEGER; + a.mode = SP_MODE_OUT; + a.comment = ""; + + v.args.push_back (a); + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + // DBMS_OUTPUT.get_lines + v.unique_name = "public.dbms_output.get_lines"; + v.sp_name = "get_lines"; + v.pkg_name = "DBMS_OUTPUT"; + v.sp_type = SP_TYPE_PROCEDURE; + v.return_type = DB_TYPE_NULL; + v.target_method = "getLines(java.lang.String[], int[])"; + + // arg(0) of get_lines + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 0; + a.arg_name = "lines"; + a.data_type = DB_TYPE_STRING; + a.mode = SP_MODE_OUT; + a.comment = ""; + + v.args.push_back (a); + + // arg(1) of get_line + a.sp_name = v.sp_name; + a.pkg_name = "DBMS_OUTPUT"; + a.index_of = 1; + a.arg_name = "cnt"; + a.data_type = DB_TYPE_INTEGER; + a.mode = SP_MODE_OUT; + a.comment = ""; + + v.args.push_back (a); + + // + sp_builtin_definition.push_back (v); + v.args.clear (); + // + + return sp_builtin_definition.size (); +} + +sp_entry::sp_entry (int size) +{ + vals.resize (size); + for (DB_VALUE &val : vals) + { + db_make_null (&val); + } +} + +sp_entry::~sp_entry () +{ + for (DB_VALUE &val : vals) + { + db_value_clear (&val); + } +} + +int sp_builtin_install () +{ + (void) sp_builtin_init (); + + int error = NO_ERROR; + for (sp_info &info : sp_builtin_definition) + { + error = sp_add_stored_procedure_internal (info, false); + assert (error == NO_ERROR); + } + return error; +} + +int +sp_check_param_type_supported (DB_TYPE domain_type, SP_MODE_ENUM mode) +{ + switch (domain_type) + { + case DB_TYPE_INTEGER: + case DB_TYPE_FLOAT: + case DB_TYPE_DOUBLE: + case DB_TYPE_STRING: + case DB_TYPE_OBJECT: + case DB_TYPE_SET: + case DB_TYPE_MULTISET: + case DB_TYPE_SEQUENCE: + case DB_TYPE_TIME: + case DB_TYPE_TIMESTAMP: + case DB_TYPE_DATE: + case DB_TYPE_MONETARY: + case DB_TYPE_SHORT: + case DB_TYPE_NUMERIC: + case DB_TYPE_CHAR: + case DB_TYPE_BIGINT: + case DB_TYPE_DATETIME: + return NO_ERROR; + break; + + case DB_TYPE_RESULTSET: + if (mode != SP_MODE_OUT) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_CANNOT_INPUT_RESULTSET, 0); + } + break; + + default: + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SP_NOT_SUPPORTED_ARG_TYPE, 1, pr_type_name (domain_type)); + break; + } + + return er_errid (); +} + +int +sp_add_stored_procedure (SP_INFO &info) +{ + return sp_add_stored_procedure_internal (info, true); +} + +static int +sp_add_stored_procedure_internal (SP_INFO &info, bool has_savepoint) +{ + DB_OBJECT *classobj_p, *object_p, *sp_args_obj; + DB_OTMPL *obt_p = NULL; + DB_VALUE value; + DB_SET *param = NULL; + MOP *mop_list = NULL; + int save, err; + + AU_DISABLE (save); + + { + classobj_p = db_find_class (SP_CLASS_NAME); + if (classobj_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + if (has_savepoint) + { + err = tran_system_savepoint (SAVEPOINT_ADD_STORED_PROC); + if (err != NO_ERROR) + { + has_savepoint = false; + goto error; + } + } + + obt_p = dbt_create_object_internal (classobj_p); + if (!obt_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + /* unique_name */ + db_make_string (&value, info.unique_name.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_UNIQUE_NAME, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + /* sp_name */ + db_make_string (&value, info.sp_name.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_NAME, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.sp_type); + err = dbt_put_internal (obt_p, SP_ATTR_SP_TYPE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + err = jsp_check_return_type_supported (info.return_type); + if (err == ER_SP_CANNOT_RETURN_RESULTSET) + { + // ignore this error here + err = NO_ERROR; + er_clear (); + } + else if (err != NO_ERROR) + { + err = er_errid (); + goto error; + } + + db_make_int (&value, (int) info.return_type); + err = dbt_put_internal (obt_p, SP_ATTR_RETURN_TYPE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + if (!info.pkg_name.empty ()) + { + sp_normalize_name (info.pkg_name); + db_make_string (&value, info.pkg_name.data ()); + } + err = dbt_put_internal (obt_p, SP_ATTR_PKG, &value); + pr_clear_value (&value); + + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.is_system_generated ? 1 : 0); + err = dbt_put_internal (obt_p, SP_ATTR_IS_SYSTEM_GENERATED, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.directive); + err = dbt_put_internal (obt_p, SP_ATTR_DIRECTIVE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + // args (_db_stored_procedure_args) begin + param = set_create_sequence (0); + if (param == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + mop_list = (MOP *) malloc (info.args.size() * sizeof (MOP)); + + int i = 0; + for (sp_arg_info &arg: info.args) + { + DB_VALUE v; + + err = sp_check_param_type_supported (arg.data_type, arg.mode); + if (err != NO_ERROR) + { + goto error; + } + + arg.sp_name = info.sp_name; + arg.pkg_name = info.pkg_name; + + err = sp_add_stored_procedure_argument (&mop_list[i], arg); + if (err != NO_ERROR) + { + goto error; + } + + db_make_object (&v, mop_list[i]); + err = set_put_element (param, i++, &v); + pr_clear_value (&v); + + if (err != NO_ERROR) + { + goto error; + } + } + db_make_sequence (&value, param); + err = dbt_put_internal (obt_p, SP_ATTR_ARGS, &value); + pr_clear_value (&value); + param = NULL; + if (err != NO_ERROR) + { + goto error; + } + // args (_db_stored_procedure_args) end + + db_make_int (&value, (int) info.args.size ()); + err = dbt_put_internal (obt_p, SP_ATTR_ARG_COUNT, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.lang); + err = dbt_put_internal (obt_p, SP_ATTR_LANG, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_string (&value, info.target_class.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_TARGET_CLASS, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_string (&value, info.target_method.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_TARGET_METHOD, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_object (&value, info.owner); + err = dbt_put_internal (obt_p, SP_ATTR_OWNER, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + if (!info.comment.empty ()) + { + db_make_string (&value, info.comment.data ()); + } + err = dbt_put_internal (obt_p, SP_ATTR_COMMENT, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + object_p = dbt_finish_object (obt_p); + if (!object_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + obt_p = NULL; + + err = locator_flush_instance (object_p); + if (err != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + obj_delete (object_p); + goto error; + } + + // args (_db_stored_procedure_args) sp_of oid begin + for (i--; i >= 0; i--) + { + obt_p = dbt_edit_object (mop_list[i]); + if (!obt_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + db_make_object (&value, object_p); + err = dbt_put_internal (obt_p, SP_ATTR_SP_OF, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + sp_args_obj = dbt_finish_object (obt_p); + if (!sp_args_obj) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + obt_p = NULL; + + err = locator_flush_instance (sp_args_obj); + if (err != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + obj_delete (sp_args_obj); + goto error; + } + } + free (mop_list); + // args (_db_stored_procedure_args) sp_of oid end + } + + AU_ENABLE (save); + return NO_ERROR; + +error: + if (param) + { + set_free (param); + } + + if (obt_p) + { + dbt_abort_object (obt_p); + } + + if (has_savepoint) + { + tran_abort_upto_system_savepoint (SAVEPOINT_ADD_STORED_PROC); + } + + AU_ENABLE (save); + + return (er_errid () != NO_ERROR) ? er_errid () : ER_FAILED; +} + +int +sp_add_stored_procedure_argument (MOP *mop_p, SP_ARG_INFO &info) +{ + DB_OBJECT *classobj_p, *object_p; + DB_OTMPL *obt_p = NULL; + DB_VALUE value; + int save; + int err; + + db_make_null (&value); + AU_DISABLE (save); + + classobj_p = db_find_class (SP_ARG_CLASS_NAME); + if (classobj_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + obt_p = dbt_create_object_internal (classobj_p); + if (obt_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + if (!info.pkg_name.empty ()) + { + db_make_string (&value, info.pkg_name.data ()); + } + err = dbt_put_internal (obt_p, SP_ATTR_PKG, &value); + pr_clear_value (&value); + + if (err != NO_ERROR) + { + goto error; + } + + db_make_string (&value, info.arg_name.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_ARG_NAME, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.index_of); + err = dbt_put_internal (obt_p, SP_ATTR_INDEX_OF_NAME, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.is_system_generated ? 1 : 0); + err = dbt_put_internal (obt_p, SP_ATTR_IS_SYSTEM_GENERATED, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.data_type); + err = dbt_put_internal (obt_p, SP_ATTR_DATA_TYPE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.mode); + err = dbt_put_internal (obt_p, SP_ATTR_MODE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.is_optional); + err = dbt_put_internal (obt_p, SP_ATTR_IS_OPTIONAL, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + err = dbt_put_internal (obt_p, SP_ATTR_DEFAULT_VALUE, &info.default_value); + if (err != NO_ERROR) + { + goto error; + } + + if (!info.comment.empty ()) + { + db_make_string (&value, info.comment.data ()); + } + err = dbt_put_internal (obt_p, SP_ATTR_ARG_COMMENT, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + object_p = dbt_finish_object (obt_p); + if (!object_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + obt_p = NULL; + + err = locator_flush_instance (object_p); + if (err != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + obj_delete (object_p); + goto error; + } + + *mop_p = object_p; + + AU_ENABLE (save); + return NO_ERROR; + +error: + if (obt_p) + { + dbt_abort_object (obt_p); + } + + AU_ENABLE (save); + return err; +} + +int +sp_add_stored_procedure_code (SP_CODE_INFO &info) +{ + DB_OBJECT *classobj_p, *object_p; + DB_OTMPL *obt_p = NULL; + DB_VALUE value; + int save; + int err; + + AU_DISABLE (save); + + classobj_p = db_find_class (SP_CODE_CLASS_NAME); + if (classobj_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + obt_p = dbt_create_object_internal (classobj_p); + if (obt_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + db_make_string (&value, info.created_time.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_TIMESTAMP, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_object (&value, info.owner); + err = dbt_put_internal (obt_p, SP_ATTR_OWNER, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_string (&value, info.name.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_CLS_NAME, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_int (&value, info.stype); + err = dbt_put_internal (obt_p, SP_ATTR_SOURCE_TYPE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_varchar (&value, DB_DEFAULT_PRECISION, info.scode.data (), info.scode.length (), LANG_SYS_CODESET, + LANG_SYS_COLLATION); + err = dbt_put_internal (obt_p, SP_ATTR_SOURCE_CODE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + + db_make_int (&value, info.otype); + err = dbt_put_internal (obt_p, SP_ATTR_OBJECT_TYPE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + db_make_varchar (&value, DB_DEFAULT_PRECISION, info.ocode.data (), info.ocode.length (), LANG_SYS_CODESET, + LANG_SYS_COLLATION); + err = dbt_put_internal (obt_p, SP_ATTR_OBJECT_CODE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + object_p = dbt_finish_object (obt_p); + if (!object_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + obt_p = NULL; + + err = locator_flush_instance (object_p); + if (err != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + obj_delete (object_p); + goto error; + } + + AU_ENABLE (save); + return NO_ERROR; + +error: + if (obt_p) + { + dbt_abort_object (obt_p); + } + + AU_ENABLE (save); + return err; +} + +int +sp_edit_stored_procedure_code (MOP code_mop, SP_CODE_INFO &info) +{ + DB_OBJECT *object_p; + DB_OTMPL *obt_p = NULL; + DB_VALUE value; + int save; + int err; + + AU_DISABLE (save); + + obt_p = dbt_edit_object (code_mop); + if (obt_p == NULL) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + + db_make_string (&value, info.name.data ()); + err = dbt_put_internal (obt_p, SP_ATTR_CLS_NAME, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + if (info.owner != NULL) + { + db_make_object (&value, info.owner); + err = dbt_put_internal (obt_p, SP_ATTR_OWNER, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + } + + db_make_varchar (&value, DB_DEFAULT_PRECISION, info.ocode.data (), info.ocode.length (), LANG_SYS_CODESET, + LANG_SYS_COLLATION); + err = dbt_put_internal (obt_p, SP_ATTR_OBJECT_CODE, &value); + pr_clear_value (&value); + if (err != NO_ERROR) + { + goto error; + } + + object_p = dbt_finish_object (obt_p); + if (!object_p) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + goto error; + } + obt_p = NULL; + + err = locator_flush_instance (object_p); + if (err != NO_ERROR) + { + assert (er_errid () != NO_ERROR); + err = er_errid (); + obj_delete (object_p); + goto error; + } + + AU_ENABLE (save); + return NO_ERROR; + +error: + if (obt_p) + { + dbt_abort_object (obt_p); + } + + AU_ENABLE (save); + return err; +} + +void sp_normalize_name (std::string &s) +{ + s.resize (SM_MAX_IDENTIFIER_LENGTH); + sm_downcase_name (s.data (), s.data (), SM_MAX_IDENTIFIER_LENGTH); +} + +void +sp_split_target_signature (const std::string &s, std::string &target_cls, std::string &target_mth) +{ + auto pos = s.find_last_of ('('); + if (pos == std::string::npos) + { + // handle the case where '(' is not found, if necessary + target_cls.clear(); + target_mth.clear(); + return; + } + + pos = s.substr (0, pos).find_last_of ('.'); + if (pos == std::string::npos) + { + // handle the case where '.' is not found, if necessary + target_cls.clear(); + target_mth.clear(); + return; + } + + target_cls = s.substr (0, pos); + target_mth = s.substr (pos + 1); // +1 to skip the '.' +} + +std::string +sp_get_entry_name (int index) +{ + return sp_entry_names[index]; +} + +std::string +sp_args_get_entry_name (int index) +{ + return sp_args_entry_names[index]; +} \ No newline at end of file diff --git a/src/sp/sp_catalog.hpp b/src/sp/sp_catalog.hpp new file mode 100644 index 0000000000..54585d1ef5 --- /dev/null +++ b/src/sp/sp_catalog.hpp @@ -0,0 +1,203 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + + +/* + * sp_catalog.hpp - Define stored procedure related system catalog's row sturcture and initializer + * + * Note: _db_stored_proceudre, _db_stored_procedure_args + */ + +#ifndef _SP_DEFINITION_HPP_ +#define _SP_DEFINITION_HPP_ + +#include +#include + +#include "jsp_cl.h" +#include "dbi.h" + +#define SAVEPOINT_ADD_STORED_PROC "ADDSTOREDPROC" +#define SAVEPOINT_CREATE_STORED_PROC "CREATESTOREDPROC" + +enum sp_source_code_type +{ + SPSC_PLCSQL, + SPSC_JAVA +}; + +enum sp_object_code_type +{ + SPOC_JAVA_CLASS, + SPOC_JAVA_JAR +}; + +enum sp_entry_index +{ + SP_ATTR_INDEX_UNIQUE_NAME, + SP_ATTR_INDEX_NAME, + SP_ATTR_INDEX_SP_TYPE, + SP_ATTR_INDEX_RETURN_TYPE, + SP_ATTR_INDEX_ARG_COUNT, + SP_ATTR_INDEX_ARGS, + SP_ATTR_INDEX_LANG, + SP_ATTR_INDEX_PKG, + SP_ATTR_INDEX_IS_SYSTEM_GENERATED, + SP_ATTR_INDEX_TARGET_CLASS, + SP_ATTR_INDEX_TARGET_METHOD, + SP_ATTR_INDEX_DIRECTIVE, + SP_ATTR_INDEX_OWNER, + SP_ATTR_INDEX_COMMENT, + SP_ATTR_INDEX_LAST +}; + + +enum sp_args_entry_index +{ + SP_ARGS_ATTR_INDEX_SP_OF, + SP_ARGS_ATTR_INDEX_PKG, + SP_ARGS_ATTR_INDEX_OF, + SP_ARGS_ATTR_INDEX_IS_SYSTEM_GENERATED, + SP_ARGS_ATTR_INDEX_ARG_NAME, + SP_ARGS_ATTR_INDEX_DATA_TYPE, + SP_ARGS_ATTR_INDEX_MODE, + SP_ARGS_ATTR_INDEX_DEFAULT_VALUE, + SP_ARGS_ATTR_INDEX_IS_OPTIONAL, + SP_ARGS_ATTR_INDEX_COMMENT, + SP_ARGS_ATTR_INDEX_LAST +}; + +// entry +// TODO: move to proper place to commonly use for any catalog +struct sp_entry +{ + OID oid; /* catalog row's oid */ + std::vector vals; + + sp_entry (int size); + ~sp_entry (); +}; + +// *INDENT-OFF* +struct sp_arg_info +{ + std::string sp_name; + std::string pkg_name; + int index_of; + bool is_system_generated; + std::string arg_name; + DB_TYPE data_type; + SP_MODE_ENUM mode; + DB_VALUE default_value; + bool is_optional; + std::string comment; + + sp_arg_info (const std::string& s_name, const std::string& p_name) + : sp_name {s_name} + , pkg_name {p_name} + , index_of {SP_TYPE_ENUM::SP_TYPE_PROCEDURE} + , is_system_generated {false} + , arg_name {} + , data_type {DB_TYPE::DB_TYPE_NULL} + , mode {SP_MODE_ENUM::SP_MODE_IN} + , default_value {} + , is_optional {false} + , comment {} + {} + + sp_arg_info () + : sp_arg_info ("", "") + {} +}; +typedef sp_arg_info SP_ARG_INFO; + +enum sp_directive : int +{ + SP_DIRECTIVE_RIGHTS_OWNER = 0x00, + SP_DIRECTIVE_RIGHTS_CALLER = (0x01 << 0), +}; +typedef sp_directive SP_DIRECTIVE_ENUM; + +struct sp_code_info +{ + std::string name; + std::string created_time; + MOP owner; + int is_static; + int is_system_generated; + int stype; + std::string scode; + int otype; + std::string ocode; +}; +typedef sp_code_info SP_CODE_INFO; + +struct sp_info +{ + std::string unique_name; + std::string sp_name; + std::string pkg_name; + SP_TYPE_ENUM sp_type; + DB_TYPE return_type; + bool is_system_generated; + std::vector args; + SP_LANG_ENUM lang; + std::string target_class; + std::string target_method; + SP_DIRECTIVE_ENUM directive; + MOP owner; + std::string comment; + + sp_info () + : unique_name {} + , sp_name {} + , pkg_name {} + , sp_type {SP_TYPE_ENUM::SP_TYPE_PROCEDURE} + , return_type {DB_TYPE::DB_TYPE_NULL} + , is_system_generated {false} + , args {} + , lang {SP_LANG_ENUM::SP_LANG_PLCSQL} + , target_class {} + , target_method {} + , directive {SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_OWNER} + , owner {nullptr} + , comment {} + {} +}; +typedef sp_info SP_INFO; +// *INDENT-ON* + +int sp_builtin_install (); + +// insert into system catalogs +int sp_add_stored_procedure (SP_INFO &info); +int sp_add_stored_procedure_argument (MOP *mop_p, SP_ARG_INFO &info); +int sp_add_stored_procedure_code (SP_CODE_INFO &info); + +// update into system catalogs +int sp_edit_stored_procedure_code (MOP code_mop, SP_CODE_INFO &info); + +// getter +std::string sp_get_entry_name (int index); +std::string sp_args_get_entry_name (int index); + +// misc +void sp_normalize_name (std::string &s); +void sp_split_target_signature (const std::string &s, std::string &target_cls, std::string &target_mth); + +#endif // _SP_DEFINITION_HPP_ diff --git a/src/sp/sp_code.cpp b/src/sp/sp_code.cpp new file mode 100644 index 0000000000..28de0a7248 --- /dev/null +++ b/src/sp/sp_code.cpp @@ -0,0 +1,264 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +// +// sp_code.cpp +// + +#include "sp_code.hpp" + +#include +#include + +#include "dbtype.h" +#include "heap_file.h" +#include "object_representation_sr.h" +#include "sp_constants.hpp" + +// XXX: SHOULD BE THE LAST INCLUDE HEADER +#include "memory_wrapper.hpp" + +ATTR_ID spcode_Attrs_id[SPC_ATTR_MAX_INDEX]; +int spcode_Num_attrs = -1; + +static int sp_load_sp_code_attribute_info (THREAD_ENTRY *thread_p); +static void sp_code_attr_init (); +static int sp_get_attrid (THREAD_ENTRY *thread_p, int attr_index, ATTR_ID &attrid); +static int sp_get_attr_idx (const std::string &attr_name); + +using sp_code_attr_map_type = std::unordered_map ; +static sp_code_attr_map_type attr_idx_map; + +static void +sp_code_attr_init () +{ + attr_idx_map [SP_ATTR_CLS_NAME] = SPC_ATTR_NAME_INDEX; + attr_idx_map [SP_ATTR_TIMESTAMP] = SPC_ATTR_CREATED_TIME; + attr_idx_map [SP_ATTR_OWNER] = SPC_ATTR_OWNER_INDEX; + attr_idx_map [SP_ATTR_IS_STATIC] = SPC_ATTR_IS_STATIC_INDEX; + attr_idx_map [SP_ATTR_IS_SYSTEM_GENERATED] = SPC_ATTR_IS_SYSTEM_GENERATED_INDEX; + attr_idx_map [SP_ATTR_SOURCE_TYPE] = SPC_ATTR_STYPE_INDEX; + attr_idx_map [SP_ATTR_SOURCE_CODE] = SPC_ATTR_SCODE_INDEX; + attr_idx_map [SP_ATTR_OBJECT_TYPE] = SPC_ATTR_OTYPE_INDEX; + attr_idx_map [SP_ATTR_OBJECT_CODE] = SPC_ATTR_OCODE_INDEX; +} + +static int +sp_get_attr_idx (const std::string &attr_name) +{ + if (attr_idx_map.size () == 0) + { + sp_code_attr_init (); + } + + auto idx_it = attr_idx_map.find (attr_name); + if (idx_it == attr_idx_map.end ()) + { + return -1; + } + else + { + return idx_it->second; + } +} + +int +sp_get_code_attr (THREAD_ENTRY *thread_p, const std::string &attr_name, const OID *sp_oidp, DB_VALUE *result) +{ + int ret = NO_ERROR; + HEAP_SCANCACHE scan_cache; + SCAN_CODE scan; + RECDES recdesc = RECDES_INITIALIZER; + HEAP_CACHE_ATTRINFO attr_info, *attr_info_p = NULL; + ATTR_ID attrid; + DB_VALUE *cur_val; + OID *sp_class_oid = oid_Sp_code_class_oid; + int idx = -1; + + heap_scancache_quick_start_with_class_oid (thread_p, &scan_cache, sp_class_oid); + /* get record into record desc */ + scan = heap_get_visible_version (thread_p, sp_oidp, sp_class_oid, &recdesc, &scan_cache, PEEK, NULL_CHN); + if (scan != S_SUCCESS) + { + if (er_errid () == ER_PB_BAD_PAGEID) + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_HEAP_UNKNOWN_OBJECT, 3, sp_oidp->volid, sp_oidp->pageid, + sp_oidp->slotid); + } + else + { + er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_CANNOT_FETCH_SERIAL, 0); + } + goto exit_on_error; + } + + /* retrieve attribute */ + idx = sp_get_attr_idx (attr_name); + if (idx == -1) + { + goto exit_on_error; + } + + if (sp_get_attrid (thread_p, idx, attrid) != NO_ERROR) + { + goto exit_on_error; + } + + assert (attrid != -1); + + ret = heap_attrinfo_start (thread_p, sp_class_oid, 1, &attrid, &attr_info); + if (ret != NO_ERROR) + { + goto exit_on_error; + } + + attr_info_p = &attr_info; + + ret = heap_attrinfo_read_dbvalues (thread_p, sp_oidp, &recdesc, attr_info_p); + if (ret != NO_ERROR) + { + goto exit_on_error; + } + + cur_val = heap_attrinfo_access (attrid, attr_info_p); + + db_value_clone (cur_val, result); + + heap_attrinfo_end (thread_p, attr_info_p); + + heap_scancache_end (thread_p, &scan_cache); + + return NO_ERROR; + +exit_on_error: + + if (attr_info_p != NULL) + { + heap_attrinfo_end (thread_p, attr_info_p); + } + + heap_scancache_end (thread_p, &scan_cache); + + ret = (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret; + return ret; +} + +static int +sp_get_attrid (THREAD_ENTRY *thread_p, int attr_index, ATTR_ID &attrid) +{ + attrid = -1; // NOT FOUND + + if (spcode_Num_attrs < 0) + { + int error = sp_load_sp_code_attribute_info (thread_p); + if (error != NO_ERROR) + { + ASSERT_ERROR (); + return error; + } + } + + if (attr_index >= 0 && attr_index <= spcode_Num_attrs) + { + attrid = spcode_Attrs_id[attr_index]; + } + return NO_ERROR; +} + +static int +sp_load_sp_code_attribute_info (THREAD_ENTRY *thread_p) +{ + HEAP_SCANCACHE scan; + RECDES class_record; + HEAP_CACHE_ATTRINFO attr_info; + int i, error = NO_ERROR; + char *attr_name_p, *string = NULL; + int alloced_string = 0; + int attr_idx = -1; + + if (spcode_Num_attrs != -1) + { + // already retrived + return error; + } + + OID *sp_code_oid_class = oid_Sp_code_class_oid; + spcode_Num_attrs = -1; + + if (heap_scancache_quick_start_with_class_oid (thread_p, &scan, sp_code_oid_class) != NO_ERROR) + { + return ER_FAILED; + } + if (heap_get_class_record (thread_p, sp_code_oid_class, &class_record, &scan, PEEK) != S_SUCCESS) + { + heap_scancache_end (thread_p, &scan); + return ER_FAILED; + } + + error = heap_attrinfo_start (thread_p, sp_code_oid_class, -1, NULL, &attr_info); + if (error != NO_ERROR) + { + (void) heap_scancache_end (thread_p, &scan); + return error; + } + + for (i = 0; i < attr_info.num_values; i++) + { + string = NULL; + alloced_string = 0; + + error = or_get_attrname (&class_record, i, &string, &alloced_string); + if (error != NO_ERROR) + { + ASSERT_ERROR (); + goto exit_on_error; + } + + attr_name_p = string; + if (attr_name_p == NULL) + { + error = ER_FAILED; + goto exit_on_error; + } + + attr_idx = sp_get_attr_idx (attr_name_p); + if (attr_idx != -1) + { + spcode_Attrs_id [attr_idx] = i; + } + + if (string != NULL && alloced_string) + { + db_private_free_and_init (NULL, string); + } + + } + spcode_Num_attrs = attr_info.num_values; + + heap_attrinfo_end (thread_p, &attr_info); + error = heap_scancache_end (thread_p, &scan); + + return error; + +exit_on_error: + + heap_attrinfo_end (thread_p, &attr_info); + (void) heap_scancache_end (thread_p, &scan); + + return error; +} diff --git a/src/sp/sp_code.hpp b/src/sp/sp_code.hpp new file mode 100644 index 0000000000..d5947834ca --- /dev/null +++ b/src/sp/sp_code.hpp @@ -0,0 +1,55 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +// +// sp_code.hpp +// + +#ifndef _SP_CODE_HPP_ +#define _SP_CODE_HPP_ + +#ident "$Id$" + +#include + +#include "dbtype_def.h" +#include "query_list.h" /* QUERY_ID, QFILE_LIST_ID */ +#include "query_manager.h" + +// thread_entry.hpp +namespace cubthread +{ + class entry; +} + +enum SP_CODE_ATTRIBUTES +{ + SPC_ATTR_NAME_INDEX, + SPC_ATTR_CREATED_TIME, + SPC_ATTR_OWNER_INDEX, + SPC_ATTR_IS_STATIC_INDEX, + SPC_ATTR_IS_SYSTEM_GENERATED_INDEX, + SPC_ATTR_STYPE_INDEX, + SPC_ATTR_SCODE_INDEX, + SPC_ATTR_OTYPE_INDEX, + SPC_ATTR_OCODE_INDEX, + SPC_ATTR_MAX_INDEX +}; + +int sp_get_code_attr (THREAD_ENTRY *thread_p, const std::string &attr_name, const OID *sp_oidp, DB_VALUE *result); +#endif /* _SP_CODE_HPP_ */ diff --git a/src/sp/sp_constants.hpp b/src/sp/sp_constants.hpp new file mode 100644 index 0000000000..2503969d8e --- /dev/null +++ b/src/sp/sp_constants.hpp @@ -0,0 +1,179 @@ +/* + * + * Copyright 2016 CUBRID Corporation + * + * Licensed 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. + * + */ + +#ifndef _SP_CONSTASNTS_HPP_ +#define _SP_CONSTASNTS_HPP_ + +#define SP_CLASS_NAME "_db_stored_procedure" +#define SP_ARG_CLASS_NAME "_db_stored_procedure_args" +#define SP_CODE_CLASS_NAME "_db_stored_procedure_code" + +#define SP_ATTR_UNIQUE_NAME "unique_name" +#define SP_ATTR_NAME "sp_name" +#define SP_ATTR_SP_TYPE "sp_type" +#define SP_ATTR_RETURN_TYPE "return_type" +#define SP_ATTR_ARGS "args" +#define SP_ATTR_ARG_COUNT "arg_count" +#define SP_ATTR_LANG "lang" +#define SP_ATTR_PKG "pkg_name" +#define SP_ATTR_IS_SYSTEM_GENERATED "is_system_generated" +#define SP_ATTR_TARGET_CLASS "target_class" +#define SP_ATTR_TARGET_METHOD "target_method" +#define SP_ATTR_DIRECTIVE "directive" +#define SP_ATTR_OWNER "owner" +#define SP_ATTR_COMMENT "comment" + +#define SP_ATTR_SP_OF "sp_of" +#define SP_ATTR_ARG_NAME "arg_name" +#define SP_ATTR_INDEX_OF_NAME "index_of" +#define SP_ATTR_DATA_TYPE "data_type" +#define SP_ATTR_MODE "mode" +#define SP_ATTR_DEFAULT_VALUE "default_value" +#define SP_ATTR_IS_OPTIONAL "is_optional" +#define SP_ATTR_ARG_COMMENT "comment" + +#define SP_ATTR_CLS_NAME "name" +#define SP_ATTR_TIMESTAMP "created_time" +#define SP_ATTR_IS_STATIC "is_static" +#define SP_ATTR_SOURCE_TYPE "stype" +#define SP_ATTR_SOURCE_CODE "scode" +#define SP_ATTR_OBJECT_TYPE "otype" +#define SP_ATTR_OBJECT_CODE "ocode" + +#define SP_MAX_DEFAULT_VALUE_LEN 255 + +typedef enum +{ + SP_TYPE_PROCEDURE = 1, + SP_TYPE_FUNCTION +} SP_TYPE_ENUM; + +typedef enum +{ + SP_MODE_IN = 1, + SP_MODE_OUT, + SP_MODE_INOUT +} SP_MODE_ENUM; + +typedef enum +{ + SP_LANG_PLCSQL = 0, + SP_LANG_JAVA = 1 +} SP_LANG_ENUM; + +// refactor following + +#define METHOD_MAX_RECURSION_DEPTH 15 + +typedef enum +{ + METHOD_SUCCESS = 1, + METHOD_EOF, + METHOD_ERROR +} METHOD_CALL_STATUS; + +enum METHOD_TYPE +{ + METHOD_TYPE_NONE = 0, + METHOD_TYPE_INSTANCE_METHOD, + METHOD_TYPE_CLASS_METHOD, + METHOD_TYPE_JAVA_SP, + METHOD_TYPE_PLCSQL +}; + +enum METHOD_AUTH +{ + METHOD_AUTH_OWNER = 0, + METHOD_AUTH_INVOKER = 1 +}; + +enum METHOD_REQUEST +{ + METHOD_REQUEST_ARG_PREPARE = 0x40, + METHOD_REQUEST_INVOKE = 0x01, + METHOD_REQUEST_CALLBACK = 0x08, + METHOD_REQUEST_END = 0x20, + + METHOD_REQUEST_COMPILE = 0x80, + METHOD_REQUEST_SQL_SEMANTICS = 0xA0, + METHOD_REQUEST_GLOBAL_SEMANTICS = 0xA1 +}; + +enum METHOD_RESPONSE +{ + METHOD_RESPONSE_SUCCESS, + METHOD_RESPONSE_ERROR +}; + +enum METHOD_CALLBACK_RESPONSE +{ + METHOD_CALLBACK_END_TRANSACTION = 1, + METHOD_CALLBACK_QUERY_PREPARE = 2, + METHOD_CALLBACK_QUERY_EXECUTE = 3, + METHOD_CALLBACK_GET_DB_PARAMETER = 4, + + METHOD_CALLBACK_CURSOR = 7, + METHOD_CALLBACK_FETCH = 8, + METHOD_CALLBACK_GET_SCHEMA_INFO = 9, + + METHOD_CALLBACK_OID_GET = 10, + METHOD_CALLBACK_OID_PUT = 11, + METHOD_CALLBACK_OID_CMD = 17, + METHOD_CALLBACK_COLLECTION = 18, + + // METHOD_CALLBACK_GET_DB_VERSION = 15, + + METHOD_CALLBACK_NEXT_RESULT = 19, + + METHOD_CALLBACK_EXECUTE_BATCH = 20, + METHOD_CALLBACK_EXECUTE_ARRAY = 21, + + METHOD_CALLBACK_CURSOR_UPDATE = 22, + + METHOD_CALLBACK_MAKE_OUT_RS = 33, + METHOD_CALLBACK_GET_GENERATED_KEYS = 34, + + METHOD_CALLBACK_LOB_NEW = 35, + METHOD_CALLBACK_LOB_WRITE = 36, + METHOD_CALLBACK_LOB_READ = 37, + + METHOD_CALLBACK_CURSOR_CLOSE = 42, + + // COMPILE + METHOD_CALLBACK_GET_SQL_SEMANTICS = 100, + METHOD_CALLBACK_GET_GLOBAL_SEMANTICS = 101, + + // AUTH + METHOD_CALLBACK_CHANGE_RIGHTS = 200, + + // CLASS ACCESS + METHOD_CALLBACK_GET_CODE_ATTR = 201 +}; + +enum METHOD_ARG_MODE +{ + METHOD_ARG_MODE_IN = 1, + METHOD_ARG_MODE_OUT, + METHOD_ARG_MODE_INOUT +}; + +#define METHOD_GROUP_ID uint64_t +#define METHOD_REQ_ID int + + +#endif // _SP_CONSTASNTS_HPP_ \ No newline at end of file diff --git a/src/storage/oid.c b/src/storage/oid.c index 883a0c1ae5..fd43aa2c09 100644 --- a/src/storage/oid.c +++ b/src/storage/oid.c @@ -57,6 +57,7 @@ static OID oid_Datatype_class = { 0, 0, 0 }; static OID oid_Classauth_class = { 0, 0, 0 }; static OID oid_Stored_proc_class = { 0, 0, 0 }; static OID oid_Stored_proc_args_class = { 0, 0, 0 }; +static OID oid_Stored_proc_code_class = { 0, 0, 0 }; static OID oid_Charset_class = { 0, 0, 0 }; static OID oid_Trigger_class = { 0, 0, 0 }; static OID oid_User_class = { 0, 0, 0 }; @@ -80,7 +81,7 @@ OID *oid_Root_class_oid = &oid_Root_class; OID *oid_Serial_class_oid = &oid_Serial_class; OID *oid_Partition_class_oid = &oid_Partition_class; OID *oid_User_class_oid = &oid_User_class; - +OID *oid_Sp_code_class_oid = &oid_Stored_proc_code_class; OID_CACHE_ENTRY oid_Cache[OID_CACHE_SIZE] = { {&oid_Root_class, NULL}, /* Root class is not identifiable by a name */ @@ -110,7 +111,8 @@ OID_CACHE_ENTRY oid_Cache[OID_CACHE_SIZE] = { {&oid_Authorizations_class, CT_AUTHORIZATIONS_NAME}, {&oid_DB_root_class, CT_ROOT_NAME}, {&oid_DBServer_class, CT_DB_SERVER_NAME}, - {&oid_Synonym_class, CT_SYNONYM_NAME} + {&oid_Synonym_class, CT_SYNONYM_NAME}, + {&oid_Stored_proc_code_class, CT_STORED_PROC_CODE_NAME}, }; /* diff --git a/src/storage/oid.h b/src/storage/oid.h index 84e79e3578..5d4acb935c 100644 --- a/src/storage/oid.h +++ b/src/storage/oid.h @@ -201,6 +201,7 @@ enum OID_CACHE_DB_ROOT_CLASS_ID, OID_CACHE_DB_SERVER_CLASS_ID, OID_CACHE_SYNONYM_CLASS_ID, + OID_CACHE_STORED_PROC_CODE_CLASS_ID, OID_CACHE_SIZE }; @@ -209,6 +210,8 @@ extern const OID oid_Null_oid; extern OID *oid_Root_class_oid; extern OID *oid_Serial_class_oid; extern OID *oid_User_class_oid; +extern OID *oid_Sp_code_class_oid; + extern PAGEID oid_Next_tempid; extern void oid_set_root (const OID * oid); diff --git a/src/transaction/boot_cl.c b/src/transaction/boot_cl.c index 70348e2080..b7efad9330 100644 --- a/src/transaction/boot_cl.c +++ b/src/transaction/boot_cl.c @@ -88,6 +88,7 @@ #include "connection_globals.h" #include "host_lookup.h" #include "schema_system_catalog.hpp" +#include "sp_catalog.hpp" #include "authenticate_context.hpp" @@ -566,6 +567,11 @@ boot_initialize_client (BOOT_CLIENT_CREDENTIAL * client_credential, BOOT_DB_PATH sm_mark_system_classes (); error_code = tran_commit (false); } + + if (error_code == NO_ERROR) + { + error_code = sp_builtin_install (); + } } } } diff --git a/src/transaction/boot_sr.c b/src/transaction/boot_sr.c index 54d3f1223d..99031330b8 100644 --- a/src/transaction/boot_sr.c +++ b/src/transaction/boot_sr.c @@ -67,7 +67,7 @@ #include "serial.h" #include "server_interface.h" #include "jansson.h" -#include "jsp_sr.h" +#include "pl_sr.h" #include "xserver_interface.h" #include "session.h" #include "event_log.h" @@ -87,6 +87,7 @@ #if defined(SERVER_MODE) #include "connection_sr.h" #include "server_support.h" +#include "pl_sr.h" #endif /* SERVER_MODE */ #if defined(WINDOWS) @@ -2072,8 +2073,8 @@ boot_restart_server (THREAD_ENTRY * thread_p, bool print_restart, const char *db char timezone_checksum[32 + 1]; const TZ_DATA *tzd; char *mk_path; - int jsp_port; - bool jsp; + int pl_port; + bool pl; /* language data is loaded in context of server */ if (lang_init () != NO_ERROR) @@ -2299,20 +2300,7 @@ boot_restart_server (THREAD_ENTRY * thread_p, bool print_restart, const char *db tsc_init (); #endif /* !SERVER_MODE */ - #if defined (SA_MODE) - // Initialize java stored procedure server for standalone mode - jsp = prm_get_bool_value (PRM_ID_JAVA_STORED_PROCEDURE); - if (jsp && !jsp_jvm_is_loaded ()) - { - jsp_port = prm_get_integer_value (PRM_ID_JAVA_STORED_PROCEDURE_PORT); - error_code = jsp_start_server (db_name, db->pathname, jsp_port); - if (error_code != NO_ERROR) - { - goto error; - } - } - /* *INDENT-OFF* */ // thread_manager was not initialized assert (thread_p == NULL); @@ -2789,6 +2777,8 @@ boot_restart_server (THREAD_ENTRY * thread_p, bool print_restart, const char *db json_set_alloc_funcs (malloc, free); #endif + pl_server_init (db_name); + return NO_ERROR; error: @@ -2817,10 +2807,13 @@ boot_restart_server (THREAD_ENTRY * thread_p, bool print_restart, const char *db session_states_finalize (thread_p); logtb_finalize_global_unique_stats_table (thread_p); + vacuum_stop_workers (thread_p); vacuum_stop_master (thread_p); #if defined(SERVER_MODE) + pl_server_destroy (); + cdc_daemons_destroy (); BO_DISABLE_FLUSH_DAEMONS (); @@ -3139,6 +3132,7 @@ xboot_shutdown_server (REFPTR (THREAD_ENTRY, thread_p), ER_FINAL_CODE is_er_fina #if defined(SERVER_MODE) pgbuf_daemons_destroy (); cdc_daemons_destroy (); + pl_server_destroy (); #endif #if defined (SA_MODE) diff --git a/src/transaction/log_tran_table.c b/src/transaction/log_tran_table.c index c030d9de11..ec0beea41d 100644 --- a/src/transaction/log_tran_table.c +++ b/src/transaction/log_tran_table.c @@ -77,7 +77,8 @@ #include "thread_manager.hpp" #include "xasl.h" #include "xasl_cache.h" -#include "method_runtime_context.hpp" +#include "pl_session.hpp" + // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" @@ -2761,6 +2762,12 @@ logtb_set_tran_index_interrupt (THREAD_ENTRY * thread_p, int tran_index, bool se pgbuf_force_to_check_for_interrupts (); er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_INTERRUPTING, 1, tran_index); perfmon_inc_stat (thread_p, PSTAT_TRAN_NUM_INTERRUPTS); + + cubpl::session * session = cubpl::get_session (); + if (session) + { + session->set_interrupt (ER_INTERRUPTED); + } } return true; @@ -2834,10 +2841,10 @@ logtb_is_interrupted_tdes (THREAD_ENTRY * thread_p, LOG_TDES * tdes, bool clear, #endif } - cubmethod::runtime_context * rctx = cubmethod::get_rctx (thread_p); - if (rctx) + cubpl::session * session = cubpl::get_session (); + if (session) { - rctx->set_interrupt (ER_INTERRUPTED); + session->set_interrupt (ER_INTERRUPTED); } } else if (interrupt == false && tdes->query_timeout > 0) @@ -6073,7 +6080,21 @@ log_tdes::lock_topop () { if (LOG_ISRESTARTED () && is_active_worker_transaction ()) { - int r = rmutex_lock (NULL, &rmutex_topop); + cubthread::entry *thread_p = NULL; +// TODO [PL/CSQL]: It will be fixed at CBRD-25641. +// The following code inside of #if block is a workaround for the issue. +#if 1 + if (rmutex_topop.owner != thread_id_t ()) + { + cubpl::session *session = cubpl::get_session(); + if (session + && session->is_thread_involved (rmutex_topop.owner)) + { + thread_p = thread_get_manager ()->find_by_tid (rmutex_topop.owner); + } + } +#endif + int r = rmutex_lock (thread_p, &rmutex_topop); assert (r == NO_ERROR); } } @@ -6083,7 +6104,21 @@ log_tdes::unlock_topop () { if (LOG_ISRESTARTED () && is_active_worker_transaction ()) { - int r = rmutex_unlock (NULL, &rmutex_topop); + cubthread::entry *thread_p = NULL; +// TODO [PL/CSQL]: It will be fixed at CBRD-25641. +// The following code inside of #if block is a workaround for the issue. +#if 1 + if (rmutex_topop.owner != thread_id_t ()) + { + cubpl::session *session = cubpl::get_session(); + if (session + && session->is_thread_involved (rmutex_topop.owner)) + { + thread_p = thread_get_manager ()->find_by_tid (rmutex_topop.owner); + } + } +#endif + int r = rmutex_unlock (thread_p, &rmutex_topop); assert (r == NO_ERROR); } } diff --git a/src/transaction/transaction_cl.c b/src/transaction/transaction_cl.c index 94592634fc..50019d645c 100644 --- a/src/transaction/transaction_cl.c +++ b/src/transaction/transaction_cl.c @@ -292,7 +292,7 @@ tran_commit (bool retain_lock) } assert (!tran_was_latest_query_aborted ()); - if (tran_was_latest_query_ended ()) + if (tran_was_latest_query_ended () || tran_is_in_libcas ()) { /* Query ended with latest executed query. No need to notify server. */ query_end_notify_server = false; diff --git a/src/win_tools/ctrlservice/ctrlservice.cpp b/src/win_tools/ctrlservice/ctrlservice.cpp index 0eb5209446..c9be9eb72f 100644 --- a/src/win_tools/ctrlservice/ctrlservice.cpp +++ b/src/win_tools/ctrlservice/ctrlservice.cpp @@ -62,8 +62,8 @@ #define SERVICE_CONTROL_SERVER_STOP 181 #define SERVICE_CONTROL_SERVICE_START 190 #define SERVICE_CONTROL_SERVICE_STOP 191 -#define SERVICE_CONTROL_JAVASP_START 210 -#define SERVICE_CONTROL_JAVASP_STOP 211 +#define SERVICE_CONTROL_PL_START 210 +#define SERVICE_CONTROL_PL_STOP 211 void WriteLog (char *p_logfile, char *p_format, ...); void GetCurDateTime (char *p_buf, char *p_form); @@ -335,11 +335,11 @@ _tmain (int argc, char *argv[]) } else if (_stricmp (argv[1], CUBRID_UTIL_JAVASP) == 0 && _stricmp (argv[2], CUBRID_COMMAND_START) == 0) { - service_control_code = SERVICE_CONTROL_JAVASP_START; + service_control_code = SERVICE_CONTROL_PL_START; } else if (_stricmp (argv[1], CUBRID_UTIL_JAVASP) == 0 && _stricmp (argv[2], CUBRID_COMMAND_STOP) == 0) { - service_control_code = SERVICE_CONTROL_JAVASP_STOP; + service_control_code = SERVICE_CONTROL_PL_STOP; } else { diff --git a/src/win_tools/cubridservice/cubridservice.cpp b/src/win_tools/cubridservice/cubridservice.cpp index 2530e495e3..de14137b51 100644 --- a/src/win_tools/cubridservice/cubridservice.cpp +++ b/src/win_tools/cubridservice/cubridservice.cpp @@ -67,8 +67,8 @@ BOOL g_isRunning = false; #define SERVICE_CONTROL_SERVER_STOP 181 #define SERVICE_CONTROL_SERVICE_START 190 #define SERVICE_CONTROL_SERVICE_STOP 191 -#define SERVICE_CONTROL_JAVASP_START 210 -#define SERVICE_CONTROL_JAVASP_STOP 211 +#define SERVICE_CONTROL_PL_START 210 +#define SERVICE_CONTROL_PL_STOP 211 #define CUBRID_UTIL_CUBRID "cubrid.exe" #define CUBRID_UTIL_SERVICE "service" @@ -195,8 +195,8 @@ vHandler (DWORD opcode) if (opcode == SERVICE_CONTROL_SERVER_START || opcode == SERVICE_CONTROL_SERVER_STOP || - opcode == SERVICE_CONTROL_JAVASP_START || - opcode == SERVICE_CONTROL_JAVASP_STOP || + opcode == SERVICE_CONTROL_PL_START || + opcode == SERVICE_CONTROL_PL_STOP || opcode == SERVICE_CONTROL_BROKER_ON || opcode == SERVICE_CONTROL_BROKER_OFF || opcode == SERVICE_CONTROL_GATEWAY_ON || opcode == SERVICE_CONTROL_GATEWAY_OFF) @@ -359,7 +359,7 @@ vHandler (DWORD opcode) args[5] = NULL; } break; - case SERVICE_CONTROL_JAVASP_START: + case SERVICE_CONTROL_PL_START: { args[1] = CUBRID_UTIL_JAVASP; args[2] = CUBRID_COMMAND_START; @@ -367,7 +367,7 @@ vHandler (DWORD opcode) args[5] = NULL; } break; - case SERVICE_CONTROL_JAVASP_STOP: + case SERVICE_CONTROL_PL_STOP: { args[1] = CUBRID_UTIL_JAVASP; args[2] = CUBRID_COMMAND_STOP; @@ -384,8 +384,8 @@ vHandler (DWORD opcode) if (opcode == SERVICE_CONTROL_SERVER_START || opcode == SERVICE_CONTROL_SERVER_STOP || - opcode == SERVICE_CONTROL_JAVASP_START || - opcode == SERVICE_CONTROL_JAVASP_STOP || + opcode == SERVICE_CONTROL_PL_START || + opcode == SERVICE_CONTROL_PL_STOP || opcode == SERVICE_CONTROL_BROKER_ON || opcode == SERVICE_CONTROL_BROKER_OFF || opcode == SERVICE_CONTROL_GATEWAY_ON || opcode == SERVICE_CONTROL_GATEWAY_OFF) diff --git a/src/method/method_compile.hpp b/src/xasl/xasl_sp.hpp similarity index 52% rename from src/method/method_compile.hpp rename to src/xasl/xasl_sp.hpp index 554abe5506..9b77313d6e 100644 --- a/src/method/method_compile.hpp +++ b/src/xasl/xasl_sp.hpp @@ -17,29 +17,31 @@ */ // -// method_compile.hpp - define structures used by method feature +// xasl_sp.hpp - XASL structures used for stored procedures // -#ifndef _METHOD_COMPILE_HPP_ -#define _METHOD_COMPILE_HPP_ +#ifndef _XASL_STORED_PROCEDURE_HPP_ +#define _XASL_STORED_PROCEDURE_HPP_ -#include "mem_block.hpp" +#include "dbtype_def.h" +#include "storage_common.h" +#include "pl_signature.hpp" -#if defined (SERVER_MODE) || defined (SA_MODE) -#include "method_invoke.hpp" -#include "method_runtime_context.hpp" -#endif +// forward definitions +struct regu_variable_list_node; +class regu_variable_node; -#include -#include - -namespace cubmethod +namespace cubxasl { -#if defined (SERVER_MODE) || defined (SA_MODE) - int invoke_compile (cubthread::entry &thread, runtime_context &ctx, const std::string &program, - const bool &verbose, - cubmem::extensible_block &blk); -#endif -} + struct sp_node + { + cubpl::pl_signature *sig; + regu_variable_list_node *args; + DB_VALUE *value; // return value + }; +}; + +// legacy aliases +using SP_TYPE = cubxasl::sp_node; -#endif //_METHOD_COMPILE_HPP_ +#endif // _XASL_STORED_PROCEDURE_HPP_ diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 3d8f74f76f..d1d36b26d4 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -96,7 +96,6 @@ set(CUB_MASTER_SOURCES ) if(UNIX) list(APPEND CUB_MASTER_SOURCES ${EXECUTABLES_DIR}/master_heartbeat.c) - list(APPEND CUB_MASTER_SOURCES ${EXECUTABLES_DIR}/master_server_monitor.cpp) SET_SOURCE_FILES_PROPERTIES( ${CUB_MASTER_SOURCES} PROPERTIES LANGUAGE CXX @@ -221,18 +220,20 @@ else(UNIX) target_link_libraries(loadjava LINK_PRIVATE cubridcs) endif(UNIX) -set(JAVASP_SERVER_SOURCES - ${EXECUTABLES_DIR}/javasp.cpp +set(PL_SERVER_SOURCES + ${EXECUTABLES_DIR}/pl.cpp ) SET_SOURCE_FILES_PROPERTIES( - ${JAVASP_SERVER_SOURCES} + ${PL_SERVER_SOURCES} PROPERTIES LANGUAGE CXX ) if(WIN32) - list(APPEND JAVASP_SERVER_SOURCES ${CMAKE_BINARY_DIR}/version.rc) + list(APPEND PL_SERVER_SOURCES ${CMAKE_BINARY_DIR}/version.rc) endif(WIN32) -add_executable(cub_javasp ${JAVASP_SERVER_SOURCES}) -target_link_libraries(cub_javasp LINK_PRIVATE cubridsa) +add_executable(cub_pl ${PL_SERVER_SOURCES}) +target_include_directories(cub_pl PRIVATE ${JAVA_INC} ${CMAKE_BINARY_DIR} ${EP_INCLUDES}) +target_compile_definitions(cub_pl PRIVATE PL_MODE ${COMMON_DEFS}) +target_link_libraries(cub_pl LINK_PRIVATE cubridsa) set(CUB_ADMIN_SOURCES ${EXECUTABLES_DIR}/util_admin.c @@ -385,7 +386,7 @@ install(TARGETS cub_commdb cubrid_rel loadjava - cub_javasp + cub_pl cub_admin cubrid_esql plcsql_helper diff --git a/win/cubridcs/cubridcs.def b/win/cubridcs/cubridcs.def index 8061507902..ac18a59f9d 100644 --- a/win/cubridcs/cubridcs.def +++ b/win/cubridcs/cubridcs.def @@ -979,3 +979,7 @@ EXPORTS gethostbyname_uhost getnameinfo_uhost trim + er_has_error + prm_get_name + windows_socket_startup + windows_socket_shutdown diff --git a/win/cubridsa/cubridsa.def b/win/cubridsa/cubridsa.def index de412f9bcf..c1d922ba23 100644 --- a/win/cubridsa/cubridsa.def +++ b/win/cubridsa/cubridsa.def @@ -132,20 +132,20 @@ EXPORTS er_init er_final er_clear - jsp_connect_server - jsp_disconnect_server - jsp_writen - jsp_readn - jsp_start_server - jsp_server_port - javasp_get_info_file - javasp_get_error_file - javasp_open_info_dir - javasp_open_info - javasp_read_info - javasp_reset_info - javasp_write_info - javasp_unlink_info + pl_connect_server + pl_disconnect_server + pl_writen + pl_readn + pl_start_jvm_server + pl_server_port + pl_get_info_file + pl_get_error_file + pl_open_info_dir + pl_open_info + pl_read_info + pl_reset_info + pl_write_info + pl_unlink_info ; ; utility functions ; From 706d93b71ec3e26c813adcb4a6cc765e1a9b836d Mon Sep 17 00:00:00 2001 From: ctshim <78332782+ctshim@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:13:45 +0900 Subject: [PATCH 03/11] [CBRD-25186] [bugfix] Run-time exception of expression BIT_LENGTH('CUBRID') (#5650) http://jira.cubrid.org/browse/CBRD-25186 * [CBRD-25186] [bugfix] Run-time exception of expression BIT_LENGTH('CUBRID') * Support LOB type in bit_length(), octet_length(). * Fix type conversion error in prepare-execute method for hex(). * Support blob in bit_length(), octet_length() --- src/parser/parse_tree_cl.c | 7 ++++ src/parser/type_checking.c | 58 +++++++++++++++++++++++++++++++--- src/query/fetch.c | 65 +++++++++++++++++++++++++++++++++++++- src/query/string_opfunc.c | 26 +++++++++++++-- 4 files changed, 148 insertions(+), 8 deletions(-) diff --git a/src/parser/parse_tree_cl.c b/src/parser/parse_tree_cl.c index 38bf91c5fd..fae8857f98 100644 --- a/src/parser/parse_tree_cl.c +++ b/src/parser/parse_tree_cl.c @@ -943,6 +943,13 @@ pt_walk_private (PARSER_CONTEXT * parser, PT_NODE * node, void *void_arg) * calling pt_apply. */ node_type = node->node_type; + assert (node_type >= PT_NODE_NONE); + if (node_type == PT_NODE_NONE) + { + assert (pt_has_error (parser)); + return NULL; + } + if (node_type >= PT_LAST_NODE_NUMBER || !(apply = pt_apply_f[node_type])) { return NULL; diff --git a/src/parser/type_checking.c b/src/parser/type_checking.c index 69f0b9d24a..4112dff288 100644 --- a/src/parser/type_checking.c +++ b/src/parser/type_checking.c @@ -529,12 +529,11 @@ pt_get_expression_definition (const PT_OP_TYPE op, EXPRESSION_DEFINITION * def) num = 0; /* two overloads */ - /* arg1 */ sig.arg1_type.type = pt_arg_type::GENERIC; sig.arg1_type.val.generic_type = PT_GENERIC_TYPE_STRING; - /* return type */ + /* return type */ sig.return_type.type = pt_arg_type::NORMAL; sig.return_type.val.type = PT_TYPE_INTEGER; def->overloads[num++] = sig; @@ -542,10 +541,13 @@ pt_get_expression_definition (const PT_OP_TYPE op, EXPRESSION_DEFINITION * def) /* arg1 */ sig.arg1_type.type = pt_arg_type::GENERIC; sig.arg1_type.val.generic_type = PT_GENERIC_TYPE_BIT; + /* return type */ + def->overloads[num++] = sig; + /* arg1 */ + sig.arg1_type.type = pt_arg_type::NORMAL; + sig.arg1_type.val.type = PT_TYPE_BLOB; /* return type */ - sig.return_type.type = pt_arg_type::NORMAL; - sig.return_type.val.type = PT_TYPE_INTEGER; def->overloads[num++] = sig; def->overloads_count = num; @@ -6128,8 +6130,8 @@ pt_apply_expressions_definition (PARSER_CONTEXT * parser, PT_NODE ** node) return NO_ERROR; } - matches = -1; best_match = 0; + matches = -1; for (i = 0; i < def.overloads_count; i++) { int match_cnt = 0; @@ -15759,6 +15761,24 @@ pt_evaluate_db_value_expr (PARSER_CONTEXT * parser, PT_NODE * expr, PT_OP_TYPE o if (!PT_IS_STRING_TYPE (o1->type_enum)) { + if (o1->type_enum == PT_TYPE_BLOB) + { + DB_VALUE tval; + + db_make_null (&tval); + dom_status = tp_value_cast (arg1, &tval, &tp_VarBit_domain, false); + if (dom_status != DOMAIN_COMPATIBLE) + { + PT_ERRORmf2 (parser, o1, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CANT_COERCE_TO, + pt_short_print (parser, o1), pt_show_type_enum (rTyp)); + db_value_clear (&tval); + return 0; + } + db_make_int (result, db_get_string_size (&tval)); + db_value_clear (&tval); + return 1; + } + return 0; } @@ -15774,6 +15794,27 @@ pt_evaluate_db_value_expr (PARSER_CONTEXT * parser, PT_NODE * expr, PT_OP_TYPE o if (!PT_IS_STRING_TYPE (o1->type_enum)) { + if (o1->type_enum == PT_TYPE_BLOB) + { + DB_VALUE tval; + int len = 0; + + db_make_null (&tval); + dom_status = tp_value_cast (arg1, &tval, &tp_VarBit_domain, false); + if (dom_status != DOMAIN_COMPATIBLE) + { + PT_ERRORmf2 (parser, o1, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CANT_COERCE_TO, + pt_short_print (parser, o1), pt_show_type_enum (rTyp)); + db_value_clear (&tval); + return 0; + } + + db_get_bit (&tval, &len); + db_make_int (result, len); + db_value_clear (&tval); + return 1; + } + return 0; } @@ -19203,6 +19244,11 @@ pt_semantic_type (PARSER_CONTEXT * parser, PT_NODE * tree, SEMANTIC_CHK_INFO * s } /* do type checking */ tree = parser_walk_tree (parser, tree, pt_eval_type_pre, sc_info_ptr, pt_eval_type, sc_info_ptr); + if (pt_has_error (parser)) + { + tree = NULL; + return tree; + } /* do constant folding */ tree = parser_walk_tree (parser, tree, pt_fold_constants_pre, NULL, pt_fold_constants_post, sc_info_ptr); if (pt_has_error (parser)) @@ -20377,6 +20423,8 @@ pt_is_op_hv_late_bind (PT_OP_TYPE op) case PT_HOURF: case PT_MINUTEF: case PT_SECONDF: + case PT_BIT_LENGTH: + case PT_OCTET_LENGTH: case PT_TO_DATE: case PT_TO_DATETIME: case PT_TO_DATETIME_TZ: diff --git a/src/query/fetch.c b/src/query/fetch.c index 0d6ee6914f..5f434052d7 100644 --- a/src/query/fetch.c +++ b/src/query/fetch.c @@ -59,7 +59,6 @@ #include "dbtype.h" // XXX: SHOULD BE THE LAST INCLUDE HEADER #include "memory_wrapper.hpp" - static int fetch_peek_arith (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var, val_descr * vd, OID * obj_oid, QFILE_TUPLE tpl, DB_VALUE ** peek_dbval); static int fetch_peek_dbval_pos (REGU_VARIABLE * regu_var, QFILE_TUPLE tpl, int pos, DB_VALUE ** peek_dbval, @@ -1211,6 +1210,37 @@ fetch_peek_arith (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var, val_descr * { PRIM_SET_NULL (arithptr->value); } + else if (DB_VALUE_DOMAIN_TYPE (peek_right) == DB_TYPE_BLOB) + { + DB_VALUE tval; + + db_make_null (&tval); + dom_status = tp_value_cast (peek_right, &tval, &tp_VarBit_domain, false); + if (dom_status != DOMAIN_COMPATIBLE) + { + (void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, peek_right, &tp_VarBit_domain); + db_value_clear (&tval); + goto error; + } + + db_make_int (arithptr->value, db_get_string_size (&tval)); + db_value_clear (&tval); + } + else if (!TP_IS_STRING_TYPE (DB_VALUE_TYPE (peek_right))) + { + DB_VALUE tval; + + db_make_null (&tval); + dom_status = tp_value_cast (peek_right, &tval, &tp_Char_domain, false); + if (dom_status != DOMAIN_COMPATIBLE) + { + (void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, peek_right, &tp_Char_domain); + db_value_clear (&tval); + goto error; + } + db_make_int (arithptr->value, db_get_string_size (&tval)); + db_value_clear (&tval); + } else { db_make_int (arithptr->value, db_get_string_size (peek_right)); @@ -1229,6 +1259,39 @@ fetch_peek_arith (THREAD_ENTRY * thread_p, REGU_VARIABLE * regu_var, val_descr * db_get_bit (peek_right, &len); db_make_int (arithptr->value, len); } + else if (DB_VALUE_DOMAIN_TYPE (peek_right) == DB_TYPE_BLOB) + { + DB_VALUE tval; + int len = 0; + + db_make_null (&tval); + dom_status = tp_value_cast (peek_right, &tval, &tp_VarBit_domain, false); + if (dom_status != DOMAIN_COMPATIBLE) + { + (void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, peek_right, &tp_VarBit_domain); + db_value_clear (&tval); + goto error; + } + + db_get_bit (&tval, &len); + db_make_int (arithptr->value, len); + db_value_clear (&tval); + } + else if (!TP_IS_CHAR_TYPE (DB_VALUE_TYPE (peek_right))) + { + DB_VALUE tval; + + db_make_null (&tval); + dom_status = tp_value_cast (peek_right, &tval, &tp_Char_domain, false); + if (dom_status != DOMAIN_COMPATIBLE) + { + (void) tp_domain_status_er_set (dom_status, ARG_FILE_LINE, peek_right, &tp_Char_domain); + db_value_clear (&tval); + goto error; + } + db_make_int (arithptr->value, 8 * db_get_string_size (&tval)); + db_value_clear (&tval); + } else { /* must be a char string type */ diff --git a/src/query/string_opfunc.c b/src/query/string_opfunc.c index 2230e1ec23..21a8bbd826 100644 --- a/src/query/string_opfunc.c +++ b/src/query/string_opfunc.c @@ -26659,6 +26659,7 @@ db_hex (const DB_VALUE * param, DB_VALUE * result) const char *str = NULL; char *hexval = NULL; int str_size = 0, hexval_len = 0, i = 0, error_code = NO_ERROR; + DB_VALUE tval, *ptval = NULL; /* check parameters for NULL values */ if (param == NULL || result == NULL) @@ -26676,6 +26677,7 @@ db_hex (const DB_VALUE * param, DB_VALUE * result) /* compute hex representation */ param_type = DB_VALUE_DOMAIN_TYPE (param); +coerce_pos: if (TP_IS_CHAR_TYPE (param_type) || TP_IS_BIT_TYPE (param_type)) { if (TP_IS_CHAR_TYPE (param_type)) @@ -26776,14 +26778,34 @@ db_hex (const DB_VALUE * param, DB_VALUE * result) } else { - error_code = ER_QSTR_INVALID_DATA_TYPE; - goto error; + db_make_null (&tval); + ptval = &tval; + if (tp_value_cast (param, &tval, &tp_Char_domain, false) != DOMAIN_COMPATIBLE) + { + error_code = ER_QSTR_INVALID_DATA_TYPE; + goto error; + } + + param = &tval; + param_type = DB_VALUE_DOMAIN_TYPE (param); + assert (TP_IS_CHAR_TYPE (param_type)); + goto coerce_pos; + } + + if (ptval) + { + db_value_clear (ptval); } /* all ok */ return NO_ERROR; error: + if (ptval) + { + db_value_clear (ptval); + } + if (result) { db_make_null (result); From 69693eeb9d9ab05d4bc6436ac27f5e814f76cea4 Mon Sep 17 00:00:00 2001 From: sjkimxxx <42533491+sjkimxxx@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:55:23 +0900 Subject: [PATCH 04/11] [CBRD-23944] Resource needs to be upgreaded for build. (#5710) Resource needs to be upgreaded for build. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6f3ade3ff0..a9b103b82e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,7 @@ jobs: <<: *defaults environment: MAKEFLAGS: -j 8 - resource_class: large + resource_class: xlarge steps: - checkout - run: From 3a6aadd447347bb8c25864cbb6e7a54db4acd928 Mon Sep 17 00:00:00 2001 From: "Na, Hyunik" <67700070+hyunikn@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:31:44 +0900 Subject: [PATCH 05/11] [CBRD-25713] Revert "[CBRD-25713] limit max length of CHAR type to 2048 (#5692)" (#5701) Revert "[CBRD-25713] limit max length of CHAR type to 2048 (#5692)" This reverts commit e560ed5639295c0dce104c7266600da55b9d39bf. From 28ba00de8f49d33a7ddc02453d6422898b14c855 Mon Sep 17 00:00:00 2001 From: "Na, Hyunik" <67700070+hyunikn@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:32:19 +0900 Subject: [PATCH 06/11] [CBRD-24941] slip: revert the use of '%' as the modular operator (#5706) revert the use of '%' as the modular operator because it confuses the lexer with the presence of cursor attributes and %type and %rowtype. --- pl_engine/pl_server/src/main/antlr/PlcLexer.g4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 b/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 index ce66a16ee7..a21cc43e38 100644 --- a/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 +++ b/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 @@ -100,7 +100,7 @@ LANGUAGE: L A N G U A G E ; LIKE: L I K E ; LIST: L I S T ; LOOP: L O O P ; -MOD: ( M O D | '%' ) ; +MOD: M O D ; MULTISET: M U L T I S E T ; NOT: N O T ; NULL_: N U L L ; From cabcf7bcba9d78d9d7c10c0b252e9595405d7c4b Mon Sep 17 00:00:00 2001 From: Yeunjun Lee Date: Thu, 12 Dec 2024 17:45:54 +0900 Subject: [PATCH 07/11] [CBRD-24741] Revert PR "Provides a way to revive the cub_server process in case of abnormal shutdown" (#5700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert "[CBRD-24741] Provides a way to revive the cub_server process in case …" This reverts commit 35419404fd2fb32885d63f5beaccc808fba4bcd4. From bffb701c89dc3ac29cc3edfbc1093a60e098d41d Mon Sep 17 00:00:00 2001 From: Hyung-Gyu Ryoo Date: Thu, 12 Dec 2024 18:39:30 +0900 Subject: [PATCH 08/11] [CBRD-25184] Revert testcases branch to develop for CI (#5713) http://jira.cubrid.org/browse/CBRD-25184 revert testcases branch to develop --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a9b103b82e..cf0d5b75e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,6 @@ test_defaults: &test_defaults shell: /bin/bash environment: _JAVA_OPTIONS: -Xmx1g - BRANCH_TESTCASES: feature/plcsql-p1 command: | ulimit -c 1 /entrypoint.sh checkout From 21754c7aa24ac1c8959f5bc3518e3ef16c629e73 Mon Sep 17 00:00:00 2001 From: jongmin-won <55681111+jongmin-won@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:47:48 +0900 Subject: [PATCH 09/11] [CBRD-25744] Fixed an issue where PROCEDURE permission (GRANT ... ON PROCEDURE) granted by another user was output when a DBA member executed unload without the --as-dba option. (#5709) http://jira.cubrid.org/browse/CBRD-25744 The DBA member user u1 has not granted the public user permission, but running unloaddb -u u1 outputs the PROCEDURE permission granted by another user. The cause of the GRANT statement being output was that we misunderstood the meaning of the au_is_dba_group_member() function while adding a condition to check whether the user is a DBA or a DBA member considering the --as-dba option, so we fixed it with the condition if(!(ctxt.is_dba_user || ctxt.is_dba_group_member)) --- src/executables/unload_schema.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/executables/unload_schema.c b/src/executables/unload_schema.c index 12ef126b85..2d2b20951d 100644 --- a/src/executables/unload_schema.c +++ b/src/executables/unload_schema.c @@ -6046,7 +6046,7 @@ emit_grant (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * clas sp_list = db_get_all_objects (db_find_class (SP_CLASS_NAME)); for (cls = sp_list; cls; cls = cls->next) { - if (!au_is_dba_group_member (Au_user)) + if (!(ctxt.is_dba_user || ctxt.is_dba_group_member)) { sp_owner = jsp_get_owner (cls->op); if (!ws_is_same_object (sp_owner, Au_user)) From dd2438d3507fc9cc730abb0d243af5a69aa798fd Mon Sep 17 00:00:00 2001 From: ctshim <78332782+ctshim@users.noreply.github.com> Date: Fri, 13 Dec 2024 08:12:08 +0900 Subject: [PATCH 10/11] [CBRD-25302] fix core dump to TO_CHAR() on PLCSQL (#5703) http://jira.cubrid.org/browse/CBRD-25302 * fix core-dump --- src/parser/type_checking.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/parser/type_checking.c b/src/parser/type_checking.c index 4112dff288..1da32ca7fb 100644 --- a/src/parser/type_checking.c +++ b/src/parser/type_checking.c @@ -9191,21 +9191,37 @@ pt_eval_expr_type (PARSER_CONTEXT * parser, PT_NODE * node) bool has_user_lang = false; const char *lang_str; - assert (arg3 != NULL && - (arg3->node_type == PT_HOST_VAR || (arg3->node_type == PT_VALUE && arg3_type == PT_TYPE_INTEGER))); + assert (arg3 != NULL); + assert ((arg3->node_type == PT_HOST_VAR) || + (arg3->node_type == PT_VALUE && arg3_type == PT_TYPE_INTEGER) || + (parser->flag.is_parsing_static_sql && arg3->node_type == PT_EXPR && arg3->info.expr.op == PT_CAST)); if (arg3->node_type != PT_HOST_VAR) { - /* change locale from date_lang (set by grammar) to number_lang */ - (void) lang_get_lang_id_from_flag (arg3->info.value.data_value.i, &has_user_format, &has_user_lang); - if (!has_user_lang) + if (arg3_type != PT_TYPE_INTEGER) { - int lang_flag; - lang_str = prm_get_string_value (PRM_ID_INTL_NUMBER_LANG); - (void) lang_set_flag_from_lang (lang_str, has_user_format, has_user_lang, &lang_flag); - arg3->info.value.data_value.i = lang_flag; - arg3->info.value.db_value_is_initialized = 0; - pt_value_to_db (parser, arg3); + assert (parser->flag.is_parsing_static_sql && + arg3->node_type == PT_EXPR && arg3->info.expr.op == PT_CAST); + /* This part is not supported normally. + * This is a problem that has persisted since the previous version. + * I assume that you can enter here only when it is written as static sql in PLCSQL. + * Also, in this case, it is promised that actual execution will not be performed separately. + * For this reason, we skip over the actual lang_id, etc. without obtaining them. + */ + } + else + { + /* change locale from date_lang (set by grammar) to number_lang */ + (void) lang_get_lang_id_from_flag (arg3->info.value.data_value.i, &has_user_format, &has_user_lang); + if (!has_user_lang) + { + int lang_flag; + lang_str = prm_get_string_value (PRM_ID_INTL_NUMBER_LANG); + (void) lang_set_flag_from_lang (lang_str, has_user_format, has_user_lang, &lang_flag); + arg3->info.value.data_value.i = lang_flag; + arg3->info.value.db_value_is_initialized = 0; + pt_value_to_db (parser, arg3); + } } } } From cdc9dddae2fe72599cadf91fad9d9034d1df7754 Mon Sep 17 00:00:00 2001 From: Mike MyungHwan Oh Date: Fri, 13 Dec 2024 11:27:56 +0900 Subject: [PATCH 11/11] [CBRD-25739] If the target object is a system object, unloaddb removes the target owner of the synonym. (#5712) http://jira.cubrid.org/browse/CBRD-25739 - A target object of synonym can be a system object (system table or system view). - But, system object can not have owner as the follow statement. error) create synonym [s1] for [dba].[_db_class] - So, if the target object of synonym is a system object (table or view), unloaddb removes the target owner of the synonym and outputs the synonym. to-be) create synonym [s1] for [_db_class] --- src/executables/unload_schema.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/executables/unload_schema.c b/src/executables/unload_schema.c index 2d2b20951d..03673a28ea 100644 --- a/src/executables/unload_schema.c +++ b/src/executables/unload_schema.c @@ -1156,17 +1156,17 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) "[owner], " "[is_public], " "[target_name], " - "LOWER([target_owner].[name]), " + "DECODE((SELECT 1 from [_db_class] WHERE [class_name] = [target_name] and [is_system_class] = 1), NULL, LOWER([target_owner].[name]), '') target_owner, " "[comment] " - "FROM [_db_synonym]"; + "FROM [_db_synonym]"; const char *query_user = "SELECT [unique_name], " - "[owner], " - "[is_public], " - "[target_name], " - "LOWER([target_owner].[name]), " - "[comment] " - "FROM [_db_synonym]" + "[owner], " + "[is_public], " + "[target_name], " + "DECODE((SELECT 1 from [_db_class] WHERE [class_name] = [target_name] and [is_system_class] = 1), NULL, LOWER([target_owner].[name]), '') target_owner, " + "[comment] " + "FROM [_db_synonym]"; "WHERE [owner].[name] = '%s'"; // *INDENT-ON* @@ -1323,9 +1323,16 @@ export_synonym (extract_context & ctxt, print_output & output_ctx) PRINT_OWNER_NAME (synonym_owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), synonym_output_owner, sizeof (synonym_owner_name)); - output_ctx (" SYNONYM %s%s%s%s FOR %s%s%s.%s%s%s", synonym_output_owner, - PRINT_IDENTIFIER (synonym_name), PRINT_IDENTIFIER (target_owner_name), - PRINT_IDENTIFIER (target_name)); + output_ctx (" SYNONYM %s%s%s%s FOR ", synonym_output_owner, PRINT_IDENTIFIER (synonym_name)); + + if (target_owner_name[0] == 0x00) + { + output_ctx ("%s%s%s", PRINT_IDENTIFIER (target_name)); + } + else + { + output_ctx ("%s%s%s.%s%s%s", PRINT_IDENTIFIER (target_owner_name), PRINT_IDENTIFIER (target_name)); + } if (DB_IS_NULL (&values[SYNONYM_COMMENT]) == false) {