Skip to content

Conversation

@robll-v1
Copy link

@robll-v1 robll-v1 commented Feb 4, 2026

PR Type

Enhancement


Description

  • Add wait_expect feature for polling query results until expected output

  • Implement parsing of wait_expect flag with interval and timeout parameters

  • Add retry logic in Executor to re-execute queries with configurable polling

  • Add getter method for actResult in SqlCommand class


Diagram Walkthrough

flowchart LR
  A["ScriptParser"] -- "parseWaitExpectFlag" --> B["SqlCommand"]
  B -- "setWaitExpect/Interval/Timeout" --> C["Command Properties"]
  C -- "isWaitExpect check" --> D["Executor"]
  D -- "retry loop with polling" --> E["Query Re-execution"]
  E -- "checkResult validation" --> F["Result Matching"]
Loading

File Walkthrough

Relevant files
Enhancement
SqlCommand.java
Add wait_expect properties and actResult getter                   

src/main/java/io/mo/cases/SqlCommand.java

  • Added three new properties: waitExpect, waitExpectInterval,
    waitExpectTimeout with getters/setters
  • Added public getter method getActResult() for accessing actual result
+16/-0   
Executor.java
Implement wait_expect polling retry logic                               

src/main/java/io/mo/db/Executor.java

  • Implemented retry loop logic in run() method that polls query results
    until expected output matches or timeout
  • Added validation to ensure wait_expect only applies to query result
    sets
  • Added sleep logic in genRS() method to wait before generating results
    when wait_expect is enabled
  • Handles interval-based polling with deadline calculation
+45/-0   
ScriptParser.java
Add wait_expect flag parsing logic                                             

src/main/java/io/mo/util/ScriptParser.java

  • Added parseWaitExpectFlag() method to parse wait_expect flag with
    interval and timeout parameters
  • Integrated flag parsing into processCommentLine() method
  • Includes validation for flag format, numeric values, and
    interval/timeout constraints
  • Logs warnings for invalid formats or values
+39/-1   
Configuration changes
COMMON.java
Add wait_expect flag constant                                                       

src/main/java/io/mo/constant/COMMON.java

  • Added new constant WAIT_EXPECT_FLAG = "-- @wait_expect" for flag
    recognition
  • Fixed file ending formatting
+2/-1     
mo.yml
Update default database configuration                                       

mo.yml

  • Changed default database from empty string to "test"
+1/-1     

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Denial of service

Description: The new wait_expect polling and sleep logic can be driven by script-provided
interval/timeout to repeatedly re-execute potentially expensive queries and/or block
threads via Thread.sleep, creating a realistic resource-exhaustion/DoS risk (CPU/DB load
and thread starvation), especially if large timeout values are allowed or many commands
enable wait_expect concurrently. Executor.java [226-428]

Referred Code
if (command.isWaitExpect()) {
    int intervalMs = command.getWaitExpectInterval() * 1000;
    int timeoutMs = command.getWaitExpectTimeout() * 1000;
    if (intervalMs > 0 && timeoutMs > 0) {
        StmtResult firstActResult = command.getActResult();
        if (firstActResult == null || firstActResult.getType() != RESULT.STMT_RESULT_TYPE_SET) {
            logger.warn(String.format(
                    "wait_expect is only safe for query results. Skip retry for command[%s][row:%d].",
                    command.getCommand(), command.getPosition()));
        } else {
            long deadline = System.currentTimeMillis() + timeoutMs;
            boolean matched = command.checkResult();
            while (!matched && System.currentTimeMillis() < deadline) {
                long now = System.currentTimeMillis();
                long sleepMs = Math.min(intervalMs, Math.max(0, deadline - now));
                if (sleepMs > 0) {
                    Thread.sleep(sleepMs);
                }
                if (statement != null) {
                    statement.close();
                }


 ... (clipped 182 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive SQL in logs: New log messages include command.getCommand() (raw SQL text) and may therefore write
sensitive data contained in queries into logs.

Referred Code
    logger.warn(String.format(
            "wait_expect is only safe for query results. Skip retry for command[%s][row:%d].",
            command.getCommand(), command.getPosition()));
} else {

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit context: The new wait/retry execution path re-runs SQL commands but does not add audit-grade
logging with actor/user identity, timestamped action metadata, and outcome sufficient to
reconstruct critical events.

Referred Code
if (command.isWaitExpect()) {
    int intervalMs = command.getWaitExpectInterval() * 1000;
    int timeoutMs = command.getWaitExpectTimeout() * 1000;
    if (intervalMs > 0 && timeoutMs > 0) {
        StmtResult firstActResult = command.getActResult();
        if (firstActResult == null || firstActResult.getType() != RESULT.STMT_RESULT_TYPE_SET) {
            logger.warn(String.format(
                    "wait_expect is only safe for query results. Skip retry for command[%s][row:%d].",
                    command.getCommand(), command.getPosition()));
        } else {
            long deadline = System.currentTimeMillis() + timeoutMs;
            boolean matched = command.checkResult();
            while (!matched && System.currentTimeMillis() < deadline) {
                long now = System.currentTimeMillis();
                long sleepMs = Math.min(intervalMs, Math.max(0, deadline - now));
                if (sleepMs > 0) {
                    Thread.sleep(sleepMs);
                }
                if (statement != null) {
                    statement.close();
                }


 ... (clipped 20 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Interrupted sleep handling: New Thread.sleep(...) calls in the retry loop and result generation path introduce
InterruptedException risk without visible local handling or restoration of the interrupt
flag, which may cause unexpected termination or compilation/runtime issues depending on
surrounding method signatures.

Referred Code
if (sleepMs > 0) {
    Thread.sleep(sleepMs);
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unbounded wait parameters: wait_expect interval/timeout are only validated as numeric and >0, with no upper
bounds, which can enable excessively large sleeps/timeouts (potential DoS) and downstream
integer-to-milliseconds conversions.

Referred Code
    if (!StringUtils.isNumeric(intervalStr) || !StringUtils.isNumeric(timeoutStr)) {
        LOG.warn(String.format("Invalid wait_expect flag values: %s. Interval/timeout must be numeric.", trimmedLine));
        return;
    }

    int interval = Integer.parseInt(intervalStr);
    int timeout = Integer.parseInt(timeoutStr);
    if (interval <= 0 || timeout <= 0) {
        LOG.warn(String.format("Invalid wait_expect flag values: %s. Interval/timeout must be > 0.", trimmedLine));
        return;
    }
    if (interval > timeout) {
        LOG.warn(String.format("wait_expect interval(%d) is greater than timeout(%d), interval will be capped to timeout.", interval, timeout));
        interval = timeout;
    }

    command.setWaitExpect(true);
    command.setWaitExpectInterval(interval);
    command.setWaitExpectTimeout(timeout);
}

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Handle empty wait_expect flag parameters

Add a check in parseWaitExpectFlag to handle cases where the flag is used
without parameters (e.g., -- @wait_expect) to prevent a
StringIndexOutOfBoundsException.

src/main/java/io/mo/util/ScriptParser.java [160-195]

 private void parseWaitExpectFlag(String trimmedLine, SqlCommand command) {
     String rest = trimmedLine.substring(COMMON.WAIT_EXPECT_FLAG.length()).trim();
+    if (rest.isEmpty()) {
+        LOG.warn(String.format("Invalid wait_expect flag format: %s. Missing (interval, timeout).", trimmedLine));
+        return;
+    }
     if (!rest.startsWith("(") || !rest.endsWith(")")) {
         LOG.warn(String.format("Invalid wait_expect flag format: %s. Expected -- @wait_expect(interval, timeout)", trimmedLine));
         return;
     }
 
     String content = rest.substring(1, rest.length() - 1);
     String[] parts = content.split(",");
     if (parts.length != 2) {
         LOG.warn(String.format("Invalid wait_expect flag format: %s. Expected -- @wait_expect(interval, timeout)", trimmedLine));
         return;
     }
 
     String intervalStr = parts[0].trim();
     String timeoutStr = parts[1].trim();
     if (!StringUtils.isNumeric(intervalStr) || !StringUtils.isNumeric(timeoutStr)) {
         LOG.warn(String.format("Invalid wait_expect flag values: %s. Interval/timeout must be numeric.", trimmedLine));
         return;
     }
 
     int interval = Integer.parseInt(intervalStr);
     int timeout = Integer.parseInt(timeoutStr);
     if (interval <= 0 || timeout <= 0) {
         LOG.warn(String.format("Invalid wait_expect flag values: %s. Interval/timeout must be > 0.", trimmedLine));
         return;
     }
     if (interval > timeout) {
         LOG.warn(String.format("wait_expect interval(%d) is greater than timeout(%d), interval will be capped to timeout.", interval, timeout));
         interval = timeout;
     }
 
     command.setWaitExpect(true);
     command.setWaitExpectInterval(interval);
     command.setWaitExpectTimeout(timeout);
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential StringIndexOutOfBoundsException if the wait_expect flag is used without parameters. Adding a check for an empty string improves the robustness of the parser.

Medium
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant