changed hex_metadata.config
 
@@ -26,4 26,4 @@
26
26
{<<"optional">>,false},
27
27
{<<"repository">>,<<"hexpm">>},
28
28
{<<"requirement">>,<<"~> 1.1">>}]]}.
29
- {<<"version">>,<<"1.1.3">>}.
29
{<<"version">>,<<"1.1.4">>}.
changed lib/tds/protocol.ex
 
@@ -16,7 16,13 @@ defmodule Tds.Protocol do
16
16
@timeout 5000
17
17
@max_packet 4 * 1024
18
18
@sock_opts [packet: :raw, mode: :binary, active: false, recbuf: 4096]
19
- @trans_levels [:read_uncommited, :read_commited, :repeatable_read, :snapshot, :serializable]
19
@trans_levels [
20
:read_uncommited,
21
:read_commited,
22
:repeatable_read,
23
:snapshot,
24
:serializable
25
]
20
26
21
27
defstruct sock: nil,
22
28
usock: nil,
 
@@ -104,23 110,34 @@ defmodule Tds.Protocol do
104
110
end
105
111
106
112
def handle_execute(
107
- %Query{statement: statement} = query,
108
- params,
109
- opts,
110
- %{sock: _sock} = s
111
- ) do
113
%Query{handle: handle, statement: statement} = query,
114
params,
115
opts,
116
%{sock: _sock} = s
117
) do
112
118
params = opts[:parameters] || params
113
119
114
- if params != [] do
115
- send_param_query(query, params, s)
116
- else
117
- send_query(statement, s)
120
try do
121
if params != [] do
122
send_param_query(query, params, s)
123
else
124
send_query(statement, s)
125
end
126
rescue
127
exception ->
128
stacktrace = System.stacktrace()
129
reraise exception, stacktrace
130
after
131
unless is_nil(handle) do
132
handle_close(query, opts, s)
133
end
118
134
end
119
135
end
120
136
121
137
def handle_prepare(%{statement: statement}, opts, %{sock: _sock} = s) do
122
- params = opts[:parameters]
123
- |> Parameter.prepared_params()
138
params =
139
opts[:parameters]
140
|> Parameter.prepared_params()
124
141
125
142
send_prepare(statement, params, s)
126
143
end
 
@@ -131,14 148,14 @@ defmodule Tds.Protocol do
131
148
send_close(query, params, s)
132
149
end
133
150
134
- def handle_begin(opts, %{sock: _, env: env}=s) do
151
def handle_begin(opts, %{sock: _, env: env} = s) do
135
152
case Keyword.get(opts, :mode, :transaction) do
136
153
:transaction ->
137
- send_transaction("TM_BEGIN_XACT", nil, %{s|transaction: :started})
154
send_transaction("TM_BEGIN_XACT", nil, %{s | transaction: :started})
138
155
139
156
:savepoint ->
140
157
savepoint = env.savepoint 1
141
- env = %{env| savepoint: savepoint}
158
env = %{env | savepoint: savepoint}
142
159
s = %{s | transaction: :started, env: env}
143
160
send_transaction("TM_SAVE_XACT", savepoint, s)
144
161
end
 
@@ -159,20 176,21 @@ defmodule Tds.Protocol do
159
176
# we don't need to call release savepoint as in postgresql for instance,
160
177
# when transaction DIDN'T failed. SQL will wait for
161
178
{:ok, %Tds.Result{rows: [], num_rows: 0}, s}
162
-
163
179
end
164
180
end
165
181
166
182
def handle_rollback(opts, %{sock: _sock, env: env} = s) do
167
183
case Keyword.get(opts, :mode, :transaction) do
168
184
:transaction ->
169
- env = %{env| savepoint: 0}
185
env = %{env | savepoint: 0}
170
186
s = %{s | transaction: :failed, env: env}
171
187
send_transaction("TM_ROLLBACK_XACT", 0, s)
172
188
173
189
:savepoint ->
174
- send_transaction("TM_ROLLBACK_XACT", env.savepoint, %{s | transaction: :failed})
175
-
190
send_transaction("TM_ROLLBACK_XACT", env.savepoint, %{
191
s
192
| transaction: :failed
193
})
176
194
end
177
195
end
178
196
 
@@ -504,40 522,44 @@ defmodule Tds.Protocol do
504
522
# end
505
523
506
524
def send_param_query(
507
- %Query{handle: handle, statement: statement} = _,
508
- params,
509
- %{transaction: :started} = s
510
- ) do
511
- msg = case handle do
512
- nil ->
513
- p = [
514
- %Parameter{
515
- name: "@statement",
516
- type: :string,
517
- direction: :input,
518
- value: statement
519
- },
520
- %Parameter{
521
- name: "@params",
522
- type: :string,
523
- direction: :input,
524
- value: Parameter.prepared_params(params)
525
- }
526
- | Parameter.prepare_params(params)
527
- ]
528
- msg_rpc(proc: :sp_executesql, params: p)
529
- handle ->
530
- p = [
531
- %Parameter{
532
- name: "@handle",
533
- type: :integer,
534
- direction: :input,
535
- value: handle
536
- }
537
- | Parameter.prepare_params(params)
538
- ]
539
- msg_rpc(proc: :sp_execute, params: p)
540
- end
525
%Query{handle: handle, statement: statement} = _,
526
params,
527
%{transaction: :started} = s
528
) do
529
msg =
530
case handle do
531
nil ->
532
p = [
533
%Parameter{
534
name: "@statement",
535
type: :string,
536
direction: :input,
537
value: statement
538
},
539
%Parameter{
540
name: "@params",
541
type: :string,
542
direction: :input,
543
value: Parameter.prepared_params(params)
544
}
545
| Parameter.prepare_params(params)
546
]
547
548
msg_rpc(proc: :sp_executesql, params: p)
549
550
handle ->
551
p = [
552
%Parameter{
553
name: "@handle",
554
type: :integer,
555
direction: :input,
556
value: handle
557
}
558
| Parameter.prepare_params(params)
559
]
560
561
msg_rpc(proc: :sp_execute, params: p)
562
end
541
563
542
564
case msg_send(msg, s) do
543
565
{:ok, %{result: result} = s} ->
 
@@ -552,40 574,44 @@ defmodule Tds.Protocol do
552
574
end
553
575
554
576
def send_param_query(
555
- %Query{handle: handle, statement: statement} = _,
556
- params,
557
- s
558
- ) do
559
- msg = case handle do
560
- nil ->
561
- p = [
562
- %Parameter{
563
- name: "@statement",
564
- type: :string,
565
- direction: :input,
566
- value: statement
567
- },
568
- %Parameter{
569
- name: "@params",
570
- type: :string,
571
- direction: :input,
572
- value: Parameter.prepared_params(params)
573
- }
574
- | Parameter.prepare_params(params)
575
- ]
576
- msg_rpc(proc: :sp_executesql, params: p)
577
- handle ->
578
- p = [
579
- %Parameter{
580
- name: "@handle",
581
- type: :integer,
582
- direction: :input,
583
- value: handle
584
- }
585
- | Parameter.prepare_params(params)
586
- ]
587
- msg_rpc(proc: :sp_execute, params: p)
588
- end
577
%Query{handle: handle, statement: statement} = _,
578
params,
579
s
580
) do
581
msg =
582
case handle do
583
nil ->
584
p = [
585
%Parameter{
586
name: "@statement",
587
type: :string,
588
direction: :input,
589
value: statement
590
},
591
%Parameter{
592
name: "@params",
593
type: :string,
863
direction: :input,
595
value: Parameter.prepared_params(params)
596
}
597
| Parameter.prepare_params(params)
598
]
599
600
msg_rpc(proc: :sp_executesql, params: p)
601
602
handle ->
603
p = [
604
%Parameter{
605
name: "@handle",
606
type: :integer,
607
direction: :input,
608
value: handle
609
}
610
| Parameter.prepare_params(params)
611
]
612
613
msg_rpc(proc: :sp_execute, params: p)
614
end
589
615
590
616
case msg_send(msg, s) do
591
617
{:ok, %{result: result} = s} ->
 
@@ -645,19 671,26 @@ defmodule Tds.Protocol do
645
671
# def message(:prelogin, _state) do
646
672
# end
647
673
648
- def message(:login, msg_login_ack(redirect: true, tokens: tokens), %{opts: opts} = s) do
674
def message(
675
:login,
676
msg_login_ack(redirect: true, tokens: tokens),
677
%{opts: opts} = s
678
) do
649
679
# we got an ENVCHANGE:redirection token, we need to disconnect and start over with new server
650
680
disconnect("redirected", s)
651
681
%{hostname: host, port: port} = tokens[:env_redirect]
682
652
683
new_opts =
653
684
opts
654
685
|> Keyword.put(:hostname, host)
655
686
|> Keyword.put(:port, port)
687
656
688
connect(new_opts)
657
689
end
658
690
659
691
def message(:login, msg_login_ack(), %{opts: opts} = s) do
660
692
state = %{s | opts: clean_opts(opts)}
693
661
694
opts
662
695
|> conn_opts()
663
696
|> IO.iodata_to_binary()
 
@@ -697,7 730,13 @@ defmodule Tds.Protocol do
697
730
def message(:executing, msg_trans(trans: trans), %{env: env} = s) do
698
731
result = %Tds.Result{columns: [], rows: [], num_rows: 0}
699
732
700
- {:ok, %{s | state: :ready, result: result, env: %{trans: trans, savepoint: env.savepoint}}}
733
{:ok,
734
%{
735
s
736
| state: :ready,
737
result: result,
738
env: %{trans: trans, savepoint: env.savepoint}
739
}}
701
740
end
702
741
703
742
def message(:executing, msg_prepared(params: params), %{} = s) do
 
@@ -717,9 756,9 @@ defmodule Tds.Protocol do
717
756
718
757
## ATTN Ack
719
758
def message(:attn, _, %{} = s) do
720
- result = %Tds.Result{columns: [], rows: [], num_rows: 0}
759
result = %Tds.Result{columns: [], rows: [], num_rows: 0}
721
760
722
- { :ok, %{s | statement: "", state: :ready, result: result} }
761
{:ok, %{s | statement: "", state: :ready, result: result}}
723
762
end
724
763
725
764
# defp simple_send(msg, %{sock: {mod, sock}, env: env}) do
 
@@ -783,16 822,18 @@ defmodule Tds.Protocol do
783
822
(buffer <> header)
784
823
|> package_recv(s, length - 8)
785
824
786
- {:ok, <<
787
- _type::int8,
788
- status::int8,
789
- length::int16,
790
- _spid::int16,
791
- _package::int8,
792
- _window::int8
793
- >> = header } ->
825
{:ok,
826
<<
827
_type::int8,
828
status::int8,
829
length::int16,
830
_spid::int16,
831
_package::int8,
832
_window::int8
833
>> = header} ->
794
834
(buffer <> header)
795
835
|> package_recv(s, length - 8)
836
796
837
raise "Status #{inspect(status)} of tds package is not yer supported!"
797
838
798
839
{:error, :closed} ->
 
