diff --git a/src/barabadb/core/columnar.nim b/src/barabadb/core/columnar.nim index 5c2e6c0..4b149e2 100644 --- a/src/barabadb/core/columnar.nim +++ b/src/barabadb/core/columnar.nim @@ -19,6 +19,7 @@ type ColumnPtr* = ref object typ*: ColumnType + nulls*: seq[bool] case kind: ColumnType of ctInt64: intData: seq[int64] of ctFloat64: floatData: seq[float64] @@ -34,35 +35,39 @@ proc newColumnBatch*(): ColumnBatch = ColumnBatch(columns: initTable[string, ColumnPtr](), rowCount: 0) proc addInt64Col*(batch: var ColumnBatch, name: string): var ColumnPtr = - var col = ColumnPtr(typ: ctInt64, kind: ctInt64, intData: @[]) + var col = ColumnPtr(typ: ctInt64, kind: ctInt64, nulls: @[], intData: @[]) batch.columns[name] = col return batch.columns[name] proc addFloat64Col*(batch: var ColumnBatch, name: string): var ColumnPtr = - var col = ColumnPtr(typ: ctFloat64, kind: ctFloat64, floatData: @[]) + var col = ColumnPtr(typ: ctFloat64, kind: ctFloat64, nulls: @[], floatData: @[]) batch.columns[name] = col return batch.columns[name] proc addStringCol*(batch: var ColumnBatch, name: string): var ColumnPtr = - var col = ColumnPtr(typ: ctString, kind: ctString, strData: @[]) + var col = ColumnPtr(typ: ctString, kind: ctString, nulls: @[], strData: @[]) batch.columns[name] = col return batch.columns[name] proc addBoolCol*(batch: var ColumnBatch, name: string): var ColumnPtr = - var col = ColumnPtr(typ: ctBool, kind: ctBool, boolData: @[]) + var col = ColumnPtr(typ: ctBool, kind: ctBool, nulls: @[], boolData: @[]) batch.columns[name] = col return batch.columns[name] proc appendInt64*(col: var ColumnPtr, val: int64, isNull: bool = false) = + col.nulls.add(isNull) col.intData.add(val) proc appendFloat64*(col: var ColumnPtr, val: float64, isNull: bool = false) = + col.nulls.add(isNull) col.floatData.add(val) proc appendString*(col: var ColumnPtr, val: string, isNull: bool = false) = + col.nulls.add(isNull) col.strData.add(val) proc appendBool*(col: var ColumnPtr, val: bool, isNull: bool = false) = + col.nulls.add(isNull) col.boolData.add(val) proc rowCount*(batch: ColumnBatch): int = diff --git a/src/barabadb/core/mvcc.nim b/src/barabadb/core/mvcc.nim index a866eb1..feab5aa 100644 --- a/src/barabadb/core/mvcc.nim +++ b/src/barabadb/core/mvcc.nim @@ -170,9 +170,12 @@ proc write*(tm: TxnManager, txn: Transaction, key: string, value: seq[byte]): bo if tm.activeTxns[creator].state == tsCommitted: release(tm.lock) return false # write-write conflict - elif creator notin tm.activeTxns: - # Already completed and visible - discard + else: + # Creator already completed — check if it committed + # If not in activeTxns, it either committed or aborted + # We treat completed-but-visible as a conflict + release(tm.lock) + return false # write-write conflict with completed txn let lsn = tm.allocLsn() let version = VersionedRecord( @@ -201,9 +204,15 @@ proc commit*(tm: TxnManager, txn: Transaction): bool = tm.globalVersions[key] = @[] # Mark previous versions as deleted by this txn + # Only mark versions that were visible to this transaction for i in 0.. 0: + for i in int(nextIdx - 1).. ^7 + if word.endsWith("ища"): return word[0..^7] + if word.endsWith("ище"): return word[0..^7] + if word.endsWith("ция"): return word[0..^7] + if word.endsWith("ние"): return word[0..^7] + if word.endsWith("ост"): return word[0..^7] + if word.endsWith("ски"): return word[0..^7] + # 4 Cyrillic chars = 8 bytes -> ^9 + if word.endsWith("ство"): return word[0..^9] + # 2 Cyrillic chars = 4 bytes -> ^5 + if word.endsWith("на"): return word[0..^5] + if word.endsWith("та"): return word[0..^5] return word proc stemGerman*(word: string): string = @@ -124,17 +126,19 @@ proc stemFrench*(word: string): string = proc stemRussian*(word: string): string = if word.len <= 3: return word - # Russian suffixes - if word.endsWith("ость"): return word[0..^5] - if word.endsWith("ение"): return word[0..^5] - if word.endsWith("ание"): return word[0..^5] - if word.endsWith("тель"): return word[0..^5] - if word.endsWith("ский"): return word[0..^5] - if word.endsWith("ция"): return word[0..^4] - if word.endsWith("ние"): return word[0..^4] - if word.endsWith("ать"): return word[0..^4] - if word.endsWith("ить"): return word[0..^4] - if word.endsWith("ыть"): return word[0..^4] + # Russian suffixes (all Cyrillic chars are 2 bytes) + # 4 Cyrillic chars = 8 bytes -> ^9 + if word.endsWith("ость"): return word[0..^9] + if word.endsWith("ение"): return word[0..^9] + if word.endsWith("ание"): return word[0..^9] + if word.endsWith("тель"): return word[0..^9] + if word.endsWith("ский"): return word[0..^9] + # 3 Cyrillic chars = 6 bytes -> ^7 + if word.endsWith("ция"): return word[0..^7] + if word.endsWith("ние"): return word[0..^7] + if word.endsWith("ать"): return word[0..^7] + if word.endsWith("ить"): return word[0..^7] + if word.endsWith("ыть"): return word[0..^7] return word proc getLanguageConfig*(lang: Language): LanguageConfig = diff --git a/src/barabadb/protocol/websocket.nim b/src/barabadb/protocol/websocket.nim index 766db89..ccc6fa7 100644 --- a/src/barabadb/protocol/websocket.nim +++ b/src/barabadb/protocol/websocket.nim @@ -5,6 +5,7 @@ import std/strutils import std/base64 import std/sha1 import std/hashes +import std/tables const WS_FIN* = 0x80'u8 diff --git a/src/barabadb/protocol/wire.nim b/src/barabadb/protocol/wire.nim index e5fe56f..418b803 100644 --- a/src/barabadb/protocol/wire.nim +++ b/src/barabadb/protocol/wire.nim @@ -180,44 +180,48 @@ proc deserializeValue*(buf: openArray[byte], pos: var int): WireValue = let kind = FieldKind(buf[pos]) inc pos case kind - of fkNull: WireValue(kind: fkNull) - of fkBool: WireValue(kind: fkBool, boolVal: buf[pos] != 0) - of fkInt8: WireValue(kind: fkInt8, int8Val: cast[int8](buf[pos])) + of fkNull: result = WireValue(kind: fkNull) + of fkBool: + result = WireValue(kind: fkBool, boolVal: buf[pos] != 0) + inc pos + of fkInt8: + result = WireValue(kind: fkInt8, int8Val: cast[int8](buf[pos])) + inc pos of fkInt16: var val: int16 var bytes: array[2, byte] for i in 0..1: bytes[i] = buf[pos + i] bigEndian16(addr val, unsafeAddr bytes) pos += 2 - WireValue(kind: fkInt16, int16Val: val) + result = WireValue(kind: fkInt16, int16Val: val) of fkInt32: - WireValue(kind: fkInt32, int32Val: int32(readUint32(buf, pos))) + result = WireValue(kind: fkInt32, int32Val: int32(readUint32(buf, pos))) of fkInt64: - WireValue(kind: fkInt64, int64Val: int64(readUint64(buf, pos))) + result = WireValue(kind: fkInt64, int64Val: int64(readUint64(buf, pos))) of fkFloat32: var fl: float32 var bytes: array[4, byte] for i in 0..3: bytes[i] = buf[pos + i] copyMem(addr fl, unsafeAddr bytes, 4) pos += 4 - WireValue(kind: fkFloat32, float32Val: fl) + result = WireValue(kind: fkFloat32, float32Val: fl) of fkFloat64: var fl: float64 var bytes: array[8, byte] for i in 0..7: bytes[i] = buf[pos + i] copyMem(addr fl, unsafeAddr bytes, 8) pos += 8 - WireValue(kind: fkFloat64, float64Val: fl) + result = WireValue(kind: fkFloat64, float64Val: fl) of fkString: - WireValue(kind: fkString, strVal: readString(buf, pos)) + result = WireValue(kind: fkString, strVal: readString(buf, pos)) of fkBytes: - WireValue(kind: fkBytes, bytesVal: readBytes(buf, pos)) + result = WireValue(kind: fkBytes, bytesVal: readBytes(buf, pos)) of fkArray: let count = int(readUint32(buf, pos)) var arr: seq[WireValue] = @[] for i in 0.. 0: copyMem(addr buf.data[field.offset + 4], unsafeAddr value[0], value.len) else: diff --git a/src/barabadb/query/lexer.nim b/src/barabadb/query/lexer.nim index e7bc68c..3d53bac 100644 --- a/src/barabadb/query/lexer.nim +++ b/src/barabadb/query/lexer.nim @@ -260,6 +260,7 @@ proc readString(l: var Lexer, quote: char): string = while l.pos < l.input.len and l.input[l.pos] != quote: if l.input[l.pos] == '\\': discard l.advance() + if l.pos >= l.input.len: break case l.input[l.pos] of 'n': result.add('\n') of 't': result.add('\t') @@ -295,10 +296,6 @@ proc readIdent(l: var Lexer, startLine, startCol: int): Token = let lowerIdent = ident.toLower() if lowerIdent in keywords: Token(kind: keywords[lowerIdent], value: ident, line: startLine, col: startCol) - elif lowerIdent == "true": - Token(kind: tkBoolLit, value: "true", line: startLine, col: startCol) - elif lowerIdent == "false": - Token(kind: tkBoolLit, value: "false", line: startLine, col: startCol) else: Token(kind: tkIdent, value: ident, line: startLine, col: startCol) diff --git a/src/barabadb/storage/btree.nim b/src/barabadb/storage/btree.nim index fa7005b..c1f0530 100644 --- a/src/barabadb/storage/btree.nim +++ b/src/barabadb/storage/btree.nim @@ -48,7 +48,7 @@ proc splitChild[K, V](parent: BTreeNode[K, V], index: int, order: int) = newNode.values.add(child.values[j]) if not child.isLeaf: - for j in mid+1..child.children.len: + for j in mid+1..