Skip to content

Handle Multiple ORDER BYs with DEFAULTs#127

Open
Lightning11wins wants to merge 10 commits into
masterfrom
add-default-keyword
Open

Handle Multiple ORDER BYs with DEFAULTs#127
Lightning11wins wants to merge 10 commits into
masterfrom
add-default-keyword

Conversation

@Lightning11wins

Copy link
Copy Markdown
Contributor

This PR will add functionality for handling multiple ORDER BY statements. Later statements append to earlier ones, or overwrite them if they use the DEFAULT keyword, as suggested by Greg.

This PR includes both docs and testing for the new functionality and the DEFAULT keyword.

@Lightning11wins Lightning11wins self-assigned this Jun 17, 2026
@Lightning11wins Lightning11wins added testing Includes testing, either new tests or updates to existing tests. ai-review Request AI review for PRs. documentation Changes, improvements, or fixes to documentation files. size: trivial Easy to review, probably ~100 lines or fewer. labels Jun 17, 2026
@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds support for multiple ORDER BY clauses in Centrallix SQL, where later clauses append their sort keys to the first, and a clause marked ORDER BY DEFAULT is silently dropped if any later ORDER BY follows it — enabling queries to declare a fallback ordering that can be overridden.

  • mq_internal_SyntaxParse now parses an optional DEFAULT keyword after ORDER BY and sets the new MQ_SF_DEFAULTORDER flag on the clause node.
  • mq_internal_PostProcess gained a pre-pass that walks all ORDER BY nodes in the query tree: DEFAULT nodes that are not the last are freed and removed, while surviving non-first nodes have their children folded into the first surviving clause before being removed.
  • Seven new test cases (.to / .cmp) cover all meaningful combinations of DEFAULT and non-DEFAULT ORDER BY orderings; documentation and the coding style guide are updated accordingly.

Confidence Score: 4/5

Safe to merge after fixing the minor documentation wording errors; the algorithmic changes are correct.

The merge logic in mq_internal_PostProcess correctly handles all tested combinations — single clause, two non-default, DEFAULT as first/last/only, two DEFAULTs, and three-clause mixes — with no memory leaks or double-free risk. The only issues are style-level: two typos in the docs, a mid-block const bool declaration that breaks the codebase's all-declarations-at-top C89 convention, and one multiline comment closed with **/ instead of ***/ .

centrallix-doc/SQL.txt has two typographical errors that should be corrected before merge; centrallix/multiquery/multiquery.c has a style inconsistency with the bool declaration.

Important Files Changed

Filename Overview
centrallix/multiquery/multiquery.c Core change: adds ORDER BY merge logic in mq_internal_PostProcess and DEFAULT keyword parsing in mq_internal_SyntaxParse. Logic is algorithmically correct (verified against all 7 test cases), but introduces a C99 mid-block const bool declaration inconsistent with the codebase's C89 declaration style, and a closing **/ on one multiline comment that should be ***/ .
centrallix-doc/SQL.txt New section documenting multiple ORDER BY and the DEFAULT keyword; has two typographical errors: 'the keyword DEFAULT keyword' (duplicate word) and 'if is the last' (missing 'it').
centrallix/include/multiquery.h Adds MQ_SF_DEFAULTORDER flag (65536 = next power-of-two after MQ_SF_PAGED=32768); copyright year update. Clean change.
centrallix/tests/test_sql_orderby_05.to New test file covering 7 ORDER BY combinations: single clause, two non-default, DEFAULT as first/last/only/both, and a three-clause mix. Comprehensive coverage of the new behaviour.
centrallix/tests/test_sql_orderby_05.cmp Expected output file for the new tests; results are consistent with the documented merge/drop semantics for all 7 queries.
centrallix-sysdoc/BeeleyCodingStyle.md Minor wording clarification to the multiline comment style description; no functional change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Parse ORDER BY token"] --> B{"Next token == DEFAULT?"}
    B -- Yes --> C["Set MQ_SF_DEFAULTORDER flag on orderby_cls"]
    B -- No --> D["mlxHoldToken (put back)"]
    C --> E["Continue parsing ORDER BY items"]
    D --> E
    E --> F["Add orderby_cls to qs->Children"]
    F --> G["mq_internal_PostProcess: Find last_orderby in qs->Children"]
    G --> H{"For each ORDER BY node in qs->Children"}
    H --> I{"Has MQ_SF_DEFAULTORDER AND not the last?"}
    I -- Yes --> J["Free & remove node (drop DEFAULT)"]
    J --> H
    I -- No --> K{"ob == NULL?"}
    K -- Yes --> L["ob = this node (first surviving clause)"]
    L --> H
    K -- No --> M["Fold children into ob, update Parent pointers"]
    M --> N["Free & remove node"]
    N --> H
    H -- Done --> O["Compile ob's ORDER BY expressions"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Parse ORDER BY token"] --> B{"Next token == DEFAULT?"}
    B -- Yes --> C["Set MQ_SF_DEFAULTORDER flag on orderby_cls"]
    B -- No --> D["mlxHoldToken (put back)"]
    C --> E["Continue parsing ORDER BY items"]
    D --> E
    E --> F["Add orderby_cls to qs->Children"]
    F --> G["mq_internal_PostProcess: Find last_orderby in qs->Children"]
    G --> H{"For each ORDER BY node in qs->Children"}
    H --> I{"Has MQ_SF_DEFAULTORDER AND not the last?"}
    I -- Yes --> J["Free & remove node (drop DEFAULT)"]
    J --> H
    I -- No --> K{"ob == NULL?"}
    K -- Yes --> L["ob = this node (first surviving clause)"]
    L --> H
    K -- No --> M["Fold children into ob, update Parent pointers"]
    M --> N["Free & remove node"]
    N --> H
    H -- Done --> O["Compile ob's ORDER BY expressions"]
Loading
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 4
centrallix-doc/SQL.txt:121-128
**Two typographical errors in new paragraph**

Line 122 reads "the keyword DEFAULT keyword" — "keyword" appears twice in a row. Line 125 reads "if is the last" which is missing "it".

### Issue 2 of 4
centrallix-doc/SQL.txt:121-125
Fix "keyword" duplication and the missing "it".

```suggestion
    A query may contain more than one ORDER BY clause.  Later ORDER BY clauses
    append their columns the first ORDER BY.  However, ORDER BY marked with the
    DEFAULT keyword is overwritten by any later ORDER BY, even if that
    ORDER BY also uses the DEFAULT keyword.  Its columns are only appended if
    it is the last ORDER BY in its SQL query.
```

### Issue 3 of 4
centrallix/multiquery/multiquery.c:661
**Mid-block `const bool` declaration inconsistent with codebase style**

The rest of this file declares all locals at the top of the function body, in the C89 style followed throughout the codebase. Placing `const bool is_last` here — after `subtree` has already been assigned — uses C99 mid-block declaration syntax and requires the newly added `<stdbool.h>`. To stay consistent, declare `is_last` (as `int`) alongside `i`, `j`, `cnt`, etc. at the top of `mq_internal_PostProcess`, and assign it at the top of the loop body.

### Issue 4 of 4
centrallix/multiquery/multiquery.c:1500-1503
**Multiline comment close uses `**/` instead of `***/`**

The coding style requires three-asterisk style for multiline comments (`/*** ... ***/`). This comment block closes with ` **/` (two asterisks) rather than the expected ` ***/`, inconsistent with every other multiline comment in the file.

Reviews (1): Last reviewed commit: "Fix wording in the code style that confu..." | Re-trigger Greptile

@Lightning11wins

Copy link
Copy Markdown
Contributor Author

This PR is ready for human review.

@gbeeley gbeeley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of changes needed - thanks!

Comment thread centrallix/multiquery/multiquery.c Outdated

/** Drop a DEFAULT clause that isn't the last one. **/
if ((subtree->Flags & MQ_SF_DEFAULTORDER) && !is_last)
goto remove_order_by_element;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid the goto since this isn't a retry mechanism or an error condition handler, and since this can be easily refactored as an if() block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

goto removed.

strcasecmp(ptr, "default") == 0)
orderby_cls->Flags |= MQ_SF_DEFAULTORDER;
else
mlxHoldToken(lxs);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add "default" to the list of reserved words at the top of this function, check type against MLX_TOK_RESERVEDWD, and do the string compare using strcmp() (in this parse, mtlexer is set to automatically lowercase reserved words).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, updated.

@Lightning11wins

Copy link
Copy Markdown
Contributor Author

@gbeeley I think I've resolved your comments.

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

Labels

ai-review Request AI review for PRs. documentation Changes, improvements, or fixes to documentation files. size: trivial Easy to review, probably ~100 lines or fewer. testing Includes testing, either new tests or updates to existing tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants