Packages
tds
2.3.1
2.3.8
2.3.7
2.3.6
2.3.5
2.3.4
2.3.2
2.3.1
2.3.0
2.3.0-rc.1
2.3.0-rc.0
2.2.0
2.1.3
2.1.2
2.1.1
2.1.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.1-rc2
2.0.1-rc1
2.0.0
retired
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.0
1.0.19
1.0.18
1.0.17
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Microsoft SQL Server client (Elixir implementation of the MS TDS protocol)
Current section
Files
Jump to
Current section
Files
lib/tds.ex
defmodule Tds do
@moduledoc """
Microsoft SQL Server driver for Elixir.
Tds is partial implementation of the Micorosoft SQL Server
[MS-TDS](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds)
Tabular Data Stream Protocol.
A Tds query is performed in separate server-side prepare and execute stages.
At the moment query handle is not reused, but there is plan to cahce handles in
near feature. It uses [RPC](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/619c43b6-9495-4a58-9e49-a4950db245b3)
requests by default to `Sp_Prepare` (ProcId=11) and `Sp_Execute` (ProcId=12)
query, but it is possible to configure driver to use only Sp_ExecuteSql.
Please consult with [configuration](readme.html#configuration) how to do this.
"""
alias Tds.Query
@timeout 5000
@execution_mode :prepare_execute
@type start_option ::
{:hostname, String.t()}
| {:port, :inet.port_number()}
| {:database, String.t()}
| {:username, String.t()}
| {:password, String.t()}
| {:timeout, timeout()}
| {:connect_timeout, timeout()}
| DBConnection.start_option()
@type isolation_level ::
:read_uncommitted
| :read_committed
| :repeatable_read
| :serializable
| :snapshot
| :no_change
@type conn :: DBConnection.conn()
@type resultset :: list(Tds.Result.t())
@type option :: DBConnection.option()
@type transaction_option ::
{:mode, :transaction | :savepoint}
| {:isolation_level, isolation_level()}
| option()
@type execute_option ::
{:decode_mapper, (list -> term)}
| {:resultset, boolean()}
| option
@spec start_link([start_option]) ::
{:ok, conn} | {:error, Tds.Error.t() | term}
def start_link(opts \\ []) do
DBConnection.start_link(Tds.Protocol, default(opts))
end
@spec query(conn, iodata, list, [execute_option]) ::
{:ok, Tds.Result.t()} | {:error, Exception.t()}
def query(conn, statement, params, opts \\ []) do
query = %Query{statement: statement}
opts = Keyword.put_new(opts, :parameters, params)
case DBConnection.prepare_execute(conn, query, params, opts) do
{:ok, _query, result} -> {:ok, result}
{:error, err} -> {:error, err}
end
end
@spec query!(conn, iodata, list, [execute_option]) ::
Tds.Result.t() | no_return()
def query!(conn, statement, params, opts \\ []) do
query = %Query{statement: statement}
opts = Keyword.put_new(opts, :parameters, params)
case DBConnection.prepare_execute(conn, query, params, opts) do
{:ok, _query, result} -> result
{:error, %{mssql: %{msg_text: msg}}} -> raise Tds.Error, msg
{:error, err} -> raise err
end
end
@doc """
Executes statement that can contain multiple SQL batches, result will contain
all results that server yield for each batch.
"""
@spec query_multi(conn, iodata, list, [execute_option]) ::
{:ok, resultset()}
| {:error, Exception.t()}
def query_multi(conn, statemnt, params, opts \\ []) do
query = %Query{statement: statemnt}
opts =
opts
|> Keyword.put_new(:parameters, params)
|> Keyword.put_new(:resultset, true)
case DBConnection.prepare_execute(conn, query, params, opts) do
{:ok, _query, resultset} -> {:ok, resultset}
{:error, err} -> {:error, err}
end
end
@spec prepare(conn, iodata, [option]) ::
{:ok, Tds.Query.t()} | {:error, Exception.t()}
def prepare(conn, statement, opts \\ []) do
query = %Query{statement: statement}
case DBConnection.prepare(conn, query, opts) do
{:ok, query} -> {:ok, query}
{:error, err} -> {:error, err}
end
end
@spec prepare!(conn, iodata, [option]) :: Tds.Query.t() | no_return()
def prepare!(conn, statement, opts \\ []) do
query = %Query{statement: statement}
case DBConnection.prepare(conn, query, opts) do
{:ok, query} -> query
{:error, %{mssql: %{msg_text: msg}}} -> raise Tds.Error, msg
{:error, err} -> raise err
end
end
@spec execute(conn, Tds.Query.t(), list, [execute_option]) ::
{:ok, Tds.Query.t(), Tds.Result.t()}
| {:error, Tds.Error.t()}
def execute(conn, query, params, opts \\ []) do
case DBConnection.execute(conn, query, params, opts) do
{:ok, q, result} -> {:ok, q, result}
{:error, err} -> {:error, err}
end
end
@spec execute!(conn, Tds.Query.t(), list, [execute_option]) ::
Tds.Result.t()
def execute!(conn, query, params, opts \\ []) do
case DBConnection.execute(conn, query, params, opts) do
{:ok, _q, result} -> result
{:error, %{mssql: %{msg_text: msg}}} -> raise Tds.Error, msg
{:error, err} -> raise err
end
end
@spec close(conn, Tds.Query.t(), [option]) :: :ok | {:error, Exception.t()}
def close(conn, query, opts \\ []) do
case DBConnection.close(conn, query, opts) do
{:ok, result} -> {:ok, result}
{:error, err} -> {:error, err}
end
end
@spec close!(conn, Tds.Query.t(), [option]) :: :ok
def close!(conn, query, opts \\ []) do
case DBConnection.close(conn, query, opts) do
{:ok, result} -> result
{:error, %{mssql: %{msg_text: msg}}} -> raise Tds.Error, msg
{:error, err} -> raise err
end
end
@spec transaction(conn, (DBConnection.t() -> result), [transaction_option()]) ::
{:ok, result} | {:error, any}
when result: var
def transaction(conn, fun, opts \\ []) do
DBConnection.transaction(conn, fun, opts)
end
@spec rollback(DBConnection.t(), reason :: any) :: no_return
defdelegate rollback(conn, any), to: DBConnection
@spec child_spec([start_option]) :: Supervisor.Spec.spec()
def child_spec(opts) do
DBConnection.child_spec(Tds.Protocol, default(opts))
end
defp default(opts) do
opts
|> Keyword.put_new(:idle_timeout, @timeout)
|> Keyword.put_new(:execution_mode, @execution_mode)
end
@doc """
Returns the configured JSON library.
To customize the JSON library, include the following in your `config/config.exs`:
config :tds, json_library: SomeJSONModule
Defaults to `Jason`.
"""
@spec json_library() :: module()
def json_library() do
Application.fetch_env!(:tds, :json_library)
end
@doc """
Generates a version 4 (random) UUID in the MS uniqueidentifier binary format.
"""
@spec generate_uuid :: <<_::128>>
def generate_uuid(), do: Tds.Types.UUID.bingenerate()
@doc """
Decodes MS uniqueidentifier binary to its string representation.
"""
def decode_uuid(uuid), do: Tds.Types.UUID.load(uuid)
@doc """
Same as `decode_uuid/1` but raises `ArgumentError` if value is invalid.
"""
def decode_uuid!(uuid) do
case Tds.Types.UUID.load(uuid) do
{:ok, value} ->
value
:error ->
raise ArgumentError, "Invalid uuid binary #{inspect(uuid)}"
end
end
@doc """
Encodes UUID string into MS uniqueidentifier binary.
"""
@spec encode_uuid(any) :: :error | {:ok, <<_::128>>}
def encode_uuid(value), do: Tds.Types.UUID.dump(value)
@doc """
Same as `encode_uuid/1` but raises `ArgumentError` if value is invalid.
"""
@spec encode_uuid!(any) :: <<_::128>>
def encode_uuid!(value), do: Tds.Types.UUID.dump!(value)
end