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
|
||||||
@@ -59,168 +59,14 @@ import ../graph/cypher as cyphermod
|
|||||||
import exec/types
|
import exec/types
|
||||||
import exec/values
|
import exec/values
|
||||||
import exec/schema
|
import exec/schema
|
||||||
|
import exec/context
|
||||||
export types
|
export types
|
||||||
export values
|
export values
|
||||||
export schema
|
export schema
|
||||||
|
export context
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
# Context management
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
proc evalNodeToString(node: Node): string
|
proc evalNodeToString(node: Node): string
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Migration Helpers
|
# Migration Helpers
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user