| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.drill.exec.store.json; |
| |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.nio.file.Paths; |
| |
| import org.apache.drill.categories.RowSetTest; |
| import org.apache.drill.categories.UnlikelyTest; |
| import org.apache.drill.common.exceptions.UserException; |
| import org.apache.drill.exec.ExecConstants; |
| import org.apache.drill.exec.proto.UserBitShared; |
| import org.apache.drill.test.BaseTestQuery; |
| import org.junit.Assert; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| /** |
| * Original JSON reader tests. Left in original form; not converted |
| * to the newer formats. |
| */ |
| @Category(RowSetTest.class) |
| public class TestJsonRecordReader extends BaseTestQuery { |
| |
| @BeforeClass |
| public static void setupTestFiles() { |
| dirTestWatcher.copyResourceToRoot(Paths.get("jsoninput/drill_3353")); |
| } |
| |
| private void enableV2Reader(boolean enable) throws Exception { |
| alterSession(ExecConstants.ENABLE_V2_JSON_READER_KEY, enable); |
| } |
| |
| private void resetV2Reader() throws Exception { |
| resetSessionOption(ExecConstants.ENABLE_V2_JSON_READER_KEY); |
| } |
| |
| public interface TestWrapper { |
| void apply() throws Exception; |
| } |
| |
| public void runBoth(TestWrapper wrapper) throws Exception { |
| try { |
| enableV2Reader(false); |
| wrapper.apply(); |
| enableV2Reader(true); |
| wrapper.apply(); |
| } finally { |
| resetV2Reader(); |
| } |
| } |
| |
| @Test |
| public void testComplexJsonInput() throws Exception { |
| runBoth(this::doTestComplexJsonInput); |
| } |
| |
| private void doTestComplexJsonInput() throws Exception { |
| test("select `integer`, x['y'] as x1, x['y'] as x2, z[0], z[0]['orange'], z[1]['pink'] from cp.`jsoninput/input2.json` limit 10 "); |
| } |
| |
| @Test |
| public void testDateJsonInput() throws Exception { |
| test("select `date`, AGE(`date`, CAST('2019-09-30 20:47:43' as timestamp)) from cp.`jsoninput/input2.json` limit 10 "); |
| } |
| |
| @Test |
| public void testContainingArray() throws Exception { |
| runBoth(this::doTestContainingArray); |
| } |
| |
| private void doTestContainingArray() throws Exception { |
| test("select * from cp.`store/json/listdoc.json`"); |
| } |
| |
| @Test |
| public void testComplexMultipleTimes() throws Exception { |
| runBoth(this::doTestComplexMultipleTimes); |
| } |
| |
| private void doTestComplexMultipleTimes() throws Exception { |
| for (int i = 0; i < 5; i++) { |
| test("select * from cp.`join/merge_join.json`"); |
| } |
| } |
| |
| @Test |
| public void trySimpleQueryWithLimit() throws Exception { |
| runBoth(this::doTrySimpleQueryWithLimit); |
| } |
| |
| private void doTrySimpleQueryWithLimit() throws Exception { |
| test("select * from cp.`limit/test1.json` limit 10"); |
| } |
| |
| @Test |
| // DRILL-1634 : retrieve an element in a nested array in a repeated map. |
| // RepeatedMap (Repeated List (Repeated varchar)) |
| public void testNestedArrayInRepeatedMap() throws Exception { |
| runBoth(() -> doTestNestedArrayInRepeatedMap()); |
| } |
| |
| private void doTestNestedArrayInRepeatedMap() throws Exception { |
| test("select a[0].b[0] from cp.`jsoninput/nestedArray.json`"); |
| test("select a[0].b[1] from cp.`jsoninput/nestedArray.json`"); |
| test("select a[1].b[1] from cp.`jsoninput/nestedArray.json`"); // index out of the range. Should return empty list. |
| } |
| |
| @Test |
| public void testEmptyMapDoesNotFailValueCapacityCheck() throws Exception { |
| runBoth(() -> doTestEmptyMapDoesNotFailValueCapacityCheck()); |
| } |
| |
| private void doTestEmptyMapDoesNotFailValueCapacityCheck() throws Exception { |
| final String sql = "select * from cp.`store/json/value-capacity.json`"; |
| test(sql); |
| } |
| |
| @Test |
| public void testEnableAllTextMode() throws Exception { |
| runBoth(() -> doTestEnableAllTextMode()); |
| } |
| |
| private void doTestEnableAllTextMode() throws Exception { |
| alterSession(ExecConstants.JSON_ALL_TEXT_MODE, true); |
| test("select * from cp.`jsoninput/big_numeric.json`"); |
| resetSessionOption(ExecConstants.JSON_ALL_TEXT_MODE); |
| } |
| |
| @Test |
| public void testExceptionHandling() throws Exception { |
| runBoth(this::doTestExceptionHandling); |
| } |
| |
| private void doTestExceptionHandling() throws Exception { |
| try { |
| test("select * from cp.`jsoninput/DRILL-2350.json`"); |
| } catch (UserException e) { |
| Assert.assertEquals( |
| UserBitShared.DrillPBError.ErrorType.UNSUPPORTED_OPERATION, e |
| .getOrCreatePBError(false).getErrorType()); |
| String s = e.getMessage(); |
| assertTrue("Expected Unsupported Operation Exception.", |
| s.contains("Drill does not support lists of different types.")); |
| } |
| |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // DRILL-1832 |
| public void testJsonWithNulls1() throws Exception { |
| runBoth(() -> doTestJsonWithNulls1()); |
| } |
| |
| private void doTestJsonWithNulls1() throws Exception { |
| final String query = "select * from cp.`jsoninput/twitter_43.json`"; |
| testBuilder().sqlQuery(query).unOrdered() |
| .jsonBaselineFile("jsoninput/drill-1832-1-result.json").go(); |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // DRILL-1832 |
| public void testJsonWithNulls2() throws Exception { |
| runBoth(() -> doTestJsonWithNulls2()); |
| } |
| |
| private void doTestJsonWithNulls2() throws Exception { |
| final String query = "select SUM(1) as `sum_Number_of_Records_ok` from cp.`jsoninput/twitter_43.json` having (COUNT(1) > 0)"; |
| testBuilder().sqlQuery(query).unOrdered() |
| .jsonBaselineFile("jsoninput/drill-1832-2-result.json").go(); |
| } |
| |
| // V1-only test. In V2, this works. See TestJsonReaderQueries. |
| |
| @Test |
| public void testMixedNumberTypes() throws Exception { |
| try { |
| enableV2Reader(false); |
| testBuilder() |
| .sqlQuery("select * from cp.`jsoninput/mixed_number_types.json`") |
| .unOrdered().jsonBaselineFile("jsoninput/mixed_number_types.json") |
| .build().run(); |
| fail("Mixed number types verification failed, expected failure on conflicting number types."); |
| } catch (Exception ex) { |
| // this indicates successful completion of the test |
| assertTrue(ex |
| .getMessage() |
| .contains( |
| "You tried to write a BigInt type when you are using a ValueWriter of type NullableFloat8WriterImpl.")); |
| } finally { |
| resetV2Reader(); |
| } |
| } |
| |
| @Test |
| public void testMixedNumberTypesInAllTextMode() throws Exception { |
| runBoth(() -> doTestMixedNumberTypesInAllTextMode()); |
| } |
| |
| private void doTestMixedNumberTypesInAllTextMode() throws Exception { |
| try { |
| alterSession("store.json.all_text_mode", true); |
| testBuilder() |
| .sqlQuery("select * from cp.`jsoninput/mixed_number_types.json`") |
| .unOrdered().baselineColumns("a").baselineValues("5.2") |
| .baselineValues("6").build().run(); |
| } finally { |
| resetSessionOption("store.json.all_text_mode"); |
| } |
| } |
| |
| @Test |
| public void testMixedNumberTypesWhenReadingNumbersAsDouble() throws Exception { |
| try { |
| alterSession(ExecConstants.JSON_READ_NUMBERS_AS_DOUBLE, true); |
| testBuilder() |
| .sqlQuery("select * from cp.`jsoninput/mixed_number_types.json`") |
| .unOrdered().baselineColumns("a").baselineValues(5.2D) |
| .baselineValues(6D).build().run(); |
| } finally { |
| resetSessionOption(ExecConstants.JSON_READ_NUMBERS_AS_DOUBLE); |
| } |
| } |
| |
| @Test |
| public void drill_3353() throws Exception { |
| try { |
| alterSession(ExecConstants.JSON_ALL_TEXT_MODE, true); |
| test("create table dfs.tmp.drill_3353 as select a from dfs.`jsoninput/drill_3353` where e = true"); |
| runBoth(this::doDrill_3353); |
| } finally { |
| resetSessionOption(ExecConstants.JSON_ALL_TEXT_MODE); |
| } |
| } |
| |
| private void doDrill_3353() throws Exception { |
| String query = "select t.a.d cnt from dfs.tmp.drill_3353 t where t.a.d is not null"; |
| test(query); |
| testBuilder() |
| .sqlQuery(query) |
| .unOrdered() |
| .baselineColumns("cnt") |
| .baselineValues("1") |
| .go(); |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // See DRILL-3476 |
| public void testNestedFilter() throws Exception { |
| runBoth(this::doTestNestedFilter); |
| } |
| |
| private void doTestNestedFilter() throws Exception { |
| String query = "select a from cp.`jsoninput/nestedFilter.json` t where t.a.b = 1"; |
| String baselineQuery = "select * from cp.`jsoninput/nestedFilter.json` t where t.a.b = 1"; |
| testBuilder().sqlQuery(query).unOrdered().sqlBaselineQuery(baselineQuery) |
| .go(); |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // See DRILL-4653 |
| /* Test for CountingJSONReader */ |
| public void testCountingQuerySkippingInvalidJSONRecords() throws Exception { |
| try { |
| String set = "alter session set `" |
| + ExecConstants.JSON_READER_SKIP_INVALID_RECORDS_FLAG + "` = true"; |
| String set1 = "alter session set `" |
| + ExecConstants.JSON_READER_PRINT_INVALID_RECORDS_LINE_NOS_FLAG |
| + "` = true"; |
| String query = "select count(*) from cp.`jsoninput/drill4653/file.json`"; |
| |
| testNoResult(set); |
| testNoResult(set1); |
| testBuilder() |
| .unOrdered() |
| .sqlQuery(query) |
| .sqlBaselineQuery(query) |
| .go(); |
| } finally { |
| String set = "alter session set `" |
| + ExecConstants.JSON_READER_SKIP_INVALID_RECORDS_FLAG + "` = false"; |
| testNoResult(set); |
| } |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // See DRILL-4653 |
| /* Test for CountingJSONReader */ |
| public void testCountingQueryNotSkippingInvalidJSONRecords() throws Exception { |
| runBoth(this::doTestCountingQueryNotSkippingInvalidJSONRecords); |
| } |
| |
| private void doTestCountingQueryNotSkippingInvalidJSONRecords() throws Exception { |
| try { |
| String query = "select count(*) from cp.`jsoninput/drill4653/file.json`"; |
| testBuilder().unOrdered().sqlQuery(query).sqlBaselineQuery(query).build() |
| .run(); |
| } catch (Exception ex) { |
| // do nothing just return |
| return; |
| } |
| throw new Exception("testCountingQueryNotSkippingInvalidJSONRecords"); |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // See DRILL-4653 |
| /* Test for JSONReader */ |
| public void testNotCountingQuerySkippingInvalidJSONRecords() throws Exception { |
| try { |
| String set = "alter session set `" |
| + ExecConstants.JSON_READER_SKIP_INVALID_RECORDS_FLAG + "` = true"; |
| String set1 = "alter session set `" |
| + ExecConstants.JSON_READER_PRINT_INVALID_RECORDS_LINE_NOS_FLAG |
| + "` = true"; |
| String query = "select sum(balance) from cp.`jsoninput/drill4653/file.json`"; |
| testNoResult(set); |
| testNoResult(set1); |
| testBuilder() |
| .unOrdered() |
| .sqlQuery(query) |
| .sqlBaselineQuery(query) |
| .go(); |
| } |
| finally { |
| String set = "alter session set `" |
| + ExecConstants.JSON_READER_SKIP_INVALID_RECORDS_FLAG + "` = false"; |
| testNoResult(set); |
| } |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // See DRILL-4653 |
| /* Test for JSONReader */ |
| public void testNotCountingQueryNotSkippingInvalidJSONRecords() |
| throws Exception { |
| runBoth(this::doTestNotCountingQueryNotSkippingInvalidJSONRecords); |
| } |
| |
| private void doTestNotCountingQueryNotSkippingInvalidJSONRecords() throws Exception { |
| try { |
| String query = "select sum(balance) from cp.`jsoninput/drill4653/file.json`"; |
| testBuilder().unOrdered().sqlQuery(query).sqlBaselineQuery(query).build() |
| .run(); |
| } catch (Exception ex) { |
| // do nothing just return |
| return; |
| } |
| throw new Exception("testNotCountingQueryNotSkippingInvalidJSONRecords"); |
| } |
| |
| @Test |
| @Category(UnlikelyTest.class) |
| // See DRILL-7362 |
| /* Test for CountingJSONReader */ |
| public void testContainingArrayCount() throws Exception { |
| runBoth(this::doTestContainingArrayCount); |
| } |
| |
| private void doTestContainingArrayCount() throws Exception { |
| testBuilder() |
| .sqlQuery("select count(*) as cnt from cp.`store/json/listdoc.json`") |
| .unOrdered() |
| .baselineColumns("cnt") |
| .baselineValues(2L) |
| .go(); |
| } |
| } |