diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java index c31ccec79d552..993342565c62a 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java @@ -489,7 +489,10 @@ else if (state == QueryState.CLOSING) .append(", state=").append(state) .append(", schema=").append(ctx.schemaName()) .append(", initiatorId=").append(initiatorId) - .append(", sql='").append(sql); + .append(", sql='").append(sql).append('\''); + + if (QueryUtils.INCLUDE_SENSITIVE && params != null && params.length != 0) + msgSb.append(", params=").append(S.arrayToString(params)); msgSb.append(']'); diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/SqlDiagnosticIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/SqlDiagnosticIntegrationTest.java index 98cce7e4e4cba..dd7ec161d755b 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/SqlDiagnosticIntegrationTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/SqlDiagnosticIntegrationTest.java @@ -1040,6 +1040,39 @@ public void testSqlFieldsQueryWithInitiatorId() throws Exception { assertTrue(logLsnr.check(1000)); } + /** Checks that query parameters are printed in the long query warning only when sensitive data is allowed. */ + @Test + public void testLongQueryParametersInLog() throws Exception { + IgniteCache cache = prepareTestCache(grid(0)); + + long arg = LONG_QRY_TIMEOUT + 1; + + boolean includeSensitive = QueryUtils.INCLUDE_SENSITIVE; + + try { + for (boolean incl : new boolean[] {true, false}) { + QueryUtils.INCLUDE_SENSITIVE = incl; + + LogListener paramsLsnr = LogListener.matches(LONG_QUERY_FINISHED_MSG) + .andMatches("params=[" + arg + "]").build(); + + LogListener finishedLsnr = LogListener.matches(LONG_QUERY_FINISHED_MSG).build(); + + log.registerListener(paramsLsnr); + log.registerListener(finishedLsnr); + + cache.query(new SqlFieldsQuery("SELECT sleep(?)").setArgs(arg)) + .getAll(); + + assertTrue(finishedLsnr.check(1000)); + assertEquals(incl, paramsLsnr.check()); + } + } + finally { + QueryUtils.INCLUDE_SENSITIVE = includeSensitive; + } + } + /** * Verifies that query total execution time is correctly accumulated in the DURATION_TOTAL field of the * SQL_QUERIES_HISTORY system view. diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2QueryInfo.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2QueryInfo.java index ba16a290e0f9e..0c313433425d2 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2QueryInfo.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2QueryInfo.java @@ -28,6 +28,7 @@ import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; import org.apache.ignite.internal.processors.query.running.RunningQueryManager; import org.apache.ignite.internal.processors.query.running.TrackableQuery; +import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.h2.command.Prepared; import org.h2.engine.Session; @@ -76,6 +77,9 @@ public class H2QueryInfo implements TrackableQuery { /** Query initiator ID. */ private final String initiatorId; + /** Query parameters. */ + private final Object[] params; + /** Query SQL plan. */ private volatile String plan; @@ -86,8 +90,17 @@ public class H2QueryInfo implements TrackableQuery { * @param nodeId Originator node id. * @param qryId Query id. * @param initiatorId Query initiator id. + * @param params Query parameters. */ - public H2QueryInfo(QueryType type, PreparedStatement stmt, String sql, UUID nodeId, long qryId, String initiatorId) { + public H2QueryInfo( + QueryType type, + PreparedStatement stmt, + String sql, + UUID nodeId, + long qryId, + String initiatorId, + @Nullable Object[] params + ) { try { assert stmt != null; @@ -96,6 +109,7 @@ public H2QueryInfo(QueryType type, PreparedStatement stmt, String sql, UUID node this.nodeId = nodeId; this.qryId = qryId; this.initiatorId = initiatorId; + this.params = params; beginTs = U.currentTimeMillis(); @@ -210,8 +224,12 @@ public synchronized void resumeTracking() { .append(", enforceJoinOrder=").append(enforceJoinOrder) .append(", schema=").append(schema) .append(", initiatorId=").append(initiatorId) - .append(", sql='").append(sql) - .append("', plan=").append(plan()); + .append(", sql='").append(sql).append("'"); + + if (QueryUtils.INCLUDE_SENSITIVE && params != null && params.length != 0) + msgSb.append(", params=").append(S.arrayToString(params)); + + msgSb.append(", plan=").append(plan()); printInfo(msgSb); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 38ee2eb4d9df0..26c7cbc8840b7 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -422,7 +422,7 @@ private GridQueryFieldsResult executeSelectLocal( H2Utils.bindParameters(stmt, F.asList(params)); qryInfo = new H2QueryInfo(H2QueryInfo.QueryType.LOCAL, stmt, qry, - ctx.localNodeId(), qryId, qryDesc.queryInitiatorId()); + ctx.localNodeId(), qryId, qryDesc.queryInitiatorId(), params); heavyQryTracker.startTracking(qryInfo); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/MapH2QueryInfo.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/MapH2QueryInfo.java index 3e10c7733b10a..5a602d4ae7bef 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/MapH2QueryInfo.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/MapH2QueryInfo.java @@ -19,6 +19,7 @@ import java.sql.PreparedStatement; import java.util.UUID; +import org.jetbrains.annotations.Nullable; /** * Map query info. @@ -40,6 +41,7 @@ public class MapH2QueryInfo extends H2QueryInfo { * @param qryId Query id. * @param locQryId Local query id. * @param initiatorId Query initiator id. + * @param params Query parameters. * @param reqId Request ID. * @param segment Segment. */ @@ -50,10 +52,11 @@ public MapH2QueryInfo( long qryId, long locQryId, String initiatorId, + @Nullable Object[] params, long reqId, int segment ) { - super(QueryType.MAP, stmt, sql, nodeId, qryId, initiatorId); + super(QueryType.MAP, stmt, sql, nodeId, qryId, initiatorId, params); this.locQryId = locQryId; this.reqId = reqId; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ReduceH2QueryInfo.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ReduceH2QueryInfo.java index 9edbf595edeaa..70ba0bd743400 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ReduceH2QueryInfo.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ReduceH2QueryInfo.java @@ -19,6 +19,7 @@ import java.sql.PreparedStatement; import java.util.UUID; +import org.jetbrains.annotations.Nullable; /** * Reduce query info. @@ -33,10 +34,19 @@ public class ReduceH2QueryInfo extends H2QueryInfo { * @param nodeId Originator node id. * @param qryId Query id. * @param initiatorId Query initiator id. + * @param params Query parameters. * @param reqId Request ID. */ - public ReduceH2QueryInfo(PreparedStatement stmt, String sql, UUID nodeId, long qryId, String initiatorId, long reqId) { - super(QueryType.REDUCE, stmt, sql, nodeId, qryId, initiatorId); + public ReduceH2QueryInfo( + PreparedStatement stmt, + String sql, + UUID nodeId, + long qryId, + String initiatorId, + @Nullable Object[] params, + long reqId + ) { + super(QueryType.REDUCE, stmt, sql, nodeId, qryId, initiatorId, params); this.reqId = reqId; } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java index e22c9b374e248..ec68bbe4e8f53 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridMapQueryExecutor.java @@ -441,13 +441,13 @@ private void onQueryRequest0( // Ensure we are on the target node for this replicated query. if (qry.node() == null || (segmentId == 0 && qry.node().equals(ctx.localNodeId()))) { String sql = qry.query(); - Collection params0 = F.asList(qry.parameters(params)); + Object[] params0 = qry.parameters(params); PreparedStatement stmt = conn.prepareStatement(sql, H2StatementCache.queryFlags( distributedJoins, enforceJoinOrder)); - H2Utils.bindParameters(stmt, params0); + H2Utils.bindParameters(stmt, F.asList(params0)); GridQueryCancel qryCancel = qryResults.queryCancel(qryIdx); @@ -468,6 +468,7 @@ private void onQueryRequest0( qryId, runningQryId, qryInitiatorId, + params0, reqId, segmentId ); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java index d3695c2c47986..660f4f72d8783 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java @@ -503,7 +503,7 @@ else if (QueryUtils.wasCancelled(err)) H2Utils.bindParameters(stmt, F.asList(rdc.parameters(params))); qryInfo = new ReduceH2QueryInfo(stmt, qry.originalSql(), - ctx.localNodeId(), qryId, qryInitiatorId, qryReqId); + ctx.localNodeId(), qryId, qryInitiatorId, params, qryReqId); h2.heavyQueriesTracker().startTracking(qryInfo); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LongRunningQueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LongRunningQueryTest.java index 01a833c9cc89e..3d2fc0838f8d0 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LongRunningQueryTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/LongRunningQueryTest.java @@ -505,6 +505,32 @@ public void testQueryInitiatorId() { LONG_QUERY_WARNING_TIMEOUT + 1); } + /** + * Verifies query parameters in logs. + */ + @Test + @MultiNodeTest + public void testQueryParameters() throws InterruptedException { + ListeningTestLogger testLog = testLog(); + + boolean includeSensitive = QueryUtils.INCLUDE_SENSITIVE; + + try { + for (boolean incl : new boolean[] {true, false}) { + QueryUtils.INCLUDE_SENSITIVE = incl; + + checkParameters(testLog, "LOCAL", "SELECT sleep_func(?, 0)", incl); + + checkParameters(testLog, "MAP", "SELECT val FROM test WHERE id = sleep_func(?, 0)", incl); + + checkParameters(testLog, "REDUCE", "SELECT sleep_func(?, sum(val)) FROM test WHERE id + 1 = 1", incl); + } + } + finally { + QueryUtils.INCLUDE_SENSITIVE = includeSensitive; + } + } + /** Verifies map query information in long-query logs. */ @Test @MultiNodeTest @@ -546,6 +572,29 @@ private void checkInitiatorId(ListeningTestLogger log, String type, String sql, assertTrue(lsnr.check()); } + /** */ + private void checkParameters( + ListeningTestLogger log, + String type, + String sql, + boolean includeSensitive + ) throws InterruptedException { + int arg = LONG_QUERY_WARNING_TIMEOUT + 1; + + LogListener paramsLsnr = LogListener.matches(LONG_QUERY_FINISHED_MSG).andMatches("type=" + type) + .andMatches("params=[" + arg + "]").build(); + + LogListener finishedLsnr = LogListener.matches(LONG_QUERY_FINISHED_MSG).andMatches("type=" + type).build(); + + log.registerListener(paramsLsnr); + log.registerListener(finishedLsnr); + + ignite.cache("test").query(new SqlFieldsQuery(sql).setArgs(arg)).getAll(); + + assertTrue(finishedLsnr.check(1000)); + assertEquals(includeSensitive, paramsLsnr.check()); + } + /** * Do several fast queries. * Log messages must not contain info about long query.