wave14a/c/d: 524/239 — rails-0018/grape-0001..3/django-0005..6/sqlalchemy-0003/go-stdlib-0001/vault-0001/tf-aws-0001

This commit is contained in:
russell@unturf.com 2026-03-27 18:11:25 -04:00
parent 8f0bc73afa
commit ac0e1e091e
20 changed files with 1948 additions and 21 deletions

View file

@ -0,0 +1,50 @@
# sqlalchemy-0003: evaluated_keys list → set in _apply_evaluators()
## Severity
MEDIUM
## Location
`lib/sqlalchemy/orm/bulk_persistence.py` — `_apply_evaluators()` (approx. line 1873)
## Description
`evaluated_keys = list(value_evaluators.keys())` converts a dict's key view
to a plain list. The list is then used for:
1. `c.key not in evaluated_keys` — O(K) membership scan inside a set
comprehension over `prefetch_cols` (one test per column)
2. `.difference(evaluated_keys)` — called on a set; this is O(P×K) rather
than the O(P) it would be with a set argument
Fix: `evaluated_keys = set(value_evaluators)` (or just use `value_evaluators`
directly for membership, since dict `in` is O(1)).
## Defective code (lines 1873–1889)
```python
evaluated_keys = list(value_evaluators.keys()) # ← plain list
to_prefetch = {
c
for c in prefetch_cols
if c.key in effective_params
and c in mapper._columntoproperty
and c.key not in evaluated_keys # ← O(K) linear scan per column
}
to_expire = {
mapper._columntoproperty[c].key
for c in postfetch_cols
if c in mapper._columntoproperty
}.difference(evaluated_keys) # ← set.difference(list) is O(P×K)
```
## Fix
```diff
--- a/lib/sqlalchemy/orm/bulk_persistence.py
+++ b/lib/sqlalchemy/orm/bulk_persistence.py
@@ -1873,1 +1873,1 @@
- evaluated_keys = list(value_evaluators.keys())
+ evaluated_keys = set(value_evaluators)
```
## Complexity
- Before: O(C×K) for the `to_prefetch` comprehension, O(P×K) for `.difference()`
- After: O(C) + O(P) — both operations drop to O(1) membership