Skip to content

Commit

Permalink
add result.columns
Browse files Browse the repository at this point in the history
  • Loading branch information
ruslandoga committed Feb 8, 2025
1 parent 0a8ca00 commit 43b3287
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 8 deletions.
11 changes: 9 additions & 2 deletions lib/ch/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,15 @@ defimpl DBConnection.Query, for: Ch.Query do
%Result{num_rows: length(rows), rows: rows, command: command, headers: headers}

"RowBinaryWithNamesAndTypes" ->
rows = data |> IO.iodata_to_binary() |> RowBinary.decode_rows()
%Result{num_rows: length(rows), rows: rows, command: command, headers: headers}
[names | rows] = data |> IO.iodata_to_binary() |> RowBinary.decode_names_and_rows()

%Result{
num_rows: length(rows),
columns: names,
rows: rows,
command: command,
headers: headers
}

_other ->
%Result{rows: data, data: data, command: command, headers: headers}
Expand Down
10 changes: 6 additions & 4 deletions lib/ch/result.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ defmodule Ch.Result do
@moduledoc """
Result struct returned from any successful query. Its fields are:
* `command` - An atom of the query command, for example: `:select`, `:insert`;
* `command` - An atom of the query command, for example: `:select`, `:insert`
* `columns` - A list of column names
* `rows` - A list of lists, each inner list corresponding to a row, each element in the inner list corresponds to a column
* `num_rows` - The number of fetched or affected rows;
* `num_rows` - The number of fetched or affected rows
* `headers` - The HTTP response headers
* `data` - The raw iodata from the response
"""

defstruct [:command, :num_rows, :rows, :headers, :data]
defstruct [:command, :num_rows, :columns, :rows, :headers, :data]

@type t :: %__MODULE__{
command: Ch.Query.command(),
command: Ch.Query.command() | nil,
num_rows: non_neg_integer | nil,
columns: [String.t()] | nil,
rows: [[term]] | iodata | nil,
headers: Mint.Types.headers(),
data: iodata
Expand Down
25 changes: 23 additions & 2 deletions lib/ch/row_binary.ex
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,12 @@ defmodule Ch.RowBinary do
def decode_rows(<<cols, rest::bytes>>), do: skip_names(rest, cols, cols)
def decode_rows(<<>>), do: []

# TODO document
@doc false
def decode_names_and_rows(<<cols, rest::bytes>>) do
decode_names(rest, cols, cols, _acc = [])
end

@doc """
Decodes [`RowBinary`](https://clickhouse.com/docs/en/sql-reference/formats#rowbinary) into rows.
Expand Down Expand Up @@ -558,8 +564,6 @@ defmodule Ch.RowBinary do
raise ArgumentError, "unsupported type for decoding: #{inspect(type)}"
end

defp skip_names(<<rest::bytes>>, 0, count), do: decode_types(rest, count, _acc = [])

varints = [
{_pattern = quote(do: <<0::1, v1::7>>), _value = quote(do: v1)},
{quote(do: <<1::1, v1::7, 0::1, v2::7>>), quote(do: (v2 <<< 7) + v1)},
Expand Down Expand Up @@ -588,12 +592,29 @@ defmodule Ch.RowBinary do
end}
]

defp skip_names(<<rest::bytes>>, 0, count), do: decode_types(rest, count, _acc = [])

for {pattern, value} <- varints do
defp skip_names(<<unquote(pattern), _::size(unquote(value))-bytes, rest::bytes>>, left, count) do
skip_names(rest, left - 1, count)
end
end

defp decode_names(<<rest::bytes>>, 0, count, names) do
[:lists.reverse(names) | decode_types(rest, count, _acc = [])]
end

for {pattern, value} <- varints do
defp decode_names(
<<unquote(pattern), name::size(unquote(value))-bytes, rest::bytes>>,
left,
count,
acc
) do
decode_names(rest, left - 1, count, [name | acc])
end
end

defp decode_types(<<>>, 0, _types), do: []

defp decode_types(<<rest::bytes>>, 0, types) do
Expand Down

0 comments on commit 43b3287

Please sign in to comment.