Handle Multiple ORDER BYs with DEFAULTs#127
Conversation
Greptile SummaryThis PR adds support for multiple
Confidence Score: 4/5Safe 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.
|
| 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"]
%%{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"]
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
|
This PR is ready for human review. |
gbeeley
left a comment
There was a problem hiding this comment.
A couple of changes needed - thanks!
|
|
||
| /** Drop a DEFAULT clause that isn't the last one. **/ | ||
| if ((subtree->Flags & MQ_SF_DEFAULTORDER) && !is_last) | ||
| goto remove_order_by_element; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
goto removed.
| strcasecmp(ptr, "default") == 0) | ||
| orderby_cls->Flags |= MQ_SF_DEFAULTORDER; | ||
| else | ||
| mlxHoldToken(lxs); |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
I see, updated.
|
@gbeeley I think I've resolved your comments. |
This PR will add functionality for handling multiple
ORDER BYstatements. Later statements append to earlier ones, or overwrite them if they use theDEFAULTkeyword, as suggested by Greg.This PR includes both docs and testing for the new functionality and the
DEFAULTkeyword.