diff --git a/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json b/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json index 91ab757f8..7ca8cd7d6 100644 --- a/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json +++ b/flavors/template-Exasol-8-python-3.10-cuda-conda/ci.json @@ -38,13 +38,6 @@ "goal": "base_test_build_run", "generic_language_tests": [] }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": ["python3"] - }, { "name": "gpu", "files": [], diff --git a/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json b/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json index 91ab757f8..7ca8cd7d6 100644 --- a/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json +++ b/flavors/template-Exasol-8-python-3.12-cuda-conda/ci.json @@ -38,13 +38,6 @@ "goal": "base_test_build_run", "generic_language_tests": [] }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": ["python3"] - }, { "name": "gpu", "files": [], diff --git a/flavors/template-Exasol-all-python-3.10-conda/ci.json b/flavors/template-Exasol-all-python-3.10-conda/ci.json index 773900816..342288f88 100644 --- a/flavors/template-Exasol-all-python-3.10-conda/ci.json +++ b/flavors/template-Exasol-all-python-3.10-conda/ci.json @@ -37,13 +37,6 @@ "folders": ["linker_namespace_sanity"], "goal": "base_test_build_run", "generic_language_tests": [] - }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": ["python3"] } ] } diff --git a/flavors/template-Exasol-all-python-3.10/ci.json b/flavors/template-Exasol-all-python-3.10/ci.json index ddddf6df6..20b227b7f 100644 --- a/flavors/template-Exasol-all-python-3.10/ci.json +++ b/flavors/template-Exasol-all-python-3.10/ci.json @@ -37,13 +37,6 @@ "folders": ["linker_namespace_sanity"], "goal": "base_test_build_run", "generic_language_tests": [] - }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": ["python3"] } ] } diff --git a/flavors/template-Exasol-all-python-3.12-conda/ci.json b/flavors/template-Exasol-all-python-3.12-conda/ci.json index 634fc08cd..348238b0c 100644 --- a/flavors/template-Exasol-all-python-3.12-conda/ci.json +++ b/flavors/template-Exasol-all-python-3.12-conda/ci.json @@ -37,13 +37,6 @@ "folders": ["linker_namespace_sanity"], "goal": "base_test_build_run", "generic_language_tests": [] - }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": ["python3"] } ] } diff --git a/flavors/template-Exasol-all-python-3.12/ci.json b/flavors/template-Exasol-all-python-3.12/ci.json index 4ce917c7b..63cd45f54 100644 --- a/flavors/template-Exasol-all-python-3.12/ci.json +++ b/flavors/template-Exasol-all-python-3.12/ci.json @@ -37,13 +37,6 @@ "folders": ["linker_namespace_sanity"], "goal": "base_test_build_run", "generic_language_tests": [] - }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": ["python3"] } ] } diff --git a/flavors/test-Exasol-8-cuda-ml/ci.json b/flavors/test-Exasol-8-cuda-ml/ci.json index ba75da971..03a4c17f8 100644 --- a/flavors/test-Exasol-8-cuda-ml/ci.json +++ b/flavors/test-Exasol-8-cuda-ml/ci.json @@ -46,15 +46,6 @@ "goal": "base_test_build_run", "generic_language_tests": [] }, - { - "name": "generic", - "files": [], - "folders": [], - "goal": "release", - "generic_language_tests": [ - "python3" - ] - }, { "name": "gpu", "files": [], diff --git a/test_container/tests/test/generic/basic.py b/test_container/tests/test/generic/basic.py index a0e121ce9..334d306a6 100755 --- a/test_container/tests/test/generic/basic.py +++ b/test_container/tests/test/generic/basic.py @@ -13,7 +13,7 @@ def test_basic_scalar_emits(self): FROM DUAL ''') self.assertRowsEqual([(x,) for x in range(3)], sorted(rows)) - + @requires('BASIC_SUM') def test_basic_set_returns(self): rows = self.query(''' diff --git a/test_container/tests/test/generic/java/basic.py b/test_container/tests/test/generic/java/basic.py new file mode 100755 index 000000000..31ffa79a2 --- /dev/null +++ b/test_container/tests/test/generic/java/basic.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + basic_emit_several_groups(a INTEGER, b INTEGER) + EMITS (i INTEGER, j VARCHAR(40)) AS + class BASIC_EMIT_SEVERAL_GROUPS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + for (int n = 0; n < ctx.getInteger("a"); n++) + for (int i = 0; i < ctx.getInteger("b"); i++) + ctx.emit(i, exa.getVmId()); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + basic_emit_two_ints() + EMITS (i INTEGER, j INTEGER) AS + class BASIC_EMIT_TWO_INTS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(1,2); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + basic_nth_partial_sum(n INTEGER) + RETURNS INTEGER as + class BASIC_NTH_PARTIAL_SUM { + static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getInteger("n") != null) + return ctx.getInteger("n") * (ctx.getInteger("n") + 1) / 2; + return 0; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + basic_range(n INTEGER) + EMITS (n INTEGER) AS + class BASIC_RANGE { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getInteger("n") != null) + for (int i = 0; i < ctx.getInteger("n"); i++) + ctx.emit(i); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + basic_sum(x INTEGER) + RETURNS INTEGER AS + class BASIC_SUM { + static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int s = 0; + while (true) { + if (ctx.getInteger("x") != null) + s += ctx.getInteger("x"); + if (!ctx.next()) + break; + } + return s; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + basic_sum_grp(x INTEGER) + EMITS (s INTEGER) AS + class BASIC_SUM_GRP { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int s = 0; + while (true) { + if (ctx.getInteger("x") != null) + s += ctx.getInteger("x"); + if (!ctx.next()) + break; + } + ctx.emit(s); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + basic_test_reset(i INTEGER, j VARCHAR(40)) + EMITS (k INTEGER) AS + class BASIC_TEST_RESET { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getInteger("i")); + ctx.next(); + ctx.emit(ctx.getInteger("i")); + ctx.reset(); + ctx.emit(ctx.getInteger("i")); + ctx.next(); + ctx.emit(ctx.getInteger("i")); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + performance_map_characters(text VARCHAR(1000)) + EMITS (w CHAR(1), c INTEGER) AS + class PERFORMANCE_MAP_CHARACTERS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String text = ctx.getString("text"); + if (text != null) { + for (int i = 0; i < text.length(); i++) { + if (Character.isHighSurrogate(text.charAt(i))) { + ctx.emit(text.substring(i, i + 2), 1); + i++; + } + else { + ctx.emit(text.substring(i, i + 1), 1); + } + } + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + performance_reduce_characters(w CHAR(1), c INTEGER) + EMITS (w CHAR(1), c INTEGER) AS + class PERFORMANCE_REDUCE_CHARACTERS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int c = 0; + String w = ctx.getString("w"); + if (w != null) { + do { + c += 1; + } while (ctx.next()); + ctx.emit(w, c); + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + set_emits_has_empty_input(a double) EMITS (x double, y varchar(10)) AS + class SET_EMITS_HAS_EMPTY_INPUT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDouble("x") == null) + ctx.emit(1,"1") + else + ctx.emit(2,"2") + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + set_returns_has_empty_input(a double) RETURNS boolean AS + class SET_RETURNS_HAS_EMPTY_INPUT { + static boolean run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getInteger("x") == null; + } + } + / + ''')) + +class BasicTest(_JavaUdfSetup): + + def test_basic_scalar_emits(self): + rows = self.query(''' + SELECT fn1.basic_range(3) + FROM DUAL + ''') + self.assertRowsEqual([(x,) for x in range(3)], sorted(rows)) + + def test_basic_set_returns(self): + rows = self.query(''' + SELECT fn1.basic_sum(3) + FROM DUAL + ''') + self.assertRowsEqual([(3,)], rows) + + def test_emit_two_ints(self): + rows = self.query(''' + SELECT fn1.basic_emit_two_ints() + FROM DUAL''') + self.assertRowsEqual([(1, 2)], rows) + + def test_simple_combination(self): + rows = self.query(''' + SELECT fn1.basic_sum(psum) + FROM ( + SELECT fn1.basic_nth_partial_sum(n) AS PSUM + FROM ( + SELECT fn1.basic_range(10) + FROM DUAL + ) + )''') + self.assertRowsEqual([(165,)], rows) + + def test_simple_combination_grouping(self): + rows = self.query(''' + SELECT fn1.BASIC_SUM_GRP(psum) + FROM ( + SELECT MOD(N, 3) AS n, + fn1.basic_nth_partial_sum(n) AS psum + FROM ( + SELECT fn1.basic_range(10) + FROM DUAL + ) + ) + GROUP BY n + ORDER BY 1''') + self.assertRowsEqual([(39.0,), (54.0,), (72.0,)], rows) + + def test_reset(self): + rows = self.query(''' + SELECT fn1.basic_test_reset(i, j) + FROM (SELECT fn1.basic_emit_several_groups(16, 8) FROM DUAL) + GROUP BY i + ORDER BY 1''') + self.assertRowsEqual([(0.0,), (0.0,), (0.0,), (0.0,), (1.0,), (1.0,), (1.0,), (1.0,), (2.0,)], rows[:9]) + + def test_order_by_clause(self): + rows = self.query(''' + SELECT fn1.performance_reduce_characters(w, c) + FROM ( + SELECT fn1.performance_map_characters('hello hello hello abc') + FROM DUAL + ) + GROUP BY w + ORDER BY c DESC''') + + unsorted_list = [tuple(x) for x in rows] + sorted_list = sorted(unsorted_list, key=lambda x: x[1], reverse=True) + #for x in zip(unsorted_list, sorted_list): + # print x + + self.assertEqual(sorted_list, unsorted_list) + + +class SetWithEmptyInput(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + self.query('OPEN SCHEMA FN1') + self.query('CREATE TABLE FN2.empty_table(c int)') + + # Create UDFs needed for SetWithEmptyInput tests + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + set_returns_has_empty_input(a double) RETURNS boolean AS + class SET_RETURNS_HAS_EMPTY_INPUT { + static boolean run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getDouble("a") == null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + set_emits_has_empty_input(a double) EMITS (x double, y varchar(10)) AS + class SET_EMITS_HAS_EMPTY_INPUT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDouble("a") == null) + ctx.emit(1,"1"); + else + ctx.emit(2,"2"); + } + } + / + ''')) + + def test_set_returns_has_empty_input_group_by(self): + self.query("""select FN1.set_returns_has_empty_input(c) from FN2.empty_table group by 'X'""") + self.assertEqual(0, self.rowcount()) + + def test_set_returns_has_empty_input_no_group_by(self): + rows = self.query('''select FN1.set_returns_has_empty_input(c) from FN2.empty_table''') + self.assertRowsEqual([(None,)], rows) + + + def test_set_emits_has_empty_input_group_by(self): + self.query("""select FN1.set_emits_has_empty_input(c) from FN2.empty_table group by 'X'""") + self.assertEqual(0, self.rowcount()) + + def test_set_emits_has_empty_input_no_group_by(self): + rows = self.query('''select FN1.set_emits_has_empty_input(c) from FN2.empty_table''') + self.assertRowsEqual([(None,None)], rows) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/combinations.py b/test_container/tests/test/generic/java/combinations.py new file mode 100755 index 000000000..cdcfd9333 --- /dev/null +++ b/test_container/tests/test/generic/java/combinations.py @@ -0,0 +1,482 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf +from exasol_python_test_framework.udf import useData + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + basic_range(n INTEGER) + EMITS (n INTEGER) AS + class BASIC_RANGE { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getInteger("n") != null) + for (int i = 0; i < ctx.getInteger("n"); i++) + ctx.emit(i); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + basic_sum(x INTEGER) + RETURNS INTEGER AS + class BASIC_SUM { + static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int s = 0; + while (true) { + if (ctx.getInteger("x") != null) + s += ctx.getInteger("x"); + if (!ctx.next()) + break; + } + return s; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SET SCRIPT + basic_sum_grp(x INTEGER) + EMITS (s INTEGER) AS + class BASIC_SUM_GRP { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int s = 0; + while (true) { + if (ctx.getInteger("x") != null) + s += ctx.getInteger("x"); + if (!ctx.next()) + break; + } + ctx.emit(s); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + SCALAR_EMITS(x double, y double) + emits (x double, y double) as + class SCALAR_EMITS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + for (int i = ctx.getDouble("x").intValue(); i < (int)(ctx.getDouble("y") + 1); i++) + ctx.emit((float) i, (float) (i * i)); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + SCALAR_RETURNS(x double, y double) + returns double as + class SCALAR_RETURNS { + static double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getDouble("x") + ctx.getDouble("y"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java set script + SET_EMITS(x double, y double) + emits (x double, y double) as + class SET_EMITS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + while (true) { + ctx.emit(ctx.getDouble("y"), ctx.getDouble("x")); + if (!ctx.next()) + break; + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java set script + SET_RETURNS(x double, y double) + returns double as + class SET_RETURNS { + static double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + double acc = 0.0; + while (true) { + acc = acc + ctx.getDouble("x") + ctx.getDouble("y"); + if (!ctx.next()) + break; + } + return acc; + } + } + / + ''')) + + self.query('DROP SCHEMA combinations CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA combinations') + self.query('CREATE TABLE combinations.small(x DOUBLE, y DOUBLE)') + self.query('INSERT INTO combinations.small VALUES (0.1, 0.2), (0.2, 0.1)') + + +class Combinations_1_ary(_JavaUdfSetup): + def test_set_returns(self): + rows = self.query(''' + SELECT fn1.SET_RETURNS(x,y) + FROM combinations.small''') + self.assertEqual(round(0.6 / 2), round(rows[0][0] / 2)) + + + def test_scalar_returns(self): + rows = self.query(''' + SELECT round(fn1.scalar_returns(x,y) / 2) + FROM combinations.small''') + self.assertRowsEqual([(round(0.3 / 2),), (round(0.3 / 2),)], rows) + + def test_scalar_emits(self): + rows = self.query(''' + SELECT fn1.scalar_emits(x * 10 ,y * 10) + FROM combinations.small''') + self.assertRowsEqual([(1, 1,), (2, 4,)], rows) + + def test_set_emits(self): + rows = self.query(''' + SELECT fn1.set_emits(x * 10 ,y * 10) + FROM combinations.small''') + self.assertRowsEqual([(2.0, 1.0,), (1.0, 2.0,)], rows) + + def test_two_scalar_returns(self): + rows = self.query(''' + SELECT + fn1.scalar_returns(fn1.scalar_returns(x * 10 ,y * 10), + fn1.scalar_returns(y * 10 ,x * 10)) + FROM combinations.small''') + self.assertRowsEqual([(6,), (6,)], rows) + + +class Combinations_2_ary_scalar_returns(_JavaUdfSetup): + def test_scalar_returns_scalar_emits(self): + rows = self.query(''' + SELECT fn1.scalar_returns(x * 10 ,y * 10 ) + FROM ( + SELECT fn1.scalar_emits(x * 10 ,y * 10) + FROM combinations.small + )''') + self.assertRowsEqual([(20,), (60,)], rows) + + def test_scalar_returns_set_returns_inline(self): + rows = self.query(''' + SELECT + fn1.scalar_returns( + fn1.set_returns(x * 10, y * 10), + fn1.set_returns(x * 10, y * 10) + ) + FROM combinations.small''') + self.assertRowsEqual([(12,)], rows) + + def test_scalar_returns_set_returns_1(self): + rows = self.query(''' + SELECT fn1.scalar_returns(a, 5) + FROM ( + SELECT fn1.set_returns(x * 10, y * 10) AS a + FROM combinations.SMALL + ) + ''') + self.assertRowsEqual([(11,)], rows) + + def test_scalar_returns_set_returns_2(self): + rows = self.query(''' + SELECT fn1.scalar_returns(aa.a, bb.a) + FROM ( + SELECT fn1.set_returns(x * 10, y * 20) AS a + FROM combinations.SMALL + ) AS aa, + ( + SELECT fn1.set_returns(x * 20, y * 10) AS a + FROM combinations.SMALL + ) AS bb + ''') + self.assertRowsEqual([(18,)], rows) + + def test_scalar_returns_set_emits_1(self): + rows = self.query(''' + SELECT fn1.scalar_returns(x * 10, y * 10) + FROM ( + SELECT fn1.set_emits(x * 10, y * 10) + FROM combinations.small + )''') + self.assertRowsEqual([(30,), (30,)], rows) + + def test_scalar_returns_set_emits_2(self): + rows = self.query(''' + SELECT fn1.scalar_returns(aa.x * 10, bb.x * 10) + FROM ( + SELECT fn1.set_emits(x * 10, y * 10) + FROM combinations.small + ) AS aa, + ( + SELECT fn1.set_emits(x * 10, y * 10) + FROM combinations.small + ) AS bb + WHERE aa.x = bb.y and aa.y = bb.x + ''') + self.assertRowsEqual([(30,), (30,)], rows) + + +class Combinations_2_ary_scalar_emits(_JavaUdfSetup): + def test_scalar_emits_scalar_returns_inline(self): + rows = self.query(''' + SELECT + fn1.scalar_emits( + fn1.scalar_returns(x * 10, y * 10), + fn1.scalar_returns(y * 10, x * 10) + ) + FROM combinations.small''') + self.assertRowsEqual([(3, 9,), (3, 9,)], rows) + + def test_scalar_emits_scalar_returns(self): + rows = self.query(''' + SELECT fn1.scalar_emits(a, b) + FROM ( + SELECT + fn1.scalar_returns(x * 10 ,y * 10) AS A, + fn1.scalar_returns(y * 10 ,x * 10) AS B + FROM combinations.small + ) + ''') + self.assertRowsEqual([(3, 9,), (3, 9,)], rows) + + def test_scalar_emits_scalar_emits(self): + rows = self.query(''' + SELECT fn1.scalar_emits(x * 10,y * 10) + FROM ( + SELECT fn1.scalar_emits(x * 10,y * 10) + FROM combinations.small + ) + ORDER by x,y''') + r = [(10.0, 100.0)] + r.extend([(i, i * i) for i in range(20, 41)]) + self.assertRowsEqual(r, rows) + + def test_scalar_emits_set_returns_inline(self): + with self.assertRaisesRegex(Exception, 'encapsulated set function'): + self.query(''' + SELECT + fn1.scalar_emits( + fn1.set_returns(x * 10, y * 10), + fn1.set_returns(x * 10, y * 10) + ) + FROM combinations.small''') + + def test_scalar_emits_set_returns(self): + rows = self.query(''' + SELECT fn1.scalar_emits(a, b) + FROM ( + SELECT fn1.set_returns(x * 10, y * 10) AS a + FROM combinations.small + ), + ( + SELECT fn1.set_returns(x * 10, y *10) AS b + FROM combinations.small + ) + ''') + self.assertRowsEqual([(6, 36)], rows) + + def test_scalar_emits_set_emits(self): + rows = self.query(''' + SELECT fn1.scalar_emits(x * 10, y * 10) + FROM ( + SELECT fn1.set_emits(x * 10, y * 10) + FROM combinations.small + )''') + r = ([(i, i * i) for i in range(10, 21)]) + self.assertRowsEqual(r, rows) + + +class Combinations_2_ary_set_returns(_JavaUdfSetup): + def test_set_returns_scalar_returns(self): + rows = self.query(''' + SELECT + fn1.set_returns( + fn1.scalar_returns(x * 10, y * 10), + fn1.scalar_returns(y * 10, x * 10) + ) + FROM combinations.small''') + self.assertRowsEqual([(12,)], rows) + + def test_set_returns_scalar_emits(self): + rows = self.query(''' + SELECT fn1.set_returns(x*10, y*10) + FROM ( + SELECT fn1.scalar_emits(x*10, y*10) + FROM combinations.small + )''') + self.assertRowsEqual([(80,)], rows) + + def test_set_returns_set_returns_inline(self): + with self.assertRaisesRegex(Exception, 'encapsulated set function'): + self.query(''' + SELECT + fn1.set_returns( + fn1.set_returns(x*10, y*10), + fn1.set_returns(x*10, y*10) + ) + FROM combinations.small''') + + def test_set_returns_set_returns(self): + rows = self.query(''' + SELECT fn1.set_returns(a, b) + FROM( + SELECT fn1.set_returns(x*20, y*30) AS a + FROM combinations.small + ), + ( + SELECT fn1.set_returns(x*50, y*70) AS b + FROM combinations.small + )''') + self.assertRowsEqual([(51,)], rows) + + def test_set_returns_set_emits(self): + rows = self.query(''' + SELECT fn1.set_returns(x*10, y*10) + FROM ( + SELECT fn1.set_emits(x*10, y*10) + FROM combinations.small + )''') + self.assertRowsEqual([(60,)], rows) + + +class Combinations_2_ary_set_emits(_JavaUdfSetup): + def test_set_emits_scalar_returns(self): + rows = self.query(''' + SELECT + fn1.set_emits( + fn1.scalar_returns(x*10, y*10), + fn1.scalar_returns(y*10, x*10) + ) + FROM combinations.small''') + self.assertRowsEqual([(3, 3,), (3, 3,)], rows) + + def test_set_emits_scalar_emits(self): + rows = self.query(''' + SELECT fn1.set_emits(x*10, y*10) + FROM ( + SELECT fn1.scalar_emits(x*10, 10*y) + FROM combinations.small + ) + ORDER BY x, y;''') + self.assertRowsEqual([(10, 10,), (40, 20,)], rows) + + def test_set_emits_set_returns_inline(self): + with self.assertRaisesRegex(Exception, 'encapsulated set function'): + self.query(''' + SELECT + fn1.set_emits( + fn1.set_returns(x*10, 10*y), + fn1.set_returns(10*x, y*10) + ) + FROM combinations.small''') + + def test_set_emits_set_returns(self): + rows = self.query(''' + SELECT fn1.set_emits(a, b) + FROM ( + SELECT fn1.set_returns(x*20, 30*y) AS a + FROM combinations.small + ), + ( + SELECT fn1.set_returns(50*x, y*70) AS b + FROM combinations.small + ) + ''') + self.assertRowsEqual([(36, 15,)], rows) + + def test_set_emits_set_emits(self): + rows = self.query(''' + SELECT fn1.set_emits(x * 10 , 10 * y) + FROM ( + SELECT fn1.set_emits(x * 10, y *10) + FROM combinations.small + ) + ORDER BY x, y;''') + self.assertRowsEqual([(10, 20,), (20, 10,)], rows) + + +class Combinations_3_ary(_JavaUdfSetup): + def test_set_returns_set_emits_scalar_emits(self): + rows = self.query(''' + SELECT fn1.basic_sum(s) + FROM ( + SELECT fn1.basic_sum_grp(n) + FROM( + SELECT fn1.basic_range(10) + FROM DUAL + ) + )''') + self.assertRowsEqual([(45,)], rows) + + def test_set_returns_scalar_emits_scalar_emits(self): + rows = self.query(''' + SELECT fn1.basic_sum(x) + FROM ( + SELECT fn1.scalar_emits(n, n+2) + FROM( + SELECT fn1.basic_range(10) + FROM DUAL + ) + )''') + self.assertRowsEqual([(165,)], rows) + + def test_set_returns_scalar_returns_scalar_emits(self): + rows = self.query(''' + SELECT fn1.basic_sum(x) + FROM ( + SELECT fn1.scalar_returns(n, 2) AS x + FROM( + SELECT fn1.basic_range(10) + FROM DUAL + ) + )''') + self.assertRowsEqual([(65,)], rows) + + +class Combinations_n_ary(_JavaUdfSetup): + @staticmethod + def partial_sum(n, degree): + def basic_range(n, d): + if d == 0: + return list(range(n)) + else: + return sum([list(range(x)) for x in basic_range(n + 1, d - 1)], []) + + return len(basic_range(n, degree)) + + @useData((i,) for i in range(10)) + def test_n_scalar_emits(self, n): + + self.query( + 'SELECT fn1.basic_range(n+1) FROM (\n' * n + + 'SELECT fn1.basic_range(5) FROM DUAL\n' + + ')' * n) + self.assertEqual(self.partial_sum(5, n), self.rowcount()) + + @useData((i,) for i in range(10)) + def test_set_returns_n_scalar_emits(self, n): + + rows = self.query( + 'SELECT max(n) FROM (' + + 'SELECT fn1.basic_range(n+1) FROM (\n' * n + + 'SELECT fn1.basic_range(5) FROM DUAL\n' + + ')' * (n + 1)) + self.assertEqual(4, rows[0][0]) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/dynamic_input.py b/test_container/tests/test/generic/java/dynamic_input.py new file mode 100755 index 000000000..5e03e5e14 --- /dev/null +++ b/test_container/tests/test/generic/java/dynamic_input.py @@ -0,0 +1,517 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class _JavaUdfSetup(udf.TestCase): + LANG = 'java' + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + basic_scalar_emit( ... ) + EMITS ("v" VARCHAR(2000)) as + import java.math.BigDecimal; + import java.sql.Date; + import java.sql.Timestamp; + class BASIC_SCALAR_EMIT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int i = 0; + while (i < exa.getInputColumnCount()) { + Class cls = exa.getInputColumnType(i); + if (cls == Integer.class) { + ctx.emit(ctx.getInteger(i).toString()); + } + else if (cls == Long.class) { + ctx.emit(ctx.getLong(i).toString()); + } + else if (cls == Class.forName("java.math.BigDecimal")) { + ctx.emit(ctx.getBigDecimal(i).toString()); + } + else if (cls == Double.class) { + ctx.emit(ctx.getDouble(i).toString()); + } + else if (cls == String.class) { + ctx.emit(ctx.getString(i)); + } + else if (cls == Boolean.class) { + ctx.emit(ctx.getBoolean(i).toString()); + } + else if (cls == Class.forName("java.sql.Date")) { + ctx.emit(ctx.getDate(i).toString()); + } + else if (cls == Class.forName("java.sql.Timestamp")) { + ctx.emit(ctx.getTimestamp(i).toString()); + } + i = i + 1; + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + basic_scalar_return( ... ) + RETURNS VARCHAR(2000) as + class BASIC_SCALAR_RETURN { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int col = (int) exa.getInputColumnCount() - 1; + Class cls = exa.getInputColumnType(col); + if (cls == Integer.class) { + return ctx.getInteger(col).toString(); + } + else if (cls == Long.class) { + return ctx.getLong(col).toString(); + } + else if (cls == Class.forName("java.math.BigDecimal")) { + return ctx.getBigDecimal(col).toString(); + } + else if (cls == Double.class) { + return ctx.getDouble(col).toString(); + } + else if (cls == String.class) { + return ctx.getString(col); + } + else if (cls == Boolean.class) { + return ctx.getBoolean(col).toString(); + } + else if (cls == Class.forName("java.sql.Date")) { + return ctx.getDate(col).toString(); + } + else if (cls == Class.forName("java.sql.Timestamp")) { + return ctx.getTimestamp(col).toString(); + } + else { + return null; + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SET SCRIPT + basic_set_emit( ... ) + EMITS ("v" VARCHAR(2000)) as + import java.math.BigDecimal; + import java.sql.Date; + import java.sql.Timestamp; + class BASIC_SET_EMIT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String var = "result: "; + while (true) { + for (int i = 0; i < exa.getInputColumnCount(); i++) { + Class cls = exa.getInputColumnType(i); + if (cls == Integer.class) { + ctx.emit(ctx.getInteger(i).toString()); + var += ctx.getInteger(i).toString() + " , "; + } + else if (cls == Long.class) { + ctx.emit(ctx.getLong(i).toString()); + var += ctx.getLong(i).toString() + " , "; + } + else if (cls == Class.forName("java.math.BigDecimal")) { + ctx.emit(ctx.getBigDecimal(i).toString()); + var += ctx.getBigDecimal(i).toString() + " , "; + } + else if (cls == Double.class) { + ctx.emit(ctx.getDouble(i).toString()); + var += ctx.getDouble(i).toString() + " , "; + } + else if (cls == String.class) { + ctx.emit(ctx.getString(i)); + var += ctx.getString(i) + " , "; + } + else if (cls == Boolean.class) { + ctx.emit(ctx.getBoolean(i).toString()); + var += ctx.getBoolean(i).toString() + " , "; + } + else if (cls == Class.forName("java.sql.Date")) { + ctx.emit(ctx.getDate(i).toString()); + var += ctx.getDate(i).toString() + " , "; + } + else if (cls == Class.forName("java.sql.Timestamp")) { + ctx.emit(ctx.getTimestamp(i).toString()); + var += ctx.getTimestamp(i).toString() + " , "; + } + } + if (!ctx.next()) + break; + } + ctx.emit(var); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SET SCRIPT + basic_set_return( ... ) + RETURNS VARCHAR(2000) as + import java.math.BigDecimal; + import java.sql.Date; + import java.sql.Timestamp; + class BASIC_SET_RETURN { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String var = "result: "; + while (true) { + for (int i = 0; i < exa.getInputColumnCount(); i++) { + Class cls = exa.getInputColumnType(i); + if (cls == Integer.class) { + var += ctx.getInteger(i).toString() + " , "; + } + else if (cls == Long.class) { + var += ctx.getLong(i).toString() + " , "; + } + else if (cls == Class.forName("java.math.BigDecimal")) { + var += ctx.getBigDecimal(i).toString() + " , "; + } + else if (cls == Double.class) { + var += ctx.getDouble(i).toString() + " , "; + } + else if (cls == String.class) { + var += ctx.getString(i) + " , "; + } + else if (cls == Boolean.class) { + var += ctx.getBoolean(i).toString() + " , "; + } + else if (cls == Class.forName("java.sql.Date")) { + var += ctx.getDate(i).toString() + " , "; + } + else if (cls == Class.forName("java.sql.Timestamp")) { + var += ctx.getTimestamp(i).toString() + " , "; + } + } + if (!ctx.next()) + break; + } + return var; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SET SCRIPT + empty_set_emits( ... ) + emits (x varchar(2000)) as + class EMPTY_SET_EMITS { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + emit(Integer.toString(1)); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SET SCRIPT + empty_set_returns( ... ) + returns varchar(2000) as + class EMPTY_SET_RETURNS { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return Integer.toString(1); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + metadata_scalar_emit (...) + EMITS("v" VARCHAR(2000)) AS + class METADATA_SCALAR_EMIT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(Long.toString(exa.getInputColumnCount())); + for (int i = 0; i < exa.getInputColumnCount(); i++) { + ctx.emit(exa.getInputColumnName(i)); + ctx.emit(exa.getInputColumnType(i).getCanonicalName()); + ctx.emit(exa.getInputColumnSqlType(i)); + ctx.emit(Long.toString(exa.getInputColumnPrecision(i))); + ctx.emit(Long.toString(exa.getInputColumnScale(i))); + ctx.emit(Long.toString(exa.getInputColumnLength(i))); + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + metadata_scalar_return (...) + RETURNS VARCHAR(2000) AS + class METADATA_SCALAR_RETURN { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return Long.toString(exa.getInputColumnCount()); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SET SCRIPT + type_specific_add(...) + RETURNS VARCHAR(2000) as + import java.math.BigDecimal; + import java.sql.Date; + import java.sql.Timestamp; + class TYPE_SPECIFIC_ADD { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String var = "result: "; + Class cls = exa.getInputColumnType(0); + if (cls == String.class) { + while (true) { + for (int i = 0; i < exa.getInputColumnCount(); i++) { + var += ctx.getString(i) + " , "; + } + if (!ctx.next()) + break; + } + } + else if (cls == Integer.class || cls == Long.class || cls == Double.class) { + double sum = 0; + while (true) { + for (int i = 0; i < exa.getInputColumnCount(); i++) { + sum += ctx.getDouble(i); + } + if (!ctx.next()) + break; + } + var += Double.toString(sum); + } + return var; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + wrong_arg(...) + returns varchar(2000) as + class WRONG_ARG { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getString(1); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + wrong_operation(...) + returns varchar(2000) as + class WRONG_OPERATION { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getString(0) * ctx.getString(1); + } + } + / + ''')) + + self.query('DROP SCHEMA dynamic_input CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA dynamic_input') + self.query('CREATE TABLE dynamic_input.small(x VARCHAR(2000), y DOUBLE)') + self.query('''INSERT INTO dynamic_input.small VALUES ('Some string ... and some more', 2.2)''') + self.query('create table dynamic_input.groupt(id int, n double, v varchar(999))') + self.query('''insert into dynamic_input.groupt values (1,1,'aa'), + (1,2,'ab'), + (2,2,'ba') + ''') + + +class DynamicMetadataTest(_JavaUdfSetup): + + def test_meta_scalar_return(self): + rows = self.query(''' + SELECT fn1.metadata_scalar_return('abc', cast(99 as double)) + FROM DUAL + ''') + self.assertRowEqual(('2',), rows[0]) + + def test_meta_scalar_emit(self): + rows = self.query(''' + SELECT fn1.metadata_scalar_emit('abc', cast(99 as double)) + FROM DUAL + ''') + self.assertRowEqual(('2',), rows[0]) + self.assertRowEqual(('0',), rows[1]) + self.assertTrue(rows[2][0] == "string" or rows[2][0] == "" or rows[2][0] == "character" or rows[2][0] == "java.lang.String" or rows[2][0] == "") + self.assertRowEqual(('CHAR(3) ASCII',), rows[3]) + self.assertRowEqual(('3',), rows[6]) + self.assertRowEqual(('1',), rows[7]) + self.assertTrue(rows[8][0] == 'number' or rows[8][0] == "" or rows[8][0] == "double" or rows[8][0] == "java.lang.Double" or rows[8][0] == "") + self.assertRowEqual(('DOUBLE',), rows[9]) + + +class DynamicInputBasic(_JavaUdfSetup): + def test_basic_scalar_emit_constants(self): + rows = self.query(''' + SELECT fn1.basic_scalar_emit('abc', cast(99 as double)) + FROM DUAL + ''') + self.assertTrue(rows[0][0] == 'abc' or rows[0][0] == "u'abc'" or rows[0][0] == "'abc'") + self.assertTrue(rows[1][0] == '99' or rows[1][0] == "99.0") + + def test_basic_scalar_emit(self): + rows = self.query(''' + SELECT fn1.basic_scalar_emit(x, y) + FROM dynamic_input.small + ''') + self.assertTrue(rows[0][0] == 'Some string ... and some more' or rows[0][0] == "u'Some string ... and some more'" or rows[0][0] == "'Some string ... and some more'") + self.assertRowEqual(('2.2',), rows[1]) + + def test_basic_scalar_return_constants(self): + rows = self.query(''' + SELECT fn1.basic_scalar_return('abc', cast(99 as double)) + FROM DUAL + ''') + self.assertTrue(rows[0][0] == '99' or rows[0][0] == "99.0") + + def test_basic_scalar_return(self): + rows = self.query(''' + SELECT fn1.basic_scalar_return(x, y, x, y, x, y, x, y, x, y, x, y, x, y, x, y) + FROM dynamic_input.small + ''') + self.assertRowEqual(('2.2',), rows[0]) + + def test_basic_set_emit_constants(self): + rows = self.query(''' + SELECT fn1.basic_set_emit(cast(99 as double),'77','aaaa') + FROM DUAL + ''') + print("0---:"+str(rows[3][0])) + self.assertTrue(rows[0][0] == '99' or rows[0][0] == "99.0") + self.assertTrue(rows[1][0] == '77' or rows[1][0] == "u'77'" or rows[1][0] == "'77'") + self.assertTrue(rows[2][0] == 'aaaa' or rows[2][0] == "u'aaaa'" or rows[2][0] == "'aaaa'") + self.assertTrue(rows[3][0] == 'result: , 99 , 77 , aaaa' or rows[3][0] == "result: 99.0 , u'77' , u'aaaa' , " or rows[3][0] == "result: 99 , 77 , aaaa , " or rows[3][0] == "result: 99.0 , 77 , aaaa , " or rows[3][0] == "result: 99.0 , '77' , 'aaaa' , ") + + def test_basic_set_emit(self): + rows = self.query(''' + SELECT fn1.basic_set_emit(n, v) + FROM dynamic_input.groupt GROUP BY id ORDER BY 1 + ''') + self.assertTrue(rows[0][0] == '1' or rows[0][0] == "1.0" or rows[0][0] == "'aa'") + self.assertTrue(rows[1][0] == '2' or rows[1][0] == "2.0" or rows[1][0] == "'ab'") + self.assertTrue(rows[2][0] == '2' or rows[2][0] == "2.0" or rows[2][0] == "'ba'") + self.assertTrue(rows[3][0] == 'aa' or rows[3][0] == "result: 1.0 , u'aa' , 2.0 , u'ab' , " or rows[3][0] == "1.0") + self.assertTrue(rows[4][0] == 'ab' or rows[4][0] == "result: 2.0 , u'ba' , " or rows[4][0] == "2.0") + self.assertTrue(rows[5][0] == 'ba' or rows[5][0] == "u'aa'" or rows[5][0] == "2.0") + self.assertTrue(rows[6][0] == 'result: , 1 , aa , 2 , ab' or rows[6][0] == "u'ab'" or rows[6][0] == "result: 1 , aa , 2 , ab , " or rows[6][0] == "result: 1.0 , aa , 2.0 , ab , " or rows[6][0] == "result: 1.0 , 'aa' , 2.0 , 'ab' , ") + self.assertTrue(rows[7][0] == 'result: , 2 , ba' or rows[7][0] == "u'ba'" or rows[7][0] == "result: 2 , ba , " or rows[7][0] == "result: 2.0 , ba , " or rows[7][0] == "result: 2.0 , 'ba' , ") + + def test_basic_set_emit_one_group(self): + rows = self.query(''' + SELECT fn1.basic_set_emit(cast(id as double), n, v) + FROM dynamic_input.groupt ORDER BY 1 + ''') + self.assertTrue(rows[0][0] == '1' or rows[0][0] == "1.0" or rows[0][0] == "'aa'") + self.assertTrue(rows[1][0] == '1' or rows[1][0] == "1.0" or rows[1][0] == "'ab'") + self.assertTrue(rows[2][0] == '1' or rows[2][0] == "1.0" or rows[2][0] == "'ba'") + self.assertTrue(rows[3][0] == '2' or rows[3][0] == "2.0" or rows[3][0] == "1.0") + self.assertTrue(rows[4][0] == '2' or rows[4][0] == "2.0" or rows[4][0] == "1.0") + self.assertTrue(rows[5][0] == '2' or rows[5][0] == "2.0" or rows[5][0] == "1.0") + self.assertTrue(rows[6][0] == 'aa' or rows[7][0] == "u'aa'" or rows[6][0] == "2.0") + self.assertTrue(rows[7][0] == 'ab' or rows[8][0] == "u'ab'" or rows[7][0] == "2.0") + self.assertTrue(rows[8][0] == 'ba' or rows[9][0] == "u'ba'" or rows[8][0] == "2.0") + self.assertTrue(rows[9][0] == 'result: , 1 , 1 , aa , 2 , 2 , ba , 1 , 2 , ab' \ + or rows[6][0] == "result: 1.0 , 1.0 , u'aa' , 2.0 , 2.0 , u'ba' , 1.0 , 2.0 , u'ab' , " \ + or rows[9][0] == "result: 1 , 1 , aa , 2 , 2 , ba , 1 , 2 , ab , " \ + or rows[9][0] == "result: 1.0 , 1.0 , aa , 2.0 , 2.0 , ba , 1.0 , 2.0 , ab , " or rows[9][0] == "result: 1.0 , 1.0 , 'aa' , 2.0 , 2.0 , 'ba' , 1.0 , 2.0 , 'ab' , ") + + def test_basic_set_return_constants(self): + rows = self.query(''' + SELECT fn1.basic_set_return(cast(99 as double),'77','aaaa') + FROM DUAL + ''') + self.assertTrue(rows[0][0] == 'result: , 99 , 77 , aaaa ' \ + or rows[0][0] == "result: 99.0 , u'77' , u'aaaa' , " \ + or rows[0][0] == "result: 99 , 77 , aaaa , " \ + or rows[0][0] == "result: 99.0 , 77 , aaaa , " or rows[0][0] == "result: 99.0 , '77' , 'aaaa' , ") + + def test_basic_set_return(self): + rows = self.query(''' + SELECT fn1.basic_set_return(n, v) + FROM dynamic_input.groupt GROUP BY id ORDER BY 1 + ''') + self.assertTrue(rows[0][0] == 'result: , 1 , aa , 2 , ab ' \ + or rows[0][0] == "result: 1.0 , u'aa' , 2.0 , u'ab' , " \ + or rows[0][0] == "result: 1 , aa , 2 , ab , " \ + or rows[0][0] == "result: 1.0 , aa , 2.0 , ab , " or rows[0][0] == "result: 1.0 , 'aa' , 2.0 , 'ab' , ") + self.assertTrue(rows[1][0] == 'result: , 2 , ba ' \ + or rows[1][0] == "result: 2.0 , u'ba' , " \ + or rows[1][0] == "result: 2 , ba , " \ + or rows [1][0] == "result: 2.0 , ba , " or rows [1][0] == "result: 2.0 , 'ba' , ") + + def test_basic_set_return_one_group(self): + rows = self.query(''' + SELECT fn1.basic_set_return(cast(id as double), n, v) + FROM dynamic_input.groupt + ''') + self.assertTrue(rows[0][0] == 'result: , 1 , 1 , aa , 2 , 2 , ba , 1 , 2 , ab ' \ + or rows[0][0] == "result: 1.0 , 1.0 , u'aa' , 2.0 , 2.0 , u'ba' , 1.0 , 2.0 , u'ab' , " \ + or rows[0][0] == "result: 1 , 1 , aa , 2 , 2 , ba , 1 , 2 , ab , " \ + or rows[0][0] == "result: 1.0 , 1.0 , aa , 2.0 , 2.0 , ba , 1.0 , 2.0 , ab , " or rows[0][0] == "result: 1.0 , 1.0 , 'aa' , 2.0 , 2.0 , 'ba' , 1.0 , 2.0 , 'ab' , ") + + +class DynamicInputDatatypeSpecific(_JavaUdfSetup): + def test_type_specific_add_string(self): + rows = self.query(''' + SELECT fn1.type_specific_add(v, v, v) + FROM dynamic_input.groupt + ''') + self.assertTrue('result: , aa , aa , aa , ba , ba , ba , ab , ab , ab' == rows[0][0] or 'result: aa , aa , aa , ba , ba , ba , ab , ab , ab , ' == rows[0][0]) + + def test_type_specific_add_number(self): + rows = self.query(''' + SELECT fn1.type_specific_add(n,n,n,n,n,n,n,n,n,n) + FROM dynamic_input.groupt + ''') + self.assertTrue(rows[0][0] == 'result: 50' or rows[0][0] == "result: 50.0" or rows[0][0] == 'result: 50') + + +class DynamicInputErrors(_JavaUdfSetup): + def test_exception_wrong_arg(self): + if self.LANG == 'r': + raise udf.SkipTest('does not work with R currently') + err_text = { + 'lua': 'out of range', + 'python3': 'does not exist', + 'java': 'does not exist', + } + with self.assertRaisesRegex(Exception, err_text[self.LANG]): + self.query('''select fn1.wrong_arg('a') from dual''') + + def test_exception_wrong_operation(self): + err_text = { + 'lua': 'attempt to perform arithmetic on field', + 'r': 'non-numeric argument to binary operator', + 'python3': 'multiply sequence by non-int of type', + 'java': 'bad operand types for binary operator', + } + with self.assertRaisesRegex(Exception, err_text[self.LANG]): + self.query('''select fn1.wrong_operation('a','b') from dual''') + + def test_exception_empty_set_returns(self): + with self.assertRaisesRegex(Exception, 'data exception - missing input parameters for SET UDF script'): + self.query('''select fn1.empty_set_returns() from dynamic_input.groupt''') + + def test_exception_empty_set_emits(self): + with self.assertRaisesRegex(Exception, 'data exception - missing input parameters for SET UDF script'): + self.query('''select fn1.empty_set_emits() from dynamic_input.groupt''') + +class DynamicInputOptimizations(_JavaUdfSetup): + def test_mapreduce_optimization(self): + rows = self.query(''' + select fn1.basic_set_return("v") from ( select fn1.basic_scalar_emit(n,n,n,n,n,n,n,n,n,n) from dynamic_input.groupt) + ''') + self.assertTrue(rows[0][0] == 'result: , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ' \ + or rows[0][0] == "result: u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'1.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , u'2.0' , " \ + or rows[0][0] == "result: 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , " \ + or rows[0][0] == "result: 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , 2.0 , " or rows[0][0] == "result: '1.0' , '1.0' , '1.0' , '1.0' , '1.0' , '1.0' , '1.0' , '1.0' , '1.0' , '1.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , '2.0' , ") + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/emit.py b/test_container/tests/test/generic/java/emit.py new file mode 100644 index 000000000..d0d875c68 --- /dev/null +++ b/test_container/tests/test/generic/java/emit.py @@ -0,0 +1,739 @@ +#!/usr/bin/env python3 + +import datetime + +from exasol_python_test_framework import udf + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + create java scalar script dob_1i_1o(x double) emits(y double) + as + class DOB_1I_1O{ + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script line_1i_1o(x double) emits(y double) + as + class LINE_1I_1O{ + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script line_1i_2o(x double) emits(y double, z double) + as + class LINE_1I_2O{ + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x"),ctx.getDouble("x")); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script line_2i_1o(x double, y double) emits(z double) + as + class LINE_2I_1O{ + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")+ctx.getDouble("y")); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script line_3i_2o(x double, y double, z double) emits(z1 double, z2 double) + as + class LINE_3I_2O{ + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")+ctx.getDouble("y"),3000); + } + } + / + ''')) + +class InputOutputMatchingTest(_JavaUdfSetup): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT dob_1i_1o(x double) + EMITS (y double) AS + class DOB_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_1o(x double) + EMITS (y double) AS + class LINE_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_2o(x double) + EMITS (y double, z double) AS + class LINE_1I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x"), ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_2i_1o(x double, y double) + EMITS (z double) AS + class LINE_2I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_3i_2o(x double, y double, z double) + EMITS (z1 double, z2 double) AS + class LINE_3I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y"), 3000.0); + } + } + / + ''')) + + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + self.query('create table fn2.t(id double, x double)') + self.query('insert into fn2.t values (100,1),(100,2),(200,3)') + + def test_iomatch_1i_1o(self): + rows = self.query(''' + select x*2, fn1.line_1i_1o(x), x*3 + FROM fn2.t + ''') + self.assertRowsEqual(sorted([(2,1,3,), (6,3,9,), (4,2,6,)]), sorted(rows)) + + def test_iomatch_1i_2o(self): + rows = self.query(''' + select x*2, fn1.line_1i_2o(x), x*3 + FROM fn2.t + ''') + self.assertRowsEqual(sorted([(2,1,1,3,), (6,3,3,9,), (4,2,2,6,)]), sorted(rows)) + + def test_iomatch_2i_1o(self): + rows = self.query(''' + select x*2, fn1.line_2i_1o(x,id), x*3 + FROM fn2.t + ''') + self.assertRowsEqual(sorted([(2,101,3,), (6,203,9,), (4,102,6,)]), sorted(rows)) + + def test_iomatch_3i_2o(self): + rows = self.query(''' + select x*2, fn1.line_3i_2o(x,id,id), x*3 + FROM fn2.t + ''') + self.assertRowsEqual(sorted([(2,101,3000,3,), (6,203,3000,9,), (4,102,3000,6,)]), sorted(rows)) + + def test_iomatch_dob_1i_1o(self): + rows = self.query(''' + select x*2, fn1.dob_1i_1o(x), x*3 + FROM fn2.t + ''') + self.assertRowsEqual(sorted([(2,1,3,), (2,1,3,), (6,3,9,), (6,3,9,), (4,2,6,), (4,2,6,)]), sorted(rows)) + + +class ColumnNamesTest(_JavaUdfSetup): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT dob_1i_1o(x double) + EMITS (y double) AS + class DOB_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_1o(x double) + EMITS (y double) AS + class LINE_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_2o(x double) + EMITS (y double, z double) AS + class LINE_1I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x"), ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_2i_1o(x double, y double) + EMITS (z double) AS + class LINE_2I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_3i_2o(x double, y double, z double) + EMITS (z1 double, z2 double) AS + class LINE_3I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y"), 3000.0); + } + } + / + ''')) + + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + self.query('create table fn2.t(id double, x double)') + self.query('insert into fn2.t values (100,1),(100,2),(200,3)') + + def test_col_names(self): + self.query(''' + create or replace table fn2.foo as select x*2 a, fn1.line_3i_2o(x,id,id), x*3 b + FROM fn2.t + ''') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('A',rows[0][0]) + self.assertEqual('Z1',rows[1][0]) + self.assertEqual('Z2',rows[2][0]) + self.assertEqual('B',rows[3][0]) + + +class DatatypesTest(_JavaUdfSetup): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT dob_1i_1o(x double) + EMITS (y double) AS + class DOB_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_1o(x double) + EMITS (y double) AS + class LINE_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_2o(x double) + EMITS (y double, z double) AS + class LINE_1I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x"), ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_2i_1o(x double, y double) + EMITS (z double) AS + class LINE_2I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_3i_2o(x double, y double, z double) + EMITS (z1 double, z2 double) AS + class LINE_3I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y"), 3000.0); + } + } + / + ''')) + + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + + def test_boolean(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x BOOLEAN)') + self.query('insert into fn2.dt values false') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(False,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('BOOLEAN', rows[0][1]) + + def test_double(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DOUBLE)') + self.query('insert into fn2.dt values 32768e100') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(3.2768e+104,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DOUBLE', rows[0][1]) + + def test_dec_32bit(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(9,0))') + self.query('insert into fn2.dt values 32768') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(32768,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DECIMAL(9,0)', rows[0][1]) + + def test_dec_64bit(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(18,0))') + self.query('insert into fn2.dt values 32768') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(32768,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DECIMAL(18,0)', rows[0][1]) + + def test_dec_128bit(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(36,0))') + self.query('insert into fn2.dt values 32768') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(32768,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DECIMAL(36,0)', rows[0][1]) + + def test_dec_32bit_with_scale(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(9,1))') + self.query('insert into fn2.dt values 99999999.1') + rows = self.query(''' + select x = 99999999.1 from (select x, fn1.line_1i_1o(0) + FROM fn2.dt) + ''') + self.assertRowsEqual([(True,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DECIMAL(9,1)', rows[0][1]) + + def test_dec_64bit_with_scale(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(18,1))') + self.query('insert into fn2.dt values 9999999999999999.1') + rows = self.query(''' + select x = 9999999999999999.1 from (select x, fn1.line_1i_1o(0) + FROM fn2.dt) + ''') + self.assertRowsEqual([(True,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DECIMAL(18,1)', rows[0][1]) + + def test_dec_128bit_with_scale(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(36,1))') + self.query('insert into fn2.dt values 999999999999999999999999999999999.1') + rows = self.query(''' + select x = 999999999999999999999999999999999.1 from (select x, fn1.line_1i_1o(0) + FROM fn2.dt) + ''') + self.assertRowsEqual([(True,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DECIMAL(36,1)', rows[0][1]) + + def test_timestamp(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x TIMESTAMP)') + self.query(''' + insert into fn2.dt values '2010-01-01 23:33:33' + ''') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(datetime.datetime(2010, 1, 1, 23, 33, 33),0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('TIMESTAMP(3)', rows[0][1]) + + def test_timestamp_with_timezone(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x TIMESTAMP WITH LOCAL TIME ZONE)') + self.query(''' + insert into fn2.dt values '2010-01-01 23:33:33' + ''') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(datetime.datetime(2010, 1, 1, 23, 33, 33),0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('TIMESTAMP(3) WITH LOCAL TIME ZONE', rows[0][1]) + + def test_date(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DATE)') + self.query(''' + insert into fn2.dt values '2010-01-01' + ''') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(datetime.date(2010, 1, 1),0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('DATE', rows[0][1]) + + def test_varchar_utf8(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x VARCHAR(3000) UTF8)') + self.query('insert into fn2.dt values repeat(5,300)') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('5'*300,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('VARCHAR(3000) UTF8', rows[0][1]) + + def test_varchar_ascii(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x VARCHAR(3000) ASCII)') + self.query('insert into fn2.dt values repeat(5,300)') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('5'*300,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('VARCHAR(3000) ASCII', rows[0][1]) + + def test_char_utf8(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x CHAR(2000) UTF8)') + self.query('insert into fn2.dt values repeat(5,2000)') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('5'*2000,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('CHAR(2000) UTF8', rows[0][1]) + + def test_char_ascii(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x CHAR(2000) ASCII)') + self.query('insert into fn2.dt values repeat(5,2000)') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('5'*2000,0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('CHAR(2000) ASCII', rows[0][1]) + + def test_interval_ym(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x INTERVAL YEAR TO MONTH)') + self.query(''' + insert into fn2.dt values '23-11' + ''') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('+23-11',0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('INTERVAL YEAR(2) TO MONTH', rows[0][1]) + + def test_interval_ds(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x INTERVAL DAY TO SECOND)') + self.query(''' + insert into fn2.dt values '30 23:33:33' + ''') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('+30 23:33:33.000',0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('INTERVAL DAY(2) TO SECOND(3)', rows[0][1]) + + def test_geometry(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x GEOMETRY)') + self.query(''' + insert into fn2.dt values 'POINT(1 1)' + ''') + rows = self.query(''' + select x, fn1.line_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([('POINT (1 1)',0,)], rows) + self.query('create or replace table fn2.foo as select x, fn1.line_1i_1o(0) from fn2.dt') + rows = self.query(''' + describe fn2.foo + ''') + self.assertEqual('GEOMETRY', rows[0][1]) + + +class NullTest(_JavaUdfSetup): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT dob_1i_1o(x double) + EMITS (y double) AS + class DOB_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_1o(x double) + EMITS (y double) AS + class LINE_1I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_1i_2o(x double) + EMITS (y double, z double) AS + class LINE_1I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x"), ctx.getDouble("x")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_2i_1o(x double, y double) + EMITS (z double) AS + class LINE_2I_1O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y")); + } + } + / + ''')) + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT line_3i_2o(x double, y double, z double) + EMITS (z1 double, z2 double) AS + class LINE_3I_2O { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(ctx.getDouble("x") + ctx.getDouble("y"), 3000.0); + } + } + / + ''')) + + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + + def test_boolean_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x BOOLEAN)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0), NVL(x,1) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,True,),(None,0,True,)], rows) + + def test_double_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DOUBLE)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(x), NVL(x,1) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,None,1,),(None,None,1,)], rows) + + def test_int32_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(9,0))') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0), NVL(x,1) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,1,),(None,0,1,)], rows) + + def test_int64_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(18,0))') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0), NVL(x,1) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,1,),(None,0,1,)], rows) + + def test_int128_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x DECIMAL(36,0))') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0), NVL(x,1) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,1,),(None,0,1,)], rows) + + def test_timestamp_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x timestamp)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + def test_date_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x date)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + def test_intervalym_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x interval year to month)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + def test_intervalds_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x interval day to second)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + def test_geo_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x geometry)') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + def test_varchar_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x varchar(2000))') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + def test_char_null(self): + self.query('CREATE OR REPLACE TABLE fn2.DT(x char(2000))') + self.query('insert into fn2.dt values NULL') + rows = self.query(''' + select x, fn1.dob_1i_1o(0) + FROM fn2.dt + ''') + self.assertRowsEqual([(None,0,),(None,0,)], rows) + + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/export_alias.py b/test_container/tests/test/generic/java/export_alias.py new file mode 100644 index 000000000..cb8325ce3 --- /dev/null +++ b/test_container/tests/test/generic/java/export_alias.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class ExportAliasTest(udf.TestCase): + result_unknown = 0 + result_ok = 1 + result_failed = 2 + result_test_error = 3 + + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + self.query('create or replace table fn2.t(a int, z varchar(3000))') + self.query("insert into fn2.t values (1, 'x')") + self.query('create or replace table fn2.\"tl\"(a int, \"z\" varchar(3000))') + self.query("insert into fn2.\"tl\" values (1, 'x')") + self.query("create connection FOOCONN to 'a' user 'b' identified by 'c'", ignore_errors=True) + + self.query('OPEN SCHEMA FN1') + + # Create all EXPORT UDF scripts + self.query(udf.fixindent(''' + create or replace java set script expal_test_pass_fail(res varchar(100)) emits (x int) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_TEST_PASS_FAIL { + public static void run(ExaMetadata meta, ExaIterator iter) throws Exception { + String result = iter.getString("res"); + if (result.equals("ok")) { + iter.emit(1); + } + else if (result.equals("failed")) { + iter.emit(2); + } + else { + iter.emit(3); + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_param_foo_bar(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_PARAM_FOO_BAR { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + !exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"T\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"T\\".\\"Z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_connection_name(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_CONNECTION_NAME { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName().equals("FOOCONN") && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + !exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"T\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"T\\".\\"Z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_connection_info(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_CONNECTION_INFO { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation().getAddress().equals("a") && + exportSpecification.getConnectionInformation().getUser().equals("b") && + exportSpecification.getConnectionInformation().getPassword().equals("c") && + !exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"T\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"T\\".\\"Z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_has_truncate(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_HAS_TRUNCATE { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"T\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"T\\".\\"Z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_replace_created_by(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_REPLACE_CREATED_BY { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + !exportSpecification.hasTruncate() && + exportSpecification.hasReplace() && + exportSpecification.hasCreatedBy() && + exportSpecification.getCreatedBy().equals("create table t(a int, z varchar(3000))") && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"T\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"T\\".\\"Z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_column_name_lower_case(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_COLUMN_NAME_LOWER_CASE { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + !exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"tl\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"tl\\".\\"z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_column_selection(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_COLUMN_SELECTION { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + !exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"tl\\".\\"A\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"tl\\".\\"z\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script expal_use_query(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class EXPAL_USE_QUERY { + static String generateSqlForExportSpec(ExaMetadata exa, ExaExportSpecification exportSpecification) { + if (exportSpecification.getParameters().size() == 2 && + exportSpecification.getParameters().get("FOO").equals("bar") && + exportSpecification.getParameters().get("BAR").equals("foo") && + !exportSpecification.hasConnectionName() && + exportSpecification.getConnectionName() == null && + !exportSpecification.hasConnectionInformation() && + exportSpecification.getConnectionInformation() == null && + !exportSpecification.hasTruncate() && + !exportSpecification.hasReplace() && + !exportSpecification.hasCreatedBy() && + exportSpecification.getSourceColumnNames().size() == 2 && + exportSpecification.getSourceColumnNames().get(0).equals("\\"col1\\"") && + exportSpecification.getSourceColumnNames().get(1).equals("\\"col2\\"")) { + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('ok')"; + } + return "select " + exa.getScriptSchema() + ".expal_test_pass_fail('failed')"; + } + } + / + ''')) + +# ATTENTION! +# ATTENTION! +# The logic for the tests had to be put in the export_alias.sql files for each language. +# This was required because EXPORT INTO SCRIPT can only return a single integer. + + def test_export_use_params(self): + rows = self.executeStatement("EXPORT fn2.t INTO SCRIPT fn1.expal_use_param_foo_bar with foo='bar' bar='foo'") + self.assertEqual(self.result_ok, rows) + + def test_export_use_connection_name(self): + rows = self.executeStatement("EXPORT fn2.t INTO SCRIPT fn1.expal_use_connection_name AT FOOCONN with foo='bar' bar='foo'") + self.assertEqual(self.result_ok, rows) + + def test_export_use_connection_info(self): + rows = self.executeStatement("EXPORT fn2.t INTO SCRIPT fn1.expal_use_connection_info AT 'a' USER 'b' IDENTIFIED BY 'c' with foo='bar' bar='foo'") + self.assertEqual(self.result_ok, rows) + + def test_export_use_has_truncate(self): + rows = self.executeStatement("EXPORT fn2.t INTO SCRIPT fn1.expal_use_has_truncate with foo='bar' bar='foo' truncate") + self.assertEqual(self.result_ok, rows) + + def test_export_use_replace_created_by(self): + rows = self.executeStatement("EXPORT fn2.t INTO SCRIPT fn1.expal_use_replace_created_by with foo='bar' bar='foo' replace created by 'create table t(a int, z varchar(3000))'") + self.assertEqual(self.result_ok, rows) + + def test_export_use_column_name_lower_case(self): + rows = self.executeStatement("EXPORT fn2.\"tl\" INTO SCRIPT fn1.expal_use_column_name_lower_case with foo='bar' bar='foo'") + self.assertEqual(self.result_ok, rows) + + def test_export_use_column_selection(self): + rows = self.executeStatement("EXPORT fn2.\"tl\"(a, \"z\") INTO SCRIPT fn1.expal_use_column_selection with foo='bar' bar='foo'") + self.assertEqual(self.result_ok, rows) + + def test_export_use_query(self): + rows = self.executeStatement("EXPORT (select a as 'col1', \"z\" as 'col2' from fn2.\"tl\") INTO SCRIPT fn1.expal_use_query with foo='bar' bar='foo'") + self.assertEqual(self.result_ok, rows) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/generic_types.py b/test_container/tests/test/generic/java/generic_types.py new file mode 100755 index 000000000..4ee3dc0d9 --- /dev/null +++ b/test_container/tests/test/generic/java/generic_types.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + bottleneck_char10(i VARCHAR(20)) + RETURNS CHAR(10) AS + class BOTTLENECK_CHAR10 { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getString("i"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + bottleneck_decimal5(i DECIMAL(20, 0)) + RETURNS DECIMAL(5, 0) AS + import java.math.BigDecimal; + class BOTTLENECK_DECIMAL5 { + static BigDecimal run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getBigDecimal("i"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + bottleneck_varchar10(i VARCHAR(20)) + RETURNS VARCHAR(10) AS + class BOTTLENECK_VARCHAR10 { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return ctx.getString("i"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_boolean(x BOOLEAN) RETURNS BOOLEAN AS + class ECHO_BOOLEAN { + static Boolean run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getBoolean("x") != null) + return ctx.getBoolean("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_char1(x CHAR(1)) RETURNS CHAR(1) AS + class ECHO_CHAR1 { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getString("x") != null) + return ctx.getString("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_char10(x CHAR(10)) RETURNS CHAR(10) AS + class ECHO_CHAR10 { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getString("x") != null && ctx.getString("x").length() == 10) + return ctx.getString("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_date(x DATE) RETURNS DATE AS + import java.sql.Date; + class ECHO_DATE { + static Date run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDate("x") != null) + return ctx.getDate("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_decimal_36_0(x DECIMAL(36,0)) RETURNS DECIMAL(36,0) AS + import java.math.BigDecimal; + class ECHO_DECIMAL_36_0 { + static BigDecimal run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getBigDecimal("x") != null) + return ctx.getBigDecimal("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_decimal_36_36(x DECIMAL(36,36)) RETURNS DECIMAL(36,36) AS + import java.math.BigDecimal; + class ECHO_DECIMAL_36_36 { + static BigDecimal run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getBigDecimal("x") != null) + return ctx.getBigDecimal("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_double(x DOUBLE) RETURNS DOUBLE AS + class ECHO_DOUBLE { + static Double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDouble("x") != null) + return ctx.getDouble("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_integer(x INTEGER) RETURNS INTEGER AS + class ECHO_INTEGER { + static Long run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getLong("x") != null) + return ctx.getLong("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_timestamp(x TIMESTAMP) RETURNS TIMESTAMP AS + import java.sql.Timestamp; + class ECHO_TIMESTAMP { + static Timestamp run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getTimestamp("x") != null) + return ctx.getTimestamp("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT echo_varchar10(x VARCHAR(10)) RETURNS VARCHAR(10) AS + class ECHO_VARCHAR10 { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getString("x") != null) + return ctx.getString("x"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT run_func_is_empty() RETURNS DOUBLE AS + class RUN_FUNC_IS_EMPTY { + static Double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return null; + } + } + / + ''')) + +class TestEcho(_JavaUdfSetup): + + def test_echo_boolean(self): + rows = self.query(''' + SELECT + fn1.echo_boolean(Null) is NULL, + fn1.echo_boolean(True) = True, + fn1.echo_boolean(False) = False + FROM DUAL''') + self.assertRowsEqual([(True, True, True)], rows) + + def test_echo_char1(self): + rows = self.query(''' + SELECT + fn1.echo_char1(NULL) is NULL, + fn1.echo_char1('a') = 'a' + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + def test_echo_char10(self): + rows = self.query(''' + SELECT + fn1.echo_char10(NULL) is NULL, + fn1.echo_char10('ab') = 'ab ' + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + def test_echo_date(self): + rows = self.query(''' + SELECT + fn1.echo_date(NULL) is NULL, + fn1.echo_date(current_date()) = current_date() + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + def test_echo_integer_basic(self): + rows = self.query(''' + SELECT + fn1.echo_integer(NULL) is NULL, + fn1.echo_integer(-1) = -1, + fn1.echo_integer(0) = 0, + fn1.echo_integer(1) = 1 + FROM DUAL''') + self.assertRowsEqual([(True, True, True, True)], rows) + + @udf.TestCase.expectedFailureIfLang('r') + def test_echo_integer_limits(self): + """DWA-13784 (R)""" + rows = self.query(''' + SELECT + fn1.echo_integer(-(1e18 - 1)) = -(1e18 - 1), + fn1.echo_integer( 1e18 - 1) = 1e18 - 1 + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + def test_echo_double(self): + rows = self.query(''' + SELECT + fn1.echo_double(NULL) is NULL, + fn1.echo_double(CAST(1.5 AS DOUBLE)) = CAST(1.5 AS DOUBLE), + fn1.echo_double(0) = 0.0, + fn1.echo_double(0.0) = 0.0, + fn1.echo_double(-1.7e-308) = -1.7e-308, + fn1.echo_double(+1.7e-308) = +1.7e-308 + FROM DUAL''') + self.assertRowsEqual([(True, True, True, True, True, True)], rows) + + def test_echo_decimal_36_0_basic(self): + rows = self.query(''' + SELECT + fn1.echo_decimal_36_0(NULL) is NULL, + fn1.echo_decimal_36_0(0) = 0, + fn1.echo_decimal_36_0(0.0) = 0.0 + FROM DUAL''') + self.assertRowsEqual([(True, True, True)], rows) + + @udf.TestCase.expectedFailureIfLang('r') + def test_echo_decimal_36_0_limits(self): + """DWA-13784 (R)""" + rows = self.query(''' + SELECT + fn1.echo_decimal_36_0(-(1e35 - 1)) = -(1e35 - 1), + fn1.echo_decimal_36_0( 1e35 - 1) = 1e35 - 1 + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + def test_echo_decimal_36_36_basic(self): + rows = self.query(''' + SELECT + fn1.echo_decimal_36_36(NULL) is NULL, + fn1.echo_decimal_36_36(0) = 0, + fn1.echo_decimal_36_36(0.0) = 0.0 + FROM DUAL''') + self.assertRowsEqual([(True, True, True)], rows) + + @udf.TestCase.expectedFailureIfLang('r') + def test_echo_decimal_36_36_limits(self): + """DWA-13784 (R)""" + rows = self.query(''' + SELECT + fn1.echo_decimal_36_36(-(1e-35 - 1)) = -(1e-35 - 1), + fn1.echo_decimal_36_36( 1e-35 - 1) = 1e-35 - 1 + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + def test_echo_varchar10(self): + rows = self.query(''' + SELECT + fn1.echo_varchar10(NULL) is NULL, + fn1.echo_varchar10('') is NULL, + fn1.echo_varchar10(' ') = ' ', + fn1.echo_varchar10('a') = 'a', + fn1.echo_varchar10('a ') = 'a ', + fn1.echo_varchar10(' a ') = ' a ' + FROM DUAL''') + self.assertRowsEqual([(True, True, True, True, True, True)], rows) + + def test_echo_timestamp(self): + rows = self.query(''' + SELECT fn1.echo_timestamp(NULL) is NULL + FROM DUAL''') + self.assertRowsEqual([(True,)], rows) + + rows = self.query(''' + SELECT fn1.echo_timestamp('2017-08-01 13:13:50.910') = '2017-08-01 13:13:50.910', + fn1.echo_timestamp('2017-08-01 13:13:50.983') = '2017-08-01 13:13:50.983' + FROM DUAL''') + self.assertRowsEqual([(True, True)], rows) + + self.query('DROP SCHEMA ECHO_TEST CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA ECHO_TEST') + self.query('''CREATE OR REPLACE TABLE ECHO_TEST.N1 (now VARCHAR(255))''') + self.query('''INSERT INTO ECHO_TEST.N1 VALUES (SELECT now() AS x FROM DUAL)''') + self.query(''' + SELECT x1 = x2, x1, x2, x3 + FROM (SELECT fn1.echo_timestamp(x) AS x1, x AS x2, x AS x3 + FROM (SELECT now AS x FROM ECHO_TEST.N1)) + ''') + self.assertEqual(True, rows[0][0], str(rows)) + self.query('''DROP SCHEMA ECHO_TEST CASCADE''') + + +class EmptyTest(_JavaUdfSetup): + def test_run_func_is_empty(self): + rows = self.query(''' + SELECT + fn1.run_func_is_empty() IS NULL + FROM DUAL''') + self.assertRowsEqual([(True,)], rows) + + +class BottleneckTest(_JavaUdfSetup): + def test_varchar10(self): + for i in 0, 1, 5, 10: + rows = self.query(''' + SELECT fn1.bottleneck_varchar10('%s') + FROM DUAL''' % ('x' * i)) + self.assertEqual('x' * i if i > 0 else None, rows[0][0]) + with self.assertRaises(Exception): + self.query(''' + SELECT fn1.bottleneck_varchar10('%s') + FROM DUAL''' % ('x' * 11)) + + def test_char10(self): + for i in 0, 1, 5, 10: + rows = self.query(''' + SELECT fn1.bottleneck_char10('%s') + FROM DUAL''' % ('x' * i)) + self.assertEqual( + ('x' * i + ' ' * 10)[:10] if i > 0 else None, + rows[0][0]) + with self.assertRaises(Exception): + self.query(''' + SELECT fn1.bottleneck_char10('%s') + FROM DUAL''' % ('x' * 11)) + + def test_decimal5(self): + for i in 3, 4: + rows = self.query(''' + SELECT fn1.bottleneck_decimal5(%d) + FROM DUAL''' % (10 ** i)) + self.assertEqual(10 ** i, rows[0][0]) + with self.assertRaises(Exception): + self.query(''' + SELECT fn1.bottleneck_decimal5(%d) + FROM DUAL''' % (10 ** 5)) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/import_alias.py b/test_container/tests/test/generic/java/import_alias.py new file mode 100644 index 000000000..71ca73254 --- /dev/null +++ b/test_container/tests/test/generic/java/import_alias.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf +from exasol_python_test_framework import exatest +from exasol_python_test_framework.udf import skip + + +class ImportAliasTest(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + self.query('create or replace table fn2.t(z varchar(3000))') + self.query('create or replace table fn2.t2(y varchar(2000), z varchar(3000))') + self.query(''' + create connection FOOCONN to 'a' user 'b' identified by 'c' + ''', ignore_errors=True) + + self.query('OPEN SCHEMA FN1') + + # Create all IMPORT UDF scripts + self.query(udf.fixindent(''' + create or replace java set script impal_use_is_subselect(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class IMPAL_USE_IS_SUBSELECT { + static String generateSqlForImportSpec(ExaMetadata exa, ExaImportSpecification importSpecification) { + return "select " + importSpecification.isSubselect(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script impal_use_param_foo_bar(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class IMPAL_USE_PARAM_FOO_BAR { + static String generateSqlForImportSpec(ExaMetadata exa, ExaImportSpecification importSpecification) { + return "select '" + importSpecification.getParameters().get("FOO") + "', '" + importSpecification.getParameters().get("BAR") + "'"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script impal_use_connection_name(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class IMPAL_USE_CONNECTION_NAME { + static String generateSqlForImportSpec(ExaMetadata exa, ExaImportSpecification importSpecification) { + return "select '" + importSpecification.getConnectionName() + "'"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script impal_use_connection_fooconn(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class IMPAL_USE_CONNECTION_FOOCONN { + static String generateSqlForImportSpec(ExaMetadata exa, ExaImportSpecification importSpecification) throws Exception { + ExaConnectionInformation c = exa.getConnection("FOOCONN"); + return "select '" + c.getAddress() + c.getUser() + c.getPassword() + "'"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script impal_use_connection(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class IMPAL_USE_CONNECTION { + static String generateSqlForImportSpec(ExaMetadata exa, ExaImportSpecification importSpecification) { + ExaConnectionInformation conn = importSpecification.getConnectionInformation(); + return "select '" + conn.getUser() + conn.getPassword() + conn.getAddress() + conn.getType().toString().toLowerCase() + "'"; + } + } + / + ''')) + + self.query(udf.fixindent(''' + create or replace java set script impal_use_all(...) emits (x varchar(2000)) as + %jvmoption -Xms64m -Xmx128m -Xss512k; + class IMPAL_USE_ALL { + static String generateSqlForImportSpec(ExaMetadata exa, ExaImportSpecification importSpecification) { + String is_sub = "FALSE"; + if (importSpecification.isSubselect()) { + is_sub = "TRUE"; + } + String connection_string = "X"; + String connection_name = "Y"; + String foo = "Z"; + String types = "T"; + String names = "N"; + if (importSpecification.hasConnectionInformation()) { + ExaConnectionInformation conn = importSpecification.getConnectionInformation(); + connection_string = conn.getUser() + conn.getPassword() + conn.getAddress() + conn.getType().toString().toLowerCase(); + } + if (importSpecification.hasConnectionName()) { + connection_name = importSpecification.getConnectionName(); + } + if (importSpecification.getParameters().get("FOO") != null) { + foo = importSpecification.getParameters().get("FOO"); + } + if (importSpecification.getSubselectColumnNames().size() > 0) { + for (int i = 0; i < importSpecification.getSubselectColumnNames().size(); i++) { + types = types + importSpecification.getSubselectColumnSqlTypes().get(i); + names = names + importSpecification.getSubselectColumnNames().get(i); + } + } + return "select 1, '" + is_sub + '_' + connection_name + '_' + connection_string + '_' + foo + '_' + types + '_' + names + "'"; + } + } + / + ''')) + + def test_import_use_is_subselect(self): + self.query(''' + IMPORT INTO fn2.t FROM SCRIPT fn1.impal_use_is_subselect + ''') + rows = self.query('select * from fn2.t') + self.assertRowsEqual([('FALSE',)], rows) + self.query('truncate table fn2.t') + + def test_import_use_is_subselect_subselect(self): + rows = self.query(''' + SELECT * FROM (IMPORT FROM SCRIPT fn1.impal_use_is_subselect) + ''') + self.assertRowsEqual([(True,)], rows) + rows = self.query(''' + IMPORT FROM SCRIPT fn1.impal_use_is_subselect + ''') + self.assertRowsEqual([(True,)], rows) + + def test_import_use_params(self): + self.query("IMPORT INTO fn2.t2 FROM SCRIPT fn1.impal_use_param_foo_bar with foo='bar' bar='foo'") + rows = self.query('select * from fn2.t2') + self.assertRowsEqual([('bar','foo')], rows) + self.query('truncate table fn2.t2') + + def test_import_use_params_subselect(self): + rows = self.query("SELECT * FROM (IMPORT FROM SCRIPT fn1.impal_use_param_foo_bar with foo='bar' bar='foo')") + self.assertRowsEqual([('bar','foo')], rows) + rows = self.query("IMPORT FROM SCRIPT fn1.impal_use_param_foo_bar with foo='bar' bar='foo'") + self.assertRowsEqual([('bar','foo')], rows) + + def test_import_use_connection_name(self): + self.query('IMPORT INTO fn2.t FROM SCRIPT fn1.impal_use_connection_name at fooconn') + rows = self.query('select * from fn2.t') + self.assertRowsEqual([('FOOCONN',)], rows) + self.query('truncate table fn2.t') + + def test_import_use_connection_fooconn(self): + rows = self.query('IMPORT FROM SCRIPT fn1.impal_use_connection_fooconn') + self.assertRowsEqual([('abc',)], rows) + self.query('truncate table fn2.t') + + def getConnection(self, username, password): + client = exatest.ODBCClient('exatest') + self.log.debug('connecting to DSN "exa" for user {username}'.format(username=username)) + client.connect(uid = username, pwd = password) + return client + + def createUser(self, username, password): + self.query('DROP USER IF EXISTS {username} CASCADE'.format(username = username)) + self.query('CREATE USER {username} IDENTIFIED BY "{password}"'.format(username = username, password = password)) + self.query('GRANT CREATE SESSION TO {username}'.format(username=username)) + + def test_import_use_connection_fooconn_fails_for_user_foo(self): + self.createUser('foo','foo') + self.commit() + foo_conn = self.getConnection('foo','foo') + with self.assertRaisesRegex(Exception, 'insufficient privileges'): + foo_conn.query('IMPORT FROM SCRIPT fn1.impal_use_connection_fooconn') + self.query('drop user foo cascade') + + @skip("IMPORT FROM SCRIPT cannot be used in view definitions") + def test_import_use_connection_fooconn_for_user_foo_and_view(self): + self.query('create view fn2.fooconn_import_view as IMPORT FROM SCRIPT fn1.impal_use_connection_fooconn') + self.createUser('foo','foo') + self.commit() + foo_conn = self.getConnection('foo','foo') + rows = foo_conn.query('select * from fn2.fooconn_import_view') + self.assertRowsEqual([('abc',)], rows) + self.query('drop user foo cascade') + self.query('drop view fn2.fooconn_import_view') + + def test_import_use_connection_name_subselect(self): + rows = self.query('SELECT * FROM (IMPORT FROM SCRIPT fn1.impal_use_connection_name at fooconn)') + self.assertRowsEqual([('FOOCONN',)], rows) + rows = self.query('IMPORT FROM SCRIPT fn1.impal_use_connection_name at fooconn') + self.assertRowsEqual([('FOOCONN',)], rows) + + def test_import_use_connection(self): + self.query(''' + IMPORT INTO fn2.t FROM SCRIPT fn1.impal_use_connection + at 'fooconn' user 'hans' identified by 'meiser' + ''') + rows = self.query('select * from fn2.t') + self.assertRowsEqual([('hansmeiserfooconnpassword',)], rows) + self.query('truncate table fn2.t') + + def test_import_use_connection_subselect(self): + rows = self.query(''' SELECT * FROM ( + IMPORT FROM SCRIPT fn1.impal_use_connection + at 'fooconn' user 'hans' identified by 'meiser') + ''') + self.assertRowsEqual([('hansmeiserfooconnpassword',)], rows) + rows = self.query(''' + IMPORT FROM SCRIPT fn1.impal_use_connection + at 'fooconn' user 'hans' identified by 'meiser' + ''') + self.assertRowsEqual([('hansmeiserfooconnpassword',)], rows) + + def test_import_use_all(self): + self.query(''' + IMPORT INTO fn2.t2 FROM SCRIPT fn1.impal_use_all + at 'fooconn' user 'hans' identified by 'meiser' with foo='a value' + ''') + rows = self.query('select * from fn2.t2') + self.assertRowsEqual([('1','FALSE_Y_hansmeiserfooconnpassword_a value_T_N')], rows) + self.query('truncate table fn2.t2') + + def test_import_use_all_subselect(self): + rows = self.query(''' SELECT * FROM ( + IMPORT INTO (a double, b varchar(3000)) FROM SCRIPT fn1.impal_use_all + at 'fooconn' user 'hans' identified by 'meiser' with foo='a value') + ''') + self.assertRowsEqual([(1, 'TRUE_Y_hansmeiserfooconnpassword_a value_TDOUBLEVARCHAR(3000) UTF8_NAB')], rows) + rows = self.query(''' + IMPORT INTO (a double, b varchar(3000)) FROM SCRIPT fn1.impal_use_all + at 'fooconn' user 'hans' identified by 'meiser' with foo='a value' + ''') + self.assertRowsEqual([(1, 'TRUE_Y_hansmeiserfooconnpassword_a value_TDOUBLEVARCHAR(3000) UTF8_NAB')], rows) + + def test_prepared_statement_params(self): + with self.assertRaisesRegex(Exception, 'syntax error, unexpected \'?\''): + rows = self.query(''' SELECT * FROM ( + IMPORT INTO (a double, b varchar(3000)) FROM SCRIPT fn1.impal_use_all + at 'fooconn' user 'hans' identified by 'meiser' with foo=?) + ''', 'bar') + + def test_prepared_statement_conn(self): + with self.assertRaisesRegex(Exception, 'syntax error, unexpected \'?\''): + rows = self.query(''' SELECT * FROM ( + IMPORT INTO (a double, b varchar(3000)) FROM SCRIPT fn1.impal_use_all + at ? user ? identified by ? with foo='bar') + ''', 'fooconn', 'hans', 'meiser', 'bar') + + def test_import_in_lua_scripting(self): + self.query(''' + create or replace script s1() as + res = pquery [[ IMPORT INTO fn2.t FROM SCRIPT fn1.impal_use_is_subselect ]] + ''') + self.query('execute script s1()') + rows = self.query('select * from fn2.t') + self.assertRowsEqual([('FALSE',)], rows) + self.query('truncate table fn2.t') + + +if __name__ == '__main__': + udf.main() + + diff --git a/test_container/tests/test/generic/java/metadata.py b/test_container/tests/test/generic/java/metadata.py new file mode 100755 index 000000000..e9b6ae7d5 --- /dev/null +++ b/test_container/tests/test/generic/java/metadata.py @@ -0,0 +1,508 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + create java scalar script + get_char_length(text char(10)) + emits(len1 number, len2 number, dummy char(20)) + as + class GET_CHAR_LENGTH { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + long v = exa.getInputColumnLength(0); + long w = exa.getOutputColumnLength(2); + ctx.emit(v, w, "9876543210"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_current_schema() returns varchar(200) as + class GET_CURRENT_SCHEMA { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getCurrentSchema(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_current_user() returns varchar(200) as + class GET_CURRENT_USER { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getCurrentUser(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + get_database_name() returns varchar(300) AS + class GET_DATABASE_NAME { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getDatabaseName(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_database_version() returns varchar(20) as + class GET_DATABASE_VERSION { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getDatabaseVersion(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_input_column_count_scalar(c1 double, c2 varchar(100)) + returns number as + class GET_INPUT_COLUMN_COUNT_SCALAR { + static long run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getInputColumnCount(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java set script + get_input_column_count_set(c1 double, c2 varchar(100)) + returns number as + class GET_INPUT_COLUMN_COUNT_SET { + static long run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getInputColumnCount(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_input_columns(c1 double, c2 varchar(200)) + emits (column_id number, column_name varchar(200), column_type varchar(20), + column_sql_type varchar(20), column_precision number, column_scale number, + column_length number) as + class GET_INPUT_COLUMNS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + for (int i = 0; i < exa.getInputColumnCount(); i++) { + String name = exa.getInputColumnName(i); + long precision = exa.getInputColumnPrecision(i); + String thetype = exa.getInputColumnType(i).getCanonicalName(); + String sql_type = exa.getInputColumnSqlType(i); + long scale = exa.getInputColumnScale(i); + long length = exa.getInputColumnLength(i); + if (name == null) + name = "no-name"; + if (thetype == null) + thetype = "no-type"; + if (sql_type == null) + sql_type = "no-sql-type"; + ctx.emit(i + 1, name, thetype, sql_type, precision, scale, length); + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_input_type_scalar() returns varchar(200) as + class GET_INPUT_TYPE_SCALAR { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getInputType(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java set script + get_input_type_set(a double) returns varchar(200) as + class GET_INPUT_TYPE_SET { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getInputType(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_node_id() returns number as + class GET_NODE_ID { + static long run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getNodeId(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_output_column_count_emit() + emits (x number, y number, z number) as + class GET_OUTPUT_COLUMN_COUNT_EMIT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(exa.getOutputColumnCount(), exa.getOutputColumnCount(), exa.getOutputColumnCount()); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_output_column_count_return() + returns number as + class GET_OUTPUT_COLUMN_COUNT_RETURN { + static long run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getOutputColumnCount(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_output_columns() + emits (column_id number, column_name varchar(200), column_type varchar(20), + column_sql_type varchar(20), column_precision number, column_scale number, + column_length number) as + class GET_OUTPUT_COLUMNS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + for (int i = 0; i < exa.getOutputColumnCount(); i++) { + String name = exa.getOutputColumnName(i); + long precision = exa.getOutputColumnPrecision(i); + String thetype = exa.getOutputColumnType(i).getCanonicalName(); + String sql_type = exa.getOutputColumnSqlType(i); + long scale = exa.getOutputColumnScale(i); + long length = exa.getOutputColumnLength(i); + if (name == null) + name = "no-name"; + if (thetype == null) + thetype = "no-type"; + if (sql_type == null) + sql_type = "no-sql-type"; + ctx.emit(i + 1, name, thetype, sql_type, precision, scale, length); + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_output_type_emit() + emits (t varchar(200)) as + class GET_OUTPUT_TYPE_EMIT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(exa.getOutputType()); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_output_type_return() + returns varchar(200) as + class GET_OUTPUT_TYPE_RETURN { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getOutputType(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_precision_scale_length(n decimal(6,3), v varchar(10)) + emits (precision1 number, scale1 number, length1 number, precision2 number, scale2 number, length2 number) as + class GET_PRECISION_SCALE_LENGTH { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + long precision1 = exa.getInputColumnPrecision(0); + long scale1 = exa.getInputColumnScale(0); + long length1 = exa.getInputColumnLength(0); + long precision2 = exa.getInputColumnPrecision(1); + long scale2 = exa.getInputColumnScale(1); + long length2 = exa.getInputColumnLength(1); + ctx.emit(precision1, scale1, length1, precision2, scale2, length2); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_scope_user() returns varchar(200) as + class GET_SCOPE_USER { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getScopeUser(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_script_code() returns varchar(2000) as + class GET_SCRIPT_CODE { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getScriptCode(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_script_language() emits (s1 varchar(300), s2 varchar(300)) as + class GET_SCRIPT_LANGUAGE { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + ctx.emit(exa.getScriptLanguage(), "Java"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_script_name() returns varchar(200) as + class GET_SCRIPT_NAME { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getScriptName(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_script_schema() returns varchar(200) as + class GET_SCRIPT_SCHEMA { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getScriptSchema(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_session_id() returns varchar(200) as + class GET_SESSION_ID { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getSessionId(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_statement_id() returns number as + class GET_STATEMENT_ID { + static long run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getStatementId(); + } + } + / + ''')) + + self.query(udf.fixindent(''' + create java scalar script + get_vm_id() returns varchar(200) as + class GET_VM_ID { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return exa.getVmId(); + } + } + / + ''')) + +class MetaDataTest(_JavaUdfSetup): + + def test_database_name(self): + rows = self.query('''SELECT fn1.get_database_name() FROM DUAL''') + self.assertTrue(len(rows[0][0]) > 0) + + def test_database_version(self): + rows = self.query('''select fn1.get_database_version() from dual''') + self.assertTrue(len(rows[0][0]) > 0) + + def test_script_language(self): + rows = self.query('''select fn1.get_script_language() from dual''') + self.assertTrue((rows[0][0]).upper().startswith((rows[0][1]).upper())) + + def test_script_name(self): + rows = self.query('''select fn1.get_script_name() from dual''') + self.assertRowEqual(('GET_SCRIPT_NAME',), rows[0]) + + def test_script_schema(self): + if (udf.opts.is_compat_mode != "true"): + rows = self.query('''select fn1.get_script_schema() from dual''') + self.assertRowEqual(('FN1',), rows[0]) + + def test_script_user(self): + if (udf.opts.is_compat_mode != "true"): + rows = self.query('''select fn1.get_current_user() from dual''') + self.assertRowEqual(('SYS',), rows[0]) + + def test_scope_user(self): + if (udf.opts.is_compat_mode != "true"): + rows = self.query('''select fn1.get_scope_user() from dual''') + self.assertRowEqual(('SYS',), rows[0]) + + def test_current_schema_null(self): + if (udf.opts.is_compat_mode != "true"): + self.query('''CLOSE SCHEMA''') + rows = self.query('''select fn1.get_current_schema() from dual''') + self.assertRowEqual(('NULL',), rows[0]) + + def test_current_schema(self): + if (udf.opts.is_compat_mode != "true"): + self.query('''create schema test_schema''') + rows = self.query('''select fn1.get_current_schema() from dual''') + self.assertRowEqual(('TEST_SCHEMA',), rows[0]) + self.query('''drop schema test_schema cascade''') + + def test_script_code(self): + rows = self.query('''select fn1.get_script_code() from dual''') + self.assertTrue((rows[0][0]).upper().find('CTX') >= 0) + + def test_session_id(self): + rows = self.query('''select fn1.get_session_id() from dual''') + self.assertTrue(len(rows[0][0]) > 0) + + def test_statement_id(self): + rows = self.query('''select fn1.get_statement_id() from dual''') + self.assertTrue(rows[0][0] >= 0) + + def test_node_id(self): + rows = self.query('''select fn1.get_node_id() from dual''') + self.assertTrue(rows[0][0] >= 0) + + def test_vm_id(self): + rows = self.query('''select fn1.get_vm_id() from dual''') + self.assertTrue(len(rows[0][0]) > 0) + + def test_input_type_scalar(self): + rows = self.query('''select fn1.get_input_type_scalar() from dual''') + self.assertRowEqual(('SCALAR',), rows[0]) + + def test_input_type_set(self): + rows = self.query('''select fn1.get_input_type_set(x) from (values 1,2,3) as t(x)''') + self.assertRowEqual(('SET',), rows[0]) + + def test_input_column_count_scalar(self): + rows = self.query('''select fn1.get_input_column_count_scalar(12.3, 'hihihi') from dual''') + self.assertRowEqual((2,), rows[0]) + + + def test_input_column_count_set(self): + rows = self.query('''select fn1.get_input_column_count_set(x, y) from (values (12.3, 'hihihi')) as t(x,y)''') + self.assertRowEqual((2,), rows[0]) + + def test_input_columns(self): + rows = self.query('''select fn1.get_input_columns(1.2, '123') from dual order by column_id''') + r0 = rows[0] + r1 = rows[1] + self.assertTrue(r0[0] == 1) + self.assertTrue(r0[1].upper() == 'C1') + self.assertTrue(r0[2].upper() == 'NUMBER' or r0[2].upper() == "" or r0[2].upper() == "DOUBLE" or r0[2].upper() == "JAVA.LANG.DOUBLE" or r0[2].upper() == "") + self.assertTrue(r0[3].upper() == 'DOUBLE') + self.assertTrue(r1[0] == 2) + self.assertTrue(r1[1].upper() == 'C2') + self.assertTrue(r1[2].upper() == 'STRING' or r1[2].upper() == "" or r1[2].upper() == "CHARACTER" or r1[2].upper() == "JAVA.LANG.STRING" or r1[2].upper() == "") + self.assertTrue(r1[3].upper().startswith('VARCHAR(200)')) + self.assertTrue(r0[6] == 0) + self.assertTrue(r1[6] == 200) + + def test_output_type_return(self): + rows = self.query('''select fn1.get_output_type_return() from dual''') + self.assertTrue(rows[0][0] == 'RETURN') + + + def test_output_type_emit(self): + rows = self.query('''select fn1.get_output_type_emit() from dual''') + self.assertTrue(rows[0][0] == 'EMIT') + + + def test_output_column_count_return(self): + rows = self.query('''select fn1.get_output_column_count_return() from dual''') + self.assertRowEqual((1,),rows[0]) + + + def test_output_column_count_emit(self): + rows = self.query('''select fn1.get_output_column_count_emit() from dual''') + self.assertRowEqual((3,3,3),rows[0]) + + def test_output_columns(self): + rows = self.query('''select fn1.get_output_columns() from dual order by column_id''') + r0 = rows[0] + r1 = rows[1] + r2 = rows[2] + r3 = rows[3] + r4 = rows[4] + r5 = rows[5] + r6 = rows[6] + self.assertTrue(r0[0] == 1) + self.assertTrue(r1[0] == 2) + self.assertTrue(r2[0] == 3) + self.assertTrue(r3[0] == 4) + self.assertTrue(r4[0] == 5) + self.assertTrue(r5[0] == 6) + self.assertTrue(r6[0] == 7) + self.assertTrue(r0[1].upper() == 'COLUMN_ID') + self.assertTrue(r1[1].upper() == 'COLUMN_NAME') + self.assertTrue(r2[1].upper() == 'COLUMN_TYPE') + self.assertTrue(r3[1].upper() == 'COLUMN_SQL_TYPE') + self.assertTrue(r4[1].upper() == 'COLUMN_PRECISION') + self.assertTrue(r5[1].upper() == 'COLUMN_SCALE') + self.assertTrue(r6[1].upper() == 'COLUMN_LENGTH') + self.assertTrue(r0[2].upper() == 'NUMBER' or r0[2].upper() == "" or r0[2].upper() == "DOUBLE" or r0[2].upper() == "JAVA.LANG.DOUBLE" or r0[2].upper() == "") + self.assertTrue(r1[2].upper() == 'STRING' or r1[2].upper() == "" or r1[2].upper() == "CHARACTER" or r1[2].upper() == "JAVA.LANG.STRING" or r1[2].upper() == "") + self.assertTrue(r2[2].upper() == 'STRING' or r2[2].upper() == "" or r2[2].upper() == "CHARACTER" or r2[2].upper() == "JAVA.LANG.STRING" or r2[2].upper() == "") + self.assertTrue(r3[2].upper() == 'STRING' or r3[2].upper() == "" or r3[2].upper() == "CHARACTER" or r3[2].upper() == "JAVA.LANG.STRING" or r3[2].upper() == "") + self.assertTrue(r4[2].upper() == 'NUMBER' or r4[2].upper() == "" or r4[2].upper() == "DOUBLE" or r4[2].upper() == "JAVA.LANG.DOUBLE" or r4[2].upper() == "") + self.assertTrue(r5[2].upper() == 'NUMBER' or r5[2].upper() == "" or r5[2].upper() == "DOUBLE" or r5[2].upper() == "JAVA.LANG.DOUBLE" or r5[2].upper() == "") + self.assertTrue(r6[2].upper() == 'NUMBER' or r6[2].upper() == "" or r6[2].upper() == "DOUBLE" or r6[2].upper() == "JAVA.LANG.DOUBLE" or r6[2].upper() == "") + self.assertTrue(r0[3].upper() == 'DOUBLE') + self.assertTrue(r1[3].upper().startswith('VARCHAR(200)')) + self.assertTrue(r2[3].upper().startswith('VARCHAR(20)')) + self.assertTrue(r3[3].upper().startswith('VARCHAR(20)')) + self.assertTrue(r4[3].upper() == 'DOUBLE') + self.assertTrue(r5[3].upper() == 'DOUBLE') + self.assertTrue(r6[3].upper() == 'DOUBLE') + self.assertTrue(r1[6] == 200) + self.assertTrue(r2[6] == 20) + self.assertTrue(r3[6] == 20) + + + + def test_precision_scale_length(self): + rows = self.query('''select fn1.get_precision_scale_length(2.5, '0123456789') from dual''') + self.assertRowEqual((6,3,0,0,0,10), rows[0]) + + + def test_char_length(self): + rows = self.query('''select fn1.get_char_length('0123456789') from dual''') + self.assertRowEqual((10,20,'9876543210 '), (int(rows[0][0]), int(rows[0][1]), rows[0][2])) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/numeric_functions.py b/test_container/tests/test/generic/java/numeric_functions.py new file mode 100755 index 000000000..a8663e429 --- /dev/null +++ b/test_container/tests/test/generic/java/numeric_functions.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + add_three_doubles(x DOUBLE, y DOUBLE, z DOUBLE) + RETURNS DOUBLE AS + class ADD_THREE_DOUBLES { + static Double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDouble("x") != null && ctx.getDouble("y") != null && ctx.getDouble("z") != null) + return (double) ctx.getDouble("x") + (double) ctx.getDouble("y") + (double) ctx.getDouble("z"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT add_two_doubles(x DOUBLE, y DOUBLE) RETURNS DOUBLE AS + class ADD_TWO_DOUBLES { + static Double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDouble("x") != null && ctx.getDouble("y") != null) + return (double) ctx.getDouble("x") + (double) ctx.getDouble("y"); + return null; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + double_mult("x" double, "y" double) + RETURNS double AS + class DOUBLE_MULT { + static Double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getDouble("x") == null || ctx.getDouble("y") == null) + return null; + else + return (double) ctx.getDouble("x") * (double) ctx.getDouble("y"); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + pi() + RETURNS double AS + class PI { + static double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return Math.PI; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + split_integer_into_digits("x" INTEGER) + EMITS (y INTEGER) AS + class SPLIT_INTEGER_INTO_DIGITS { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getInteger("x") != null) { + int y = Math.abs(ctx.getInteger("x")); + while (y > 0) { + ctx.emit(y % 10); + y /= 10; + } + } + } + } + / + ''')) + +class Test(_JavaUdfSetup): + def test_pi(self): + rows = self.query(''' + SELECT fn1.pi() + FROM dual''') + result = rows[0][0] + self.assertAlmostEqual(3.1415926535, result) + + def test_select(self): + rows = self.query(''' + SELECT DISTINCT + FN1.double_mult(float1, float2) = float1 * float2 AS a + FROM test.enginetablebig1 + ORDER BY a + ''') + self.assertRowsEqual([(True,), (None,)], rows) + + def test_select_into(self): + self.query('DROP SCHEMA FN2 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN2') + self.query('CREATE TABLE FN2.t(diff double)') + self.query(''' + INSERT INTO FN2.t + SELECT + fn1.double_mult(float1, float2) - float1 * float2 AS a + FROM test.enginetable + ''') + self.query(''' + SELECT DISTINCT diff + FROM FN2.t + WHERE diff != 0 AND diff IS NOT NULL + ''') + self.assertEqual(0, self.rowcount()) + + def test_subselect(self): + rows = self.query(''' + SELECT i, a + FROM ( + SELECT int_index AS i, + (fn1.double_mult(float1, float2) - float1 * float2) AS a + FROM test.enginetable) + WHERE a IS NOT NULL + ORDER BY a + LIMIT 20''') + for row in rows: + rows2 = self.query(''' + SELECT + float1, + float2, + fn1.double_mult(float1, float2) - float1 * float2 AS a + FROM test.enginetable + WHERE int_index = ?''', + row.I) + self.assertEqual(row.A, rows2[0].A) + + def test_udf_with_two_doubles(self): + rows = self.query(''' + SELECT + fn1.add_two_doubles(NULL, NULL) IS NULL, + fn1.add_two_doubles(NULL, 0) IS NULL, + fn1.add_two_doubles( 0, NULL) IS NULL, + fn1.add_two_doubles(0,0) = 0, + fn1.add_two_doubles(1,0) = 1, + fn1.add_two_doubles(0,2) = 2, + fn1.add_two_doubles(2,3) = 5 + FROM DUAL''') + self.assertRowsEqual([tuple([True] * 7)], rows) + + def test_udf_with_three_doubles_part1(self): + rows = self.query(''' + SELECT + fn1.add_three_doubles(NULL, NULL, NULL) is NULL, + fn1.add_three_doubles(NULL, NULL, 0) is NULL, + fn1.add_three_doubles(NULL, 0, NULL) is NULL, + fn1.add_three_doubles( 0, NULL, NULL) is NULL, + fn1.add_three_doubles(NULL, 0, 0) is NULL + FROM DUAL''') + self.assertRowsEqual([tuple([True] * 5)], rows) + + def test_udf_with_three_doubles_part2(self): + rows = self.query(''' + SELECT + fn1.add_three_doubles( 0, NULL, 0) is NULL, + fn1.add_three_doubles( 0, 0, NULL) is NULL, + fn1.add_three_doubles(0, 0, 0) = 0, + fn1.add_three_doubles(1, 0, 0) = 1, + fn1.add_three_doubles(0, 2, 0) = 2 + FROM DUAL''') + self.assertRowsEqual([tuple([True] * 5)], rows) + + def test_udf_with_three_doubles_part3(self): + rows = self.query(''' + SELECT + fn1.add_three_doubles(0, 0, 3) = 3, + fn1.add_three_doubles(1, 2, 0) = 3, + fn1.add_three_doubles(1, 0, 3) = 4, + fn1.add_three_doubles(0, 2, 3) = 5, + fn1.add_three_doubles(1, 2, 3) = 6 + FROM DUAL''') + self.assertRowsEqual([tuple([True] * 5)], rows) + + def test_right_number_of_emitted_rows(self): + rows = self.query(''' + SELECT fn1.split_integer_into_digits(123) + FROM DUAL''') + self.assertRowsEqual([(3,), (2,), (1,)], rows) + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/pathological_functions.py b/test_container/tests/test/generic/java/pathological_functions.py new file mode 100755 index 000000000..522470c3c --- /dev/null +++ b/test_container/tests/test/generic/java/pathological_functions.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf + + +class Test(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + sleep("sec" double) + RETURNS double AS + class SLEEP { + static double run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int sec = ctx.getInteger("sec"); + Thread.sleep(sec * 1000); + return sec; + } + } + / + ''')) + + def test_query_timeout(self): + self.query('ALTER SESSION SET QUERY_TIMEOUT = 10') + try: + with self.assertRaisesRegex(Exception, 'Successfully reconnected after query timeout'): + self.query('SELECT fn1.sleep(100) FROM dual') + finally: + self.query('ALTER SESSION SET QUERY_TIMEOUT = 0') + + +if __name__ == '__main__': + udf.main() diff --git a/test_container/tests/test/generic/java/unicode.py b/test_container/tests/test/generic/java/unicode.py new file mode 100755 index 000000000..92949828c --- /dev/null +++ b/test_container/tests/test/generic/java/unicode.py @@ -0,0 +1,333 @@ +#!/usr/bin/env python3 + +from exasol_python_test_framework import udf +from exasol_python_test_framework.udf import useData + + +class _JavaUdfSetup(udf.TestCase): + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + unicode_count(word VARCHAR(1000), convert_ INT) + EMITS (uchar VARCHAR(1), count INT) AS + import java.util.Map; + import java.util.HashMap; + import java.util.Set; + import java.util.Iterator; + class UNICODE_COUNT { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String s = ctx.getString("word"); + if (s == null) + return; + if (ctx.getInteger("convert_") > 0) + s = s.toUpperCase(); + else if (ctx.getInteger("convert_") < 0) + s = s.toLowerCase(); + + Map count = new HashMap(); + for (int i = 0; i < s.length(); i++) { + Integer codepoint = s.codePointAt(i); + Integer num = count.get(codepoint); + count.put(codepoint, (num == null ? 1 : num + 1)); + if (Character.isHighSurrogate(s.charAt(i))) + i++; + } + Iterator> iter = count.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry item = iter.next(); + ctx.emit(new String(Character.toChars(item.getKey())), item.getValue()); + } + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + unicode_len(word VARCHAR(1000)) + RETURNS INT AS + class UNICODE_LEN { + static int run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String s = ctx.getString("word"); + return (s == null) ? 0 : s.codePointCount(0, s.length()); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + unicode_upper(word VARCHAR(1000)) + RETURNS VARCHAR(1000) AS + class UNICODE_UPPER { + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + String s = ctx.getString("word"); + return (s == null) ? null : s.toUpperCase(); + } + } + / + ''')) + +# coding: utf-8 + +import csv +import locale +import logging +import os +import subprocess +import sys +import tempfile +import unicodedata +import re +import argparse + +from exasol_python_test_framework import udf + +udf.pythonVersionInUdf = -1 +from exasol_python_test_framework.exatest.testcase import skipIf + + +locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') + + +def getPythonVersionInUDFs(server, script_languages): + log = logging.getLogger('unicodedata') + log.info("trying to figure out python version of python in UDFs") + sql = udf.fixindent(''' + alter session set script_languages='%(sl)s'; + drop schema if exists pyversion_schema cascade; + create schema pyversion_schema; + create or replace python3 scalar script pyversion_schema.python_version() returns varchar(1000) as + import sys + def run(ctx): + return 'Python='+str(sys.version_info[0]) + / + select pyversion_schema.python_version(); + ''' % {'sl': script_languages}) + cmd = '''%(exaplus)s -c %(conn)s -u sys -P exasol + -no-config -autocommit ON -L -pipe -jdbcparam validateservercertificate=0''' % { + 'exaplus': os.environ.get('EXAPLUS', + '/usr/opt/EXASuite-4/EXASolution-4.2.9/bin/Console/exaplus'), + 'conn': server + } + env = os.environ.copy() + # env['PATH'] = '/usr/opt/jdk1.8.0_latest/bin:' + env['PATH'] + exaplus = subprocess.Popen( + cmd.split(), + env=env, + + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, _err = exaplus.communicate(sql.encode('utf-8')) + pythonVersionInUdf = -1 + for line in out.strip().decode('utf-8').split(sep="\n"): + m = re.search(r'Python=(\d)', line) + if m: + pythonVersionInUdf = int(m.group(1)) + continue + + if pythonVersionInUdf not in [2, 3]: + print('cannot set pythonVersionInUdf: %s' % pythonVersionInUdf) + sys.exit(1) + + return pythonVersionInUdf + + +def setUpModule(): + log = logging.getLogger('unicodedata') + + log.info('generating unicodedata CSV') + with tempfile.NamedTemporaryFile(prefix='unicode-', suffix='.csv', encoding='utf-8', mode='w+', + delete=False) as csvfile: + c = csv.writer(csvfile, quoting=csv.QUOTE_ALL) + for i in range(sys.maxunicode + 1): + if i >= 5024 and i <= 5119: + continue # the Unicode Cherokee-Block is broken in Python 2.7 and Python 3.4 (maybe also 3.5) + u = chr(i) + if unicodedata.category(u).startswith('C'): + # [Cc]Other, Control + # [Cf]Other, Format + # [Cn]Other, Not Assigned + # [Co]Other, Private Use + # [Cs]Other, Surrogate + continue + row = (i, # INT 0-1114111 + unicodedata.name(u, 'UNICODE U+%08X' % i), # VARCHAR(100) ASCII + u, # VARCHAR(1) UNICODE + u.upper(), # VARCHAR(1) UNICODE + u.lower(), # VARCHAR(1) UNICODE + unicodedata.decimal(u, None), # INT + unicodedata.numeric(u, None), # DOUBLE + unicodedata.category(u), # VARCHAR(3) ASCII + unicodedata.bidirectional(u), # VARCHAR(3) ASCII + unicodedata.combining(u), # VARCHAR(3) ASCII + unicodedata.east_asian_width(u), # VARCHAR(1) ASCII + bool(unicodedata.mirrored), # BOOLEAN + unicodedata.decomposition(u), # VARCHAR(10) ASCII + unicodedata.normalize('NFC', u), # VARCHAR(3) UNICODE + unicodedata.normalize('NFD', u), # VARCHAR(3) UNICODE + unicodedata.normalize('NFKC', u), # VARCHAR(3) UNICODE + unicodedata.normalize('NFKD', u), # VARCHAR(3) UNICODE + ) + c.writerow(row) + csvfile.flush() + + log.info('loading CSV') + sql = ''' + DROP SCHEMA utest CASCADE; + CREATE SCHEMA utest; + CREATE TABLE utest.unicodedata ( + codepoint INT NOT NULL, + name VARCHAR(100) ASCII, + uchar VARCHAR(1) UTF8, + to_upper VARCHAR(1) UTF8, + to_lower VARCHAR(1) UTF8, + decimal_value INT, + numeric_value INT, + category VARCHAR(3) ASCII, + bidirectional VARCHAR(3) ASCII, + combining VARCHAR(10) ASCII, + east_asian_width VARCHAR(2) ASCII, mirrored BOOLEAN, + decomposition VARCHAR(100) ASCII, + NFC VARCHAR(10) UTF8, + NFD VARCHAR(10) UTF8, + NFKC VARCHAR(20) UTF8, + NFKD VARCHAR(20) UTF8 + ); + IMPORT INTO utest.unicodedata + FROM LOCAL CSV FILE '%s' + ROW SEPARATOR = 'CRLF'; + ''' % os.path.join(os.getcwd(), csvfile.name) + cmd = '''%(exaplus)s -c %(conn)s -u sys -P exasol + -no-config -autocommit ON -L -pipe -jdbcparam validateservercertificate=0''' % { + 'exaplus': os.environ.get('EXAPLUS', + '/usr/opt/EXASuite-4/EXASolution-4.2.9/bin/Console/exaplus'), + 'conn': udf.opts.server + } + env = os.environ.copy() + env['PATH'] = '/usr/opt/jdk1.8.0_latest/bin:' + env['PATH'] + exaplus = subprocess.Popen( + cmd.split(), + env=env, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, _err = exaplus.communicate(sql.encode('utf-8')) + if exaplus.returncode != 0 or _err is not None: + log.critical('EXAplus error: %d', exaplus.returncode) + log.error(out) + else: + log.debug(out) + + +def add_uniname(data): + return [(n, unicodedata.name(chr(n), 'U+%04X' % n)) + for n in data] + + +class Unicode(_JavaUdfSetup): + + def query_unicode_char(self, u): + rows = self.query(''' + SELECT count, unicode(uchar) AS u + FROM ( + SELECT fn1.unicode_count(unicodechr(%d), 0) + FROM dual) + ''' % u) + self.assertEqual(1, self.rowcount()) + self.assertEqual(1, rows[0].COUNT) + self.assertEqual(u, rows[0].U) + + data = add_uniname(( + 65, + 255, + 382, + 65279, + 63882, + 65534, + 66432, + 173746, + 1114111, + )) + + @useData(data) + def test_unicode(self, codepoint, _name): + self.query_unicode_char(codepoint) + + def test_unicode_count(self): + self.maxDiff = 1024 + rows = self.query(''' + SELECT + c1_integer AS i, + len(c2_varchar100) AS len_exa, + fn1.unicode_len(c2_varchar100) AS len + FROM test.enginetablebigunicodevarchar + WHERE len(c2_varchar100) != fn1.unicode_len(c2_varchar100) + ORDER BY c1_integer + LIMIT 100 + ''') + self.assertRowsEqual([], rows) + + +class UnicodeData(_JavaUdfSetup): + + # @udf.TestCase.expectedFailureIfLang('lua') + def test_unicode_upper_is_subset_of_Unicode520_part2(self): + """DWA-13388 (Lua); DWA-13702 (Lua)""" + rows = self.query(''' + SELECT + codepoint, + name, + unicode(to_upper), + unicode(fn1.unicode_upper(uchar)) + FROM utest.unicodedata + WHERE codepoint in (181, 8126) + and (to_upper != fn1.unicode_upper(uchar)) + and (uchar != fn1.unicode_upper(uchar)) + ORDER BY codepoint + LIMIT 50 + ''') + self.assertRowsEqual([], rows) + + @udf.TestCase.expectedFailureIfLang('lua') + def test_unicode_upper_is_subset_of_Unicode520_part3(self): + """DWA-13388 (Lua); DWA-13702 (Lua); DWA-13782 (R)""" + rows = self.query(''' + SELECT + codepoint, + name, + unicode(to_upper), + unicode(fn1.unicode_upper(uchar)) + FROM utest.unicodedata + WHERE codepoint in (1010) + and (to_upper != fn1.unicode_upper(uchar)) + and (uchar != fn1.unicode_upper(uchar)) + ORDER BY codepoint + LIMIT 50 + ''') + self.assertRowsEqual([], rows) + + def test_unicode_len(self): + rows = self.query(''' + SELECT codepoint, name + FROM utest.unicodedata + WHERE codepoint not between 55296 and 57343 + and len(uchar) != fn1.unicode_len(uchar) + ORDER BY codepoint + LIMIT 100 + ''') + self.assertRowsEqual([], rows) + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--server', help='connection string') + parser.add_argument('--script-languages', help='definition of the SCRIPT_LANGUAGES variable') + opts, _unknown = parser.parse_known_args() + setattr(udf, 'pythonVersionInUdf', getPythonVersionInUDFs(opts.server, opts.script_languages)) + udf.main() diff --git a/test_container/tests/test/generic/java/vectorsize.py b/test_container/tests/test/generic/java/vectorsize.py new file mode 100755 index 000000000..8e6ca6792 --- /dev/null +++ b/test_container/tests/test/generic/java/vectorsize.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 + +import sys + +from exasol_python_test_framework import udf +from exasol_python_test_framework.udf import useData + + +class _JavaUdfSetup(udf.TestCase): + LANG = 'java' + def setUp(self): + self.query('DROP SCHEMA FN1 CASCADE', ignore_errors=True) + self.query('CREATE SCHEMA FN1') + self.query('OPEN SCHEMA FN1') + self.query(udf.fixindent(''' + CREATE java SCALAR SCRIPT + basic_range(n INTEGER) + EMITS (n INTEGER) AS + class BASIC_RANGE { + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + if (ctx.getInteger("n") != null) + for (int i = 0; i < ctx.getInteger("n"); i++) + ctx.emit(i); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + vectorsize(length DOUBLE, dummy DOUBLE) + RETURNS VARCHAR(2000000) AS + import java.util.Map; + import java.util.HashMap; + + class VECTORSIZE { + static Map cache = new HashMap(); + + static void fillCache(int len) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append(Integer.toString(i)); + } + cache.put(len, sb.toString()); + } + + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int len = ctx.getInteger("length"); + if (!cache.containsKey(len)) + fillCache(len); + return cache.get(len); + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT vectorsize5000(A DOUBLE) + RETURNS VARCHAR(2000000) AS + class VECTORSIZE5000 { + static String numbers; + + static { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5000; i++) { + sb.append(Integer.toString(i)); + } + numbers = sb.toString(); + } + + static String run(ExaMetadata exa, ExaIterator ctx) throws Exception { + return numbers; + } + } + / + ''')) + + self.query(udf.fixindent(''' + CREATE JAVA SCALAR SCRIPT + vectorsize_set(length DOUBLE, n DOUBLE, dummy DOUBLE) + EMITS (o VARCHAR(2000000)) AS + import java.util.Map; + import java.util.HashMap; + + class VECTORSIZE_SET { + static Map cache = new HashMap(); + + static void fillCache(int len) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i++) { + sb.append(Integer.toString(i)); + } + cache.put(len, sb.toString()); + } + + static void run(ExaMetadata exa, ExaIterator ctx) throws Exception { + int len = ctx.getInteger("length"); + if (!cache.containsKey(len)) + fillCache(len); + int n = ctx.getInteger("n"); + for (int i = 0; i < n; i++) { + ctx.emit(cache.get(len)); + } + } + } + / + ''')) + +class Vectorsize(_JavaUdfSetup): + + def test_vectorsize_5000(self): + self.query(''' + SELECT max(fn1.vectorsize5000(float1)) + FROM TEST.ENGINETABLEBIG1''') + + data = [ + (10,), + (30,), + (100,), + (300,), + (1000,), + (3000,), + (10000,), + (30000,), + (100000,), + (200000,), + (351850,), + ] + + @useData(data) + def test_vectorsize(self, size): + limits = { + 'lua': 100000, + 'python3': 8000, + 'r': 3000, + 'java': 3000 + } + if size > limits.get(self.LANG, sys.maxsize): + raise udf.SkipTest('test is to slow') + + self.query(''' + SELECT max(fn1.vectorsize(%d, float1)) + FROM TEST.ENGINETABLEBIG1 + ''' % size) + + data = [ + (10, 10, 10), + (100, 100, 100), + (1000, 100, 100), + (10000, 100, 100), + (100000, 100, 100), + (351850, 100, 100), + (100, 10, 100000), + (100, 100, 10000), + (100, 1000, 1000), + (100, 10000, 100), + (100, 100000, 10), + ] + + @useData(data) + def test_vectorsize_set(self, a, b, c): + q = ''' + SELECT max(o) + FROM ( + SELECT fn1.vectorsize_set(%d, %d, n) + FROM ( + SELECT fn1.basic_range(%d) + FROM DUAL + ) + ) + ''' % (a, b, c) + self.query(q) + + +if __name__ == '__main__': + udf.main()