Bug fixes: composite PK, nl_to_sql sandbox, FK check, SQL injection, storage correctness
Critical fixes: - Composite PK: execInsert + validateConstraints use all PK columns - nl_to_sql: non-SELECT SQL no longer executed directly during validation - FK check: removed O(N) scanMemTable fallback, uses db.get() with SSTables - exprToSql: nkIdent wrapped in quotes to prevent SQL injection - restoreSchema: try/except around tokenize/parse for crash resilience - recovery.nim: lastTxnId tracking + putUnsafe/deleteUnsafe without WAL - SCRAM: verifyClientProof length check + DefaultIterationCount restored Storage fixes: - lsm.nim: SSTable sort order fixed (ascending), close() flushes all memtables - compaction.nim: tombstones preserved during compaction - wal.nim: header written for empty existing files, readEntries checks magic - btree.nim: B+ tree leaf split keeps boundary key - bloom.nim: deserialize raises on short data - mmap.nim: bounds checks for adviseWillNeed/DontNeed + posix.close() Protocol fixes: - zerocopy.nim: readString bounds check - wire.nim: deserializeValue 32-bit underflow check - auth.nim: JWT JSON escaping for claims - server.nim: readUint32BE bounds check + specific exception handling - raft.nim: readData checks + specific exception handling Tests: - Added Composite Primary Key test suite (4 tests) Build: 0 warnings, 0 errors
This commit is contained in:
@@ -32,6 +32,7 @@ type
|
||||
dataDir*: string
|
||||
entries*: seq[RecoveredEntry]
|
||||
result*: RecoveryResult
|
||||
lastTxnId*: uint64 # tracks commits seen in WAL
|
||||
|
||||
proc newCrashRecovery*(walDir: string, dataDir: string): CrashRecovery =
|
||||
CrashRecovery(
|
||||
@@ -101,6 +102,7 @@ proc scanWAL*(rec: CrashRecovery): seq[RecoveredEntry] =
|
||||
discard
|
||||
|
||||
stream.close()
|
||||
rec.lastTxnId = txnId
|
||||
|
||||
proc analyze*(rec: CrashRecovery): RecoveryResult =
|
||||
rec.entries = rec.scanWAL()
|
||||
@@ -109,10 +111,7 @@ proc analyze*(rec: CrashRecovery): RecoveryResult =
|
||||
rec.result = RecoveryResult(state: recDone, applied: false)
|
||||
return rec.result
|
||||
|
||||
var lastCommitted: uint64 = 0
|
||||
for entry in rec.entries:
|
||||
if entry.txnId > lastCommitted:
|
||||
lastCommitted = entry.txnId
|
||||
var lastCommitted = rec.lastTxnId
|
||||
|
||||
var redoCount = 0
|
||||
var undoCount = 0
|
||||
@@ -149,11 +148,11 @@ proc recover*(rec: CrashRecovery, db: LSMTree = nil): RecoveryResult =
|
||||
var undoCount = 0
|
||||
for entry in rec.entries:
|
||||
if entry.txnId < analysis.lastTxn:
|
||||
# Committed — redo
|
||||
# Committed — redo (bypass WAL to avoid duplicate entries)
|
||||
if entry.isDelete:
|
||||
db.delete(entry.key)
|
||||
db.deleteUnsafe(entry.key)
|
||||
else:
|
||||
db.put(entry.key, entry.value)
|
||||
db.putUnsafe(entry.key, entry.value)
|
||||
inc redoCount
|
||||
else:
|
||||
# Uncommitted — skip (undo)
|
||||
|
||||
Reference in New Issue
Block a user