|
31 | 31 | import static org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TenantViewOptions; |
32 | 32 | import static org.apache.phoenix.util.PhoenixRuntime.TENANT_ID_ATTRIB; |
33 | 33 | import static org.junit.Assert.assertEquals; |
| 34 | +import static org.junit.Assert.assertFalse; |
| 35 | +import static org.junit.Assert.assertTrue; |
34 | 36 |
|
35 | 37 | import java.io.IOException; |
36 | 38 | import java.sql.Connection; |
37 | 39 | import java.sql.DriverManager; |
| 40 | +import java.sql.PreparedStatement; |
| 41 | +import java.sql.ResultSet; |
38 | 42 | import java.sql.SQLException; |
39 | 43 | import java.util.List; |
40 | 44 | import java.util.Random; |
|
46 | 50 | import org.apache.hadoop.hbase.client.Scan; |
47 | 51 | import org.apache.hadoop.hbase.client.Table; |
48 | 52 | import org.apache.hadoop.hbase.util.Bytes; |
| 53 | +import org.apache.phoenix.jdbc.PhoenixResultSet; |
49 | 54 | import org.apache.phoenix.query.PhoenixTestBuilder.BasicDataWriter; |
50 | 55 | import org.apache.phoenix.query.PhoenixTestBuilder.DataSupplier; |
51 | 56 | import org.apache.phoenix.query.PhoenixTestBuilder.DataWriter; |
52 | 57 | import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder; |
53 | 58 | import org.apache.phoenix.query.QueryConstants; |
54 | 59 | import org.apache.phoenix.schema.PTable; |
| 60 | +import org.apache.phoenix.util.EnvironmentEdgeManager; |
55 | 61 | import org.apache.phoenix.util.IndexUtil; |
| 62 | +import org.apache.phoenix.util.ManualEnvironmentEdge; |
| 63 | +import org.apache.phoenix.util.QueryUtil; |
56 | 64 | import org.apache.phoenix.util.SchemaUtil; |
57 | 65 | import org.apache.phoenix.util.TestUtil; |
58 | 66 | import org.junit.Ignore; |
@@ -703,6 +711,55 @@ public List<Object> getValues(int rowIndex) { |
703 | 711 | } |
704 | 712 | } |
705 | 713 |
|
| 714 | + /** |
| 715 | + * Test that the empty column cell is returned by the scan when there is a DistinctPrefixFilter |
| 716 | + * and an EmptyColumnOnlyFilter. If there is no empty column cell returned in the scan then TTL |
| 717 | + * masking logic can break. |
| 718 | + */ |
| 719 | + @Test |
| 720 | + public void testMaskingWithDistinctPrefixFilter() throws Exception { |
| 721 | + try (Connection conn = DriverManager.getConnection(getUrl())) { |
| 722 | + int ttl = 10; |
| 723 | + String dataTableName = generateUniqueName(); |
| 724 | + // not using column encoding so that we use EmptyColumnOnlyFilter |
| 725 | + String ddl = "create table " + dataTableName + " (id1 varchar(10) not null , " |
| 726 | + + "id2 varchar(10) not null , val1 varchar(10), val2 varchar(10) " |
| 727 | + + "constraint PK primary key (id1, id2)) COLUMN_ENCODED_BYTES=0, TTL=" + ttl; |
| 728 | + conn.createStatement().execute(ddl); |
| 729 | + |
| 730 | + String[] expectedValues = { "val1_1", "val1_2", "val1_3", "val1_4" }; |
| 731 | + String dml = "UPSERT INTO " + dataTableName + " VALUES(?, ?, ?, ?)"; |
| 732 | + PreparedStatement ps = conn.prepareStatement(dml); |
| 733 | + for (int id1 = 0; id1 < 5; ++id1) { |
| 734 | + ps.setString(1, "id1_" + id1); |
| 735 | + for (int id2 = 0; id2 < 5; ++id2) { |
| 736 | + ps.setString(2, "id2_" + id2); |
| 737 | + ps.setString(3, "val1_" + id1 % 2); |
| 738 | + ps.setString(4, "val2_" + id2 % 2); |
| 739 | + ps.executeUpdate(); |
| 740 | + } |
| 741 | + } |
| 742 | + conn.commit(); |
| 743 | + try { |
| 744 | + ManualEnvironmentEdge injectEdge = new ManualEnvironmentEdge(); |
| 745 | + // expire the rows |
| 746 | + injectEdge.setValue(EnvironmentEdgeManager.currentTimeMillis() + ttl * 1000 + 2); |
| 747 | + EnvironmentEdgeManager.injectEdge(injectEdge); |
| 748 | + String distinctQuery = "SELECT DISTINCT id1 FROM " + dataTableName; |
| 749 | + try (ResultSet rs = conn.createStatement().executeQuery(distinctQuery)) { |
| 750 | + PhoenixResultSet prs = rs.unwrap(PhoenixResultSet.class); |
| 751 | + String explainPlan = QueryUtil.getExplainPlan(prs.getUnderlyingIterator()); |
| 752 | + assertTrue(explainPlan.contains("SERVER FILTER BY EMPTY COLUMN ONLY")); |
| 753 | + assertTrue(explainPlan.contains("SERVER DISTINCT PREFIX FILTER OVER")); |
| 754 | + // all the rows should have been masked |
| 755 | + assertFalse(rs.next()); |
| 756 | + } |
| 757 | + } finally { |
| 758 | + EnvironmentEdgeManager.reset(); |
| 759 | + } |
| 760 | + } |
| 761 | + } |
| 762 | + |
706 | 763 | private void upsertDataAndRunValidations(int numRowsToUpsert, |
707 | 764 | ExpectedTestResults expectedTestResults, DataWriter dataWriter, SchemaBuilder schemaBuilder, |
708 | 765 | List<Integer> overriddenColumnsPositions) throws Exception { |
|
0 commit comments