package granary
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Pure-OCaml SQL engine
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.0.3.tar.gz
sha256=8b18780ea373be48301d9f333925860a2f9110fc0ac28684295118d72b65a67e
sha512=25ca3c9c5e2b528704a542502e0f37dc33ba003f65622d969b8c2b800778585f8ef0cf89b36e6679832e3993e8303aecddfc662742baf7044d6afe4a796b8f11
doc/src/granary.encoding/schema_fingerprint.ml.html
Source file schema_fingerprint.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112(* FNV-1a 64-bit. Self-contained copy (the storage-layer WAL has its own, but this module lives in [granary.encoding] which storage does not depend on, so we keep an independent, tested copy here rather than introduce a dependency edge into the crash-recovery-critical WAL code). *) let fnv64_offset = 0xCBF29CE484222325L let fnv64_prime = 0x00000100000001B3L let fnv64_byte h b = Int64.mul (Int64.logxor h (Int64.of_int (b land 0xff))) fnv64_prime let fnv64_bytes h (b : bytes) = let h = ref h in for i = 0 to Bytes.length b - 1 do h := fnv64_byte !h (Bytes.get_uint8 b i) done; !h ;; (* Canonicalization format version. Bump this if the byte layout below ever changes, so old and new fingerprints are never silently compared. *) let canon_version = 1 let type_tag : Row.ty -> int = function | Row.Integer -> 1 | Row.Text -> 2 | Row.Real -> 3 | Row.Blob -> 4 ;; let default_tag : Row.default_value -> int = function | Row.DV_null -> 0 | Row.DV_int _ -> 1 | Row.DV_real _ -> 2 | Row.DV_text _ -> 3 | Row.DV_blob _ -> 4 | Row.DV_current_timestamp -> 5 | Row.DV_current_date -> 6 | Row.DV_current_time -> 7 ;; (* Length-delimited string: varint(len) ++ bytes. The length prefix makes the serialization unambiguous, so two adjacent string fields cannot be re-split to produce the same byte stream. *) let add_str buf s = Varint.encode_uint64 buf (Int64.of_int (String.length s)); Buffer.add_string buf s ;; let add_u8 buf n = Buffer.add_uint8 buf (n land 0xff) let add_int64_le buf x = for k = 0 to 7 do add_u8 buf (Int64.to_int (Int64.logand (Int64.shift_right_logical x (k * 8)) 0xFFL)) done ;; let add_default buf (dv : Row.default_value) = add_u8 buf (default_tag dv); match dv with | Row.DV_null | Row.DV_current_timestamp | Row.DV_current_date | Row.DV_current_time -> () | Row.DV_int n -> add_int64_le buf n | Row.DV_real f -> add_int64_le buf (Int64.bits_of_float f) | Row.DV_text s -> add_str buf s | Row.DV_blob b -> add_str buf (Bytes.to_string b) ;; let add_column buf (c : Row.column) = add_str buf c.name; add_u8 buf (type_tag c.ty); add_u8 buf (if c.not_null then 1 else 0); add_u8 buf (if c.primary_key then 1 else 0); (* #312: a DESC PK (non-alias: hidden rowid + __pk index) is a different decode shape than the alias, so it must change the fingerprint. Emit a marker ONLY when [pk_desc] is set, so v1 on-disk fingerprints (and the per-page stamps derived from them, #174) of every existing schema stay byte-identical — no false corruption mismatch on reopen. *) if c.pk_desc then add_u8 buf 0xD5; (match c.default with | None -> add_u8 buf 0 | Some dv -> add_u8 buf 1; add_default buf dv); (match c.check_sql with | None -> add_u8 buf 0 | Some sql -> add_u8 buf 1; add_str buf sql); match c.generated_as with | None -> add_u8 buf 0 | Some (expr, is_stored) -> add_u8 buf 1; add_u8 buf (if is_stored then 1 else 0); add_str buf expr ;; let canonical ~columns ~without_rowid = let buf = Buffer.create 64 in add_u8 buf canon_version; add_u8 buf (if without_rowid then 1 else 0); Varint.encode_uint64 buf (Int64.of_int (List.length columns)); List.iter (add_column buf) columns; Buffer.to_bytes buf ;; let compute ~columns ~without_rowid = fnv64_bytes fnv64_offset (canonical ~columns ~without_rowid) ;; let low32 (x : int64) : int32 = Int64.to_int32 (Int64.logand x 0xFFFFFFFFL) [@@@ai_disclosure "ai-generated"] [@@@ai_model "claude-opus-4-7"] [@@@ai_provider "Anthropic"]
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>