refactor(exec): extract context management into exec/context.nim
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
## Execution context lifecycle — creation and per-connection cloning.
|
||||
##
|
||||
## Extracted from `executor.nim` (Task 1 of the executor split).
|
||||
## Also hosts the AST-to-SQL serializer used for VIEW DDL persistence.
|
||||
import std/strutils
|
||||
import std/tables
|
||||
import std/locks
|
||||
import ../ast
|
||||
import ../../storage/lsm
|
||||
import ../../storage/btree
|
||||
import ../../core/mvcc
|
||||
import ../../core/registry
|
||||
import ../../fts/engine as fts
|
||||
import ../../vector/engine as vengine
|
||||
import types
|
||||
import schema
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Context management
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc newExecutionContext*(db: LSMTree, registry: DatabaseRegistry = nil): ExecutionContext =
|
||||
result = ExecutionContext(db: db, tables: initTable[string, TableDef](),
|
||||
btrees: initTable[string, BTreeIndex[string, IndexEntry]](),
|
||||
views: initTable[string, Node](),
|
||||
cteTables: initTable[string, seq[Row]](),
|
||||
ftsIndexes: initTable[string, fts.InvertedIndex](),
|
||||
vectorIndexes: initTable[string, vengine.HNSWIndex](),
|
||||
users: initTable[string, UserDef](),
|
||||
policies: initTable[string, seq[PolicyDef]](),
|
||||
currentUser: "", currentRole: "",
|
||||
sessionVars: initTable[string, string](),
|
||||
autoIncCounters: initTable[string, int64](),
|
||||
sequences: initTable[string, int64](),
|
||||
txnManager: newTxnManager(),
|
||||
onChange: nil,
|
||||
currentDatabase: "default",
|
||||
registry: registry)
|
||||
result.sharedLock = SharedLock()
|
||||
initLock(result.sharedLock.lock)
|
||||
restoreSchema(result)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# AST to SQL serializer (for VIEW DDL persistence)
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
proc exprToSql*(node: Node): string =
|
||||
if node == nil:
|
||||
return ""
|
||||
case node.kind
|
||||
of nkIntLit:
|
||||
return $node.intVal
|
||||
of nkFloatLit:
|
||||
return $node.floatVal
|
||||
of nkStringLit:
|
||||
return "'" & node.strVal.replace("'", "''") & "'"
|
||||
of nkBoolLit:
|
||||
return if node.boolVal: "true" else: "false"
|
||||
of nkNullLit:
|
||||
return "null"
|
||||
of nkIdent:
|
||||
return "\"" & node.identName.replace("\"", "\"\"") & "\""
|
||||
of nkStar:
|
||||
return "*"
|
||||
of nkBinOp:
|
||||
let opStr = case node.binOp
|
||||
of bkEq: "="
|
||||
of bkNotEq: "!="
|
||||
of bkLt: "<"
|
||||
of bkLtEq: "<="
|
||||
of bkGt: ">"
|
||||
of bkGtEq: ">="
|
||||
of bkAnd: " AND "
|
||||
of bkOr: " OR "
|
||||
of bkAdd: " + "
|
||||
of bkSub: " - "
|
||||
of bkMul: " * "
|
||||
of bkDiv: " / "
|
||||
else: " " & $node.binOp & " "
|
||||
return exprToSql(node.binLeft) & opStr & exprToSql(node.binRight)
|
||||
of nkFuncCall:
|
||||
if node.funcArgs.len > 0:
|
||||
return node.funcName & "(" & exprToSql(node.funcArgs[0]) & ")"
|
||||
else:
|
||||
return node.funcName & "()"
|
||||
of nkUnaryOp:
|
||||
return $node.unOp & " " & exprToSql(node.unOperand)
|
||||
of nkPath:
|
||||
return node.pathParts.join(".")
|
||||
else:
|
||||
return $node.kind
|
||||
|
||||
proc selectToSql*(node: Node): string =
|
||||
if node == nil:
|
||||
return ""
|
||||
result = "SELECT "
|
||||
# Column list
|
||||
for i, e in node.selResult:
|
||||
if i > 0: result.add(", ")
|
||||
result.add(exprToSql(e))
|
||||
if e.exprAlias.len > 0:
|
||||
result.add(" AS " & e.exprAlias)
|
||||
# FROM
|
||||
if node.selFrom != nil and node.selFrom.kind == nkFrom and node.selFrom.fromTable.len > 0:
|
||||
result.add(" FROM " & node.selFrom.fromTable)
|
||||
if node.selFrom.fromAlias.len > 0:
|
||||
result.add(" AS " & node.selFrom.fromAlias)
|
||||
# JOINs
|
||||
for j in node.selJoins:
|
||||
if j.kind == nkJoin:
|
||||
let jkStr = case j.joinKind
|
||||
of jkInner: "INNER JOIN"
|
||||
of jkLeft: "LEFT JOIN"
|
||||
of jkRight: "RIGHT JOIN"
|
||||
of jkFull: "FULL JOIN"
|
||||
of jkCross: "CROSS JOIN"
|
||||
if j.joinLateral:
|
||||
result.add(" " & jkStr & " LATERAL (subquery)")
|
||||
else:
|
||||
result.add(" " & jkStr & " " & j.joinTarget.fromTable)
|
||||
if j.joinAlias.len > 0:
|
||||
result.add(" AS " & j.joinAlias)
|
||||
if j.joinOn != nil:
|
||||
result.add(" ON " & exprToSql(j.joinOn))
|
||||
# WHERE
|
||||
if node.selWhere != nil and node.selWhere.whereExpr != nil:
|
||||
result.add(" WHERE " & exprToSql(node.selWhere.whereExpr))
|
||||
# GROUP BY
|
||||
if node.selGroupBy.len > 0:
|
||||
result.add(" GROUP BY ")
|
||||
for i, g in node.selGroupBy:
|
||||
if i > 0: result.add(", ")
|
||||
result.add(exprToSql(g))
|
||||
# HAVING
|
||||
if node.selHaving != nil and node.selHaving.havingExpr != nil:
|
||||
result.add(" HAVING " & exprToSql(node.selHaving.havingExpr))
|
||||
# ORDER BY
|
||||
if node.selOrderBy.len > 0:
|
||||
result.add(" ORDER BY ")
|
||||
for i, o in node.selOrderBy:
|
||||
if i > 0: result.add(", ")
|
||||
result.add(exprToSql(o.orderByExpr))
|
||||
if o.orderByDir == sdDesc:
|
||||
result.add(" DESC")
|
||||
# LIMIT / OFFSET
|
||||
if node.selLimit != nil and node.selLimit.limitExpr.kind == nkIntLit:
|
||||
result.add(" LIMIT " & $node.selLimit.limitExpr.intVal)
|
||||
if node.selOffset != nil and node.selOffset.offsetExpr.kind == nkIntLit:
|
||||
result.add(" OFFSET " & $node.selOffset.offsetExpr.intVal)
|
||||
|
||||
proc cloneForConnection*(ctx: ExecutionContext): ExecutionContext =
|
||||
var svCopy = initTable[string, string]()
|
||||
for k, v in ctx.sessionVars:
|
||||
svCopy[k] = v
|
||||
result = ExecutionContext(db: ctx.db, tables: ctx.tables,
|
||||
btrees: ctx.btrees, views: ctx.views,
|
||||
cteTables: initTable[string, seq[Row]](),
|
||||
ftsIndexes: ctx.ftsIndexes,
|
||||
vectorIndexes: ctx.vectorIndexes,
|
||||
graphs: ctx.graphs,
|
||||
users: ctx.users, policies: ctx.policies,
|
||||
txnManager: ctx.txnManager,
|
||||
currentUser: ctx.currentUser, currentRole: ctx.currentRole,
|
||||
sessionVars: svCopy,
|
||||
autoIncCounters: ctx.autoIncCounters,
|
||||
sequences: ctx.sequences,
|
||||
pendingTxn: nil, onChange: ctx.onChange,
|
||||
embedder: ctx.embedder,
|
||||
llmClient: ctx.llmClient,
|
||||
currentDatabase: ctx.currentDatabase,
|
||||
registry: ctx.registry)
|
||||
result.sharedLock = ctx.sharedLock
|
||||
Reference in New Issue
Block a user