Current section

Files

Jump to
tds lib tds protocol.ex
Raw

lib/tds/protocol.ex

defmodule Tds.Protocol do
require Logger
import Tds.Utils
import Tds.Messages
alias Tds.Parameter
def prelogin(%{sock: sock, opts: opts} = s) do
msg = msg_prelogin(params: opts)
case msg_send(msg, sock) do
:ok ->
{:noreply, %{s | state: :prelogin}}
{:error, reason} ->
{:stop, :normal, %Tds.Error{message: "tcp send: #{reason}"}, s}
end
end
def login(%{sock: sock, opts: opts} = s) do
msg = msg_login(params: opts)
case msg_send(msg, sock) do
:ok ->
#Logger.debug "Set State: Login"
{:noreply, %{s | state: :login}}
{:error, reason} ->
{:stop, :normal, %Tds.Error{message: "tcp send: #{reason}"}, s}
end
end
def send_query(statement, s) do
msg = msg_sql(query: statement)
case send_to_result(msg, s) do
{:ok, s} ->
#Logger.debug "Send Query"
{:ok, %{s | statement: nil, state: :executing}}
err ->
err
end
end
def send_param_query(statement, params, s) do
param_desc = params |> Enum.map(fn(%Parameter{} = param) ->
Tds.Types.encode_param_descriptor(param)
end)
param_desc = param_desc
|> Enum.join(", ")
msg = msg_rpc(proc: :sp_executesql, params: [%Parameter{value: statement}, %Parameter{value: param_desc}] ++ params)
case send_to_result(msg, s) do
{:ok, s} ->
#Logger.debug "Send Query"
{:ok, %{s | statement: nil, state: :executing}}
err ->
err
end
end
def send_proc(proc, params, s) do
msg = msg_rpc(proc: proc, params: params)
case send_to_result(msg, s) do
{:ok, s} ->
Logger.debug "Send Query"
{:ok, %{s | statement: nil, state: :executing}}
err ->
err
end
end
## SERVER Packet Responses
def message(:prelogin, _state) do
end
def message(:login, msg_login_ack(), %{opts: opts, tail: _tail, queue: queue, opts: opts} = s) do
#Logger.debug "Protocol Message"
opts = clean_opts(opts)
queue = :queue.drop(queue)
#TODO: Bootstrap Query
#s = %{s | bootstrap: true, opts: opts}
#Connection.new_query(Types.bootstrap_query, [], s)
reply(:ok, s)
{:ok, %{s | state: :ready, opts: opts, queue: queue}}
end
## executing
def message(:executing, msg_sql_result(columns: columns, rows: rows, done: _done), %{queue: queue} = s) do
if columns != nil do
columns = Enum.reduce(columns, [], fn (col, acc) -> [col[:name]|acc] end) |> Enum.reverse
end
num_rows = 0;
if rows != nil do
rows = Enum.reverse rows
num_rows = Enum.count rows
end
result = %Tds.Result{columns: columns, rows: rows, num_rows: num_rows}
reply(result, s)
queue = :queue.drop(queue)
{:ok, %{s | queue: queue, statement: "", state: :ready}}
end
# def message(:executing, msg_empty_query(), s) do
# reply(%Postgrex.Result{}, s)
# {:ok, s}
# end
# ## Async
# def message(_, msg_ready(), %{queue: queue} = s) do
# queue = :queue.drop(queue)
# Connection.next(%{s | queue: queue, state: :ready})
# end
## Error
def message(_, msg_error(e: e), %{queue: queue} = s) do
reply(%Tds.Error{mssql: e}, s)
queue = :queue.drop(queue)
{:ok, %{s | queue: queue, statement: "", state: :ready}}
end
defp msg_send(msg, %{sock: sock}), do: msg_send(msg, sock)
defp msg_send(msg, {mod, sock}) do
data = encode_msg(msg)
mod.send(sock, data)
end
defp send_to_result(msg, s) do
case msg_send(msg, s) do
:ok ->
{:ok, s}
{:error, reason} ->
{:error, %Tds.Error{message: "tcp send: #{reason}"} , s}
end
end
defp clean_opts(opts) do
Keyword.put(opts, :password, :REDACTED)
end
end