diff --git a/ql/src/test/queries/clientpositive/ppd_like_filter.q b/ql/src/test/queries/clientpositive/ppd_like_filter.q index f9a8fc13a0bf..cec2d0655e2a 100644 --- a/ql/src/test/queries/clientpositive/ppd_like_filter.q +++ b/ql/src/test/queries/clientpositive/ppd_like_filter.q @@ -28,5 +28,8 @@ select * from test_tbl where b like '___'; select * from test_tbl where b like '%%%'; select * from test_tbl where b like '%\\\\%'; - - +select * from test_tbl where b like 'a.*'; +select * from test_tbl where b like 'd.\%.*'; +select * from test_tbl where b like 'd.\\%.*'; +select * from test_tbl where b like 'd.\\\\%.*'; +select * from test_tbl where b like '.\\_.*'; diff --git a/ql/src/test/results/clientpositive/llap/ppd_like_filter.q.out b/ql/src/test/results/clientpositive/llap/ppd_like_filter.q.out index 125f7bb0f5e2..85abbc2ffd74 100644 --- a/ql/src/test/results/clientpositive/llap/ppd_like_filter.q.out +++ b/ql/src/test/results/clientpositive/llap/ppd_like_filter.q.out @@ -256,3 +256,51 @@ POSTHOOK: type: QUERY POSTHOOK: Input: default@test_tbl POSTHOOK: Input: default@test_tbl@b=d_%5C%25ae #### A masked pattern was here #### +PREHOOK: query: select * from test_tbl where b like 'a.*' +PREHOOK: type: QUERY +PREHOOK: Input: default@test_tbl +PREHOOK: Input: default@test_tbl@b=abc +PREHOOK: Input: default@test_tbl@b=af%25 +#### A masked pattern was here #### +POSTHOOK: query: select * from test_tbl where b like 'a.*' +POSTHOOK: type: QUERY +POSTHOOK: Input: default@test_tbl +POSTHOOK: Input: default@test_tbl@b=abc +POSTHOOK: Input: default@test_tbl@b=af%25 +#### A masked pattern was here #### +PREHOOK: query: select * from test_tbl where b like 'd.\%.*' +PREHOOK: type: QUERY +PREHOOK: Input: default@test_tbl +#### A masked pattern was here #### +POSTHOOK: query: select * from test_tbl where b like 'd.\%.*' +POSTHOOK: type: QUERY +POSTHOOK: Input: default@test_tbl +#### A masked pattern was here #### +PREHOOK: query: select * from test_tbl where b like 'd.\\%.*' +PREHOOK: type: QUERY +PREHOOK: Input: default@test_tbl +#### A masked pattern was here #### +POSTHOOK: query: select * from test_tbl where b like 'd.\\%.*' +POSTHOOK: type: QUERY +POSTHOOK: Input: default@test_tbl +#### A masked pattern was here #### +PREHOOK: query: select * from test_tbl where b like 'd.\\\\%.*' +PREHOOK: type: QUERY +PREHOOK: Input: default@test_tbl +PREHOOK: Input: default@test_tbl@b=d_%5C%25ae +#### A masked pattern was here #### +POSTHOOK: query: select * from test_tbl where b like 'd.\\\\%.*' +POSTHOOK: type: QUERY +POSTHOOK: Input: default@test_tbl +POSTHOOK: Input: default@test_tbl@b=d_%5C%25ae +#### A masked pattern was here #### +PREHOOK: query: select * from test_tbl where b like '.\\_.*' +PREHOOK: type: QUERY +PREHOOK: Input: default@test_tbl +PREHOOK: Input: default@test_tbl@b=d_%5C%25ae +#### A masked pattern was here #### +POSTHOOK: query: select * from test_tbl where b like '.\\_.*' +POSTHOOK: type: QUERY +POSTHOOK: Input: default@test_tbl +POSTHOOK: Input: default@test_tbl@b=d_%5C%25ae +#### A masked pattern was here #### diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java index 686c1e9c3713..d9c39180eda1 100644 --- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java @@ -856,6 +856,15 @@ public int getMaxRows(int batch, int paramSize) { return batch; } + public String escapeClause() { + if (isMYSQL()) { + // MySQL does not support ESCAPE '\' + return " ESCAPE '\\\\' "; + } else { + return " ESCAPE '\\' "; + } + } + // This class implements the Configurable interface for the benefit // of "plugin" instances created via reflection (see invocation of // ReflectionUtils.newInstance in method determineDatabaseProduct) diff --git a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java index 415d7c7f557a..37161973edff 100644 --- a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java +++ b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java @@ -1528,7 +1528,11 @@ public void visit(LeafNode node) throws MetaException { String tableValue = "\"FILTER" + partColIndex + "\".\"PART_KEY_VAL\""; if (node.isReverseOrder && nodeValue != null) { - params.add(nodeValue); + if (node.operator == Operator.LIKE) { + params.add(makeDirectFilterForLike(nodeValue.toString())); + } else { + params.add(nodeValue); + } } String tableColumn = tableValue; if ((colType != FilterType.String) && (!isDefaultPartition)) { @@ -1560,12 +1564,16 @@ public void visit(LeafNode node) throws MetaException { } if (!node.isReverseOrder && nodeValue != null) { - params.add(nodeValue); + if (node.operator == Operator.LIKE) { + params.add(makeDirectFilterForLike(nodeValue.toString())); + } else { + params.add(nodeValue); + } } // The following syntax is required for using LIKE clause wildcards '_' and '%' as literals. if (node.operator == Operator.LIKE) { - nodeValue0 = nodeValue0 + " ESCAPE '\\' "; + nodeValue0 = nodeValue0 + dbType.escapeClause(); } String filter = node.isReverseOrder ? nodeValue0 + " " + node.operator.getSqlOp() + " " + tableValue @@ -1607,6 +1615,30 @@ public void visit(LeafNode node) throws MetaException { filterBuffer.append("(" + filter + ")"); } + + private String makeDirectFilterForLike(String likePattern) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < likePattern.length(); i++) { + char n = likePattern.charAt(i); + // MySQL default ESCAPE is "\\\\", but prepared statement parameters + // are transmitted as raw values, so only "\\" is needed. + if (dbType.isMYSQL() && n == '\\' && i + 1 < likePattern.length() + && likePattern.charAt(i + 1) == '\\') { + i++; + } + if (n == '.') { + if (i + 1 < likePattern.length() && likePattern.charAt(i + 1) == '*') { + sb.append("%"); + i++; + } else { + sb.append("_"); + } + continue; + } + sb.append(n); + } + return sb.toString(); + } } /**