refactor(exec): extract param binding into exec/params.nim
This commit is contained in:
@@ -0,0 +1,180 @@
|
|||||||
|
## Parameter binding — placeholder substitution and statement column metadata.
|
||||||
|
##
|
||||||
|
## Extracted from `executor.nim` (Task 3 of the executor split).
|
||||||
|
import std/strutils
|
||||||
|
import std/tables
|
||||||
|
import ../ast
|
||||||
|
import ../../protocol/wire
|
||||||
|
import context
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Parameter binding
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc doBindParams(node: Node, params: seq[WireValue], idx: var int): Node =
|
||||||
|
if node == nil: return nil
|
||||||
|
case node.kind
|
||||||
|
of nkPlaceholder:
|
||||||
|
if idx < params.len:
|
||||||
|
let p = params[idx]
|
||||||
|
inc idx
|
||||||
|
case p.kind
|
||||||
|
of fkString: return Node(kind: nkStringLit, strVal: p.strVal)
|
||||||
|
of fkInt64: return Node(kind: nkIntLit, intVal: int(p.int64Val))
|
||||||
|
of fkInt32: return Node(kind: nkIntLit, intVal: int(p.int32Val))
|
||||||
|
of fkInt16: return Node(kind: nkIntLit, intVal: int(p.int16Val))
|
||||||
|
of fkInt8: return Node(kind: nkIntLit, intVal: int(p.int8Val))
|
||||||
|
of fkFloat64: return Node(kind: nkFloatLit, floatVal: p.float64Val)
|
||||||
|
of fkFloat32: return Node(kind: nkFloatLit, floatVal: float(p.float32Val))
|
||||||
|
of fkBool: return Node(kind: nkBoolLit, boolVal: p.boolVal)
|
||||||
|
of fkNull: return Node(kind: nkNullLit)
|
||||||
|
else: return Node(kind: nkNullLit)
|
||||||
|
else:
|
||||||
|
return Node(kind: nkNullLit)
|
||||||
|
of nkBinOp:
|
||||||
|
result = Node(kind: nkBinOp, binOp: node.binOp,
|
||||||
|
line: node.line, col: node.col)
|
||||||
|
result.binLeft = doBindParams(node.binLeft, params, idx)
|
||||||
|
result.binRight = doBindParams(node.binRight, params, idx)
|
||||||
|
of nkUnaryOp:
|
||||||
|
result = Node(kind: nkUnaryOp, unOp: node.unOp,
|
||||||
|
line: node.line, col: node.col)
|
||||||
|
result.unOperand = doBindParams(node.unOperand, params, idx)
|
||||||
|
of nkFuncCall:
|
||||||
|
result = Node(kind: nkFuncCall, funcName: node.funcName,
|
||||||
|
line: node.line, col: node.col)
|
||||||
|
result.funcArgs = @[]
|
||||||
|
for arg in node.funcArgs:
|
||||||
|
result.funcArgs.add(doBindParams(arg, params, idx))
|
||||||
|
of nkArrayLit:
|
||||||
|
result = Node(kind: nkArrayLit, line: node.line, col: node.col)
|
||||||
|
result.arrayElems = @[]
|
||||||
|
for e in node.arrayElems:
|
||||||
|
result.arrayElems.add(doBindParams(e, params, idx))
|
||||||
|
of nkStatementList:
|
||||||
|
result = Node(kind: nkStatementList, line: node.line, col: node.col)
|
||||||
|
result.stmts = @[]
|
||||||
|
for s in node.stmts:
|
||||||
|
result.stmts.add(doBindParams(s, params, idx))
|
||||||
|
of nkSelect:
|
||||||
|
result = Node(kind: nkSelect, line: node.line, col: node.col)
|
||||||
|
result.selDistinct = node.selDistinct
|
||||||
|
result.selResult = @[]
|
||||||
|
for e in node.selResult:
|
||||||
|
result.selResult.add(doBindParams(e, params, idx))
|
||||||
|
result.selFrom = node.selFrom # FROM doesn't have placeholders
|
||||||
|
result.selJoins = @[]
|
||||||
|
for j in node.selJoins:
|
||||||
|
var nj = Node(kind: nkJoin, joinKind: j.joinKind,
|
||||||
|
joinTarget: j.joinTarget, joinAlias: j.joinAlias,
|
||||||
|
line: j.line, col: j.col)
|
||||||
|
nj.joinOn = doBindParams(j.joinOn, params, idx)
|
||||||
|
result.selJoins.add(nj)
|
||||||
|
result.selWhere = doBindParams(node.selWhere, params, idx)
|
||||||
|
result.selGroupBy = @[]
|
||||||
|
for g in node.selGroupBy:
|
||||||
|
result.selGroupBy.add(doBindParams(g, params, idx))
|
||||||
|
result.selHaving = doBindParams(node.selHaving, params, idx)
|
||||||
|
result.selOrderBy = @[]
|
||||||
|
for o in node.selOrderBy:
|
||||||
|
var no = Node(kind: nkOrderBy, orderByDir: o.orderByDir,
|
||||||
|
line: o.line, col: o.col)
|
||||||
|
no.orderByExpr = doBindParams(o.orderByExpr, params, idx)
|
||||||
|
result.selOrderBy.add(no)
|
||||||
|
result.selLimit = doBindParams(node.selLimit, params, idx)
|
||||||
|
result.selOffset = doBindParams(node.selOffset, params, idx)
|
||||||
|
of nkInsert:
|
||||||
|
result = Node(kind: nkInsert, insTarget: node.insTarget,
|
||||||
|
line: node.line, col: node.col)
|
||||||
|
result.insFields = node.insFields
|
||||||
|
result.insValues = @[]
|
||||||
|
for v in node.insValues:
|
||||||
|
result.insValues.add(doBindParams(v, params, idx))
|
||||||
|
result.insReturning = node.insReturning
|
||||||
|
of nkUpdate:
|
||||||
|
result = Node(kind: nkUpdate, updTarget: node.updTarget,
|
||||||
|
updAlias: node.updAlias, line: node.line, col: node.col)
|
||||||
|
result.updSet = @[]
|
||||||
|
for s in node.updSet:
|
||||||
|
var ns = Node(kind: nkBinOp, binOp: s.binOp, line: s.line, col: s.col)
|
||||||
|
ns.binLeft = s.binLeft
|
||||||
|
ns.binRight = doBindParams(s.binRight, params, idx)
|
||||||
|
result.updSet.add(ns)
|
||||||
|
result.updWhere = doBindParams(node.updWhere, params, idx)
|
||||||
|
result.updReturning = node.updReturning
|
||||||
|
of nkWhere:
|
||||||
|
result = Node(kind: nkWhere, line: node.line, col: node.col)
|
||||||
|
result.whereExpr = doBindParams(node.whereExpr, params, idx)
|
||||||
|
of nkHaving:
|
||||||
|
result = Node(kind: nkHaving, line: node.line, col: node.col)
|
||||||
|
result.havingExpr = doBindParams(node.havingExpr, params, idx)
|
||||||
|
of nkLimit:
|
||||||
|
result = Node(kind: nkLimit, line: node.line, col: node.col)
|
||||||
|
result.limitExpr = doBindParams(node.limitExpr, params, idx)
|
||||||
|
of nkOffset:
|
||||||
|
result = Node(kind: nkOffset, line: node.line, col: node.col)
|
||||||
|
result.offsetExpr = doBindParams(node.offsetExpr, params, idx)
|
||||||
|
of nkReturning:
|
||||||
|
result = Node(kind: nkReturning, line: node.line, col: node.col)
|
||||||
|
result.retExprs = @[]
|
||||||
|
for e in node.retExprs:
|
||||||
|
result.retExprs.add(doBindParams(e, params, idx))
|
||||||
|
of nkDelete:
|
||||||
|
result = Node(kind: nkDelete, delTarget: node.delTarget,
|
||||||
|
delAlias: node.delAlias, line: node.line, col: node.col)
|
||||||
|
result.delWhere = doBindParams(node.delWhere, params, idx)
|
||||||
|
result.delReturning = node.delReturning
|
||||||
|
else:
|
||||||
|
result = node
|
||||||
|
|
||||||
|
proc bindParams*(node: Node, params: seq[WireValue]): Node =
|
||||||
|
var idx = 0
|
||||||
|
result = doBindParams(node, params, idx)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Statement metadata
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc getSelectColumns*(stmt: Node): seq[string] =
|
||||||
|
result = @[]
|
||||||
|
if stmt.kind != nkSelect: return result
|
||||||
|
var seenAliases = initTable[string, int]()
|
||||||
|
for i, e in stmt.selResult:
|
||||||
|
var alias = ""
|
||||||
|
if e.exprAlias.len > 0:
|
||||||
|
alias = e.exprAlias
|
||||||
|
elif e.kind == nkIdent:
|
||||||
|
alias = e.identName
|
||||||
|
elif e.kind == nkPath and e.pathParts.len > 0:
|
||||||
|
alias = e.pathParts.join(".")
|
||||||
|
elif e.kind == nkFuncCall:
|
||||||
|
var aliasArgs: seq[string] = @[]
|
||||||
|
for arg in e.funcArgs:
|
||||||
|
aliasArgs.add(exprToSql(arg))
|
||||||
|
alias = e.funcName & "(" & aliasArgs.join(", ") & ")"
|
||||||
|
elif e.kind == nkStar:
|
||||||
|
alias = "*"
|
||||||
|
else:
|
||||||
|
alias = "col" & $i
|
||||||
|
if alias in seenAliases:
|
||||||
|
seenAliases[alias] += 1
|
||||||
|
alias = alias & "_" & $seenAliases[alias]
|
||||||
|
else:
|
||||||
|
seenAliases[alias] = 0
|
||||||
|
result.add(alias)
|
||||||
|
|
||||||
|
proc isDDL*(stmt: Node): bool =
|
||||||
|
case stmt.kind
|
||||||
|
of nkCreateTable, nkDropTable, nkAlterTable,
|
||||||
|
nkCreateView, nkDropView,
|
||||||
|
nkCreateIndex, nkDropIndex,
|
||||||
|
nkCreateTrigger, nkDropTrigger,
|
||||||
|
nkCreateUser, nkDropUser,
|
||||||
|
nkCreatePolicy, nkDropPolicy,
|
||||||
|
nkCreateGraph, nkDropGraph,
|
||||||
|
nkCreateDatabase, nkDropDatabase,
|
||||||
|
nkGrant, nkRevoke,
|
||||||
|
nkEnableRLS, nkDisableRLS:
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
result = false
|
||||||
@@ -44,11 +44,13 @@ import exec/values
|
|||||||
import exec/schema
|
import exec/schema
|
||||||
import exec/context
|
import exec/context
|
||||||
import exec/helpers
|
import exec/helpers
|
||||||
|
import exec/params
|
||||||
export types
|
export types
|
||||||
export values
|
export values
|
||||||
export schema
|
export schema
|
||||||
export context
|
export context
|
||||||
export helpers
|
export helpers
|
||||||
|
export params
|
||||||
|
|
||||||
proc evalNodeToString(node: Node): string
|
proc evalNodeToString(node: Node): string
|
||||||
|
|
||||||
@@ -3433,178 +3435,10 @@ proc executePlan*(ctx: ExecutionContext, plan: IRPlan): seq[Row] =
|
|||||||
else:
|
else:
|
||||||
return @[]
|
return @[]
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Parameter binding
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
proc doBindParams(node: Node, params: seq[WireValue], idx: var int): Node =
|
|
||||||
if node == nil: return nil
|
|
||||||
case node.kind
|
|
||||||
of nkPlaceholder:
|
|
||||||
if idx < params.len:
|
|
||||||
let p = params[idx]
|
|
||||||
inc idx
|
|
||||||
case p.kind
|
|
||||||
of fkString: return Node(kind: nkStringLit, strVal: p.strVal)
|
|
||||||
of fkInt64: return Node(kind: nkIntLit, intVal: int(p.int64Val))
|
|
||||||
of fkInt32: return Node(kind: nkIntLit, intVal: int(p.int32Val))
|
|
||||||
of fkInt16: return Node(kind: nkIntLit, intVal: int(p.int16Val))
|
|
||||||
of fkInt8: return Node(kind: nkIntLit, intVal: int(p.int8Val))
|
|
||||||
of fkFloat64: return Node(kind: nkFloatLit, floatVal: p.float64Val)
|
|
||||||
of fkFloat32: return Node(kind: nkFloatLit, floatVal: float(p.float32Val))
|
|
||||||
of fkBool: return Node(kind: nkBoolLit, boolVal: p.boolVal)
|
|
||||||
of fkNull: return Node(kind: nkNullLit)
|
|
||||||
else: return Node(kind: nkNullLit)
|
|
||||||
else:
|
|
||||||
return Node(kind: nkNullLit)
|
|
||||||
of nkBinOp:
|
|
||||||
result = Node(kind: nkBinOp, binOp: node.binOp,
|
|
||||||
line: node.line, col: node.col)
|
|
||||||
result.binLeft = doBindParams(node.binLeft, params, idx)
|
|
||||||
result.binRight = doBindParams(node.binRight, params, idx)
|
|
||||||
of nkUnaryOp:
|
|
||||||
result = Node(kind: nkUnaryOp, unOp: node.unOp,
|
|
||||||
line: node.line, col: node.col)
|
|
||||||
result.unOperand = doBindParams(node.unOperand, params, idx)
|
|
||||||
of nkFuncCall:
|
|
||||||
result = Node(kind: nkFuncCall, funcName: node.funcName,
|
|
||||||
line: node.line, col: node.col)
|
|
||||||
result.funcArgs = @[]
|
|
||||||
for arg in node.funcArgs:
|
|
||||||
result.funcArgs.add(doBindParams(arg, params, idx))
|
|
||||||
of nkArrayLit:
|
|
||||||
result = Node(kind: nkArrayLit, line: node.line, col: node.col)
|
|
||||||
result.arrayElems = @[]
|
|
||||||
for e in node.arrayElems:
|
|
||||||
result.arrayElems.add(doBindParams(e, params, idx))
|
|
||||||
of nkStatementList:
|
|
||||||
result = Node(kind: nkStatementList, line: node.line, col: node.col)
|
|
||||||
result.stmts = @[]
|
|
||||||
for s in node.stmts:
|
|
||||||
result.stmts.add(doBindParams(s, params, idx))
|
|
||||||
of nkSelect:
|
|
||||||
result = Node(kind: nkSelect, line: node.line, col: node.col)
|
|
||||||
result.selDistinct = node.selDistinct
|
|
||||||
result.selResult = @[]
|
|
||||||
for e in node.selResult:
|
|
||||||
result.selResult.add(doBindParams(e, params, idx))
|
|
||||||
result.selFrom = node.selFrom # FROM doesn't have placeholders
|
|
||||||
result.selJoins = @[]
|
|
||||||
for j in node.selJoins:
|
|
||||||
var nj = Node(kind: nkJoin, joinKind: j.joinKind,
|
|
||||||
joinTarget: j.joinTarget, joinAlias: j.joinAlias,
|
|
||||||
line: j.line, col: j.col)
|
|
||||||
nj.joinOn = doBindParams(j.joinOn, params, idx)
|
|
||||||
result.selJoins.add(nj)
|
|
||||||
result.selWhere = doBindParams(node.selWhere, params, idx)
|
|
||||||
result.selGroupBy = @[]
|
|
||||||
for g in node.selGroupBy:
|
|
||||||
result.selGroupBy.add(doBindParams(g, params, idx))
|
|
||||||
result.selHaving = doBindParams(node.selHaving, params, idx)
|
|
||||||
result.selOrderBy = @[]
|
|
||||||
for o in node.selOrderBy:
|
|
||||||
var no = Node(kind: nkOrderBy, orderByDir: o.orderByDir,
|
|
||||||
line: o.line, col: o.col)
|
|
||||||
no.orderByExpr = doBindParams(o.orderByExpr, params, idx)
|
|
||||||
result.selOrderBy.add(no)
|
|
||||||
result.selLimit = doBindParams(node.selLimit, params, idx)
|
|
||||||
result.selOffset = doBindParams(node.selOffset, params, idx)
|
|
||||||
of nkInsert:
|
|
||||||
result = Node(kind: nkInsert, insTarget: node.insTarget,
|
|
||||||
line: node.line, col: node.col)
|
|
||||||
result.insFields = node.insFields
|
|
||||||
result.insValues = @[]
|
|
||||||
for v in node.insValues:
|
|
||||||
result.insValues.add(doBindParams(v, params, idx))
|
|
||||||
result.insReturning = node.insReturning
|
|
||||||
of nkUpdate:
|
|
||||||
result = Node(kind: nkUpdate, updTarget: node.updTarget,
|
|
||||||
updAlias: node.updAlias, line: node.line, col: node.col)
|
|
||||||
result.updSet = @[]
|
|
||||||
for s in node.updSet:
|
|
||||||
var ns = Node(kind: nkBinOp, binOp: s.binOp, line: s.line, col: s.col)
|
|
||||||
ns.binLeft = s.binLeft
|
|
||||||
ns.binRight = doBindParams(s.binRight, params, idx)
|
|
||||||
result.updSet.add(ns)
|
|
||||||
result.updWhere = doBindParams(node.updWhere, params, idx)
|
|
||||||
result.updReturning = node.updReturning
|
|
||||||
of nkWhere:
|
|
||||||
result = Node(kind: nkWhere, line: node.line, col: node.col)
|
|
||||||
result.whereExpr = doBindParams(node.whereExpr, params, idx)
|
|
||||||
of nkHaving:
|
|
||||||
result = Node(kind: nkHaving, line: node.line, col: node.col)
|
|
||||||
result.havingExpr = doBindParams(node.havingExpr, params, idx)
|
|
||||||
of nkLimit:
|
|
||||||
result = Node(kind: nkLimit, line: node.line, col: node.col)
|
|
||||||
result.limitExpr = doBindParams(node.limitExpr, params, idx)
|
|
||||||
of nkOffset:
|
|
||||||
result = Node(kind: nkOffset, line: node.line, col: node.col)
|
|
||||||
result.offsetExpr = doBindParams(node.offsetExpr, params, idx)
|
|
||||||
of nkReturning:
|
|
||||||
result = Node(kind: nkReturning, line: node.line, col: node.col)
|
|
||||||
result.retExprs = @[]
|
|
||||||
for e in node.retExprs:
|
|
||||||
result.retExprs.add(doBindParams(e, params, idx))
|
|
||||||
of nkDelete:
|
|
||||||
result = Node(kind: nkDelete, delTarget: node.delTarget,
|
|
||||||
delAlias: node.delAlias, line: node.line, col: node.col)
|
|
||||||
result.delWhere = doBindParams(node.delWhere, params, idx)
|
|
||||||
result.delReturning = node.delReturning
|
|
||||||
else:
|
|
||||||
result = node
|
|
||||||
|
|
||||||
proc bindParams*(node: Node, params: seq[WireValue]): Node =
|
|
||||||
var idx = 0
|
|
||||||
result = doBindParams(node, params, idx)
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# High-level execute
|
# High-level execute
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
proc getSelectColumns(stmt: Node): seq[string] =
|
|
||||||
result = @[]
|
|
||||||
if stmt.kind != nkSelect: return result
|
|
||||||
var seenAliases = initTable[string, int]()
|
|
||||||
for i, e in stmt.selResult:
|
|
||||||
var alias = ""
|
|
||||||
if e.exprAlias.len > 0:
|
|
||||||
alias = e.exprAlias
|
|
||||||
elif e.kind == nkIdent:
|
|
||||||
alias = e.identName
|
|
||||||
elif e.kind == nkPath and e.pathParts.len > 0:
|
|
||||||
alias = e.pathParts.join(".")
|
|
||||||
elif e.kind == nkFuncCall:
|
|
||||||
var aliasArgs: seq[string] = @[]
|
|
||||||
for arg in e.funcArgs:
|
|
||||||
aliasArgs.add(exprToSql(arg))
|
|
||||||
alias = e.funcName & "(" & aliasArgs.join(", ") & ")"
|
|
||||||
elif e.kind == nkStar:
|
|
||||||
alias = "*"
|
|
||||||
else:
|
|
||||||
alias = "col" & $i
|
|
||||||
if alias in seenAliases:
|
|
||||||
seenAliases[alias] += 1
|
|
||||||
alias = alias & "_" & $seenAliases[alias]
|
|
||||||
else:
|
|
||||||
seenAliases[alias] = 0
|
|
||||||
result.add(alias)
|
|
||||||
|
|
||||||
proc isDDL(stmt: Node): bool =
|
|
||||||
case stmt.kind
|
|
||||||
of nkCreateTable, nkDropTable, nkAlterTable,
|
|
||||||
nkCreateView, nkDropView,
|
|
||||||
nkCreateIndex, nkDropIndex,
|
|
||||||
nkCreateTrigger, nkDropTrigger,
|
|
||||||
nkCreateUser, nkDropUser,
|
|
||||||
nkCreatePolicy, nkDropPolicy,
|
|
||||||
nkCreateGraph, nkDropGraph,
|
|
||||||
nkCreateDatabase, nkDropDatabase,
|
|
||||||
nkGrant, nkRevoke,
|
|
||||||
nkEnableRLS, nkDisableRLS:
|
|
||||||
result = true
|
|
||||||
else:
|
|
||||||
result = false
|
|
||||||
|
|
||||||
proc executeQueryImpl(ctx: ExecutionContext, astNode: Node, params: seq[WireValue] = @[]): ExecResult =
|
proc executeQueryImpl(ctx: ExecutionContext, astNode: Node, params: seq[WireValue] = @[]): ExecResult =
|
||||||
if astNode == nil or astNode.stmts.len == 0:
|
if astNode == nil or astNode.stmts.len == 0:
|
||||||
return okResult()
|
return okResult()
|
||||||
|
|||||||
Reference in New Issue
Block a user