From e42b5a898f9525586172036b55bbb79ea346b88d Mon Sep 17 00:00:00 2001 From: Thomas Ubensee <34603111+tomuben@users.noreply.github.com> Date: Wed, 30 Oct 2024 05:58:58 -0300 Subject: [PATCH] #988: Adapted Java integration tests for new ScriptOptions parser (#464) related to exasol/script-languages-release#988 --- .../tests/lang/java/get_connection.sql | 13 ++ .../tests/test/generic/get_connection.py | 6 + .../tests/test/java/external_jar_files.py | 83 ++++++++ test_container/tests/test/java/general.py | 181 +++++++++++++---- .../tests/test/java/java_modules.py | 17 +- .../tests/test/java/script_import.py | 182 +++++++++++++----- 6 files changed, 391 insertions(+), 91 deletions(-) create mode 100644 test_container/tests/test/java/external_jar_files.py diff --git a/test_container/tests/lang/java/get_connection.sql b/test_container/tests/lang/java/get_connection.sql index af91c06b8..c8b87eac0 100644 --- a/test_container/tests/lang/java/get_connection.sql +++ b/test_container/tests/lang/java/get_connection.sql @@ -10,6 +10,19 @@ class PRINT_CONNECTION { } / +CREATE or replace java SCALAR SCRIPT print_connection_v2(conn varchar (1000)) +emits(type varchar(200), addr varchar(2000000), usr varchar(2000000), pwd varchar(2000000)) +as +%env SCRIPT_OPTIONS_PARSER_VERSION=2; +%jvmoption -Xms64m -Xmx128m -Xss512k; +class PRINT_CONNECTION_V2 { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ExaConnectionInformation c = exa.getConnection(ctx.getString("conn")); + ctx.emit(c.getType().toString().toLowerCase(),c.getAddress(),c.getUser(), c.getPassword()); + } +} +/ + CREATE or replace java SET SCRIPT print_connection_set_emits(conn varchar (1000)) emits(type varchar(200), addr varchar(2000000), usr varchar(2000000), pwd varchar(2000000)) as diff --git a/test_container/tests/test/generic/get_connection.py b/test_container/tests/test/generic/get_connection.py index fa3797c98..7f5ad9d39 100644 --- a/test_container/tests/test/generic/get_connection.py +++ b/test_container/tests/test/generic/get_connection.py @@ -48,6 +48,12 @@ def test_connection_not_found(self): SELECT fn1.print_connection('FOO') ''') + @requires('PRINT_CONNECTION_V2') + def test_print_existing_connection_v2(self): + rows = self.query(''' + SELECT fn1.print_connection_v2('FOOCONN') + ''') + self.assertRowsEqual([('password', 'a', 'b', 'c')], rows) class GetConnectionAccessControlTest(udf.TestCase): def setUp(self): diff --git a/test_container/tests/test/java/external_jar_files.py b/test_container/tests/test/java/external_jar_files.py new file mode 100644 index 000000000..fe9c9ee02 --- /dev/null +++ b/test_container/tests/test/java/external_jar_files.py @@ -0,0 +1,83 @@ +import os +import shutil +import subprocess +import tempfile +from pathlib import Path +import tarfile + +import requests +from exasol_python_test_framework import udf +from exasol_python_test_framework import docker_db_environment +from exasol_python_test_framework.udf import useData, expectedFailure +from exasol_python_test_framework.udf.udf_debug import UdfDebugger +from exasol_python_test_framework.exatest.utils import obj_from_json_file +from requests.auth import HTTPBasicAuth + +script_dir = Path(os.path.dirname(os.path.realpath(__file__))) +java_udf_dir = script_dir / "resources/java_udf" + +@udf.skipIfNot(docker_db_environment.is_available, reason="This test requires a docker-db environment") +class JavaExtJarFileReferences(udf.TestCase): + """ + Test for the Script Options Parser v2 which validates that correct processing of the (%jar) option. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.java_udf_jar_java = self.build_java_udf() + + def setUp(self): + self.query('CREATE SCHEMA JAVA_MODULES', ignore_errors=True) + self.query('OPEN SCHEMA JAVA_MODULES') + self.env = docker_db_environment.DockerDBEnvironment("JAVA_MODULE_TEST") + self.jar_target = self.build_java_udf() + + def build_java_udf(self) -> Path: + result = subprocess.run(["mvn", "--batch-mode", "--file", java_udf_dir / "pom.xml", "clean", "package", + f"-Djava.version=11"], stdout=subprocess.PIPE) + result.check_returncode() + jar = java_udf_dir / f"target/test-udf-java-11.jar" + assert jar.exists() + target = Path(tempfile.gettempdir()) / f"test-udf-java-11.jar" + shutil.move(jar, target) + return target + + def upload_to_bucketfs(self, src_path: Path, expected_jar_in_script_option: str, target_filename: str) -> str: + env_info = obj_from_json_file("/environment_info.json") + docker_db_ip = env_info.database_info.container_info.ip_address + bucketfs_port = env_info.database_info.ports.bucketfs + with tempfile.TemporaryDirectory() as tmp_dir: + local_target_file_path = Path(tmp_dir) / target_filename + shutil.copy(src_path, local_target_file_path) + target_targz_filename = Path(tmp_dir) / "java_jar_ref_test.tar.gz" + with tarfile.open(target_targz_filename, "w:gz") as tar: + tar.add(local_target_file_path, arcname=target_filename) + upload_url = f"http://{docker_db_ip}:{bucketfs_port}/myudfs/jar_references_test/java_jar_ref_test.tar.gz" + username = "w" + password = "write" + print(f"Trying to upload to {upload_url}") + r_upload = requests.put(upload_url, data=target_targz_filename.read_bytes(), auth=HTTPBasicAuth(username, password)) + r_upload.raise_for_status() + return f"/buckets/bfsdefault/myudfs/jar_references_test/java_jar_ref_test/{expected_jar_in_script_option}" + + @useData([("java_jar.jar", "java_jar.jar"), ("java_jar.jar\ ", "java_jar.jar "), + (r"java_jar.jar\ ", r"java_jar.jar "), ("java_jar.jar\\t", "java_jar.jar\t"), + ("java_jar.jar ", "java_jar.jar")]) + def test_jar_references(self, expected_jar_in_script_option, uploaded_jar): + """ + Install the jar file with the specific file name in BucketFS, and then create the UDF + which uses this JAR file name. The JAR filename in the UDF (%jar) needs to be properly encoded. + """ + bucketfs_path = self.upload_to_bucketfs(self.jar_target, expected_jar_in_script_option, uploaded_jar) + self.query(udf.fixindent(f''' + CREATE OR REPLACE JAVA SCALAR SCRIPT JAVA_TEST_JAR_UDF() RETURNS INT AS + %scriptclass com.exasol.slc.testudf.Main; + %env SCRIPT_OPTIONS_PARSER_VERSION=2; + %jar {bucketfs_path}; + ''')) + rows = self.query(f"SELECT JAVA_TEST_JAR_UDF()") + self.assertGreaterEqual(rows[0][0], 11) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/java/general.py b/test_container/tests/test/java/general.py index 534562a30..c203bef37 100755 --- a/test_container/tests/test/java/general.py +++ b/test_container/tests/test/java/general.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from exasol_python_test_framework import udf +from exasol_python_test_framework.exatest import useData class JavaInterpreter(udf.TestCase): @@ -110,7 +111,7 @@ class FOO { ''')) with self.assertRaisesRegex(Exception, '4711'): self.query('SELECT foo() FROM dual') - + def test_exception_in_run_and_cleanup_is_propagated(self): out, _err = self.query_via_exaplus(udf.fixindent(''' DROP SCHEMA test_exception_in_run_and_cleanup_is_propagated CASCADE; @@ -161,25 +162,38 @@ class FOO { class JavaJar(udf.TestCase): + + legacy_env_declaration = "" + ctpg_parser_env_declaration = "%env SCRIPT_OPTIONS_PARSER_VERSION=2;" + additional_env_declarations = [(legacy_env_declaration,), (ctpg_parser_env_declaration,)] + def setUp(self): self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) self.query('CREATE SCHEMA FN2') - def test_jar_path(self): + @useData(((legacy_env_declaration, 'No values found for %jar statement'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:5\] PARSE: Syntax error: Unexpected \'\'"))) + def test_jar_path(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jar_path() RETURNS int AS + ''' + additional_env_declaration + ''' %jar ''')) - with self.assertRaisesRegex(Exception, 'No values found for %jar statement'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jar_path() FROM dual') - def test_jar_path2(self): + @useData(((legacy_env_declaration, 'End of %jar statement not found'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:5\] PARSE: Syntax error: Unexpected \'\'"))) + def test_jar_path2(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jar_path2() RETURNS int AS + ''' + additional_env_declaration + ''' %jar class TEST_JAR_PATH2 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -188,14 +202,18 @@ class TEST_JAR_PATH2 { } } ''')) - with self.assertRaisesRegex(Exception, 'End of %jar statement not found'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jar_path2() FROM dual') - def test_jar_path3(self): + @useData(((legacy_env_declaration, 'No values found for %jar statement'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:6\] PARSE: Syntax error: Unexpected \';\'"))) + def test_jar_path3(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jar_path3() RETURNS int AS + ''' + additional_env_declaration + ''' %jar ; class TEST_JAR_PATH3 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -204,23 +222,29 @@ class TEST_JAR_PATH3 { } } ''')) - with self.assertRaisesRegex(Exception, 'No values found for %jar statement'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jar_path3() FROM dual') - def test_jar_path_end(self): + @useData(((legacy_env_declaration, 'End of %jar statement not found'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:20\] PARSE: Syntax error: Unexpected \'\'"))) + def test_jar_path_end(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jar_path_end() RETURNS int AS + ''' + additional_env_declaration + ''' %jar /my/path/x.jar''')) - with self.assertRaisesRegex(Exception, 'End of %jar statement not found'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jar_path_end() FROM dual') - def test_jar_tab(self): + @useData(additional_env_declarations) + def test_jar_tab(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_tab() RETURNS int AS + ''' + additional_env_declaration + ''' %jar /my/path/x.jar; class JAR_CASE_TAB { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -231,11 +255,18 @@ class JAR_CASE_TAB { with self.assertRaisesRegex(Exception, 'No such file or directory'): rows = self.query('SELECT jar_case_tab() FROM DUAL') - def test_jar_tab_end(self): + @useData(additional_env_declarations) + def test_jar_tab_end(self, additional_env_declaration): + """ + Note that both parser throw errors for different reasons: + 1. The legacy parser will convert '/my/path/x.jar ' to '/my/path/x.jar' + 2. The ctpg based parser will keep the trailing white spaces. + """ self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_tab_end() RETURNS int AS + ''' + additional_env_declaration + ''' %jar /my/path/x.jar ; class JAR_CASE_TAB_END { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -246,11 +277,13 @@ class JAR_CASE_TAB_END { with self.assertRaisesRegex(Exception, 'No such file or directory'): rows = self.query('SELECT jar_case_tab_end() FROM DUAL') - def test_jar_multiple_statements(self): + @useData(additional_env_declarations) + def test_jar_multiple_statements(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_multi_statements() RETURNS int AS + ''' + additional_env_declaration + ''' %jar /my/path/x.jar; %jar /my/path/x2.jar; class JAR_CASE_MULTI_STATEMENTS { @@ -262,11 +295,13 @@ class JAR_CASE_MULTI_STATEMENTS { with self.assertRaisesRegex(Exception, 'No such file or directory'): rows = self.query('SELECT jar_case_multi_statements() FROM DUAL') - def test_jar_commented(self): + @useData(additional_env_declarations) + def test_jar_commented(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_commented() RETURNS int AS + ''' + additional_env_declaration + ''' // %jar /my/path/x.jar; class JAR_CASE_COMMENTED { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -277,11 +312,13 @@ class JAR_CASE_COMMENTED { rows = self.query('SELECT jar_case_commented() FROM DUAL') self.assertEqual(1, rows[0][0]) - def test_jar_commented_after_code(self): + @useData(additional_env_declarations) + def test_jar_commented_after_code(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_commented_after_code() RETURNS int AS + ''' + additional_env_declaration + ''' class JAR_CASE_COMMENTED_AFTER_CODE { // %jar /my/path/x.jar; static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return 1; @@ -291,11 +328,13 @@ class JAR_CASE_COMMENTED_AFTER_CODE { // %jar /my/path/x.jar; rows = self.query('SELECT jar_case_commented_after_code() FROM DUAL') self.assertEqual(1, rows[0][0]) - def test_jar_after_code(self): + @useData(additional_env_declarations) + def test_jar_after_code(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_after_code() RETURNS int AS + ''' + additional_env_declaration + ''' class JAR_CASE_AFTER_CODE { %jar /my/path/x.jar; static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return 1; @@ -305,12 +344,13 @@ class JAR_CASE_AFTER_CODE { %jar /my/path/x.jar; with self.assertRaisesRegex(Exception, 'VM error:'): rows = self.query('SELECT jar_case_after_code() FROM DUAL') - - def test_jar_multiple_jars(self): + @useData(additional_env_declarations) + def test_jar_multiple_jars(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT jar_case_multi_jars() RETURNS int AS + ''' + additional_env_declaration + ''' %jar /my/path/x.jar:/my/path/x2.jar; class JAR_CASE_MULTI_JARS { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -380,25 +420,38 @@ class JAVA_COMMENTS { class JavaJvmOption(udf.TestCase): + + legacy_env_declaration = "" + ctpg_parser_env_declaration = "%env SCRIPT_OPTIONS_PARSER_VERSION=2;" + additional_env_declarations = [(legacy_env_declaration,), (ctpg_parser_env_declaration,)] + def setUp(self): self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) self.query('CREATE SCHEMA FN2') - def test_jvm_opt(self): + @useData(((legacy_env_declaration, 'No values found for %jvmoption statement'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:11\] PARSE: Syntax error: Unexpected \'\'"))) + def test_jvm_opt(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption ''')) - with self.assertRaisesRegex(Exception, 'No values found for %jvmoption statement'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jvm_opt() FROM dual') - def test_jvm_opt2(self): + @useData(((legacy_env_declaration, 'End of %jvmoption statement not found'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:11\] PARSE: Syntax error: Unexpected \'\'"))) + def test_jvm_opt2(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt2() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption class TEST_JVM_OPT2 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -407,14 +460,18 @@ class TEST_JVM_OPT2 { } } ''')) - with self.assertRaisesRegex(Exception, 'End of %jvmoption statement not found'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jvm_opt2() FROM dual') - def test_jvm_opt3(self): + @useData(((legacy_env_declaration, 'No values found for %jvmoption statement'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:12\] PARSE: Syntax error: Unexpected \';\'"))) + def test_jvm_opt3(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt3() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption ; class TEST_JVM_OPT3 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -423,23 +480,29 @@ class TEST_JVM_OPT3 { } } ''')) - with self.assertRaisesRegex(Exception, 'No values found for %jvmoption statement'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jvm_opt3() FROM dual') - def test_jvm_opt4(self): + @useData(((legacy_env_declaration, 'End of %jvmoption statement not found'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:20\] PARSE: Syntax error: Unexpected \'\'"))) + def test_jvm_opt4(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt4() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmx512m''')) - with self.assertRaisesRegex(Exception, 'End of %jvmoption statement not found'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT test_jvm_opt4() FROM dual') - def test_jvm_opt_tab(self): + @useData(additional_env_declarations) + def test_jvm_opt_tab(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_tab() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmx512m; class TEST_JVM_OPT_TAB { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -450,11 +513,13 @@ class TEST_JVM_OPT_TAB { rows = self.query('SELECT test_jvm_opt_tab() FROM DUAL') self.assertEqual(1, rows[0][0]) - def test_jvm_opt_tab_end(self): + @useData(additional_env_declarations) + def test_jvm_opt_tab_end(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_tab_end() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmx512m ; class TEST_JVM_OPT_TAB_END { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -465,11 +530,13 @@ class TEST_JVM_OPT_TAB_END { rows = self.query('SELECT test_jvm_opt_tab_end() FROM DUAL') self.assertEqual(1, rows[0][0]) - def test_jvm_opt_multiple_opts(self): + @useData(additional_env_declarations) + def test_jvm_opt_multiple_opts(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_multiple_opts() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xms56m -Xmx128m -Xss512k; class TEST_JVM_OPT_MULTIPLE_OPTS { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -480,11 +547,13 @@ class TEST_JVM_OPT_MULTIPLE_OPTS { rows = self.query('SELECT test_jvm_opt_multiple_opts() FROM DUAL') self.assertEqual(1, rows[0][0]) - def test_jvm_opt_multiple_opts2(self): + @useData(additional_env_declarations) + def test_jvm_opt_multiple_opts2(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_multiple_opts2() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmx5000m; %jvmoption -Xms56m -Xmx128m -Xss1k; %jvmoption -Xss512k -Xms128m; @@ -497,11 +566,13 @@ class TEST_JVM_OPT_MULTIPLE_OPTS2 { rows = self.query('SELECT test_jvm_opt_multiple_opts2() FROM DUAL') self.assertEqual(1, rows[0][0]) - def test_jvm_opt_invalid_opt(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_opt(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_opt() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmj56m; class TEST_JVM_OPT_INVALID_OPT { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -512,11 +583,13 @@ class TEST_JVM_OPT_INVALID_OPT { with self.assertRaisesRegex(Exception, '.*Cannot start the JVM: unknown error.*'): rows = self.query('SELECT test_jvm_opt_invalid_opt() FROM dual') - def test_jvm_opt_invalid_opt2(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_opt2(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_opt2() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmx56m junk; class TEST_JVM_OPT_INVALID_OPT2 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -527,11 +600,13 @@ class TEST_JVM_OPT_INVALID_OPT2 { with self.assertRaisesRegex(Exception, '.*Cannot start the JVM: unknown error.*'): rows = self.query('SELECT test_jvm_opt_invalid_opt2() FROM dual') - def test_jvm_opt_invalid_opt3(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_opt3(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_opt3() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xjunk; %jvmoption -Xmx56m; class TEST_JVM_OPT_INVALID_OPT3 { @@ -543,11 +618,13 @@ class TEST_JVM_OPT_INVALID_OPT3 { with self.assertRaisesRegex(Exception, '.*Cannot start the JVM: unknown error.*'): rows = self.query('SELECT test_jvm_opt_invalid_opt3() FROM dual') - def test_jvm_opt_invalid_opt4(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_opt4(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_opt4() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xms56q; class TEST_JVM_OPT_INVALID_OPT4 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -558,11 +635,13 @@ class TEST_JVM_OPT_INVALID_OPT4 { with self.assertRaisesRegex(Exception, 'invalid arguments'): rows = self.query('SELECT test_jvm_opt_invalid_opt4() FROM dual') - def test_jvm_opt_invalid_mem(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_mem(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_mem() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xmx900000000m; class TEST_JVM_OPT_INVALID_MEM { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -573,11 +652,13 @@ class TEST_JVM_OPT_INVALID_MEM { with self.assertRaisesRegex(Exception, 'VM crashed'): rows = self.query('SELECT test_jvm_opt_invalid_mem() FROM dual') - def test_jvm_opt_invalid_mem2(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_mem2(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_mem2() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xms1m -Xmx1m; class TEST_JVM_OPT_INVALID_MEM2 { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -588,11 +669,13 @@ class TEST_JVM_OPT_INVALID_MEM2 { with self.assertRaisesRegex(Exception, 'VM error:'): rows = self.query('SELECT test_jvm_opt_invalid_mem2() FROM dual') - def test_jvm_opt_invalid_stack_size(self): + @useData(additional_env_declarations) + def test_jvm_opt_invalid_stack_size(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT test_jvm_opt_invalid_stack_size() RETURNS int AS + ''' + additional_env_declaration + ''' %jvmoption -Xss1k; class TEST_JVM_OPT_INVALID_STACK_SIZE { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -605,14 +688,19 @@ class TEST_JVM_OPT_INVALID_STACK_SIZE { class JavaScriptClass(udf.TestCase): + + additional_env_declarations = [("",), ("%env SCRIPT_OPTIONS_PARSER_VERSION=2;",)] + def setUp(self): self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) self.query('CREATE SCHEMA FN2') - def test_set_script_class(self): + @useData(additional_env_declarations) + def test_set_script_class(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT A() RETURNS int AS + ''' + additional_env_declaration + ''' %scriptclass com.exasol.B; class B { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -623,10 +711,13 @@ class B { self.assertRowsEqual([(1,)], self.query('''SELECT a()''')) - def test_set_script_class_2(self): + + @useData(additional_env_declarations) + def test_set_script_class_2(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT A() RETURNS int AS + ''' + additional_env_declaration + ''' %scriptclass com.exasol.B ; class B { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -637,10 +728,12 @@ class B { self.assertRowsEqual([(1,)], self.query('''SELECT a()''')) - def test_set_invalid_script_class(self): + @useData(additional_env_declarations) + def test_set_invalid_script_class(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT A() RETURNS int AS + ''' + additional_env_declaration + ''' %scriptclass com.exasol.C; class B { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -651,10 +744,12 @@ class B { with self.assertRaisesRegex(Exception, 'The main script class .* cannot be found:'): self.query('''SELECT a()''') - def test_set_invalid_script_class_2(self): + @useData(additional_env_declarations) + def test_set_invalid_script_class_2(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT A() RETURNS int AS + ''' + additional_env_declaration + ''' // Looks correct, however the script B is in the com.exasol package implicitly. %scriptclass B; class B { @@ -666,10 +761,12 @@ class B { with self.assertRaisesRegex(Exception, 'The main script class .* cannot be found:'): self.query('''SELECT a()''') - def test_invalid_script_class(self): + @useData(additional_env_declarations) + def test_invalid_script_class(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT A() RETURNS int AS + ''' + additional_env_declaration + ''' class B { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return 1; @@ -684,7 +781,7 @@ class JavaGenericEmit(udf.TestCase): def setUp(self): self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) self.query('CREATE SCHEMA FN2') - + def test_emit_object_array_multi_arg(self): self.query(udf.fixindent(''' CREATE JAVA SET SCRIPT EMIT_OBJECT (a int) EMITS (a varchar(100), b int) AS diff --git a/test_container/tests/test/java/java_modules.py b/test_container/tests/test/java/java_modules.py index b2cb34dda..c0c44521c 100644 --- a/test_container/tests/test/java/java_modules.py +++ b/test_container/tests/test/java/java_modules.py @@ -24,6 +24,8 @@ class JavaModules(udf.TestCase): env = None java_udf_jar_java11 = None java_udf_jar_java17 = None + + additional_env_declarations = [("",), ("%env SCRIPT_OPTIONS_PARSER_VERSION=2;",)] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -65,15 +67,16 @@ def upload_to_bucketfs(self, path: Path) -> str: r_upload.raise_for_status() return f"/buckets/bfsdefault/myudfs/{path.name}" - - def test_java_11_udf(self): + @useData(additional_env_declarations) + def test_java_11_udf(self, additional_env_declaration): """ Verify that a module JAR built for Java 11 with a module-info.class can be used in a UDF. We don't know the JRE version installed in the SLC, so we accept both 11 and 17. """ - assert self.get_jre_version() in ["11", "17"] + assert self.get_jre_version(additional_env_declaration) in ["11", "17"] - def test_java_17_udf(self): + @useData(additional_env_declarations) + def test_java_17_udf(self, additional_env_declaration): """ Verify that a module JAR built for Java 17 can be used in a UDF. We don't know the JRE version installed in the SLC, so first check that it is 11 or 17. @@ -82,23 +85,25 @@ def test_java_17_udf(self): bucketfs_path = self.upload_to_bucketfs(self.java_udf_jar_java17) self.query(udf.fixindent(f''' CREATE JAVA SCALAR SCRIPT JAVA_17_UDF() RETURNS INT AS + {additional_env_declaration} %scriptclass com.exasol.slc.testudf.Main; %jar {bucketfs_path}; ''')) - if self.get_jre_version() == "17": + if self.get_jre_version(additional_env_declaration) == "17": rows = self.query("SELECT JAVA_17_UDF()") return str(rows[0][0]) else: with self.assertRaisesRegex(Exception, "UnsupportedClassVersionError: com/exasol/slc/testudf/Main has been compiled by a more recent version of the Java Runtime"): self.query("SELECT JAVA_17_UDF()") - def get_jre_version(self) -> str: + def get_jre_version(self, additional_env_declaration) -> str: """ Get the SLC's JRE version by executing a Java 11 UDF that returns the JRE major version ("11" or "17"). """ bucketfs_path = self.upload_to_bucketfs(self.java_udf_jar_java11) self.query(udf.fixindent(f''' CREATE JAVA SCALAR SCRIPT JRE_VERSION() RETURNS INT AS + {additional_env_declaration} %scriptclass com.exasol.slc.testudf.Main; %jar {bucketfs_path}; ''')) diff --git a/test_container/tests/test/java/script_import.py b/test_container/tests/test/java/script_import.py index 70df08b34..011b5fd56 100755 --- a/test_container/tests/test/java/script_import.py +++ b/test_container/tests/test/java/script_import.py @@ -6,6 +6,10 @@ class ScriptImport(udf.TestCase): + legacy_env_declaration = "" + ctpg_parser_env_declaration = "%env SCRIPT_OPTIONS_PARSER_VERSION=2;" + additional_env_declarations = [(legacy_env_declaration,), (ctpg_parser_env_declaration,)] + def setUp(self): self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) self.query('DROP SCHEMA FN3 CASCADE', ignore_errors=True) @@ -43,11 +47,13 @@ class CATCH_IMPORT_EXCEPTION { rows = self.query('SELECT catch_import_exception() FROM dual') self.assertRowsEqual([(42,)], rows) - def test_preprocessed_ImportError_is_not_catchable(self): + @useData(additional_env_declarations) + def test_preprocessed_ImportError_is_not_catchable(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT cannot_catch_import_exception() RETURNS int AS + ''' + additional_env_declaration + ''' %import X; class CANNOT_CATCH_IMPORT_EXCEPTION { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -59,21 +65,29 @@ class CANNOT_CATCH_IMPORT_EXCEPTION { with self.assertRaisesRegex(Exception, 'script X not found'): rows = self.query('SELECT cannot_catch_import_exception() FROM dual') - def test_preprocessed_Import_missing_script_name(self): + @useData(((legacy_env_declaration, 'No values found for %import statement'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:8\] PARSE: Syntax error: Unexpected \'\'"))) + def test_preprocessed_Import_missing_script_name(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT missing_import_script_exception() RETURNS int AS + ''' + additional_env_declaration + ''' %import ''')) - with self.assertRaisesRegex(Exception, 'No values found for %import statement'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT missing_import_script_exception() FROM dual') - def test_preprocessed_Import_missing_script_name2(self): + @useData(((legacy_env_declaration, 'End of %import statement not found'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:8\] PARSE: Syntax error: Unexpected \'\'"))) + def test_preprocessed_Import_missing_script_name2(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT missing_import_script_exception2() RETURNS int AS + ''' + additional_env_declaration + ''' %import class CANNOT_CATCH_IMPORT_EXCEPTION { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -82,14 +96,18 @@ class CANNOT_CATCH_IMPORT_EXCEPTION { } } ''')) - with self.assertRaisesRegex(Exception, 'End of %import statement not found'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT missing_import_script_exception2() FROM dual') - def test_preprocessed_Import_missing_script_name3(self): + @useData(((legacy_env_declaration, 'No values found for %import statement'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:9\] PARSE: Syntax error: Unexpected \';\'"))) + def test_preprocessed_Import_missing_script_name3(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT missing_import_script_exception3() RETURNS int AS + ''' + additional_env_declaration + ''' %import ; class CANNOT_CATCH_IMPORT_EXCEPTION { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -98,28 +116,34 @@ class CANNOT_CATCH_IMPORT_EXCEPTION { } } ''')) - with self.assertRaisesRegex(Exception, 'No values found for %import statement'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT missing_import_script_exception3() FROM dual') - def test_preprocessed_Import_missing_import_end(self): + @useData(((legacy_env_declaration, 'End of %import statement not found'), + (ctpg_parser_env_declaration, + "Error parsing script options at line 1: \[1:10\] PARSE: Syntax error: Unexpected \'\'"))) + def test_preprocessed_Import_missing_import_end(self, additional_env_declaration, expected_error): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT missing_import_end_exception() RETURNS int AS + ''' + additional_env_declaration + ''' %import X''')) - with self.assertRaisesRegex(Exception, 'End of %import statement not found'): + with self.assertRaisesRegex(Exception, expected_error): rows = self.query('SELECT missing_import_end_exception() FROM dual') - def test_import_is_case_sensitive(self): + @useData(additional_env_declarations) + def test_import_is_case_sensitive(self, additional_env_declaration): scripts = [ - ('my_module', 'my_module', 4711), - ('My_Module', 'My_Module', 42), - ('MY_MODULE', 'MY_MODULE', 1234), + ('my_module', additional_env_declaration, 'my_module', 4711), + ('My_Module', additional_env_declaration, 'My_Module', 42), + ('MY_MODULE', additional_env_declaration, 'MY_MODULE', 1234), ] sql = ''' CREATE OR REPLACE java SCALAR SCRIPT "%s"() RETURNS int AS + %s class %s { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return %d; @@ -147,16 +171,18 @@ class IMPORT_CASE_SENSITIVE { rows = self.query('SELECT import_case_sensitive() FROM DUAL') self.assertRowsEqual([(42,)], rows) - def test_preprocessed_import_is_case_sensitive(self): + @useData(additional_env_declarations) + def test_preprocessed_import_is_case_sensitive(self, additional_env_declaration): scripts = [ - ('my_module', 'my_module', 4711), - ('My_Module', 'My_Module', 42), - ('MY_MODULE', 'MY_MODULE', 1234), + ('my_module', additional_env_declaration, 'my_module', 4711), + ('My_Module', additional_env_declaration, 'My_Module', 42), + ('MY_MODULE', additional_env_declaration, 'MY_MODULE', 1234), ] sql = ''' CREATE OR REPLACE java SCALAR SCRIPT "%s"() RETURNS int AS + %s class %s { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return %d; @@ -170,6 +196,7 @@ class %s { CREATE OR REPLACE java SCALAR SCRIPT preprocessed_import_case_sensitive() RETURNS int AS + ''' + additional_env_declaration + ''' %import "My_Module"; class PREPROCESSED_IMPORT_CASE_SENSITIVE { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -180,11 +207,13 @@ class PREPROCESSED_IMPORT_CASE_SENSITIVE { rows = self.query('SELECT preprocessed_import_case_sensitive() FROM DUAL') self.assertRowsEqual([(42,)], rows) - def test_preprocessed_import_tab(self): + @useData(additional_env_declarations) + def test_preprocessed_import_tab(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT X() RETURNS int AS + ''' + additional_env_declaration + ''' class X { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return 1; @@ -196,6 +225,7 @@ class X { CREATE OR REPLACE java SCALAR SCRIPT preprocessed_import_case_tab() RETURNS int AS + ''' + additional_env_declaration + ''' %import X; class PREPROCESSED_IMPORT_CASE_TAB { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -206,11 +236,42 @@ class PREPROCESSED_IMPORT_CASE_TAB { rows = self.query('SELECT preprocessed_import_case_tab() FROM DUAL') self.assertRowsEqual([(1,)], rows) - def test_preprocessed_import_tab_end(self): + @useData(additional_env_declarations) + def test_preprocessed_import_quoted_whitespaces(self, additional_env_declaration): + self.query(udf.fixindent(''' + CREATE OR REPLACE java SCALAR SCRIPT + "X "() + RETURNS int AS + ''' + additional_env_declaration + ''' + class X { + static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return 1; + } + } + ''')) + + self.query(udf.fixindent(''' + CREATE OR REPLACE java SCALAR SCRIPT + preprocessed_import_case_tab_end() + RETURNS int AS + ''' + additional_env_declaration + ''' + %import "X "; + class PREPROCESSED_IMPORT_CASE_TAB_END { + static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return X.run(exa, ctx); + } + } + ''')) + rows = self.query('SELECT preprocessed_import_case_tab_end() FROM DUAL') + self.assertRowsEqual([(1,)], rows) + + @useData(additional_env_declarations) + def test_preprocessed_import_unquoted_whitespaces(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT X() RETURNS int AS + ''' + additional_env_declaration + ''' class X { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return 1; @@ -222,6 +283,7 @@ class X { CREATE OR REPLACE java SCALAR SCRIPT preprocessed_import_case_tab_end() RETURNS int AS + ''' + additional_env_declaration + ''' %import X ; class PREPROCESSED_IMPORT_CASE_TAB_END { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -232,16 +294,18 @@ class PREPROCESSED_IMPORT_CASE_TAB_END { rows = self.query('SELECT preprocessed_import_case_tab_end() FROM DUAL') self.assertRowsEqual([(1,)], rows) - def test_preprocessed_import_multiple(self): + @useData(additional_env_declarations) + def test_preprocessed_import_multiple(self, additional_env_declaration): scripts = [ - ('A', 'A', 1), - ('B', 'B', 2), - ('C', 'C', 3), + ('A', additional_env_declaration, 'A', 1), + ('B', additional_env_declaration, 'B', 2), + ('C', additional_env_declaration, 'C', 3), ] sql = ''' CREATE OR REPLACE java SCALAR SCRIPT "%s"() RETURNS int AS + %s %%import A; %%import B; %%import C; @@ -258,6 +322,7 @@ class %s { CREATE OR REPLACE java SCALAR SCRIPT X() RETURNS int AS + ''' + additional_env_declaration + ''' %import A; %import B; %import C; @@ -270,11 +335,13 @@ class X { rows = self.query('SELECT X() FROM DUAL') self.assertRowsEqual([(6,)], rows) - def test_preprocessed_import_recursive(self): + @useData(additional_env_declarations) + def test_preprocessed_import_recursive(self, additional_env_declaration): sql = ''' CREATE OR REPLACE java SCALAR SCRIPT A() RETURNS int AS + ''' + additional_env_declaration + ''' %import B; class A { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -287,6 +354,7 @@ class A { CREATE OR REPLACE java SCALAR SCRIPT B() RETURNS int AS + ''' + additional_env_declaration + ''' %import C; class B { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -299,6 +367,7 @@ class B { CREATE OR REPLACE java SCALAR SCRIPT C() RETURNS int AS + ''' + additional_env_declaration + ''' class C { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return 3; @@ -311,6 +380,7 @@ class C { CREATE OR REPLACE java SCALAR SCRIPT X() RETURNS int AS + ''' + additional_env_declaration + ''' %import A; class X { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -321,11 +391,13 @@ class X { rows = self.query('SELECT X() FROM DUAL') self.assertRowsEqual([(6,)], rows) - def test_import_works(self): + @useData(additional_env_declarations) + def test_import_works(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT foo() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bottom; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -337,19 +409,21 @@ class FOO { rows = self.query('SELECT foo() FROM DUAL') self.assertRowsEqual([(42,)], rows) - def test_import_is_semi_case_sensitive(self): + @useData(additional_env_declarations) + def test_import_is_semi_case_sensitive(self, additional_env_declaration): def check(import_name, classname, n): self.query(udf.fixindent(''' CREATE OR REPLACE java SCALAR SCRIPT foo() RETURNS INT AS + %s %%import %s; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { return %s.f(); } } - /''' % (import_name, classname))) + /''' % (additional_env_declaration, import_name, classname))) self.assertRowsEqual([(n,)], self.query('SELECT foo() FROM DUAL')) @@ -358,12 +432,13 @@ class FOO { CREATE java SCALAR SCRIPT "%s"() RETURNS INT AS + %s class %s { static int f() { return %d; } } - /''' % (name, name, sum(x.isupper() for x in name)) + /''' % (name, additional_env_declaration, name, sum(x.isupper() for x in name)) )) check("bar", "BAR", 3) @@ -371,11 +446,13 @@ class %s { check("\"Bar\"", "Bar", 1) check("\"bar\"", "bar", 0) - def test_import_fails_for_lua_script(self): + @useData(additional_env_declarations) + def test_import_fails_for_lua_script(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT foo() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bar; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -388,7 +465,7 @@ class FOO { CREATE lua SCALAR SCRIPT bar() RETURNS DOUBLE AS - + ''' + additional_env_declaration + ''' function f() return 32 end @@ -397,11 +474,13 @@ class FOO { with self.assertRaisesRegex(Exception, 'VM error:.* wrong language LUA'): self.query('SELECT foo() FROM DUAL') - def test_import_fails_for_r_script(self): + @useData(additional_env_declarations) + def test_import_fails_for_r_script(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT foo() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bar; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -414,6 +493,7 @@ class FOO { CREATE r SCALAR SCRIPT bar() RETURNS DOUBLE AS + ''' + additional_env_declaration + ''' f <- function() { 32 @@ -423,11 +503,13 @@ class FOO { with self.assertRaisesRegex(Exception, 'VM error:.* wrong language R'): self.query('SELECT foo() FROM DUAL') - def test_import_fails_for_python_script(self): + @useData(additional_env_declarations) + def test_import_fails_for_python_script(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT foo() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bar; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -440,7 +522,7 @@ class FOO { CREATE python3 SCALAR SCRIPT bar() RETURNS DOUBLE AS - + ''' + additional_env_declaration + ''' def f(): return 32 / @@ -449,18 +531,24 @@ def f(): self.query('SELECT foo() FROM DUAL') @useData([ - ('fn2', 'bottom', 'BOTTOM'), - ('fn2', 'fn2.bottom', 'BOTTOM'), - ('fn2', 'exa_db.fn2.bottom', 'BOTTOM'), - ('fn3', 'fn2.bottom', 'BOTTOM'), - ('fn3', 'exa_db.fn2.bottom', 'BOTTOM') + ('fn2', 'bottom', 'BOTTOM', ''), + ('fn2', 'fn2.bottom', 'BOTTOM', ''), + ('fn2', 'exa_db.fn2.bottom', 'BOTTOM', ''), + ('fn3', 'fn2.bottom', 'BOTTOM', ''), + ('fn3', 'exa_db.fn2.bottom', 'BOTTOM', ''), + ('fn2', 'bottom', 'BOTTOM', "%env SCRIPT_OPTIONS_PARSER_VERSION=2;"), + ('fn2', 'fn2.bottom', 'BOTTOM', "%env SCRIPT_OPTIONS_PARSER_VERSION=2;"), + ('fn2', 'exa_db.fn2.bottom', 'BOTTOM', "%env SCRIPT_OPTIONS_PARSER_VERSION=2;"), + ('fn3', 'fn2.bottom', 'BOTTOM', "%env SCRIPT_OPTIONS_PARSER_VERSION=2;"), + ('fn3', 'exa_db.fn2.bottom', 'BOTTOM', "%env SCRIPT_OPTIONS_PARSER_VERSION=2;"), ]) - def test_import_works_with_qualified_names(self, schema, name, classname): + def test_import_works_with_qualified_names(self, schema, name, classname, additional_env_declaration): self.query('OPEN SCHEMA %s' % schema) self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT foo() RETURNS INT AS + %s %%import %s; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -468,15 +556,17 @@ class FOO { } } / - ''' % (name, classname))) + ''' % (additional_env_declaration, name, classname))) rows = self.query('SELECT foo() FROM DUAL') self.assertRowsEqual([(42,)], rows) - def test_chained_import_works_via_function_call(self): + @useData(additional_env_declarations) + def test_chained_import_works_via_function_call(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT foo() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bar; class FOO { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -489,6 +579,7 @@ class FOO { CREATE java SCALAR SCRIPT bar() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bottom; class BAR { static int b() { @@ -500,11 +591,13 @@ class BAR { rows = self.query('SELECT foo() FROM DUAL') self.assertRowsEqual([(42,)], rows) - def test_mutual_import_works(self): + @useData(additional_env_declarations) + def test_mutual_import_works(self, additional_env_declaration): self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT ping() RETURNS INT AS + ''' + additional_env_declaration + ''' %import pong; class PING { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { @@ -523,6 +616,7 @@ class PING { CREATE java SCALAR SCRIPT pong() RETURNS INT AS + ''' + additional_env_declaration + ''' %import ping; class PONG { static int pong(int n) { @@ -537,13 +631,15 @@ class PONG { rows = self.query('SELECT ping() FROM DUAL') self.assertRowsEqual([(42,)], rows) - def testImportWithView(self): + @useData(additional_env_declarations) + def testImportWithView(self, additional_env_declaration): self.createUser("foo", "foo") self.commit() self.query(udf.fixindent(''' CREATE java SCALAR SCRIPT spot42542script() RETURNS INT AS + ''' + additional_env_declaration + ''' %import bottom; class SPOT42542SCRIPT { static int run(ExaMetadata exa, ExaIterator ctx) throws Exception {