From 9abf0460905ce15e212b3d42f99542820811283d Mon Sep 17 00:00:00 2001 From: Hyung-Gyu Ryoo Date: Wed, 17 Apr 2024 16:58:16 +0900 Subject: [PATCH] [CBRD-25097] PL/CSQL phase-0 internal release (#4825) http://jira.cubrid.org/browse/CBRD-25097 This PR includes PL/CSQL project's phase-0 implementations (feature/plcsql). After this PR is merged in the develop branch, the internal release is considered completed once QA testing is completed for the following features that must be satisfied in phase-0. The features are as follows: - PL/CSQL program compiler: The PL/CSQL compiler parses the program according to the PL/CSQL grammar defined in the issue and then includes a module that communicates with the DB server for information needed in CUBRID SQL parts such as Static SQL. - Support PL/CSQL in DDL (CREATE PROCEDURE/FUNCTION) statement: In CREATE PROCEDURE/FUNCTION statement, stored routine can be written between BEGIN ... END. The stored routine body is sent to the PL/CSQL compiler and it is registered if compiling succeed. - Support TCL (COMMIT/ROLLBACK) in stored routine: COMMIT and ROLLBACK have been ignored in Java SP. In this change, they are supported if pl_transaction_control parameter is on, which is introduced for backward compatibility. - Support DBMS_OUTPUT built-in functions: Yet package is not added in CUBRID. But, DBMS_OUTPUT is used frequently to debug or log when users write procedure/function. --- .circleci/config.yml | 25 +- .../workflows/license_headers/apache_bat3.txt | 18 + .gitignore | 2 +- CMakeLists.txt | 2 +- cs/CMakeLists.txt | 3 +- cubrid/CMakeLists.txt | 5 +- demo/CMakeLists.txt | 7 +- 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 + jsp/CMakeLists.txt | 72 - jsp/build.xml | 124 - jsp/ivy.xml | 16 - jsp/ivysettings.xml | 27 - msg/de_DE.utf8/cubrid.msg | 8 +- msg/de_DE.utf8/utils.msg | 1 + msg/en_US.utf8/cubrid.msg | 8 +- msg/en_US.utf8/utils.msg | 1 + msg/en_US/cubrid.msg | 8 +- msg/en_US/utils.msg | 1 + msg/es_ES.utf8/cubrid.msg | 8 +- msg/es_ES.utf8/utils.msg | 1 + msg/fr_FR.utf8/cubrid.msg | 8 +- msg/fr_FR.utf8/utils.msg | 1 + msg/it_IT.utf8/cubrid.msg | 8 +- msg/it_IT.utf8/utils.msg | 1 + msg/ja_JP.utf8/cubrid.msg | 8 +- msg/ja_JP.utf8/utils.msg | 1 + msg/km_KH.utf8/cubrid.msg | 8 +- msg/km_KH.utf8/utils.msg | 1 + msg/ko_KR.euckr/cubrid.msg | 4 +- msg/ko_KR.euckr/utils.msg | 1 + msg/ko_KR.utf8/cubrid.msg | 8 +- msg/ko_KR.utf8/utils.msg | 1 + msg/ro_RO.utf8/cubrid.msg | 8 +- msg/ro_RO.utf8/utils.msg | 1 + msg/tr_TR.utf8/cubrid.msg | 8 +- msg/tr_TR.utf8/utils.msg | 1 + msg/vi_VN.utf8/cubrid.msg | 8 +- msg/vi_VN.utf8/utils.msg | 1 + msg/zh_CN.utf8/cubrid.msg | 8 +- msg/zh_CN.utf8/utils.msg | 1 + pl_engine/.gitattributes | 9 + pl_engine/.gitignore | 6 + pl_engine/CMakeLists.txt | 65 + .../cmake/copy_submodule_jdbc.cmake | 6 +- pl_engine/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 62076 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + pl_engine/gradlew | 245 + pl_engine/gradlew.bat | 95 + pl_engine/pl_server/build.gradle.kts | 150 + .../pl_server/src/main/antlr/PlcLexer.g4 | 297 ++ .../pl_server/src/main/antlr/PlcParser.g4 | 571 +++ .../java/com/cubrid/jsp/ExecuteThread.java | 461 ++ .../java}/com/cubrid/jsp/ListenerThread.java | 0 .../java}/com/cubrid/jsp/LoggingThread.java | 12 +- .../java}/com/cubrid/jsp/OSValidator.java | 0 .../src/main/java/com/cubrid/jsp/Server.java | 267 ++ .../java/com/cubrid/jsp/ServerConfig.java | 73 + .../com/cubrid/jsp/SpSecurityManager.java | 5 +- .../java}/com/cubrid/jsp/StoredProcedure.java | 7 +- .../java}/com/cubrid/jsp/TargetMethod.java | 23 +- .../com/cubrid/jsp/TargetMethodCache.java | 16 +- .../jsp/classloader/BaseClassLoader.java | 87 +- .../jsp/classloader/ClassLoaderManager.java | 116 + .../jsp/classloader/ContextClassLoader.java | 54 + .../jsp/classloader/ServerClassLoader.java | 50 + .../java/com/cubrid/jsp/context/Context.java | 207 + .../cubrid/jsp/context/ContextManager.java | 90 + .../com/cubrid/jsp/data/CUBRIDPacker.java | 16 +- .../com/cubrid/jsp/data/CUBRIDUnpacker.java | 27 + .../java}/com/cubrid/jsp/data/CallInfo.java | 0 .../java}/com/cubrid/jsp/data/ClientIds.java | 0 .../java}/com/cubrid/jsp/data/ColumnInfo.java | 2 + .../java}/com/cubrid/jsp/data/ColumnMeta.java | 0 .../java/com/cubrid/jsp/data/CompileInfo.java | 78 + .../com/cubrid/jsp/data/DBParameterInfo.java | 0 .../java}/com/cubrid/jsp/data/DBType.java | 3 +- .../com/cubrid/jsp/data/DataUtilities.java | 0 .../java}/com/cubrid/jsp/data/ErrorInfo.java | 0 .../com/cubrid/jsp/data/ExecuteInfo.java | 0 .../java}/com/cubrid/jsp/data/FetchInfo.java | 0 .../com/cubrid/jsp/data/GetByOIDInfo.java | 0 .../cubrid/jsp/data/GetGeneratedKeysInfo.java | 0 .../com/cubrid/jsp/data/GetSchemaInfo.java | 0 .../cubrid/jsp/data/MakeOutResultSetInfo.java | 0 .../com/cubrid/jsp/data/PrepareInfo.java | 0 .../com/cubrid/jsp/data/QueryResultInfo.java | 0 .../main/java}/com/cubrid/jsp/data/SOID.java | 0 .../exception/CUBRIDServerSideException.java | 0 .../jsp/exception/ExecuteException.java | 0 .../jsp/exception/TypeMismatchException.java | 0 .../com/cubrid/jsp/impl/SUBindParameter.java | 0 .../com/cubrid/jsp/impl/SUConnection.java | 64 +- .../com/cubrid/jsp/impl/SUFunctionCode.java | 1 + .../com/cubrid/jsp/impl/SUParameter.java | 0 .../com/cubrid/jsp/impl/SUResultTuple.java | 0 .../com/cubrid/jsp/impl/SUStatement.java | 4 +- .../CUBRIDServerSideCallableStatement.java | 0 .../jsp/jdbc/CUBRIDServerSideConnection.java | 123 +- .../jsp/jdbc/CUBRIDServerSideConstants.java | 4 + .../CUBRIDServerSideDatabaseMetaData.java | 0 .../jsp/jdbc/CUBRIDServerSideDriver.java | 68 +- .../jdbc/CUBRIDServerSideJDBCErrorCode.java | 0 .../CUBRIDServerSideJDBCErrorManager.java | 0 .../cubrid/jsp/jdbc/CUBRIDServerSideOID.java | 0 .../jdbc/CUBRIDServerSideOutResultSet.java | 0 .../CUBRIDServerSidePreparedStatement.java | 0 .../jsp/jdbc/CUBRIDServerSideResultSet.java | 2 +- .../CUBRIDServerSideResultSetMetaData.java | 0 .../jsp/jdbc/CUBRIDServerSideStatement.java | 0 .../jsp/protocol/GlobalSemanticsRequest.java | 26 + .../jsp/protocol/GlobalSemanticsResponse.java | 31 + .../java/com/cubrid/jsp/protocol/Header.java | 38 + .../cubrid/jsp/protocol/PackableObject.java | 7 + .../com/cubrid/jsp/protocol/PrepareArgs.java | 53 + .../com/cubrid/jsp/protocol/RequestCode.java | 24 + .../jsp/protocol/SqlSemanticsRequest.java | 24 + .../jsp/protocol/SqlSemanticsResponse.java | 27 + .../cubrid/jsp/protocol/UnPackableObject.java | 7 + .../com/cubrid/jsp/value/BooleanValue.java | 4 + .../java}/com/cubrid/jsp/value/ByteValue.java | 0 .../com/cubrid/jsp/value/DateTimeParser.java | 385 ++ .../java}/com/cubrid/jsp/value/DateValue.java | 0 .../com/cubrid/jsp/value/DatetimeValue.java | 4 + .../com/cubrid/jsp/value/DoubleValue.java | 0 .../com/cubrid/jsp/value/FloatValue.java | 0 .../java}/com/cubrid/jsp/value/IntValue.java | 0 .../java}/com/cubrid/jsp/value/LongValue.java | 0 .../java}/com/cubrid/jsp/value/NullValue.java | 0 .../com/cubrid/jsp/value/NumericValue.java | 5 + .../java}/com/cubrid/jsp/value/OidValue.java | 0 .../com/cubrid/jsp/value/ResultSetValue.java | 0 .../java}/com/cubrid/jsp/value/SetValue.java | 0 .../com/cubrid/jsp/value/ShortValue.java | 0 .../com/cubrid/jsp/value/StringValue.java | 47 +- .../java}/com/cubrid/jsp/value/TimeValue.java | 0 .../com/cubrid/jsp/value/TimestampValue.java | 4 + .../java}/com/cubrid/jsp/value/Value.java | 0 .../com/cubrid/jsp/value/ValueUtilities.java | 0 .../cubrid/plcsql/builtin/DBMS_OUTPUT.java | 97 + .../cubrid/plcsql/builtin/MessageBuffer.java | 139 + .../com/cubrid/plcsql/compiler/Coercion.java | 447 ++ .../plcsql/compiler/CoercionScheme.java | 619 +++ .../cubrid/plcsql/compiler/DBTypeAdapter.java | 196 + .../java/com/cubrid/plcsql/compiler/Misc.java | 214 + .../plcsql/compiler/ParseTreeConverter.java | 2616 +++++++++++ .../plcsql/compiler/ParseTreePrinter.java | 81 + .../cubrid/plcsql/compiler/PlcLexerEx.java | 85 + .../plcsql/compiler/PlcsqlCompilerMain.java | 304 ++ .../com/cubrid/plcsql/compiler/Scope.java | 51 + .../cubrid/plcsql/compiler/SemanticError.java | 50 + .../com/cubrid/plcsql/compiler/StaticSql.java | 77 + .../plcsql/compiler/StaticSqlCollector.java | 78 + .../cubrid/plcsql/compiler/SymbolStack.java | 834 ++++ .../cubrid/plcsql/compiler/SyntaxError.java | 43 + .../plcsql/compiler/annotation/Operator.java | 43 + .../cubrid/plcsql/compiler/ast/AstNode.java | 45 + .../com/cubrid/plcsql/compiler/ast/Body.java | 61 + .../cubrid/plcsql/compiler/ast/CaseExpr.java | 58 + .../cubrid/plcsql/compiler/ast/CaseStmt.java | 58 + .../cubrid/plcsql/compiler/ast/CondExpr.java | 52 + .../cubrid/plcsql/compiler/ast/CondStmt.java | 56 + .../com/cubrid/plcsql/compiler/ast/Decl.java | 53 + .../cubrid/plcsql/compiler/ast/DeclConst.java | 68 + .../plcsql/compiler/ast/DeclCursor.java | 103 + .../plcsql/compiler/ast/DeclException.java | 55 + .../plcsql/compiler/ast/DeclForIter.java | 57 + .../plcsql/compiler/ast/DeclForRecord.java | 63 + .../cubrid/plcsql/compiler/ast/DeclFunc.java | 65 + .../cubrid/plcsql/compiler/ast/DeclId.java | 39 + .../plcsql/compiler/ast/DeclIdTyped.java | 41 + .../cubrid/plcsql/compiler/ast/DeclLabel.java | 59 + .../cubrid/plcsql/compiler/ast/DeclParam.java | 52 + .../plcsql/compiler/ast/DeclParamIn.java | 55 + .../plcsql/compiler/ast/DeclParamOut.java | 58 + .../cubrid/plcsql/compiler/ast/DeclProc.java | 60 + .../plcsql/compiler/ast/DeclRoutine.java | 80 + .../cubrid/plcsql/compiler/ast/DeclVar.java | 66 + .../cubrid/plcsql/compiler/ast/ExHandler.java | 55 + .../cubrid/plcsql/compiler/ast/ExName.java | 61 + .../com/cubrid/plcsql/compiler/ast/Expr.java | 27 +- .../plcsql/compiler/ast/ExprAutoParam.java | 126 + .../plcsql/compiler/ast/ExprBetween.java | 60 + .../plcsql/compiler/ast/ExprBinaryOp.java | 60 + .../compiler/ast/ExprBuiltinFuncCall.java | 59 + .../cubrid/plcsql/compiler/ast/ExprCase.java | 67 + .../cubrid/plcsql/compiler/ast/ExprCond.java | 59 + .../plcsql/compiler/ast/ExprCursorAttr.java | 68 + .../cubrid/plcsql/compiler/ast/ExprDate.java | 62 + .../plcsql/compiler/ast/ExprDatetime.java | 69 + .../cubrid/plcsql/compiler/ast/ExprFalse.java | 50 + .../cubrid/plcsql/compiler/ast/ExprField.java | 86 + .../cubrid/plcsql/compiler/ast/ExprFloat.java | 66 + .../compiler/ast/ExprGlobalFuncCall.java | 55 + .../cubrid/plcsql/compiler/ast/ExprId.java | 99 + .../cubrid/plcsql/compiler/ast/ExprIn.java | 58 + .../cubrid/plcsql/compiler/ast/ExprLike.java | 54 + .../compiler/ast/ExprLocalFuncCall.java | 60 + .../cubrid/plcsql/compiler/ast/ExprNull.java | 46 + .../plcsql/compiler/ast/ExprSerialVal.java | 59 + .../plcsql/compiler/ast/ExprSqlCode.java | 61 + .../plcsql/compiler/ast/ExprSqlErrm.java | 59 + .../plcsql/compiler/ast/ExprSqlRowCount.java | 46 + .../cubrid/plcsql/compiler/ast/ExprStr.java | 86 + .../cubrid/plcsql/compiler/ast/ExprTime.java | 56 + .../plcsql/compiler/ast/ExprTimestamp.java | 72 + .../cubrid/plcsql/compiler/ast/ExprTrue.java | 46 + .../cubrid/plcsql/compiler/ast/ExprUint.java | 65 + .../plcsql/compiler/ast/ExprUnaryOp.java | 52 + .../cubrid/plcsql/compiler/ast/NodeList.java | 55 + .../com/cubrid/plcsql/compiler/ast/Stmt.java | 39 + .../plcsql/compiler/ast/StmtAssign.java | 52 + .../plcsql/compiler/ast/StmtBasicLoop.java | 52 + .../cubrid/plcsql/compiler/ast/StmtBlock.java | 54 + .../cubrid/plcsql/compiler/ast/StmtCase.java | 68 + .../plcsql/compiler/ast/StmtCommit.java | 46 + .../plcsql/compiler/ast/StmtContinue.java | 59 + .../plcsql/compiler/ast/StmtCursorClose.java | 50 + .../plcsql/compiler/ast/StmtCursorFetch.java | 64 + .../plcsql/compiler/ast/StmtCursorOpen.java | 55 + .../plcsql/compiler/ast/StmtExecImme.java | 58 + .../cubrid/plcsql/compiler/ast/StmtExit.java | 59 + .../compiler/ast/StmtForCursorLoop.java | 63 + .../compiler/ast/StmtForExecImmeLoop.java | 59 + .../plcsql/compiler/ast/StmtForIterLoop.java | 70 + .../plcsql/compiler/ast/StmtForSqlLoop.java | 62 + .../compiler/ast/StmtForStaticSqlLoop.java | 64 + .../compiler/ast/StmtGlobalProcCall.java | 55 + .../cubrid/plcsql/compiler/ast/StmtIf.java | 58 + .../compiler/ast/StmtLocalProcCall.java | 61 + .../cubrid/plcsql/compiler/ast/StmtNull.java | 46 + .../plcsql/compiler/ast/StmtOpenFor.java | 53 + .../cubrid/plcsql/compiler/ast/StmtRaise.java | 52 + .../plcsql/compiler/ast/StmtRaiseAppErr.java | 52 + .../plcsql/compiler/ast/StmtReturn.java | 53 + .../plcsql/compiler/ast/StmtRollback.java | 46 + .../cubrid/plcsql/compiler/ast/StmtSql.java | 73 + .../plcsql/compiler/ast/StmtStaticSql.java | 60 + .../plcsql/compiler/ast/StmtWhileLoop.java | 55 + .../cubrid/plcsql/compiler/ast/TypeSpec.java | 75 + .../plcsql/compiler/ast/TypeSpecPercent.java | 51 + .../com/cubrid/plcsql/compiler/ast/Unit.java | 119 + .../compiler/serverapi/PlParamInfo.java | 81 + .../plcsql/compiler/serverapi/ServerAPI.java | 305 ++ .../compiler/serverapi/ServerConstants.java | 54 + .../compiler/serverapi/SqlSemantics.java | 115 + .../com/cubrid/plcsql/compiler/type/Type.java | 217 + .../cubrid/plcsql/compiler/type/TypeChar.java | 73 + .../plcsql/compiler/type/TypeNumeric.java | 79 + .../plcsql/compiler/type/TypeVarchar.java | 73 + .../plcsql/compiler/type/TypeVariadic.java | 60 + .../plcsql/compiler/visitor/AstVisitor.java | 210 + .../compiler/visitor/JavaCodeWriter.java | 2859 ++++++++++++ .../plcsql/compiler/visitor/TypeChecker.java | 1297 ++++++ .../plcsql/predefined/PlcsqlRuntimeError.java | 62 + .../cubrid/plcsql/predefined/sp/SpLib.java | 4021 +++++++++++++++++ .../src/main/resources}/logging.properties | 0 .../test/java/com/cubrid/jsp}/TestSample.java | 9 +- .../test/java/com/cubrid/jsp/TestServer.java | 95 + .../plcsql/predefined/TestSpLib.java.disable | 954 ++++ .../predefined/TestSpLibPriv.java.disable | 160 + pl_engine/settings.gradle.kts | 17 + sa/CMakeLists.txt | 6 +- src/base/error_code.h | 3 +- src/base/mem_block.hpp | 10 +- src/base/packer.hpp | 23 +- src/base/porting.h | 2 +- src/base/system_parameter.c | 21 +- src/base/system_parameter.h | 1 + src/broker/cas_execute.c | 7 + src/broker/cas_function.c | 1 + src/communication/network.h | 3 + src/communication/network_common.cpp | 4 +- src/communication/network_interface_cl.c | 58 + src/communication/network_interface_cl.h | 6 + src/communication/network_interface_sr.c | 45 +- src/communication/network_interface_sr.h | 4 + src/communication/network_sr.c | 5 + src/compat/db_client_type.hpp | 1 + src/compat/db_vdb.c | 13 + src/compat/dbi.h | 6 + src/compat/dbi_compat.h | 6 + src/executables/csql.c | 146 +- src/executables/csql.h | 7 +- src/executables/csql_session.c | 5 +- src/executables/csql_support.c | 302 +- src/executables/javasp.cpp | 148 +- src/executables/loadjava.cpp | 79 +- src/executables/plcsql.cpp | 341 ++ src/executables/unload_schema.c | 35 + src/executables/util_sa.c | 54 + src/executables/utility.h | 1 + src/jsp/com/cubrid/jsp/ExecuteThread.java | 479 -- src/jsp/com/cubrid/jsp/Server.java | 220 - src/jsp/jsp_cl.c | 93 +- src/jsp/jsp_cl.h | 1 + src/jsp/jsp_comm.c | 13 +- src/jsp/jsp_comm.h | 15 +- src/jsp/jsp_sr.c | 6 +- src/method/method_callback.cpp | 517 ++- src/method/method_callback.hpp | 9 + src/method/method_compile.cpp | 135 + src/method/method_compile.hpp | 45 + src/method/method_compile_def.cpp | 575 +++ src/method/method_compile_def.hpp | 198 + src/method/method_connection.hpp | 61 + src/method/method_connection_java.cpp | 175 + src/method/method_connection_java.hpp | 66 + src/method/method_connection_sr.cpp | 40 +- src/method/method_connection_sr.hpp | 43 +- src/method/method_def.cpp | 208 +- src/method/method_def.hpp | 27 +- src/method/method_invoke.hpp | 11 +- src/method/method_invoke_builtin.cpp | 4 +- src/method/method_invoke_group.cpp | 33 +- src/method/method_invoke_group.hpp | 17 +- src/method/method_invoke_java.cpp | 303 +- src/method/method_query_cursor.cpp | 19 +- src/method/method_query_handler.cpp | 31 +- src/method/method_query_handler.hpp | 6 +- src/method/method_query_util.cpp | 29 +- src/method/method_runtime_context.cpp | 7 + src/method/method_runtime_context.hpp | 11 +- src/method/method_schema_info.cpp | 14 +- src/method/method_schema_info.hpp | 9 +- src/method/method_struct_invoke.cpp | 62 +- src/method/method_struct_invoke.hpp | 29 +- src/method/method_struct_query.cpp | 11 + src/method/method_struct_query.hpp | 5 + src/method/method_struct_schema_info.cpp | 26 + src/method/method_struct_schema_info.hpp | 14 + src/method/method_struct_value.cpp | 7 +- src/method/query_method.cpp | 24 +- src/optimizer/query_rewrite.c | 5 + src/parser/csql_grammar.y | 324 +- src/parser/csql_lexer.l | 220 +- src/parser/name_resolution.c | 84 +- src/parser/parse_tree.c | 4 + src/parser/parse_tree.h | 18 +- src/parser/parse_tree_cl.c | 111 +- src/parser/parser_message.h | 1 + src/parser/semantic_check.c | 31 + src/transaction/log_manager.c | 10 +- src/transaction/transaction_cl.c | 9 +- util/CMakeLists.txt | 22 + win/cubridcs/cubridcs.def | 1 + win/cubridsa/cubridsa.def | 1 + 365 files changed, 31102 insertions(+), 1810 deletions(-) create mode 100644 .github/workflows/license_headers/apache_bat3.txt create mode 100644 demo/plcsql/README.md create mode 100644 demo/plcsql/StmtForStaticSqlLoop-test-without-condition.sql create mode 100644 demo/plcsql/demo_global_semantics_serial.sql create mode 100644 demo/plcsql/demo_global_semantics_type.sql create mode 100644 demo/plcsql/demo_global_semantics_udpf.sql create mode 100644 demo/plcsql/demo_hello.sql create mode 100644 demo/plcsql/demo_hello_ret.sql create mode 100644 demo/plcsql/test_ddl.sql create mode 100644 demo/plcsql/test_dml_delete.sql create mode 100644 demo/plcsql/test_dml_insert.sql create mode 100644 demo/plcsql/test_dml_truncate.sql create mode 100644 demo/plcsql/test_query_cursor_hostvar.sql create mode 100644 demo/plcsql/test_query_cursor_simple.sql create mode 100644 demo/plcsql/test_query_cursor_simple_nocond.sql create mode 100644 demo/plcsql/test_query_single_row.sql create mode 100644 demo/plcsql/test_query_single_row_const.sql create mode 100644 demo/plcsql/test_semantic_error_unknown_tbl.sql create mode 100644 demo/plcsql/test_semantic_error_wrong_literal.sql create mode 100644 demo/plcsql/test_tcl_commit.sql create mode 100644 demo/plcsql/test_tcl_rollback.sql delete mode 100644 jsp/CMakeLists.txt delete mode 100644 jsp/build.xml delete mode 100644 jsp/ivy.xml delete mode 100644 jsp/ivysettings.xml create mode 100644 pl_engine/.gitattributes create mode 100644 pl_engine/.gitignore create mode 100644 pl_engine/CMakeLists.txt rename {jsp => pl_engine}/cmake/copy_submodule_jdbc.cmake (81%) create mode 100644 pl_engine/gradle/wrapper/gradle-wrapper.jar create mode 100644 pl_engine/gradle/wrapper/gradle-wrapper.properties create mode 100755 pl_engine/gradlew create mode 100644 pl_engine/gradlew.bat create mode 100644 pl_engine/pl_server/build.gradle.kts create mode 100644 pl_engine/pl_server/src/main/antlr/PlcLexer.g4 create mode 100644 pl_engine/pl_server/src/main/antlr/PlcParser.g4 create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/ExecuteThread.java rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/ListenerThread.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/LoggingThread.java (88%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/OSValidator.java (100%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/Server.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/ServerConfig.java rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/SpSecurityManager.java (95%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/StoredProcedure.java (98%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/TargetMethod.java (94%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/TargetMethodCache.java (84%) rename src/jsp/com/cubrid/jsp/StoredProcedureClassLoader.java => pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/BaseClassLoader.java (54%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ClassLoaderManager.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ContextClassLoader.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ServerClassLoader.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/Context.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/ContextManager.java rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/CUBRIDPacker.java (95%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/CUBRIDUnpacker.java (95%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/CallInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/ClientIds.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/ColumnInfo.java (97%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/ColumnMeta.java (100%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileInfo.java rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/DBParameterInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/DBType.java (98%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/DataUtilities.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/ErrorInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/ExecuteInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/FetchInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/GetByOIDInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/GetGeneratedKeysInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/GetSchemaInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/MakeOutResultSetInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/PrepareInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/QueryResultInfo.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/data/SOID.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/exception/CUBRIDServerSideException.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/exception/ExecuteException.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/exception/TypeMismatchException.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/impl/SUBindParameter.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/impl/SUConnection.java (89%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/impl/SUFunctionCode.java (99%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/impl/SUParameter.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/impl/SUResultTuple.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/impl/SUStatement.java (99%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideCallableStatement.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java (84%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java (95%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideDatabaseMetaData.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java (71%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorCode.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorManager.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideOID.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideOutResultSet.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSidePreparedStatement.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java (99%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSetMetaData.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/jdbc/CUBRIDServerSideStatement.java (100%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsRequest.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsResponse.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/Header.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PackableObject.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PrepareArgs.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/RequestCode.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsRequest.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsResponse.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/UnPackableObject.java rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/BooleanValue.java (96%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/ByteValue.java (100%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateTimeParser.java rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/DateValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/DatetimeValue.java (97%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/DoubleValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/FloatValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/IntValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/LongValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/NullValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/NumericValue.java (98%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/OidValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/ResultSetValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/SetValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/ShortValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/StringValue.java (83%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/TimeValue.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/TimestampValue.java (97%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/Value.java (100%) rename {src/jsp => pl_engine/pl_server/src/main/java}/com/cubrid/jsp/value/ValueUtilities.java (100%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/builtin/DBMS_OUTPUT.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/builtin/MessageBuffer.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Coercion.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/CoercionScheme.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/DBTypeAdapter.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Misc.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ParseTreeConverter.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ParseTreePrinter.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/PlcLexerEx.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/PlcsqlCompilerMain.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/Scope.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/SemanticError.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/StaticSql.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/StaticSqlCollector.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/SymbolStack.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/SyntaxError.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/annotation/Operator.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/AstNode.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Body.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/CaseExpr.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/CaseStmt.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/CondExpr.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/CondStmt.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Decl.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclConst.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclCursor.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclException.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclForIter.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclForRecord.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclFunc.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclId.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclIdTyped.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclLabel.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclParam.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclParamIn.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclParamOut.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclProc.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclRoutine.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/DeclVar.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExHandler.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExName.java rename src/jsp/com/cubrid/jsp/ExecuteThreadStatus.java => pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Expr.java (80%) create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprAutoParam.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprBetween.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprBinaryOp.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprBuiltinFuncCall.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprCase.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprCond.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprCursorAttr.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprDate.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprDatetime.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprFalse.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprField.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprFloat.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprGlobalFuncCall.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprId.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprIn.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprLike.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprLocalFuncCall.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprNull.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprSerialVal.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprSqlCode.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprSqlErrm.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprSqlRowCount.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprStr.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprTime.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprTimestamp.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprTrue.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprUint.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/ExprUnaryOp.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/NodeList.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Stmt.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtAssign.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtBasicLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtBlock.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtCase.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtCommit.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtContinue.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtCursorClose.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtCursorFetch.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtCursorOpen.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtExecImme.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtExit.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtForCursorLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtForExecImmeLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtForIterLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtForSqlLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtForStaticSqlLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtGlobalProcCall.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtIf.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtLocalProcCall.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtNull.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtOpenFor.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtRaise.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtRaiseAppErr.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtReturn.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtRollback.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtSql.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtStaticSql.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/StmtWhileLoop.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/TypeSpec.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/TypeSpecPercent.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/ast/Unit.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/serverapi/PlParamInfo.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/serverapi/ServerAPI.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/serverapi/ServerConstants.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/serverapi/SqlSemantics.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/Type.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeChar.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeNumeric.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeVarchar.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/type/TypeVariadic.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/visitor/AstVisitor.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/visitor/JavaCodeWriter.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/compiler/visitor/TypeChecker.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/predefined/PlcsqlRuntimeError.java create mode 100644 pl_engine/pl_server/src/main/java/com/cubrid/plcsql/predefined/sp/SpLib.java rename {src/jsp => pl_engine/pl_server/src/main/resources}/logging.properties (100%) rename {src/jsp/com/cubrid/jsp/test => pl_engine/pl_server/src/test/java/com/cubrid/jsp}/TestSample.java (92%) create mode 100644 pl_engine/pl_server/src/test/java/com/cubrid/jsp/TestServer.java create mode 100644 pl_engine/pl_server/src/test/java/com/cubrid/plcsql/predefined/TestSpLib.java.disable create mode 100644 pl_engine/pl_server/src/test/java/com/cubrid/plcsql/predefined/TestSpLibPriv.java.disable create mode 100644 pl_engine/settings.gradle.kts create mode 100644 src/executables/plcsql.cpp delete mode 100644 src/jsp/com/cubrid/jsp/ExecuteThread.java delete mode 100644 src/jsp/com/cubrid/jsp/Server.java create mode 100644 src/method/method_compile.cpp create mode 100644 src/method/method_compile.hpp create mode 100644 src/method/method_compile_def.cpp create mode 100644 src/method/method_compile_def.hpp create mode 100644 src/method/method_connection.hpp create mode 100644 src/method/method_connection_java.cpp create mode 100644 src/method/method_connection_java.hpp diff --git a/.circleci/config.yml b/.circleci/config.yml index 23eb7df6b72..d4cccd092c0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,20 @@ test_defaults: &test_defaults command: | ulimit -c 1 /entrypoint.sh checkout - circleci tests glob cubrid-testcases/$TEST_SUITE/_* | circleci tests split | tee tc.list + if [ $TEST_SUITE = "plcsql" ] + then + # Hack way to run plcsql test without modifying CUBRID CI docker + TEST_SUITE="sql" + glob_path=cubrid-testcases/sql/{_05_plcsql,_35_fig_cake/plcsql} + elif [ $TEST_SUITE = "sql" ] + then + rm -rf cubrid-testcases/$TEST_SUITE/_05_plcsql + rm -rf cubrid-testcases/$TEST_SUITE/_35_fig_cake/plcsql + glob_path="cubrid-testcases/$TEST_SUITE/_*" + else + glob_path="cubrid-testcases/$TEST_SUITE/_*" + fi + circleci tests glob $glob_path | circleci tests split | tee tc.list find cubrid-testcases/$TEST_SUITE/_* -maxdepth 0 -type d -print0 | grep -vzZ -f tc.list | xargs -0 rm -rf /entrypoint.sh test - run: @@ -79,6 +92,13 @@ jobs: parallelism: 8 <<: *test_defaults + test_plcsql: + <<: *defaults + environment: + TEST_SUITE: plcsql + resource_class: medium + <<: *test_defaults + build-windows: machine: image: 'windows-server-2019-vs2019:2022.08.1' @@ -124,5 +144,8 @@ workflows: - test_sql: requires: - build + - test_plcsql: + requires: + - build - build-windows diff --git a/.github/workflows/license_headers/apache_bat3.txt b/.github/workflows/license_headers/apache_bat3.txt new file mode 100644 index 00000000000..74760ea39a9 --- /dev/null +++ b/.github/workflows/license_headers/apache_bat3.txt @@ -0,0 +1,18 @@ +@echo off + +@rem +@rem +@rem Copyright 2016 CUBRID Corporation +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem diff --git a/.gitignore b/.gitignore index f8bc5ea0792..610245c07e4 100644 --- a/.gitignore +++ b/.gitignore @@ -67,7 +67,7 @@ cm_common/cub_jobsa cm_common/cub_sainfo .installed /java/bin/ -/java/jspserver.jar +/java/pl_server.jar /java/src-jsp/ /java/src/ /msg/*/*.cat diff --git a/CMakeLists.txt b/CMakeLists.txt index a379aba7dc8..be059c6ecac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -831,7 +831,7 @@ add_subdirectory(demo) add_subdirectory(contrib) add_subdirectory(locales) add_subdirectory(timezones) -add_subdirectory(jsp) +add_subdirectory(pl_engine) if(AT_LEAST_ONE_UNIT_TEST) add_subdirectory(unit_tests) endif() diff --git a/cs/CMakeLists.txt b/cs/CMakeLists.txt index c0736b5d556..0bd794bfaf4 100644 --- a/cs/CMakeLists.txt +++ b/cs/CMakeLists.txt @@ -295,6 +295,7 @@ set(JSP_SOURCES 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 @@ -513,7 +514,7 @@ add_library(cubridcs SHARED ) set_target_properties(cubridcs PROPERTIES SOVERSION "${CUBRID_MAJOR_VERSION}.${CUBRID_MINOR_VERSION}") -target_compile_definitions(cubridcs PRIVATE CS_MODE ${COMMON_DEFS}) +target_compile_definitions(cubridcs PRIVATE CS_MODE CUBRID_EXPORTING ${COMMON_DEFS}) if(NOT USE_CUBRID_ENV) target_compile_definitions(cubridcs PRIVATE ${DIR_DEFS}) endif(NOT USE_CUBRID_ENV) diff --git a/cubrid/CMakeLists.txt b/cubrid/CMakeLists.txt index 7a043c2b418..22b0a70e0d7 100644 --- a/cubrid/CMakeLists.txt +++ b/cubrid/CMakeLists.txt @@ -272,8 +272,11 @@ set(JSP_SOURCES ) 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 @@ -518,7 +521,7 @@ if(WIN32) set_target_properties(cubrid PROPERTIES OUTPUT_NAME libcubrid) endif(WIN32) -target_compile_definitions(cubrid PRIVATE SERVER_MODE ${COMMON_DEFS}) +target_compile_definitions(cubrid PRIVATE SERVER_MODE CUBRID_EXPORTING ${COMMON_DEFS}) if(NOT USE_CUBRID_ENV) target_compile_definitions(cubrid PRIVATE ${DIR_DEFS}) endif(NOT USE_CUBRID_ENV) diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index fd4cf4976c1..9dbd42e6314 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -19,7 +19,12 @@ install(FILES ${CMAKE_SOURCE_DIR}/demo/demodb_objects ${CMAKE_SOURCE_DIR}/demo/demodb_schema - DESTINATION ${CUBRID_DEMODIR}) + DESTINATION ${CUBRID_DEMODIR}) + +install(DIRECTORY + ${CMAKE_SOURCE_DIR}/demo/plcsql + DESTINATION ${CUBRID_DEMODIR} +) if(UNIX) set(DEMODB_SCRIPT make_cubrid_demo.sh) diff --git a/demo/plcsql/README.md b/demo/plcsql/README.md new file mode 100644 index 00000000000..f903993bdab --- /dev/null +++ b/demo/plcsql/README.md @@ -0,0 +1,478 @@ +# 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 new file mode 100644 index 00000000000..31d44c652fa --- /dev/null +++ b/demo/plcsql/StmtForStaticSqlLoop-test-without-condition.sql @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..e9d074c592c --- /dev/null +++ b/demo/plcsql/demo_global_semantics_serial.sql @@ -0,0 +1,6 @@ +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 new file mode 100644 index 00000000000..328cfa71687 --- /dev/null +++ b/demo/plcsql/demo_global_semantics_type.sql @@ -0,0 +1,12 @@ +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 new file mode 100644 index 00000000000..f25fecaaf1f --- /dev/null +++ b/demo/plcsql/demo_global_semantics_udpf.sql @@ -0,0 +1,7 @@ +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 new file mode 100644 index 00000000000..d9db0445e52 --- /dev/null +++ b/demo/plcsql/demo_hello.sql @@ -0,0 +1,4 @@ +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 new file mode 100644 index 00000000000..0581d99eeae --- /dev/null +++ b/demo/plcsql/demo_hello_ret.sql @@ -0,0 +1,4 @@ +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 new file mode 100644 index 00000000000..6022a519d05 --- /dev/null +++ b/demo/plcsql/test_ddl.sql @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..0a0be734afd --- /dev/null +++ b/demo/plcsql/test_dml_delete.sql @@ -0,0 +1,27 @@ +/* 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 new file mode 100644 index 00000000000..cc94cefaf17 --- /dev/null +++ b/demo/plcsql/test_dml_insert.sql @@ -0,0 +1,77 @@ +/* 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 new file mode 100644 index 00000000000..c15666cc59e --- /dev/null +++ b/demo/plcsql/test_dml_truncate.sql @@ -0,0 +1,8 @@ +/* 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 new file mode 100644 index 00000000000..c87a288df2a --- /dev/null +++ b/demo/plcsql/test_query_cursor_hostvar.sql @@ -0,0 +1,22 @@ +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 new file mode 100644 index 00000000000..75c86dc67e8 --- /dev/null +++ b/demo/plcsql/test_query_cursor_simple.sql @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..3f0ca2a8b3d --- /dev/null +++ b/demo/plcsql/test_query_cursor_simple_nocond.sql @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..fa20469f932 --- /dev/null +++ b/demo/plcsql/test_query_single_row.sql @@ -0,0 +1,16 @@ +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 new file mode 100644 index 00000000000..02c8fe4c59b --- /dev/null +++ b/demo/plcsql/test_query_single_row_const.sql @@ -0,0 +1,14 @@ +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 new file mode 100644 index 00000000000..942665b2f8f --- /dev/null +++ b/demo/plcsql/test_semantic_error_unknown_tbl.sql @@ -0,0 +1,4 @@ +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 new file mode 100644 index 00000000000..1577716389a --- /dev/null +++ b/demo/plcsql/test_semantic_error_wrong_literal.sql @@ -0,0 +1,7 @@ +/* + 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 new file mode 100644 index 00000000000..5b5dca1fa68 --- /dev/null +++ b/demo/plcsql/test_tcl_commit.sql @@ -0,0 +1,30 @@ +/* +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 new file mode 100644 index 00000000000..64304b7a9b0 --- /dev/null +++ b/demo/plcsql/test_tcl_rollback.sql @@ -0,0 +1,45 @@ +/* +=====[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/jsp/CMakeLists.txt b/jsp/CMakeLists.txt deleted file mode 100644 index a3500952f33..00000000000 --- a/jsp/CMakeLists.txt +++ /dev/null @@ -1,72 +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. -# -# -include(FindJava) -find_package(Java 1.6 COMPONENTS Development) - -find_program(ANT ant PATHS $ENV{ANT_HOME} ENV PATH) -if(NOT ANT) - message(FATAL_ERROR "The ANT was not found. check PATH or install ant to build JDBC") -endif(NOT ANT) - -add_custom_target(jsp_build ALL) - -if (EXISTS ${CMAKE_SOURCE_DIR}/cubrid-jdbc/src) - set(JDBC_DIR ${CMAKE_SOURCE_DIR}/cubrid-jdbc) - set(JSP_LIB_DIR ${CMAKE_BINARY_DIR}/jsp/lib) - - add_custom_command(TARGET jsp_build - COMMAND ${CMAKE_COMMAND} -E make_directory ${JSP_LIB_DIR} - COMMAND ${CMAKE_COMMAND} -DJDBC_DIR=${JDBC_DIR} -DJSP_LIB_DIR=${JSP_LIB_DIR} -P ${CMAKE_SOURCE_DIR}/jsp/cmake/copy_submodule_jdbc.cmake - ) - - add_dependencies(jsp_build jdbc_build) -endif(EXISTS ${CMAKE_SOURCE_DIR}/cubrid-jdbc/src) - -# download ivy -message("Download ivy ...") -set(IVY_VERSION "2.4.0") -set(IVY_URL "https://archive.apache.org/dist/ant/ivy/${IVY_VERSION}/maven2/${IVY_VERSION}/ivy-${IVY_VERSION}.jar") -set(IVY_DIR "${CMAKE_BINARY_DIR}/jsp/external") -set(IVY_FILENAME "${IVY_DIR}/ivy.jar") -file(DOWNLOAD ${IVY_URL} ${IVY_FILENAME}) - -add_custom_command(TARGET jsp_build - COMMAND ${CMAKE_COMMAND} -E echo "copying ivy.xml to ${CMAKE_BINARY_DIR}/jsp/ivy.xml" - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/jsp/ivy.xml ${CMAKE_BINARY_DIR}/jsp/ivy.xml - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/jsp/ivysettings.xml ${CMAKE_BINARY_DIR}/jsp/ivysettings.xml - COMMAND ${ANT} dist -buildfile ${CMAKE_SOURCE_DIR}/jsp/build.xml -Dbasedir=. -Dversion=${BUILD_NUMBER} -Dsrc.dir=${JSP_DIR} -Divy.install.dir="${IVY_DIR}" - COMMENT "Build Java SP Server with Ant ..." -) - -add_custom_target(jsp_unittest) -add_custom_command(TARGET jsp_unittest - COMMAND ${ANT} test-junit -buildfile ${CMAKE_SOURCE_DIR}/jsp/build.xml -Dbasedir=. -Dversion=${BUILD_NUMBER} -Dsrc.dir=${JSP_DIR} -Divy.install.dir="${IVY_DIR}" - COMMENT "Unit Test Java SP Server with JUnit ..." -) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/jspserver.jar - ${JSP_DIR}/logging.properties - DESTINATION ${CUBRID_JAVADIR} -) - -install(DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/lib/ - DESTINATION ${CUBRID_JAVADIR}/lib - FILES_MATCHING PATTERN "*.jar" -) diff --git a/jsp/build.xml b/jsp/build.xml deleted file mode 100644 index 8fed82736ff..00000000000 --- a/jsp/build.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jsp/ivy.xml b/jsp/ivy.xml deleted file mode 100644 index 0bd0c40f03d..00000000000 --- a/jsp/ivy.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/jsp/ivysettings.xml b/jsp/ivysettings.xml deleted file mode 100644 index e2b72d20e36..00000000000 --- a/jsp/ivysettings.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/msg/de_DE.utf8/cubrid.msg b/msg/de_DE.utf8/cubrid.msg index 6bdfa12e374..1fb6a8f1114 100644 --- a/msg/de_DE.utf8/cubrid.msg +++ b/msg/de_DE.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ $ LOADDB 1358 Die Anzahl der betroffenen Zeilen ist unbekannt. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Letzter Fehler +1361 Letzter Fehler $set 6 MSGCAT_SET_INTERNAL 1 Fehler in Fehler-Subsystem (Zeile %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 Ungültiges create Benutzer\n CREATE BENUTZER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 Ungültiges create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 Ungültiges create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 Ungültiges create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 Ungültiges create Funktion\n CREATE FUNKTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 Ungültiges create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 Ungültiges create Funktion\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 Ungültiges groups\n groups spec: GROUPS identifier {, identifier}* 37 Ungültiges members\n member spec: MEMBERS identifier {, identifier}* 38 Ungültiges password\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Außer virtuellem Speicher: %1$d Bytes können nicht zugewiesen werden. diff --git a/msg/de_DE.utf8/utils.msg b/msg/de_DE.utf8/utils.msg index 8c941619b47..00182234623 100644 --- a/msg/de_DE.utf8/utils.msg +++ b/msg/de_DE.utf8/utils.msg @@ -915,6 +915,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite Klassendatei, wenn vorhanden, überschreiben, Standard nein\n\ + -p, --package Java-Paketname, leer, wenn nicht angegeben\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/en_US.utf8/cubrid.msg b/msg/en_US.utf8/cubrid.msg index 406dfc61edd..29ee3cafd22 100644 --- a/msg/en_US.utf8/cubrid.msg +++ b/msg/en_US.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1358 Number of rows affected is unknown. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Last Error +1361 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 invalid create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 invalid create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 invalid create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 invalid create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 invalid create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 invalid create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 invalid create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 invalid groups\n groups spec: GROUPS identifier {, identifier}* 37 invalid members\n member spec: MEMBERS identifier {, identifier}* 38 invalid password\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. diff --git a/msg/en_US.utf8/utils.msg b/msg/en_US.utf8/utils.msg index 4138e2bb090..d39c1903c1d 100644 --- a/msg/en_US.utf8/utils.msg +++ b/msg/en_US.utf8/utils.msg @@ -916,6 +916,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite overwrite class file if exist, default no\n\ + -p, --package java package name, empty if not specified\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/en_US/cubrid.msg b/msg/en_US/cubrid.msg index a374f63c74e..dacb8ee924f 100644 --- a/msg/en_US/cubrid.msg +++ b/msg/en_US/cubrid.msg @@ -1445,8 +1445,9 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1358 Number of rows affected is unknown. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Last Error +1361 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1508,8 +1509,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 invalid create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 invalid create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 invalid create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 invalid create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 invalid create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 invalid create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 invalid create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 invalid groups\n groups spec: GROUPS identifier {, identifier}* 37 invalid members\n member spec: MEMBERS identifier {, identifier}* 38 invalid password\n password spec: PASSWORD 'STRING' @@ -1931,6 +1932,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. diff --git a/msg/en_US/utils.msg b/msg/en_US/utils.msg index 016e3a52f13..f8f60d43ef1 100644 --- a/msg/en_US/utils.msg +++ b/msg/en_US/utils.msg @@ -916,6 +916,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite overwrite class file if exist, default no\n\ + -p, --package java package name, empty if not specified\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/es_ES.utf8/cubrid.msg b/msg/es_ES.utf8/cubrid.msg index 6b041d5690c..28477edff4e 100644 --- a/msg/es_ES.utf8/cubrid.msg +++ b/msg/es_ES.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ Verifique la ruta del archivo de claves (_keys) y asegúrese de que incluya la c 1358 Se desconoce el número de filas afectadas. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Ultimo error +1361 Ultimo error $set 6 MSGCAT_SET_INTERNAL 1 Error en subsistema de error (linea %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 Crear utilizador no valido\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 Crear trigger no valido\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 Crear serial no valido\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 Crear procedimiento no valido\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 Crear funcion no valido\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 Crear procedimiento no valido\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 Crear funcion no valido\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 Grupos no validos\n groups spec: GROUPS identifier {, identifier}* 37 Miembros no validos\n member spec: MEMBERS identifier {, identifier}* 38 Contraseña no valida\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Sin memoria virtual: incapaz de asignar %1$d bytes. diff --git a/msg/es_ES.utf8/utils.msg b/msg/es_ES.utf8/utils.msg index 0ba442f4de8..cb63fdfe8e8 100644 --- a/msg/es_ES.utf8/utils.msg +++ b/msg/es_ES.utf8/utils.msg @@ -915,6 +915,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite sobrescribir archivo de clase si existe, estandar no\n\ + -p, --package nombre del paquete java, vacío si no se especifica\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/fr_FR.utf8/cubrid.msg b/msg/fr_FR.utf8/cubrid.msg index 97d482d6881..4a7bfcf03b0 100644 --- a/msg/fr_FR.utf8/cubrid.msg +++ b/msg/fr_FR.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ Vérifiez le chemin du fichier de clé (_keys) et assurez-vous qu'il inclut la c 1358 Le nombre de lignes affectées est inconnu. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Dernière erreur +1361 Dernière erreur $set 6 MSGCAT_SET_INTERNAL 1 Erreur dans le sous-système d'erreur (ligne %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 instruction non valide: create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 instruction non valide: create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 instruction non valide: create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 instruction non valide: create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 instruction non valide: create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 instruction non valide: create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 instruction non valide: create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 instruction non valide: groups\n groups spec: GROUPS identifier {, identifier}* 37 instruction non valide: members\n member spec: MEMBERS identifier {, identifier}* 38 instruction non valide: password\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Mémoire virtuelle épuisée: impossible d'allouer %1$d octets. diff --git a/msg/fr_FR.utf8/utils.msg b/msg/fr_FR.utf8/utils.msg index f401c825120..b077cdcf617 100644 --- a/msg/fr_FR.utf8/utils.msg +++ b/msg/fr_FR.utf8/utils.msg @@ -918,6 +918,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite remplace le fichier de classe si lui existe, par défaut non\n\ + -p, --package nom du package java, vide s'il n'est pas spécifié\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/it_IT.utf8/cubrid.msg b/msg/it_IT.utf8/cubrid.msg index fc1e77f23d7..dac6ef310b9 100644 --- a/msg/it_IT.utf8/cubrid.msg +++ b/msg/it_IT.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ Controllare il percorso del file della chiave (_keys) e assicurarsi che includa 1358 Il numero di righe interessate è sconosciuto. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Ultimo errore +1361 Ultimo errore $set 6 MSGCAT_SET_INTERNAL 1 Errore nel sottosistema di errore (linea %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 Istruzione non valida "create user"\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 Istruzione non valida "create trigger"\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition} EXECUTE {AFTER|DEFERRED} trigger_action 33 Istruzione non valida "create serial"\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 Istruzione non valida "create procedure"\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 Istruzione non valida "create function"\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 Istruzione non valida "create procedure"\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 Istruzione non valida "create function"\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 Istruzione non valida "groups"\n groups spec: GROUPS identifier {, identifier}* 37 Istruzione non valida "members"\n member spec: MEMBERS identifier {, identifier}* 38 Istruzione non valida "password"\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Fuori di memoria virtuale: Impossibile allocare %1$d byte. diff --git a/msg/it_IT.utf8/utils.msg b/msg/it_IT.utf8/utils.msg index 5bc6ae9fb31..291fd39a8a4 100644 --- a/msg/it_IT.utf8/utils.msg +++ b/msg/it_IT.utf8/utils.msg @@ -915,6 +915,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite sovrascrivere class file, se esiste, niente predefinito\n\ + -p, --package nome pacchetto java, vuoto se non specificato\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/ja_JP.utf8/cubrid.msg b/msg/ja_JP.utf8/cubrid.msg index 944c3abd574..4f693b70096 100644 --- a/msg/ja_JP.utf8/cubrid.msg +++ b/msg/ja_JP.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ $ LOADDB 1358 影響をå—ã‘る行数ã¯ä¸æ˜Žã§ã™ã€‚ 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 ラストエラー +1361 ラストエラー $set 6 MSGCAT_SET_INTERNAL 1 エラーサブシステムã«ã‚¨ãƒ©ãƒ¼ç™ºç”Ÿ(ライン %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 æ­£ã—ããªã„create userステートメントã§ã™ã€‚\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 æ­£ã—ããªã„create triggerステートメントã§ã™ã€‚\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 æ­£ã—ããªã„create シリアルステートメントã§ã™ã€‚\n CREATE シリアル identifier {START WITH integer} {INCREMENT BY integer}\n シリアル_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 æ­£ã—ããªã„create procedureステートメントã§ã™ã€‚\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 æ­£ã—ããªã„create functionステートメントã§ã™ã€‚\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 æ­£ã—ããªã„create procedureステートメントã§ã™ã€‚\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 æ­£ã—ããªã„create functionステートメントã§ã™ã€‚\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 æ­£ã—ããªã„groupsステートメントã§ã™ã€‚\n groups spec: GROUPS identifier {, identifier}* 37 æ­£ã—ããªã„membersステートメントã§ã™ã€‚\n member spec: MEMBERS identifier {, identifier}* 38 æ­£ã—ããªã„passwordステートメントã§ã™ã€‚\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 ãƒãƒãƒ£ãƒ¼ãƒ«ãƒ¡ãƒ¢ãƒªãƒ¼ãŒè¶³ã‚Šã¾ã›ã‚“。: %1$dãƒã‚¤ãƒˆãŒã‚¢ãƒ­ã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã§ãã¾ã›ã‚“。 diff --git a/msg/ja_JP.utf8/utils.msg b/msg/ja_JP.utf8/utils.msg index d232e45aa0a..0d4ada2ddaf 100644 --- a/msg/ja_JP.utf8/utils.msg +++ b/msg/ja_JP.utf8/utils.msg @@ -915,6 +915,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite クラスファイルãŒã‚‚ã†å­˜åœ¨ã—ãŸã‚‰ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒˆã™ã‚‹ã€‚; デフォルト: オーãƒãƒ¼ãƒ©ã‚¤ãƒˆã—ãªã„\n\ + -p, --package Javaパッケージåã€æŒ‡å®šã•ã‚Œã¦ã„ãªã„å ´åˆã¯ç©º\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/km_KH.utf8/cubrid.msg b/msg/km_KH.utf8/cubrid.msg index 7072353024e..c7c699208a3 100644 --- a/msg/km_KH.utf8/cubrid.msg +++ b/msg/km_KH.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1358 Number of rows affected is unknown. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Last Error +1361 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 invalid create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 invalid create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 invalid create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 invalid create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 invalid create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 invalid create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 invalid create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 invalid groups\n groups spec: GROUPS identifier {, identifier}* 37 invalid members\n member spec: MEMBERS identifier {, identifier}* 38 invalid password\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. diff --git a/msg/km_KH.utf8/utils.msg b/msg/km_KH.utf8/utils.msg index 9bdb0de1351..8772b601318 100644 --- a/msg/km_KH.utf8/utils.msg +++ b/msg/km_KH.utf8/utils.msg @@ -917,6 +917,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite overwrite class file if exist, default no\n\ + -p, --package java package name, empty if not specified\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/ko_KR.euckr/cubrid.msg b/msg/ko_KR.euckr/cubrid.msg index f00cb98177e..c81017672bb 100644 --- a/msg/ko_KR.euckr/cubrid.msg +++ b/msg/ko_KR.euckr/cubrid.msg @@ -1444,8 +1444,9 @@ $ LOADDB 1358 ¿µÇâÀ» ¹ÞÀº Çà ¼ö¸¦ ¾Ë ¼ö ¾øÀ½. 1359 Java VM ¿¡ Àå¾Ö°¡ ¹ß»ýÇÔ. : %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 ¸¶Áö¸· ¿¡·¯ +1361 ¸¶Áö¸· ¿¡·¯ $set 6 MSGCAT_SET_INTERNAL 1 ¿¡·¯ ¼­ºê ½Ã½ºÅÛ¿¡ ¿¡·¯ ¹ß»ý(¶óÀÎ %1$d): @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 µ¿ÀǾî "%1$s"ÀÌ(°¡) Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù. 315 À̸§ ¹Ù²Ù±â´Â ¼ÒÀ¯ÀÚ¸¦ º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù. 316 À̸§ ¹Ù²Ù±â´Â °°Àº À̸§À¸·Î º¯°æÇÒ ¼ö ¾ø½À´Ï´Ù. +317 ½Äº°ÀÚ´Â LIMIT Àý ¾È¿¡ ÀÖÀ» ¼ö ¾ø½À´Ï´Ù. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 °¡»ó ¸Þ¸ð¸® ¾øÀ½: %1$d ¹ÙÀÌÆ®¸¦ ÇÒ´çÇÒ ¼ö ¾ø½À´Ï´Ù. diff --git a/msg/ko_KR.euckr/utils.msg b/msg/ko_KR.euckr/utils.msg index b50b8f07645..a49b2c85f42 100644 --- a/msg/ko_KR.euckr/utils.msg +++ b/msg/ko_KR.euckr/utils.msg @@ -915,6 +915,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite Ŭ·¡½º ÆÄÀÏÀÌ ÀÌ¹Ì Á¸ÀçÇÏ¸é µ¤¾î¾¸; ±âº»°ª: µ¤¾î¾²Áö ¾ÊÀ½\n\ + -p, --package Java ÆÐÅ°Áö À̸§; ÁöÁ¤ÇÏÁö ¾ÊÀ¸¸é ºó ¹®ÀÚ¿­\n\ -j, --jni JNI »ç¿ëÀ» À§ÇØ Á¤Àû ·Îµù ¿µ¿ª¿¡ Ŭ·¡½º ¶Ç´Â Jar¸¦ Ãß°¡ÇÔ\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/ko_KR.utf8/cubrid.msg b/msg/ko_KR.utf8/cubrid.msg index b947be8afcd..e3e32c456bb 100644 --- a/msg/ko_KR.utf8/cubrid.msg +++ b/msg/ko_KR.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ $ LOADDB 1358 ì˜í–¥ì„ ë°›ì€ í–‰ 수를 ì•Œ 수 ì—†ìŒ. 1359 Java VM ì— ìž¥ì• ê°€ ë°œìƒí•¨. : %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 마지막 ì—러 +1361 마지막 ì—러 $set 6 MSGCAT_SET_INTERNAL 1 ì—러 서브 ì‹œìŠ¤í…œì— ì—러 ë°œìƒ(ë¼ì¸ %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 ìž˜ëª»ëœ í˜•ì‹ì˜ create user 구문입니다.\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 ìž˜ëª»ëœ í˜•ì‹ì˜ create trigger 구문입니다.\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 ìž˜ëª»ëœ í˜•ì‹ì˜ create serial 구문입니다.\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 ìž˜ëª»ëœ í˜•ì‹ì˜ create procedure 구문입니다.\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 ìž˜ëª»ëœ í˜•ì‹ì˜ create function 구문입니다.\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 ìž˜ëª»ëœ í˜•ì‹ì˜ create procedure 구문입니다.\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 ìž˜ëª»ëœ í˜•ì‹ì˜ create function 구문입니다.\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 ìž˜ëª»ëœ í˜•ì‹ì˜ groups 구문입니다.\n groups spec: GROUPS identifier {, identifier}* 37 ìž˜ëª»ëœ í˜•ì‹ì˜ members 구문입니다.\n member spec: MEMBERS identifier {, identifier}* 38 ìž˜ëª»ëœ í˜•ì‹ì˜ password 구문입니다.\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 ë™ì˜ì–´ "%1$s"ì´(ê°€) 존재하지 않습니다. 315 ì´ë¦„ 바꾸기는 소유ìžë¥¼ 변경할 수 없습니다. 316 ì´ë¦„ 바꾸기는 ê°™ì€ ì´ë¦„으로 변경할 수 없습니다. +317 ì‹ë³„ìžëŠ” LIMIT ì ˆ ì•ˆì— ìžˆì„ ìˆ˜ 없습니다. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 ê°€ìƒ ë©”ëª¨ë¦¬ ì—†ìŒ: %1$d ë°”ì´íŠ¸ë¥¼ 할당할 수 없습니다. diff --git a/msg/ko_KR.utf8/utils.msg b/msg/ko_KR.utf8/utils.msg index 00c376283b7..1c02ba7556f 100644 --- a/msg/ko_KR.utf8/utils.msg +++ b/msg/ko_KR.utf8/utils.msg @@ -913,6 +913,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite í´ëž˜ìŠ¤ 파ì¼ì´ ì´ë¯¸ 존재하면 ë®ì–´ì”€; 기본값: ë®ì–´ì“°ì§€ ì•ŠìŒ\n\ + -p, --package Java 패키지 ì´ë¦„; 지정하지 않으면 빈 문ìžì—´\n\ -j, --jni JNI ì‚¬ìš©ì„ ìœ„í•´ ì •ì  ë¡œë”© ì˜ì—­ì— í´ëž˜ìŠ¤ ë˜ëŠ” Jar를 추가함\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/ro_RO.utf8/cubrid.msg b/msg/ro_RO.utf8/cubrid.msg index c49db51dc57..46d111804dc 100644 --- a/msg/ro_RO.utf8/cubrid.msg +++ b/msg/ro_RO.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ VerificaÈ›i calea fiÈ™ierului cheie (_keys) È™i asiguraÈ›i-vă că acesta includ 1358 Numărul de rânduri afectate este necunoscut. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Ultima eroare +1361 Ultima eroare $set 6 MSGCAT_SET_INTERNAL 1 Eroare în subsistemul de erori (linia %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 instrucÅ£iune invalidă: create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 instrucÅ£iune invalidă: create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 instrucÅ£iune invalidă: create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 instrucÅ£iune invalidă: create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 instrucÅ£iune invalidă: create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 instrucÅ£iune invalidă: create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 instrucÅ£iune invalidă: create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 instrucÅ£iune invalidă: groups\n groups spec: GROUPS identifier {, identifier}* 37 instrucÅ£iune invalidă: members\n member spec: MEMBERS identifier {, identifier}* 38 instrucÅ£iune invalidă: password\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Memorie virtuală epuizată: nu s-au putut aloca %1$d bytes. diff --git a/msg/ro_RO.utf8/utils.msg b/msg/ro_RO.utf8/utils.msg index aa363f9921d..3c968d7a54b 100644 --- a/msg/ro_RO.utf8/utils.msg +++ b/msg/ro_RO.utf8/utils.msg @@ -932,6 +932,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite suprascrie fiÅŸierul de clasă dacă exista, implicit nu\n\ + -p, --package Numele pachetului Java, gol dacă nu este specificat\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/tr_TR.utf8/cubrid.msg b/msg/tr_TR.utf8/cubrid.msg index 621f66ba7a8..10e179ea88c 100644 --- a/msg/tr_TR.utf8/cubrid.msg +++ b/msg/tr_TR.utf8/cubrid.msg @@ -1444,8 +1444,9 @@ Anahtar dosyasının (_keys) yolunu kontrol edin ve uygun anahtarı içerdiÄŸind 1358 Etkilenen satır sayısı bilinmiyor. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Son Hata +1361 Son Hata $set 6 MSGCAT_SET_INTERNAL 1 Alt Hata içinde hata (satır %1$d): @@ -1507,8 +1508,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 geçersiz create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 geçersiz create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 geçersiz create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 geçersiz create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 geçersiz create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 geçersiz create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 geçersiz create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 geçersiz groups\n groups spec: GROUPS identifier {, identifier}* 37 geçersiz members\n member spec: MEMBERS identifier {, identifier}* 38 geçersiz password\n password spec: PASSWORD 'STRING' @@ -1930,6 +1931,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Sanal bellek yetersiz: %1$d bayt bölüm ayıramadı. diff --git a/msg/tr_TR.utf8/utils.msg b/msg/tr_TR.utf8/utils.msg index 34a79a1d97f..980af904340 100644 --- a/msg/tr_TR.utf8/utils.msg +++ b/msg/tr_TR.utf8/utils.msg @@ -915,6 +915,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite varsa sınıf dosyanın üzerine yazmak, varsayılan yok\n\ + -p, --package Java paket adı, belirtilmemiÅŸse boÅŸ\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/vi_VN.utf8/cubrid.msg b/msg/vi_VN.utf8/cubrid.msg index 1592070be66..4ba4950ea02 100644 --- a/msg/vi_VN.utf8/cubrid.msg +++ b/msg/vi_VN.utf8/cubrid.msg @@ -1451,8 +1451,9 @@ Check the path of the key file (_keys) and make sure that it includes proper key 1358 Number of rows affected is unknown. 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 Last Error +1361 Last Error $set 6 MSGCAT_SET_INTERNAL 1 Error in error subsystem (line %1$d): @@ -1514,8 +1515,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 invalid create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 invalid create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 invalid create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 invalid create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 invalid create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 invalid create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 invalid create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 invalid groups\n groups spec: GROUPS identifier {, identifier}* 37 invalid members\n member spec: MEMBERS identifier {, identifier}* 38 invalid password\n password spec: PASSWORD 'STRING' @@ -1937,6 +1938,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 Out of virtual memory: unable to allocate %1$d bytes. diff --git a/msg/vi_VN.utf8/utils.msg b/msg/vi_VN.utf8/utils.msg index 2afcb616aac..5b7ee0a3e26 100644 --- a/msg/vi_VN.utf8/utils.msg +++ b/msg/vi_VN.utf8/utils.msg @@ -917,6 +917,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite overwrite class file if exist, default no\n\ + -p, --package java package name, empty if not specified\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/msg/zh_CN.utf8/cubrid.msg b/msg/zh_CN.utf8/cubrid.msg index db33d149f4e..97c91fc89f2 100644 --- a/msg/zh_CN.utf8/cubrid.msg +++ b/msg/zh_CN.utf8/cubrid.msg @@ -1445,8 +1445,9 @@ $ LOADDB 1358 å—å½±å“的行数未知。 1359 Java VM crashed: %1$s +1360 In line %1$d, column %2$d\nStored procedure compile error: %3$s -1360 最åŽä¸€ä¸ªé”™è¯¯. +1361 最åŽä¸€ä¸ªé”™è¯¯. $set 6 MSGCAT_SET_INTERNAL 1 在错误å­ç³»ç»Ÿä¸­é”™è¯¯ (line %1$d): @@ -1508,8 +1509,8 @@ $set 7 MSGCAT_SET_PARSER_SYNTAX 31 无效的 create user\n CREATE USER identifier {PASSWORD 'STRING'} {GROUPS identifier {, identifier}* } {MEMBERS identifier {, identifier}* } 32 无效的 create trigger\n CREATE TRIGGER identifier {STATE [ACTIVE|INACTIVE]} {PRIORITY unsigned_real}\n [BEFORE|AFTER|DEFERRED] event_spec {IF trigger_condition}\n EXECUTE {AFTER|DEFERRED} trigger_action 33 无效的 create serial\n CREATE SERIAL identifier {START WITH integer} {INCREMENT BY integer}\n serial_min_max {CYCLE|NOCYCLE} {CACHE unsigned_integer|NOCACHE} -34 无效的 create procedure\n CREATE PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} LANGUAGE JAVA NAME 'STRING' -35 无效的 create function\n CREATE FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} LANGUAGE JAVA NAME 'STRING' +34 无效的 create procedure\n CREATE [OR REPLACE] PROCEDURE identifier '(' {sp_param_list} ')' {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {procedure_source|procedure_spec} +35 无效的 create function\n CREATE [OR REPLACE] FUNCTION identifier '(' {sp_param_list} ')' RETURN {data_type|CURSOR} {IS|AS} {[LANGUAGE PLCSQL|LANGUAGE JAVA]} {function_source|function_spec} 36 无效的组\n groups spec: GROUPS identifier {, identifier}* 37 无效的æˆå‘˜\n member spec: MEMBERS identifier {, identifier}* 38 无效的密ç \n password spec : PASSWORD 'STRING' @@ -1931,6 +1932,7 @@ $set 8 MSGCAT_SET_PARSER_SEMANTIC 314 Synonym "%1$s" does not exist. 315 Rename cannot change owner. 316 Rename cannot be changed to the same name. +317 Identifiers cannot be in a LIMIT clause. $set 9 MSGCAT_SET_PARSER_RUNTIME 1 虚拟内存耗尽: 无法申请 %1$d 字节. diff --git a/msg/zh_CN.utf8/utils.msg b/msg/zh_CN.utf8/utils.msg index 8c49006ad83..16f19d84f14 100644 --- a/msg/zh_CN.utf8/utils.msg +++ b/msg/zh_CN.utf8/utils.msg @@ -914,6 +914,7 @@ Usage: loadjava [OPTION] database-name java-class-file\n\ \n\ valid options:\n\ -y, --overwrite 如果类存在则进行é‡å†™, 默认 ä¸\n\ + -p, --package Java包å,ä¸æŒ‡å®šåˆ™ä¸ºç©º\n\ -j, --jni add a Class or Jar to static loading for JNI\n $set 37 MSGCAT_UTIL_SET_PLANDUMP diff --git a/pl_engine/.gitattributes b/pl_engine/.gitattributes new file mode 100644 index 00000000000..097f9f98d9e --- /dev/null +++ b/pl_engine/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/pl_engine/.gitignore b/pl_engine/.gitignore new file mode 100644 index 00000000000..4a305d7d24a --- /dev/null +++ b/pl_engine/.gitignore @@ -0,0 +1,6 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build +bin \ No newline at end of file diff --git a/pl_engine/CMakeLists.txt b/pl_engine/CMakeLists.txt new file mode 100644 index 00000000000..86020ea20d1 --- /dev/null +++ b/pl_engine/CMakeLists.txt @@ -0,0 +1,65 @@ +# +# 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. +# +# +include(FindJava) +find_package(Java 1.6 COMPONENTS Development) + +set(PL_ENGINE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/pl_engine) +set(PL_ENGINE_BUILD_DIR ${CMAKE_BINARY_DIR}/pl_engine) + +# Find gradlew +if(UNIX) + set(GRADLE_EXECUTABLE ${PL_ENGINE_SOURCE_DIR}/gradlew) +else(UNIX) + set(GRADLE_EXECUTABLE ${PL_ENGINE_SOURCE_DIR}/gradlew.bat) +endif(UNIX) + +set(LOCAL_JDBC_PATH_COMMAND) + +add_custom_target(pl_build ALL) + +if (EXISTS ${CMAKE_SOURCE_DIR}/cubrid-jdbc/src) + set(JDBC_DIR ${CMAKE_SOURCE_DIR}/cubrid-jdbc) + set(PL_LIB_DIR ${PL_ENGINE_BUILD_DIR}/lib) + + add_custom_command(TARGET pl_build + COMMAND ${CMAKE_COMMAND} -E make_directory ${PL_LIB_DIR} + COMMAND ${CMAKE_COMMAND} -DJDBC_DIR=${JDBC_DIR} -DPL_LIB_DIR=${PL_LIB_DIR} -P ${PL_ENGINE_SOURCE_DIR}/cmake/copy_submodule_jdbc.cmake + ) + + set(LOCAL_JDBC_PATH_COMMAND "-PcubridJdbcPath=${PL_LIB_DIR}") + message ("Add cubrid jdbc dependency from cubrid-jdbc submodule path: ${LOCAL_JDBC_PATH_COMMAND}") + + add_dependencies(pl_build jdbc_build) +endif(EXISTS ${CMAKE_SOURCE_DIR}/cubrid-jdbc/src) + +add_custom_command(TARGET pl_build + COMMAND ${CMAKE_COMMAND} -E make_directory ${PL_ENGINE_BUILD_DIR} + COMMAND ${GRADLE_EXECUTABLE} build -x test -p ${PL_ENGINE_SOURCE_DIR} -PbuildDir=${PL_ENGINE_BUILD_DIR} ${LOCAL_JDBC_PATH_COMMAND} +) + +add_custom_target(pl_unittest) +add_custom_command(TARGET pl_unittest + COMMAND ${GRADLE_EXECUTABLE} cleanTest test -p ${PL_ENGINE_SOURCE_DIR} -DbuildDir=${PL_ENGINE_BUILD_DIR} ${LOCAL_JDBC_PATH_COMMAND} +) +add_dependencies(pl_unittest pl_build) + +install(FILES + ${PL_ENGINE_BUILD_DIR}/libs/pl_server.jar + ${PL_ENGINE_BUILD_DIR}/resources/main/logging.properties + DESTINATION ${CUBRID_JAVADIR} +) \ No newline at end of file diff --git a/jsp/cmake/copy_submodule_jdbc.cmake b/pl_engine/cmake/copy_submodule_jdbc.cmake similarity index 81% rename from jsp/cmake/copy_submodule_jdbc.cmake rename to pl_engine/cmake/copy_submodule_jdbc.cmake index 875d8273bb6..52b6acfaf04 100644 --- a/jsp/cmake/copy_submodule_jdbc.cmake +++ b/pl_engine/cmake/copy_submodule_jdbc.cmake @@ -21,9 +21,9 @@ message ("[INFO] JDBC Driver built at cubrid-jdbc submodule") set(JDBC_VERSION_FILE ${JDBC_DIR}/output/VERSION-DIST) file(STRINGS ${JDBC_VERSION_FILE} JDBC_VERSION_STR) execute_process ( - COMMAND ${CMAKE_COMMAND} -E copy ${JDBC_DIR}/JDBC-${JDBC_VERSION_STR}-cubrid.jar ${JSP_LIB_DIR}/cubrid-jdbc-${JDBC_VERSION_STR}.jar + COMMAND ${CMAKE_COMMAND} -E copy ${JDBC_DIR}/JDBC-${JDBC_VERSION_STR}-cubrid.jar ${PL_LIB_DIR}/cubrid-jdbc-${JDBC_VERSION_STR}.jar ) -if (NOT EXISTS ${JSP_LIB_DIR}/cubrid-jdbc-${JDBC_VERSION_STR}.jar) +if (NOT EXISTS ${PL_LIB_DIR}/cubrid-jdbc-${JDBC_VERSION_STR}.jar) message (FATAL_ERROR "Could not copy JDBC driver") -endif (NOT EXISTS ${JSP_LIB_DIR}/cubrid-jdbc-${JDBC_VERSION_STR}.jar) +endif (NOT EXISTS ${PL_LIB_DIR}/cubrid-jdbc-${JDBC_VERSION_STR}.jar) diff --git a/pl_engine/gradle/wrapper/gradle-wrapper.jar b/pl_engine/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..c1962a79e29d3e0ab67b14947c167a862655af9b GIT binary patch literal 62076 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 literal 0 HcmV?d00001 diff --git a/pl_engine/gradle/wrapper/gradle-wrapper.properties b/pl_engine/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..37aef8d3f0c --- /dev/null +++ b/pl_engine/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/pl_engine/gradlew b/pl_engine/gradlew new file mode 100755 index 00000000000..dafd1297742 --- /dev/null +++ b/pl_engine/gradlew @@ -0,0 +1,245 @@ +#!/bin/sh +# +# +# 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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/pl_engine/gradlew.bat b/pl_engine/gradlew.bat new file mode 100644 index 00000000000..dbe840bb8c7 --- /dev/null +++ b/pl_engine/gradlew.bat @@ -0,0 +1,95 @@ +@echo off + +@rem +@rem +@rem Copyright 2016 CUBRID Corporation +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pl_engine/pl_server/build.gradle.kts b/pl_engine/pl_server/build.gradle.kts new file mode 100644 index 00000000000..8ee0fbf52c2 --- /dev/null +++ b/pl_engine/pl_server/build.gradle.kts @@ -0,0 +1,150 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java application project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/8.1.1/userguide/building_java_projects.html + */ + +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent + +plugins { + // Apply the application plugin to add support for building a CLI application in Java. + antlr + java + application +} + +repositories { + mavenLocal() + + // Use Maven Central for resolving dependencies. + mavenCentral() + + // CUBRID JDBC + var jdbc_path = project.properties["cubridJdbcPath"] + if (jdbc_path != null) { + // find cubrid-jdbc in local submodule path + flatDir { + dirs("$jdbc_path") + } + } else { + // find in cubrid's artifactory repository + maven { + url = uri("http://maven.cubrid.org/") + isAllowInsecureProtocol = true + } + } +} + +dependencies { + // Use JUnit Jupiter for testing. + testImplementation("org.junit.jupiter:junit-jupiter:5.9.1") + + // Unix Domain Socket + implementation("com.kohlschutter.junixsocket:junixsocket-core:2.8.3") + implementation("com.kohlschutter.junixsocket:junixsocket-server:2.8.3") + + // ANTLR + antlr("org.antlr:antlr4:4.9.3") + + 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("org.antlr:antlr4-runtime:4.9.3") + + // CUBRID JDBC + implementation("cubrid:cubrid-jdbc:latest.integration") + + // netty + implementation("io.netty:netty-buffer:4.1.95.Final") +} + +// Antlr +tasks.generateGrammarSource { + // outputDirectory = file("${project.buildDir}/generated-src/antlr") + arguments = arguments + listOf("-listener","-visitor") +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(8)) + } +} + +application { + // Define the main class for the application. + mainClass.set("com.cubrid.jsp.Server") +} + +tasks.test { + // Use JUnit Platform for unit tests. + useJUnitPlatform() + + testLogging { + lifecycle { + events = mutableSetOf(TestLogEvent.FAILED, TestLogEvent.PASSED, TestLogEvent + .SKIPPED) + exceptionFormat = TestExceptionFormat.FULL + + showExceptions = true + showCauses = true + showStackTraces = true + showStandardStreams = true + } + info.events = lifecycle.events + info.exceptionFormat = lifecycle.exceptionFormat + } + + val failedTests = mutableListOf() + val skippedTests = mutableListOf() + + addTestListener(object : TestListener { + override fun beforeSuite(suite: TestDescriptor) {} + + override fun beforeTest(testDescriptor: TestDescriptor) {} + + override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) { + when (result.resultType) { + TestResult.ResultType.FAILURE -> failedTests.add(testDescriptor) + TestResult.ResultType.SKIPPED -> skippedTests.add(testDescriptor) + else -> Unit + } + } + + override fun afterSuite(suite: TestDescriptor, result: TestResult) { + if (suite.parent == null) { + logger.lifecycle("\n################ Summary::Start ################") + logger.lifecycle("Test result: ${result.resultType}") + logger.lifecycle( + "Test summary: ${result.testCount} tests, " + + "${result.successfulTestCount} succeeded, " + + "${result.failedTestCount} failed, " + + "${result.skippedTestCount} skipped") + failedTests.takeIf { it.isNotEmpty() }?.prefixedSummary("\tFailed Tests") + skippedTests.takeIf { it.isNotEmpty() }?.prefixedSummary("\tSkipped Tests:") + logger.lifecycle("################ Summary::End ##################") + } + } + + private infix fun List.prefixedSummary(subject: String) { + logger.lifecycle(subject) + forEach { test -> logger.lifecycle("\t\t${test.displayName()}") } + } + + private fun TestDescriptor.displayName() = parent?.let { "${it.name} - $name" } ?: "$name" + + }) +} + +tasks.jar { + // To make fat Jar + val dependencies = configurations + .runtimeClasspath + .get() + .map(::zipTree) // OR .map { zipTree(it) } + from(dependencies) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} diff --git a/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 b/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 new file mode 100644 index 00000000000..abe1c7bfa33 --- /dev/null +++ b/pl_engine/pl_server/src/main/antlr/PlcLexer.g4 @@ -0,0 +1,297 @@ +/** + * CUBRID PL/CSQL Parser grammar based on and updated from + * Oracle(c) PL/SQL 11g Parser (https://github.com/antlr/grammars-v4/tree/master/sql/plsql) + * + * Copyright (c) 2009-2011 Alexandre Porcelli + * Copyright (c) 2015-2019 Ivan Kochurkin (KvanTTT, kvanttt@gmail.com, Positive Technologies). + * Copyright (c) 2017 Mark Adams + * Copyright (c) 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. + */ + +lexer grammar PlcLexer; + +@header { +package com.cubrid.plcsql.compiler.antlrgen; +} + +@members { +private int staticSqlParenMatch = -1; +private boolean checkFirstLParen = false; // to detect that it is actually not a static sql but a built-in function call +} + +// keywords that starts Static SQL +// INSERT, REPLACE, TRAUNCATE: also a built-in function +WITH: W I T H { staticSqlParenMatch++; mode(STATIC_SQL); }; +SELECT: S E L E C T { staticSqlParenMatch++; mode(STATIC_SQL); }; +INSERT: I N S E R T { staticSqlParenMatch++; checkFirstLParen = true; mode(STATIC_SQL); }; +UPDATE: U P D A T E { staticSqlParenMatch++; mode(STATIC_SQL); }; +DELETE: D E L E T E { staticSqlParenMatch++; mode(STATIC_SQL); }; +REPLACE: R E P L A C E { staticSqlParenMatch++; checkFirstLParen = true; mode(STATIC_SQL); }; +MERGE: M E R G E { staticSqlParenMatch++; mode(STATIC_SQL); }; +TRUNCATE: T R U N C A T E { staticSqlParenMatch++; checkFirstLParen = true; mode(STATIC_SQL); }; + +// other keywords +AND: A N D ; +AS: A S ; +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 ; +BIGINT: B I G I N T ; +BOOLEAN: B O O L E A N ; +BY: B Y ; +CASE: C A S E ; +CHARACTER: C H A R A C T E R ; +CHAR: C H A R ; +CLOSE: C L O S E ; +COMMENT: C O M M E N T ; +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 ; +CURSOR: C U R S O R ; +DATE: D A T E ; +DATETIME: D A T E T I M E ; +DATETIMELTZ: D A T E T I M E L T Z ; +DATETIMETZ: D A T E T I M E T Z ; +DBMS_OUTPUT: D B M S '_' O U T P U T ; +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 ; +DIV: D I V ; +DOUBLE: D O U B L E ; +ELSE: E L S E ; +ELSIF: E L S I F ; +END: E N D ; +ESCAPE: E S C A P E ; +EXCEPTION: E X C E P T I O N ; +EXECUTE: E X E C U T E ; +EXIT: E X I T ; +FALSE: F A L S E ; +FETCH: F E T C H ; +FLOAT: F L O A T ; +FOR: F O R ; +FUNCTION: F U N C T I O N ; +IF: I F ; +IMMEDIATE: I M M E D I A T E ; +IN: I N ; +INOUT: I N O U T ; +INTEGER: I N T E G E R ; +INT: I N T ; +INTO: I N T O ; +IS: I S ; +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 | '%' ) ; +MULTISET: M U L T I S E T ; +NOT: N O T ; +NULL_: N U L L ; +NUMERIC: N U M E R I C ; +OF: O F ; +OPEN: O P E N ; +OR_REPLACE: O R SPACE+ R E P L A C E ; +OR: O R ; +OUT: O U T ; +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 ; +PERCENT_ROWCOUNT: '%' SPACE* R O W C O U N T ; +PERCENT_TYPE: '%' SPACE* T Y P E ; +PLCSQL: P L C S Q L ; +PRAGMA: P R A G M A ; +PRECISION: P R E C I S I O N ; +PROCEDURE: P R O C E D U R E ; +RAISE: R A I S E ; +RAISE_APPLICATION_ERROR: R A I S E '_' A P P L I C A T I O N '_' E R R O R ; +REAL: R E A L ; +RETURN: R E T U R N ; +REVERSE: R E V E R S E ; +ROLLBACK: R O L L B A C K ; +SEQUENCE: S E Q U E N C E ; +SET: S E T ; +SETEQ: S E T E Q ; +SETNEQ: S E T N E Q ; +SHORT: S H O R T ; +SMALLINT: S M A L L I N T ; +SQL: S Q L ; +SQLCODE: S Q L C O D E ; +SQLERRM: S Q L E R R M ; +STRING: S T R I N G ; +SUBSET: S U B S E T ; +SUBSETEQ: S U B S E T E Q ; +SUPERSET: S U P E R S E T ; +SUPERSETEQ: S U P E R S E T E Q ; +SYS_REFCURSOR: S Y S '_' R E F C U R S O R ; +THEN: T H E N ; +TIMESTAMP: T I M E S T A M P ; +TIMESTAMPLTZ: T I M E S T A M P L T Z ; +TIMESTAMPTZ: T I M E S T A M P T Z ; +TIME: T I M E ; +TRUE: T R U E ; +USING: U S I N G ; +VARCHAR: V A R C H A R ; +WHEN: W H E N ; +WHILE: W H I L E ; +WORK: W O R K ; +XOR: X O R ; +VARYING: V A R Y I N G ; + +PERIOD2: '..'; +PERIOD: '.'; + +// NOTE: a literal with 'e/E' notation is deemed to be a DOUBLE type numeric literal in CUBRID even when +// it does not have a floating point +FLOATING_POINT_NUM: FPNUM_W_POINT | FPNUM_WO_POINT; +UNSIGNED_INTEGER: BASIC_UINT; + +DELIMITED_ID: ('"' REGULAR_ID '"') | ('[' REGULAR_ID ']') | ('`' REGULAR_ID '`') ; +CHAR_STRING: '\'' (~('\'' | '\r' | '\n') | '\'' '\'' | NEWLINE)* '\''; + +NULL_SAFE_EQUALS_OP: '<=>'; + +GE: '>='; +LE: '<='; +CONCAT_OP: '||'; +LT2: '<<'; +GT2: '>>'; +ASTERISK2: '**'; + +LPAREN: '('; +RPAREN: ')'; +ASTERISK: '*'; +PLUS_SIGN: '+'; +MINUS_SIGN: '-'; +BIT_COMPLI: '~'; +COMMA: ','; +SOLIDUS: '/'; +AT_SIGN: '@'; +ASSIGN_OP: ':='; + +NOT_EQUAL_OP: '!=' + | '<>' + ; + +AMPERSAND: '&'; +CARRET_OP: '^'; +EXCLAMATION_OP: '!'; +GT: '>'; +LT: '<'; +COLON: ':'; +SEMICOLON: ';'; + +BAR: '|'; +EQUALS_OP: '='; + +LEFT_BRACKET: '['; +RIGHT_BRACKET: ']'; + +LEFT_BRACE: '{'; +RIGHT_BRACE: '}'; + +INTRODUCER: '_'; + +SINGLE_LINE_COMMENT: '--' ~('\r' | '\n')* NEWLINE_EOF -> channel(HIDDEN); +SINGLE_LINE_COMMENT2: '//' ~('\r' | '\n')* NEWLINE_EOF -> channel(HIDDEN); +MULTI_LINE_COMMENT: '/*' .*? '*/' -> channel(HIDDEN); + +REGULAR_ID: (SIMPLE_LETTER | '_') (SIMPLE_LETTER | '_' | [0-9])*; + +SPACES: [ \t\r\n]+ -> channel(HIDDEN); + +// ************************ +mode STATIC_SQL; +// ************************ + +// Do not drop comments because they can have a hint. +SS_SINGLE_LINE_COMMENT: '--' ~('\r' | '\n')* NEWLINE_EOF { setType(PlcParser.SS_NON_STR); } ; +SS_SINGLE_LINE_COMMENT2: '//' ~('\r' | '\n')* NEWLINE_EOF { setType(PlcParser.SS_NON_STR); } ; +SS_MULTI_LINE_COMMENT: '/*' .*? '*/' { setType(PlcParser.SS_NON_STR); } ; + +SS_SEMICOLON : ';' { + setType(PlcParser.SEMICOLON); + staticSqlParenMatch = -1; + checkFirstLParen = false; + mode(DEFAULT_MODE); + }; +SS_STR : '\'' (~('\'' | '\r' | '\n') | '\'' '\'' | NEWLINE)* '\'' { + checkFirstLParen = false; + }; +SS_WS : [ \t\r\n]+ ; +SS_LPAREN : '(' { + if (checkFirstLParen) { + setType(PlcParser.LPAREN); + staticSqlParenMatch = -1; + checkFirstLParen = false; + mode(DEFAULT_MODE); + } else { + staticSqlParenMatch++; + setType(PlcParser.SS_NON_STR); + } + }; +SS_RPAREN : ')' { + checkFirstLParen = false; + staticSqlParenMatch--; + if (staticSqlParenMatch == -1) { + mode(DEFAULT_MODE); + setType(PlcParser.RPAREN); + } else { + setType(PlcParser.SS_NON_STR); + } + }; +SS_NON_STR: ~( ';' | '\'' | ' ' | '\t' | '\r' | '\n' | '(' | ')' )+ { + checkFirstLParen = false; + }; + +// ************************ +// Fragment rules +// ************************ + +fragment FPNUM_W_POINT : (BASIC_UINT? '.' [0-9]+ | BASIC_UINT '.') ([eE] ('+'|'-')? BASIC_UINT)? [fF]?; +fragment FPNUM_WO_POINT : BASIC_UINT [eE] ('+'|'-')? BASIC_UINT [fF]?; +fragment BASIC_UINT : '0'|[1-9][0-9]*; +fragment NEWLINE_EOF : NEWLINE | EOF; +fragment SIMPLE_LETTER : [A-Za-z] | [\uAC00-\uD7A3]; // English letters and Korean letters +fragment NEWLINE : '\r'? '\n'; +fragment SPACE : [ \t]; + +fragment A : [aA]; // match either an 'a' or 'A' +fragment B : [bB]; +fragment C : [cC]; +fragment D : [dD]; +fragment E : [eE]; +fragment F : [fF]; +fragment G : [gG]; +fragment H : [hH]; +fragment I : [iI]; +fragment J : [jJ]; +fragment K : [kK]; +fragment L : [lL]; +fragment M : [mM]; +fragment N : [nN]; +fragment O : [oO]; +fragment P : [pP]; +fragment Q : [qQ]; +fragment R : [rR]; +fragment S : [sS]; +fragment T : [tT]; +fragment U : [uU]; +fragment V : [vV]; +fragment W : [wW]; +fragment X : [xX]; +fragment Y : [yY]; +fragment Z : [zZ]; + diff --git a/pl_engine/pl_server/src/main/antlr/PlcParser.g4 b/pl_engine/pl_server/src/main/antlr/PlcParser.g4 new file mode 100644 index 00000000000..e2167cb1b46 --- /dev/null +++ b/pl_engine/pl_server/src/main/antlr/PlcParser.g4 @@ -0,0 +1,571 @@ +/** + * CUBRID PL/CSQL Parser grammar based on and updated from + * Oracle(c) PL/SQL 11g Parser (https://github.com/antlr/grammars-v4/tree/master/sql/plsql) + * + * Copyright (c) 2009-2011 Alexandre Porcelli + * Copyright (c) 2015-2019 Ivan Kochurkin (KvanTTT, kvanttt@gmail.com, Positive Technologies). + * Copyright (c) 2017 Mark Adams + * Copyright (c) 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. + */ + +parser grammar PlcParser; + +@header { +package com.cubrid.plcsql.compiler.antlrgen; +} + +options { + tokenVocab=PlcLexer; +} + +sql_script + : create_routine EOF + ; + +create_routine + : CREATE (OR_REPLACE)? routine_definition (COMMENT CHAR_STRING)? + ; + +routine_definition + : (PROCEDURE | FUNCTION) identifier ( (LPAREN parameter_list RPAREN)? | LPAREN RPAREN ) (RETURN type_spec)? + (IS | AS) (LANGUAGE PLCSQL)? seq_of_declare_specs? body (SEMICOLON)? + ; + +parameter_list + : parameter (',' parameter)* + ; + +parameter + : parameter_name IN? type_spec # parameter_in + | parameter_name ( IN? OUT | INOUT ) type_spec # parameter_out + ; + +default_value_part + : (':=' | DEFAULT) expression + ; + +seq_of_declare_specs + : declare_spec+ + ; + +declare_spec + : pragma_declaration + | item_declaration + | cursor_definition + | routine_definition + ; + +item_declaration + : constant_declaration + | exception_declaration + | variable_declaration + ; + +variable_declaration + : identifier type_spec ((NOT NULL_)? default_value_part)? SEMICOLON + ; + +constant_declaration + : identifier CONSTANT type_spec (NOT NULL_)? default_value_part SEMICOLON + ; + +cursor_definition + : CURSOR identifier ( (LPAREN parameter_list RPAREN)? | LPAREN RPAREN ) IS static_sql SEMICOLON + ; + +exception_declaration + : identifier EXCEPTION SEMICOLON + ; + +pragma_declaration + : PRAGMA AUTONOMOUS_TRANSACTION SEMICOLON + ; + +seq_of_statements + : (statement SEMICOLON)+ + ; + +label_declaration + : '<<' label_name '>>' + ; + +statement + : block # stmt_block + | sql_statement # stmt_sql // must go before procedure_call + | raise_application_error_statement # stmt_raise_app_err // must go before procedure_call + | execute_immediate # stmt_exec_imme + | assignment_statement # stmt_assign + | continue_statement # stmt_continue + | exit_statement # stmt_exit + | null_statement # stmt_null + | raise_statement # stmt_raise + | return_statement # stmt_return + | procedure_call # stmt_proc_call + | if_statement # stmt_if + | loop_statement # stmt_loop + | case_statement # stmt_case + ; + +execute_immediate + : EXECUTE IMMEDIATE dyn_sql (into_clause? restricted_using_clause? | restricted_using_clause into_clause) + ; + +dyn_sql + : expression + ; + +into_clause + : INTO identifier (',' identifier)* + ; + +assignment_statement + : identifier ':=' expression + ; + +continue_statement + : CONTINUE label_name? (WHEN expression)? + ; + +exit_statement + : EXIT label_name? (WHEN expression)? + ; + +if_statement + : IF expression THEN seq_of_statements elsif_part* else_part? END IF + ; + +elsif_part + : ELSIF expression THEN seq_of_statements + ; + +else_part + : ELSE seq_of_statements + ; + +loop_statement + : label_declaration? LOOP seq_of_statements END LOOP label_name? # stmt_basic_loop + | label_declaration? WHILE expression LOOP seq_of_statements END LOOP label_name? # stmt_while_loop + | label_declaration? FOR iterator LOOP seq_of_statements END LOOP label_name? # stmt_for_iter_loop + | label_declaration? FOR for_cursor LOOP seq_of_statements END LOOP label_name? # stmt_for_cursor_loop + | label_declaration? FOR for_static_sql LOOP seq_of_statements END LOOP label_name? # stmt_for_static_sql_loop + | label_declaration? FOR for_dynamic_sql LOOP seq_of_statements END LOOP label_name? # stmt_for_dynamic_sql_loop + ; + + // actually far more complicated according to the Spec. +iterator + : index_name IN REVERSE? lower_bound '..' upper_bound (BY step)? + ; + +for_cursor + : record_name IN cursor_exp (LPAREN expressions? RPAREN)? + ; + +for_static_sql + : record_name IN LPAREN static_sql RPAREN + ; + +for_dynamic_sql + : record_name IN LPAREN EXECUTE IMMEDIATE dyn_sql restricted_using_clause? RPAREN + ; + +lower_bound + : concatenation + ; + +upper_bound + : concatenation + ; + +step + : concatenation + ; + +null_statement + : NULL_ + ; + +raise_statement + : RAISE exception_name? + ; + +return_statement + : RETURN expression? + ; + +procedure_call + : (DBMS_OUTPUT '.')? routine_name function_argument? + ; + +body + : BEGIN seq_of_statements (EXCEPTION exception_handler+)? END label_name? + ; + +exception_handler + : WHEN exception_name (OR exception_name)* THEN seq_of_statements + ; + +block + : (DECLARE seq_of_declare_specs)? body + ; + +sql_statement + : static_sql + | cursor_manipulation_statement + | transaction_control_statement + ; + +static_sql + : static_sql_begin (SS_STR | SS_WS | SS_NON_STR)+ + ; + +static_sql_begin + : WITH + | SELECT + | INSERT + | UPDATE + | DELETE + | REPLACE + | MERGE + | TRUNCATE + ; + +cursor_manipulation_statement + : close_statement + | open_statement + | fetch_statement + | open_for_statement + ; + +close_statement + : CLOSE cursor_exp + ; + +open_statement + : OPEN cursor_exp (LPAREN expressions? RPAREN)? + ; + +fetch_statement + : FETCH cursor_exp INTO identifier (',' identifier)* + ; + +open_for_statement + : OPEN identifier FOR static_sql + ; + +transaction_control_statement + : commit_statement + | rollback_statement + ; + +commit_statement + : COMMIT WORK? + ; + +rollback_statement + : ROLLBACK WORK? + ; + +expressions + : expression (',' expression)* + ; + +expression + : unary_logical_expression # expression_prime + | expression AND expression # and_exp + | expression XOR expression # xor_exp + | expression OR expression # or_exp + ; + +unary_logical_expression + : relational_expression # unary_logical_expression_prime + | NOT unary_logical_expression # not_exp + ; + +relational_expression + : between_expression # relational_expression_prime + | relational_expression relational_operator relational_expression # rel_exp + ; + +between_expression + : in_expression # between_expression_prime + | between_expression NOT? BETWEEN between_elements # between_exp + ; + +in_expression + : like_expression # in_expression_prime + | in_expression NOT? IN in_elements # in_exp + ; + +like_expression + : is_null_expression # like_expression_prime + | like_expression NOT? LIKE pattern=concatenation (ESCAPE escape=quoted_string)? # like_exp + ; + +is_null_expression + : concatenation # is_null_expression_prime + | is_null_expression IS NOT? NULL_ # is_null_exp + ; + +concatenation + : unary_expression # concatenation_prime + | concatenation ('*' | '/' | DIV | MOD) concatenation # mult_exp + | concatenation ('+' | '-' ) concatenation # add_exp + | concatenation '||' concatenation # str_concat_exp + | concatenation ('<<' | '>>') concatenation # bit_shift_exp + | concatenation ('&') concatenation # bit_and_exp + | concatenation ('^') concatenation # bit_xor_exp + | concatenation ('|') concatenation # bit_or_exp + ; + +unary_expression + : atom # unary_expression_prime + | ('-' | '+') unary_expression # sign_exp + | '~' unary_expression # bit_compli_exp + ; + +atom + : literal # literal_exp + | record=identifier '.' field=identifier # field_exp + | function_call # call_exp + | identifier # id_exp + | 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 + | LPAREN expression RPAREN # paren_exp + | SQLCODE # sqlcode_exp + | SQLERRM # sqlerrm_exp + ; + +function_call + : function_name function_argument + ; + +relational_operator + : '=' + | NULL_SAFE_EQUALS_OP + | NOT_EQUAL_OP + | '<=' + | '>=' + | '<' + | '>' + ; + +in_elements + : LPAREN in_expression (',' in_expression)* RPAREN + ; + +between_elements + : between_expression AND between_expression + ; + +case_expression + : searched_case_expression + | simple_case_expression + ; + +simple_case_expression + : CASE expression simple_case_expression_when_part+ case_expression_else_part? END + ; + +simple_case_expression_when_part + : WHEN expression THEN expression + ; + +searched_case_expression + : CASE searched_case_expression_when_part+ case_expression_else_part? END + ; + +searched_case_expression_when_part + : WHEN expression THEN expression + ; + +case_expression_else_part + : ELSE expression + ; + +case_statement + : searched_case_statement + | simple_case_statement + ; + +raise_application_error_statement + : RAISE_APPLICATION_ERROR LPAREN err_code ',' err_msg RPAREN + ; + +err_code + : concatenation + ; + +err_msg + : concatenation + ; + +simple_case_statement + : CASE expression simple_case_statement_when_part+ case_statement_else_part? END CASE label_name? + ; + +simple_case_statement_when_part + : WHEN expression THEN seq_of_statements + ; + +searched_case_statement + : CASE searched_case_statement_when_part+ case_statement_else_part? END CASE label_name? + ; + +searched_case_statement_when_part + : WHEN expression THEN seq_of_statements + ; + +case_statement_else_part + : ELSE seq_of_statements + ; + +restricted_using_clause + : USING restricted_using_element (',' restricted_using_element)* + ; + +restricted_using_element + : (IN)? expression + ; + +routine_name + : identifier + ; + +parameter_name + : identifier + ; + +label_name + : identifier + ; + +exception_name + : identifier + ; + +index_name + : identifier + ; + +cursor_exp + //: function_call TODO + : identifier + ; + +record_name + : identifier + ; + +table_name + : (identifier '.')? identifier + ; + +column_name + : identifier + ; + +function_argument + : LPAREN (argument (',' argument)*)? RPAREN + ; + +argument + : expression + ; + +type_spec + : native_datatype # native_type_spec + | (table_name '.')? identifier PERCENT_TYPE # percent_type_spec + ; + +native_datatype + : numeric_type + | char_type + | varchar_type + | simple_type + ; + +numeric_type + : (NUMERIC | DECIMAL | DEC) (LPAREN precision=UNSIGNED_INTEGER (',' scale=UNSIGNED_INTEGER)? RPAREN)? + ; + +char_type + : (CHAR | CHARACTER) ( LPAREN length=UNSIGNED_INTEGER RPAREN )? + ; + +varchar_type + : (VARCHAR | CHAR VARYING | CHARACTER VARYING) ( LPAREN length=UNSIGNED_INTEGER RPAREN )? + | STRING + ; + +simple_type + : BOOLEAN + | SHORT | SMALLINT + | INT | INTEGER + | BIGINT + | FLOAT | REAL + | DOUBLE PRECISION? + | DATE + | TIME + | TIMESTAMP + | DATETIME + | SYS_REFCURSOR + ; + +literal + : DATE quoted_string # date_exp + | TIME quoted_string # time_exp + | TIMESTAMP quoted_string # timestamp_exp + | DATETIME quoted_string # datetime_exp + | numeric # num_exp + | quoted_string # str_exp + | NULL_ # null_exp + | TRUE # true_exp + | FALSE # false_exp + ; + +numeric + : UNSIGNED_INTEGER # uint_exp + | FLOATING_POINT_NUM # fp_num_exp + ; + +numeric_negative + : '-' numeric + ; + +quoted_string + : CHAR_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 new file mode 100644 index 00000000000..e3ebaa780cc --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ExecuteThread.java @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2008 Search Solution Corporation. + * 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 com.cubrid.jsp.classloader.ClassLoaderManager; +import com.cubrid.jsp.context.Context; +import com.cubrid.jsp.context.ContextManager; +import com.cubrid.jsp.data.CUBRIDPacker; +import com.cubrid.jsp.data.CUBRIDUnpacker; +import com.cubrid.jsp.data.CompileInfo; +import com.cubrid.jsp.data.DataUtilities; +import com.cubrid.jsp.exception.ExecuteException; +import com.cubrid.jsp.exception.TypeMismatchException; +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.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.sql.SQLException; +import java.util.List; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; + +public class ExecuteThread extends Thread { + + public static String charSet = "UTF-8"; + + private Socket client; + + private DataInputStream input; + private DataOutputStream output; + + /* + * TODO: It will be replaced with DirectByteBuffer-based new buffer which + * dynamically extended if overflow exists + */ + /* + * Since DirectByteBuffer's allocation time is slow, DirectByteBuffer pooling + * should be implemented + */ + private ByteBuffer resultBuffer; + + private CUBRIDUnpacker unpacker = new CUBRIDUnpacker(); + private CUBRIDPacker packer; + + private StoredProcedure storedProcedure = null; + private PrepareArgs prepareArgs = null; + + private Context ctx = null; + + ExecuteThread(Socket client) throws IOException { + super(); + this.client = client; + output = new DataOutputStream(new BufferedOutputStream(this.client.getOutputStream())); + + resultBuffer = ByteBuffer.allocate(4096); + + packer = new CUBRIDPacker(resultBuffer); + } + + public Socket getSocket() { + return client; + } + + public Context getCurrentContext() { + return ctx; + } + + public void closeSocket() { + try { + output.close(); + client.close(); + } catch (IOException e) { + } + + client = null; + output = null; + // charSet = null; + } + + public void setCharSet(String conCharsetName) { + // this.charSet = conCharsetName; + } + + @Override + public void run() { + /* main routine handling stored procedure */ + Header header = null; + while (!Thread.interrupted()) { + try { + header = listenCommand(); + ContextManager.registerThread(Thread.currentThread().getId(), ctx.getSessionId()); + switch (header.code) { + /* + * the following two request codes are for processing java stored procedure + * routine + */ + case RequestCode.PREPARE_ARGS: + { + processPrepare(); + break; + } + case RequestCode.INVOKE_SP: + { + processStoredProcedure(); + ctx = null; + break; + } + + case RequestCode.COMPILE: + { + processCompile(); + break; + } + + /* the following request codes are for javasp utility */ + case RequestCode.UTIL_PING: + { + String ping = Server.getServer().getServerName(); + + resultBuffer.clear(); /* prepare to put */ + packer.setBuffer(resultBuffer); + packer.packString(ping); + + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + break; + } + case RequestCode.UTIL_STATUS: + { + // TODO: create a packable class for status + resultBuffer.clear(); /* prepare to put */ + packer.setBuffer(resultBuffer); + + packer.packInt(Server.getServer().getServerPort()); + packer.packString(Server.getServer().getServerName()); + List vm_args = Server.getJVMArguments(); + packer.packInt(vm_args.size()); + for (String arg : vm_args) { + packer.packString(arg); + } + + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + break; + } + case RequestCode.UTIL_TERMINATE_THREAD: + { + // hacky way.. If thread is terminated and socket is closed immediately, + // "ping" or "status" command does not work properly + sleep(100); + Thread.currentThread().interrupt(); + break; + } + case RequestCode.UTIL_TERMINATE_SERVER: + { + Server.stop(0); + break; + } + + /* invalid request */ + default: + { + // throw new ExecuteException ("invalid request code: " + requestCode); + } + } + ContextManager.deregisterThread(Thread.currentThread().getId()); + } catch (Throwable e) { + if (e instanceof IOException) { + /* + * CAS disconnects socket + * 1) end of the procedure successfully by calling jsp_close_internal_connection + * 2) socket is in invalid status. we do not have to deal with it here. + */ + break; + } else { + Throwable throwable = e; + if (e instanceof InvocationTargetException) { + throwable = ((InvocationTargetException) e).getTargetException(); + } + Server.log(throwable); + try { + // TODO: error managing module + if (throwable instanceof SQLException) { + sendError(throwable.toString()); + } else if (throwable instanceof PlcsqlRuntimeError) { + PlcsqlRuntimeError plcsqlError = (PlcsqlRuntimeError) throwable; + String errMsg = + String.format( + "\n (line %d, column %d) %s", + plcsqlError.getLine(), + plcsqlError.getColumn(), + plcsqlError.getMessage()); + sendError(errMsg); + } else { + sendError(throwable.toString()); + } + } catch (IOException e1) { + Server.log(e1); + } + } + } finally { + ContextManager.deregisterThread(Thread.currentThread().getId()); + ctx = null; + } + } + closeSocket(); + } + + private Header listenCommand() throws Exception { + ByteBuffer inputBuffer = receiveBuffer(); + + unpacker.setBuffer(inputBuffer); + + /* read header */ + Header header = new Header(unpacker); + ctx = ContextManager.getContext(header.id); + ctx.checkHeader(header); + + ByteBuffer payloadBuffer = + ByteBuffer.wrap( + inputBuffer.array(), + unpacker.getCurrentPosition(), + unpacker.getCurrentLimit() - unpacker.getCurrentPosition()); + ctx.getInboundQueue().add(payloadBuffer); + return header; + } + + public ByteBuffer receiveBuffer() throws IOException { + if (input == null) { + input = new DataInputStream(new BufferedInputStream(this.client.getInputStream())); + } + + int size = input.readInt(); // size + byte[] bytes = new byte[size]; + input.readFully(bytes); + + return ByteBuffer.wrap(bytes); + } + + private void writeBuffer(ByteBuffer buffer) throws IOException { + output.writeInt(buffer.position()); + output.write(buffer.array(), 0, buffer.position()); + output.flush(); + } + + public CUBRIDUnpacker getUnpacker() { + return unpacker; + } + + private void processPrepare() throws Exception { + unpacker.setBuffer(ctx.getInboundQueue().take()); + 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 processCompile() throws Exception { + unpacker.setBuffer(ctx.getInboundQueue().take()); + boolean verbose = unpacker.unpackBool(); + String inSource = unpacker.unpackCString(); + + CompileInfo info = null; + try { + info = PlcsqlCompilerMain.compilePLCSQL(inSource, 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"); + } + + 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); + } + } + } catch (Exception e) { + info = + new CompileInfo( + -1, 0, 0, e.getMessage().isEmpty() ? "unknown error" : e.getMessage()); + throw new RuntimeException(e); + } finally { + CUBRIDPacker packer = new CUBRIDPacker(ByteBuffer.allocate(1024)); + info.pack(packer); + Context.getCurrentExecuteThread().sendCommand(RequestCode.COMPILE, packer.getBuffer()); + } + } + + private StoredProcedure makeStoredProcedure(CUBRIDUnpacker unpacker) throws Exception { + String methodSig = unpacker.unpackCString(); + 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[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); + 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++) { + 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); + } + } + } + + 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); + returnOutArgs(procedure, packer); + + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + } + + public void sendCommand(int code, ByteBuffer buffer) throws IOException { + resultBuffer.clear(); /* prepare to put */ + packer.setBuffer(resultBuffer); + + packer.packInt(code); + packer.align(DataUtilities.MAX_ALIGNMENT); + packer.packPrimitiveBytes(buffer); + + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + } + + public void sendCommand(ByteBuffer buffer) throws IOException { + resultBuffer.clear(); /* prepare to put */ + packer.setBuffer(resultBuffer); + + packer.packInt(RequestCode.INTERNAL_JDBC); + packer.align(DataUtilities.MAX_ALIGNMENT); + packer.packPrimitiveBytes(buffer); + + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + } + + private void sendError(String exception) throws IOException { + resultBuffer.clear(); + packer.setBuffer(resultBuffer); + + packer.packInt(RequestCode.ERROR); + packer.align(DataUtilities.MAX_ALIGNMENT); + packer.packString(exception); + + resultBuffer = packer.getBuffer(); + writeBuffer(resultBuffer); + } +} diff --git a/src/jsp/com/cubrid/jsp/ListenerThread.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ListenerThread.java similarity index 100% rename from src/jsp/com/cubrid/jsp/ListenerThread.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/ListenerThread.java diff --git a/src/jsp/com/cubrid/jsp/LoggingThread.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/LoggingThread.java similarity index 88% rename from src/jsp/com/cubrid/jsp/LoggingThread.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/LoggingThread.java index 6a1bad2714b..818b6b19b14 100644 --- a/src/jsp/com/cubrid/jsp/LoggingThread.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/LoggingThread.java @@ -32,6 +32,7 @@ package com.cubrid.jsp; import java.io.IOException; +import java.nio.file.Path; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.FileHandler; import java.util.logging.Level; @@ -40,18 +41,20 @@ public class LoggingThread extends Thread { private final Logger logger = Logger.getLogger("com.cubrid.jsp"); + private boolean isRunning = false; private FileHandler logHandler = null; private LinkedBlockingQueue logQueue = new LinkedBlockingQueue(); private Level logginLevel = Level.SEVERE; - public LoggingThread(String path) throws SecurityException, IOException { + public LoggingThread(Path path) throws SecurityException, IOException { super(); - logHandler = new FileHandler(path, true); + logHandler = new FileHandler(path.toAbsolutePath().toString(), true); logger.addHandler(logHandler); } @Override public void run() { + isRunning = true; while (Thread.interrupted() == false) { try { String logString = logQueue.take(); @@ -63,6 +66,7 @@ public void run() { if (logHandler != null) { try { + isRunning = false; logHandler.close(); logger.removeHandler(logHandler); } catch (Throwable e) { @@ -76,4 +80,8 @@ public void log(String str) { } catch (InterruptedException e) { } } + + public boolean isRunning() { + return isRunning; + } } diff --git a/src/jsp/com/cubrid/jsp/OSValidator.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/OSValidator.java similarity index 100% rename from src/jsp/com/cubrid/jsp/OSValidator.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/OSValidator.java 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 new file mode 100644 index 00000000000..b97b1589169 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/Server.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2008 Search Solution Corporation. + * 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 com.cubrid.jsp.classloader.ClassLoaderManager; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.net.ServerSocket; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; +import org.newsclub.net.unix.AFUNIXServerSocket; +import org.newsclub.net.unix.AFUNIXSocketAddress; + +public class Server { + private static final Logger logger = Logger.getLogger("com.cubrid.jsp"); + + public static final int PORT_NUMBER_UNKNOWN = -2; + public static final int PORT_NUMBER_UDS = -1; + + private static AtomicBoolean shutdown = new AtomicBoolean(false); + + private static ServerConfig config = null; + + private static List jvmArguments = null; + private static int portNumber = PORT_NUMBER_UNKNOWN; + + private static Server serverInstance = null; + + private static Thread socketListener = null; + private static LoggingThread loggingThread = null; + + private Server(ServerConfig conf) throws IOException, ClassNotFoundException { + config = conf; + + // Server's security manager should be set first + System.setSecurityManager(new SpSecurityManager()); + + // initialize env + initailizeEnvironments(config); + + // initialize logger + initializeLogger(config); + + // initialize class loader + Files.createDirectories(ClassLoaderManager.getRootPath()); + + // initialize socket + initializeSocket(config); + + System.setProperty("cubrid.server.version", config.getVersion()); + Class.forName("com.cubrid.jsp.jdbc.CUBRIDServerSideDriver"); + + // store JVM options + getJVMArguments(); + } + + private synchronized void initailizeEnvironments(ServerConfig config) { + System.setProperty("java.io.tmpdir", config.getTmpPath()); + } + + private synchronized void initializeLogger(ServerConfig config) + throws SecurityException, IOException { + Path logPath = Paths.get(config.getLogPath()); + if (Files.notExists(logPath)) { + Files.createDirectories(logPath.getParent()); + Files.createFile(logPath); + } + + loggingThread = new LoggingThread(logPath); + loggingThread.start(); + } + + private synchronized void initializeSocket(ServerConfig config) throws IOException { + ServerSocket serverSocket = null; + if (config.getSocketType().equals("UDS")) { + final Path socketFile = Paths.get(config.getSocketInfo()); + + // create parent directory if exists + if (!Files.exists(socketFile.getParent())) { + Files.createDirectories(socketFile.getParent()); + } + + // remove previous socket file + Files.deleteIfExists(socketFile); + + AFUNIXSocketAddress sockAddr = AFUNIXSocketAddress.of(socketFile); + serverSocket = AFUNIXServerSocket.bindOn(sockAddr); + portNumber = PORT_NUMBER_UDS; + } else { + portNumber = Integer.parseInt(config.getSocketInfo()); + serverSocket = new ServerSocket(portNumber); + portNumber = serverSocket.getLocalPort(); + } + + socketListener = new ListenerThread(serverSocket); + } + + private void startSocketListener() { + if (socketListener != null) { + socketListener.setDaemon(true); + socketListener.start(); + } + } + + private void stopSocketListener() { + if (socketListener != null) { + socketListener.interrupt(); + socketListener = null; + } + } + + public static Server getServer() { + return serverInstance; + } + + public static ServerConfig getServerConfig() { + return config; + } + + public String getServerName() { + return config.getName(); + } + + public int getServerPort() { + return portNumber; + } + + public Path getRootPath() { + if (getServer() != null) { + return Paths.get(config.getRootPath()); + } else { + return null; + } + } + + public Path getDatabasePath() { + if (getServer() != null) { + return Paths.get(config.getDatabasePath()); + } else { + return null; + } + } + + public static List getJVMArguments() { + if (jvmArguments == null) { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + jvmArguments = runtimeMxBean.getInputArguments(); + } + + return jvmArguments; + } + + /* For JNI */ + public static int start(String[] args) throws Exception { + try { + String name = args[0]; + String dbPath = args[1]; + String version = args[2]; + String envRoot = args[3]; + String udsPath = args[4]; + String port = args[5]; + + String socketInfo = null; + int port_number = Integer.parseInt(port); + if (OSValidator.IS_UNIX && port_number == PORT_NUMBER_UDS) { + socketInfo = udsPath; + } else { + socketInfo = port; + } + + ServerConfig config = new ServerConfig(name, version, envRoot, dbPath, socketInfo); + + return startWithConfig(config); + } catch (Exception e) { + /* error, serverSocket is not properly initialized */ + shutdown.set(true); + if (loggingThread != null && loggingThread.isRunning()) { + log(e); + loggingThread.interrupt(); + } + throw e; + } + } + + /* Entry point (main) */ + public static int startWithConfig(ServerConfig config) + throws ClassNotFoundException, IOException { + if (config == null) { + throw new IllegalArgumentException("ServerConfig is null"); + } + + serverInstance = new Server(config); + serverInstance.startSocketListener(); + + return Server.getServer().getServerPort(); + } + + public static void stop(int status) { + if (serverInstance != null) { + serverInstance.setShutdown(); + serverInstance.stopSocketListener(); + + loggingThread.interrupt(); + + serverInstance = null; + } + } + + public static void main(String[] args) throws Exception { + Server.start(args); + } + + public static void log(Throwable ex) { + StringWriter sw = new StringWriter(); + ex.printStackTrace(new PrintWriter(sw)); + String exceptionAsString = sw.toString(); + loggingThread.log(exceptionAsString); + } + + public static void log(String str) { + loggingThread.log(str); + } + + public void setShutdown() { + shutdown.set(true); + } + + public boolean getShutdown() { + return shutdown.get(); + } +} 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 new file mode 100644 index 00000000000..4f71ee1ad76 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/ServerConfig.java @@ -0,0 +1,73 @@ +package com.cubrid.jsp; + +import java.io.File; +import org.apache.commons.lang3.StringUtils; + +public class ServerConfig { + + private static final String LOG_DIR = "log"; + + private final String name; + private final String version; + + /* Paths */ + private final String rootPath; // $CUBRID + private final String dbPath; // $CUBRID_DATABASES + + private final String logPath; + private final String tmpPath; + + private final String socketType; // TCP or UDS + private final String socketInfo; // port number or socket file path + + public ServerConfig( + String name, String version, String rPath, String dbPath, String socketInfo) { + this.name = name; + this.version = version; + + this.rootPath = rPath; + this.dbPath = dbPath; + + this.logPath = + rootPath + File.separatorChar + LOG_DIR + File.separatorChar + name + "_java.log"; + + String cubridTmpEnv = System.getenv("CUBRID_TMP"); + this.tmpPath = + (cubridTmpEnv != null) ? cubridTmpEnv : this.rootPath + File.separatorChar + "tmp"; + + this.socketInfo = socketInfo; + this.socketType = StringUtils.isNumeric(socketInfo) ? "TCP" : "UDS"; + } + + public String getName() { + return name; + } + + public String getVersion() { + return version; + } + + public String getRootPath() { + return rootPath; + } + + public String getLogPath() { + return logPath; + } + + public String getTmpPath() { + return tmpPath; + } + + public String getSocketType() { + return socketType; + } + + public String getDatabasePath() { + return dbPath; + } + + public String getSocketInfo() { + return socketInfo; + } +} diff --git a/src/jsp/com/cubrid/jsp/SpSecurityManager.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/SpSecurityManager.java similarity index 95% rename from src/jsp/com/cubrid/jsp/SpSecurityManager.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/SpSecurityManager.java index c6e33a498b5..41f04732c2b 100644 --- a/src/jsp/com/cubrid/jsp/SpSecurityManager.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/SpSecurityManager.java @@ -37,7 +37,10 @@ public class SpSecurityManager extends SecurityManager { public void checkExit(int status) { - if (Server.getServer().getShutdown() == false) { + super.checkExit(status); + + Server instance = Server.getServer(); + if (instance != null && instance.getShutdown() == false) { throw new SecurityException(); } } diff --git a/src/jsp/com/cubrid/jsp/StoredProcedure.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java similarity index 98% rename from src/jsp/com/cubrid/jsp/StoredProcedure.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java index 0eed06c7785..e14f485a731 100644 --- a/src/jsp/com/cubrid/jsp/StoredProcedure.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/StoredProcedure.java @@ -31,6 +31,7 @@ package com.cubrid.jsp; +import com.cubrid.jsp.context.ContextManager; import com.cubrid.jsp.exception.ExecuteException; import com.cubrid.jsp.exception.TypeMismatchException; import com.cubrid.jsp.value.BooleanValue; @@ -40,6 +41,7 @@ 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.SetValue; @@ -68,7 +70,8 @@ public StoredProcedure(String signature, Value[] args, int returnType) throws Ex this.signature = signature; this.args = args; this.returnType = returnType; - this.target = TargetMethodCache.getInstance().get(signature); + this.target = + ContextManager.getContextofCurrentThread().getTargetMethodCache().get(signature); this.cachedResolved = null; checkArgs(); @@ -329,7 +332,7 @@ public Value makeReturnValue(Object o) throws ExecuteException { } else if (o instanceof Double) { val = new DoubleValue(((Double) o).doubleValue()); } else if (o instanceof BigDecimal) { - val = new DoubleValue(((BigDecimal) o).doubleValue()); + val = new NumericValue(((BigDecimal) o)); } else if (o instanceof String) { val = new StringValue((String) o); } else if (o instanceof java.sql.Date) { diff --git a/src/jsp/com/cubrid/jsp/TargetMethod.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java similarity index 94% rename from src/jsp/com/cubrid/jsp/TargetMethod.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java index 6e21b35fb57..2867fe91b7c 100644 --- a/src/jsp/com/cubrid/jsp/TargetMethod.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethod.java @@ -31,6 +31,8 @@ package com.cubrid.jsp; +import com.cubrid.jsp.context.Context; +import com.cubrid.jsp.context.ContextManager; import com.cubrid.jsp.exception.ExecuteException; import cubrid.sql.CUBRIDOID; import java.lang.reflect.Method; @@ -76,8 +78,25 @@ public TargetMethod(String signature) throws Exception { } private Class getClass(String name) throws ClassNotFoundException { - ClassLoader cl = StoredProcedureClassLoader.getInstance(); - return cl.loadClass(name); + Context ctx = ContextManager.getContextofCurrentThread(); + ClassLoader cl = ctx.getClassLoader(); + Class c = null; + try { + c = cl.loadClass(name); + return c; + } catch (ClassNotFoundException e) { + // + } + + // TODO: CBRD-24514 + try { + c = Server.class.getClassLoader().loadClass(name); + return c; + } catch (ClassNotFoundException e) { + // + } + + return c; } private Class[] classesFor(String args) throws ClassNotFoundException, ExecuteException { diff --git a/src/jsp/com/cubrid/jsp/TargetMethodCache.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java similarity index 84% rename from src/jsp/com/cubrid/jsp/TargetMethodCache.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java index 48da94962d8..60a6c500e2b 100644 --- a/src/jsp/com/cubrid/jsp/TargetMethodCache.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/TargetMethodCache.java @@ -36,9 +36,7 @@ public class TargetMethodCache { private HashMap methods; - private static volatile TargetMethodCache instance = null; - - private TargetMethodCache() { + public TargetMethodCache() { methods = new HashMap(); } @@ -54,15 +52,7 @@ public TargetMethod get(String signature) throws Exception { return method; } - public static TargetMethodCache getInstance() { - if (instance == null) { - synchronized (TargetMethodCache.class) { - if (instance == null) { - instance = new TargetMethodCache(); - } - } - } - - return instance; + public void clear() { + methods.clear(); } } diff --git a/src/jsp/com/cubrid/jsp/StoredProcedureClassLoader.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/BaseClassLoader.java similarity index 54% rename from src/jsp/com/cubrid/jsp/StoredProcedureClassLoader.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/BaseClassLoader.java index cce16829af6..9d02036fd94 100644 --- a/src/jsp/com/cubrid/jsp/StoredProcedureClassLoader.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/BaseClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Search Solution Corporation. + * * Copyright (c) 2016 CUBRID Corporation. * * Redistribution and use in source and binary forms, with or without modification, @@ -29,8 +29,9 @@ * */ -package com.cubrid.jsp; +package com.cubrid.jsp.classloader; +import com.cubrid.jsp.Server; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -38,47 +39,26 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; import java.util.stream.Stream; -public class StoredProcedureClassLoader extends URLClassLoader { - private static volatile StoredProcedureClassLoader instance = null; - private static volatile StoredProcedureStaticClassLoader parentInstance = null; - - private static final String ROOT_PATH = Server.getSpPath() + "/java/"; - private static final Path root = Paths.get(ROOT_PATH); - - private FileTime lastModified = null; - - /* For singleton */ - public static synchronized StoredProcedureClassLoader getInstance() { - if (instance == null) { - instance = new StoredProcedureClassLoader(); - } - parentInstance = StoredProcedureStaticClassLoader.getInstance(); - - return instance; - } +public abstract class BaseClassLoader extends URLClassLoader { - private StoredProcedureClassLoader() { - super(new URL[0]); - init(); + public BaseClassLoader(Path path, URL[] urls, ClassLoader parent) { + super(urls, parent); + init(path); } - private void init() { + private void init(Path path) { try { - addURL(root.toUri().toURL()); - initJar(); - lastModified = getLastModifiedTime(root); + addURL(path.toUri().toURL()); + initJar(path); } catch (Exception e) { Server.log(e); } } - private void initJar() throws IOException { - try (Stream files = Files.list(root)) { + private void initJar(Path path) throws IOException { + try (Stream files = Files.list(path)) { files.filter((file) -> !Files.isDirectory(file) && (file.toString().endsWith(".jar"))) .forEach( jar -> { @@ -93,32 +73,33 @@ private void initJar() throws IOException { } } - public Class loadClass(String name) throws ClassNotFoundException { - Class found = null; - try { - if (isModified()) { - instance = new StoredProcedureClassLoader(); - found = instance.loadClass(name); - } else { - found = super.loadClass(name); + public Class loadClass(String name) { + Class c = findLoadedClass(name); + if (c == null) { + // find child first + try { + c = super.loadClass(name); + } catch (ClassNotFoundException e) { + // ignore } - } catch (Exception e) { } - if (found == null) { - found = parentInstance.loadClass(name); + if (c == null && getParent() != null) { + try { + c = getParent().loadClass(name); + } catch (ClassNotFoundException e) { + // ignore + } } - return found; - } - - private boolean isModified() throws IOException { - return lastModified.compareTo(getLastModifiedTime(root)) != 0; - } + if (c == null) { + try { + c = getSystemClassLoader().loadClass(name); + } catch (ClassNotFoundException e) { + // ignore + } + } - private FileTime getLastModifiedTime(Path path) throws IOException { - BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); - FileTime lastModifiedTime = attr.lastModifiedTime(); - return lastModifiedTime; + return c; } } diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ClassLoaderManager.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ClassLoaderManager.java new file mode 100644 index 00000000000..7b3c4ac451d --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ClassLoaderManager.java @@ -0,0 +1,116 @@ +/* + * + * 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.Server; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.util.Hashtable; + +public class ClassLoaderManager { + private static Hashtable lastModifiedMap = new Hashtable<>(); + + private static Path rootPath = null; + private static Path staticPath = null; + private static Path dynamicPath = null; + + public static Path getRootPath() { + if (rootPath == null) { + rootPath = Paths.get(Server.getServerConfig().getDatabasePath()); + createDirIfNotExists(rootPath); + } + return rootPath; + } + + public static Path getDynamicPath() { + if (dynamicPath == null) { + dynamicPath = getRootPath().resolve("java/"); + createDirIfNotExists(dynamicPath); + } + return dynamicPath; + } + + public static Path getStaticPath() { + if (staticPath == null) { + staticPath = getRootPath().resolve("java_static/"); + createDirIfNotExists(staticPath); + } + return staticPath; + } + + public static boolean isModified(Path path) { + Instant currentModified = getLastModifiedTimeOfPath(path).toInstant(); + Instant prevModified = lastModifiedMap.get(path); + if (prevModified != null && currentModified.compareTo(prevModified) == 0) { + return false; + } else { + lastModifiedMap.put(path, currentModified); + return true; + } + } + + public static FileTime getLastModifiedTimeOfPath(Path path) { + FileTime lastModifiedTime; + try { + lastModifiedTime = Files.getLastModifiedTime(path); + } catch (IOException e) { + // should not be here... + return null; + } + return lastModifiedTime; + } + + public static FileTime setLastModifiedTime(Path path, FileTime lastModifiedTime) { + try { + lastModifiedTime = Files.getLastModifiedTime(path); + } catch (IOException e) { + // should not be here... + return null; + } + return lastModifiedTime; + } + + private static void createDirIfNotExists(Path path) { + if (path.toFile().exists() == false) { + try { + Files.createDirectories(path); + } catch (IOException e) { + Server.log(e); + System.exit(1); + } + } + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ContextClassLoader.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ContextClassLoader.java new file mode 100644 index 00000000000..53a9c8d2d11 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ContextClassLoader.java @@ -0,0 +1,54 @@ +/* + * + * 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 java.net.URL; +import java.nio.file.attribute.FileTime; + +public class ContextClassLoader extends BaseClassLoader { + private FileTime initializedTime = null; + + public ContextClassLoader(ClassLoader parent) { + super(ClassLoaderManager.getDynamicPath(), new URL[0], parent); + initializedTime = + ClassLoaderManager.getLastModifiedTimeOfPath(ClassLoaderManager.getDynamicPath()); + ClassLoaderManager.isModified(ClassLoaderManager.getDynamicPath()); + } + + public ContextClassLoader() { + this(ServerClassLoader.getInstance()); + } + + public FileTime getInitializedTime() { + return initializedTime; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ServerClassLoader.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ServerClassLoader.java new file mode 100644 index 00000000000..dd2e90603a9 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/classloader/ServerClassLoader.java @@ -0,0 +1,50 @@ +/* + * + * 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 java.net.URL; + +public class ServerClassLoader extends BaseClassLoader { + + // singleton + private static class LazyHolder { + private static final ServerClassLoader INSTANCE = new ServerClassLoader(); + } + + public static ServerClassLoader getInstance() { + return LazyHolder.INSTANCE; + } + + private ServerClassLoader() { + super(ClassLoaderManager.getStaticPath(), new URL[0], null); + } +} 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 new file mode 100644 index 00000000000..9403ccbf4ba --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/Context.java @@ -0,0 +1,207 @@ +/* + * + * 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.context; + +import com.cubrid.jsp.ExecuteThread; +import com.cubrid.jsp.TargetMethodCache; +import com.cubrid.jsp.classloader.ClassLoaderManager; +import com.cubrid.jsp.classloader.ContextClassLoader; +import com.cubrid.jsp.jdbc.CUBRIDServerSideConnection; +import com.cubrid.jsp.protocol.Header; +import com.cubrid.plcsql.builtin.MessageBuffer; +import java.nio.ByteBuffer; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; +import java.util.concurrent.LinkedBlockingQueue; + +public class Context { + // To recognize unique DB session + private long sessionId = -1; + + // transaction Id + private int tranactionId = -1; + + // request Id (for future) + private int prevRequestId = 0; + + // charset + private String charSet = "UTF-8"; + + // single server-side connection per Context + private CUBRIDServerSideConnection connection = null; + + private LinkedBlockingQueue inBound = null; + + // CAS client information connecting with this Context + private Properties clientInfo = null; + + // dynamic classLoader for a session + private ContextClassLoader classLoader = null; + + // method cache + private TargetMethodCache methodCache = null; + + // Whether SP is able to process TCL (commit, rollback). (default: false) + private boolean transactionControl = false; + + // Connection Properties + private Properties connectionInfo = null; + + // message buffer for DBMS_OUTPUT + private MessageBuffer messageBuffer; + + public Context(long id) { + sessionId = id; + } + + public long getSessionId() { + return sessionId; + } + + public synchronized Connection getConnection(Properties prop) { + if (this.connection == null) { + this.connectionInfo = prop; + this.connection = new CUBRIDServerSideConnection(this); + } + return connection; + } + + public void closeConnection(Connection conn) throws SQLException { + if (connection != null) { + connection.close(); + } + } + + public Properties getClientInfo() { + if (clientInfo == null) { + clientInfo = new Properties(); + } + return clientInfo; + } + + public LinkedBlockingQueue getInboundQueue() { + if (inBound == null) { + inBound = new LinkedBlockingQueue(); + } + return inBound; + } + + public String getCharset() { + return charSet; + } + + public void checkHeader(Header header) { + if (prevRequestId > header.requestId) { + // not incremented + // a new session is started with the same session Id or the trasaction is ended + clear(); + } + prevRequestId = header.requestId; + } + + public void checkTranId(int tid) { + if (tranactionId == -1) { + tranactionId = tid; + } + + if (tranactionId != tid) { + // re-cretae dynamic class loader + if (classLoader + .getInitializedTime() + .compareTo( + ClassLoaderManager.getLastModifiedTimeOfPath( + ClassLoaderManager.getDynamicPath())) + != 0) { + classLoader = new ContextClassLoader(); + methodCache.clear(); + } + clear(); + tranactionId = tid; + } + } + + public void clear() { + try { + closeConnection(connection); + } catch (Exception e) { + // ignore + } finally { + connection = null; + } + } + + public MessageBuffer getMessageBuffer() { + if (messageBuffer == null) { + messageBuffer = new MessageBuffer(); + } + return messageBuffer; + } + + public ClassLoader getClassLoader() { + if (classLoader == null) { + classLoader = new ContextClassLoader(); + } + + return classLoader; + } + + public TargetMethodCache getTargetMethodCache() { + if (methodCache == null) { + methodCache = new TargetMethodCache(); + } + + return methodCache; + } + + public void setTransactionControl(boolean tc) { + this.transactionControl = tc; + } + + public boolean canTransactionControl() { + if (transactionControl) { + return true; + } + + String tcProp = connectionInfo.getProperty("transaction_control"); + if (tcProp != null && "true".equalsIgnoreCase(tcProp)) { + return true; + } + + return false; + } + + // TODO: move this function to proper place + public static ExecuteThread getCurrentExecuteThread() { + return (ExecuteThread) Thread.currentThread(); + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/ContextManager.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/ContextManager.java new file mode 100644 index 00000000000..e81f0689a02 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/context/ContextManager.java @@ -0,0 +1,90 @@ +/* + * + * 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.context; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class ContextManager { + + // singleton + private ContextManager() { + // + } + + // Context ID => Context Object + private static ConcurrentMap contextMap = new ConcurrentHashMap(); + + public static boolean hasContext(long id) { + return contextMap.containsKey(id); + } + + public static Context getContext(long id) { + if (hasContext(id)) { + return contextMap.get(id); + } else { + synchronized (ContextManager.class) { + Context newCtx = new Context(id); + contextMap.put(id, newCtx); + return newCtx; + } + } + } + + // Java Thread ID => Context ID + private static ConcurrentMap contextThreadMap = new ConcurrentHashMap(); + + public static void registerThread(long threadId, long ctxId) { + if (contextThreadMap.containsKey(threadId) == false) { + contextThreadMap.put(threadId, ctxId); + } + } + + public static void deregisterThread(long threadId) { + if (contextThreadMap.containsKey(threadId) == true) { + contextThreadMap.remove(threadId); + } + } + + public static Long getContextIdByThreadId(long threadId) { + if (contextThreadMap.containsKey(threadId)) { + return contextThreadMap.get(threadId); + } + return null; + } + + public static Context getContextofCurrentThread() { + Thread t = Thread.currentThread(); + Long ctxId = ContextManager.getContextIdByThreadId(t.getId()); + return ContextManager.getContext(ctxId); + } +} diff --git a/src/jsp/com/cubrid/jsp/data/CUBRIDPacker.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java similarity index 95% rename from src/jsp/com/cubrid/jsp/data/CUBRIDPacker.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java index e00cced3957..9233d792b8a 100644 --- a/src/jsp/com/cubrid/jsp/data/CUBRIDPacker.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDPacker.java @@ -32,6 +32,7 @@ package com.cubrid.jsp.data; import com.cubrid.jsp.jdbc.CUBRIDServerSideResultSet; +import com.cubrid.jsp.protocol.PackableObject; import cubrid.sql.CUBRIDOID; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; @@ -138,6 +139,15 @@ public void packCString(byte[] value) { } } + public void packPackableObject(PackableObject o) { + o.pack(this); + } + + public void packPrimitiveBytes(ByteBuffer b) { + ensureSpace(b.position()); + 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) throws UnsupportedEncodingException { @@ -160,7 +170,7 @@ public void packValue(Object result, int ret_type, String charset) packDouble(((Double) result).doubleValue()); } else if (result instanceof BigDecimal) { packInt(DBType.DB_NUMERIC); - packString(((BigDecimal) result).toString(), charset); + packString(((BigDecimal) result).toPlainString(), charset); } else if (result instanceof String) { packInt(DBType.DB_STRING); packString((String) result, charset); @@ -234,9 +244,9 @@ public void packValue(Object result, int ret_type, String charset) } } - private void align(int size) { + public void align(int size) { int currentPosition = buffer.position(); - int newPosition = DataUtilities.alignedPosition(buffer, size); + int newPosition = DataUtilities.alignedPosition(currentPosition, size); ensureSpace(newPosition - currentPosition); if (newPosition - currentPosition > 0) { diff --git a/src/jsp/com/cubrid/jsp/data/CUBRIDUnpacker.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java similarity index 95% rename from src/jsp/com/cubrid/jsp/data/CUBRIDUnpacker.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java index 7aace497b24..27e3d03f36a 100644 --- a/src/jsp/com/cubrid/jsp/data/CUBRIDUnpacker.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CUBRIDUnpacker.java @@ -39,6 +39,10 @@ public class CUBRIDUnpacker { private ByteBuffer buffer; + public CUBRIDUnpacker() { + this.buffer = null; + } + public CUBRIDUnpacker(ByteBuffer buffer) { this.buffer = buffer; } @@ -130,6 +134,21 @@ public int unpackStringSize() { return len; } + public ByteBuffer unpackBuffer() { + align(DataUtilities.INT_ALIGNMENT); + + int size = buffer.getInt(); + if (size > 0) { + byte[] buf = new byte[size]; + buffer.get(buf); + + align(DataUtilities.INT_ALIGNMENT); + return ByteBuffer.wrap(buf); + } else { + return ByteBuffer.allocate(0); + } + } + public SOID unpackOID() { align(DataUtilities.INT_ALIGNMENT); int pageId = buffer.getInt(); @@ -354,4 +373,12 @@ private Value[] unpackSetValue(int paramCount) throws TypeMismatchException { public void align(int size) { DataUtilities.align(buffer, size); } + + public int getCurrentPosition() { + return buffer.position(); + } + + public int getCurrentLimit() { + return buffer.limit(); + } } diff --git a/src/jsp/com/cubrid/jsp/data/CallInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CallInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/CallInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CallInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/ClientIds.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ClientIds.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/ClientIds.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ClientIds.java diff --git a/src/jsp/com/cubrid/jsp/data/ColumnInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ColumnInfo.java similarity index 97% rename from src/jsp/com/cubrid/jsp/data/ColumnInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ColumnInfo.java index 728870ab3c7..dca264dda6e 100644 --- a/src/jsp/com/cubrid/jsp/data/ColumnInfo.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ColumnInfo.java @@ -22,6 +22,8 @@ public class ColumnInfo { public byte shared; public String defaultValueString; + public ColumnInfo() {} // for mock server API + public ColumnInfo(CUBRIDUnpacker unpacker) { type = unpacker.unpackInt(); setType = unpacker.unpackInt(); diff --git a/src/jsp/com/cubrid/jsp/data/ColumnMeta.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ColumnMeta.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/ColumnMeta.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ColumnMeta.java 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 new file mode 100644 index 00000000000..b09e349f862 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/CompileInfo.java @@ -0,0 +1,78 @@ +/* + * + * 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 CompileInfo implements PackableObject { + public int errCode = -1; // 0: no error, < 0: error + public int errLine = 0; + public int errColumn = 0; + public String errMsg = null; + + public String translated = null; + public String createStmt = null; + public String className = null; + public String signature = null; + + public CompileInfo(int code, int line, int column, String msg) { + assert code < 0; + + errCode = code; + errLine = line; + errColumn = column; + errMsg = msg; + } + + public CompileInfo(String translated, String stmt, String name, String sig) { + errCode = 0; + this.translated = translated; + this.createStmt = stmt; + this.className = name; + this.signature = sig; + } + + @Override + public void pack(CUBRIDPacker packer) { + packer.packInt(errCode); + if (errCode < 0) { + packer.packInt(errLine); + packer.packInt(errColumn); + packer.packString(errMsg); + } else { + packer.packString(translated); + packer.packString(createStmt); + packer.packString(className); + packer.packString(signature); + } + } +} diff --git a/src/jsp/com/cubrid/jsp/data/DBParameterInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DBParameterInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/DBParameterInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DBParameterInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/DBType.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DBType.java similarity index 98% rename from src/jsp/com/cubrid/jsp/data/DBType.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DBType.java index 301407fc395..b8537a73861 100644 --- a/src/jsp/com/cubrid/jsp/data/DBType.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DBType.java @@ -42,7 +42,7 @@ import java.sql.Time; import java.sql.Timestamp; -public class DBType { +public class DBType { // see src/compat/dbtype_def.h public static final int DB_NULL = 0; public static final int DB_INT = 1; public static final int DB_FLOAT = 2; @@ -56,6 +56,7 @@ public class DBType { public static final int DB_TIMESTAMP = 11; public static final int DB_DATE = 12; public static final int DB_MONETARY = 13; + public static final int DB_VARIABLE = 14; public static final int DB_SHORT = 18; public static final int DB_NUMERIC = 22; public static final int DB_OID = 20; diff --git a/src/jsp/com/cubrid/jsp/data/DataUtilities.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DataUtilities.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/DataUtilities.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/DataUtilities.java diff --git a/src/jsp/com/cubrid/jsp/data/ErrorInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ErrorInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/ErrorInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ErrorInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/ExecuteInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ExecuteInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/ExecuteInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/ExecuteInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/FetchInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/FetchInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/FetchInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/FetchInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/GetByOIDInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/GetByOIDInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/GetByOIDInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/GetByOIDInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/GetGeneratedKeysInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/GetGeneratedKeysInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/GetGeneratedKeysInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/GetGeneratedKeysInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/GetSchemaInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/GetSchemaInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/GetSchemaInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/GetSchemaInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/MakeOutResultSetInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/MakeOutResultSetInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/MakeOutResultSetInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/MakeOutResultSetInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/PrepareInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/PrepareInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/PrepareInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/PrepareInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/QueryResultInfo.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/QueryResultInfo.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/QueryResultInfo.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/QueryResultInfo.java diff --git a/src/jsp/com/cubrid/jsp/data/SOID.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/SOID.java similarity index 100% rename from src/jsp/com/cubrid/jsp/data/SOID.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/data/SOID.java diff --git a/src/jsp/com/cubrid/jsp/exception/CUBRIDServerSideException.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/exception/CUBRIDServerSideException.java similarity index 100% rename from src/jsp/com/cubrid/jsp/exception/CUBRIDServerSideException.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/exception/CUBRIDServerSideException.java diff --git a/src/jsp/com/cubrid/jsp/exception/ExecuteException.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/exception/ExecuteException.java similarity index 100% rename from src/jsp/com/cubrid/jsp/exception/ExecuteException.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/exception/ExecuteException.java diff --git a/src/jsp/com/cubrid/jsp/exception/TypeMismatchException.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/exception/TypeMismatchException.java similarity index 100% rename from src/jsp/com/cubrid/jsp/exception/TypeMismatchException.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/exception/TypeMismatchException.java diff --git a/src/jsp/com/cubrid/jsp/impl/SUBindParameter.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUBindParameter.java similarity index 100% rename from src/jsp/com/cubrid/jsp/impl/SUBindParameter.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUBindParameter.java diff --git a/src/jsp/com/cubrid/jsp/impl/SUConnection.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java similarity index 89% rename from src/jsp/com/cubrid/jsp/impl/SUConnection.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java index b7399b9914f..36c8fdbe6f0 100644 --- a/src/jsp/com/cubrid/jsp/impl/SUConnection.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUConnection.java @@ -31,7 +31,7 @@ package com.cubrid.jsp.impl; -import com.cubrid.jsp.ExecuteThread; +import com.cubrid.jsp.context.Context; import com.cubrid.jsp.data.CUBRIDPacker; import com.cubrid.jsp.data.CUBRIDUnpacker; import com.cubrid.jsp.data.DBParameterInfo; @@ -49,6 +49,7 @@ import com.cubrid.jsp.jdbc.CUBRIDServerSideConstants; import com.cubrid.jsp.jdbc.CUBRIDServerSideJDBCErrorCode; import com.cubrid.jsp.jdbc.CUBRIDServerSideJDBCErrorManager; +import com.cubrid.jsp.protocol.Header; import cubrid.sql.CUBRIDOID; import java.io.IOException; import java.nio.ByteBuffer; @@ -56,17 +57,26 @@ public class SUConnection { - ExecuteThread thread = null; + Context ctx = null; ByteBuffer outputBuffer = ByteBuffer.allocate(4096); - public SUConnection(ExecuteThread t) { - thread = t; + public SUConnection(Context t) { + ctx = t; } public CUBRIDUnpacker request(ByteBuffer buffer) throws IOException, SQLException { - thread.sendCommand(buffer); + Context.getCurrentExecuteThread().sendCommand(buffer); buffer.clear(); - CUBRIDUnpacker unpacker = thread.receiveBuffer(); + + 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(); if (responseCode != 0) { @@ -79,7 +89,7 @@ public CUBRIDUnpacker request(ByteBuffer buffer) throws IOException, SQLExceptio return unpacker; } - // UFunctionCode.GET_DB_PARAMETER + // SUFunctionCode.GET_DB_PARAMETER public DBParameterInfo getDBParameter() throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); packer.packInt(SUFunctionCode.GET_DB_PARAMETER.getCode()); @@ -89,7 +99,7 @@ public DBParameterInfo getDBParameter() throws IOException, SQLException { return info; } - // UFunctionCode.PREPARE + // SUFunctionCode.PREPARE public SUStatement prepare(String sql, byte flag) throws IOException, SQLException { return prepare(sql, flag, false); } @@ -114,7 +124,7 @@ public SUStatement prepare(String sql, byte flag, boolean recompile) return stmt; } - // UFunctionCode.GET_SCHEMA_INFO + // SUFunctionCode.GET_SCHEMA_INFO public SUStatement getSchemaInfo(int type, String arg1, String arg2, byte flag) throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); @@ -130,7 +140,7 @@ public SUStatement getSchemaInfo(int type, String arg1, String arg2, byte flag) return stmt; } - // UFunctionCode.EXECUTE + // SUFunctionCode.EXECUTE public ExecuteInfo execute( int handlerId, byte executeFlag, @@ -161,7 +171,7 @@ public ExecuteInfo execute( return info; } - // UFunctionCode.FETCH + // SUFunctionCode.FETCH public FetchInfo fetch(long queryId, int currentRowIndex, int fetchSize, int fetchFlag) throws IOException, TypeMismatchException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); @@ -176,7 +186,7 @@ public FetchInfo fetch(long queryId, int currentRowIndex, int fetchSize, int fet return info; } - // UFunctionCode.MAKE_OUT_RS + // SUFunctionCode.MAKE_OUT_RS public MakeOutResultSetInfo makeOutResult(long queryId) throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); packer.packInt(SUFunctionCode.MAKE_OUT_RS.getCode()); @@ -187,7 +197,7 @@ public MakeOutResultSetInfo makeOutResult(long queryId) throws IOException, SQLE return info; } - // UFunctionCode.NEXT_RESULT + // SUFunctionCode.NEXT_RESULT public ExecuteInfo nextResult(int handlerId) throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); packer.packInt(SUFunctionCode.NEXT_RESULT.getCode()); @@ -198,7 +208,7 @@ public ExecuteInfo nextResult(int handlerId) throws IOException, SQLException { return info; } - // UFunctionCode.GET_BY_OID + // SUFunctionCode.GET_BY_OID public SUStatement getByOID(CUBRIDOID oid, String[] attributeName) throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); @@ -224,7 +234,7 @@ public SUStatement getByOID(CUBRIDOID oid, String[] attributeName) return stmt; } - // UFunctionCode.GET_GENERATED_KEYS + // SUFunctionCode.GET_GENERATED_KEYS public SUStatement getGeneratedKeys(int handlerId) throws IOException, SQLException, TypeMismatchException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); @@ -237,7 +247,7 @@ public SUStatement getGeneratedKeys(int handlerId) return stmt; } - // UFunctionCode.PUT_BY_OID + // SUFunctionCode.PUT_BY_OID public void putByOID(CUBRIDOID oid, String[] attributeName, Object values[]) throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); @@ -264,7 +274,7 @@ public void putByOID(CUBRIDOID oid, String[] attributeName, Object values[]) int result = unpacker.unpackInt(); } - // UFunctionCode.RELATED_TO_OID + // SUFunctionCode.RELATED_TO_OID public Object oidCmd(CUBRIDOID oid, int command) throws IOException, SQLException { CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); packer.packInt(SUFunctionCode.RELATED_TO_OID.getCode()); @@ -284,7 +294,7 @@ public Object oidCmd(CUBRIDOID oid, int command) throws IOException, SQLExceptio return null; } - // UFunctionCode.RELATED_TO_COLLECTION + // SUFunctionCode.RELATED_TO_COLLECTION protected CUBRIDUnpacker collectionCmd( int cmd, CUBRIDOID oid, String attributeName, Object value, int index) throws IOException, SQLException { @@ -312,6 +322,18 @@ protected CUBRIDUnpacker collectionCmd( return unpacker; } + // SUFunctionCode.END_TRANSACTION + public void endTransaction(boolean type) throws IOException, SQLException { + CUBRIDPacker packer = new CUBRIDPacker(outputBuffer); + packer.packInt(SUFunctionCode.END_TRANSACTION.getCode()); + packer.packInt( + (type == true) + ? CUBRIDServerSideConstants.END_TRAN_COMMIT + : CUBRIDServerSideConstants.END_TRAN_ROLLBACK); + CUBRIDUnpacker unpacker = request(packer.getBuffer()); + unpacker.unpackInt(); + } + public void addElementToSet(CUBRIDOID oid, String attributeName, Object value) throws IOException, SQLException { collectionCmd(CUBRIDServerSideConstants.ADD_ELEMENT_TO_SET, oid, attributeName, value, -1); @@ -367,7 +389,7 @@ public int getSizeOfCollection(CUBRIDOID oid, String attributeName) return size; } - // UFunctionCode.NEW_LOB - // UFunctionCode.WRITE_LOB - // UFunctionCode.READ_LOB + // SUFunctionCode.NEW_LOB + // SUFunctionCode.WRITE_LOB + // SUFunctionCode.READ_LOB } diff --git a/src/jsp/com/cubrid/jsp/impl/SUFunctionCode.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUFunctionCode.java similarity index 99% rename from src/jsp/com/cubrid/jsp/impl/SUFunctionCode.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUFunctionCode.java index d7637481b36..3100618fa6c 100644 --- a/src/jsp/com/cubrid/jsp/impl/SUFunctionCode.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUFunctionCode.java @@ -37,6 +37,7 @@ * added in UFunctionCode, it should be added below. */ public enum SUFunctionCode { + END_TRANSACTION(1), PREPARE(2), EXECUTE(3), GET_DB_PARAMETER(4), diff --git a/src/jsp/com/cubrid/jsp/impl/SUParameter.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUParameter.java similarity index 100% rename from src/jsp/com/cubrid/jsp/impl/SUParameter.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUParameter.java diff --git a/src/jsp/com/cubrid/jsp/impl/SUResultTuple.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUResultTuple.java similarity index 100% rename from src/jsp/com/cubrid/jsp/impl/SUResultTuple.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUResultTuple.java diff --git a/src/jsp/com/cubrid/jsp/impl/SUStatement.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUStatement.java similarity index 99% rename from src/jsp/com/cubrid/jsp/impl/SUStatement.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUStatement.java index 2c9f0252356..49f0dfbe9d7 100644 --- a/src/jsp/com/cubrid/jsp/impl/SUStatement.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/impl/SUStatement.java @@ -239,8 +239,8 @@ public void execute(int maxRow, int maxField, boolean isSensitive, boolean isScr } if (bindParameter != null && !bindParameter.checkAllBinded()) { - // TODO: error handling - return; + throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( + CUBRIDServerSideJDBCErrorCode.ER_NOT_BIND, null); } setExecuteFlags(maxRow, isSensitive); diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideCallableStatement.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideCallableStatement.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideCallableStatement.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideCallableStatement.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java similarity index 84% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java index bf08de00fc8..93db90e3cdf 100644 --- a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideConnection.java @@ -31,7 +31,7 @@ package com.cubrid.jsp.jdbc; -import com.cubrid.jsp.ExecuteThread; +import com.cubrid.jsp.context.Context; import com.cubrid.jsp.data.DBParameterInfo; import com.cubrid.jsp.impl.SUConnection; import cubrid.jdbc.jci.CUBRIDIsolationLevel; @@ -64,7 +64,7 @@ * @version 2.0 */ public class CUBRIDServerSideConnection implements Connection { - private ExecuteThread thread = null; + private Context context = null; protected CUBRIDServerSideDatabaseMetaData mdata = null; protected List statements = null; @@ -72,10 +72,9 @@ public class CUBRIDServerSideConnection implements Connection { private int transactionIsolation; private int holdability; - private Properties clientInfo = null; - public CUBRIDServerSideConnection(ExecuteThread thread) { - this.thread = thread; + public CUBRIDServerSideConnection(Context ctx) { + this.context = ctx; holdability = ResultSet.HOLD_CURSORS_OVER_COMMIT; // default value, there is no meaning for the @@ -87,42 +86,42 @@ public CUBRIDServerSideConnection(ExecuteThread thread) { public SUConnection getSUConnection() { if (suConn == null) { - suConn = new SUConnection(thread); + suConn = new SUConnection(context); } return suConn; } protected void requestDBParameter() throws IOException, SQLException { - DBParameterInfo info = getSUConnection().getDBParameter(); - - switch (info.tran_isolation) { - case CUBRIDIsolationLevel.TRAN_READ_COMMITTED: - transactionIsolation = TRANSACTION_READ_COMMITTED; - break; - - case CUBRIDIsolationLevel.TRAN_REPEATABLE_READ: - transactionIsolation = TRANSACTION_REPEATABLE_READ; - break; - - case CUBRIDIsolationLevel.TRAN_SERIALIZABLE: - transactionIsolation = TRANSACTION_SERIALIZABLE; - break; + Properties clientInfo = context.getClientInfo(); + if (clientInfo.contains("type") == false) { + DBParameterInfo info = getSUConnection().getDBParameter(); + + switch (info.tran_isolation) { + case CUBRIDIsolationLevel.TRAN_READ_COMMITTED: + transactionIsolation = TRANSACTION_READ_COMMITTED; + break; + + case CUBRIDIsolationLevel.TRAN_REPEATABLE_READ: + transactionIsolation = TRANSACTION_REPEATABLE_READ; + break; + + case CUBRIDIsolationLevel.TRAN_SERIALIZABLE: + transactionIsolation = TRANSACTION_SERIALIZABLE; + break; + + default: + transactionIsolation = TRANSACTION_NONE; + break; + } - default: - transactionIsolation = TRANSACTION_NONE; - break; + clientInfo.put("type", String.valueOf(info.clientIds.clientType)); + clientInfo.put("program", info.clientIds.programName); + clientInfo.put("host", info.clientIds.hostName); + clientInfo.put("login", info.clientIds.loginName); + clientInfo.put("user", info.clientIds.dbUser); + clientInfo.put("ip", info.clientIds.clientIp); + clientInfo.put("pid", String.valueOf(info.clientIds.processId)); } - - // TODO: lock timeout? - - clientInfo = new Properties(); - clientInfo.put("type", String.valueOf(info.clientIds.clientType)); - clientInfo.put("program", info.clientIds.programName); - clientInfo.put("host", info.clientIds.hostName); - clientInfo.put("login", info.clientIds.loginName); - clientInfo.put("user", info.clientIds.dbUser); - clientInfo.put("ip", info.clientIds.clientIp); - clientInfo.put("pid", String.valueOf(info.clientIds.processId)); } /* To manage List statements */ @@ -170,17 +169,39 @@ public boolean getAutoCommit() throws SQLException { } public void commit() throws SQLException { - /* do nothing */ + if (context.canTransactionControl()) { + try { + close(); + getSUConnection().endTransaction(true); + } catch (IOException e) { + throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( + CUBRIDServerSideJDBCErrorCode.ER_COMMUNICATION, e); + } + } } public void rollback() throws SQLException { - /* do nothing */ + if (context.canTransactionControl()) { + try { + close(); + getSUConnection().endTransaction(false); + } catch (IOException e) { + throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( + CUBRIDServerSideJDBCErrorCode.ER_COMMUNICATION, e); + } + } } public void close() throws SQLException { - /* Becuase It is assume that Java SP Server always connecting with DB Server directly, It should not be closed */ + /* + * Becuase It is assume that Java SP Server always connecting with DB Server + * directly, It should not be closed + */ /* Here, only the JDBC resources are cleaned up */ - /* The connection is not actually terminated or database resources such as query handlers and result sets are removed. */ + /* + * The connection is not actually terminated or database resources such as query + * handlers and result sets are removed. + */ if (statements != null) { for (Statement s : statements) { s.close(); @@ -225,13 +246,11 @@ public void setTransactionIsolation(int level) throws SQLException { } public int getTransactionIsolation() throws SQLException { - if (transactionIsolation == TRANSACTION_NONE) { - try { - requestDBParameter(); - } catch (IOException e) { - throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( - CUBRIDServerSideJDBCErrorCode.ER_COMMUNICATION, e); - } + try { + requestDBParameter(); + } catch (IOException e) { + throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( + CUBRIDServerSideJDBCErrorCode.ER_COMMUNICATION, e); } return transactionIsolation; @@ -405,16 +424,14 @@ public void setClientInfo(String arg0, String arg1) throws SQLClientInfoExceptio /* JDK 1.6 */ public Properties getClientInfo() throws SQLException { - if (clientInfo == null) { - try { - requestDBParameter(); - } catch (IOException e) { - throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( - CUBRIDServerSideJDBCErrorCode.ER_COMMUNICATION, e); - } + try { + requestDBParameter(); + } catch (IOException e) { + throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( + CUBRIDServerSideJDBCErrorCode.ER_COMMUNICATION, e); } - return clientInfo; + return context.getClientInfo(); } /* JDK 1.6 */ diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java similarity index 95% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java index bef3dba9363..fbce70377e6 100644 --- a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideConstants.java @@ -69,4 +69,8 @@ public class CUBRIDServerSideConstants { DROP_ELEMENT_IN_SEQUENCE = 5, INSERT_ELEMENT_INTO_SEQUENCE = 6, PUT_ELEMENT_ON_SEQUENCE = 7; + + /* end transaction constants */ + public static final byte END_TRAN_COMMIT = 1; + public static final byte END_TRAN_ROLLBACK = 2; } diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideDatabaseMetaData.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideDatabaseMetaData.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideDatabaseMetaData.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideDatabaseMetaData.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java similarity index 71% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java index c4fdfb55332..fa3fe5d560f 100644 --- a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideDriver.java @@ -31,7 +31,7 @@ package com.cubrid.jsp.jdbc; -import java.lang.reflect.Method; +import com.cubrid.jsp.context.ContextManager; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; @@ -40,11 +40,16 @@ import java.util.Properties; import java.util.StringTokenizer; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class CUBRIDServerSideDriver implements Driver { private static final String JDBC_DEFAULT_CONNECTION = "jdbc:default:connection"; + private static final String JDBC_DEFAULT_CONNECTION_PATTERN = + "jdbc:default:connection(::\\?[a-zA-Z_0-9]+=[^&=?]+(&[a-zA-Z_0-9]+=[^&=?]+)*)?"; + private static String VERSION_STRING; private static int VERSION_MAJOR; private static int VERSION_MINOR; @@ -78,22 +83,25 @@ public Connection connect(String url, Properties info) throws SQLException { return null; } - Connection conn = null; - try { - Thread t = Thread.currentThread(); - conn = - (Connection) - invoke( - "com.cubrid.jsp.ExecuteThread", - "createConnection", - null, - t, - null); - } catch (Exception e) { - /* do nothing. The exception will be dealt with in ExecuteThread */ + Pattern pattern = + Pattern.compile(JDBC_DEFAULT_CONNECTION_PATTERN, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(url); + if (!matcher.find()) { + // TODO: error? + return null; } - return conn; + setDefaultProperties(info); + + // parse property + String prop = matcher.group(1); + if (prop != null) { + setProperties(prop, info); + } + + Thread t = Thread.currentThread(); + Long ctxId = ContextManager.getContextIdByThreadId(t.getId()); + return ContextManager.getContext(ctxId).getConnection(info); } @Override @@ -109,6 +117,25 @@ public boolean acceptsURL(String url) throws SQLException { return false; } + private void setProperties(String propertyString, Properties info) { + StringTokenizer st = new StringTokenizer(propertyString, "?&;"); + while (st.hasMoreTokens()) { + String propString = st.nextToken(); + StringTokenizer pt = new StringTokenizer(propString, "="); + if (pt.hasMoreTokens()) { + String name = pt.nextToken().toLowerCase(); + if (pt.hasMoreTokens()) { + String value = pt.nextToken(); + info.put(name, value); + } + } + } + } + + private void setDefaultProperties(Properties info) { + info.setProperty("transaction_control", "false"); + } + @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return new DriverPropertyInfo[0]; @@ -133,15 +160,4 @@ public boolean jdbcCompliant() { public Logger getParentLogger() { throw new java.lang.UnsupportedOperationException(); } - - private Object invoke( - String cls_name, String method, Class[] param_cls, Object cls, Object[] params) { - try { - Class c = Class.forName(cls_name); - Method m = c.getMethod(method, param_cls); - return m.invoke(cls, params); - } catch (Exception e) { - throw new RuntimeException(e); - } - } } diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorCode.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorCode.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorCode.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorCode.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorManager.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorManager.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorManager.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideJDBCErrorManager.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideOID.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideOID.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideOID.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideOID.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideOutResultSet.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideOutResultSet.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideOutResultSet.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideOutResultSet.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSidePreparedStatement.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSidePreparedStatement.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSidePreparedStatement.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSidePreparedStatement.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java similarity index 99% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java index d1a9acac538..044308d884f 100644 --- a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSet.java @@ -451,7 +451,7 @@ public Object getObject(String columnName) throws SQLException { public int findColumn(String columnName) throws SQLException { Integer index = statementHandler.getColNameIndex().get(columnName.toLowerCase()); if (index == null) { - CUBRIDServerSideJDBCErrorManager.createCUBRIDException( + throw CUBRIDServerSideJDBCErrorManager.createCUBRIDException( CUBRIDServerSideJDBCErrorCode.ER_INVALID_COLUMN_NAME, null); } diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSetMetaData.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSetMetaData.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSetMetaData.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideResultSetMetaData.java diff --git a/src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideStatement.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideStatement.java similarity index 100% rename from src/jsp/com/cubrid/jsp/jdbc/CUBRIDServerSideStatement.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/jdbc/CUBRIDServerSideStatement.java diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsRequest.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsRequest.java new file mode 100644 index 00000000000..068c81a067f --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsRequest.java @@ -0,0 +1,26 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDPacker; +import com.cubrid.plcsql.compiler.serverapi.ServerAPI.Question; +import java.util.List; + +public class GlobalSemanticsRequest implements PackableObject { + + public List questions = null; + + public GlobalSemanticsRequest(List questions) { + this.questions = questions; + } + + @Override + public void pack(CUBRIDPacker packer) { + if (questions != null) { + packer.packBigInt(questions.size()); + for (Question q : questions) { + q.pack(packer); + } + } else { + assert false; + } + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsResponse.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsResponse.java new file mode 100644 index 00000000000..300466d9785 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/GlobalSemanticsResponse.java @@ -0,0 +1,31 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDUnpacker; +import com.cubrid.plcsql.compiler.serverapi.ServerAPI.Question; +import java.util.List; + +public class GlobalSemanticsResponse implements UnPackableObject { + + public List semantics = null; + + public GlobalSemanticsResponse(List semantics, CUBRIDUnpacker unpacker) { + this.semantics = semantics; + unpack(unpacker); + } + + @Override + public void unpack(CUBRIDUnpacker unpacker) { + int size = (int) unpacker.unpackBigint(); + if (size > 0) { + for (int i = 0; i < size; i++) { + semantics.get(i).unpack(unpacker); + } + } else { + assert false; + } + } + + public List getResponse() { + return semantics; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/Header.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/Header.java new file mode 100644 index 00000000000..9f2efef85a5 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/Header.java @@ -0,0 +1,38 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDUnpacker; + +public class Header { + + public static final int EMPTY_SESSION_ID = 0; + public static final int BYTES = getHeaderSize(); + + public long id; // DB SESSION ID + public int code; // code + public int requestId; // request Id + + /* for runtime */ + public int payloadSize = 0; + public boolean hasPayload = false; + + public Header(CUBRIDUnpacker unpacker) { + id = unpacker.unpackBigint(); + code = unpacker.unpackInt(); + requestId = unpacker.unpackInt(); + } + + public Header(long id, int code, int size) { + this.id = id; + this.code = code; + this.requestId = size; + } + + @Override + public String toString() { + return "Header [id=" + id + ", code=" + code + ", rid=" + requestId + "]"; + } + + public static int getHeaderSize() { + return 16; + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PackableObject.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PackableObject.java new file mode 100644 index 00000000000..7e8f90bcc58 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PackableObject.java @@ -0,0 +1,7 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDPacker; + +public interface PackableObject { + void pack(CUBRIDPacker packer); +} 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 new file mode 100644 index 00000000000..d52e29d7270 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/PrepareArgs.java @@ -0,0 +1,53 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDUnpacker; +import com.cubrid.jsp.exception.TypeMismatchException; +import com.cubrid.jsp.value.Value; + +public class PrepareArgs { + + private long groupId = -1; + private int tranId; + private Value[] arguments = null; + + public PrepareArgs(CUBRIDUnpacker unpacker) throws TypeMismatchException { + readArgs(unpacker); + } + + public void setArgs(Value[] args) { + this.arguments = args; + } + + public Value[] getArgs() { + return arguments; + } + + public int getArgCount() { + if (arguments == null) { + return -1; + } else { + return arguments.length; + } + } + + public int getTranId() { + return tranId; + } + + public void readArgs(CUBRIDUnpacker unpacker) throws TypeMismatchException { + groupId = unpacker.unpackBigint(); + tranId = unpacker.unpackInt(); + int argCount = unpacker.unpackInt(); + + if (arguments == null || argCount != arguments.length) { + arguments = new Value[argCount]; + } + + for (int i = 0; i < arguments.length; i++) { + int paramType = unpacker.unpackInt(); + + Value arg = unpacker.unpackValue(paramType); + arguments[i] = (arg); + } + } +} 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 new file mode 100644 index 00000000000..59fc505d7bc --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/RequestCode.java @@ -0,0 +1,24 @@ +package com.cubrid.jsp.protocol; + +public class RequestCode { + public static final int INVOKE_SP = 0x01; + public static final int RESULT = 0x02; + public static final int ERROR = 0x04; + public static final int INTERNAL_JDBC = 0x08; + + // private static final int DESTROY = 0x10; + // private static final int END = 0x20; + + public static final int PREPARE_ARGS = 0x40; + + public static final int COMPILE = 0x80; + + public static final int REQUEST_SQL_SEMANTICS = 0xA0; + public static final int REQUEST_GLOBAL_SEMANTICS = 0xA1; + public static final int REQUEST_BUILTIN_FUNCTION = 0xA4; + + public static final int UTIL_PING = 0xDE; + public static final int UTIL_STATUS = 0xEE; + public static final int UTIL_TERMINATE_THREAD = 0xFE; + public static final int UTIL_TERMINATE_SERVER = 0xFF; // to shutdown javasp server +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsRequest.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsRequest.java new file mode 100644 index 00000000000..44e4886b868 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsRequest.java @@ -0,0 +1,24 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDPacker; +import java.util.List; + +public class SqlSemanticsRequest implements PackableObject { + + public List sqlTexts = null; + + public SqlSemanticsRequest(List sqls) { + this.sqlTexts = sqls; + } + + public void pack(CUBRIDPacker packer) { + if (sqlTexts != null) { + packer.packInt(sqlTexts.size()); + for (String s : sqlTexts) { + packer.packString(s); + } + } else { + packer.packInt(0); + } + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsResponse.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsResponse.java new file mode 100644 index 00000000000..2b971a8544d --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/SqlSemanticsResponse.java @@ -0,0 +1,27 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDUnpacker; +import com.cubrid.plcsql.compiler.serverapi.SqlSemantics; +import java.util.ArrayList; +import java.util.List; + +public class SqlSemanticsResponse implements UnPackableObject { + + public List semantics = null; + + public SqlSemanticsResponse(CUBRIDUnpacker unpacker) { + unpack(unpacker); + } + + @Override + public void unpack(CUBRIDUnpacker unpacker) { + int size = unpacker.unpackInt(); + if (size > 0) { + semantics = new ArrayList(size); + for (int i = 0; i < size; i++) { + SqlSemantics s = new SqlSemantics(unpacker); + semantics.add(s); + } + } + } +} diff --git a/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/UnPackableObject.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/UnPackableObject.java new file mode 100644 index 00000000000..210083d30b0 --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/protocol/UnPackableObject.java @@ -0,0 +1,7 @@ +package com.cubrid.jsp.protocol; + +import com.cubrid.jsp.data.CUBRIDUnpacker; + +public interface UnPackableObject { + void unpack(CUBRIDUnpacker packer); +} diff --git a/src/jsp/com/cubrid/jsp/value/BooleanValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java similarity index 96% rename from src/jsp/com/cubrid/jsp/value/BooleanValue.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java index a5865131382..8c948bbdc90 100644 --- a/src/jsp/com/cubrid/jsp/value/BooleanValue.java +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/BooleanValue.java @@ -70,6 +70,10 @@ public Double toDoubleObject() throws TypeMismatchException { return new Double(value); } + public Object toObject() { + return Boolean.valueOf(value == 1 ? true : false); + } + public String toString() { return "" + value; } diff --git a/src/jsp/com/cubrid/jsp/value/ByteValue.java b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ByteValue.java similarity index 100% rename from src/jsp/com/cubrid/jsp/value/ByteValue.java rename to pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/ByteValue.java 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 new file mode 100644 index 00000000000..7b6859dbf3f --- /dev/null +++ b/pl_engine/pl_server/src/main/java/com/cubrid/jsp/value/DateTimeParser.java @@ -0,0 +1,385 @@ +/* + * 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.value; + +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Locale; + +public class DateTimeParser { + + private static final ZoneOffset TIMEZONE_0 = ZoneOffset.of("Z"); + // TODO: update the following value along with the server + private static final ZoneOffset TIMEZONE_SESSION = ZoneOffset.of("+09:00"); + + // zoneless part of min timestamp: 1970-01-01 00:00:01 + private static final LocalDateTime minTimestampLocal = LocalDateTime.of(1970, 1, 1, 0, 0, 1); + // zoneless part of max timestamp local part: 2038-01-19 03:14:07 + private static final LocalDateTime maxTimestampLocal = LocalDateTime.of(2038, 1, 19, 3, 14, 7); + // min datetime: 0001-01-01 00:00:00.000 + private static final LocalDateTime minDatetime = LocalDateTime.of(1, 1, 1, 0, 0, 0, 0); + // max datetime: 9999-12-31 23:59:59.999 + private static final LocalDateTime maxDatetime = + LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999); + + private static final ZonedDateTime minTimestamp = + ZonedDateTime.of(minTimestampLocal, TIMEZONE_0); + private static final ZonedDateTime maxTimestamp = + ZonedDateTime.of(maxTimestampLocal, TIMEZONE_0); + private static final ZonedDateTime minDatetimeUTC = ZonedDateTime.of(minDatetime, TIMEZONE_0); + private static final ZonedDateTime maxDatetimeUTC = ZonedDateTime.of(maxDatetime, TIMEZONE_0); + + public static final LocalDate nullDate = LocalDate.MAX; + public static final LocalDateTime nullDatetime = LocalDateTime.MAX; + public static final ZonedDateTime nullDatetimeUTC = ZonedDateTime.of(nullDatetime, TIMEZONE_0); + + public static class DateLiteral { + + public static LocalDate parse(String s) { + LocalDate ret = parseDateFragment(s); + + if (ret != null + && ret != nullDate + && (ret.compareTo(minDate) < 0 || ret.compareTo(maxDate) > 0)) { + return null; + } + + return ret; + } + + // --------------------------------------- + // Private + // --------------------------------------- + + private static final LocalDate minDate = LocalDate.of(1, 1, 1); // 0001-01-01 + private static final LocalDate maxDate = LocalDate.of(9999, 12, 31); // 9999-12-31 + } + + public static class TimeLiteral { + + public static LocalTime parse(String s) { + return parseTimeFragment(s, false); + } + } + + public static class TimestampLiteral { + + public static ZonedDateTime parse(String s) { + return ZonedDateTimeLiteral.parse( + s, false); // same as TIMESTAMPLTZ with timezone omitted + } + } + + public static class DatetimeLiteral { + + public static LocalDateTime parse(String s) { + + LocalDateTime ret = parseDateAndTime(s, true); + if (ret != null + && ret != nullDatetime + && (ret.compareTo(minDatetime) < 0 || ret.compareTo(maxDatetime) > 0)) { + return null; + } + + return ret; + } + } + + public static class ZonedDateTimeLiteral { + public static ZonedDateTime parse(String s, boolean forDatetime) { + return parseZonedDateAndTime(s, forDatetime); + } + } + + // --------------------------------------- + // Private + // --------------------------------------- + + // returns a ZonedDateTime when a timezone offset is given, otherwise returns a LocalDateTime + public static ZonedDateTime parseZonedDateAndTime(String s, boolean forDatetime) { + + // get timezone offset + LocalDateTime localPart; + ZoneOffset zone; + int delim = s.lastIndexOf(" "); + if (delim < 0) { + // no timezone offset + localPart = parseDateAndTime(s, forDatetime); + zone = TIMEZONE_SESSION; + } else { + String dt = s.substring(0, delim); + String z = s.substring(delim + 1); + try { + localPart = parseDateAndTime(dt, forDatetime); + zone = ZoneOffset.of(z); + } catch (DateTimeException e) { + // z turn out not to be a timezone offset. try timezone omitted string + localPart = parseDateAndTime(s, forDatetime); + zone = TIMEZONE_SESSION; + } + } + + if (localPart == null) { + return null; + } + if (localPart == nullDatetime) { + return nullDatetimeUTC; + } + + ZonedDateTime ret = ZonedDateTime.of(localPart, zone); + if (forDatetime) { + if (ret.compareTo(minDatetimeUTC) < 0 || ret.compareTo(maxDatetimeUTC) > 0) { + return null; + } + } else { + // in this case, for TIMESTAMP* + if (ret.compareTo(minTimestamp) < 0 || ret.compareTo(maxTimestamp) > 0) { + return null; + } + } + + return ret; + } + + private static LocalDateTime parseDateAndTime(String s, boolean millis) { + + s = s.trim(); + + String timeStr, dateStr; + int colonIdx = s.indexOf(":"); + if (colonIdx == 1 || colonIdx == 2) { + // order: