From f8d164e716632d376e0dab098f4ee376e3a56e98 Mon Sep 17 00:00:00 2001 From: Bertrand Martin Date: Tue, 29 Sep 2026 21:56:58 +0200 Subject: [PATCH] Accept multi-line WHERE clauses in WQL queries WmiHelper.WQL_SIMPLE_SELECT_PATTERN was compiled without Pattern.DOTALL, so `.*` in the optional WHERE group stopped at the first line break and queries written as text blocks were rejected with WqlSyntaxException. The legacy WqlQuery pattern already had DOTALL and is unaffected. Fixes #190 Co-Authored-By: Claude Fable 5.1 --- .../java/org/metricshub/winrm/WmiHelper.java | 2 +- src/site/markdown/wql.md | 3 +- .../org/metricshub/winrm/WmiHelperTest.java | 63 +++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/metricshub/winrm/WmiHelperTest.java diff --git a/src/main/java/org/metricshub/winrm/WmiHelper.java b/src/main/java/org/metricshub/winrm/WmiHelper.java index 054e036..03f4899 100644 --- a/src/main/java/org/metricshub/winrm/WmiHelper.java +++ b/src/main/java/org/metricshub/winrm/WmiHelper.java @@ -43,7 +43,7 @@ private WmiHelper() {} */ private static final Pattern WQL_SIMPLE_SELECT_PATTERN = Pattern.compile( "^\\s*SELECT\\s+(\\*|(?!SELECT|FROM|WHERE)[a-z0-9._]+|((?!SELECT|FROM|WHERE)[a-z0-9._]+\\s*,\\s*)+((?!SELECT|FROM|WHERE)[a-z0-9._]+))\\s+FROM\\s+((?!WHERE|FROM)\\w+)\\s*(WHERE\\s+.*)?$", - Pattern.CASE_INSENSITIVE + Pattern.CASE_INSENSITIVE | Pattern.DOTALL ); /** diff --git a/src/site/markdown/wql.md b/src/site/markdown/wql.md index 7aa531c..562b1e8 100644 --- a/src/site/markdown/wql.md +++ b/src/site/markdown/wql.md @@ -140,7 +140,8 @@ SELECT Name FROM Win32_Process WHERE Name = 'explorer.exe' ``` The grammar is a single `SELECT` of either `*` or a comma-separated property list, a `FROM` clause -naming one class, and an optional `WHERE` clause. Anything else, such as `ASSOCIATORS OF`, +naming one class, and an optional `WHERE` clause. Line breaks are accepted wherever whitespace is, +so queries written as Java text blocks work as is. Anything else, such as `ASSOCIATORS OF`, `REFERENCES OF` or event queries (`WITHIN`), is rejected: an invalid query raises a [`WqlSyntaxException`](apidocs/org/metricshub/winrm/exceptions/WqlSyntaxException.html) before anything is sent to the host. diff --git a/src/test/java/org/metricshub/winrm/WmiHelperTest.java b/src/test/java/org/metricshub/winrm/WmiHelperTest.java new file mode 100644 index 0000000..1c7091f --- /dev/null +++ b/src/test/java/org/metricshub/winrm/WmiHelperTest.java @@ -0,0 +1,63 @@ +package org.metricshub.winrm; + +/*- + * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲ + * WinRM Java Client + * ჻჻჻჻჻჻ + * Copyright 2023 - 2026 MetricsHub + * ჻჻჻჻჻჻ + * Licensed 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. + * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱ + */ +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class WmiHelperTest { + + @Test + void isValidWqlAcceptsSingleLineQueries() { + assertTrue(WmiHelper.isValidWql("SELECT * FROM Win32_Service")); + assertTrue(WmiHelper.isValidWql("SELECT Name FROM Win32_Service WHERE State = 'Running' AND StartMode = 'Auto'")); + } + + @Test + void isValidWqlAcceptsLineBreaksBeforeWhere() { + assertTrue(WmiHelper.isValidWql("SELECT Name FROM Win32_Service\nWHERE State = 'Running'")); + } + + @Test + void isValidWqlAcceptsMultiLineWhereClause() { + assertTrue( + WmiHelper.isValidWql("SELECT Name FROM Win32_Service\nWHERE State = 'Running'\n AND StartMode = 'Auto'\n") + ); + assertTrue( + WmiHelper.isValidWql( + "SELECT Name, ProcessId\r\nFROM Win32_Service\r\nWHERE State = 'Running'\r\n AND StartMode = 'Auto'" + ) + ); + } + + @Test + void isValidWqlRejectsNonSelectQueries() { + assertFalse(WmiHelper.isValidWql("ASSOCIATORS OF {Win32_Service.Name='W32Time'}")); + assertFalse(WmiHelper.isValidWql("REFERENCES OF {Win32_Service.Name='W32Time'}")); + assertFalse( + WmiHelper + .isValidWql("SELECT * FROM __InstanceModificationEvent WITHIN 1\nWHERE TargetInstance ISA 'Win32_Service'") + ); + assertFalse(WmiHelper.isValidWql("SELECT Name FROM Win32_Service\nSELECT Name FROM Win32_Process")); + assertFalse(WmiHelper.isValidWql("SELECT Name FROM Win32_Service WHERE")); + } +}