Skip to content

Commit cf851b9

Browse files
committed
fixing issue with double precision floats
1 parent d2085d1 commit cf851b9

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

lib/tds/types.ex

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,26 @@ defmodule Tds.Types do
10111011
<<0>>
10121012
end
10131013
def encode_data(@tds_data_type_floatn, value, _) do
1014-
<<0x04, value::little-float-size(32)>>
1014+
d_ctx = Decimal.get_context
1015+
d_ctx = %{d_ctx | precision: 38}
1016+
Decimal.set_context d_ctx
1017+
value_list = Decimal.new(value)
1018+
|> Decimal.abs
1019+
|> Decimal.to_string(:scientific)
1020+
|> String.split(".")
1021+
precision =
1022+
case value_list do
1023+
[p,s] ->
1024+
String.length(p) + String.length(s)
1025+
[p] ->
1026+
String.length(p)
1027+
end
1028+
if precision <= 7 + 1 do
1029+
<<0x04, value::little-float-size(32)>>
1030+
else
1031+
# up to 15 digits of precision https://docs.microsoft.com/en-us/sql/t-sql/data-types/float-and-real-transact-sql
1032+
<<0x08, value::little-float-size(64)>>
1033+
end
10151034
end
10161035

10171036
@doc """

lib/tds/utils.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,16 @@ defmodule Tds.Utils do
8585
def pow10(num,pow) when pow < 0 do
8686
pow10(num/10, pow + 1)
8787
end
88+
89+
def pow(_, 0), do: 1
90+
def pow(a, 1), do: a
91+
92+
def pow(a, n) when rem(n, 2) === 0 do
93+
tmp = pow(a, div(n, 2))
94+
tmp * tmp
95+
end
96+
97+
def pow(a, n) do
98+
a * pow(a, n-1)
99+
end
88100
end

test/tds_ex_test.exs

Lines changed: 0 additions & 4 deletions
This file was deleted.

test/tds_issues.exs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
defmodule TdsTest do
2+
use ExUnit.Case, async: true
3+
require Logger
4+
import Tds.TestHelper
5+
6+
@tag timeout: 50000
7+
8+
setup do
9+
opts = Application.fetch_env!(:tds, :opts)
10+
{:ok, pid} = Tds.start_link(opts)
11+
12+
{:ok, [pid: pid]}
13+
end
14+
15+
test "issue 33: Sending Float with more than 9 characters should not fail", context do
16+
query("DROP TABLE hades_sealed_cfdis", [])
17+
query(
18+
"""
19+
CREATE TABLE hades_sealed_cfdis(
20+
[id] int identity(1,1) not null primary key,
21+
[total] float(53),
22+
[inserted_at] datetime,
23+
[updated_at] datetime
24+
)
25+
""", [])
26+
f = fn val ->
27+
res = query("INSERT INTO hades_sealed_cfdis ([total] ,[inserted_at], [updated_at]) VALUES (@1,@2,@3)",
28+
[%Tds.Parameter{name: "@1", value: val, type: :float},
29+
%Tds.Parameter{name: "@2", value: {{2016, 12, 20}, {23, 59, 23, 0}}},
30+
%Tds.Parameter{name: "@3", value: {{2016, 12, 20}, {23, 59, 23, 0}}}])
31+
32+
assert :ok == res
33+
assert [[val]] = query("SELECT [total] FROM hades_sealed_cfdis WHERE id in (select max(id) from hades_sealed_cfdis)", [])
34+
end
35+
Enum.flat_map(1..17, &([1/&1, -1/&1]))
36+
|> Enum.each(f)
37+
query("DROP TABLE hades_sealed_cfdis", [])
38+
end
39+
40+
end

0 commit comments

Comments
 (0)