changed CHANGELOG.md
 
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+ ## v2.3.2 (2022-10-04)
9
+ ### Fixes
10
+ * Fix error on redirect request from the server #140 (Thanks @zerobatu)
11
+
12
+ ## v2.3.1 (2022-07-08)
13
+ ### Fixes
14
+ * Add `:ssl` to `extra_applications`
15
+ * Fix message handling for TCP / SSL errors
16
+ * Don't redact password before login handshake is done
8
17
9
18
## v2.3.0 (2021-12-08)
10
19
* No changes since v2.3.0-rc.1
changed README.md
 
@@ -25,20 +25,16 @@ end
25
25
```
26
26
27
27
As of TDS version `>= 1.2`, tds can support windows codepages other than `windows-1252` (latin1).
28
- If you need such support you will need to include additional dependency `{:tds_encoding, "~> 1.0"}`
29
- and configure `:tds` app to use `Tds.Encoding` module like this:
28
+ If you need such support you will need to include additional dependency `{:excoding, "~> 0.1"}`
29
+ and configure `:tds` app to use `Excoding` module like this:
30
30
31
31
32
32
```elixir
33
33
import Mix.Config
34
34
35
- config :tds, :text_encoder, Tds.Encoding
35
+ config :tds, :text_encoder, Excoding
36
36
```
37
37
38
- Note that `:tds_encoding` requires Rust compiler installed in order to compile nif.
39
- In previous versions only `SQL_Latin1_General` was supported (codepage `windows-1252`).
40
- Please follow instructions at [Rust website](https://www.rust-lang.org/tools/install) to install Rust.
41
-
42
38
When you are done, run `mix deps.get` in your shell to fetch and compile Tds.
43
39
Start an interactive Elixir shell with `iex -S mix`.
changed hex_metadata.config
 
@@ -2,7 +2,7 @@
2
2
{<<"build_tools">>,[<<"mix">>]}.
3
3
{<<"description">>,
4
4
<<"Microsoft SQL Server client (Elixir implementation of the MS TDS protocol)">>}.
5
- {<<"elixir">>,<<"~> 1.0">>}.
5
+ {<<"elixir">>,<<"~> 1.11">>}.
6
6
{<<"files">>,
7
7
[<<"lib">>,<<"lib/tds.ex">>,<<"lib/tds">>,<<"lib/tds/protocol.ex">>,
8
8
<<"lib/tds/types">>,<<"lib/tds/types/uuid.ex">>,<<"lib/tds/types.ex">>,
 
@@ -37,4 +37,4 @@
37
37
{<<"optional">>,false},
38
38
{<<"repository">>,<<"hexpm">>},
39
39
{<<"requirement">>,<<"~> 2.0">>}]]}.
40
- {<<"version">>,<<"2.3.1">>}.
40
+ {<<"version">>,<<"2.3.2">>}.
changed lib/tds.ex
 
@@ -16,6 +16,7 @@ defmodule Tds do
16
16
Please consult with [configuration](readme.html#configuration) how to do this.
17
17
"""
18
18
alias Tds.Query
19
+ alias Tds.Types.UUID
19
20
20
21
@timeout 5000
21
22
@execution_mode :prepare_execute
 
@@ -195,8 +196,8 @@ defmodule Tds do
195
196
196
197
Defaults to `Jason`.
197
198
"""
198
- @spec json_library() :: module()
199
- def json_library() do
199
+ @spec json_library :: module()
200
+ def json_library do
200
201
Application.fetch_env!(:tds, :json_library)
201
202
end
202
203
 
@@ -204,18 +205,18 @@ defmodule Tds do
204
205
Generates a version 4 (random) UUID in the MS uniqueidentifier binary format.
205
206
"""
206
207
@spec generate_uuid :: <<_::128>>
207
- def generate_uuid(), do: Tds.Types.UUID.bingenerate()
208
+ def generate_uuid, do: UUID.bingenerate()
208
209
209
210
@doc """
210
211
Decodes MS uniqueidentifier binary to its string representation.
211
212
"""
212
- def decode_uuid(uuid), do: Tds.Types.UUID.load(uuid)
213
+ def decode_uuid(uuid), do: UUID.load(uuid)
213
214
214
215
@doc """
215
216
Same as `decode_uuid/1` but raises `ArgumentError` if value is invalid.
216
217
"""
217
218
def decode_uuid!(uuid) do
218
- case Tds.Types.UUID.load(uuid) do
219
+ case UUID.load(uuid) do
219
220
{:ok, value} ->
220
221
value
221
222
 
@@ -228,11 +229,11 @@ defmodule Tds do
228
229
Encodes UUID string into MS uniqueidentifier binary.
229
230
"""
230
231
@spec encode_uuid(any) :: :error | {:ok, <<_::128>>}
231
- def encode_uuid(value), do: Tds.Types.UUID.dump(value)
232
+ def encode_uuid(value), do: UUID.dump(value)
232
233
233
234
@doc """
234
235
Same as `encode_uuid/1` but raises `ArgumentError` if value is invalid.
235
236
"""
236
237
@spec encode_uuid!(any) :: <<_::128>>
237
- def encode_uuid!(value), do: Tds.Types.UUID.dump!(value)
238
+ def encode_uuid!(value), do: UUID.dump!(value)
238
239
end
changed lib/tds/binary_utils.ex
 
@@ -4,58 +4,58 @@ defmodule Tds.BinaryUtils do
4
4
@doc """
5
5
A single bit value of either 0 or 1.
6
6
"""
7
- defmacro bit(), do: quote(do: size(1))
7
+ defmacro bit, do: quote(do: size(1))
8
8
9
9
@doc """
10
10
An unsigned single byte (8-bit) value. The range is 0 to 255.
11
11
"""
12
- defmacro byte(), do: quote(do: unsigned - 8)
12
+ defmacro byte, do: quote(do: unsigned - 8)
13
13
14
14
@doc """
15
15
An unsigned single byte (8-bit) value representing the length of the
16
16
associated data. The range is 0 to 255.
17
17
"""
18
- defmacro bytelen(), do: quote(do: unsigned - 8)
18
+ defmacro bytelen, do: quote(do: unsigned - 8)
19
19
20
20
@doc """
21
21
An unsigned 2-byte (16-bit) value. The range is 0 to 65535.
22
22
"""
23
- defmacro ushort(), do: quote(do: little - unsigned - 16)
23
+ defmacro ushort, do: quote(do: little - unsigned - 16)
24
24
25
25
@doc """
26
26
An unsigned 6-byte (48-bit) value. The range is 0 to (2^48)-1
27
27
"""
28
- defmacro sixbyte(), do: quote(do: unsigned - 48)
28
+ defmacro sixbyte, do: quote(do: unsigned - 48)
29
29
30
30
@doc """
31
31
A signed 4-byte (32-bit) value. The range is -(2^31) to (2^31)-1.
32
32
"""
33
- defmacro long(), do: quote(do: little - signed - 32)
33
+ defmacro long, do: quote(do: little - signed - 32)
34
34
35
35
@doc """
36
36
A signed 8-byte (64-bit) value. The range is –(2^63) to (2^63)-1.
37
37
"""
38
- defmacro longlong(), do: quote(do: little - signed - 64)
38
+ defmacro longlong, do: quote(do: little - signed - 64)
39
39
40
40
@doc """
41
41
An unsigned 4-byte (32-bit) value. The range is 0 to (2^32)-1
42
42
"""
43
- defmacro ulong(), do: quote(do: little - unsigned - 32)
43
+ defmacro ulong, do: quote(do: little - unsigned - 32)
44
44
45
45
@doc """
46
46
An unsigned 8-byte (64-bit) value. The range is 0 to (2^64)-1.
47
47
"""
48
- defmacro ulonglong(), do: quote(do: little - unsigned - 64)
48
+ defmacro ulonglong, do: quote(do: little - unsigned - 64)
49
49
50
50
@doc """
51
51
An unsigned 4-byte (32-bit) value. The range when used as a numeric value is 0 to (2^32)- 1.
52
52
"""
53
- defmacro dword(), do: quote(do: unsigned - 32)
53
+ defmacro dword, do: quote(do: unsigned - 32)
54
54
55
55
@doc """
56
56
An unsigned single byte (8-bit) value representing a character. The range is 0 to 255.
57
57
"""
58
- defmacro uchar(), do: quote(do: unsigned - 8)
58
+ defmacro uchar, do: quote(do: unsigned - 8)
59
59
60
60
@doc """
61
61
An unsigned 2-byte (16-bit) value representing the length of the associated
 
@@ -63,7 +63,7 @@ defmodule Tds.BinaryUtils do
63
63
64
64
The range is 0 to 65535.
65
65
"""
66
- defmacro ushortlen(), do: quote(do: little - unsigned - 16)
66
+ defmacro ushortlen, do: quote(do: little - unsigned - 16)
67
67
68
68
@doc """
69
69
An unsigned 2-byte (16-bit) value representing the length of the associated
 
@@ -71,7 +71,7 @@ defmodule Tds.BinaryUtils do
71
71
72
72
The range is 0 to 8000.
73
73
"""
74
- defmacro ushortcharbinlen(), do: quote(do: little - unsigned - 16)
74
+ defmacro ushortcharbinlen, do: quote(do: little - unsigned - 16)
75
75
76
76
@doc """
77
77
A signed 4-byte (32-bit) value representing the length of the associated
 
@@ -79,7 +79,7 @@ defmodule Tds.BinaryUtils do
79
79
80
80
The range is -(2^31) to (2^31)-1.
81
81
"""
82
- defmacro longlen(), do: quote(do: little - signed - 32)
82
+ defmacro longlen, do: quote(do: little - signed - 32)
83
83
84
84
@doc """
85
85
An unsigned 8-byte (64-bit) value representing the length of the associated
 
@@ -87,19 +87,19 @@ defmodule Tds.BinaryUtils do
87
87
88
88
The range is 0 to (2^64)-1.
89
89
"""
90
- defmacro ulonglonglen(), do: quote(do: little - unsigned - 64)
90
+ defmacro ulonglonglen, do: quote(do: little - unsigned - 64)
91
91
92
92
@doc """
93
93
An unsigned single byte (8-bit) value representing the precision of a numeric
94
94
number.
95
95
"""
96
- defmacro precision(), do: quote(do: unsigned - 8)
96
+ defmacro precision, do: quote(do: unsigned - 8)
97
97
98
98
@doc """
99
99
An unsigned single byte (8-bit) value representing the scale of a numeric
100
100
number.
101
101
"""
102
- defmacro scale(), do: quote(do: unsigned - 8)
102
+ defmacro scale, do: quote(do: unsigned - 8)
103
103
104
104
@doc """
105
105
A single byte (8-bit) value representing a NULL value, `0x00`.
 
@@ -110,7 +110,7 @@ defmodule Tds.BinaryUtils do
110
110
iex> <<_::gen_null()>> = <<0x00 :: size(8)>>
111
111
112
112
"""
113
- defmacro gen_null(), do: quote(do: size(8))
113
+ defmacro gen_null, do: quote(do: size(8))
114
114
115
115
@doc """
116
116
A 2-byte (16-bit) value representing a T-SQL NULL value for a character or
 
@@ -123,7 +123,7 @@ defmodule Tds.BinaryUtils do
123
123
124
124
Please refer to TYPE_VARBYTE (see MS-TDS.pdf section 2.2.5.2.3) for additional details.
125
125
"""
126
- defmacro charbin_null16(), do: quote(do: size(16))
126
+ defmacro charbin_null16, do: quote(do: size(16))
127
127
128
128
@doc """
129
129
A 4-byte (32-bit) value representing a T-SQL NULL value for a character or
 
@@ -136,14 +136,14 @@ defmodule Tds.BinaryUtils do
136
136
137
137
Please refer to TYPE_VARBYTE (see MS-TDS.pdf section 2.2.5.2.3) for additional details.
138
138
"""
139
- defmacro charbin_null32(), do: quote(do: size(32))
139
+ defmacro charbin_null32, do: quote(do: size(32))
140
140
141
141
@doc """
142
142
A FRESERVEDBIT is a BIT value used for padding that does not transmit information.
143
143
144
144
FRESERVEDBIT fields SHOULD be set to %b0 and MUST be ignored on receipt.
145
145
"""
146
- defmacro freservedbit(), do: quote(do: 0x0 :: size(1))
146
+ defmacro freservedbit, do: quote(do: 0x0 :: size(1))
147
147
148
148
@doc """
149
149
A FRESERVEDBYTE is a BYTE value used for padding that does not transmit
 
@@ -152,54 +152,54 @@ defmodule Tds.BinaryUtils do
152
152
FRESERVEDBYTE fields SHOULD be set to %x00 and MUST be ignored
153
153
on receipt.
154
154
"""
155
- defmacro freservedbyte(), do: quote(do: 0x00 :: size(8))
155
+ defmacro freservedbyte, do: quote(do: 0x00 :: size(8))
156
156
157
157
@doc """
158
158
A 8-bit signed integer.
159
159
"""
160
- defmacro int8(), do: quote(do: signed - 8)
160
+ defmacro int8, do: quote(do: signed - 8)
161
161
162
162
@doc """
163
163
A 16-bit signed integer.
164
164
"""
165
- defmacro int16(), do: quote(do: signed - 16)
165
+ defmacro int16, do: quote(do: signed - 16)
166
166
167
167
@doc """
168
168
A 32-bit signed integer.
169
169
"""
170
- defmacro int32(), do: quote(do: signed - 32)
170
+ defmacro int32, do: quote(do: signed - 32)
171
171
172
172
@doc """
173
173
A 64-bit signed integer.
174
174
"""
175
- defmacro int64(), do: quote(do: signed - 64)
175
+ defmacro int64, do: quote(do: signed - 64)
176
176
177
177
@doc """
178
178
A 8-bit signed unsigned integer.
179
179
"""
180
- defmacro uint8(), do: quote(do: unsigned - 8)
180
+ defmacro uint8, do: quote(do: unsigned - 8)
181
181
182
182
@doc """
183
183
A 16-bit signed unsigned integer.
184
184
"""
185
- defmacro uint16(), do: quote(do: unsigned - 16)
185
+ defmacro uint16, do: quote(do: unsigned - 16)
186
186
187
187
@doc """
188
188
A 32-bit signed unsigned integer.
189
189
"""
190
- defmacro uint32(), do: quote(do: unsigned - 32)
190
+ defmacro uint32, do: quote(do: unsigned - 32)
191
191
192
192
@doc """
193
193
A 64-bit signed unsigned integer.
194
194
"""
195
- defmacro uint64(), do: quote(do: unsigned - 64)
195
+ defmacro uint64, do: quote(do: unsigned - 64)
196
196
197
197
@doc """
198
198
A 64-bit signed float.
199
199
"""
200
- defmacro float64(), do: quote(do: signed - float - 64)
200
+ defmacro float64, do: quote(do: signed - float - 64)
201
201
202
- defmacro float32(), do: quote(do: signed - float - 32)
202
+ defmacro float32, do: quote(do: signed - float - 32)
203
203
204
204
defmacro binary(size), do: quote(do: binary - size(unquote(size)))
changed lib/tds/messages.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Messages do
2
+ @moduledoc false
3
+
2
4
import Record, only: [defrecord: 2]
3
5
import Tds.Tokens, only: [decode_tokens: 1]
4
6
 
@@ -313,9 +315,9 @@ defmodule Tds.Messages do
313
315
314
316
defp encode(msg_transmgr(command: "TM_ROLLBACK_XACT", name: name), %{trans: trans}) do
315
317
payload =
316
- unless name > 0,
317
- do: <<0x00::size(2)-unit(8)>>,
318
- else: <<2::unsigned-8, name::little-size(2)-unit(8), 0x0::size(1)-unit(8)>>
318
+ if name > 0,
319
+ do: <<2::unsigned-8, name::little-size(2)-unit(8), 0x0::size(1)-unit(8)>>,
320
+ else: <<0x00::size(2)-unit(8)>>
319
321
320
322
encode_trans(8, trans, payload)
321
323
end
changed lib/tds/parameter.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Parameter do
2
+ @moduledoc false
3
+
2
4
alias Tds.Types
3
5
4
6
@type t :: %__MODULE__{
 
@@ -35,9 +37,11 @@ defmodule Tds.Parameter do
35
37
params
36
38
|> List.wrap()
37
39
|> name(0)
38
- |> Enum.map(&fix_data_type/1)
39
- |> Enum.map(&Types.encode_param_descriptor/1)
40
- |> Enum.join(", ")
40
+ |> Enum.map_join(", ", fn param ->
41
+ param
42
+ |> fix_data_type()
43
+ |> Types.encode_param_descriptor()
44
+ end)
41
45
end
42
46
43
47
@doc """
changed lib/tds/protocol.ex
 
@@ -104,7 +104,7 @@ defmodule Tds.Protocol do
104
104
105
105
{:error, err, s} ->
106
106
err =
107
- if Exception.exception?(err) do
107
+ if is_exception(err) do
108
108
err
109
109
else
110
110
Tds.Error.exception(inspect(err))
changed lib/tds/protocol/header.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Protocol.Header do
2
+ @moduledoc false
3
+
2
4
import Tds.BinaryUtils
3
5
import Bitwise
4
6
 
@@ -84,19 +86,21 @@ defmodule Tds.Protocol.Header do
84
86
<<type::int8(), status::int8(), length::int16(), spid::int16(), package::int8(),
85
87
window::int8()>>
86
88
) do
87
- with {^type, pkg_header_type, has_data} <- decode_type(type) do
88
- {:ok,
89
- struct!(__MODULE__,
90
- type: pkg_header_type,
91
- status: decode_status(status),
92
- length: length - 8,
93
- spid: spid,
94
- package: package,
95
- window: window,
96
- has_data: has_data
97
- )}
98
- else
99
- {:error, _} = e -> e
89
+ case decode_type(type) do
90
+ {^type, pkg_header_type, has_data} ->
91
+ {:ok,
92
+ struct!(__MODULE__,
93
+ type: pkg_header_type,
94
+ status: decode_status(status),
95
+ length: length - 8,
96
+ spid: spid,
97
+ package: package,
98
+ window: window,
99
+ has_data: has_data
100
+ )}
101
+
102
+ {:error, _} = e ->
103
+ e
100
104
end
101
105
end
changed lib/tds/protocol/token.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Protocol.Token do
2
+ @moduledoc false
3
+
2
4
import Bitwise
3
5
4
6
# @tokens [
changed lib/tds/query.ex
 
@@ -26,10 +26,7 @@ defimpl DBConnection.Query, for: Tds.Query do
26
26
end
27
27
28
28
def encode(%Query{statement: statement}, params, _) do
29
- param_desc =
30
- params
31
- |> Enum.map(&Types.encode_param_descriptor/1)
32
- |> Enum.join(", ")
29
+ param_desc = Enum.map_join(params, ", ", &Types.encode_param_descriptor/1)
33
30
34
31
[
35
32
%Parameter{value: statement, type: :string},
changed lib/tds/tokens.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Tokens do
2
+ @moduledoc false
3
+
2
4
import Tds.BinaryUtils
3
5
import Bitwise
4
6
 
@@ -401,8 +403,17 @@ defmodule Tds.Tokens do
401
403
rest::binary
402
404
>> = tail
403
405
406
+ {hostname, instance} =
407
+ UCS2.to_string(alt_host)
408
+ |> String.split("\\")
409
+ |> case do
410
+ [host, instance] -> {host, instance}
411
+ [host] -> {host, nil}
412
+ end
413
+
404
414
routing = %{
405
- hostname: UCS2.to_string(alt_host),
415
+ hostname: hostname,
416
+ instance: instance,
406
417
port: port
407
418
}
changed lib/tds/types.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Types do
2
+ @moduledoc false
3
+
2
4
import Tds.BinaryUtils
3
5
import Tds.Utils
changed lib/tds/versions.ex
 
@@ -1,4 +1,6 @@
1
1
defmodule Tds.Version do
2
+ @moduledoc false
3
+
2
4
import Tds.Protocol.Grammar
3
5
4
6
@default_version :v7_4
changed mix.exs
 
@@ -2,13 +2,13 @@ defmodule Tds.Mixfile do
2
2
use Mix.Project
3
3
4
4
@source_url "https://github.com/elixir-ecto/tds"
5
- @version "2.3.1"
5
+ @version "2.3.2"
6
6
7
7
def project do
8
8
[
9
9
app: :tds,
10
10
version: @version,
11
- elixir: "~> 1.0",
11
+ elixir: "~> 1.11",
12
12
name: "Tds",
13
13
deps: deps(),
14
14
docs: docs(),
 
@@ -37,7 +37,7 @@ defmodule Tds.Mixfile do
37
37
{:jason, "~> 1.0", optional: true},
38
38
{:db_connection, "~> 2.0"},
39
39
{:ex_doc, "~> 0.19", only: :docs},
40
- {:tds_encoding, "~> 1.1", optional: true, only: :test},
40
+ {:excoding, "~> 0.1", optional: true, only: :test},
41
41
{:tzdata, "~> 1.0", optional: true, only: :test}
42
42
]
43
43
end