Number (ulong64, cas value) conversion issue

Hello again couchbasia
I have a certain infrastructure to take care of volatility for me which revolves around the cas value.
The number conversion between the couchbase server and my app (C#aspnetcore) mismatch,
for instance when calling CouchbaseClient sdk Replace with a certain cas value result (IMutationResult ) ‘Cas’ member the value 1639300746363797504 (debug) is returned

options.Cas(“valid_cas_here”);
var mrs = await bucket.DefaultCollection().ReplaceAsync(key, entity, options);
// mrs.Cas == 1639300746363797504

however n1ql query at localhost:8091

SELECT RAW TONUMBER(“1639300746363797504”) as num
[ 1639300746363797500]

thanks in advance!

N1QL uses golang float64 as data type.
which looses precision over -2^53 to 2^53 Double-precision floating-point format - Wikipedia

Track via MB-24464

N1QL internally handles the cas has int64 . If did not do any athematic operations on int64 it should give results as it is.

6.6.3 gives right results.

 SELECT RAW TONUMBER("1639300746363797504");
{
    "requestID": "3798863a-6f2d-48c4-9be0-c5c0fef14116",
    "signature": "number",
    "results": [
    1639300746363797504
    ],
    "status": "success",
    "metrics": {
        "elapsedTime": "574.031µs",
        "executionTime": "517.815µs",
        "resultCount": 1,
        "resultSize": 19
    }
}

please consider:
// client specifies cas as a valid value string which i then convert to a ulong (transforms ok)

IMutationResult result = await bucket.DefaultCollection().ReplaceAsync(key, entity, options);

//result.Cas == 1639300746363797504

and that I have implemented my own ITypeSerializer for couchbase client

public T Deserialize(Stream stream) // ITypeSerializer, also catches serialization requests for QueryDataResult<…> (IQueryResult?)
{
var sr = new StreamReader(stream);
stream.Flush();
var json = sr.ReadToEnd();

        return JsonConvert.DeserializeObject<T>(json, DefaultSettings);

}

my issue is that json variable (read from the stream) is {... "cas": 1639300746363797504 ...} , note as a Raw JSON Number - but in database 1639300746363797500 … my guess is that the couchbase binary who has created this stream was relying on the same type of conversion (Javascript Number => UInt64) also to my understanding couchbase has a different bigint conversion from normal Javascript Number which i was wonder if i could reproduce in the couchbase client without going to the querying server (ie TONUMBER("…"))

I am also aware it is possible to can send a query to the server then specify TO_STRING(META(…).cas) but then I will be also require to use the REPLACE query and not the couchbase client sdk Repalce method which also got me wondering about the cost of this approach

thanks for the quick reply!

adding to the confusion
TO_STRING(1639300746363797500)
yields “1639300746363797504”

TO_NUMBER(TO_STRING(1639300746363797500))
yield 1639300746363797500

how can i produce the same number from the string “1639300746363797500”?

N1QL doesn’t deal with external cas values (There is no interface to supply user cas value via N1QL). What version of CB you are using. If required try 6.6.3

select RAW TO_STRING(1639300746363797500);
{
    "results": [
    "1639300746363797500"
    ]
}

couchbase-server-enterprise_7.0.2-windows_amd64.msi

What output you get when you run the statement.

[
“1639300746363797500”
]

I Don’t know if there is any issue with N1QL. It might be SDKs that how convert. That is not my expertise.
If you use META().cas, TO_STRING(META().cas) it will not loose any precision represent as int64

SELECT RAW { “cas”: META(usr).cas, “cas_str”: TO_STRING(META(usr).cas), “cas_str_then_num”: TO_NUMBER(TO_STRING(META(usr).cas)) } FROM SeymourUsers usr WHERE usr.UserName == ‘mazorsk’ LIMIT 1

[
{
“cas”: 1639300746363797500,
“cas_str”: “1639300746363797504”,
“cas_str_then_num”: 1639300746363797500
}
]

Thanks for reporting.

TO_STR() is right , TO_NUMBER() is not properly treating if string integers are outside range -2^52 to 2^52.
Track Via MB-50055

1 Like