fix: deadlock detector, graph/query/lexer бъгове
Поправени проблеми: - Deadlock detector: cycle reconstruction вече проверява пълен цикъл - Graph cypher: executeCypher acquire-ва lock при четене - Graph engine: loadFromFile acquire-ва lock при зареждане - Graph engine: lock поле е exported за външен достъп - Query: parseRowData поддържа escape-ване на , и = в стойности - Query: execUpdateRow escape-ва стойности при сериализация - Lexer: readNumber спира при втора точка (1.2.3 вече не е валиден float) - Lexer: skipBlockComment хвърля ValueError при незатворен коментар 292 теста, 0 failure-а.
This commit is contained in:
@@ -406,14 +406,49 @@ proc getValue(values: seq[string], fields: seq[string], colName: string): string
|
||||
proc isNull*(value: string): bool =
|
||||
value.len == 0 or value.toLower() == "null"
|
||||
|
||||
proc escapeRowVal(v: string): string =
|
||||
v.replace("\\", "\\\\").replace(",", "\\,").replace("=", "\\=")
|
||||
|
||||
proc unescapeRowVal(v: string): string =
|
||||
result = ""
|
||||
var i = 0
|
||||
while i < v.len:
|
||||
if v[i] == '\\' and i + 1 < v.len:
|
||||
case v[i+1]
|
||||
of '\\', ',', '=':
|
||||
result &= v[i+1]
|
||||
i += 2
|
||||
continue
|
||||
else: discard
|
||||
result &= v[i]
|
||||
inc i
|
||||
|
||||
proc parseRowData(valStr: string): Table[string, string] =
|
||||
## Parse "col1=val1,col2=val2" into a table
|
||||
result = initTable[string, string]()
|
||||
for part in valStr.split(","):
|
||||
var i = 0
|
||||
var part = ""
|
||||
while i < valStr.len:
|
||||
if valStr[i] == '\\' and i + 1 < valStr.len:
|
||||
part &= valStr[i]
|
||||
part &= valStr[i+1]
|
||||
i += 2
|
||||
continue
|
||||
if valStr[i] == ',':
|
||||
let eqPos = part.find('=')
|
||||
if eqPos >= 0:
|
||||
let k = part[0..<eqPos].strip()
|
||||
let v = unescapeRowVal(part[eqPos+1..^1].strip())
|
||||
result[k] = v
|
||||
part = ""
|
||||
else:
|
||||
part &= valStr[i]
|
||||
inc i
|
||||
if part.len > 0:
|
||||
let eqPos = part.find('=')
|
||||
if eqPos >= 0:
|
||||
let k = part[0..<eqPos].strip()
|
||||
let v = part[eqPos+1..^1].strip()
|
||||
let v = unescapeRowVal(part[eqPos+1..^1].strip())
|
||||
result[k] = v
|
||||
|
||||
proc executePlan*(ctx: ExecutionContext, plan: IRPlan): seq[Row]
|
||||
@@ -844,7 +879,7 @@ proc execUpdateRow*(ctx: ExecutionContext, table: string, key: string, sets: Tab
|
||||
return 0
|
||||
var parts: seq[string] = @[]
|
||||
for col, val in parsed:
|
||||
parts.add(col & "=" & val)
|
||||
parts.add(col & "=" & escapeRowVal(val))
|
||||
let newVal = parts.join(",")
|
||||
# Update indexes: remove old, insert new
|
||||
for colName in ctx.btrees.keys.toSeq():
|
||||
|
||||
@@ -363,6 +363,7 @@ proc skipBlockComment(l: var Lexer) =
|
||||
discard l.advance()
|
||||
return
|
||||
discard l.advance()
|
||||
raise newException(ValueError, "Unclosed block comment at line " & $l.line & ", col " & $l.col)
|
||||
|
||||
proc readString(l: var Lexer, quote: char): string =
|
||||
result = ""
|
||||
@@ -389,6 +390,8 @@ proc readNumber(l: var Lexer, startLine, startCol: int): Token =
|
||||
var isFloat = false
|
||||
while l.pos < l.input.len and (l.input[l.pos] in Digits or l.input[l.pos] == '.'):
|
||||
if l.input[l.pos] == '.':
|
||||
if isFloat:
|
||||
break # second dot ends the number
|
||||
isFloat = true
|
||||
numStr.add(l.input[l.pos])
|
||||
discard l.advance()
|
||||
|
||||
Reference in New Issue
Block a user