Files
Baradb/src/barabadb/query/ir.nim
T
dimgigov 6aaabb518d fix: високо и средно приоритетни бъгове в query, protocol, storage, vector, fts
Поправени проблеми:
- Wire protocol: bounds checking, max length limits, recursion depth limit
- SQL injection: escape-ване на quotes в exprToSql string literals
- ReDoS: escape-ване на regex metachars в LIKE/ILIKE
- Stale BTree indexes: добавен BTree.remove() + изтриване при UPDATE/DELETE
- SSL: quoteShell за всички shell команди с пътища
- Boolean literals: parser вече разпознава tkTrue/tkFalse
- Unary minus: lowerExpr map-ва ukNeg към irNeg (вместо irNot)
- Non-aggregate UDFs: lowerExpr създава irekFuncCall вместо NULL literal
- UTF-8 FTS: tokenize използва runes вместо байтове
- HNSW: добавен Lock за thread-safe insert/search

292 теста, 0 failure-а.
2026-05-12 23:02:54 +03:00

258 lines
6.4 KiB
Nim

## BaraQL IR — Intermediate Representation for compilation
import std/tables
import ../core/types
type
IRTypeKind* = enum
itkScalar
itkObject
itkArray
itkSet
itkOptional
itkFunction
IRType* = ref object
name*: string
kind*: IRTypeKind
fields*: Table[string, IRType]
isNullable*: bool
elementType*: IRType
IROperator* = enum
irAdd, irSub, irMul, irDiv, irMod, irPow
irEq, irNeq, irLt, irLte, irGt, irGte
irAnd, irOr, irNot, irNeg
irIn, irNotIn
irLike, irILike
irBetween
irIsNull, irIsNotNull
irFtsMatch
IRAggregate* = enum
irCount, irSum, irAvg, irMin, irMax
IRLiteral* = object
case kind*: ValueKind
of vkNull: discard
of vkBool: boolVal*: bool
of vkInt64: int64Val*: int64
of vkFloat64: float64Val*: float64
of vkString: strVal*: string
else: discard
IRExprKind* = enum
irekLiteral
irekField
irekUnary
irekBinary
irekAggregate
irekFuncCall
irekCast
irekConditional
irekExists
irekStar
irekJsonPath
IRJoinKind* = enum
irjkInner
irjkLeft
irjkRight
irjkFull
irjkCross
IRPlanKind* = enum
irpkScan
irpkFilter
irpkProject
irpkGroupBy
irpkJoin
irpkSort
irpkLimit
irpkInsert
irpkUpdate
irpkDelete
irpkCreateType
irpkUnion
irpkCTE
irpkValues
irpkExplain
IRPlan* = ref object
case kind*: IRPlanKind
of irpkScan:
scanTable*: string
scanAlias*: string
of irpkFilter:
filterSource*: IRPlan
filterCond*: IRExpr
of irpkProject:
projectSource*: IRPlan
projectExprs*: seq[IRExpr]
projectAliases*: seq[string]
of irpkGroupBy:
groupSource*: IRPlan
groupKeys*: seq[IRExpr]
groupAggs*: seq[IRExpr]
groupHaving*: IRExpr
of irpkJoin:
joinKind*: IRJoinKind
joinLeft*: IRPlan
joinRight*: IRPlan
joinCond*: IRExpr
joinAlias*: string
of irpkSort:
sortSource*: IRPlan
sortExprs*: seq[IRExpr]
sortDirs*: seq[bool]
of irpkLimit:
limitSource*: IRPlan
limitCount*: int64
limitOffset*: int64
of irpkInsert:
insertTable*: string
insertFields*: seq[string]
insertValues*: seq[seq[IRExpr]]
of irpkUpdate:
updateTable*: string
updateAlias*: string
updateSets*: seq[(string, IRExpr)]
updateSource*: IRPlan
of irpkDelete:
deleteTable*: string
deleteAlias*: string
deleteSource*: IRPlan
of irpkCreateType:
createTypeName*: string
createTypeDef*: IRType
of irpkUnion:
unionLeft*: IRPlan
unionRight*: IRPlan
unionAll*: bool
of irpkCTE:
cteName*: string
cteQuery*: IRPlan
cteMain*: IRPlan
of irpkValues:
valuesRows*: seq[seq[IRExpr]]
of irpkExplain:
explainPlan*: IRPlan
IRExpr* = ref object
case kind*: IRExprKind
of irekLiteral:
literal*: IRLiteral
of irekField:
fieldPath*: seq[string]
of irekUnary:
unOp*: IROperator
unExpr*: IRExpr
of irekBinary:
binOp*: IROperator
binLeft*: IRExpr
binRight*: IRExpr
of irekAggregate:
aggOp*: IRAggregate
aggArgs*: seq[IRExpr]
aggDistinct*: bool
of irekFuncCall:
irFunc*: string
irFuncArgs*: seq[IRExpr]
of irekCast:
irCastType*: IRType
irCastExpr*: IRExpr
of irekConditional:
cond*: IRExpr
thenExpr*: IRExpr
elseExpr*: IRExpr
of irekExists:
existsSubquery*: IRPlan
of irekStar:
discard
of irekJsonPath:
jpExpr*: IRExpr
jpKey*: string
jpAsText*: bool
type
TypeChecker* = ref object
schemas: Table[string, IRType]
proc newTypeChecker*(): TypeChecker =
TypeChecker(schemas: initTable[string, IRType]())
proc registerType*(tc: TypeChecker, name: string, typ: IRType) =
tc.schemas[name] = typ
proc getType*(tc: TypeChecker, name: string): IRType =
tc.schemas.getOrDefault(name, nil)
proc inferExpr*(tc: TypeChecker, expr: IRExpr, context: Table[string, IRType]): IRType =
case expr.kind
of irekLiteral:
case expr.literal.kind
of vkBool: return IRType(name: "bool", kind: itkScalar)
of vkInt64: return IRType(name: "int64", kind: itkScalar)
of vkFloat64: return IRType(name: "float64", kind: itkScalar)
of vkString: return IRType(name: "str", kind: itkScalar)
of vkNull: return IRType(name: "null", kind: itkScalar, isNullable: true)
else: return IRType(name: "unknown", kind: itkScalar)
of irekField:
if expr.fieldPath.len == 0:
return nil
let rootName = expr.fieldPath[0]
if rootName in context:
var current = context[rootName]
for i in 1..<expr.fieldPath.len:
if expr.fieldPath[i] in current.fields:
current = current.fields[expr.fieldPath[i]]
else:
return nil
return current
return nil
of irekUnary:
let operandType = tc.inferExpr(expr.unExpr, context)
if operandType == nil:
return nil
case expr.unOp
of irEq, irNeq, irLt, irLte, irGt, irGte, irAnd, irOr, irNot,
irIsNull, irIsNotNull, irIn, irNotIn, irLike, irILike, irBetween,
irFtsMatch:
return IRType(name: "bool", kind: itkScalar)
else:
return nil
of irekBinary:
let leftType = tc.inferExpr(expr.binLeft, context)
let rightType = tc.inferExpr(expr.binRight, context)
if leftType == nil or rightType == nil:
return nil
case expr.binOp
of irAdd, irSub, irMul, irDiv, irMod, irPow:
return leftType
of irEq, irNeq, irLt, irLte, irGt, irGte, irAnd, irOr,
irIn, irNotIn, irLike, irILike, irBetween:
return IRType(name: "bool", kind: itkScalar)
else:
return nil
of irekAggregate:
case expr.aggOp
of irCount: return IRType(name: "int64", kind: itkScalar)
of irSum, irAvg: return IRType(name: "float64", kind: itkScalar)
of irMin, irMax:
if expr.aggArgs.len > 0:
return tc.inferExpr(expr.aggArgs[0], context)
return nil
of irekFuncCall:
return IRType(name: "unknown", kind: itkScalar)
of irekCast:
return expr.irCastType
of irekConditional:
let thenType = tc.inferExpr(expr.thenExpr, context)
return thenType
of irekExists:
return IRType(name: "bool", kind: itkScalar)
of irekStar:
return IRType(name: "star", kind: itkScalar)
of irekJsonPath:
if expr.jpAsText: return IRType(name: "str", kind: itkScalar)
return IRType(name: "json", kind: itkScalar)