fix(executor): handle subqueries in comparisons and per-row UPDATE expressions
- Add missing nkSubquery case in lowerExpr so scalar subqueries (e.g. budget > (SELECT AVG(budget) FROM projects)) are lowered correctly instead of being treated as NULL literals. - Move UPDATE SET expression evaluation inside the row loop so column references (e.g. salary + 5000) are resolved against the current row, fixing type validation failures. - Make irAdd/irSub/irMul/irDiv return integer strings when the result is a whole number, avoiding spurious float output for INT columns (e.g. MERGE UPDATE qty = 100 + 50 now yields 150). These fix regressions introduced by switching NULL representation from empty string to \N, which exposed the pre-existing bugs above. Refs: issue #9, issue #10
This commit is contained in:
@@ -581,18 +581,34 @@ proc evalExpr*(expr: IRExpr, row: Table[string, string], ctx: ExecutionContext =
|
||||
if left == "true" or right == "true": return "true"
|
||||
return "false"
|
||||
of irAdd:
|
||||
try: return $(parseFloat(left) + parseFloat(right))
|
||||
try:
|
||||
let sum = parseFloat(left) + parseFloat(right)
|
||||
if sum == float(int(sum)):
|
||||
return $int(sum)
|
||||
return $sum
|
||||
except: return left & right
|
||||
of irSub:
|
||||
try: return $(parseFloat(left) - parseFloat(right))
|
||||
try:
|
||||
let diff = parseFloat(left) - parseFloat(right)
|
||||
if diff == float(int(diff)):
|
||||
return $int(diff)
|
||||
return $diff
|
||||
except: return "0"
|
||||
of irMul:
|
||||
try: return $(parseFloat(left) * parseFloat(right))
|
||||
try:
|
||||
let prod = parseFloat(left) * parseFloat(right)
|
||||
if prod == float(int(prod)):
|
||||
return $int(prod)
|
||||
return $prod
|
||||
except: return "0"
|
||||
of irDiv:
|
||||
try:
|
||||
let r = parseFloat(right)
|
||||
if r != 0: return $(parseFloat(left) / r)
|
||||
if r != 0:
|
||||
let quot = parseFloat(left) / r
|
||||
if quot == float(int(quot)):
|
||||
return $int(quot)
|
||||
return $quot
|
||||
return "0"
|
||||
except: return "0"
|
||||
of irMod:
|
||||
@@ -1528,6 +1544,9 @@ proc lowerExpr*(node: Node): IRExpr =
|
||||
result.binRight = lowerExpr(node.inRight)
|
||||
of nkExists:
|
||||
result = IRExpr(kind: irekExists)
|
||||
of nkSubquery:
|
||||
result = IRExpr(kind: irekSubquery)
|
||||
result.subqueryPlan = lowerSelect(node.subQuery)
|
||||
of nkStar:
|
||||
result = IRExpr(kind: irekStar)
|
||||
of nkWindowExpr:
|
||||
@@ -3166,23 +3185,23 @@ proc executeQuery*(ctx: ExecutionContext, astNode: Node, params: seq[WireValue]
|
||||
of nkUpdate:
|
||||
if stmt.updSet.len == 0: return okResult()
|
||||
# Simple UPDATE: scan table, filter by WHERE, apply SET
|
||||
var sets = initTable[string, string]()
|
||||
for s in stmt.updSet:
|
||||
if s.kind == nkBinOp and s.binOp == bkAssign:
|
||||
if s.binLeft.kind == nkIdent:
|
||||
let val = if s.binRight.kind == nkStringLit: s.binRight.strVal
|
||||
elif s.binRight.kind == nkIntLit: $s.binRight.intVal
|
||||
elif s.binRight.kind == nkFloatLit: $s.binRight.floatVal
|
||||
elif s.binRight.kind == nkBoolLit: $s.binRight.boolVal
|
||||
elif s.binRight.kind == nkNullLit: "\\N"
|
||||
else: evalNodeToString(s.binRight)
|
||||
sets[s.binLeft.identName] = val
|
||||
|
||||
# Scan and apply
|
||||
let rows = execScan(ctx, stmt.updTarget)
|
||||
var count = 0
|
||||
var kvPairs: seq[(string, seq[byte])]
|
||||
for row in rows:
|
||||
# Compute sets for this row (expressions may reference columns)
|
||||
var sets = initTable[string, string]()
|
||||
for s in stmt.updSet:
|
||||
if s.kind == nkBinOp and s.binOp == bkAssign:
|
||||
if s.binLeft.kind == nkIdent:
|
||||
let val = if s.binRight.kind == nkStringLit: s.binRight.strVal
|
||||
elif s.binRight.kind == nkIntLit: $s.binRight.intVal
|
||||
elif s.binRight.kind == nkFloatLit: $s.binRight.floatVal
|
||||
elif s.binRight.kind == nkBoolLit: $s.binRight.boolVal
|
||||
elif s.binRight.kind == nkNullLit: "\\N"
|
||||
else: evalExpr(lowerExpr(s.binRight), row, ctx)
|
||||
sets[s.binLeft.identName] = val
|
||||
# Check WHERE
|
||||
if stmt.updWhere != nil and stmt.updWhere.whereExpr != nil:
|
||||
let whereExpr = lowerExpr(stmt.updWhere.whereExpr)
|
||||
|
||||
+1
-1
@@ -2997,7 +2997,7 @@ suite "MERGE Statement":
|
||||
check r.success
|
||||
check r.affectedRows == 1
|
||||
let verify = qexec.executeQuery(ctx, parse("SELECT * FROM inventory WHERE sku = 'SKU001'"))
|
||||
check verify.rows[0]["qty"] == "150.0"
|
||||
check verify.rows[0]["qty"] == "150"
|
||||
|
||||
test "MERGE WHEN NOT MATCHED INSERT":
|
||||
let r = qexec.executeQuery(ctx, parse("""
|
||||
|
||||
Reference in New Issue
Block a user