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/context
|
||||
import exec/helpers
|
||||
import exec/params
|
||||
export types
|
||||
export values
|
||||
export schema
|
||||
export context
|
||||
export helpers
|
||||
export params
|
||||
|
||||
proc evalNodeToString(node: Node): string
|
||||
|
||||
@@ -3433,178 +3435,10 @@ proc executePlan*(ctx: ExecutionContext, plan: IRPlan): seq[Row] =
|
||||
else:
|
||||
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
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
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 =
|
||||
if astNode == nil or astNode.stmts.len == 0:
|
||||
return okResult()
|
||||
|
||||
Reference in New Issue
Block a user