@@ -896,123 937,162 @@ defmodule Tds.Protocol do
896
937
897
938
defp append_opts(conn, opts, :set_language) do
898
939
case Keyword.get(opts, :set_language) do
899
- nil -> conn
940
nil -> conn
900
941
val -> conn ["SET LANGUAGE #{val}; "]
901
942
end
902
943
end
903
944
904
945
defp append_opts(conn, opts, :set_datefirst) do
905
946
case Keyword.get(opts, :set_datefirst) do
906
- nil -> conn
907
- val when val in 1..7 -> conn ["SET DATEFIRST #{val}; "]
908
- val -> raise(
909
- ArgumentError,
910
- "set_datefirst: #{inspect(val)} is out of bounds, valid range is 1..7"
911
- )
947
nil ->
948
conn
949
950
val when val in 1..7 ->
951
conn ["SET DATEFIRST #{val}; "]
952
953
val ->
954
raise(
955
ArgumentError,
956
"set_datefirst: #{inspect(val)} is out of bounds, valid range is 1..7"
957
)
912
958
end
913
959
end
914
960
915
961
defp append_opts(conn, opts, :set_dateformat) do
916
962
case Keyword.get(opts, :set_dateformat) do
917
- nil -> conn
963
nil ->
964
conn
965
918
966
val when val in [:mdy, :dmy, :ymd, :ydm, :myd, :dym] ->
919
967
conn ["SET DATEFORMAT #{val}; "]
920
- val -> raise(
921
- ArgumentError,
922
- "set_dateformat: #{inspect(val)} is an invalid value, " <>
923
- "valid values are [:mdy, :dmy, :ymd, :ydm, :myd, :dym]"
924
- )
968
969
val ->
970
raise(
971
ArgumentError,
972
"set_dateformat: #{inspect(val)} is an invalid value, " <>
973
"valid values are [:mdy, :dmy, :ymd, :ydm, :myd, :dym]"
974
)
925
975
end
926
976
end
927
977
928
-
929
978
defp append_opts(conn, opts, :set_deadlock_priority) do
930
979
case Keyword.get(opts, :set_deadlock_priority) do
931
- nil -> conn
980
nil ->
981
conn
982
932
983
val when val in [:low, :high, :normal] ->
933
984
conn ["SET DEADLOCK_PRIORITY #{val}; "]
934
- nil -> conn
985
986
nil ->
987
conn
988
935
989
val when val in -10..10 ->
936
990
conn ["SET DEADLOCK_PRIORITY #{val}; "]
937
- val -> raise(
938
- ArgumentError,
939
- "set_deadlock_priority: #{inspect(val)} is an invalid value, " <>
940
- "valid values are #{inspect([:low, :high, :normal|-10..10])}"
941
- )
991
992
val ->
993
raise(
994
ArgumentError,
995
"set_deadlock_priority: #{inspect(val)} is an invalid value, " <>
996
"valid values are #{inspect([:low, :high, :normal | -10..10])}"
997
)
942
998
end
943
999
end
944
1000
945
1001
defp append_opts(conn, opts, :set_lock_timeout) do
946
1002
case Keyword.get(opts, :set_lock_timeout) do
947
- nil -> conn
1003
nil ->
1004
conn
1005
948
1006
val when val > 0 ->
949
1007
conn ["SET LOCK_TIMEOUT #{val}; "]
950
- val -> raise(
951
- ArgumentError,
952
- "set_lock_timeout: #{inspect(val)} is an invalid value, " <>
953
- "must be an positive integer."
954
- )
1008
1009
val ->
1010
raise(
1011
ArgumentError,
1012
"set_lock_timeout: #{inspect(val)} is an invalid value, " <>
1013
"must be an positive integer."
1014
)
955
1015
end
956
1016
end
957
1017
958
1018
defp append_opts(conn, opts, :set_remote_proc_transactions) do
959
1019
case Keyword.get(opts, :set_remote_proc_transactions) do
960
- nil -> conn
1020
nil ->
1021
conn
1022
961
1023
val when val in [:on, :off] ->
962
1024
val = val |> Atom.to_string() |> String.upcase()
963
1025
conn ["SET REMOTE_PROC_TRANSACTIONS #{val}; "]
964
- val -> raise(
965
- ArgumentError,
966
- "set_remote_proc_transactions: #{inspect(val)} is an invalid value, " <>
967
- "should be either :on, :off, nil"
968
- )
1026
1027
val ->
1028
raise(
1029
ArgumentError,
1030
"set_remote_proc_transactions: #{inspect(val)} is an invalid value, " <>
1031
"should be either :on, :off, nil"
1032
)
969
1033
end
970
1034
end
971
1035
972
1036
defp append_opts(conn, opts, :set_implicit_transactions) do
973
1037
case Keyword.get(opts, :set_implicit_transactions) do
974
- nil -> conn ["SET IMPLICIT_TRANSACTIONS OFF; "]
1038
nil ->
1039
conn ["SET IMPLICIT_TRANSACTIONS OFF; "]
1040
975
1041
val when val in [:on, :off] ->
976
1042
val = val |> Atom.to_string() |> String.upcase()
977
1043
conn ["SET IMPLICIT_TRANSACTIONS #{val}; "]
978
- val -> raise(
979
- ArgumentError,
980
- "set_implicit_transactions: #{inspect(val)} is an invalid value, " <>
981
- "should be either :on, :off, nil"
982
- )
1044
1045
val ->
1046
raise(
1047
ArgumentError,
1048
"set_implicit_transactions: #{inspect(val)} is an invalid value, " <>
1049
"should be either :on, :off, nil"
1050
)
983
1051
end
984
1052
end
985
1053
986
-
987
1054
defp append_opts(conn, opts, :set_transaction_isolation_level) do
988
1055
case Keyword.get(opts, :set_transaction_isolation_level) do
989
- nil -> conn
1056
nil ->
1057
conn
1058
990
1059
val when val in @trans_levels ->
991
- t = val
992
- |> Atom.to_string()
993
- |> String.replace("_", " ")
994
- |> String.upcase()
1060
t =
1061
val
1062
|> Atom.to_string()
1063
|> String.replace("_", " ")
1064
|> String.upcase()
1065
995
1066
conn ["SET TRANSACTION ISOLATION LEVEL #{t}; "]
996
- val -> raise(
997
- ArgumentError,
998
- "set_transaction_isolation_level: #{inspect(val)} is an invalid value, " <>
999
- "should be one of #{inspect(@trans_levels)} or nil"
1000
- )
1067
1068
val ->
1069
raise(
1070
ArgumentError,
1071
"set_transaction_isolation_level: #{inspect(val)} is an invalid value, " <>
1072
"should be one of #{inspect(@trans_levels)} or nil"
1073
)
1001
1074
end
1002
1075
end
1003
1076
1004
1077
defp append_opts(conn, opts, :set_allow_snapshot_isolation) do
1005
1078
database = Keyword.get(opts, :database)
1079
1006
1080
case Keyword.get(opts, :set_allow_snapshot_isolation) do
1007
- nil -> conn
1081
nil ->
1082
conn
1083
1008
1084
val when val in [:on, :off] ->
1009
1085
val = val |> Atom.to_string() |> String.upcase()
1010
- conn ["ALTER DATABASE [#{database}] SET ALLOW_SNAPSHOT_ISOLATION #{val}; "]
1011
- val -> raise(
1012
- ArgumentError,
1013
- "set_allow_snapshot_isolation: #{inspect(val)} is an invalid value, " <>
1014
- "should be either :on, :off, nil"
1015
- )
1086
1087
conn
1088
["ALTER DATABASE [#{database}] SET ALLOW_SNAPSHOT_ISOLATION #{val}; "]
1089
1090
val ->
1091
raise(
1092
ArgumentError,
1093
"set_allow_snapshot_isolation: #{inspect(val)} is an invalid value, " <>
1094
"should be either :on, :off, nil"
1095
)
1016
1096
end
1017
1097
end
1018
1098
end
changed mix.exs
 
@@ -5,7 5,7 @@ defmodule Tds.Mixfile do
5
5
def project do
6
6
[
7
7
app: :tds,
8
- version: "1.1.3",
8
version: "1.1.4",
9
9
elixir: "~> 1.0",
10
10
deps: deps(),
11
11
test_coverage: [tool: ExCoveralls],