Scanned xTuple OpenRPT (public C++/Qt report engine used by xTuple ERP). One MOAD-0001 defect found in orutils.cpp SQL parameter parsing loop. MOADs 0002/0003/0004/0005 CLEAN.
61 lines
1.9 KiB
Markdown
61 lines
1.9 KiB
Markdown
# xtuple-0001: orutils.cpp missingParamList QStringList::contains O(P*M) in SQL param parse loop
|
|
|
|
**Project:** xTuple / OpenRPT (open-source ERP report engine)
|
|
**File:** `OpenRPT/renderer/orutils.cpp`
|
|
**MOAD:** 0001 (CWE-407 — Inefficient Algorithmic Complexity)
|
|
**Severity:** LOW-MEDIUM
|
|
**Speedup:** ~10-50x at P=1000, M=500
|
|
|
|
## Description
|
|
|
|
`orQuery::orQuery()` parses a SQL string to find parameter placeholders
|
|
(`$"name"` and `%N` style). As it encounters each placeholder, it checks
|
|
whether the parameter name is already in `missingParamList` before appending:
|
|
|
|
```cpp
|
|
// OpenRPT/renderer/orutils.cpp:65
|
|
if(!missingParamList.contains(n))
|
|
missingParamList.append(n);
|
|
```
|
|
|
|
`missingParamList` is declared as `QStringList` (i.e. `QList<QString>`).
|
|
`QStringList::contains()` is a linear O(M) scan where M is our current missing
|
|
param count. The outer loop iterates P times (once per param placeholder in
|
|
the SQL). Total complexity: O(P * M).
|
|
|
|
For a parametric report template with hundreds of placeholder occurrences and
|
|
many distinct missing params (e.g., a batch report runner that pre-scans many
|
|
SQL templates), this compounds into measurable overhead.
|
|
|
|
## Fix
|
|
|
|
Replace the membership check with a `QSet<QString>` shadow set for O(1)
|
|
average-case lookup, while keeping `missingParamList` as the ordered
|
|
`QStringList` for downstream consumption (it is a public member used by
|
|
callers to display ordered missing-param dialogs).
|
|
|
|
```cpp
|
|
QSet<QString> missingParamSet;
|
|
// ...
|
|
if(!missingParamSet.contains(n)) {
|
|
missingParamSet.insert(n);
|
|
missingParamList.append(n);
|
|
}
|
|
```
|
|
|
|
## Complexity
|
|
|
|
| Version | Time |
|
|
|---------|------|
|
|
| Before | O(P * M) |
|
|
| After | O(P) amortized |
|
|
|
|
## Affected File
|
|
|
|
`OpenRPT/renderer/orutils.cpp` (and `orutils.h` for the shadow set field)
|
|
|
|
## Test
|
|
|
|
`defects/xtuple-0001/test/test_xtuple_0001.py` — simulates the pattern in
|
|
Python, benchmarks N=1000 param slots with M=500 distinct missing params,
|
|
asserts speedup > 3x.
|