This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
So I’m running into an error when inserting values that are :db.type/bigint
I’ve managed to narrow it down to encode-bigint:
(encode-bigint (biginteger "-1"))
;; fv8
(encode-bigint (biginteger "-34"))
;; ft4
(encode-bigint (biginteger "34"))
;; Value out of range for byte: 129
(encode-bigint (biginteger "123456789123456789"))
;; Value out of range for byte: 136
(encode-bigint (BigInteger. "-1"))
;; fv8
(encode-bigint (BigInteger. "-34"))
;; ft4
(encode-bigint (BigInteger. "34"))
;; Value out of range for byte: 129
(encode-bigint (BigInteger. "123456789123456789"))
;; Value out of range for byte: 136
So looks like the problem is with this function:
(defn encode-bigint
[^BigInteger x]
(let [bs (.toByteArray x)
n (alength bs)]
(assert (< n 128)
"Does not support integer beyond the range of [-2^1015, 2^1015-1]")
(let [bs1 (byte-array (inc n))]
(aset bs1 0 (byte (if (= (.signum x) -1)
(- 127 n)
(bit-flip n 7))))
(System/arraycopy bs 0 bs1 1 n)
bs1)))
Specifically on the branch when the number is positive.
(byte (bit-flip 7 n))
(byte (bit-flip 7 (alength (.toByteArray (biginteger "34")))))
;; 129
(byte 129)
;; Value out of range for byte: 129
As byte is between -128 and 127.
Unfortunately, my understanding of bit encoding etc is completely non existent. So I have no idea what (bit-flip n 7)
is supposed to do.So tried this (direct copy from datalevin/bits.clj on github) in an empty repl session (no dependencies) Clojure 1.11.1:
(defn encode-bigint
[^BigInteger x]
(let [bs (.toByteArray x)
n (alength bs)]
(assert (< n 128)
"Does not support integer beyond the range of [-2^1015, 2^1015-1]")
(let [bs1 (byte-array (inc n))]
(aset bs1 0 (byte (if (= (.signum x) -1)
(- 127 n)
(bit-flip n 7))))
(System/arraycopy bs 0 bs1 1 n)
bs1)))
(encode-bigint (biginteger "34"))
;; Execution error (IllegalArgumentException) at user/encode-bigint (REPL:8).
;; Value out of range for byte: 129
Still get the error, so that means it’s most likely the fact that I’m running JDK17? I’ll give that a test.Yes, changing it to unckecked-byte
fixes it :thinking_face:🙏
(defn encode-bigint
[^BigInteger x]
(let [bs (.toByteArray x)
n (alength bs)]
(assert (< n 128)
"Does not support integer beyond the range of [-2^1015, 2^1015-1]")
(let [bs1 (byte-array (inc n))]
(aset bs1 0 (byte (if (= (.signum x) -1)
(- 127 n)
n)))
(System/arraycopy bs 0 bs1 1 n)
bs1)))
(defn decode-bigint [bs]
(BigInteger. ^bytes (Arrays/copyOfRange bs 1 (alength bs))))
(decode-bigint (encode-bigint (biginteger "343")))
;; "343"
(decode-bigint (encode-bigint (biginteger "-343")))
;; "-343"
So replacing (bit-flip n 7)
with n
seems to make it roundtrip. But haven’t tested this with the actual db and as mentioned before don’t actually know enough about any of this to know what bit-flip was/is doing.Datalevin has worked well for me. Transaction functions work well, and composing them is a pleasure. One thing I noticed with transaction functions is that I cannot use any external libraries within them (I believe this is also how it is in datomic). Is this something that is an inherent property of the datalevin tx-fn implementation, or something that can be amended?
Yeah, here is a simple test case:
(ns slix.node)
(defn testing-fn []
"test-value")
(di/definterfn test-tx1 [db tempid]
[{:db/id tempid :node/value (slix.node/testing-fn)}])
(di/definterfn test-tx2 [db tempid]
[{:db/id tempid :node/value "test-value"}])
(d/transact! test-conn [{:db/ident :add-node1
:db/fn test-tx1}])
(d/transact! test-conn [{:db/ident :add-node2
:db/fn test-tx2}])
:add-node1 fails, but :add-node2 succeeds.I am getting "Can only freeze an inter-fn" when not defining test-tx2 as definterfn, just simply:
(defn testing-fn []
"test-value")
How do I know if I am using embedded? I think I am because I haven't separated out the db from the app, but I am getting the "Can only freeze an inter-fn" error.
Hmm. I will try that. I have transaction functions call other transaction functions, so I might need persistence. For instance, :db.fn/call might call an external function within a transaction function definition, which won't work (given what I have seen).
:db.fn/call
just call the function, without persistence, it does not involve serialization of the function
serialized code is handled with sci, so it doesn’t have access to clojure vars, but can probably be made so
(defn testing-fn [] "test-value")
(deftest test-fn
(let [dir (u/tmp-dir (str "test-fn-" (UUID/randomUUID)))
conn (d/create-conn dir)
test-tx (fn [_ tempid]
[{:db/id tempid :node/value (testing-fn)}])
{:keys [db-after]} (d/transact! conn [[:db.fn/call test-tx -1]])
e (d/entity db-after 1)]
(is (= (:node/value e) "test-value"))
(d/close conn)
(u/delete-files dir)))